parent
d121e74c6f
commit
f5619ce591
@ -0,0 +1,54 @@
|
|||||||
|
import { LuaError } from './LuaError'
|
||||||
|
import { LuaType } from './utils'
|
||||||
|
|
||||||
|
export type ThreadStatus = 'running' | 'suspended' | 'dead'
|
||||||
|
|
||||||
|
type Gen = Generator<LuaType[], LuaType[], LuaType[]>
|
||||||
|
|
||||||
|
type GenFn = (...args: LuaType[]) => Gen
|
||||||
|
|
||||||
|
class Thread {
|
||||||
|
private readonly fn: GenFn
|
||||||
|
private gen?: Gen
|
||||||
|
public status: ThreadStatus = 'suspended'
|
||||||
|
public last: LuaType[] = []
|
||||||
|
|
||||||
|
public static current: Thread
|
||||||
|
public static main: Thread
|
||||||
|
|
||||||
|
public constructor(fn: GenFn) {
|
||||||
|
this.fn = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
public resume(...args: LuaType[]): LuaType[] {
|
||||||
|
if (this.status === 'dead') {
|
||||||
|
throw new LuaError('cannot resume dead coroutine')
|
||||||
|
}
|
||||||
|
const prev = Thread.current
|
||||||
|
Thread.current = this
|
||||||
|
this.status = 'running'
|
||||||
|
try {
|
||||||
|
if (!this.gen) {
|
||||||
|
this.gen = this.fn(...args)
|
||||||
|
const r = this.gen.next()
|
||||||
|
this.status = r.done ? 'dead' : 'suspended'
|
||||||
|
this.last = r.value || []
|
||||||
|
return this.last
|
||||||
|
}
|
||||||
|
const r = this.gen.next(args)
|
||||||
|
this.status = r.done ? 'dead' : 'suspended'
|
||||||
|
this.last = r.value || []
|
||||||
|
return this.last
|
||||||
|
} finally {
|
||||||
|
Thread.current = prev
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
||||||
|
const mainThread = new Thread((function* () {}) as unknown as GenFn)
|
||||||
|
mainThread.status = 'running'
|
||||||
|
Thread.main = mainThread
|
||||||
|
Thread.current = mainThread
|
||||||
|
|
||||||
|
export { Thread }
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
import { Table } from '../Table'
|
||||||
|
import { LuaType, coerceArgToFunction, coerceArgToThread } from '../utils'
|
||||||
|
import { LuaError } from '../LuaError'
|
||||||
|
import { Thread } from '../Thread'
|
||||||
|
|
||||||
|
function create(fn: LuaType): Thread {
|
||||||
|
const F = coerceArgToFunction(fn, 'create', 1)
|
||||||
|
return new Thread(F as (...args: LuaType[]) => Generator<LuaType[]>)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resume(thread: LuaType, ...args: LuaType[]): LuaType[] {
|
||||||
|
const THREAD = coerceArgToThread(thread, 'resume', 1)
|
||||||
|
try {
|
||||||
|
return [true, ...THREAD.resume(...args)]
|
||||||
|
} catch (e) {
|
||||||
|
if (e instanceof LuaError) return [false, e.message]
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function status(thread: LuaType): string {
|
||||||
|
const THREAD = coerceArgToThread(thread, 'status', 1)
|
||||||
|
return THREAD.status
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrap(fn: LuaType): Function {
|
||||||
|
const thread = create(fn)
|
||||||
|
return (...args: LuaType[]): LuaType[] => thread.resume(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
function running(): LuaType[] {
|
||||||
|
return [Thread.current, Thread.current === Thread.main]
|
||||||
|
}
|
||||||
|
|
||||||
|
const libCoroutine = new Table({
|
||||||
|
create,
|
||||||
|
resume,
|
||||||
|
wrap,
|
||||||
|
running,
|
||||||
|
status
|
||||||
|
})
|
||||||
|
|
||||||
|
export { libCoroutine }
|
||||||
Loading…
Reference in new issue