forked from yuin/gopher-lua
-
Notifications
You must be signed in to change notification settings - Fork 0
/
coroutinelib.go
112 lines (102 loc) · 1.94 KB
/
coroutinelib.go
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
package lua
func OpenCoroutine(L *LState) int {
// TODO: Tie module name to contents of linit.go?
mod := L.RegisterModule(CoroutineLibName, coFuncs)
L.Push(mod)
return 1
}
var coFuncs = map[string]LGFunction{
"create": coCreate,
"yield": coYield,
"resume": coResume,
"running": coRunning,
"status": coStatus,
"wrap": coWrap,
}
func coCreate(L *LState) int {
fn := L.CheckFunction(1)
newthread, _ := L.NewThread()
base := 0
newthread.stack.Push(callFrame{
Fn: fn,
Pc: 0,
Base: base,
LocalBase: base + 1,
ReturnBase: base,
NArgs: 0,
NRet: MultRet,
Parent: nil,
TailCall: 0,
})
L.Push(newthread)
return 1
}
func coYield(L *LState) int {
return -1
}
func coResume(L *LState) int {
th := L.CheckThread(1)
if L.G.CurrentThread == th {
msg := "can not resume a running thread"
if th.wrapped {
L.RaiseError(msg)
return 0
}
L.Push(LFalse)
L.Push(LString(msg))
return 2
}
if th.Dead {
msg := "can not resume a dead thread"
if th.wrapped {
L.RaiseError(msg)
return 0
}
L.Push(LFalse)
L.Push(LString(msg))
return 2
}
th.Parent = L
L.G.CurrentThread = th
if !th.isStarted() {
cf := th.stack.Last()
th.currentFrame = cf
th.SetTop(0)
nargs := L.GetTop() - 1
L.XMoveTo(th, nargs)
cf.NArgs = nargs
th.initCallFrame(cf)
th.Panic = panicWithoutTraceback
} else {
nargs := L.GetTop() - 1
L.XMoveTo(th, nargs)
}
top := L.GetTop()
threadRun(th)
return L.GetTop() - top
}
func coRunning(L *LState) int {
if L.G.MainThread == L {
L.Push(LNil)
return 1
}
L.Push(L.G.CurrentThread)
return 1
}
func coStatus(L *LState) int {
L.Push(LString(L.Status(L.CheckThread(1))))
return 1
}
func wrapaux(L *LState) int {
L.Insert(L.ToThread(UpvalueIndex(1)), 1)
return coResume(L)
}
func coWrap(L *LState) int {
coCreate(L)
L.CheckThread(L.GetTop()).wrapped = true
v := L.Get(L.GetTop())
L.Pop(1)
L.Push(L.NewClosure(wrapaux, v))
return 1
}
//