diff --git a/src/__tests__/__snapshots__/display.ts.snap b/src/__tests__/__snapshots__/display.ts.snap index 17d11e49e..6b6ccfc32 100644 --- a/src/__tests__/__snapshots__/display.ts.snap +++ b/src/__tests__/__snapshots__/display.ts.snap @@ -106,27 +106,6 @@ Object { } `; -exports[`display can be used to display objects: expectDisplayResult 1`] = ` -Object { - "alertResult": Array [], - "code": "display({a: 1, b: 2, c: {d: 3}});", - "displayResult": Array [ - "{\\"a\\": 1, \\"b\\": 2, \\"c\\": {\\"d\\": 3}}", - ], - "numErrors": 0, - "parsedErrors": "", - "result": Object { - "a": 1, - "b": 2, - "c": Object { - "d": 3, - }, - }, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`display second argument can be a string: expectDisplayResult 1`] = ` Object { "alertResult": Array [], diff --git a/src/__tests__/__snapshots__/index.ts.snap b/src/__tests__/__snapshots__/index.ts.snap index 2339d62aa..40d7d2f44 100644 --- a/src/__tests__/__snapshots__/index.ts.snap +++ b/src/__tests__/__snapshots__/index.ts.snap @@ -14,20 +14,6 @@ a[1];", } `; -exports[`Accessing object with nonexistent property returns undefined: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = {}; -o.nonexistent;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": undefined, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Allow display to return value it is displaying: expectResult 1`] = ` Object { "alertResult": Array [], @@ -181,23 +167,6 @@ test();", } `; -exports[`Deep object assignment and retrieval: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = {}; -o.a = {}; -o.a.b = {}; -o.a.b.c = \\"string\\"; -o.a.b.c;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "string", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Empty code returns undefined: expectResult 1`] = ` Object { "alertResult": Array [], @@ -579,55 +548,6 @@ identity(t) === t && t(1, 2, 3) === 6;", } `; -exports[`Multiline string self-evaluates to itself: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "\`1 -1\`;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "1 -1", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Objects toString matches up with JS: expect to match JS 1`] = ` -Object { - "alertResult": Array [], - "code": "toString({a: 1});", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "[object Object]", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Rest parameters work: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "function rest(a, b, ...c) { - let sum = a + b; - for (let i = 0; i < array_length(c); i = i + 1) { - sum = sum + c[i]; - } - return sum; -} -rest(1, 2); // no error -rest(1, 2, ...[3, 4, 5], ...[6, 7], ...[]);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 28, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Simple arrow function infinite recursion represents CallExpression well: expectParsedErrorNoErrorSnapshot 1`] = ` Object { "alertResult": Array [], @@ -649,11 +569,11 @@ Object { "displayResult": Array [], "numErrors": 1, "parsedErrors": "Line 1: Maximum call stack size exceeded - x(function f(x) { + x(x => { return x(x)(x); -}).. x(function f(x) { +}).. x(x => { return x(x)(x); -}).. x(function f(x) { +}).. x(x => { return x(x)(x); })..", "result": undefined, @@ -662,21 +582,6 @@ Object { } `; -exports[`Simple object assignment and retrieval: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = {}; -o.a = 1; -o.a;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Single boolean self-evaluates to itself: expectResult 1`] = ` Object { "alertResult": Array [], @@ -723,7 +628,8 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 60, + "result": "native:60 +interpreted:undefined", "resultStatus": "finished", "visualiseListResult": Array [], } @@ -786,32 +692,6 @@ Object { } `; -exports[`Test equal for different lists: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "!equal(list(1, 2), pair(1, 2)) && !equal(list(1, 2, 3), list(1, list(2, 3)));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Test equal for lists: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(list(1, 2), pair(1, pair(2, null))) && equal(list(1, 2, 3, 4), list(1, 2, 3, 4));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Test equal for primitives: expectResult 1`] = ` Object { "alertResult": Array [], @@ -866,9 +746,8 @@ toString(a=>a) + toString(f);", "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": "a => afunction f(x) { - return 5; -}", + "result": "native:\\"a => afunction f(x) {\\\\n return 5;\\\\n}\\" +interpreted:\\"a => ax => {\\\\n return 5;\\\\n}\\"", "resultStatus": "finished", "visualiseListResult": Array [], } diff --git a/src/__tests__/__snapshots__/lazy.ts.snap b/src/__tests__/__snapshots__/lazy.ts.snap index 58034a994..6afc6ad90 100644 --- a/src/__tests__/__snapshots__/lazy.ts.snap +++ b/src/__tests__/__snapshots__/lazy.ts.snap @@ -35,28 +35,6 @@ res;", } `; -exports[`Tail calls work: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "function test(a, b) { - return a === 1 ? a : b; -} - -function test2(a) { - return test(a, head(null)); -} - -const res = test2(1); -res;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Thunks are memoized: expectResult 1`] = ` Object { "alertResult": Array [], @@ -119,20 +97,3 @@ res;", "visualiseListResult": Array [], } `; - -exports[`Unused arguments are not evaluated: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "function test(a, b, c, d, e, f) { - return a; -} -const res = test(1, head(null), 1 + '', !1, '' - 1, head(head(null))); -res;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; diff --git a/src/__tests__/__snapshots__/scmlib.ts.snap b/src/__tests__/__snapshots__/scmlib.ts.snap index 6b4087707..59bcac4bd 100644 --- a/src/__tests__/__snapshots__/scmlib.ts.snap +++ b/src/__tests__/__snapshots__/scmlib.ts.snap @@ -1502,7 +1502,8 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 1, + "result": "native:1 +interpreted:undefined", "resultStatus": "finished", "visualiseListResult": Array [], } diff --git a/src/__tests__/__snapshots__/stdlib.ts.snap b/src/__tests__/__snapshots__/stdlib.ts.snap index 6bfca218b..d9d0699d6 100644 --- a/src/__tests__/__snapshots__/stdlib.ts.snap +++ b/src/__tests__/__snapshots__/stdlib.ts.snap @@ -408,32 +408,6 @@ Object { } `; -exports[`Builtins work as expected 31: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "is_object({});", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 32: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "is_object({a: 1});", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Builtins work as expected 33: expectResult 1`] = ` Object { "alertResult": Array [], @@ -551,32 +525,6 @@ Object { } `; -exports[`Builtins work as expected 42: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "has_own_property({a: 1, b: 2}, 'a');", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 43: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "has_own_property({a: 1, b: 2}, 'c');", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Builtins work as expected 44: expectResult 1`] = ` Object { "alertResult": Array [], diff --git a/src/__tests__/__snapshots__/stringify.ts.snap b/src/__tests__/__snapshots__/stringify.ts.snap index 609e54290..494c56d15 100644 --- a/src/__tests__/__snapshots__/stringify.ts.snap +++ b/src/__tests__/__snapshots__/stringify.ts.snap @@ -44,31 +44,6 @@ stringify(f);", } `; -exports[`String representation of big objects are nice: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = { a: 1, b: true, c: () => 1, d: { e: 5, f: 6 }, g: 0, h: 0, i: 0, j: 0, k: 0, l: 0, m: 0, n: 0}; -stringify(o);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "{ \\"a\\": 1, - \\"b\\": true, - \\"c\\": () => 1, - \\"d\\": {\\"e\\": 5, \\"f\\": 6}, - \\"g\\": 0, - \\"h\\": 0, - \\"i\\": 0, - \\"j\\": 0, - \\"k\\": 0, - \\"l\\": 0, - \\"m\\": 0, - \\"n\\": 0}", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`String representation of booleans are nice: expectResult 1`] = ` Object { "alertResult": Array [], @@ -121,9 +96,8 @@ stringify(f);", "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": "function f(x, y) { - return x; -}", + "result": "native:\\"function f(x, y) {\\\\n return x;\\\\n}\\" +interpreted:\\"(x, y) => {\\\\n return x;\\\\n}\\"", "resultStatus": "finished", "visualiseListResult": Array [], } @@ -373,35 +347,6 @@ stringify(xs);", } `; -exports[`String representation of nested objects are nice: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = { a: 1, b: true, c: () => 1, d: { e: 5, f: 6 } }; -stringify(o);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "{\\"a\\": 1, \\"b\\": true, \\"c\\": () => 1, \\"d\\": {\\"e\\": 5, \\"f\\": 6}}", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`String representation of nested objects are nice: expectResult 2`] = ` -Object { - "alertResult": Array [], - "code": "let o = {}; -o.o = o; -stringify(o);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "{\\"o\\": ...}", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`String representation of null is nice: expectResult 1`] = ` Object { "alertResult": Array [], @@ -428,34 +373,6 @@ Object { } `; -exports[`String representation of objects are nice: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = { a: 1, b: true, c: () => 1 }; -stringify(o);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "{\\"a\\": 1, \\"b\\": true, \\"c\\": () => 1}", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`String representation of objects with toReplString member calls toReplString: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const o = { toReplString: () => '' }; -stringify(o);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`String representation of strings are nice: expectResult 1`] = ` Object { "alertResult": Array [], diff --git a/src/__tests__/environmentTree.ts b/src/__tests__/environmentTree.ts index a06582eb5..9b24043c5 100644 --- a/src/__tests__/environmentTree.ts +++ b/src/__tests__/environmentTree.ts @@ -1,5 +1,5 @@ import { createGlobalEnvironment, EnvTree, EnvTreeNode } from '../createContext' -import { pushEnvironment } from '../interpreter/interpreter' +import { pushEnvironment } from '../cse-machine/utils' import { mockContext, mockEnvironment } from '../mocks/context' import { Chapter } from '../types' diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine.ts.snap index 1c66d16cd..0094a4140 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine.ts.snap @@ -520,30 +520,6 @@ test();", } `; -exports[`streams and its pre-defined/pre-built functions are working as intended: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "function make_alternating_stream(stream) { - return pair(head(stream), () => make_alternating_stream( - negate_whole_stream( - stream_tail(stream)))); -} - -function negate_whole_stream(stream) { - return pair(-head(stream), () => negate_whole_stream(stream_tail(stream))); -} - -const ones = pair(1, () => ones); -list_ref(eval_stream(make_alternating_stream(enum_stream(1, 9)), 9), 8);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 9, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`streams can be created and functions with no return statements are still evaluated properly: expectResult 1`] = ` Object { "alertResult": Array [], diff --git a/src/interpreter/__tests__/__snapshots__/interpreter-errors.ts.snap b/src/interpreter/__tests__/__snapshots__/interpreter-errors.ts.snap index 4f232772a..2997d1fe9 100644 --- a/src/interpreter/__tests__/__snapshots__/interpreter-errors.ts.snap +++ b/src/interpreter/__tests__/__snapshots__/interpreter-errors.ts.snap @@ -1,18 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Access local property: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "({a: 0})[\\"a\\"];", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Builtins don't create additional errors when it's not their fault: expectParsedError 1`] = ` Object { "alertResult": Array [], @@ -45,8 +32,9 @@ function negate_whole_stream(stream) { const ones = pair(1, () => ones); eval_stream(make_alternating_stream(enum_stream(1, 9)), 10);", "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 8: Error: head(xs) expects a pair as argument xs, but encountered null", + "numErrors": 2, + "parsedErrors": "native:\\"Line 8: Error: head(xs) expects a pair as argument xs, but encountered null\\" +interpreted:\\"Line 8: Error: head(xs) expects a pair as argument xs, but encountered undefined\\\\nLine 463: Name n not declared.\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -70,19 +58,6 @@ h(null);", } `; -exports[`Error when accessing inherited property of object: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "({}).valueOf;", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 1: Cannot read inherited property valueOf of {}.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - exports[`Error when assigning to builtin - verbose: expectParsedError 1`] = ` Object { "alertResult": Array [], @@ -479,51 +454,6 @@ Object { } `; -exports[`Error when calling non function value object - verbose: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "\\"enable verbose\\"; -({a: 1})();", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 2, Column 0: Calling non-function value {\\"a\\": 1}. -Because {\\"a\\": 1} is not a function, you cannot run {\\"a\\": 1}(). -", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`Error when calling non function value object - verbose: expectParsedError 2`] = ` -Object { - "alertResult": Array [], - "code": "\\"enable verbose\\"; -({a: 1})();", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 2, Column 0: Calling non-function value {\\"a\\": 1}. -Because {\\"a\\": 1} is not a function, you cannot run {\\"a\\": 1}(). -", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`Error when calling non function value object: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "({a: 1})();", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 1: Calling non-function value {\\"a\\": 1}.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - exports[`Error when calling non function value true - verbose: expectParsedError 1`] = ` Object { "alertResult": Array [], @@ -982,7 +912,8 @@ Object { f.prototype;", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 4: Expected object or array, got function.", + "parsedErrors": "native:\\"Line 4: Expected object or array, got function.\\" +interpreted:\\"Line 4: Name prototype not declared.\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -995,20 +926,8 @@ Object { "code": "null.prop;", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 1: Expected object or array, got null.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`Type error when accessing property of string: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "'hi'.length;", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 1: Expected object or array, got string.", + "parsedErrors": "native:\\"Line 1: Expected object or array, got null.\\" +interpreted:\\"Line 1: Name prop not declared.\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -1024,7 +943,8 @@ Object { f.prop = 5;", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 4: Expected object or array, got function.", + "parsedErrors": "native:\\"Line 4: Expected object or array, got function.\\" +interpreted:\\"Line 4: Name prop not declared.\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -1037,7 +957,8 @@ Object { "code": "'hi'.prop = 5;", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 1: Expected object or array, got string.", + "parsedErrors": "native:\\"Line 1: Expected object or array, got string.\\" +interpreted:\\"Line 1: Name prop not declared.\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], diff --git a/src/interpreter/closure.ts b/src/interpreter/closure.ts index ad0974c45..f91be3e07 100644 --- a/src/interpreter/closure.ts +++ b/src/interpreter/closure.ts @@ -12,7 +12,7 @@ import { identifier, returnStatement } from '../utils/astCreator' -import { apply } from './interpreter' +import { apply } from './interpreter-non-det' const closureToJS = (value: Closure, context: Context, klass: string) => { function DummyClass(this: Closure) { diff --git a/src/interpreter/interpreter.ts b/src/interpreter/interpreter.ts index f883d3a95..508ec3f4e 100644 --- a/src/interpreter/interpreter.ts +++ b/src/interpreter/interpreter.ts @@ -1,104 +1,15 @@ /* tslint:disable:max-classes-per-file */ import * as es from 'estree' -import { isEmpty, uniqueId } from 'lodash' -import { UNKNOWN_LOCATION } from '../constants' -import { LazyBuiltIn } from '../createContext' +import { createBlockEnvironment, pushEnvironment } from '../cse-machine/utils' import * as errors from '../errors/errors' import { RuntimeSourceError } from '../errors/runtimeSourceError' import { UndefinedImportError } from '../modules/errors' import { initModuleContext, loadModuleBundle } from '../modules/moduleLoader' import { ModuleFunctions } from '../modules/moduleTypes' import { checkEditorBreakpoints } from '../stdlib/inspector' -import { Context, ContiguousArrayElements, Environment, Frame, Value, Variant } from '../types' +import { Context, Value } from '../types' import assert from '../utils/assert' -import * as create from '../utils/astCreator' -import { conditionalExpression, literal, primitive } from '../utils/astCreator' -import { evaluateBinaryExpression, evaluateUnaryExpression } from '../utils/operators' -import * as rttc from '../utils/rttc' -import Closure from './closure' - -class BreakValue {} - -class ContinueValue {} - -class ReturnValue { - constructor(public value: Value) {} -} - -class TailCallReturnValue { - constructor(public callee: Closure, public args: Value[], public node: es.CallExpression) {} -} - -class Thunk { - public value: Value - public isMemoized: boolean - constructor(public exp: es.Node, public env: Environment) { - this.isMemoized = false - this.value = null - } -} - -const delayIt = (exp: es.Node, env: Environment): Thunk => new Thunk(exp, env) - -function* forceIt(val: any, context: Context): Value { - if (val instanceof Thunk) { - if (val.isMemoized) return val.value - - pushEnvironment(context, val.env) - const evalRes = yield* actualValue(val.exp, context) - popEnvironment(context) - val.value = evalRes - val.isMemoized = true - return evalRes - } else return val -} - -export function* actualValue(exp: es.Node, context: Context): Value { - const evalResult = yield* evaluate(exp, context) - const forced = yield* forceIt(evalResult, context) - return forced -} - -const createEnvironment = ( - closure: Closure, - args: Value[], - callExpression?: es.CallExpression -): Environment => { - const environment: Environment = { - name: closure.functionName, // TODO: Change this - tail: closure.environment, - head: {}, - id: uniqueId() - } - if (callExpression) { - environment.callExpression = { - ...callExpression, - arguments: args.map(primitive) - } - } - closure.node.params.forEach((param, index) => { - if (param.type === 'RestElement') { - environment.head[(param.argument as es.Identifier).name] = args.slice(index) - } else { - environment.head[(param as es.Identifier).name] = args[index] - } - }) - return environment -} - -export const createBlockEnvironment = ( - context: Context, - name = 'blockEnvironment', - head: Frame = {} -): Environment => { - return { - name, - tail: currentEnvironment(context), - head, - id: uniqueId() - } -} const handleRuntimeError = (context: Context, error: RuntimeSourceError): never => { context.errors.push(error) @@ -124,30 +35,6 @@ function declareIdentifier(context: Context, name: string, node: es.Node) { return environment } -function declareVariables(context: Context, node: es.VariableDeclaration) { - for (const declaration of node.declarations) { - declareIdentifier(context, (declaration.id as es.Identifier).name, node) - } -} - -function declareFunctionsAndVariables(context: Context, node: es.BlockStatement) { - for (const statement of node.body) { - switch (statement.type) { - case 'VariableDeclaration': - declareVariables(context, statement) - break - case 'FunctionDeclaration': - if (statement.id === null) { - throw new Error( - 'Encountered a FunctionDeclaration node without an identifier. This should have been caught when parsing.' - ) - } - declareIdentifier(context, statement.id.name, statement) - break - } - } -} - function defineVariable(context: Context, name: string, value: Value, constant = false) { const environment = currentEnvironment(context) @@ -180,535 +67,6 @@ function* leave(context: Context) { } const currentEnvironment = (context: Context) => context.runtime.environments[0] -const replaceEnvironment = (context: Context, environment: Environment) => { - context.runtime.environments[0] = environment - context.runtime.environmentTree.insert(environment) -} -const popEnvironment = (context: Context) => context.runtime.environments.shift() -export const pushEnvironment = (context: Context, environment: Environment) => { - context.runtime.environments.unshift(environment) - context.runtime.environmentTree.insert(environment) -} - -const getVariable = (context: Context, name: string) => { - let environment: Environment | null = currentEnvironment(context) - while (environment) { - if (environment.head.hasOwnProperty(name)) { - if (environment.head[name] === DECLARED_BUT_NOT_YET_ASSIGNED) { - return handleRuntimeError( - context, - new errors.UnassignedVariable(name, context.runtime.nodes[0]) - ) - } else { - return environment.head[name] - } - } else { - environment = environment.tail - } - } - return handleRuntimeError(context, new errors.UndefinedVariable(name, context.runtime.nodes[0])) -} - -const setVariable = (context: Context, name: string, value: any) => { - let environment: Environment | null = currentEnvironment(context) - while (environment) { - if (environment.head.hasOwnProperty(name)) { - if (environment.head[name] === DECLARED_BUT_NOT_YET_ASSIGNED) { - break - } - const descriptors = Object.getOwnPropertyDescriptors(environment.head) - if (descriptors[name].writable) { - environment.head[name] = value - return undefined - } - return handleRuntimeError( - context, - new errors.ConstAssignment(context.runtime.nodes[0]!, name) - ) - } else { - environment = environment.tail - } - } - return handleRuntimeError(context, new errors.UndefinedVariable(name, context.runtime.nodes[0])) -} - -const checkNumberOfArguments = ( - context: Context, - callee: Closure | Value, - args: Value[], - exp: es.CallExpression -) => { - if (callee instanceof Closure) { - const params = callee.node.params - const hasVarArgs = params[params.length - 1]?.type === 'RestElement' - if (hasVarArgs ? params.length - 1 > args.length : params.length !== args.length) { - return handleRuntimeError( - context, - new errors.InvalidNumberOfArguments( - exp, - hasVarArgs ? params.length - 1 : params.length, - args.length, - hasVarArgs - ) - ) - } - } else { - const hasVarArgs = callee.minArgsNeeded != undefined - if (hasVarArgs ? callee.minArgsNeeded > args.length : callee.length !== args.length) { - return handleRuntimeError( - context, - new errors.InvalidNumberOfArguments( - exp, - hasVarArgs ? callee.minArgsNeeded : callee.length, - args.length, - hasVarArgs - ) - ) - } - } - return undefined -} - -function* getArgs(context: Context, call: es.CallExpression) { - const args = [] - for (const arg of call.arguments) { - if (context.variant === Variant.LAZY) { - args.push(delayIt(arg, currentEnvironment(context))) - } else if (arg.type === 'SpreadElement') { - args.push(...(yield* actualValue(arg.argument, context))) - } else { - args.push(yield* actualValue(arg, context)) - } - } - return args -} - -function transformLogicalExpression(node: es.LogicalExpression): es.ConditionalExpression { - if (node.operator === '&&') { - return conditionalExpression(node.left, node.right, literal(false), node.loc) - } else { - return conditionalExpression(node.left, literal(true), node.right, node.loc) - } -} - -function* reduceIf( - node: es.IfStatement | es.ConditionalExpression, - context: Context -): IterableIterator { - const test = yield* actualValue(node.test, context) - - const error = rttc.checkIfStatement(node, test, context.chapter) - if (error) { - return handleRuntimeError(context, error) - } - - return test ? node.consequent : node.alternate -} - -export type Evaluator = (node: T, context: Context) => IterableIterator - -function* evaluateBlockStatement(context: Context, node: es.BlockStatement) { - declareFunctionsAndVariables(context, node) - let result - for (const statement of node.body) { - result = yield* evaluate(statement, context) - if ( - result instanceof ReturnValue || - result instanceof TailCallReturnValue || - result instanceof BreakValue || - result instanceof ContinueValue - ) { - break - } - } - return result -} - -/** - * WARNING: Do not use object literal shorthands, e.g. - * { - * *Literal(node: es.Literal, ...) {...}, - * *ThisExpression(node: es.ThisExpression, ..._ {...}, - * ... - * } - * They do not minify well, raising uncaught syntax errors in production. - * See: https://github.com/webpack/webpack/issues/7566 - */ -// tslint:disable:object-literal-shorthand -// prettier-ignore -export const evaluators: { [nodeType: string]: Evaluator } = { - /** Simple Values */ - Literal: function*(node: es.Literal, _context: Context) { - return node.value - }, - - TemplateLiteral: function*(node: es.TemplateLiteral) { - // Expressions like `${1}` are not allowed, so no processing needed - return node.quasis[0].value.cooked - }, - - ThisExpression: function*(node: es.ThisExpression, context: Context) { - return currentEnvironment(context).thisContext - }, - - ArrayExpression: function*(node: es.ArrayExpression, context: Context) { - const res = [] - for (const n of node.elements as ContiguousArrayElements) { - res.push(yield* evaluate(n, context)) - } - return res - }, - - DebuggerStatement: function*(node: es.DebuggerStatement, context: Context) { - context.runtime.break = true - yield - }, - - FunctionExpression: function*(node: es.FunctionExpression, context: Context) { - return new Closure(node, currentEnvironment(context), context) - }, - - ArrowFunctionExpression: function*(node: es.ArrowFunctionExpression, context: Context) { - return Closure.makeFromArrowFunction(node, currentEnvironment(context), context) - }, - - Identifier: function*(node: es.Identifier, context: Context) { - return getVariable(context, node.name) - }, - - CallExpression: function*(node: es.CallExpression, context: Context) { - const callee = yield* actualValue(node.callee, context) - const args = yield* getArgs(context, node) - let thisContext - if (node.callee.type === 'MemberExpression') { - thisContext = yield* actualValue(node.callee.object, context) - } - const result = yield* apply(context, callee, args, node, thisContext) - return result - }, - - NewExpression: function*(node: es.NewExpression, context: Context) { - const callee = yield* evaluate(node.callee, context) - const args = [] - for (const arg of node.arguments) { - args.push(yield* evaluate(arg, context)) - } - const obj: Value = {} - if (callee instanceof Closure) { - obj.__proto__ = callee.fun.prototype - callee.fun.apply(obj, args) - } else { - obj.__proto__ = callee.prototype - callee.apply(obj, args) - } - return obj - }, - - UnaryExpression: function*(node: es.UnaryExpression, context: Context) { - const value = yield* actualValue(node.argument, context) - - const error = rttc.checkUnaryExpression(node, node.operator, value, context.chapter) - if (error) { - return handleRuntimeError(context, error) - } - return evaluateUnaryExpression(node.operator, value) - }, - - BinaryExpression: function*(node: es.BinaryExpression, context: Context) { - const left = yield* actualValue(node.left, context) - const right = yield* actualValue(node.right, context) - const error = rttc.checkBinaryExpression(node, node.operator, context.chapter, left, right) - if (error) { - return handleRuntimeError(context, error) - } - return evaluateBinaryExpression(node.operator, left, right) - }, - - ConditionalExpression: function*(node: es.ConditionalExpression, context: Context) { - return yield* this.IfStatement(node, context) - }, - - LogicalExpression: function*(node: es.LogicalExpression, context: Context) { - return yield* this.ConditionalExpression(transformLogicalExpression(node), context) - }, - - VariableDeclaration: function*(node: es.VariableDeclaration, context: Context) { - const declaration = node.declarations[0] - const constant = node.kind === 'const' - const id = declaration.id as es.Identifier - const value = yield* evaluate(declaration.init!, context) - defineVariable(context, id.name, value, constant) - return undefined - }, - - ContinueStatement: function*(_node: es.ContinueStatement, _context: Context) { - return new ContinueValue() - }, - - BreakStatement: function*(_node: es.BreakStatement, _context: Context) { - return new BreakValue() - }, - - ForStatement: function*(node: es.ForStatement, context: Context) { - // Create a new block scope for the loop variables - const loopEnvironment = createBlockEnvironment(context, 'forLoopEnvironment') - pushEnvironment(context, loopEnvironment) - - const initNode = node.init! - const testNode = node.test! - const updateNode = node.update! - if (initNode.type === 'VariableDeclaration') { - declareVariables(context, initNode) - } - yield* actualValue(initNode, context) - - let value - while (yield* actualValue(testNode, context)) { - // create block context and shallow copy loop environment head - // see https://www.ecma-international.org/ecma-262/6.0/#sec-for-statement-runtime-semantics-labelledevaluation - // and https://hacks.mozilla.org/2015/07/es6-in-depth-let-and-const/ - // We copy this as a const to avoid ES6 funkiness when mutating loop vars - // https://github.com/source-academy/js-slang/issues/65#issuecomment-425618227 - const environment = createBlockEnvironment(context, 'forBlockEnvironment') - pushEnvironment(context, environment) - for (const name in loopEnvironment.head) { - if (loopEnvironment.head.hasOwnProperty(name)) { - declareIdentifier(context, name, node) - defineVariable(context, name, loopEnvironment.head[name], true) - } - } - - value = yield* actualValue(node.body, context) - - // Remove block context - popEnvironment(context) - if (value instanceof ContinueValue) { - value = undefined - } - if (value instanceof BreakValue) { - value = undefined - break - } - if (value instanceof ReturnValue || value instanceof TailCallReturnValue) { - break - } - - yield* actualValue(updateNode, context) - } - - popEnvironment(context) - - return value - }, - - MemberExpression: function*(node: es.MemberExpression, context: Context) { - let obj = yield* actualValue(node.object, context) - if (obj instanceof Closure) { - obj = obj.fun - } - let prop - if (node.computed) { - prop = yield* actualValue(node.property, context) - } else { - prop = (node.property as es.Identifier).name - } - - const error = rttc.checkMemberAccess(node, obj, prop) - if (error) { - return handleRuntimeError(context, error) - } - - if ( - obj !== null && - obj !== undefined && - typeof obj[prop] !== 'undefined' && - !obj.hasOwnProperty(prop) - ) { - return handleRuntimeError(context, new errors.GetInheritedPropertyError(node, obj, prop)) - } - try { - return obj[prop] - } catch { - return handleRuntimeError(context, new errors.GetPropertyError(node, obj, prop)) - } - }, - - AssignmentExpression: function*(node: es.AssignmentExpression, context: Context) { - if (node.left.type === 'MemberExpression') { - const left = node.left - const obj = yield* actualValue(left.object, context) - let prop - if (left.computed) { - prop = yield* actualValue(left.property, context) - } else { - prop = (left.property as es.Identifier).name - } - - const error = rttc.checkMemberAccess(node, obj, prop) - if (error) { - return handleRuntimeError(context, error) - } - - const val = yield* evaluate(node.right, context) - try { - obj[prop] = val - } catch { - return handleRuntimeError(context, new errors.SetPropertyError(node, obj, prop)) - } - return val - } - const id = node.left as es.Identifier - // Make sure it exist - const value = yield* evaluate(node.right, context) - setVariable(context, id.name, value) - return value - }, - - FunctionDeclaration: function*(node: es.FunctionDeclaration, context: Context) { - const id = node.id - if (id === null) { - throw new Error("Encountered a FunctionDeclaration node without an identifier. This should have been caught when parsing.") - } - // tslint:disable-next-line:no-any - const closure = new Closure(node, currentEnvironment(context), context) - defineVariable(context, id.name, closure, true) - return undefined - }, - - IfStatement: function*(node: es.IfStatement | es.ConditionalExpression, context: Context) { - const result = yield* reduceIf(node, context) - if (result === null) { - return undefined; - } - return yield* evaluate(result, context) - }, - - ExpressionStatement: function*(node: es.ExpressionStatement, context: Context) { - return yield* evaluate(node.expression, context) - }, - - ReturnStatement: function*(node: es.ReturnStatement, context: Context) { - let returnExpression = node.argument! - - // If we have a conditional expression, reduce it until we get something else - while ( - returnExpression.type === 'LogicalExpression' || - returnExpression.type === 'ConditionalExpression' - ) { - if (returnExpression.type === 'LogicalExpression') { - returnExpression = transformLogicalExpression(returnExpression) - } - returnExpression = yield* reduceIf(returnExpression, context) - } - - // If we are now left with a CallExpression, then we use TCO - if (returnExpression.type === 'CallExpression' && context.variant !== Variant.LAZY) { - const callee = yield* actualValue(returnExpression.callee, context) - const args = yield* getArgs(context, returnExpression) - return new TailCallReturnValue(callee, args, returnExpression) - } else { - return new ReturnValue(yield* evaluate(returnExpression, context)) - } - }, - - WhileStatement: function*(node: es.WhileStatement, context: Context) { - let value: any // tslint:disable-line - while ( - // tslint:disable-next-line - (yield* actualValue(node.test, context)) && - !(value instanceof ReturnValue) && - !(value instanceof BreakValue) && - !(value instanceof TailCallReturnValue) - ) { - value = yield* actualValue(node.body, context) - } - if (value instanceof BreakValue) { - return undefined - } - return value - }, - - ObjectExpression: function*(node: es.ObjectExpression, context: Context) { - const obj = {} - for (const propUntyped of node.properties) { - // node.properties: es.Property | es.SpreadExpression, but - // our Acorn is set to ES6 which cannot have a es.SpreadExpression - // at this point. Force the type. - const prop = propUntyped as es.Property - let key - if (prop.key.type === 'Identifier') { - key = prop.key.name - } else { - key = yield* evaluate(prop.key, context) - } - obj[key] = yield* evaluate(prop.value, context) - } - return obj - }, - - BlockStatement: function*(node: es.BlockStatement, context: Context) { - // Create a new environment (block scoping) - const environment = createBlockEnvironment(context, 'blockEnvironment') - pushEnvironment(context, environment) - const result: Value = yield* evaluateBlockStatement(context, node) - popEnvironment(context) - return result - }, - - ImportDeclaration: function*(node: es.ImportDeclaration, context: Context) { - throw new Error('ImportDeclarations should already have been removed') - }, - - ExportNamedDeclaration: function*(_node: es.ExportNamedDeclaration, _context: Context) { - // Exports are handled as a separate pre-processing step in 'transformImportedFile'. - // Subsequently, they are removed from the AST by 'removeExports' before the AST is evaluated. - // As such, there should be no ExportNamedDeclaration nodes in the AST. - throw new Error('Encountered an ExportNamedDeclaration node in the AST while evaluating. This suggests that an invariant has been broken.') - }, - - ExportDefaultDeclaration: function*(_node: es.ExportDefaultDeclaration, _context: Context) { - // Exports are handled as a separate pre-processing step in 'transformImportedFile'. - // Subsequently, they are removed from the AST by 'removeExports' before the AST is evaluated. - // As such, there should be no ExportDefaultDeclaration nodes in the AST. - throw new Error('Encountered an ExportDefaultDeclaration node in the AST while evaluating. This suggests that an invariant has been broken.') - }, - - ExportAllDeclaration: function*(_node: es.ExportAllDeclaration, _context: Context) { - // Exports are handled as a separate pre-processing step in 'transformImportedFile'. - // Subsequently, they are removed from the AST by 'removeExports' before the AST is evaluated. - // As such, there should be no ExportAllDeclaration nodes in the AST. - throw new Error('Encountered an ExportAllDeclaration node in the AST while evaluating. This suggests that an invariant has been broken.') - }, - - Program: function*(node: es.BlockStatement, context: Context) { - throw new Error('A program should not contain another program within itself') - } -} -// tslint:enable:object-literal-shorthand - -// TODO: move to util -/** - * Checks if `env` is empty (that is, head of env is an empty object) - */ -function isEmptyEnvironment(env: Environment) { - return isEmpty(env.head) -} - -/** - * Extracts the non-empty tail environment from the given environment and - * returns current environment if tail environment is a null. - */ -function getNonEmptyEnv(environment: Environment): Environment { - if (isEmptyEnvironment(environment)) { - const tailEnvironment = environment.tail - if (tailEnvironment === null) { - return environment - } - return getNonEmptyEnv(tailEnvironment) - } else { - return environment - } -} export function* evaluateProgram( program: es.Program, @@ -727,6 +85,7 @@ export function* evaluateProgram( try { for (const node of program.body) { + console.log(node) if (node.type !== 'ImportDeclaration') { otherNodes.push(node as es.Statement) continue @@ -746,6 +105,7 @@ export function* evaluateProgram( } const functions = moduleFunctions[moduleName] + console.log('tests') for (const spec of node.specifiers) { assert( @@ -758,140 +118,15 @@ export function* evaluateProgram( } declareIdentifier(context, spec.local.name, node) - defineVariable(context, spec.local.name, functions[spec.imported.name], true) + const importedObj = functions[spec.imported.name] + console.log('hi2') + Object.defineProperty(importedObj, 'name', { value: spec.local.name }) + defineVariable(context, spec.local.name, importedObj, true) } yield* leave(context) } } catch (error) { handleRuntimeError(context, error) } - - const newProgram = create.blockStatement(otherNodes) - const result = yield* forceIt(yield* evaluateBlockStatement(context, newProgram), context) - yield* leave(context) // Done visiting program - - if (result instanceof Closure) { - Object.defineProperty(getNonEmptyEnv(currentEnvironment(context)).head, uniqueId(), { - value: result, - writable: false, - enumerable: true - }) - } - return result -} - -function* evaluate(node: es.Node, context: Context) { - yield* visit(context, node) - const result = yield* evaluators[node.type](node, context) - yield* leave(context) - if (result instanceof Closure) { - Object.defineProperty(getNonEmptyEnv(currentEnvironment(context)).head, uniqueId(), { - value: result, - writable: false, - enumerable: true - }) - } - return result -} - -export function* apply( - context: Context, - fun: Closure | Value, - args: (Thunk | Value)[], - node: es.CallExpression, - thisContext?: Value -) { - let result: Value - let total = 0 - - while (!(result instanceof ReturnValue)) { - if (fun instanceof Closure) { - checkNumberOfArguments(context, fun, args, node!) - const environment = createEnvironment(fun, args, node) - if (result instanceof TailCallReturnValue) { - replaceEnvironment(context, environment) - } else { - pushEnvironment(context, environment) - total++ - } - const bodyEnvironment = createBlockEnvironment(context, 'functionBodyEnvironment') - bodyEnvironment.thisContext = thisContext - pushEnvironment(context, bodyEnvironment) - result = yield* evaluateBlockStatement(context, fun.node.body as es.BlockStatement) - popEnvironment(context) - if (result instanceof TailCallReturnValue) { - fun = result.callee - node = result.node - args = result.args - } else if (!(result instanceof ReturnValue)) { - // No Return Value, set it as undefined - result = new ReturnValue(undefined) - } - } else if (fun instanceof LazyBuiltIn) { - try { - let finalArgs = args - if (fun.evaluateArgs) { - finalArgs = [] - for (const arg of args) { - finalArgs.push(yield* forceIt(arg, context)) - } - } - result = fun.func.apply(thisContext, finalArgs) - break - } catch (e) { - // Recover from exception - context.runtime.environments = context.runtime.environments.slice( - -context.numberOfOuterEnvironments - ) - - const loc = node.loc ?? UNKNOWN_LOCATION - if (!(e instanceof RuntimeSourceError || e instanceof errors.ExceptionError)) { - // The error could've arisen when the builtin called a source function which errored. - // If the cause was a source error, we don't want to include the error. - // However if the error came from the builtin itself, we need to handle it. - return handleRuntimeError(context, new errors.ExceptionError(e, loc)) - } - result = undefined - throw e - } - } else if (typeof fun === 'function') { - checkNumberOfArguments(context, fun, args, node!) - try { - const forcedArgs = [] - - for (const arg of args) { - forcedArgs.push(yield* forceIt(arg, context)) - } - - result = fun.apply(thisContext, forcedArgs) - break - } catch (e) { - // Recover from exception - context.runtime.environments = context.runtime.environments.slice( - -context.numberOfOuterEnvironments - ) - - const loc = node.loc ?? UNKNOWN_LOCATION - if (!(e instanceof RuntimeSourceError || e instanceof errors.ExceptionError)) { - // The error could've arisen when the builtin called a source function which errored. - // If the cause was a source error, we don't want to include the error. - // However if the error came from the builtin itself, we need to handle it. - return handleRuntimeError(context, new errors.ExceptionError(e, loc)) - } - result = undefined - throw e - } - } else { - return handleRuntimeError(context, new errors.CallingNonFunctionValue(fun, node)) - } - } - // Unwraps return value and release stack environment - if (result instanceof ReturnValue) { - result = result.value - } - for (let i = 1; i <= total; i++) { - popEnvironment(context) - } - return result } diff --git a/src/mocks/context.ts b/src/mocks/context.ts index d3e7b925f..645aa0e97 100644 --- a/src/mocks/context.ts +++ b/src/mocks/context.ts @@ -1,8 +1,8 @@ import * as es from 'estree' import createContext, { EnvTree } from '../createContext' +import { createBlockEnvironment } from '../cse-machine/utils' import Closure from '../interpreter/closure' -import { createBlockEnvironment } from '../interpreter/interpreter' import { Chapter, Context, Environment, Frame, Variant } from '../types' export function mockContext( diff --git a/src/parser/__tests__/__snapshots__/allowed-syntax.ts.snap b/src/parser/__tests__/__snapshots__/allowed-syntax.ts.snap index bfc5a3d5e..5b6531f86 100644 --- a/src/parser/__tests__/__snapshots__/allowed-syntax.ts.snap +++ b/src/parser/__tests__/__snapshots__/allowed-syntax.ts.snap @@ -2190,30 +2190,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 17: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "let i = 1; -for (let j = 0; j < 5; j = j + 1) { - if (j < 1) { - continue; - } else { - i = i + 1; - if (j > 2) { - break; - } - } -} -i;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 4, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 18: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3052,22 +3028,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 24: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "function f(x, y, ...z) { - return x + y; -} -f(...[1, 2]);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 25: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3100,19 +3060,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 25: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({});", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": Object {}, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 26: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3193,22 +3140,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 26: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({a: 1, b: 2});", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": Object { - "a": 1, - "b": 2, - }, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 27: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3304,19 +3235,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 27: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({a: 1, b: 2})['a'];", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 28: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3413,19 +3331,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 28: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({a: 1, b: 2}).a;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 29: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3522,19 +3427,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 29: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({'a': 1, 'b': 2}).a;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 30: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3630,19 +3522,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 30: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "({1: 1, 2: 2})['1'];", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 31: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3772,20 +3651,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 31: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "const key = 'a'; -({a: 1, b: 2})[key];", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 32: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -3931,20 +3796,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 32: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "let x = {a: 1, b: 2}; -x.a = 3;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 33: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -4089,20 +3940,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 33: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "let x = {a: 1, b: 2}; -x['a'] = 3;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 34: fails a chapter below 1`] = ` Object { "alertResult": Array [], @@ -4272,21 +4109,6 @@ Object { } `; -exports[`Syntaxes are allowed in the chapter they are introduced 34: passes 1`] = ` -Object { - "alertResult": Array [], - "code": "let x = {a: 1, b: 2}; -const key = 'a'; -x[key] = 3;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`Syntaxes are allowed in the chapter they are introduced 35: fails a chapter below 1`] = ` Object { "alertResult": Array [], diff --git a/src/parser/__tests__/__snapshots__/disallowed-syntax.ts.snap b/src/parser/__tests__/__snapshots__/disallowed-syntax.ts.snap index 79ab4aa80..fd28ad2e7 100644 --- a/src/parser/__tests__/__snapshots__/disallowed-syntax.ts.snap +++ b/src/parser/__tests__/__snapshots__/disallowed-syntax.ts.snap @@ -1260,41 +1260,6 @@ Every statement must be terminated by a semicolon. } `; -exports[`no this, no new - verbose: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "\\"enable verbose\\"; -function Box() { - this[0] = 5; -} -const box = new Box();", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 3, Column 2: Expected string as prop, got number. -Expected string as prop, got number. -", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`no this, no new: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": "function Box() { - this[0] = 5; -} -const box = new Box();", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 2: Expected string as prop, got number.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - exports[`no try statements - verbose: expectParsedError 1`] = ` Object { "alertResult": Array [], diff --git a/src/repl/repl.ts b/src/repl/repl.ts index b3b4f7f47..9695296d4 100644 --- a/src/repl/repl.ts +++ b/src/repl/repl.ts @@ -9,7 +9,7 @@ import { ExecutionMethod, Variant } from '../types' function startRepl( chapter = 1, - executionMethod: ExecutionMethod = 'interpreter', + executionMethod: ExecutionMethod = 'cse-machine', variant: Variant = Variant.DEFAULT, useSubst: boolean = false, useRepl: boolean, @@ -113,10 +113,10 @@ function main() { } const executionMethod = - opt.options.variant === 'interpreter' || - opt.options.variant === 'non-det' || - opt.options.variant === 'explicit-control' + opt.options.variant === 'non-det' ? 'interpreter' + : opt.options.variant === 'explicit-control' + ? 'cse-machine' : 'native' const useSubst = opt.options.variant === 'substituter' const useRepl = !opt.options.e diff --git a/src/runner/sourceRunner.ts b/src/runner/sourceRunner.ts index ee6e6c085..13946ad12 100644 --- a/src/runner/sourceRunner.ts +++ b/src/runner/sourceRunner.ts @@ -4,7 +4,7 @@ import type { RawSourceMap } from 'source-map' import type { IOptions, Result } from '..' import { JSSLANG_PROPERTIES, UNKNOWN_LOCATION } from '../constants' -import { CSEResultPromise, evaluate as CSEvaluate } from '../cse-machine/interpreter' +import { CSEResultPromise, evaluate } from '../cse-machine/interpreter' import { ExceptionError } from '../errors/errors' import { CannotFindModuleError } from '../errors/localImportErrors' import { RuntimeSourceError } from '../errors/runtimeSourceError' @@ -12,7 +12,6 @@ import { TimeoutError } from '../errors/timeoutErrors' import { transpileToGPU } from '../gpu/gpu' import { isPotentialInfiniteLoop } from '../infiniteLoops/errors' import { testForInfiniteLoop } from '../infiniteLoops/runtime' -import { evaluateProgram as evaluate } from '../interpreter/interpreter' import { nonDetEvaluate } from '../interpreter/interpreter-non-det' import { transpileToLazy } from '../lazy/lazy' import preprocessFileImports from '../localImports/preprocessor' @@ -113,7 +112,7 @@ async function runSubstitution( } function runInterpreter(program: es.Program, context: Context, options: IOptions): Promise { - let it = evaluate(program, context, true, true) + let it = evaluate(program, context, options) let scheduler: Scheduler if (context.variant === Variant.NON_DET) { it = nonDetEvaluate(program, context) @@ -219,7 +218,7 @@ async function runNative( } function runCSEMachine(program: es.Program, context: Context, options: IOptions): Promise { - const value = CSEvaluate(program, context, options) + const value = evaluate(program, context, options) return CSEResultPromise(context, value) } diff --git a/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap b/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap index dba6ef575..dd2af90f7 100644 --- a/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap +++ b/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap @@ -1,94 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`accumulate: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "accumulate((curr, acc) => curr + acc, 0, list(2, 3, 4, 1));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 10, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`append left list is infinite: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -const b = append(a, list(3,4)); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`append right list is infinite: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -const b = append(list(3,4),a); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`append: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(append(list(123, 123), list(456, 456, 456)), list(123, 123, 456, 456, 456));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`arguments are not evaluated for list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "head(list(1,head(null)));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`arguments are not evaluated for pair: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "head(pair(1,head(null)));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`bad index error list_ref: expectParsedError 1`] = ` Object { "alertResult": Array [], "code": "list_ref(list(1, 2, 3), 3);", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "parsedErrors": "native:\\"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null\\" +interpreted:\\"Line 1: Calling non-function value [object Object].\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -101,7 +20,8 @@ Object { "code": "list_ref(list(1, 2, 3), -1);", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "parsedErrors": "native:\\"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null\\" +interpreted:\\"Line 1: Calling non-function value [object Object].\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -114,7 +34,8 @@ Object { "code": "list_ref(list(1, 2, 3), 1.5);", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "parsedErrors": "native:\\"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null\\" +interpreted:\\"Line 1: Calling non-function value [object Object].\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -127,7 +48,8 @@ Object { "code": "list_ref(list(1, 2, 3), '1');", "displayResult": Array [], "numErrors": 1, - "parsedErrors": "Line 149: Expected string on right hand side of operation, got number.", + "parsedErrors": "native:\\"Line 149: Expected string on right hand side of operation, got number.\\" +interpreted:\\"Line 1: Calling non-function value [object Object].\\"", "result": undefined, "resultStatus": "error", "visualiseListResult": Array [], @@ -185,401 +107,3 @@ Object { "visualiseListResult": Array [], } `; - -exports[`build_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(build_list(x => x * x, 5), list(0, 1, 4, 9, 16));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`empty list is null: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "list();", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": null, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`enum_list with floats: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(enum_list(1.5, 5), list(1.5, 2.5, 3.5, 4.5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`enum_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(enum_list(1, 5), list(1, 2, 3, 4, 5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`filter on infinite lists: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,pair(2,a)); -const b = filter(x => x % 2 === 0,a); -list_ref(b,1);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`filter: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(filter(x => x <= 4, list(2, 10, 1000, 1, 3, 100, 4, 5, 2, 1000)), list(2, 1, 3, 4, 2));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`for_each: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "let sum = 0; -for_each(x => { - sum = sum + x; -}, list(1, 2, 3)); -sum;", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 6, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`head works: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "head(pair(1, 'a string \\"\\"'));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`is_list on infinite lists works: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = list(1,a); -is_list(a);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`list_ref on infinite lists: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -list_ref(a,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`list_ref: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "list_ref(list(1, 2, 3, \\"4\\", 4), 4);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 4, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`list_to_string: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "list_to_string(list(1, 2, 3));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "[1,[2,[3,null]]]", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`map on infinite lists works: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -const b = map(x => 2 * x, a); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`map on infinite lists works: expectResult 2`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -const b = map(x => 2 * x, a); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`map: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(map(x => 2 * x, list(12, 11, 3)), list(24, 22, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`member: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal( - member(4, list(1, 2, 3, 4, 123, 456, 789)), - list(4, 123, 456, 789));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`pair creates pair: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "is_pair (pair(1, 'a string \\"\\"'));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`recursive list definitions are possible (head): expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = list (1,a); -head(a) + head(head(tail(a)));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`recursive pair definitions are possible (head): expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair (a,1); -tail(a) + tail(head(a));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`recursive pair definitions are possible (tail): expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair (1,a); -head(a) + head(tail(a));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove all ones on infinite list of ones and twos: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,pair(2,a)); -const b = remove_all(1,a); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove not found: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal (remove(2, list(1)),list(1));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove on infinite list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "const a = pair(1,a); -const b = remove(1,a); -list_ref(b,200);", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "remove(1, list(1));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": null, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove_all not found: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(remove_all(1, list(2, 3, 4)), list(2, 3, 4));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove_all: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(remove_all(1, list(1, 2, 3, 4, 1, 1, 1, 5, 1, 1, 6)), list(2, 3, 4, 5, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`reverse: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(reverse(list(\\"string\\", \\"null\\", \\"undefined\\", \\"null\\", 123)), list(123, \\"null\\", \\"undefined\\", \\"null\\", \\"string\\"));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`tail of a 1 element list is null: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "tail(list(1));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": null, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`tail works: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "tail(pair(1, 'a string \\"\\"'));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "a string \\"\\"", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; diff --git a/src/stdlib/__tests__/__snapshots__/list.ts.snap b/src/stdlib/__tests__/__snapshots__/list.ts.snap index e0d1de59a..b545f8a4f 100644 --- a/src/stdlib/__tests__/__snapshots__/list.ts.snap +++ b/src/stdlib/__tests__/__snapshots__/list.ts.snap @@ -325,32 +325,6 @@ Object { } `; -exports[`append: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(append(list(123, 123), list(456, 456, 456)), list(123, 123, 456, 456, 456));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`build_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(build_list(x => x * x, 5), list(0, 1, 4, 9, 16));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`display_list MCE fuzz test: expectDisplayResult 1`] = ` Object { "alertResult": Array [], @@ -733,32 +707,6 @@ Object { } `; -exports[`enum_list with floats: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(enum_list(1.5, 5), list(1.5, 2.5, 3.5, 4.5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`enum_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(enum_list(1, 5), list(1, 2, 3, 4, 5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`equal: expectResult 1`] = ` Object { "alertResult": Array [], @@ -772,19 +720,6 @@ Object { } `; -exports[`filter: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(filter(x => x <= 4, list(2, 10, 1000, 1, 3, 100, 4, 5, 2, 1000)), list(2, 1, 3, 4, 2));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`for_each: expectResult 1`] = ` Object { "alertResult": Array [], @@ -851,25 +786,20 @@ list(1, 'a string \\"\\"', () => f, f, true, 3.14);", "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": Array [ - 1, - Array [ - "a string \\"\\"", - Array [ - [Function], - Array [ - [Function], - Array [ - true, - Array [ - 3.14, - null, - ], - ], - ], - ], - ], - ], + "result": "native:[ 1, +[ \\"a string \\\\\\"\\\\\\"\\", +[ () => f, +[ function f() { + return 1; + }, +[true, [3.14, null]]]]]] +interpreted:[ 1, +[ \\"a string \\\\\\"\\\\\\"\\", +[ () => f, +[ () => { + return 1; + }, +[true, [3.14, null]]]]]]", "resultStatus": "finished", "visualiseListResult": Array [], } @@ -901,34 +831,6 @@ Object { } `; -exports[`map: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(map(x => 2 * x, list(12, 11, 3)), list(24, 22, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`member: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal( - member(4, list(1, 2, 3, 4, 123, 456, 789)), - list(4, 123, 456, 789));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`non-list error head: expectParsedError 1`] = ` Object { "alertResult": Array [], @@ -1000,77 +902,6 @@ Object { } `; -exports[`remove_all not found: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(remove_all(1, list(2, 3, 4)), list(2, 3, 4));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove_all: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(remove_all(1, list(1, 2, 3, 4, 1, 1, 1, 5, 1, 1, 6)), list(2, 3, 4, 5, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`reverse: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(reverse(list(\\"string\\", \\"null\\", \\"undefined\\", \\"null\\", 123)), list(123, \\"null\\", \\"undefined\\", \\"null\\", \\"string\\"));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`set_head: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "let p = pair(1, 2); -const q = p; -set_head(p, 3); -p === q && equal(p, pair(3, 2));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`set_tail: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "let p = pair(1, 2); -const q = p; -set_tail(p, 3); -p === q && equal(p, pair(1, 3));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`tail of a 1 element list is null: expectResult 1`] = ` Object { "alertResult": Array [], diff --git a/src/stdlib/__tests__/__snapshots__/stream.ts.snap b/src/stdlib/__tests__/__snapshots__/stream.ts.snap index 4ab231de7..37c28046f 100644 --- a/src/stdlib/__tests__/__snapshots__/stream.ts.snap +++ b/src/stdlib/__tests__/__snapshots__/stream.ts.snap @@ -1,75 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`append: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(stream_append(stream(\\"string\\", 123), stream(456, null, undefined))) - , list(\\"string\\", 123, 456, null, undefined));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`build_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(build_stream(x => x * x, 5)), list(0, 1, 4, 9, 16));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`enum_list with floats: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(enum_stream(1.5, 5)), list(1.5, 2.5, 3.5, 4.5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`enum_list: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(enum_stream(1, 5)), list(1, 2, 3, 4, 5));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`filter: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal( - stream_to_list( - stream_filter(x => x <= 4, stream(2, 10, 1000, 1, 3, 100, 4, 5, 2, 1000)) - ) -, list(2, 1, 3, 4, 2));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`for_each: expectResult 1`] = ` Object { "alertResult": Array [], @@ -100,34 +30,6 @@ Object { } `; -exports[`map: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(stream_map(x => 2 * x, stream(12, 11, 3))), list(24, 22, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`member: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal( - stream_to_list(stream_member(\\"string\\", stream(1, 2, 3, \\"string\\", 123, 456, null, undefined))), - list(\\"string\\", 123, 456, null, undefined));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`primitive stream functions empty stream is null: expectResult 1`] = ` Object { "alertResult": Array [], @@ -164,10 +66,8 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": Array [ - 1, - [Function], - ], + "result": "native:[1, () => integers_from(n + 1)] +interpreted:undefined", "resultStatus": "finished", "visualiseListResult": Array [], } @@ -230,22 +130,6 @@ Object { } `; -exports[`remove not found: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "stream_to_list(stream_remove(2, stream(1)));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": Array [ - 1, - null, - ], - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - exports[`remove: expectResult 1`] = ` Object { "alertResult": Array [], @@ -258,46 +142,3 @@ Object { "visualiseListResult": Array [], } `; - -exports[`remove_all not found: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(stream_remove_all(1, stream(2, 3, \\"1\\"))), list(2, 3, \\"1\\"));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`remove_all: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list(stream_remove_all(1, stream(1, 2, 3, 4, 1, 1, \\"1\\", 5, 1, 1, 6))), - list(2, 3, 4, \\"1\\", 5, 6));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`reverse: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "equal(stream_to_list( - stream_reverse( - stream(\\"string\\", null, undefined, null, 123))), -list(123, null, undefined, null, \\"string\\"));", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; diff --git a/src/utils/testing.ts b/src/utils/testing.ts index 8b1d0be1a..2380e5acf 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -117,7 +117,7 @@ async function testInContext(code: string, options: TestOptions): Promise