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