-
Notifications
You must be signed in to change notification settings - Fork 1
/
base.t
104 lines (93 loc) · 2.87 KB
/
base.t
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
-- SPDX-FileCopyrightText: 2024 René Hiemstra <[email protected]>
-- SPDX-FileCopyrightText: 2024 Torsten Keßler <[email protected]>
--
-- SPDX-License-Identifier: MIT
local concepts = require("concept-impl")
local Base = {}
function Base:new(name, func)
local base = {name = name}
setmetatable(base, {__index = self})
local mt = getmetatable(base)
function mt:__call(T)
func(T)
end
function mt.__mul(B1, B2)
local function impl(T)
B1(T)
B2(T)
end
return Base:new(B1.name .. "And" .. B2.name, impl)
end
return base
end
local AbstractBase = Base:new("AbstractBase",
function(T)
assert(terralib.types.istype(T))
assert(T:isstruct())
local Self = terralib.types.newstruct("Self" .. tostring(T))
concepts.Base(Self)
Self.friends[T] = true
for key, val in pairs({staticmethods = {}, templates = {}, varargtemplates = {}, Self = Self, traits = {}}) do
T[key] = val
end
Self.methods = T.methods
Self.staticmethods = T.staticmethods
Self.templates = T.templates
T.metamethods.__getmethod = function(self, methodname)
local fnlike = self.methods[methodname]
--try staticmethods table
if not fnlike then
fnlike = T.staticmethods[methodname]
--detect name collisions with T.tempplates
if fnlike and T.templates[methodname] then
return error("NameCollision: Function " .. methodname .. " defined in "..
tostring(T) .. ".templates and " .. tostring(T) ..".staticmethods.")
end
end
--if no implementation is found try __methodmissing
if not fnlike and terralib.ismacro(self.metamethods.__methodmissing) then
fnlike = terralib.internalmacro(function(ctx, tree, ...)
return self.metamethods.__methodmissing:run(ctx, tree, methodname, ...)
end)
end
return fnlike
end
T.metamethods.__methodmissing = macro(function(name, obj, ...)
assert(obj.tree.type == T) --__methodmissing should only be called for
--class methods, not for static methods
local args = terralib.newlist{...}
local types = args:map(function(t) return t.tree.type end)
types:insert(1, &T)
local method = T.templates[name]
if method then
local sig, func = method(unpack(types))
if func then
if not sig:isvararg() then
--regular template dispatch
return `[func](&obj, [args])
else
--variable argument dispatch
local newargs, varargs = terralib.newlist(), terralib.newlist()
local m = sig:len()-2 --sig includes concepts Vararg and Self. Therefore we subtract 2.
for k = 1, m do
newargs:insert(args[k])
end
for k = m+1,#args do
varargs:insert(args[k])
end
return `[func](&obj, [newargs], {[varargs]})
end
end
end
error(
(
"Cannot find implementation for method %s on type %s"
):format(name, tostring(T))
)
end)
end
)
return {
Base = Base,
AbstractBase = AbstractBase
}