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
}
//
|