-
Notifications
You must be signed in to change notification settings - Fork 2
/
recursive.lua
92 lines (81 loc) · 1.91 KB
/
recursive.lua
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
local wrap = coroutine.wrap
local yield = coroutine.yield
local pack = table.pack
local unpack = table.unpack
local Stacks = {}
local YieldMark = {}
local First = true
local function createStack(func, ...)
local s = {
thd = wrap(func),
arg = pack(...),
st = 0,
}
Stacks[#Stacks+1] = s
return s
end
local function getResult(stack)
local res = stack.res
if not res then
return
end
return unpack(res, 1, res.n)
end
local function getArg(stack)
local arg = stack.arg
if not arg then
return
end
return unpack(arg, 1, arg.n)
end
local function callStack(stack, ...)
local thd = stack.thd
local res = pack(thd(...))
if res[1] == YieldMark then
stack.st = 1
else
stack.st = 2
stack.res = res
end
end
local function firstCall(max, func, ...)
local lastStack = createStack(func, ...)
for _ = 1, max do
local len = #Stacks
local stack = Stacks[len]
if stack.st == 0 then
callStack(stack, getArg(stack))
elseif stack.st == 1 then
callStack(stack, getResult(lastStack))
else
if len == 1 then
return getResult(stack)
end
lastStack = stack
Stacks[len] = nil
end
end
error('stack overflow!')
end
local function subCall(func, ...)
createStack(func, ...)
return yield(YieldMark)
end
local m = {}
function m.resolve(func, max)
return function (...)
if First then
First = false
local res = pack(xpcall(firstCall, debug.traceback, max or 10000, func, ...))
First = true
if res[1] == true then
return unpack(res, 2, res.n)
else
error(res[2])
end
else
return subCall(func, ...)
end
end
end
return m