forked from ceu-lang/ceu
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtight.lua
More file actions
197 lines (175 loc) · 5.63 KB
/
Copy pathtight.lua
File metadata and controls
197 lines (175 loc) · 5.63 KB
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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
_TIGHT = false
function OR_all (me, t)
t = t or me
me.tl_awaits = false
me.tl_escapes = false
me.tl_blocks = false
for _, sub in ipairs(t) do
if _AST.isNode(sub) then
me.tl_awaits = me.tl_awaits or sub.tl_awaits
me.tl_escapes = me.tl_escapes or sub.tl_escapes
me.tl_blocks = me.tl_blocks or sub.tl_blocks
end
end
end
function AND_all (me, t)
t = t or me
me.tl_awaits = true
me.tl_escapes = true
me.tl_blocks = true
for _, sub in ipairs(t) do
if _AST.isNode(sub) then
me.tl_awaits = me.tl_awaits and sub.tl_awaits
me.tl_escapes = me.tl_escapes and sub.tl_escapes
me.tl_blocks = me.tl_blocks and sub.tl_blocks
end
end
end
function SAME (me, sub)
me.tl_awaits = sub.tl_awaits
me.tl_escapes = sub.tl_escapes
me.tl_blocks = sub.tl_blocks
end
F = {
Node_pre = function (me)
me.tl_awaits = false
me.tl_escapes = false
me.tl_blocks = false
end,
Node = function (me)
if not F[me.tag] then
OR_all(me)
end
end,
Stmts = OR_all,
ParEver = OR_all,
ParAnd = OR_all,
ParOr = AND_all,
If = function (me)
local c, t, f = unpack(me)
AND_all(me, {t,f})
end,
Break = function (me)
me.tl_blocks = true
end,
Loop = function (me)
local body = unpack(me)
SAME(me, body)
local isTight = (not _AST.iter(_AST.pred_async)())
and (not body.tl_blocks)
and (not me.isBounded)
WRN(not isTight, me, 'tight loop')
_TIGHT = _TIGHT or isTight
me.tl_blocks = (body.tl_awaits or body.tl_escapes) and me.isBounded~='var'
local dcl = _AST.iter'Dcl_fun'()
if dcl and isTight then
dcl.var.fun.isTight = true
end
end,
SetBlock = function (me)
local blk,_ = unpack(me)
SAME(me, blk)
me.tl_escapes = false
end,
Escape = function (me)
me.tl_escapes = true
me.tl_blocks = true
end,
Thread = 'Async',
Async = function (me)
local _,body = unpack(me)
SAME(me, body)
me.tl_awaits = true
me.tl_blocks = true
end,
AwaitExt = function (me)
me.tl_awaits = true
me.tl_blocks = true
end,
AwaitInt = 'AwaitExt',
AwaitT = 'AwaitExt',
AwaitN = 'AwaitExt',
AwaitS = 'AwaitExt',
Op2_call = function (me)
local op, f, _ = unpack(me)
if not (f.var and f.var.fun) then
return -- ignore native and pointer calls
end
-- if calling a tight (or unknown) function,
-- then the top function is also tight
local dcl = _AST.iter'Dcl_fun'()
if dcl and (f.var.fun.isTight or f.var.fun.isTight==nil) then
dcl.var.fun.isTight = true
ASR(dcl.var.fun.mod.delay == true,
dcl, 'function must be declared with "delay"')
end
-- assert that the call is using call/delay correctly
if f.var.fun.mod.delay then
ASR(op=='call/delay',
me, '`call/delay´ is required for "'..f.var.fun.id..'"')
else
ASR(op=='call',
me, '`call/delay´ is not required for "'..f.var.fun.id..'"')
end
end,
Dcl_fun = function (me)
local _, delay, _, _, id, blk = unpack(me)
if not blk then
return -- pure declarations
end
-- if I'm not discovered as tight, then I'm not tight
if me.var.fun.isTight == nil then
me.var.fun.isTight = false
end
if me.var.fun.isTight then
ASR(me.var.fun.mod.delay == me.var.fun.isTight,
me, 'function must be declared with delay')
else
WRN(me.var.fun.mod.delay == me.var.fun.isTight,
me, 'function may be declared without delay')
end
-- copy isTight to all matching interfaces with method "id"
local matches = CLS().matches or {}
for ifc in pairs(matches) do
local var = ifc.blk_ifc.vars[id]
if var then
assert(var.fun)
local t = var.fun.__tights or {}
var.fun.__tights = t
t[#t+1] = me.var.fun.isTight
end
end
end,
Root = function (me)
-- check if all interface methods have "mod.delay"
-- respecting their implementations
for _, ifc in pairs(_ENV.clss_ifc) do
for _,var in ipairs(ifc.blk_ifc.vars) do
if var.fun then
local t = var.fun.__tights or {}
-- If "delay", at least one implementation should
-- not be isTight.
if var.fun.mod.delay then
local ok = false
for _, isTight in ipairs(t) do
if isTight then
ok = true
break
end
end
WRN(ok, var.ln,
'function may be declared without "delay"')
-- If not "delay", all implementations should be
-- isTight.
else
for _, isTight in ipairs(t) do
ASR((not isTight), var.ln,
'function must be declared with "delay"')
end
end
end
end
end
end,
}
_AST.visit(F)