diff --git a/src/createContext.ts b/src/createContext.ts index b6616a456..8243a7c9c 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -10,7 +10,7 @@ import * as misc from './stdlib/misc' import * as parser from './stdlib/parser' import * as stream from './stdlib/stream' import { streamPrelude } from './stdlib/stream.prelude' -import { Context, CustomBuiltIns, Environment, Value, Variant } from './types' +import { Context, CustomBuiltIns, Environment, NativeStorage, Value, Variant } from './types' import * as operators from './utils/operators' import * as gpu_lib from './gpu/lib' import { stringify } from './utils/stringify' @@ -112,11 +112,13 @@ export const createGlobalEnvironment = (): Environment => ({ head: {} }) -const createNativeStorage = () => ({ - globals: { variables: new Map(), previousScope: null }, +const createNativeStorage = (): NativeStorage => ({ + builtins: new Map(), + previousProgramsIdentifiers: new Set(), operators: new Map(Object.entries(operators)), gpu: new Map(Object.entries(gpu_lib)), - maxExecTime: JSSLANG_PROPERTIES.maxExecTime + maxExecTime: JSSLANG_PROPERTIES.maxExecTime, + evaller: null }) export const createEmptyContext = <T>( @@ -171,10 +173,7 @@ export const defineSymbol = (context: Context, name: string, value: Value) => { writable: false, enumerable: true }) - context.nativeStorage.globals!.variables.set(name, { - kind: 'const', - getValue: () => value - }) + context.nativeStorage.builtins.set(name, value) const typeEnv = context.typeEnvironment[0] // if the global type env doesn't already have the imported symbol, // we set it to a type var T that can typecheck with anything. diff --git a/src/index.ts b/src/index.ts index c73289c7a..44d16b91c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -489,7 +489,6 @@ export async function runInContext( } let transpiled let sourceMapJson: RawSourceMap | undefined - let lastStatementSourceMapJson: RawSourceMap | undefined try { appendModulesToContext(program, context) // Mutates program @@ -502,11 +501,7 @@ export async function runInContext( break } - const temp = transpile(program, context, false) - // some issues with formatting and semicolons and tslint so no destructure - transpiled = temp.transpiled - sourceMapJson = temp.codeMap - lastStatementSourceMapJson = temp.evalMap + ;({ transpiled, codeMap: sourceMapJson } = transpile(program, context)) let value = await sandboxedEval(transpiled, context.nativeStorage, context.moduleParams) if (context.variant === 'lazy') { value = forceIt(value) @@ -544,24 +539,20 @@ export async function runInContext( } const line = Number(match![1]) const column = Number(match![2]) - return SourceMapConsumer.with( - line === 1 ? lastStatementSourceMapJson! : sourceMapJson!, - null, - consumer => { - const { - line: originalLine, - column: originalColumn, - name - } = consumer.originalPositionFor({ - line, - column - }) - context.errors.push( - convertNativeErrorToSourceError(error, originalLine, originalColumn, name) - ) - return resolvedErrorPromise - } - ) + return SourceMapConsumer.with(sourceMapJson!, null, consumer => { + const { + line: originalLine, + column: originalColumn, + name + } = consumer.originalPositionFor({ + line, + column + }) + context.errors.push( + convertNativeErrorToSourceError(error, originalLine, originalColumn, name) + ) + return resolvedErrorPromise + }) } } else { let it = evaluate(program, context) diff --git a/src/repl/transpiler.ts b/src/repl/transpiler.ts index 6726ab166..d2afc6907 100644 --- a/src/repl/transpiler.ts +++ b/src/repl/transpiler.ts @@ -29,7 +29,7 @@ function transpileCode(chapter = 1, variant: Variant = 'default', code = '', pre if (pretranspile) { return generate(program) } else { - return transpile(program as Program, context, false).transpiled + return transpile(program as Program, context).transpiled } } diff --git a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap index 0f50e7ef3..361c06462 100644 --- a/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap +++ b/src/transpiler/__tests__/__snapshots__/transpiled-code.ts.snap @@ -1,95 +1,96 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Ensure no name clashes 1`] = ` -"const native0 = nativeStorage; -const callIfFuncAndRightArgs0 = native0.operators.get(\\"callIfFuncAndRightArgs\\"); -const boolOrErr0 = native0.operators.get(\\"boolOrErr\\"); -const wrap90 = native0.operators.get(\\"wrap\\"); -const unaryOp = native0.operators.get(\\"unaryOp\\"); -const binaryOp = native0.operators.get(\\"binaryOp\\"); -const throwIfTimeout = native0.operators.get(\\"throwIfTimeout\\"); -const setProp = native0.operators.get(\\"setProp\\"); -const getProp = native0.operators.get(\\"getProp\\"); -let lastStatementResult = undefined; -const globals = native0.globals; -{ - const get_time = globals.previousScope.variables.get(\\"get_time\\").getValue(); - const display = globals.previousScope.variables.get(\\"display\\").getValue(); - const raw_display = globals.previousScope.variables.get(\\"raw_display\\").getValue(); - const stringify = globals.previousScope.variables.get(\\"stringify\\").getValue(); - const error = globals.previousScope.variables.get(\\"error\\").getValue(); - const prompt = globals.previousScope.variables.get(\\"prompt\\").getValue(); - const is_number = globals.previousScope.variables.get(\\"is_number\\").getValue(); - const is_string = globals.previousScope.variables.get(\\"is_string\\").getValue(); - const is_function = globals.previousScope.variables.get(\\"is_function\\").getValue(); - const is_boolean = globals.previousScope.variables.get(\\"is_boolean\\").getValue(); - const is_undefined = globals.previousScope.variables.get(\\"is_undefined\\").getValue(); - const parse_int = globals.previousScope.variables.get(\\"parse_int\\").getValue(); - const char_at = globals.previousScope.variables.get(\\"char_at\\").getValue(); - const undefined = globals.previousScope.variables.get(\\"undefined\\").getValue(); - const NaN = globals.previousScope.variables.get(\\"NaN\\").getValue(); - const Infinity = globals.previousScope.variables.get(\\"Infinity\\").getValue(); - const math_abs = globals.previousScope.variables.get(\\"math_abs\\").getValue(); - const math_acos = globals.previousScope.variables.get(\\"math_acos\\").getValue(); - const math_acosh = globals.previousScope.variables.get(\\"math_acosh\\").getValue(); - const math_asin = globals.previousScope.variables.get(\\"math_asin\\").getValue(); - const math_asinh = globals.previousScope.variables.get(\\"math_asinh\\").getValue(); - const math_atan = globals.previousScope.variables.get(\\"math_atan\\").getValue(); - const math_atanh = globals.previousScope.variables.get(\\"math_atanh\\").getValue(); - const math_atan2 = globals.previousScope.variables.get(\\"math_atan2\\").getValue(); - const math_ceil = globals.previousScope.variables.get(\\"math_ceil\\").getValue(); - const math_cbrt = globals.previousScope.variables.get(\\"math_cbrt\\").getValue(); - const math_expm1 = globals.previousScope.variables.get(\\"math_expm1\\").getValue(); - const math_clz32 = globals.previousScope.variables.get(\\"math_clz32\\").getValue(); - const math_cos = globals.previousScope.variables.get(\\"math_cos\\").getValue(); - const math_cosh = globals.previousScope.variables.get(\\"math_cosh\\").getValue(); - const math_exp = globals.previousScope.variables.get(\\"math_exp\\").getValue(); - const math_floor = globals.previousScope.variables.get(\\"math_floor\\").getValue(); - const math_fround = globals.previousScope.variables.get(\\"math_fround\\").getValue(); - const math_hypot = globals.previousScope.variables.get(\\"math_hypot\\").getValue(); - const math_imul = globals.previousScope.variables.get(\\"math_imul\\").getValue(); - const math_log = globals.previousScope.variables.get(\\"math_log\\").getValue(); - const math_log1p = globals.previousScope.variables.get(\\"math_log1p\\").getValue(); - const math_log2 = globals.previousScope.variables.get(\\"math_log2\\").getValue(); - const math_log10 = globals.previousScope.variables.get(\\"math_log10\\").getValue(); - const math_max = globals.previousScope.variables.get(\\"math_max\\").getValue(); - const math_min = globals.previousScope.variables.get(\\"math_min\\").getValue(); - const math_pow = globals.previousScope.variables.get(\\"math_pow\\").getValue(); - const math_random = globals.previousScope.variables.get(\\"math_random\\").getValue(); - const math_round = globals.previousScope.variables.get(\\"math_round\\").getValue(); - const math_sign = globals.previousScope.variables.get(\\"math_sign\\").getValue(); - const math_sin = globals.previousScope.variables.get(\\"math_sin\\").getValue(); - const math_sinh = globals.previousScope.variables.get(\\"math_sinh\\").getValue(); - const math_sqrt = globals.previousScope.variables.get(\\"math_sqrt\\").getValue(); - const math_tan = globals.previousScope.variables.get(\\"math_tan\\").getValue(); - const math_tanh = globals.previousScope.variables.get(\\"math_tanh\\").getValue(); - const math_trunc = globals.previousScope.variables.get(\\"math_trunc\\").getValue(); - const math_E = globals.previousScope.variables.get(\\"math_E\\").getValue(); - const math_LN10 = globals.previousScope.variables.get(\\"math_LN10\\").getValue(); - const math_LN2 = globals.previousScope.variables.get(\\"math_LN2\\").getValue(); - const math_LOG10E = globals.previousScope.variables.get(\\"math_LOG10E\\").getValue(); - const math_LOG2E = globals.previousScope.variables.get(\\"math_LOG2E\\").getValue(); - const math_PI = globals.previousScope.variables.get(\\"math_PI\\").getValue(); - const math_SQRT1_2 = globals.previousScope.variables.get(\\"math_SQRT1_2\\").getValue(); - const math_SQRT2 = globals.previousScope.variables.get(\\"math_SQRT2\\").getValue(); - const pair = globals.previousScope.variables.get(\\"pair\\").getValue(); - const is_pair = globals.previousScope.variables.get(\\"is_pair\\").getValue(); - const head = globals.previousScope.variables.get(\\"head\\").getValue(); - const tail = globals.previousScope.variables.get(\\"tail\\").getValue(); - const is_null = globals.previousScope.variables.get(\\"is_null\\").getValue(); - const list = globals.previousScope.variables.get(\\"list\\").getValue(); - const draw_data = globals.previousScope.variables.get(\\"draw_data\\").getValue(); - const display_list = globals.previousScope.variables.get(\\"display_list\\").getValue(); - const set_head = globals.previousScope.variables.get(\\"set_head\\").getValue(); - const set_tail = globals.previousScope.variables.get(\\"set_tail\\").getValue(); - const array_length = globals.previousScope.variables.get(\\"array_length\\").getValue(); - const is_array = globals.previousScope.variables.get(\\"is_array\\").getValue(); - const stream_tail = globals.previousScope.variables.get(\\"stream_tail\\").getValue(); - const stream = globals.previousScope.variables.get(\\"stream\\").getValue(); - const list_to_stream = globals.previousScope.variables.get(\\"list_to_stream\\").getValue(); - const parse = globals.previousScope.variables.get(\\"parse\\").getValue(); - const apply_in_underlying_javascript = globals.previousScope.variables.get(\\"apply_in_underlying_javascript\\").getValue(); +"{ + const get_time = nativeStorage.builtins.get(\\"get_time\\"); + const display = nativeStorage.builtins.get(\\"display\\"); + const raw_display = nativeStorage.builtins.get(\\"raw_display\\"); + const stringify = nativeStorage.builtins.get(\\"stringify\\"); + const error = nativeStorage.builtins.get(\\"error\\"); + const prompt = nativeStorage.builtins.get(\\"prompt\\"); + const is_number = nativeStorage.builtins.get(\\"is_number\\"); + const is_string = nativeStorage.builtins.get(\\"is_string\\"); + const is_function = nativeStorage.builtins.get(\\"is_function\\"); + const is_boolean = nativeStorage.builtins.get(\\"is_boolean\\"); + const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\"); + const parse_int = nativeStorage.builtins.get(\\"parse_int\\"); + const char_at = nativeStorage.builtins.get(\\"char_at\\"); + const undefined = nativeStorage.builtins.get(\\"undefined\\"); + const NaN = nativeStorage.builtins.get(\\"NaN\\"); + const Infinity = nativeStorage.builtins.get(\\"Infinity\\"); + const math_abs = nativeStorage.builtins.get(\\"math_abs\\"); + const math_acos = nativeStorage.builtins.get(\\"math_acos\\"); + const math_acosh = nativeStorage.builtins.get(\\"math_acosh\\"); + const math_asin = nativeStorage.builtins.get(\\"math_asin\\"); + const math_asinh = nativeStorage.builtins.get(\\"math_asinh\\"); + const math_atan = nativeStorage.builtins.get(\\"math_atan\\"); + const math_atanh = nativeStorage.builtins.get(\\"math_atanh\\"); + const math_atan2 = nativeStorage.builtins.get(\\"math_atan2\\"); + const math_ceil = nativeStorage.builtins.get(\\"math_ceil\\"); + const math_cbrt = nativeStorage.builtins.get(\\"math_cbrt\\"); + const math_expm1 = nativeStorage.builtins.get(\\"math_expm1\\"); + const math_clz32 = nativeStorage.builtins.get(\\"math_clz32\\"); + const math_cos = nativeStorage.builtins.get(\\"math_cos\\"); + const math_cosh = nativeStorage.builtins.get(\\"math_cosh\\"); + const math_exp = nativeStorage.builtins.get(\\"math_exp\\"); + const math_floor = nativeStorage.builtins.get(\\"math_floor\\"); + const math_fround = nativeStorage.builtins.get(\\"math_fround\\"); + const math_hypot = nativeStorage.builtins.get(\\"math_hypot\\"); + const math_imul = nativeStorage.builtins.get(\\"math_imul\\"); + const math_log = nativeStorage.builtins.get(\\"math_log\\"); + const math_log1p = nativeStorage.builtins.get(\\"math_log1p\\"); + const math_log2 = nativeStorage.builtins.get(\\"math_log2\\"); + const math_log10 = nativeStorage.builtins.get(\\"math_log10\\"); + const math_max = nativeStorage.builtins.get(\\"math_max\\"); + const math_min = nativeStorage.builtins.get(\\"math_min\\"); + const math_pow = nativeStorage.builtins.get(\\"math_pow\\"); + const math_random = nativeStorage.builtins.get(\\"math_random\\"); + const math_round = nativeStorage.builtins.get(\\"math_round\\"); + const math_sign = nativeStorage.builtins.get(\\"math_sign\\"); + const math_sin = nativeStorage.builtins.get(\\"math_sin\\"); + const math_sinh = nativeStorage.builtins.get(\\"math_sinh\\"); + const math_sqrt = nativeStorage.builtins.get(\\"math_sqrt\\"); + const math_tan = nativeStorage.builtins.get(\\"math_tan\\"); + const math_tanh = nativeStorage.builtins.get(\\"math_tanh\\"); + const math_trunc = nativeStorage.builtins.get(\\"math_trunc\\"); + const math_E = nativeStorage.builtins.get(\\"math_E\\"); + const math_LN10 = nativeStorage.builtins.get(\\"math_LN10\\"); + const math_LN2 = nativeStorage.builtins.get(\\"math_LN2\\"); + const math_LOG10E = nativeStorage.builtins.get(\\"math_LOG10E\\"); + const math_LOG2E = nativeStorage.builtins.get(\\"math_LOG2E\\"); + const math_PI = nativeStorage.builtins.get(\\"math_PI\\"); + const math_SQRT1_2 = nativeStorage.builtins.get(\\"math_SQRT1_2\\"); + const math_SQRT2 = nativeStorage.builtins.get(\\"math_SQRT2\\"); + const pair = nativeStorage.builtins.get(\\"pair\\"); + const is_pair = nativeStorage.builtins.get(\\"is_pair\\"); + const head = nativeStorage.builtins.get(\\"head\\"); + const tail = nativeStorage.builtins.get(\\"tail\\"); + const is_null = nativeStorage.builtins.get(\\"is_null\\"); + const list = nativeStorage.builtins.get(\\"list\\"); + const draw_data = nativeStorage.builtins.get(\\"draw_data\\"); + const display_list = nativeStorage.builtins.get(\\"display_list\\"); + const set_head = nativeStorage.builtins.get(\\"set_head\\"); + const set_tail = nativeStorage.builtins.get(\\"set_tail\\"); + const array_length = nativeStorage.builtins.get(\\"array_length\\"); + const is_array = nativeStorage.builtins.get(\\"is_array\\"); + const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\"); + const stream = nativeStorage.builtins.get(\\"stream\\"); + const list_to_stream = nativeStorage.builtins.get(\\"list_to_stream\\"); + const parse = nativeStorage.builtins.get(\\"parse\\"); + const apply_in_underlying_javascript = nativeStorage.builtins.get(\\"apply_in_underlying_javascript\\"); { + const native0 = nativeStorage; + const callIfFuncAndRightArgs0 = native0.operators.get(\\"callIfFuncAndRightArgs\\"); + const boolOrErr0 = native0.operators.get(\\"boolOrErr\\"); + const wrap90 = native0.operators.get(\\"wrap\\"); + const unaryOp = native0.operators.get(\\"unaryOp\\"); + const binaryOp = native0.operators.get(\\"binaryOp\\"); + const throwIfTimeout = native0.operators.get(\\"throwIfTimeout\\"); + const setProp = native0.operators.get(\\"setProp\\"); + const getProp = native0.operators.get(\\"getProp\\"); + const builtins = native0.operators.get(\\"builtins\\"); + native0.evaller = program => eval(program); + undefined; const boolOrErr = 1; setProp(boolOrErr, 123, 1, 2, 0); const f = wrap90((callIfFuncAndRightArgs, wrap0, wrap1, wrap2, wrap3, wrap4, wrap5, wrap6, wrap7, wrap8, wrap9) => { @@ -106,126 +107,107 @@ const globals = native0.globals; wrap9; }, \\"function f(callIfFuncAndRightArgs, wrap0, wrap1, wrap2, wrap3, wrap4, wrap5, wrap6, wrap7, wrap8, wrap9) {\\\\n let wrap = 2;\\\\n wrap0;\\\\n wrap1;\\\\n wrap2;\\\\n wrap3;\\\\n wrap4;\\\\n wrap5;\\\\n wrap6;\\\\n wrap7;\\\\n wrap8;\\\\n wrap9;\\\\n}\\", native0); const native = 123; - globals.variables.set(\\"boolOrErr\\", { - kind: \\"const\\", - getValue: () => { - return boolOrErr; - } - }); - globals.variables.set(\\"f\\", { - kind: \\"const\\", - getValue: () => { - return f; - } - }); - globals.variables.set(\\"native\\", { - kind: \\"const\\", - getValue: () => { - return native; - } - }); } } -lastStatementResult; " `; exports[`builtins do get prepended 1`] = ` Object { "code": "\\"ensure_builtins\\";", - "transpiled": "const native = nativeStorage; -const callIfFuncAndRightArgs = native.operators.get(\\"callIfFuncAndRightArgs\\"); -const boolOrErr = native.operators.get(\\"boolOrErr\\"); -const wrap = native.operators.get(\\"wrap\\"); -const unaryOp = native.operators.get(\\"unaryOp\\"); -const binaryOp = native.operators.get(\\"binaryOp\\"); -const throwIfTimeout = native.operators.get(\\"throwIfTimeout\\"); -const setProp = native.operators.get(\\"setProp\\"); -const getProp = native.operators.get(\\"getProp\\"); -let lastStatementResult = undefined; -const globals = native.globals; -{ - const get_time = globals.previousScope.variables.get(\\"get_time\\").getValue(); - const display = globals.previousScope.variables.get(\\"display\\").getValue(); - const raw_display = globals.previousScope.variables.get(\\"raw_display\\").getValue(); - const stringify = globals.previousScope.variables.get(\\"stringify\\").getValue(); - const error = globals.previousScope.variables.get(\\"error\\").getValue(); - const prompt = globals.previousScope.variables.get(\\"prompt\\").getValue(); - const is_number = globals.previousScope.variables.get(\\"is_number\\").getValue(); - const is_string = globals.previousScope.variables.get(\\"is_string\\").getValue(); - const is_function = globals.previousScope.variables.get(\\"is_function\\").getValue(); - const is_boolean = globals.previousScope.variables.get(\\"is_boolean\\").getValue(); - const is_undefined = globals.previousScope.variables.get(\\"is_undefined\\").getValue(); - const parse_int = globals.previousScope.variables.get(\\"parse_int\\").getValue(); - const char_at = globals.previousScope.variables.get(\\"char_at\\").getValue(); - const undefined = globals.previousScope.variables.get(\\"undefined\\").getValue(); - const NaN = globals.previousScope.variables.get(\\"NaN\\").getValue(); - const Infinity = globals.previousScope.variables.get(\\"Infinity\\").getValue(); - const math_abs = globals.previousScope.variables.get(\\"math_abs\\").getValue(); - const math_acos = globals.previousScope.variables.get(\\"math_acos\\").getValue(); - const math_acosh = globals.previousScope.variables.get(\\"math_acosh\\").getValue(); - const math_asin = globals.previousScope.variables.get(\\"math_asin\\").getValue(); - const math_asinh = globals.previousScope.variables.get(\\"math_asinh\\").getValue(); - const math_atan = globals.previousScope.variables.get(\\"math_atan\\").getValue(); - const math_atanh = globals.previousScope.variables.get(\\"math_atanh\\").getValue(); - const math_atan2 = globals.previousScope.variables.get(\\"math_atan2\\").getValue(); - const math_ceil = globals.previousScope.variables.get(\\"math_ceil\\").getValue(); - const math_cbrt = globals.previousScope.variables.get(\\"math_cbrt\\").getValue(); - const math_expm1 = globals.previousScope.variables.get(\\"math_expm1\\").getValue(); - const math_clz32 = globals.previousScope.variables.get(\\"math_clz32\\").getValue(); - const math_cos = globals.previousScope.variables.get(\\"math_cos\\").getValue(); - const math_cosh = globals.previousScope.variables.get(\\"math_cosh\\").getValue(); - const math_exp = globals.previousScope.variables.get(\\"math_exp\\").getValue(); - const math_floor = globals.previousScope.variables.get(\\"math_floor\\").getValue(); - const math_fround = globals.previousScope.variables.get(\\"math_fround\\").getValue(); - const math_hypot = globals.previousScope.variables.get(\\"math_hypot\\").getValue(); - const math_imul = globals.previousScope.variables.get(\\"math_imul\\").getValue(); - const math_log = globals.previousScope.variables.get(\\"math_log\\").getValue(); - const math_log1p = globals.previousScope.variables.get(\\"math_log1p\\").getValue(); - const math_log2 = globals.previousScope.variables.get(\\"math_log2\\").getValue(); - const math_log10 = globals.previousScope.variables.get(\\"math_log10\\").getValue(); - const math_max = globals.previousScope.variables.get(\\"math_max\\").getValue(); - const math_min = globals.previousScope.variables.get(\\"math_min\\").getValue(); - const math_pow = globals.previousScope.variables.get(\\"math_pow\\").getValue(); - const math_random = globals.previousScope.variables.get(\\"math_random\\").getValue(); - const math_round = globals.previousScope.variables.get(\\"math_round\\").getValue(); - const math_sign = globals.previousScope.variables.get(\\"math_sign\\").getValue(); - const math_sin = globals.previousScope.variables.get(\\"math_sin\\").getValue(); - const math_sinh = globals.previousScope.variables.get(\\"math_sinh\\").getValue(); - const math_sqrt = globals.previousScope.variables.get(\\"math_sqrt\\").getValue(); - const math_tan = globals.previousScope.variables.get(\\"math_tan\\").getValue(); - const math_tanh = globals.previousScope.variables.get(\\"math_tanh\\").getValue(); - const math_trunc = globals.previousScope.variables.get(\\"math_trunc\\").getValue(); - const math_E = globals.previousScope.variables.get(\\"math_E\\").getValue(); - const math_LN10 = globals.previousScope.variables.get(\\"math_LN10\\").getValue(); - const math_LN2 = globals.previousScope.variables.get(\\"math_LN2\\").getValue(); - const math_LOG10E = globals.previousScope.variables.get(\\"math_LOG10E\\").getValue(); - const math_LOG2E = globals.previousScope.variables.get(\\"math_LOG2E\\").getValue(); - const math_PI = globals.previousScope.variables.get(\\"math_PI\\").getValue(); - const math_SQRT1_2 = globals.previousScope.variables.get(\\"math_SQRT1_2\\").getValue(); - const math_SQRT2 = globals.previousScope.variables.get(\\"math_SQRT2\\").getValue(); - const pair = globals.previousScope.variables.get(\\"pair\\").getValue(); - const is_pair = globals.previousScope.variables.get(\\"is_pair\\").getValue(); - const head = globals.previousScope.variables.get(\\"head\\").getValue(); - const tail = globals.previousScope.variables.get(\\"tail\\").getValue(); - const is_null = globals.previousScope.variables.get(\\"is_null\\").getValue(); - const list = globals.previousScope.variables.get(\\"list\\").getValue(); - const draw_data = globals.previousScope.variables.get(\\"draw_data\\").getValue(); - const display_list = globals.previousScope.variables.get(\\"display_list\\").getValue(); - const set_head = globals.previousScope.variables.get(\\"set_head\\").getValue(); - const set_tail = globals.previousScope.variables.get(\\"set_tail\\").getValue(); - const array_length = globals.previousScope.variables.get(\\"array_length\\").getValue(); - const is_array = globals.previousScope.variables.get(\\"is_array\\").getValue(); - const stream_tail = globals.previousScope.variables.get(\\"stream_tail\\").getValue(); - const stream = globals.previousScope.variables.get(\\"stream\\").getValue(); - const list_to_stream = globals.previousScope.variables.get(\\"list_to_stream\\").getValue(); - const parse = globals.previousScope.variables.get(\\"parse\\").getValue(); - const apply_in_underlying_javascript = globals.previousScope.variables.get(\\"apply_in_underlying_javascript\\").getValue(); + "transpiled": "{ + const get_time = nativeStorage.builtins.get(\\"get_time\\"); + const display = nativeStorage.builtins.get(\\"display\\"); + const raw_display = nativeStorage.builtins.get(\\"raw_display\\"); + const stringify = nativeStorage.builtins.get(\\"stringify\\"); + const error = nativeStorage.builtins.get(\\"error\\"); + const prompt = nativeStorage.builtins.get(\\"prompt\\"); + const is_number = nativeStorage.builtins.get(\\"is_number\\"); + const is_string = nativeStorage.builtins.get(\\"is_string\\"); + const is_function = nativeStorage.builtins.get(\\"is_function\\"); + const is_boolean = nativeStorage.builtins.get(\\"is_boolean\\"); + const is_undefined = nativeStorage.builtins.get(\\"is_undefined\\"); + const parse_int = nativeStorage.builtins.get(\\"parse_int\\"); + const char_at = nativeStorage.builtins.get(\\"char_at\\"); + const undefined = nativeStorage.builtins.get(\\"undefined\\"); + const NaN = nativeStorage.builtins.get(\\"NaN\\"); + const Infinity = nativeStorage.builtins.get(\\"Infinity\\"); + const math_abs = nativeStorage.builtins.get(\\"math_abs\\"); + const math_acos = nativeStorage.builtins.get(\\"math_acos\\"); + const math_acosh = nativeStorage.builtins.get(\\"math_acosh\\"); + const math_asin = nativeStorage.builtins.get(\\"math_asin\\"); + const math_asinh = nativeStorage.builtins.get(\\"math_asinh\\"); + const math_atan = nativeStorage.builtins.get(\\"math_atan\\"); + const math_atanh = nativeStorage.builtins.get(\\"math_atanh\\"); + const math_atan2 = nativeStorage.builtins.get(\\"math_atan2\\"); + const math_ceil = nativeStorage.builtins.get(\\"math_ceil\\"); + const math_cbrt = nativeStorage.builtins.get(\\"math_cbrt\\"); + const math_expm1 = nativeStorage.builtins.get(\\"math_expm1\\"); + const math_clz32 = nativeStorage.builtins.get(\\"math_clz32\\"); + const math_cos = nativeStorage.builtins.get(\\"math_cos\\"); + const math_cosh = nativeStorage.builtins.get(\\"math_cosh\\"); + const math_exp = nativeStorage.builtins.get(\\"math_exp\\"); + const math_floor = nativeStorage.builtins.get(\\"math_floor\\"); + const math_fround = nativeStorage.builtins.get(\\"math_fround\\"); + const math_hypot = nativeStorage.builtins.get(\\"math_hypot\\"); + const math_imul = nativeStorage.builtins.get(\\"math_imul\\"); + const math_log = nativeStorage.builtins.get(\\"math_log\\"); + const math_log1p = nativeStorage.builtins.get(\\"math_log1p\\"); + const math_log2 = nativeStorage.builtins.get(\\"math_log2\\"); + const math_log10 = nativeStorage.builtins.get(\\"math_log10\\"); + const math_max = nativeStorage.builtins.get(\\"math_max\\"); + const math_min = nativeStorage.builtins.get(\\"math_min\\"); + const math_pow = nativeStorage.builtins.get(\\"math_pow\\"); + const math_random = nativeStorage.builtins.get(\\"math_random\\"); + const math_round = nativeStorage.builtins.get(\\"math_round\\"); + const math_sign = nativeStorage.builtins.get(\\"math_sign\\"); + const math_sin = nativeStorage.builtins.get(\\"math_sin\\"); + const math_sinh = nativeStorage.builtins.get(\\"math_sinh\\"); + const math_sqrt = nativeStorage.builtins.get(\\"math_sqrt\\"); + const math_tan = nativeStorage.builtins.get(\\"math_tan\\"); + const math_tanh = nativeStorage.builtins.get(\\"math_tanh\\"); + const math_trunc = nativeStorage.builtins.get(\\"math_trunc\\"); + const math_E = nativeStorage.builtins.get(\\"math_E\\"); + const math_LN10 = nativeStorage.builtins.get(\\"math_LN10\\"); + const math_LN2 = nativeStorage.builtins.get(\\"math_LN2\\"); + const math_LOG10E = nativeStorage.builtins.get(\\"math_LOG10E\\"); + const math_LOG2E = nativeStorage.builtins.get(\\"math_LOG2E\\"); + const math_PI = nativeStorage.builtins.get(\\"math_PI\\"); + const math_SQRT1_2 = nativeStorage.builtins.get(\\"math_SQRT1_2\\"); + const math_SQRT2 = nativeStorage.builtins.get(\\"math_SQRT2\\"); + const pair = nativeStorage.builtins.get(\\"pair\\"); + const is_pair = nativeStorage.builtins.get(\\"is_pair\\"); + const head = nativeStorage.builtins.get(\\"head\\"); + const tail = nativeStorage.builtins.get(\\"tail\\"); + const is_null = nativeStorage.builtins.get(\\"is_null\\"); + const list = nativeStorage.builtins.get(\\"list\\"); + const draw_data = nativeStorage.builtins.get(\\"draw_data\\"); + const display_list = nativeStorage.builtins.get(\\"display_list\\"); + const set_head = nativeStorage.builtins.get(\\"set_head\\"); + const set_tail = nativeStorage.builtins.get(\\"set_tail\\"); + const array_length = nativeStorage.builtins.get(\\"array_length\\"); + const is_array = nativeStorage.builtins.get(\\"is_array\\"); + const stream_tail = nativeStorage.builtins.get(\\"stream_tail\\"); + const stream = nativeStorage.builtins.get(\\"stream\\"); + const list_to_stream = nativeStorage.builtins.get(\\"list_to_stream\\"); + const parse = nativeStorage.builtins.get(\\"parse\\"); + const apply_in_underlying_javascript = nativeStorage.builtins.get(\\"apply_in_underlying_javascript\\"); { - lastStatementResult = eval(\\"\\\\\\"ensure_builtins\\\\\\";\\"); + const native = nativeStorage; + const callIfFuncAndRightArgs = native.operators.get(\\"callIfFuncAndRightArgs\\"); + const boolOrErr = native.operators.get(\\"boolOrErr\\"); + const wrap = native.operators.get(\\"wrap\\"); + const unaryOp = native.operators.get(\\"unaryOp\\"); + const binaryOp = native.operators.get(\\"binaryOp\\"); + const throwIfTimeout = native.operators.get(\\"throwIfTimeout\\"); + const setProp = native.operators.get(\\"setProp\\"); + const getProp = native.operators.get(\\"getProp\\"); + const builtins = native.operators.get(\\"builtins\\"); + native.evaller = program => eval(program); + undefined; + \\"ensure_builtins\\"; } } -lastStatementResult; ", } `; diff --git a/src/transpiler/evalContainer.ts b/src/transpiler/evalContainer.ts index 81484bd67..627ce776f 100644 --- a/src/transpiler/evalContainer.ts +++ b/src/transpiler/evalContainer.ts @@ -13,6 +13,10 @@ export const sandboxedEval: Evaler = new Function( NATIVE_STORAGE_ID, MODULE_PARAMS_ID, ` -return eval(code) + if (${NATIVE_STORAGE_ID}.evaller === null) { + return eval(code); + } else { + return ${NATIVE_STORAGE_ID}.evaller(code); + } ` ) as Evaler diff --git a/src/transpiler/transpiler.ts b/src/transpiler/transpiler.ts index a6ee75781..44e65aca8 100644 --- a/src/transpiler/transpiler.ts +++ b/src/transpiler/transpiler.ts @@ -1,9 +1,9 @@ import { ancestor, simple } from '../utils/walkers' import { generate } from 'astring' import * as es from 'estree' -import { RawSourceMap, SourceMapGenerator } from 'source-map' -import { AllowedDeclarations, Context, NativeStorage, ValueWrapper } from '../types' -import { ConstAssignment, UndefinedVariable } from '../errors/errors' +import { SourceMapGenerator } from 'source-map' +import { AllowedDeclarations, Context, NativeStorage } from '../types' +import { UndefinedVariable } from '../errors/errors' import { memoizedGetModuleFile } from '../modules/moduleLoader' import * as create from '../utils/astCreator' import { @@ -29,8 +29,7 @@ const globalIdNames = [ 'throwIfTimeout', 'setProp', 'getProp', - 'lastStatementResult', - 'globals' + 'builtins' ] as const export type NativeIds = Record<typeof globalIdNames[number], es.Identifier> @@ -96,79 +95,7 @@ export function transformImportDeclarations(program: es.Program) { program.body = (result as (es.Statement | es.ModuleDeclaration)[]).concat(program.body) } -function createStatementAstToStoreBackCurrentlyDeclaredGlobal( - name: string, - kind: AllowedDeclarations, - globalIds: NativeIds, - usedIdentifiers: Set<string> -): es.ExpressionStatement { - const paramName = create.identifier(getUniqueId(usedIdentifiers)) - const variableIdentifier = create.identifier(name) - const properties = [ - create.property('kind', create.literal(kind)), - create.property( - 'getValue', - create.blockArrowFunction([], [create.returnStatement(variableIdentifier)]) - ) - ] - if (kind === 'let') { - properties.push( - create.property( - 'assignNewValue', - create.functionExpression( - [paramName], - [create.returnStatement(create.assignmentExpression(variableIdentifier, paramName))] - ) - ) - ) - } - return create.expressionStatement( - create.callExpression( - create.memberExpression(create.memberExpression(globalIds.globals, 'variables'), 'set'), - [create.literal(name), create.objectExpression(properties)] - ) - ) -} - -function wrapWithPreviouslyDeclaredGlobals( - statements: es.Statement[], - nativeStorage: NativeStorage, - globalIds: NativeIds -) { - let currentVariableScope = nativeStorage.globals!.previousScope - let timesToGoUp = 1 - let wrapped = create.blockStatement(statements) - while (currentVariableScope !== null) { - const initialisingStatements: es.Statement[] = [] - currentVariableScope.variables.forEach(({ kind }: ValueWrapper, name: string) => { - let unwrappedValueAst: es.Expression = globalIds.globals - for (let i = 0; i < timesToGoUp; i += 1) { - unwrappedValueAst = create.memberExpression(unwrappedValueAst, 'previousScope') - } - unwrappedValueAst = create.callExpression( - create.memberExpression( - create.callExpression( - create.memberExpression(create.memberExpression(unwrappedValueAst, 'variables'), 'get'), - [create.literal(name)] - ), - 'getValue' - ), - [] - ) - initialisingStatements.push(create.declaration(name, kind, unwrappedValueAst)) - }) - timesToGoUp += 1 - currentVariableScope = currentVariableScope.previousScope - wrapped = create.blockStatement([...initialisingStatements, wrapped]) - } - return wrapped -} - -function createStatementsToStoreCurrentlyDeclaredGlobals( - program: es.Program, - globalIds: NativeIds, - usedIdentifiers: Set<string> -) { +function getGloballyDeclaredIdentifiers(program: es.Program): string[] { return program.body .filter(statement => statement.type === 'VariableDeclaration') .map( @@ -177,13 +104,7 @@ function createStatementsToStoreCurrentlyDeclaredGlobals( 0: { id } }, kind - }: es.VariableDeclaration) => - createStatementAstToStoreBackCurrentlyDeclaredGlobal( - (id as es.Identifier).name, - kind as AllowedDeclarations, - globalIds, - usedIdentifiers - ) + }: es.VariableDeclaration) => (id as es.Identifier).name ) } @@ -337,46 +258,13 @@ function transformCallExpressionsToCheckIfFunction(program: es.Program, globalId }) } -export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBackNewValue( +export function checkForUndefinedVariables( program: es.Program, - skipErrors = false, nativeStorage: NativeStorage, - globalIds: NativeIds + globalIds: NativeIds, + skipUndefined: boolean ) { - const globalEnvironment = nativeStorage.globals - const previousVariablesToAst = new Map< - string, - { isConstant: boolean; variableLocationId: es.Expression } - >() - let variableScope = globalEnvironment - let variableScopeId: es.Expression = globalIds.globals - while (variableScope !== null) { - for (const [name, { kind }] of variableScope.variables) { - if (!previousVariablesToAst.has(name)) { - previousVariablesToAst.set(name, { - isConstant: kind === 'const', - variableLocationId: create.callExpression( - create.memberExpression(create.memberExpression(variableScopeId, 'variables'), 'get'), - [create.literal(name)] - ) - }) - } - } - variableScope = variableScope.previousScope - variableScopeId = create.memberExpression(variableScopeId, 'previousScope') - } - for (const node of program.body) { - if (node.type !== 'ImportDeclaration') { - break - } - const symbols = node.specifiers.map(specifier => specifier.local.name) - for (const symbol of symbols) { - previousVariablesToAst.set(symbol, { - isConstant: true, - variableLocationId: create.literal(-1) - }) - } - } + const builtins = nativeStorage.builtins const identifiersIntroducedByNode = new Map<es.Node, Set<string>>() function processBlock(node: es.Program | es.BlockStatement) { const identifiers = new Set<string>() @@ -391,7 +279,7 @@ export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBack } function processFunction( node: es.FunctionDeclaration | es.ArrowFunctionExpression, - ancestors: es.Node[] + _ancestors: es.Node[] ) { identifiersIntroducedByNode.set( node, @@ -431,74 +319,20 @@ export function checkForUndefinedVariablesAndTransformAssignmentsToPropagateBack for (const [identifier, ancestors] of identifiersToAncestors) { const name = identifier.name const isCurrentlyDeclared = ancestors.some(a => identifiersIntroducedByNode.get(a)?.has(name)) - if (!isCurrentlyDeclared) { - if (previousVariablesToAst.has(name)) { - const lastAncestor: es.Node = ancestors[ancestors.length - 2] - const { isConstant, variableLocationId } = previousVariablesToAst.get(name)! - if (lastAncestor.type === 'AssignmentExpression' && lastAncestor.left === identifier) { - // if this is an assignment expression, we want to propagate back the change - if (isConstant) { - throw new ConstAssignment(identifier, name) - } else { - lastAncestor.right = create.callExpression( - create.memberExpression(variableLocationId, 'assignNewValue'), - [lastAncestor.right] - ) - } - } else { - /** - * if this is not the left side of an assignment expression, we need to replace this with - * the actual value stored in the correct scope, as calling functions defined in a - * previous block might have side effects that change the variable. - * e.g. - * // first eval: - * let counter = 0; - * function f() { - * counter = counter + 1; - * } - * becomes - * let counter = 0; - * function f() { - * counter = counter + 1; - * } - * variables.set("counter", getValue: ()=>counter, assignNewValue: newValue => counter = newValue); - * // second eval (wrong): - * f(); counter; - * becomes - * let counter = variables.get("counter").getValue(); // set back counter; - * { - * f(); // this has a side effect of incrementing counter - * return counter; // that does not get propagated here - * } - * // second eval (fixed): - * f(); counter; - * becomes - * let counter = variables.get("counter").getValue(); // set back counter; - * { - * f(); // this has a side effect of incrementing counter - * return (counter = variables.get("counter").getValue()); // we have no choice but to - * // always assume that counter is updated through a side effect and always retrieve its - * // real value - * } - */ - if (!isConstant) { - // if it is a constant, it will definitely not mutate so above change is not needed - const toExpression: es.AssignmentExpression = - identifier as unknown as es.AssignmentExpression - toExpression.type = 'AssignmentExpression' - toExpression.operator = '=' - toExpression.left = create.identifier(name) - toExpression.right = create.callExpression( - create.memberExpression(variableLocationId, 'getValue'), - [] - ) - } - } - } else if (!nativeInternalNames.has(name)) { - if (!skipErrors) { - throw new UndefinedVariable(name, identifier) - } - } + if (isCurrentlyDeclared) { + continue + } + const isPreviouslyDeclared = nativeStorage.previousProgramsIdentifiers.has(name) + if (isPreviouslyDeclared) { + continue + } + const isBuiltin = builtins.has(name) + if (isBuiltin) { + continue + } + const isNativeId = nativeInternalNames.has(name) + if (!isNativeId && !skipUndefined) { + throw new UndefinedVariable(name, identifier) } } } @@ -538,55 +372,6 @@ function getNativeIds(program: es.Program, usedIdentifiers: Set<string>): Native return globalIds as NativeIds } -/** - * statement1; - * statement2; - * ... - * const a = 1; //lastStatement example 1 (should give undefined) - * 1 + 1; //lastStatement example 2 (should give 2) - * b = fun(5); //lastStatement example 3 (should set b to fun(5)) - * if (true) { true; } else { false; } //lastStatement example 4 (should give true) - * for (let i = 0; i < 5; i = i + 1) { i; } //lastStatement example 5 (should give 4) - * - * We want to preserve the last evaluated statement's result to return back, so - * for const/let declarations we simply don't change anything, and return undefined - * at the end. - * - * For others, we will convert it into a string, wrap it in an eval, and store - * the result in a temporary variable. e.g. - * - * const tempVar = eval("1+1;"); - * const tempVar = eval("if (true) { true; } else { false; }"); - * etc etc... - * now at the end of all the appended statements we can do - * return tempVar; - */ - -function splitLastStatementIntoStorageOfResultAndAccessorPair( - lastStatement: es.Statement, - globalIds: NativeIds -): { lastStatementStoredInResult: es.Statement; evalMap?: RawSourceMap } { - if (lastStatement.type === 'VariableDeclaration') { - return { - lastStatementStoredInResult: lastStatement - } - } - const map = new SourceMapGenerator({ file: 'lastline' }) - const lastStatementAsCode = generate(lastStatement, { lineEnd: ' ', sourceMap: map, version: 3 }) - const uniqueDeclarationToStoreLastStatementResult = create.expressionStatement( - create.assignmentExpression( - globalIds.lastStatementResult, - create.callExpression(create.identifier('eval'), [ - create.literal(lastStatementAsCode, lastStatement.loc!) - ]) - ) - ) - return { - lastStatementStoredInResult: uniqueDeclarationToStoreLastStatementResult, - evalMap: map.toJSON() - } -} - function transformUnaryAndBinaryOperationsToFunctionCalls( program: es.Program, globalIds: NativeIds, @@ -694,20 +479,46 @@ function addInfiniteLoopProtection( }) } -export function transpile( - program: es.Program, - context: Context, - skipUndefinedVariableErrors = false +function evallerReplacer(globalIds: NativeIds): es.ExpressionStatement { + const arg = create.identifier('program') + return create.expressionStatement( + create.assignmentExpression( + create.memberExpression(globalIds.native, 'evaller'), + create.arrowFunctionExpression([arg], create.callExpression(create.identifier('eval'), [arg])) + ) + ) +} + +function wrapWithBuiltins( + statements: es.Statement[], + nativeStorage: NativeStorage, + globalIds: NativeIds ) { + const initialisingStatements: es.Statement[] = [] + nativeStorage.builtins.forEach((_unused, name: string) => { + initialisingStatements.push( + create.declaration( + name, + 'const', + create.callExpression( + create.memberExpression( + create.memberExpression(create.identifier(NATIVE_STORAGE_ID), 'builtins'), + 'get' + ), + [create.literal(name)] + ) + ) + ) + }) + return create.blockStatement([...initialisingStatements, create.blockStatement(statements)]) +} + +export function transpile(program: es.Program, context: Context, skipUndefined = false) { const usedIdentifiers = new Set<string>([ ...getIdentifiersInProgram(program), ...getIdentifiersInNativeStorage(context.nativeStorage) ]) const globalIds = getNativeIds(program, usedIdentifiers) - context.nativeStorage.globals = { - variables: new Map(), - previousScope: context.nativeStorage.globals - } if (program.body.length === 0) { return { transpiled: '' } } @@ -720,43 +531,33 @@ export function transpile( transformSomeExpressionsToCheckIfBoolean(program, globalIds) transformPropertyAssignment(program, globalIds) transformPropertyAccess(program, globalIds) - checkForUndefinedVariablesAndTransformAssignmentsToPropagateBackNewValue( - program, - skipUndefinedVariableErrors, - context.nativeStorage, - globalIds - ) + checkForUndefinedVariables(program, context.nativeStorage, globalIds, skipUndefined) transformFunctionDeclarationsToArrowFunctions(program, functionsToStringMap) wrapArrowFunctionsToAllowNormalCallsAndNiceToString(program, functionsToStringMap, globalIds) addInfiniteLoopProtection(program, globalIds, usedIdentifiers) const modulePrefix = prefixModule(program) transformImportDeclarations(program) - const statementsToSaveDeclaredGlobals = createStatementsToStoreCurrentlyDeclaredGlobals( - program, - globalIds, - usedIdentifiers + getGloballyDeclaredIdentifiers(program).forEach(id => + context.nativeStorage.previousProgramsIdentifiers.add(id) ) const statements = program.body as es.Statement[] - const lastStatement = statements.pop() as es.Statement - const { lastStatementStoredInResult, evalMap } = - splitLastStatementIntoStorageOfResultAndAccessorPair(lastStatement, globalIds) - - const body = [ - wrapWithPreviouslyDeclaredGlobals( - [...statements, lastStatementStoredInResult, ...statementsToSaveDeclaredGlobals], - context.nativeStorage, - globalIds - ), - create.expressionStatement(globalIds.lastStatementResult) + const newStatements = [ + ...getDeclarationsToAccessTranspilerInternals(globalIds), + evallerReplacer(globalIds), + create.expressionStatement(create.identifier('undefined')), + ...statements ] - program.body = [...getDeclarationsToAccessTranspilerInternals(globalIds), ...body] + program.body = + context.nativeStorage.evaller === null + ? [wrapWithBuiltins(newStatements, context.nativeStorage, globalIds)] + : [create.blockStatement(newStatements)] const map = new SourceMapGenerator({ file: 'source' }) const transpiled = modulePrefix + generate(program, { sourceMap: map }) const codeMap = map.toJSON() - return { transpiled, codeMap, evalMap } + return { transpiled, codeMap } } function getDeclarationsToAccessTranspilerInternals( @@ -764,12 +565,9 @@ function getDeclarationsToAccessTranspilerInternals( ): es.VariableDeclaration[] { return Object.entries(globalIds).map(([key, { name }]) => { let value: es.Expression - let kind: AllowedDeclarations = 'const' + const kind: AllowedDeclarations = 'const' if (key === 'native') { value = create.identifier(NATIVE_STORAGE_ID) - } else if (key === 'lastStatementResult') { - value = create.primitive(undefined) - kind = 'let' } else if (key === 'globals') { value = create.memberExpression(globalIds.native, 'globals') } else { diff --git a/src/types.ts b/src/types.ts index a21b1a9b8..da7aa3d91 100644 --- a/src/types.ts +++ b/src/types.ts @@ -78,16 +78,18 @@ export interface ConstWrapper { getValue: () => Value } -export interface Globals { - variables: Map<string, ValueWrapper> - previousScope: Globals | null -} - export interface NativeStorage { - globals: Globals | null + builtins: Map<string, Value> + previousProgramsIdentifiers: Set<string> operators: Map<string, (...operands: Value[]) => Value> gpu: Map<string, (...operands: Value[]) => Value> maxExecTime: number + evaller: null | ((program: string) => Value) + /* + the first time evaller is used, it must be used directly like `eval(code)` to inherit + surrounding scope, so we cannot set evaller to `eval` directly. subsequent assignments to evaller will + close in the surrounding values, so no problem + */ } export interface Context<T = any> { diff --git a/src/utils/testing.ts b/src/utils/testing.ts index 59145e096..85a007474 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -115,9 +115,10 @@ async function testInContext(code: string, options: TestOptions): Promise<TestRe const nativeTestContext = createTestContext(options) let pretranspiled: string = '' let transpiled: string = '' - let parsed - try { - parsed = parse(code, nativeTestContext)! + const parsed = parse(code, nativeTestContext)! + if (parsed === undefined) { + pretranspiled = 'parseError' + } else { // Mutates program switch (options.variant) { case 'gpu': @@ -132,15 +133,11 @@ async function testInContext(code: string, options: TestOptions): Promise<TestRe try { transpiled = transpile(parsed, nativeTestContext, true).transpiled // replace declaration of builtins since they're repetitive - transpiled = transpiled.replace( - /\n const \w+ = globals\.(previousScope.)+variables.get\("\w+"\)\.getValue\(\);/g, - '' - ) + transpiled = transpiled.replace(/\n const \w+ = nativeStorage\..*;/g, '') + transpiled = transpiled.replace(/\n\s*const \w+ = .*\.operators\..*;/g, '') } catch { transpiled = 'parseError' } - } catch { - pretranspiled = 'parseError' } const nativeResult = getTestResult( nativeTestContext, diff --git a/src/utils/uniqueIds.ts b/src/utils/uniqueIds.ts index 7a8c4bea5..cdeac5e74 100644 --- a/src/utils/uniqueIds.ts +++ b/src/utils/uniqueIds.ts @@ -18,15 +18,9 @@ export function getUniqueId(usedIdentifiers: Set<string>, uniqueId = 'unique') { } export function getIdentifiersInNativeStorage(nativeStorage: NativeStorage) { - const identifiers = new Set<string>() - let variableScope = nativeStorage.globals - while (variableScope !== null) { - for (const name of variableScope.variables.keys()) { - identifiers.add(name) - } - variableScope = variableScope.previousScope - } - return identifiers + const used = new Set(...nativeStorage.builtins.keys()) + nativeStorage.previousProgramsIdentifiers.forEach(id => used.add(id)) + return used } export function getIdentifiersInProgram(program: es.Program) { diff --git a/src/vm/svml-machine.ts b/src/vm/svml-machine.ts index e66bc8b6e..e7d75c440 100644 --- a/src/vm/svml-machine.ts +++ b/src/vm/svml-machine.ts @@ -1770,7 +1770,7 @@ export function runWithProgram(p: Program, context: Context): any { // setup externalBuiltins // certain functions are imported from cadet-frontend // so import them first every time - const externals = context.nativeStorage.globals!.variables + const externals = context.nativeStorage.builtins if (externals.size > 0) { EXTERNAL_PRIMITIVES.forEach(func => extractExternalBuiltin(func, externals)) } @@ -1834,5 +1834,5 @@ const externalFunctions = new Map<number, any>() function extractExternalBuiltin(func: [string, number], externals: Map<string, any>) { const name = func[0] const opcode = func[1] - externalFunctions.set(opcode, externals.get(name).getValue()) + externalFunctions.set(opcode, externals.get(name)) }