From eb5fd65c1f282fc004833afd988a984b2bd4b498 Mon Sep 17 00:00:00 2001 From: Ahmedjjj <33035022+Ahmedjjj@users.noreply.github.com> Date: Tue, 28 Apr 2020 07:59:59 +0800 Subject: [PATCH] Lazy lists support for lazy source 2 (#564) * added option for lazy evaluation to interpreter * tests for lazy evaluation * finished transpiler * additional test case * updated REPL to have nice command line args * updated REPL to have nice command line args * added html test reporter * fixed function printing bug in REPL * formatting * fixed REPL printing bug for null and undefined * changed REPL bug fix * changed REPL bug fix * implement lazy pairs * add lazy pairs * add tests for lists, fix bugs for lazy lists * previous tests fixes * remove console.log calls * minor style fix for lazy context creation * untracked coverage * formatting * Updated last references to evaluationMethod Co-authored-by: Ian Duncan --- .gitignore | 1 + package.json | 2 +- src/createContext.ts | 43 +- src/interpreter/interpreter.ts | 28 + src/repl/repl.ts | 2 +- .../__tests__/__snapshots__/lazyLists.ts.snap | 2224 +++++++++++++++++ src/stdlib/__tests__/lazyLists.ts | 423 ++++ src/stdlib/lazyList.prelude.ts | 164 ++ src/utils/operators.ts | 53 +- src/utils/stringify.ts | 2 + src/utils/testing.ts | 1 - 11 files changed, 2916 insertions(+), 27 deletions(-) create mode 100644 src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap create mode 100644 src/stdlib/__tests__/lazyLists.ts create mode 100644 src/stdlib/lazyList.prelude.ts diff --git a/.gitignore b/.gitignore index 99c890ab8..f794196d2 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ node_modules *.map dist/ .idea/ +coverage/ # emacs backup files *~ diff --git a/package.json b/package.json index 48bda6b07..c45eed01e 100644 --- a/package.json +++ b/package.json @@ -91,7 +91,7 @@ "/src/typings/", "/src/utils/testing.ts" ], - "reporters": [ + "reporters": [ "default", [ "./node_modules/jest-html-reporter", diff --git a/src/createContext.ts b/src/createContext.ts index 32142acad..ca3b90eeb 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -13,7 +13,15 @@ import { streamPrelude } from './stdlib/stream.prelude' import { Context, CustomBuiltIns, Value, Variant } from './types' import * as operators from './utils/operators' import { stringify } from './utils/stringify' - +import { lazyListPrelude } from './stdlib/lazyList.prelude' +export class LazyBuiltIn { + func: (...arg0: any) => any + evaluateArgs: boolean + constructor(func: (...arg0: any) => any, evaluateArgs: boolean) { + this.func = func + this.evaluateArgs = evaluateArgs + } +} const createEmptyRuntime = () => ({ break: false, debuggerOn: true, @@ -103,6 +111,12 @@ export const defineBuiltin = (context: Context, name: string, value: Value) => { wrapped.toString = () => repr defineSymbol(context, funName, wrapped) + } else if (value instanceof LazyBuiltIn) { + const wrapped = (...args: any) => value.func(...args) + const funName = name.split('(')[0].trim() + const repr = `function ${name} {\n\t[implementation hidden]\n}` + wrapped.toString = () => repr + defineSymbol(context, funName, new LazyBuiltIn(wrapped, value.evaluateArgs)) } else { defineSymbol(context, name, value) } @@ -154,13 +168,24 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn if (context.chapter >= 2) { // List library - defineBuiltin(context, 'pair(left, right)', list.pair) - defineBuiltin(context, 'is_pair(val)', list.is_pair) - defineBuiltin(context, 'head(xs)', list.head) - defineBuiltin(context, 'tail(xs)', list.tail) - defineBuiltin(context, 'is_null(val)', list.is_null) - defineBuiltin(context, 'list(...values)', list.list) - defineBuiltin(context, 'draw_data(xs)', visualiseList) + + if (context.variant === 'lazy') { + defineBuiltin(context, 'pair(left, right)', new LazyBuiltIn(list.pair, false)) + defineBuiltin(context, 'list(...values)', new LazyBuiltIn(list.list, false)) + defineBuiltin(context, 'is_pair(val)', new LazyBuiltIn(list.is_pair, true)) + defineBuiltin(context, 'head(xs)', new LazyBuiltIn(list.head, true)) + defineBuiltin(context, 'tail(xs)', new LazyBuiltIn(list.tail, true)) + defineBuiltin(context, 'is_null(val)', new LazyBuiltIn(list.is_null, true)) + defineBuiltin(context, 'draw_data(xs)', new LazyBuiltIn(visualiseList, true)) + } else { + defineBuiltin(context, 'pair(left, right)', list.pair) + defineBuiltin(context, 'is_pair(val)', list.is_pair) + defineBuiltin(context, 'head(xs)', list.head) + defineBuiltin(context, 'tail(xs)', list.tail) + defineBuiltin(context, 'is_null(val)', list.is_null) + defineBuiltin(context, 'list(...values)', list.list) + defineBuiltin(context, 'draw_data(xs)', visualiseList) + } } if (context.chapter >= 3) { @@ -202,7 +227,7 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn function importPrelude(context: Context) { let prelude = '' if (context.chapter >= 2) { - prelude += listPrelude + prelude += context.variant === 'lazy' ? lazyListPrelude : listPrelude } if (context.chapter >= 3) { prelude += streamPrelude diff --git a/src/interpreter/interpreter.ts b/src/interpreter/interpreter.ts index 2e2333b62..471b7d0ea 100644 --- a/src/interpreter/interpreter.ts +++ b/src/interpreter/interpreter.ts @@ -9,6 +9,7 @@ import { conditionalExpression, literal, primitive } from '../utils/astCreator' import { evaluateBinaryExpression, evaluateUnaryExpression } from '../utils/operators' import * as rttc from '../utils/rttc' import Closure from './closure' +import { LazyBuiltIn } from '../createContext' import { loadIIFEModule } from '../modules/moduleLoader' class BreakValue {} @@ -662,6 +663,33 @@ export function* apply( // 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 ? node.loc! : constants.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') { try { const forcedArgs = [] diff --git a/src/repl/repl.ts b/src/repl/repl.ts index 9ba212fad..e32999841 100644 --- a/src/repl/repl.ts +++ b/src/repl/repl.ts @@ -14,7 +14,7 @@ function startRepl( prelude = '' ) { // use defaults for everything - const context = createContext(chapter) + const context = createContext(chapter, undefined, undefined, undefined) const options: Partial = { scheduler: 'preemptive', executionMethod, diff --git a/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap b/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap new file mode 100644 index 000000000..f37a6ccd2 --- /dev/null +++ b/src/stdlib/__tests__/__snapshots__/lazyLists.ts.snap @@ -0,0 +1,2224 @@ +// 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 [], + "errors": Array [], + "parsedErrors": "", + "result": 10, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(accumulate, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return wrap((curr, acc) => ({ isTail: false, value: binaryOp(\\\\\\"+\\\\\\", curr, acc, 1, 26) }), \\\\\\"(curr, acc) => curr + acc\\\\\\"); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 0; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 41, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + const b = callIfFuncAndRightArgs(append, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return callIfFuncAndRightArgs(list, 2, 20, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 3; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 4; + } + }); + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + const b = callIfFuncAndRightArgs(append, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return callIfFuncAndRightArgs(list, 2, 17, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 3; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 4; + } + }); + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`append: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal(append(list(\\"string\\", 123), list(456, null, undefined)), list(\\"string\\", 123, 456, null, undefined));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(append, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 13, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 34, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 456; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 63, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 456; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`arguments are not evaluated for list: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "head(list(1,head(null)));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(head, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 5, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(head, 1, 12, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }); } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`arguments are not evaluated for pair: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "head(pair(1,head(null)));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(head, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(pair, 1, 5, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(head, 1, 12, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }); } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad index error list_ref: expectParsedError 1`] = ` +Object { + "alertResult": Array [], + "code": "list_ref(list(1, 2, 3), 3);", + "displayResult": Array [], + "errors": Array [ + ExceptionError { + "error": [Error: tail(xs) expects a pair as argument xs, but encountered null], + "location": SourceLocation { + "end": Position { + "column": 23, + "line": 148, + }, + "start": Position { + "column": 15, + "line": 148, + }, + }, + "severity": "Error", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad index error list_ref: expectParsedError 2`] = ` +Object { + "alertResult": Array [], + "code": "list_ref(list(1, 2, 3), -1);", + "displayResult": Array [], + "errors": Array [ + ExceptionError { + "error": [Error: tail(xs) expects a pair as argument xs, but encountered null], + "location": SourceLocation { + "end": Position { + "column": 23, + "line": 148, + }, + "start": Position { + "column": 15, + "line": 148, + }, + }, + "severity": "Error", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return unaryOp(\\\\\\"-\\\\\\", 1, 1, 24); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad index error list_ref: expectParsedError 3`] = ` +Object { + "alertResult": Array [], + "code": "list_ref(list(1, 2, 3), 1.5);", + "displayResult": Array [], + "errors": Array [ + ExceptionError { + "error": [Error: tail(xs) expects a pair as argument xs, but encountered null], + "location": SourceLocation { + "end": Position { + "column": 23, + "line": 148, + }, + "start": Position { + "column": 15, + "line": 148, + }, + }, + "severity": "Error", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1.5; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad index error list_ref: expectParsedError 4`] = ` +Object { + "alertResult": Array [], + "code": "list_ref(list(1, 2, 3), '1');", + "displayResult": Array [], + "errors": Array [ + TypeError { + "expected": "number", + "got": "string", + "location": SourceLocation { + "end": Position { + "column": 50, + "line": 149, + }, + "start": Position { + "column": 45, + "line": 149, + }, + }, + "severity": "Error", + "side": " on left hand side of operation", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 149: Expected number on left hand side of operation, got string.", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '1'; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad number error build_list: expectParsedError 1`] = ` +Object { + "alertResult": Array [], + "code": "build_list('1', x => x);", + "displayResult": Array [], + "errors": Array [ + TypeError { + "expected": "number", + "got": "string", + "location": SourceLocation { + "end": Position { + "column": 20, + "line": 45, + }, + "start": Position { + "column": 15, + "line": 45, + }, + }, + "severity": "Error", + "side": " on left hand side of operation", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 45: Expected number on left hand side of operation, got string.", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(build_list, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '1'; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return wrap(x => ({ isTail: false, value: x }), \\\\\\"x => x\\\\\\"); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad number error enum_list: expectParsedError 1`] = ` +Object { + "alertResult": Array [], + "code": "enum_list('1', '5');", + "displayResult": Array [], + "errors": Array [ + TypeError { + "expected": "string", + "got": "number", + "location": SourceLocation { + "end": Position { + "column": 28, + "line": 139, + }, + "start": Position { + "column": 19, + "line": 139, + }, + }, + "severity": "Error", + "side": " on right hand side of operation", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 139: Expected string on right hand side of operation, got number.", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(enum_list, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '1'; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '5'; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad number error enum_list: expectParsedError 2`] = ` +Object { + "alertResult": Array [], + "code": "enum_list('1', 5);", + "displayResult": Array [], + "errors": Array [ + TypeError { + "expected": "string", + "got": "number", + "location": SourceLocation { + "end": Position { + "column": 28, + "line": 139, + }, + "start": Position { + "column": 19, + "line": 139, + }, + }, + "severity": "Error", + "side": " on right hand side of operation", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 139: Expected string on right hand side of operation, got number.", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(enum_list, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '1'; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`bad number error enum_list: expectParsedError 3`] = ` +Object { + "alertResult": Array [], + "code": "enum_list(1, '5');", + "displayResult": Array [], + "errors": Array [ + TypeError { + "expected": "number", + "got": "string", + "location": SourceLocation { + "end": Position { + "column": 20, + "line": 140, + }, + "start": Position { + "column": 9, + "line": 140, + }, + }, + "severity": "Error", + "side": " on right hand side of operation", + "type": "Runtime", + }, + ], + "parsedErrors": "Line 140: Expected number on right hand side of operation, got string.", + "result": undefined, + "resultStatus": "error", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(enum_list, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return '5'; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`build_list: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal(build_list(5, x => x * x), list(0, 1, 4, 9, 16));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(build_list, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return wrap(x => ({ isTail: false, value: binaryOp(\\\\\\"*\\\\\\", x, x, 1, 25) }), \\\\\\"x => x * x\\\\\\"); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 33, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 0; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 9; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 16; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`empty list is null: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "list();", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": null, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list, 1, 0);\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(enum_list, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1.5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 25, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1.5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2.5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3.5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4.5; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`enum_list: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal(enum_list(1, 5), list(1, 2, 3, 4, 5));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(enum_list, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 23, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return callIfFuncAndRightArgs(pair, 1, 17, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 2; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + } + }); + const b = callIfFuncAndRightArgs(filter, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return wrap(x => ({ + isTail: false, + value: binaryOp(\\"===\\", binaryOp(\\"%\\", x, 2, 2, 22), 0, 2, 22) + }), \\"x => x % 2 === 0\\"); + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(filter, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return wrap(x => ({ isTail: false, value: binaryOp(\\\\\\"<=\\\\\\", x, 4, 1, 18) }), \\\\\\"x => x <= 4\\\\\\"); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 26, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 10; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1000; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 100; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1000; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 72, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 6, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + let sum = 0; + callIfFuncAndRightArgs(for_each, 2, 0, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return wrap(x => { + sum = binaryOp(\\"+\\", sum, x, 3, 8); + }, \\"x => {\\\\n sum = sum + x;\\\\n}\\"); + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return callIfFuncAndRightArgs(list, 4, 3, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 2; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 3; + } + }); + } + }); + lastStatementResult = eval(\\"sum;\\"); + globals.variables.set(\\"sum\\", { + kind: \\"let\\", + getValue: () => { + return sum; + }, + assignNewValue: function (unique) { + return sum = unique; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`head works: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "head(pair(1, 'a string \\"\\"'));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(head, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(pair, 1, 5, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 'a string \\\\\\"\\\\\\"'; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(list, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(is_list, 2, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 2, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`list_ref: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "list_ref(list(1, 2, 3, \\"4\\", 4), 4);", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": 4, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"4\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`list_to_string: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "list_to_string(list(1, 2, 3));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": "[1,[2,[3,null]]]", + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_to_string, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 15, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + const b = callIfFuncAndRightArgs(map, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return wrap(x => ({ + isTail: false, + value: binaryOp(\\"*\\", 2, x, 2, 19) + }), \\"x => 2 * x\\"); + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + const b = callIfFuncAndRightArgs(map, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return wrap(x => ({ + isTail: false, + value: binaryOp(\\"*\\", 2, x, 2, 19) + }), \\"x => 2 * x\\"); + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(map, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return wrap(x => ({ isTail: false, value: binaryOp(\\\\\\"*\\\\\\", 2, x, 1, 15) }), \\\\\\"x => 2 * x\\\\\\"); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 22, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 12; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 11; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 40, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 24; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 22; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 6; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`member: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal( + member(\\"string\\", list(1, 2, 3, \\"string\\", 123, 456, null, undefined)), + list(\\"string\\", 123, 456, null, undefined));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(member, 2, 2, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 2, 19, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 456; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 3, 2, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 456; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`pair creates pair: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "is_pair (pair(1, 'a string \\"\\"'));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(is_pair, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(pair, 1, 9, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 'a string \\\\\\"\\\\\\"'; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(list, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"binaryOp(\\\\\\"+\\\\\\", callIfFuncAndRightArgs(head, 2, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }), callIfFuncAndRightArgs(head, 2, 10, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(head, 2, 15, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(tail, 2, 20, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }); } }); } }), 2, 0);\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }); + lastStatementResult = eval(\\"binaryOp(\\\\\\"+\\\\\\", callIfFuncAndRightArgs(tail, 2, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }), callIfFuncAndRightArgs(tail, 2, 10, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(head, 2, 15, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }); } }), 2, 0);\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"binaryOp(\\\\\\"+\\\\\\", callIfFuncAndRightArgs(head, 2, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }), callIfFuncAndRightArgs(head, 2, 10, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(tail, 2, 15, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return a; } }); } }), 2, 0);\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 2, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return callIfFuncAndRightArgs(pair, 1, 17, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 2; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + } + }); + const b = callIfFuncAndRightArgs(remove_all, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`remove not found: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal (remove(2, list(1)),list(1));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(remove, 1, 7, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 17, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 26, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": 1, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + const a = callIfFuncAndRightArgs(pair, 1, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + const b = callIfFuncAndRightArgs(remove, 2, 10, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return 1; + } + }, { + isThunk: true, + memoizedValue: 0, + isMemoized: false, + expr: () => { + return a; + } + }); + lastStatementResult = eval(\\"callIfFuncAndRightArgs(list_ref, 3, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return b; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 200; } });\\"); + globals.variables.set(\\"a\\", { + kind: \\"const\\", + getValue: () => { + return a; + } + }); + globals.variables.set(\\"b\\", { + kind: \\"const\\", + getValue: () => { + return b; + } + }); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`remove: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "remove(1, list(1));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": null, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(remove, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 10, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`remove_all not found: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "equal(remove_all(1, list(2, 3, \\"1\\")), list(2, 3, \\"1\\"));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(remove_all, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 20, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"1\\\\\\"; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 38, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"1\\\\\\"; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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, \\"1\\", 5, 6));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(remove_all, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 20, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"1\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 6; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 62, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 2; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 3; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 4; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"1\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 5; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 6; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "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 [], + "errors": Array [], + "parsedErrors": "", + "result": true, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(equal, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(reverse, 1, 6, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 14, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }); } }); } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 59, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 123; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return undefined; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return null; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return \\\\\\"string\\\\\\"; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`tail of a 1 element list is null: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "tail(list(1));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": null, + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(tail, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(list, 1, 5, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; + +exports[`tail works: expectResult 1`] = ` +Object { + "alertResult": Array [], + "code": "tail(pair(1, 'a string \\"\\"'));", + "displayResult": Array [], + "errors": Array [], + "parsedErrors": "", + "result": "a string \\"\\"", + "resultStatus": "finished", + "transpiled": "const native = $$NATIVE_STORAGE; +const forceIt = native.operators.get(\\"forceIt\\"); +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_STORAGE.globals; +(( ) => { + return (() => { + { + { + lastStatementResult = eval(\\"callIfFuncAndRightArgs(tail, 1, 0, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return callIfFuncAndRightArgs(pair, 1, 5, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 1; } }, { isThunk: true, memoizedValue: 0, isMemoized: false, expr: () => { return 'a string \\\\\\"\\\\\\"'; } }); } });\\"); + } + } + return forceIt(lastStatementResult); + })(); +})(); +", + "visualiseListResult": Array [], +} +`; diff --git a/src/stdlib/__tests__/lazyLists.ts b/src/stdlib/__tests__/lazyLists.ts new file mode 100644 index 000000000..377f29e1d --- /dev/null +++ b/src/stdlib/__tests__/lazyLists.ts @@ -0,0 +1,423 @@ +import { stripIndent } from '../../utils/formatters' +import { expectParsedError, expectResult } from '../../utils/testing' + +test('pair creates pair', () => { + return expectResult( + stripIndent` + is_pair (pair(1, 'a string ""')); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('head works', () => { + return expectResult( + stripIndent` + head(pair(1, 'a string ""')); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('tail works', () => { + return expectResult( + stripIndent` + tail(pair(1, 'a string ""')); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`"a string \\"\\""`) +}) + +test('tail of a 1 element list is null', () => { + return expectResult( + stripIndent` + tail(list(1)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`null`) +}) + +test('empty list is null', () => { + return expectResult( + stripIndent` + list(); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot('null') +}) + +test('for_each', () => { + return expectResult( + stripIndent` + let sum = 0; + for_each(x => { + sum = sum + x; + }, list(1, 2, 3)); + sum; + `, + { chapter: 3, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`6`) +}) + +test('map', () => { + return expectResult( + stripIndent` + equal(map(x => 2 * x, list(12, 11, 3)), list(24, 22, 6)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('filter', () => { + return expectResult( + stripIndent` + equal(filter(x => x <= 4, list(2, 10, 1000, 1, 3, 100, 4, 5, 2, 1000)), list(2, 1, 3, 4, 2)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('build_list', () => { + return expectResult( + stripIndent` + equal(build_list(5, x => x * x), list(0, 1, 4, 9, 16)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('reverse', () => { + return expectResult( + stripIndent` + equal(reverse(list("string", null, undefined, null, 123)), list(123, null, undefined, null, "string")); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('append', () => { + return expectResult( + stripIndent` + equal(append(list("string", 123), list(456, null, undefined)), list("string", 123, 456, null, undefined)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('member', () => { + return expectResult( + stripIndent` + equal( + member("string", list(1, 2, 3, "string", 123, 456, null, undefined)), + list("string", 123, 456, null, undefined)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('remove', () => { + return expectResult( + stripIndent` + remove(1, list(1)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`null`) +}) + +test('remove not found', () => { + return expectResult( + stripIndent` + equal (remove(2, list(1)),list(1)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('remove_all', () => { + return expectResult( + stripIndent` + equal(remove_all(1, list(1, 2, 3, 4, 1, 1, "1", 5, 1, 1, 6)), list(2, 3, 4, "1", 5, 6)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('remove_all not found', () => { + return expectResult( + stripIndent` + equal(remove_all(1, list(2, 3, "1")), list(2, 3, "1")); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('enum_list', () => { + return expectResult( + stripIndent` + equal(enum_list(1, 5), list(1, 2, 3, 4, 5)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('enum_list with floats', () => { + return expectResult( + stripIndent` + equal(enum_list(1.5, 5), list(1.5, 2.5, 3.5, 4.5)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) + +test('list_ref', () => { + return expectResult( + stripIndent` + list_ref(list(1, 2, 3, "4", 4), 4); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`4`) +}) + +test('accumulate', () => { + return expectResult( + stripIndent` + accumulate((curr, acc) => curr + acc, 0, list(2, 3, 4, 1)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`10`) +}) + +test('list_to_string', () => { + return expectResult( + stripIndent` + list_to_string(list(1, 2, 3)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`"[1,[2,[3,null]]]"`) +}) +test('bad number error build_list', () => { + return expectParsedError( + stripIndent` + build_list('1', x => x); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`"Line 45: Expected number on left hand side of operation, got string."`) +}) + +test('bad number error enum_list', () => { + return expectParsedError( + stripIndent` +enum_list('1', '5'); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 139: Expected string on right hand side of operation, got number."` + ) +}) + +test('bad number error enum_list', () => { + return expectParsedError( + stripIndent` +enum_list('1', 5); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 139: Expected string on right hand side of operation, got number."` + ) +}) + +test('bad number error enum_list', () => { + return expectParsedError( + stripIndent` +enum_list(1, '5'); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 140: Expected number on right hand side of operation, got string."` + ) +}) + +test('bad index error list_ref', () => { + return expectParsedError( + stripIndent` +list_ref(list(1, 2, 3), 3); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null"` + ) +}) + +test('bad index error list_ref', () => { + return expectParsedError( + stripIndent` +list_ref(list(1, 2, 3), -1); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null"` + ) +}) + +test('bad index error list_ref', () => { + return expectParsedError( + stripIndent` +list_ref(list(1, 2, 3), 1.5); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot( + `"Line 148: Error: tail(xs) expects a pair as argument xs, but encountered null"` + ) +}) + +test('bad index error list_ref', () => { + return expectParsedError( + stripIndent` +list_ref(list(1, 2, 3), '1'); +`, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`"Line 149: Expected number on left hand side of operation, got string."`) +}) + +test('arguments are not evaluated for pair', () => { + return expectResult( + stripIndent` + head(pair(1,head(null))); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) +test('arguments are not evaluated for list', () => { + return expectResult( + stripIndent` + head(list(1,head(null))); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('recursive pair definitions are possible (tail)', () => { + return expectResult( + stripIndent` + const a = pair (1,a); + head(a) + head(tail(a)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('recursive pair definitions are possible (head)', () => { + return expectResult( + stripIndent` + const a = pair (a,1); + tail(a) + tail(head(a)); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('recursive list definitions are possible (head)', () => { + return expectResult( + stripIndent` + const a = list (1,a); + head(a) + head(head(tail(a))); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('is_list on infinite lists works', () => { + return expectResult( + stripIndent` + const a = list(1,a); + is_list(a); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`true`) +}) +test('list_ref on infinite lists', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + list_ref(a,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('map on infinite lists works', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + const b = map(x => 2 * x, a); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('map on infinite lists works', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + const b = map(x => 2 * x, a); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('append left list is infinite', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + const b = append(a, list(3,4)); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('append right list is infinite', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + const b = append(list(3,4),a); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('remove on infinite list', () => { + return expectResult( + stripIndent` + const a = pair(1,a); + const b = remove(1,a); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`1`) +}) + +test('remove all ones on infinite list of ones and twos', () => { + return expectResult( + stripIndent` + const a = pair(1,pair(2,a)); + const b = remove_all(1,a); + list_ref(b,200); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) + +test('filter on infinite lists', () => { + return expectResult( + stripIndent` + const a = pair(1,pair(2,a)); + const b = filter(x => x % 2 === 0,a); + list_ref(b,1); + `, + { chapter: 2, native: true, variant: 'lazy' } + ).toMatchInlineSnapshot(`2`) +}) diff --git a/src/stdlib/lazyList.prelude.ts b/src/stdlib/lazyList.prelude.ts new file mode 100644 index 000000000..dc2a7aac1 --- /dev/null +++ b/src/stdlib/lazyList.prelude.ts @@ -0,0 +1,164 @@ +export const lazyListPrelude = ` + +/** + * recurses down the list and checks that it ends with the empty list null + * @param {value} xs - given candidate + * @returns {boolean} indicating whether {xs} is a list + */ + +function is_list(xs) { + return is_null(xs) || (is_pair(xs) && is_list(tail(xs))); +} + +// equal computes the structural equality +// over its arguments + +function equal(x, y) { + return is_pair(x) && is_pair(y) ? equal(head(x), head(y)) && equal(tail(x), tail(y)) : x === y; +} + +// returns the length of a given argument list +// assumes that the argument is a list + +function length(xs) { + return is_null(xs) ? 0 : 1 + length(tail(xs)); +} + +// map applies first arg f, assumed to be a unary function, +// to the elements of the second argument, assumed to be a list. +// f is applied element-by-element: +// map(f, list(1, 2)) results in list(f(1), f(2)) + +function map(f, xs) { + return is_null(xs) ? null : pair(f(head(xs)), map(f, tail(xs))); +} + +// build_list takes a non-negative integer n as first argument, +// and a function fun as second argument. +// build_list returns a list of n elements, that results from +// applying fun to the numbers from 0 to n-1. + +function build_list(n, fun) { + function build(i, fun, already_built) { + return i < 0 ? already_built : build(i - 1, fun, pair(fun(i), already_built)); + } + return build(n - 1, fun, null); +} + +// for_each applies first arg fun, assumed to be a unary function, +// to the elements of the second argument, assumed to be a list. +// fun is applied element-by-element: +// for_each(fun, list(1, 2)) results in the calls fun(1) and fun(2). +// for_each returns true. + +function for_each(fun, xs) { + if (is_null(xs)) { + return true; + } else { + fun(head(xs)); + return for_each(fun, tail(xs)); + } +} + +// list_to_string returns a string that represents the argument list. +// It applies itself recursively on the elements of the given list. +// When it encounters a non-list, it applies to_string to it. + +function list_to_string(xs) { + return is_null(xs) + ? "null" + : is_pair(xs) + ? "[" + list_to_string(head(xs)) + "," + + list_to_string(tail(xs)) + "]" + : stringify(xs); +} + +// reverse reverses the argument, assumed to be a list + +function reverse(xs) { + function rev(original, reversed) { + return is_null(original) ? reversed : rev(tail(original), pair(head(original), reversed)); + } + return rev(xs, null); +} + +// append first argument, assumed to be a list, to the second argument. +// In the result null at the end of the first argument list +// is replaced by the second argument, regardless what the second +// argument consists of. + +function append(xs, ys) { + return is_null(xs) ? ys : pair(head(xs), append(tail(xs), ys)); +} + +// member looks for a given first-argument element in the +// second argument, assumed to be a list. It returns the first +// postfix sublist that starts with the given element. It returns null if the +// element does not occur in the list + +function member(v, xs) { + return is_null(xs) ? null : v === head(xs) ? xs : member(v, tail(xs)); +} + +// removes the first occurrence of a given first-argument element +// in second-argument, assmed to be a list. Returns the original +// list if there is no occurrence. + +function remove(v, xs) { + return is_null(xs) ? null : v === head(xs) ? tail(xs) : pair(head(xs), remove(v, tail(xs))); +} + +// Similar to remove, but removes all instances of v +// instead of just the first + +function remove_all(v, xs) { + return is_null(xs) + ? null + : v === head(xs) + ? remove_all(v, tail(xs)) + : pair(head(xs), remove_all(v, tail(xs))); +} + +// filter returns the sublist of elements of the second argument +// (assumed to be a list), for which the given predicate function +// returns true. + +function filter(pred, xs) { + return is_null(xs) + ? xs + : pred(head(xs)) + ? pair(head(xs), filter(pred, tail(xs))) + : filter(pred, tail(xs)); +} + +// enumerates numbers starting from start, assumed to be a number, +// using a step size of 1, until the number exceeds end, assumed +// to be a number + +function enum_list(start, end) { + const newStart = start + 1; + return start > end ? null : pair(start, enum_list(newStart, end)); +} + +// Returns the item in xs (assumed to be a list) at index n, +// assumed to be a non-negative integer. +// Note: the first item is at position 0 + +function list_ref(xs, n) { + const rest = tail(xs); + return n === 0 ? head(xs) : list_ref(rest, n - 1); +} + +// accumulate applies an operation op (assumed to be a binary function) +// to elements of sequence (assumed to be a list) in a right-to-left order. +// first apply op to the last element and initial, resulting in r1, then to +// the second-last element and r1, resulting in r2, etc, and finally +// to the first element and r_n-1, where n is the length of the +// list. +// accumulate(op, zero, list(1, 2, 3)) results in +// op(1, op(2, op(3, zero))) + +function accumulate(f, initial, xs) { + return is_null(xs) ? initial : f(head(xs), accumulate(f, initial, tail(xs))); +} +` diff --git a/src/utils/operators.ts b/src/utils/operators.ts index 69dbf6945..685810094 100644 --- a/src/utils/operators.ts +++ b/src/utils/operators.ts @@ -14,6 +14,7 @@ import { import { callExpression, locationDummyNode } from './astCreator' import * as create from './astCreator' import * as rttc from './rttc' +import { LazyBuiltIn } from '../createContext' export function throwIfTimeout(start: number, current: number, line: number, column: number) { if (current - start > JSSLANG_PROPERTIES.maxExecTime) { @@ -72,6 +73,20 @@ export function callIfFuncAndRightArgs( } return candidate(...args) } + } else if (candidate instanceof LazyBuiltIn) { + try { + if (candidate.evaluateArgs) { + args = args.map(forceIt) + } + return candidate.func(...args) + } catch (error) { + // if we already handled the error, simply pass it on + if (!(error instanceof RuntimeSourceError || error instanceof ExceptionError)) { + throw new ExceptionError(error, dummy.loc!) + } else { + throw error + } + } } else { throw new CallingNonFunctionValue(candidate, dummy) } @@ -179,23 +194,31 @@ export const callIteratively = (f: any, ...args: any[]) => { const dummy = locationDummyNode(line, column) if (Date.now() - startTime > MAX_TIME) { throw new PotentialInfiniteRecursionError(dummy, pastCalls) - } else if (typeof f !== 'function') { - throw new CallingNonFunctionValue(f, dummy) } - if (f.transformedFunction! !== undefined) { - f = f.transformedFunction - const expectedLength = f.length - const receivedLength = args.length - if (expectedLength !== receivedLength) { - throw new InvalidNumberOfArguments( - callExpression(locationDummyNode(line, column), args, { - start: { line, column }, - end: { line, column } - }), - expectedLength, - receivedLength - ) + f = forceIt(f) + if (typeof f === 'function') { + if (f.transformedFunction !== undefined) { + f = f.transformedFunction + const expectedLength = f.length + const receivedLength = args.length + if (expectedLength !== receivedLength) { + throw new InvalidNumberOfArguments( + callExpression(locationDummyNode(line, column), args, { + start: { line, column }, + end: { line, column } + }), + expectedLength, + receivedLength + ) + } + } + } else if (f instanceof LazyBuiltIn) { + if (f.evaluateArgs) { + args = args.map(forceIt) } + f = f.func + } else { + throw new CallingNonFunctionValue(f, dummy) } let res try { diff --git a/src/utils/stringify.ts b/src/utils/stringify.ts index 3bc351161..1671238b7 100644 --- a/src/utils/stringify.ts +++ b/src/utils/stringify.ts @@ -1,5 +1,6 @@ import { MAX_LIST_DISPLAY_LENGTH } from '../constants' import Closure from '../interpreter/closure' +import { forceIt } from './operators' import { Value, Type } from '../types' function makeIndent(indent: number | string): string { @@ -30,6 +31,7 @@ export const stringify = ( ): string => { // Used to check if there are any cyclic structures const ancestors = new Set() + value = forceIt(value) // Precompute useful strings const indentString = makeIndent(indent) diff --git a/src/utils/testing.ts b/src/utils/testing.ts index a395ca69f..af1c57694 100644 --- a/src/utils/testing.ts +++ b/src/utils/testing.ts @@ -72,7 +72,6 @@ export function createTestContext({ alertResult: [], visualiseListResult: [] } - Object.entries(testBuiltins).forEach(([key, value]) => defineBuiltin(testContext, key, value)) return testContext