-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinterface.t
122 lines (106 loc) · 3.94 KB
/
interface.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
-- SPDX-FileCopyrightText: 2024 René Hiemstra <[email protected]>
-- SPDX-FileCopyrightText: 2024 Torsten Keßler <[email protected]>
--
-- SPDX-License-Identifier: MIT
local base = require("base")
local templates = require("template")
local newinterface = terralib.memoize(function(name)
local interface = terralib.types.newstruct(name)
interface.type = "interface"
local vtable = terralib.types.newstruct(name .. "Vtable")
function interface.metamethods.__getentries(Self)
for name, method in pairs(Self.methods) do
vtable.entries:insert({field = name, type = &opaque})
end
vtable:complete()
local entries = terralib.newlist()
entries:insert({field = "data", type = &opaque})
entries:insert({field = "ftab", type = &vtable})
return entries
end
function interface.metamethods.__staticinitialize(Self)
for name, method in pairs(Self.methods) do
local sig = method.type
local typ = terralib.newlist()
typ:insertall(sig.parameters)
typ[1] = &opaque
local ret = sig.returntype
local sym = typ:sub(2, -1):map(symbol)
Self.methods[name] = terra(self: &Self, [sym])
var func = [typ -> ret](self.ftab.[name])
return func(self.data, [sym])
end
end
end
function interface.metamethods.__cast(from, to, exp)
assert(to == interface)
if from:ispointertostruct() then
from = from.type
local methods = assert(interface:isimplemented(from))
local impl = terralib.newlist()
for _, entry in ipairs(vtable.entries) do
local name = entry.field
impl:insert(methods[name])
end
local ftab = constant(`vtable {[impl]})
return `to {[&opaque](exp), &ftab}
else
error("Cannot perform cast to dynamic interface")
end
end
function interface:isimplemented(T)
local methods = {}
for name, method in pairs(self.methods) do
local Isig = method.type
local Tmethod = T.methods[name]
local Ttemplate = T.templates and T.templates[name]
assert(
Tmethod or Ttemplate,
(
"Interface %s requires method %s"
):format(tostring(self), name)
)
if Tmethod then
local Tsig = T.methods[name].type
local are_same = true
are_same = (#Isig.parameters == #Tsig.parameters) and are_same
-- Skip self parameter
for i = 2, #Isig.parameters do
are_same = (
(Isig.parameters[i] == Tsig.parameters[i]) and are_same
)
end
are_same = (Isig.returntype == Tsig.returntype) and are_same
assert(
are_same,
(
"Interface %s method %s requires %s but given %s"
):format(
tostring(self),
name,
tostring(Isig),
tostring(Tsig)
)
)
methods[name] = Tmethod
else
local args = terralib.newlist()
args:insertall(Isig.parameters)
-- For the method dispatch we have to replace the abstract
-- self &interface with the concrete self &T.
args[1] = &T
local sig, method = Ttemplate(unpack(args))
methods[name] = method
end
end
return methods
end
return interface
end)
local function isinterface(I)
return terralib.types.istype(I) and I.type == "interface"
end
return {
newinterface = newinterface,
isinterface = isinterface,
}