forked from defunkt/ReefVM
fix nested globals
This commit is contained in:
parent
e542070677
commit
052f989e82
|
|
@ -14,7 +14,7 @@ export function wrapNative(vm: VM, fn: Function): (this: VM, ...args: Value[]) =
|
|||
const wrapped = async function (this: VM, ...values: Value[]) {
|
||||
const nativeArgs = values.map(arg => fromValue(arg, vm))
|
||||
const result = await fn.call(this, ...nativeArgs)
|
||||
return toValue(result)
|
||||
return toValue(result, this)
|
||||
}
|
||||
|
||||
const wrappedObj = wrapped as any
|
||||
|
|
|
|||
14
src/value.ts
14
src/value.ts
|
|
@ -1,3 +1,4 @@
|
|||
import { wrapNative } from "./function"
|
||||
import { OpCode } from "./opcode"
|
||||
import { Scope } from "./scope"
|
||||
import { VM } from "./vm"
|
||||
|
|
@ -41,7 +42,7 @@ export function isValue(v: any): boolean {
|
|||
return !!(v && typeof v === 'object' && v.type && 'value' in v)
|
||||
}
|
||||
|
||||
export function toValue(v: any): Value /* throws */ {
|
||||
export function toValue(v: any, vm?: VM): Value /* throws */ {
|
||||
if (v === null || v === undefined)
|
||||
return { type: 'null', value: null }
|
||||
|
||||
|
|
@ -49,7 +50,7 @@ export function toValue(v: any): Value /* throws */ {
|
|||
return v as Value
|
||||
|
||||
if (Array.isArray(v))
|
||||
return { type: 'array', value: v.map(toValue) }
|
||||
return { type: 'array', value: v.map(x => toValue(x, vm)) }
|
||||
|
||||
if (v instanceof RegExp)
|
||||
return { type: 'regex', value: v }
|
||||
|
|
@ -64,11 +65,12 @@ export function toValue(v: any): Value /* throws */ {
|
|||
case 'function':
|
||||
if ((v as any)[REEF_FUNCTION])
|
||||
return (v as any)[REEF_FUNCTION]
|
||||
throw new Error("can't toValue() a js function yet")
|
||||
if (!vm) throw new Error("can't toValue() function without a vm")
|
||||
return { type: 'native', fn: wrapNative(vm, v), value: '<function>' }
|
||||
case 'object':
|
||||
const dict: Dict = new Map()
|
||||
|
||||
for (const key of Object.keys(v)) dict.set(key, toValue(v[key]))
|
||||
for (const key of Object.keys(v)) dict.set(key, toValue(v[key], vm))
|
||||
|
||||
return { type: 'dict', value: dict }
|
||||
default:
|
||||
|
|
@ -210,10 +212,10 @@ export function fnFromValue(fn: Value, vm: VM): Function {
|
|||
newVM.scope = fn.parentScope
|
||||
|
||||
newVM.stack.push(fn)
|
||||
newVM.stack.push(...positional.map(toValue))
|
||||
newVM.stack.push(...positional.map(x => toValue(x, vm)))
|
||||
for (const [key, val] of Object.entries(named)) {
|
||||
newVM.stack.push(toValue(key))
|
||||
newVM.stack.push(toValue(val))
|
||||
newVM.stack.push(toValue(val, vm))
|
||||
}
|
||||
newVM.stack.push(toValue(positional.length))
|
||||
newVM.stack.push(toValue(Object.keys(named).length))
|
||||
|
|
|
|||
|
|
@ -49,14 +49,11 @@ export class VM {
|
|||
}
|
||||
|
||||
set(name: string, value: any) {
|
||||
if (typeof value === 'function')
|
||||
this.setFunction(name, value)
|
||||
else
|
||||
this.scope.set(name, toValue(value))
|
||||
this.scope.set(name, toValue(value, this))
|
||||
}
|
||||
|
||||
setFunction(name: string, fn: TypeScriptFunction) {
|
||||
this.scope.set(name, { type: 'native', fn: wrapNative(this, fn), value: '<function>' })
|
||||
this.scope.set(name, toValue(fn, this))
|
||||
}
|
||||
|
||||
setValueFunction(name: string, fn: NativeFunction) {
|
||||
|
|
|
|||
|
|
@ -1760,3 +1760,27 @@ test("builtin global functions are placed into a higher level scope", async () =
|
|||
expect(globals).toEqual(['sum', 'greet'])
|
||||
expect(locals).toEqual(['x'])
|
||||
})
|
||||
|
||||
|
||||
test("builtin global scope can be values too", async () => {
|
||||
const bytecode = toBytecode(`
|
||||
PUSH 1
|
||||
STORE x
|
||||
HALT
|
||||
`)
|
||||
|
||||
const vm = new VM(bytecode, {
|
||||
pi: 3.14,
|
||||
universe: true,
|
||||
algorithms: {
|
||||
bigOne: () => false,
|
||||
}
|
||||
})
|
||||
await vm.run()
|
||||
|
||||
const locals = Array.from(vm.scope.locals.entries()).map(([name,]) => name)
|
||||
const globals = Array.from(vm.scope.parent!.locals.entries()).map(([name,]) => name)
|
||||
|
||||
expect(globals).toEqual(['pi', 'universe', 'algorithms'])
|
||||
expect(locals).toEqual(['x'])
|
||||
})
|
||||
Loading…
Reference in New Issue
Block a user