From 51144f9e409ecfcbf63108632c39f246be8f387d Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 7 Mar 2024 06:26:14 +0800 Subject: [PATCH 01/41] Prepare scheme files for new parser --- src/createContext.ts | 187 ++++++++++++++++++++++++++----------- src/parser/scheme/index.ts | 57 ++++++++++- 2 files changed, 186 insertions(+), 58 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index 42c4a5563..30ed7ce96 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -415,50 +415,115 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn // Introduction to mutable values, streams // Scheme pair mutation - defineBuiltin(context, 'set$45$car$33$(pair, val)', scheme_libs.set_carB) - defineBuiltin(context, 'set$45$cdr$33$(pair, val)', scheme_libs.set_cdrB) + defineBuiltin(context, 'set$45$car$33$(pair, val)', scheme_libs.set$45$car$33$) + defineBuiltin(context, 'set$45$cdr$33$(pair, val)', scheme_libs.set$45$cdr$33$) // Scheme list mutation - defineBuiltin(context, 'list$45$set$33$(xs, n, val)', scheme_libs.list_setB) + defineBuiltin(context, 'list$45$set$33$(xs, n, val)', scheme_libs.list$45$set$33$) //defineBuiltin(context, 'filter$33$(pred, xs)', scheme_libs.filterB); // Scheme promises - defineBuiltin(context, 'promise$63$()', scheme_libs.promiseQ) + defineBuiltin(context, 'promise$63$()', scheme_libs.promise$63$) defineBuiltin(context, 'force(p)', scheme_libs.force) + // Scheme vectors + defineBuiltin(context, 'vector(...vals)', scheme_libs.vector, 0) + defineBuiltin(context, 'make$45$vector(n, val)', scheme_libs.make$45$vector, 1) + + defineBuiltin(context, 'vector$63$(v)', scheme_libs.vector$63$) + + defineBuiltin(context, 'vector$45$length(v)', scheme_libs.vector$45$length) + defineBuiltin(context, 'vector$45$empty$63$(v)', scheme_libs.vector$45$empty$63$) + + defineBuiltin(context, 'vector$45$ref(v, k)', scheme_libs.vector$45$ref) + + defineBuiltin(context, 'vector$45$set$33$(v, k, val)', scheme_libs.vector$45$set$33$) + defineBuiltin( + context, + 'vector$45$fill$33$(v, val, start, end)', + scheme_libs.vector$45$fill$33$, + 2 + ) + defineBuiltin(context, 'list$45$$62$vector(xs)', scheme_libs.list$45$$62$vector) + case Chapter.SCHEME_2: + // Splicing builtin resolvers + // defineBuiltin(context, '$36$make$45$splice(expr)', scheme_libs.make_splice) + // defineBuiltin(context, '$36$resolve$45$splice(xs)', scheme_libs.resolve_splice) + // Scheme pairs defineBuiltin(context, 'cons(left, right)', scheme_libs.cons) - defineBuiltin(context, 'pair$63$(val)', scheme_libs.pairQ) + defineBuiltin(context, 'xcons(right, left)', scheme_libs.xcons) + defineBuiltin(context, 'pair$63$(val)', scheme_libs.pair$63$) + defineBuiltin(context, 'not$45$pair$63$(val)', scheme_libs.not$45$pair$63$) defineBuiltin(context, 'car(xs)', scheme_libs.car) defineBuiltin(context, 'cdr(xs)', scheme_libs.cdr) // Scheme lists - defineBuiltin(context, 'make$45$list(n, val)', scheme_libs.make_list, 1) - defineBuiltin(context, 'list(...values)', scheme_libs.list, 0) - defineBuiltin(context, 'list$63$(val)', scheme_libs.listQ) - defineBuiltin(context, 'null$63$(val)', scheme_libs.nullQ) + defineBuiltin(context, 'list(...vals)', scheme_libs.list, 0) + defineBuiltin(context, 'list$42$(...vals)', scheme_libs.list$42$, 1) + defineBuiltin(context, 'cons$42$(...vals)', scheme_libs.cons$42$, 1) + defineBuiltin(context, 'circular$45$list(...vals)', scheme_libs.circular$45$list, 0) + defineBuiltin(context, 'make$45$list(n, val)', scheme_libs.make$45$list, 1) + + defineBuiltin(context, 'circular$45$list$63$(val)', scheme_libs.circular$45$list$63$) + defineBuiltin(context, 'proper$45$list$63$(val)', scheme_libs.proper$45$list$63$) + defineBuiltin(context, 'dotted$45$list$63$(val)', scheme_libs.dotted$45$list$63$) + defineBuiltin(context, 'null$63$(val)', scheme_libs.null$63$) + defineBuiltin(context, 'null$45$list$63$(val)', scheme_libs.null$45$list$63$) + defineBuiltin(context, 'list$63$(val)', scheme_libs.list$63$) + + defineBuiltin(context, 'list$45$tabulate(n, f)', scheme_libs.list$45$tabulate) + defineBuiltin(context, 'list$45$tail(xs, n)', scheme_libs.list$45$tail) + defineBuiltin(context, 'list$45$ref(xs, k)', scheme_libs.list$45$ref) + defineBuiltin(context, 'last(xs)', scheme_libs.last) + defineBuiltin(context, 'last$45$pair(xs)', scheme_libs.last$45$pair) + + defineBuiltin(context, 'first(xs)', scheme_libs.first) + defineBuiltin(context, 'second(xs)', scheme_libs.second) + defineBuiltin(context, 'third(xs)', scheme_libs.third) + defineBuiltin(context, 'fourth(xs)', scheme_libs.fourth) + defineBuiltin(context, 'fifth(xs)', scheme_libs.fifth) + defineBuiltin(context, 'sixth(xs)', scheme_libs.sixth) + defineBuiltin(context, 'seventh(xs)', scheme_libs.seventh) + defineBuiltin(context, 'eighth(xs)', scheme_libs.eighth) + defineBuiltin(context, 'ninth(xs)', scheme_libs.ninth) + defineBuiltin(context, 'tenth(xs)', scheme_libs.tenth) + + defineBuiltin(context, 'filter(pred, xs)', scheme_libs.filter) + defineBuiltin(context, 'map(f, ...xss)', scheme_libs.map, 2) + defineBuiltin(context, 'fold(f, init, ...xss)', scheme_libs.fold, 3) + defineBuiltin(context, 'fold$45$right(f, init, ...xss)', scheme_libs.fold$45$right, 3) + defineBuiltin(context, 'fold$45$left(f, init, ...xss)', scheme_libs.fold$45$left, 3) + defineBuiltin(context, 'reduce(f, ridentity, xs)', scheme_libs.reduce) + defineBuiltin(context, 'reduce$45$right(f, ridentity, xs)', scheme_libs.reduce$45$right) + defineBuiltin(context, 'reduce$45$left(f, ridentity, xs)', scheme_libs.reduce$45$left) + + defineBuiltin(context, 'any(xs)', scheme_libs.any) + defineBuiltin(context, 'list$45$copy(xs)', scheme_libs.list$45$copy) defineBuiltin(context, 'length(xs)', scheme_libs.length) - defineBuiltin(context, 'append(...xs)', scheme_libs.append, 0) + defineBuiltin(context, 'length$43$(xs)', scheme_libs.length$43$) + defineBuiltin(context, 'append(...xss)', scheme_libs.append, 0) + defineBuiltin(context, 'concatenate(xss)', scheme_libs.concatenate) defineBuiltin(context, 'reverse(xs)', scheme_libs.reverse) - defineBuiltin(context, 'list$45$tail(xs, n)', scheme_libs.list_tail) - defineBuiltin(context, 'list$45$ref(xs, n)', scheme_libs.list_ref) + defineBuiltin(context, 'take(xs, n)', scheme_libs.take) + defineBuiltin(context, 'take$45$right(xs, n)', scheme_libs.take$45$right) + defineBuiltin(context, 'drop(xs, n)', scheme_libs.drop) + defineBuiltin(context, 'drop$45$right(xs, n)', scheme_libs.drop$45$right) + + defineBuiltin(context, 'list$61$(eq$45$pred, ...xss)', scheme_libs.list$61$, 1) + + /* defineBuiltin(context, 'memq(item, xs)', scheme_libs.memq) defineBuiltin(context, 'memv(item, xs)', scheme_libs.memv) defineBuiltin(context, 'member(item, xs)', scheme_libs.member) defineBuiltin(context, 'assq(item, xs)', scheme_libs.assq) defineBuiltin(context, 'assv(item, xs)', scheme_libs.assv) defineBuiltin(context, 'assoc(item, xs)', scheme_libs.assoc) - defineBuiltin(context, 'list$45$copy(xs)', scheme_libs.list_copy) - defineBuiltin(context, 'map(f, ...xs)', scheme_libs.map, 1) - defineBuiltin(context, 'filter(pred, xs)', scheme_libs.filter) - defineBuiltin(context, 'fold(f, init, ...xs)', scheme_libs.fold, 2) - defineBuiltin(context, 'fold$45$right(f, init, ...xs)', scheme_libs.fold_right, 2) - defineBuiltin(context, 'reduce(f, rIdentity, xs)', scheme_libs.reduce) + */ // Scheme cxrs - // Probably can do this better. defineBuiltin(context, 'caar(xs)', scheme_libs.caar) defineBuiltin(context, 'cadr(xs)', scheme_libs.cadr) defineBuiltin(context, 'cdar(xs)', scheme_libs.cdar) @@ -489,19 +554,21 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'cddddr(xs)', scheme_libs.cddddr) // Scheme symbols - defineBuiltin(context, 'symbol$63$(val)', scheme_libs.symbolQ) - defineBuiltin(context, 'symbol$61$63$(sym1, sym2)', scheme_libs.symbolEQ) - defineBuiltin(context, 'symbol$45$$62$string(str)', scheme_libs.symbol_Gstring) - defineBuiltin(context, 'string$45$$62$symbol(sym)', scheme_libs.string_Gsymbol) + defineBuiltin(context, 'symbol$63$(val)', scheme_libs.symbol$63$) + defineBuiltin(context, 'symbol$61$$63$(sym1, sym2)', scheme_libs.symbol$61$$63$) + //defineBuiltin(context, 'symbol$45$$62$string(str)', scheme_libs.symbol_Gstring) + defineBuiltin(context, 'string$45$$62$symbol(sym)', scheme_libs.string$45$$62$symbol) + + /* // Scheme strings defineBuiltin(context, 'string$45$$62$list(str)', scheme_libs.string_Glist) defineBuiltin(context, 'list$45$$62$string(xs)', scheme_libs.list_Gstring) - + */ case Chapter.SCHEME_1: // Display defineBuiltin(context, 'display(val)', display) - defineBuiltin(context, 'newline()', scheme_libs.newline) + defineBuiltin(context, 'newline()', () => display('')) // I/O defineBuiltin(context, 'read(str)', () => prompt('')) @@ -510,42 +577,52 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'error(str, prepend = undefined)', misc.error_message, 1) // Scheme truthy and falsy value evaluator - defineBuiltin(context, '$36$true(val)', scheme_libs.$true) + defineBuiltin(context, 'truthy(val)', scheme_libs.truthy) + + // Scheme conversion from vector to list, defined here as + // it is used to support variadic functions + defineBuiltin(context, 'vector$45$$62$list(v)', scheme_libs.vector$45$$62$list) + + // Scheme function to build numbers + defineBuiltin(context, 'make_number(n)', scheme_libs.make_number) // Scheme equality predicates - defineBuiltin(context, 'eq$63$(...vals)', scheme_libs.eqQ) - defineBuiltin(context, 'eqv$63$(...vals)', scheme_libs.eqvQ) - defineBuiltin(context, 'equal$63$(...vals)', scheme_libs.equalQ) + + defineBuiltin(context, 'eq$63$(...vals)', scheme_libs.eq$63$) + defineBuiltin(context, 'eqv$63$(...vals)', scheme_libs.eqv$63$) + defineBuiltin(context, 'equal$63$(...vals)', scheme_libs.equal$63$) // Scheme basic arithmetic - defineBuiltin(context, '$43$(...vals)', scheme_libs.plus, 0) - defineBuiltin(context, '$42$(...vals)', scheme_libs.multiply, 0) - defineBuiltin(context, '$45$(...vals)', scheme_libs.minus, 1) - defineBuiltin(context, '$47$(...vals)', scheme_libs.divide, 1) + defineBuiltin(context, '$43$(...vals)', scheme_libs.$43$, 0) + defineBuiltin(context, '$42$(...vals)', scheme_libs.$42$, 0) + defineBuiltin(context, '$45$(...vals)', scheme_libs.$45$, 1) + defineBuiltin(context, '$47$(...vals)', scheme_libs.$47$, 1) // Scheme comparison - defineBuiltin(context, '$61$(...vals)', scheme_libs.E, 1) - defineBuiltin(context, '$60$(...vals)', scheme_libs.L, 1) - defineBuiltin(context, '$62$(...vals)', scheme_libs.G, 1) - defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.LE, 1) - defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.GE, 1) + defineBuiltin(context, '$61$(...vals)', scheme_libs.$61$, 1) + defineBuiltin(context, '$60$(...vals)', scheme_libs.$60$, 1) + defineBuiltin(context, '$62$(...vals)', scheme_libs.$62$, 1) + defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.$60$$61$, 1) + defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.$62$$61$, 1) // Scheme math functions - defineBuiltin(context, 'number$63$(val)', scheme_libs.numberQ) - defineBuiltin(context, 'complex$63$(val)', scheme_libs.complexQ) - defineBuiltin(context, 'real$63$(val)', scheme_libs.realQ) - defineBuiltin(context, 'rational$63$(val)', scheme_libs.rationalQ) - defineBuiltin(context, 'integer$63$(val)', scheme_libs.integerQ) - defineBuiltin(context, 'exact$63$(val)', scheme_libs.exactQ) - defineBuiltin(context, 'exact$45$integer$63$(val)', scheme_libs.exact_integerQ) - defineBuiltin(context, 'zero$63$(val)', scheme_libs.zeroQ) - defineBuiltin(context, 'positive$63$(val)', scheme_libs.positiveQ) - defineBuiltin(context, 'negative$63$(val)', scheme_libs.negativeQ) - defineBuiltin(context, 'odd$63$(val)', scheme_libs.oddQ) - defineBuiltin(context, 'even$63$(val)', scheme_libs.evenQ) + defineBuiltin(context, 'number$63$(val)', scheme_libs.number$63$) + defineBuiltin(context, 'complex$63$(val)', scheme_libs.complex$63$) + defineBuiltin(context, 'real$63$(val)', scheme_libs.real$63$) + defineBuiltin(context, 'rational$63$(val)', scheme_libs.rational$63$) + defineBuiltin(context, 'integer$63$(val)', scheme_libs.integer$63$) + defineBuiltin(context, 'exact$63$(val)', scheme_libs.exact$63$) + defineBuiltin(context, 'inexact$63$(val)', scheme_libs.inexact$63$) + //defineBuiltin(context, 'exact$45$integer$63$(val)', scheme_libs.exact_integerQ) + defineBuiltin(context, 'zero$63$(val)', scheme_libs.zero$63$) + defineBuiltin(context, 'positive$63$(val)', scheme_libs.positive$63$) + defineBuiltin(context, 'negative$63$(val)', scheme_libs.negative$63$) + //defineBuiltin(context, 'odd$63$(val)', scheme_libs.oddQ) + //defineBuiltin(context, 'even$63$(val)', scheme_libs.evenQ) defineBuiltin(context, 'max(...vals)', scheme_libs.max, 0) defineBuiltin(context, 'min(...vals)', scheme_libs.min, 0) defineBuiltin(context, 'abs(val)', scheme_libs.abs) + /* defineBuiltin(context, 'quotient(n, d)', scheme_libs.quotient) defineBuiltin(context, 'modulo(n, d)', scheme_libs.modulo) defineBuiltin(context, 'remainder(n, d)', scheme_libs.remainder) @@ -559,15 +636,17 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'exact$45$integer$45$sqrt(val)', scheme_libs.exact_integer_sqrt) defineBuiltin(context, 'expt(base, exp)', scheme_libs.expt) defineBuiltin(context, 'number$45$$62$string(val)', scheme_libs.number_Gstring) + */ // Scheme booleans - defineBuiltin(context, 'boolean$63$(val)', scheme_libs.booleanQ) - defineBuiltin(context, 'boolean$61$$63$(x, y)', scheme_libs.booleanEQ) + defineBuiltin(context, 'boolean$63$(val)', scheme_libs.boolean$63$) + defineBuiltin(context, 'boolean$61$$63$(x, y)', scheme_libs.boolean$61$$63$) defineBuiltin(context, 'and(...vals)', scheme_libs.and, 0) defineBuiltin(context, 'or(...vals)', scheme_libs.or, 0) defineBuiltin(context, 'not(val)', scheme_libs.not) // Scheme strings + /* defineBuiltin(context, 'string$63$(val)', scheme_libs.stringQ) defineBuiltin(context, 'make$45$string(n, char)', scheme_libs.make_string, 1) defineBuiltin(context, 'string(...vals)', scheme_libs.string, 0) @@ -584,9 +663,11 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'string$45$map(f, str)', scheme_libs.string_map) defineBuiltin(context, 'string$45$for$45$each(f, str)', scheme_libs.string_for_each) defineBuiltin(context, 'string$45$$62$number(str)', scheme_libs.string_Gnumber) + */ // Scheme procedures - defineBuiltin(context, 'procedure$63$(val)', scheme_libs.procedureQ) + defineBuiltin(context, 'procedure$63$(val)', scheme_libs.procedure$63$) + defineBuiltin(context, 'compose(...fns)', scheme_libs.compose, 0) // Special values defineBuiltin(context, 'undefined', undefined) diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index dd421cb11..ed309f80d 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,7 +1,19 @@ import { Node, Program } from 'estree' import { decode, encode, schemeParse } from '../../scm-slang/src' -import { Pair } from '../../scm-slang/src/stdlib/source-scheme-library' +import { + car, + cdr, + circular$45$list$63$, + cons, + last$45$pair, + list$45$tail, + pair$63$, + procedure$63$, + set$45$cdr$33$, + vector$63$ +} from '../../scm-slang/src/stdlib/base' +import { List, Pair } from '../../stdlib/list' import { Chapter, Context, ErrorType, SourceError } from '../../types' import { FatalSyntaxError } from '../errors' import { AcornOptions, Parser } from '../types' @@ -81,14 +93,49 @@ function decodeString(str: string): string { // Given any value, decode it if and // only if an encoded value may exist in it. export function decodeValue(x: any): any { + // helper version of list_tail that ensures non-null return value + function list_tail(xs: List, i: number): List { + if (i === 0) { + return xs + } else { + return list_tail(list$45$tail(xs), i - 1) + } + } // In future: add support for decoding vectors. - if (x instanceof Pair) { + if (circular$45$list$63$(x)) { + // May contain encoded strings, but we want to avoid a stack overflow. + let circular_pair_index = -1 + const all_pairs: Pair[] = [] + + // iterate through all pairs in the list until we find the circular pair + let current = x + while (current !== null) { + if (all_pairs.includes(current)) { + circular_pair_index = all_pairs.indexOf(current) + break + } + all_pairs.push(current) + current = cdr(current) + } + + // assemble a new list using the elements in all_pairs + let new_list = null + for (let i = all_pairs.length - 1; i >= 0; i--) { + new_list = cons(decodeValue(car(all_pairs[i])), new_list) + } + + // finally we can set the last cdr of the new list to the circular-pair itself + + const circular_pair = list_tail(new_list, circular_pair_index) + set$45$cdr$33$(last$45$pair(new_list), circular_pair) + return new_list + } else if (pair$63$(x)) { // May contain encoded strings. - return new Pair(decodeValue(x.car), decodeValue(x.cdr)) - } else if (x instanceof Array) { + return cons(decodeValue(car(x)), decodeValue(cdr(x))) + } else if (vector$63$(x)) { // May contain encoded strings. return x.map(decodeValue) - } else if (x instanceof Function) { + } else if (procedure$63$(x)) { const newString = decodeString(x.toString()) x.toString = () => newString return x From c5429c02aa949999e1d08ab0c461c4c1b149d233 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 7 Mar 2024 07:12:02 +0800 Subject: [PATCH 02/41] update JS version for js-slang --- tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 3e4181868..b29b2ae4d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "outDir": "./dist", "module": "commonjs", "declaration": true, - "target": "es2016", + "target": "es2020", "lib": [ "es2021.string", "es2018", From d341b96308b3b308477659a5c6ad3aee815b30f4 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 7 Mar 2024 07:17:53 +0800 Subject: [PATCH 03/41] proper formatting of files --- src/editors/ace/modes/source.ts | 2 +- src/name-extractor/__tests__/autocomplete.ts | 36 +++++++------------- src/transpiler/transpiler.ts | 2 +- src/types.ts | 2 +- 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/src/editors/ace/modes/source.ts b/src/editors/ace/modes/source.ts index c507e581e..92446a920 100644 --- a/src/editors/ace/modes/source.ts +++ b/src/editors/ace/modes/source.ts @@ -861,7 +861,7 @@ export function ModeSelector( // @ts-ignore this.$id = 'ace/mode/source' + name - }).call(Mode.prototype) + }.call(Mode.prototype)) exports.Mode = Mode } diff --git a/src/name-extractor/__tests__/autocomplete.ts b/src/name-extractor/__tests__/autocomplete.ts index 17170bf96..f0b8eaf00 100644 --- a/src/name-extractor/__tests__/autocomplete.ts +++ b/src/name-extractor/__tests__/autocomplete.ts @@ -14,8 +14,7 @@ test('Test empty program does not generate names', async () => { }) test('Test simple extraction of constant and variable names', async () => { - const code: string = - '\ + const code: string = '\ const foo1 = 1;\n\ let foo2 = 2;\n\ f\ @@ -177,8 +176,7 @@ test('Test accessing parameter names inside function', async () => { // For-loops test('Test accessing local block in for-loop parameter', async () => { - const code: string = - '\ + const code: string = '\ let bar = 1;\n\ let baz = 2;\n\ for (b) {\ @@ -194,8 +192,7 @@ test('Test accessing local block in for-loop parameter', async () => { }) test('Test accessing for-loop parameter in for-loop body', async () => { - const code: string = - '\ + const code: string = '\ for (let foo=10;) {\n\ f\n\ }\ @@ -208,8 +205,7 @@ test('Test accessing for-loop parameter in for-loop body', async () => { }) test('Test that for-loop local variable cannot be accessed outside loop', async () => { - const code: string = - '\ + const code: string = '\ for (let x=1; x<10; x=x+1) {\n\ let foo = x;\n\ }\n\ @@ -225,8 +221,7 @@ test('Test that for-loop local variable cannot be accessed outside loop', async // While-loops test('Test accessing local block in while-loop parameter', async () => { - const code: string = - '\ + const code: string = '\ let bar = 1;\n\ let baz = 2;\n\ while (b) {\ @@ -242,8 +237,7 @@ test('Test accessing local block in while-loop parameter', async () => { }) test('Test that while-loop local variable cannot be accessed outside loop', async () => { - const code: string = - '\ + const code: string = '\ while (let x=1; x<10; x=x+1) {\n\ let foo = x;\n\ }\n\ @@ -259,8 +253,7 @@ test('Test that while-loop local variable cannot be accessed outside loop', asyn // Conditionals test('Test accessing local block in if-else parameter', async () => { - const code: string = - '\ + const code: string = '\ let bar = 1;\n\ let baz = 2;\n\ if (b) {\ @@ -276,8 +269,7 @@ test('Test accessing local block in if-else parameter', async () => { }) test('Test that local variable in if-block cannot be accessed in else-block', async () => { - const code: string = - '\ + const code: string = '\ if (true) {\n\ let foo = x;\n\ } else {\n\ @@ -331,8 +323,7 @@ test('Test that variable in if cannot be accessed outside if-statement', async ( // Blocks test('Test that declaration in blocks cannot be accessed outside block', async () => { - const code: string = - '\ + const code: string = '\ {\n\ let foo = 1;\n\ }\n\ @@ -346,8 +337,7 @@ test('Test that declaration in blocks cannot be accessed outside block', async ( }) test('Test that declaration outside blocks can be accessed inside block', async () => { - const code: string = - '\ + const code: string = '\ let bar = 1;\n\ {\n\ let baz = 1;\n\ @@ -407,8 +397,7 @@ test('Test that declaration inside anonymous functions can be accessed in body', }) test('Test that declaration inside anonymous functions cannot be accessed outside', async () => { - const code: string = - '\ + const code: string = '\ let foo = (bar1, bar2) => { \n\ let baz = 1;\n\ }\n\ @@ -445,8 +434,7 @@ test('Test that local and global variables are available in return statements', // Declarations test('Test that no prompts are returned when user is declaring variable', async () => { - const code: string = - '\ + const code: string = '\ let bar = 1;\n\ let b\n\ ' diff --git a/src/transpiler/transpiler.ts b/src/transpiler/transpiler.ts index 9614c02f1..e14343c61 100644 --- a/src/transpiler/transpiler.ts +++ b/src/transpiler/transpiler.ts @@ -55,7 +55,7 @@ const globalIdNames = [ 'builtins' ] as const -export type NativeIds = Record<(typeof globalIdNames)[number], es.Identifier> +export type NativeIds = Record export async function transformImportDeclarations( program: es.Program, diff --git a/src/types.ts b/src/types.ts index 1509eafb3..77f232d8b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -351,7 +351,7 @@ export type TSAllowedTypes = 'any' | 'void' export const disallowedTypes = ['bigint', 'never', 'object', 'symbol', 'unknown'] as const -export type TSDisallowedTypes = (typeof disallowedTypes)[number] +export type TSDisallowedTypes = typeof disallowedTypes[number] // All types recognised by type parser as basic types export type TSBasicType = PrimitiveType | TSAllowedTypes | TSDisallowedTypes From 0e4367631a5aada702ece927929be920f52e1dc1 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 7 Mar 2024 16:41:06 +0800 Subject: [PATCH 04/41] fix separate program environments across REPL eval calls --- src/createContext.ts | 10 +++--- .../__snapshots__/cse-machine-callcc.ts.snap | 10 ++++-- src/cse-machine/interpreter.ts | 35 ++++++++++++++++++- 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index 30ed7ce96..3fc500cd2 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -599,11 +599,11 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, '$47$(...vals)', scheme_libs.$47$, 1) // Scheme comparison - defineBuiltin(context, '$61$(...vals)', scheme_libs.$61$, 1) - defineBuiltin(context, '$60$(...vals)', scheme_libs.$60$, 1) - defineBuiltin(context, '$62$(...vals)', scheme_libs.$62$, 1) - defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.$60$$61$, 1) - defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.$62$$61$, 1) + defineBuiltin(context, '$61$(...vals)', scheme_libs.$61$, 2) + defineBuiltin(context, '$60$(...vals)', scheme_libs.$60$, 2) + defineBuiltin(context, '$62$(...vals)', scheme_libs.$62$, 2) + defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.$60$$61$, 2) + defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.$62$$61$, 2) // Scheme math functions defineBuiltin(context, 'number$63$(val)', scheme_libs.number$63$) diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap index 73f8a048f..f10317a0a 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap @@ -11,7 +11,10 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 10, + "result": SchemeInteger { + "numberType": 1, + "value": 10n, + }, "resultStatus": "finished", "visualiseListResult": Array [], } @@ -54,7 +57,10 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 2, + "result": SchemeInteger { + "numberType": 1, + "value": 2n, + }, "resultStatus": "finished", "visualiseListResult": Array [], } diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index a32e88776..65cc4145c 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -367,6 +367,39 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { declareFunctionsAndVariables(context, command, environment) } + // A strange bug occurs here when successive REPL commands are run, as they + // are each evaluated as separate programs. This causes the environment to be + // pushed multiple times. + + // As such, we need to "append" the tail environment to the current environment + // if and only if the tail environment is a previous program environment. + + const currEnv = currentEnvironment(context) + if (currEnv && currEnv.tail && currEnv.tail.name === 'programEnvironment') { + console.log(currEnv.head) + // we need to take that tail environment and append its items to the current environment + const oldEnv = currEnv.tail + + console.log(oldEnv.head) + // separate the tail environment from the environments list + currEnv.tail = oldEnv.tail + + // we will recycle the old environment's item list + // add the items from the current environment to the tail environment + // this is fine, especially as the older program will never + // need to use the old environment's items again + for (const key in currEnv.head) { + oldEnv.head[key] = currEnv.head[key] + } + + // set the current environment to the old one + // this will work across successive programs as well + + // this will also allow continuations to read newer program + // values from their "outdated" program environment + currEnv.head = oldEnv.head + } + if (command.body.length == 1) { // If program only consists of one statement, evaluate it immediately const next = command.body[0] @@ -1119,7 +1152,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { // Push the expression given to the continuation onto the stash stash.push(expression) - // Restore the environment pointer to that of the continuation + // Restore the environment pointer to that of the continuation's environment context.runtime.environments = contEnv } } From 18cb104461f2872ab219f8068e28cdb342cc43cd Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 7 Mar 2024 20:15:10 +0800 Subject: [PATCH 05/41] remove logger messages from interpreter --- src/cse-machine/interpreter.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 65cc4145c..1795d6c67 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -375,12 +375,15 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { // if and only if the tail environment is a previous program environment. const currEnv = currentEnvironment(context) - if (currEnv && currEnv.tail && currEnv.tail.name === 'programEnvironment') { - console.log(currEnv.head) + if ( + currEnv && + currEnv.name === 'programEnvironment' && + currEnv.tail && + currEnv.tail.name === 'programEnvironment' + ) { // we need to take that tail environment and append its items to the current environment const oldEnv = currEnv.tail - console.log(oldEnv.head) // separate the tail environment from the environments list currEnv.tail = oldEnv.tail From 28b2e8f982abdfcd49f3bd033b0f45037f2470a7 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 11 Mar 2024 21:45:46 +0800 Subject: [PATCH 06/41] Enable variadic continuations for future --- src/cse-machine/continuations.ts | 3 ++- src/cse-machine/instrCreator.ts | 3 ++- src/cse-machine/interpreter.ts | 25 +++++++++++++++---------- src/cse-machine/types.ts | 4 +++- src/cse-machine/utils.ts | 7 +++++++ 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/cse-machine/continuations.ts b/src/cse-machine/continuations.ts index 2f0729b8e..2a4b2e0cd 100644 --- a/src/cse-machine/continuations.ts +++ b/src/cse-machine/continuations.ts @@ -50,7 +50,8 @@ export function getContinuationEnv(cn: Continuation): Environment[] { export function makeContinuation(control: Control, stash: Stash, env: Environment[]): Function { // Cast a function into a continuation - const fn: any = (x: any) => x + // a continuation may take any amount of arguments + const fn: Function = (...x: any[]) => x const cn: Continuation = fn as Continuation // Set the control, stash and environment diff --git a/src/cse-machine/instrCreator.ts b/src/cse-machine/instrCreator.ts index c0974ff2d..d5b3208d8 100644 --- a/src/cse-machine/instrCreator.ts +++ b/src/cse-machine/instrCreator.ts @@ -148,7 +148,8 @@ export const genContInstr = (srcNode: es.Node): GenContInstr => ({ srcNode }) -export const resumeContInstr = (srcNode: es.Node): ResumeContInstr => ({ +export const resumeContInstr = (numOfArgs: number, srcNode: es.Node): ResumeContInstr => ({ + numOfArgs: numOfArgs, instrType: InstrType.RESUME_CONT, srcNode }) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 1795d6c67..22dbf247c 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -47,8 +47,10 @@ import { CseError, EnvInstr, ForInstr, + GenContInstr, Instr, InstrType, + ResumeContInstr, UnOpInstr, WhileInstr } from './types' @@ -922,17 +924,16 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { // Check for number of arguments mismatch error checkNumberOfArguments(context, func, args, command.srcNode) - // A continuation is always given a single argument - const expression: Value = args[0] - const dummyContCallExpression = makeDummyContCallExpression('f', 'cont') // Restore the state of the stash, // but replace the function application instruction with // a resume continuation instruction stash.push(func) - stash.push(expression) - control.push(instr.resumeContInstr(dummyContCallExpression)) + // we need to push the arguments back onto the stash + // as well + stash.push(...args) + control.push(instr.resumeContInstr(command.numOfArgs, dummyContCallExpression)) return } @@ -1115,7 +1116,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { [InstrType.BREAK_MARKER]: function () {}, [InstrType.GENERATE_CONT]: function ( - _command: Instr, + _command: GenContInstr, context: Context, control: Control, stash: Stash @@ -1136,12 +1137,16 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { }, [InstrType.RESUME_CONT]: function ( - _command: Instr, + command: ResumeContInstr, context: Context, control: Control, stash: Stash ) { - const expression = stash.pop() + // pop the arguments + const args: Value[] = [] + for (let i = 0; i < command.numOfArgs; i++) { + args.unshift(stash.pop()) + } const cn: Continuation = stash.pop() as Continuation const contControl = getContinuationControl(cn) @@ -1152,8 +1157,8 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { control.setTo(contControl) stash.setTo(contStash) - // Push the expression given to the continuation onto the stash - stash.push(expression) + // Push the arguments given to the continuation back onto the stash + stash.push(...args) // Restore the environment pointer to that of the continuation's environment context.runtime.environments = contEnv diff --git a/src/cse-machine/types.ts b/src/cse-machine/types.ts index e6efe9290..620dd1ebd 100644 --- a/src/cse-machine/types.ts +++ b/src/cse-machine/types.ts @@ -77,7 +77,9 @@ export interface ArrLitInstr extends BaseInstr { export type GenContInstr = BaseInstr -export type ResumeContInstr = BaseInstr +export interface ResumeContInstr extends BaseInstr { + numOfArgs: number +} export type Instr = | BaseInstr diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 8dbaf7f90..89cffc06f 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -7,6 +7,7 @@ import { RuntimeSourceError } from '../errors/runtimeSourceError' import Closure from '../interpreter/closure' import { Environment, Frame, RawBlockStatement, Value } from '../types' import * as ast from '../utils/astCreator' +import { isContinuation } from './continuations' import * as instr from './instrCreator' import { Control } from './interpreter' import { AppInstr, AssmtInstr, ControlItem, Instr, InstrType } from './types' @@ -490,6 +491,12 @@ export const checkNumberOfArguments = ( ) ) } + } else if (isContinuation(callee)) { + // Continuations have variadic arguments, + // and so we can let it pass + // in future, if we can somehow check the number of arguments + // expected by the continuation, we can add a check here. + return undefined } else { // Pre-built functions const hasVarArgs = callee.minArgsNeeded != undefined From af278467f16e636f7a4daef4c738f48c4f7800b3 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 12 Mar 2024 05:17:49 +0800 Subject: [PATCH 07/41] Remove Infinity and NaN representation from Scheme --- src/createContext.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index 3fc500cd2..cb4dbcc7f 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -671,9 +671,6 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn // Special values defineBuiltin(context, 'undefined', undefined) - defineBuiltin(context, 'NaN', NaN) - defineBuiltin(context, 'Infinity', Infinity) - break default: //should be unreachable From fd62e0628d39cc428a2402d3b8b42676eb99ad75 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 12 Mar 2024 05:19:45 +0800 Subject: [PATCH 08/41] Change scm-slang to follow forked version --- src/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scm-slang b/src/scm-slang index 35fe554e4..19dbf8d5a 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 35fe554e473f48f1079586ea60334d83f0adaee4 +Subproject commit 19dbf8d5a6465c79e47dd0a968ff999e65a85375 From cfa44bd8ad8c70b83be7c730299893289d305349 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 18 Mar 2024 16:19:35 +0800 Subject: [PATCH 09/41] update scm-slang to newest parser --- src/__tests__/__snapshots__/scmlib.ts.snap | 1535 ----------------- src/__tests__/scmlib.ts | 1186 ------------- src/createContext.ts | 3 +- .../__snapshots__/cse-machine-callcc.ts.snap | 34 - .../__tests__/cse-machine-callcc.ts | 20 +- src/scm-slang | 2 +- 6 files changed, 20 insertions(+), 2760 deletions(-) delete mode 100644 src/__tests__/__snapshots__/scmlib.ts.snap delete mode 100644 src/__tests__/scmlib.ts diff --git a/src/__tests__/__snapshots__/scmlib.ts.snap b/src/__tests__/__snapshots__/scmlib.ts.snap deleted file mode 100644 index 6b4087707..000000000 --- a/src/__tests__/__snapshots__/scmlib.ts.snap +++ /dev/null @@ -1,1535 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Builtins work as expected 0: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? \\"a\\" \\"a\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 1: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? \\"a\\" \\"b\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 2: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 3: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eqv? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 4: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(equal? 1 \\"1\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 5: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(equal? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 6: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(+)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 7: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(+ 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 6, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 8: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(- 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 9: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(- 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 10: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(*)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 11: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(* 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 6, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 12: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(/ 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0.5, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 13: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(= 1 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 14: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 15: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(< 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 16: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(< 1 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 17: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(> 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 18: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(> 3 2 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 19: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(<= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 20: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(<= 1 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 21: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 22: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 3 2 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 23: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 3 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 24: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 25: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number? \\"1\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 26: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(real? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 27: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(integer? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 28: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(integer? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 29: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 30: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 31: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 32: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(zero? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 33: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(zero? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 34: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(positive? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 35: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(positive? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 36: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(negative? -1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 37: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(negative? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 38: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(odd? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 39: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(odd? 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 40: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(even? 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 41: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(even? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 42: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(max 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 43: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(max)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -Infinity, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 44: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(min)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": Infinity, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 45: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(min 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 46: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(abs -1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 47: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(abs 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 48: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 49: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 2.5)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 50: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 -2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 51: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(modulo 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 52: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(modulo 5 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 53: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(remainder 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 54: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(remainder 5 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 55: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(gcd 32 4110 22)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 56: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(lcm 32 4110 22)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 723360, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 57: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(floor 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 58: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(ceiling 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 59: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(truncate 1.6)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 60: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(truncate 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 61: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(round 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 62: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(round 1.6)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 63: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(square 4)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 16, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 64: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer-sqrt 16)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 4, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 65: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(expt 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 8, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 66: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number->string 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "1", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 67: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(boolean? (= 0 0))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 68: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(boolean? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 69: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(and #t #t #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 70: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(and #t #f #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 71: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(or #f #f #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 72: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(or #f #f #f)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 73: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(not #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 74: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(not #f)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 75: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 76: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 77: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(make-string 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": " ", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 78: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(make-string 3 \\"a\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "aaa", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 79: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string \\"hi\\" \\" \\" \\"mum\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "hi mum", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 80: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-length \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 81: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-ref \\"abc\\" 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "b", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 82: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 83: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 84: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 87: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 88: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 89: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 90: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 91: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 92: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 93: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 94: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(substring \\"abc\\" 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "bc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 95: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(substring \\"abc\\" 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "b", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 96: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-append \\"a\\" \\"b\\" \\"c\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 97: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string->number \\"123\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 123, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 98: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(procedure? (lambda (a) a))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 99: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(procedure? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 100: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(pair? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 101: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(pair? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 102: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(car (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 103: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(cdr (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 104: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list? (list 1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 105: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 106: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(null? (list))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 107: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(null? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 108: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(length (list 1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 109: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(length (list))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 110: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list-ref (list 1 2 3) 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 111: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list->string '(\\"a\\" \\"b\\" \\"c\\"))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 112: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list->string (string->list \\"abc\\"))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 113: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(promise? (delay 1))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 114: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(promise? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 115: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(force (delay 1))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 116: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(apply + 1 2 3 4 '(5 6 7 8))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 36, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 117: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(apply + '(5 6 7 8))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 26, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; diff --git a/src/__tests__/scmlib.ts b/src/__tests__/scmlib.ts deleted file mode 100644 index e7f87b6f6..000000000 --- a/src/__tests__/scmlib.ts +++ /dev/null @@ -1,1186 +0,0 @@ -import { Chapter, Value } from '../types' -import { stripIndent } from '../utils/formatters' -import { expectResult, snapshotFailure } from '../utils/testing' - -test.each([ - // Scheme 1 - - // Equality predicates - [ - Chapter.SCHEME_1, - ` - (eq? "a" "a") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (eq? "a" "b") - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (eq? '(1 2 3) '(1 2 3)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (eqv? '(1 2 3) '(1 2 3)) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (equal? 1 "1") - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (equal? '(1 2 3) '(1 2 3)) - `, - true, - true - ], - - // Basic arithmetic - [ - Chapter.SCHEME_1, - ` - (+) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (+ 1 2 3) - `, - true, - 6 - ], - - [ - Chapter.SCHEME_1, - ` - (- 1) - `, - true, - -1 - ], - - [ - Chapter.SCHEME_1, - ` - (- 1 2) - `, - true, - -1 - ], - - [ - Chapter.SCHEME_1, - ` - (*) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (* 1 2 3) - `, - true, - 6 - ], - - [ - Chapter.SCHEME_1, - ` - (/ 1 2) - `, - true, - 0.5 - ], - - // Arithmetic comparisons - - [ - Chapter.SCHEME_1, - ` - (= 1 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (= 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (< 1 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (< 1 2 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (> 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (> 3 2 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (<= 1 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (<= 1 2 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (>= 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (>= 3 2 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (>= 3 2 2) - `, - true, - true - ], - - // Math functions - - [ - Chapter.SCHEME_1, - ` - (number? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (number? "1") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (real? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (integer? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (integer? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (exact? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (zero? 0) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (zero? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (positive? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (positive? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (negative? -1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (negative? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (odd? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (odd? 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (even? 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (even? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (max 1 2 3) - `, - true, - 3 - ], - - [ - Chapter.SCHEME_1, - ` - (max) - `, - true, - -Infinity - ], - - [ - Chapter.SCHEME_1, - ` - (min) - `, - true, - Infinity - ], - - [ - Chapter.SCHEME_1, - ` - (min 1 2 3) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (abs -1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (abs 1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 2) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 2.5) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 -2) - `, - true, - -2 - ], - - [ - Chapter.SCHEME_1, - ` - (modulo 5 2) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (modulo 5 1) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (remainder 5 2) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (remainder 5 1) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (gcd 32 4110 22) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (lcm 32 4110 22) - `, - true, - 723360 - ], - - [ - Chapter.SCHEME_1, - ` - (floor 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (ceiling 1.1) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (truncate 1.6) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (truncate 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (round 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (round 1.6) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (square 4) - `, - true, - 16 - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer-sqrt 16) - `, - true, - 4 - ], - - [ - Chapter.SCHEME_1, - ` - (expt 2 3) - `, - true, - 8 - ], - - [ - Chapter.SCHEME_1, - ` - (number->string 1) - `, - true, - '1' - ], - - // Booleans - - [ - Chapter.SCHEME_1, - ` - (boolean? (= 0 0)) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (boolean? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (and #t #t #t) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (and #t #f #t) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (or #f #f #t) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (or #f #f #f) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (not #t) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (not #f) - `, - true, - true - ], - - // Strings - - [ - Chapter.SCHEME_1, - ` - (string? "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (make-string 3) - `, - true, - ' ' - ], - - [ - Chapter.SCHEME_1, - ` - (make-string 3 "a") - `, - true, - 'aaa' - ], - - [ - Chapter.SCHEME_1, - ` - (string "hi" " " "mum") - `, - true, - 'hi mum' - ], - - [ - Chapter.SCHEME_1, - ` - (string-length "abc") - `, - true, - 3 - ], - - [ - Chapter.SCHEME_1, - ` - (string-ref "abc" 1) - `, - true, - 'b' - ], - - [ - Chapter.SCHEME_1, - ` - (string=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string=? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string>? "def" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "abc" "def") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "def" "abc") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "def" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (substring "abc" 1) - `, - true, - 'bc' - ], - - [ - Chapter.SCHEME_1, - ` - (substring "abc" 1 2) - `, - true, - 'b' - ], - - [ - Chapter.SCHEME_1, - ` - (string-append "a" "b" "c") - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_1, - ` - (string->number "123") - `, - true, - 123 - ], - - // Procedures - - [ - Chapter.SCHEME_1, - ` - (procedure? (lambda (a) a)) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (procedure? 1) - `, - true, - false - ], - - // Scheme 2 - - // Pairs - - [ - Chapter.SCHEME_2, - ` - (pair? (cons 1 2)) - `, - true, - true - ], - - // FAILS 7 BELOW - - [ - Chapter.SCHEME_2, - ` - (pair? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (car (cons 1 2)) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_2, - ` - (cdr (cons 1 2)) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_2, - ` - (list? (list 1 2 3)) - `, - true, - true - ], - - [ - Chapter.SCHEME_2, - ` - (list? (cons 1 2)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (null? (list)) - `, - true, - true - ], - - [ - Chapter.SCHEME_2, - ` - (null? (cons 1 2)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (length (list 1 2 3)) - `, - true, - 3 - ], - - [ - Chapter.SCHEME_2, - ` - (length (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (list-ref (list 1 2 3) 1) - `, - true, - 2 - ], - - /* FAILS. Issue with the interepreter detecting wrong arity of lambda functions: 0 - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (+ a b)) 0 (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (+ a b)) 0 (list 1)) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_2, - ` - (fold-right (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'cba' - ], - - [ - Chapter.SCHEME_2, - ` - (fold-right (lambda (a b) (+ a b)) 0 (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (reduce (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'abc' - ], - - */ - - // Lists - - // Symbols - - // Strings - - [ - Chapter.SCHEME_2, - ` - (list->string '("a" "b" "c")) - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_2, - ` - (list->string (string->list "abc")) - `, - true, - 'abc' - ], - - // Scheme 3 - - // Pair mutation - - // List mutation - - // Promises - - [ - Chapter.SCHEME_3, - ` - (promise? (delay 1)) - `, - true, - true - ], - - [ - Chapter.SCHEME_3, - ` - (promise? 1) - `, - true, - false - ], - - /* FAILS. Some issues involving the interpreter detecting wrong arity of lambda functions: 0 - - [ - Chapter.SCHEME_3, - ` - (promise? (lambda (a) a)) - `, - true, - false - ], - - */ - - [ - Chapter.SCHEME_3, - ` - (force (delay 1)) - `, - true, - 1 - ], - - // Scheme 4 - - [ - Chapter.SCHEME_4, - ` - (apply + 1 2 3 4 '(5 6 7 8)) - `, - true, - 36 - ], - - [ - Chapter.SCHEME_4, - ` - (apply + '(5 6 7 8)) - `, - true, - 26 - ] -] as [Chapter, string, boolean, Value][])( - 'Builtins work as expected %#', - (chapter: Chapter, snippet: string, passing: boolean, returnValue: Value) => { - if (passing) { - return expectResult(stripIndent(snippet), { - chapter, - native: true - }).toEqual(returnValue) - } else { - return snapshotFailure(stripIndent(snippet), { chapter }, 'fails') - } - } -) diff --git a/src/createContext.ts b/src/createContext.ts index cb4dbcc7f..933e738dd 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -423,7 +423,8 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn //defineBuiltin(context, 'filter$33$(pred, xs)', scheme_libs.filterB); // Scheme promises - defineBuiltin(context, 'promise$63$()', scheme_libs.promise$63$) + defineBuiltin(context, 'make$45$promise(thunk)', scheme_libs.make$45$promise) + defineBuiltin(context, 'promise$63$(p)', scheme_libs.promise$63$) defineBuiltin(context, 'force(p)', scheme_libs.force) // Scheme vectors diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap index f10317a0a..df1220603 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap @@ -98,37 +98,3 @@ Object { "visualiseListResult": Array [], } `; - -exports[`cont throws error given >1 argument: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": " - (+ 1 2 (call/cc - (lambda (k) (k 3 'wrongwrongwrong!))) - 4) - ", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 3: Expected 1 arguments, but got 2.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`cont throws error given no arguments: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": " - (+ 1 2 (call/cc - (lambda (k) (k))) - 4) - ", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 3: Expected 1 arguments, but got 0.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; diff --git a/src/cse-machine/__tests__/cse-machine-callcc.ts b/src/cse-machine/__tests__/cse-machine-callcc.ts index 24f55ad6e..a4fc3450d 100644 --- a/src/cse-machine/__tests__/cse-machine-callcc.ts +++ b/src/cse-machine/__tests__/cse-machine-callcc.ts @@ -13,7 +13,12 @@ test('basic call/cc works', () => { 4) `, optionECScm - ).toMatchInlineSnapshot(`10`) + ).toMatchInlineSnapshot(` +SchemeInteger { + "numberType": 1, + "value": 10n, +} +`) }) test('call/cc can be used to escape a computation', () => { @@ -28,7 +33,12 @@ test('call/cc can be used to escape a computation', () => { test `, optionECScm - ).toMatchInlineSnapshot(`2`) + ).toMatchInlineSnapshot(` +SchemeInteger { + "numberType": 1, + "value": 2n, +} +`) }) test('call/cc throws error given no arguments', () => { @@ -52,6 +62,10 @@ test('call/cc throws error given >1 argument', () => { ).toMatchInlineSnapshot(`"Line 2: Expected 1 arguments, but got 2."`) }) +/* +for now, continuations have variable arity but are unable to check for the "correct" +number of arguments. we will omit these tests for now + test('cont throws error given no arguments', () => { return expectParsedError( ` @@ -73,7 +87,7 @@ test('cont throws error given >1 argument', () => { optionECScm ).toMatchInlineSnapshot(`"Line 3: Expected 1 arguments, but got 2."`) }) - +*/ test('call/cc can be stored as a value', () => { return expectResult( ` diff --git a/src/scm-slang b/src/scm-slang index 19dbf8d5a..779d0354a 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 19dbf8d5a6465c79e47dd0a968ff999e65a85375 +Subproject commit 779d0354aad5a560a83dd62b59d3128f25a83144 From 9347f347730dfa2e6b621314aedbcfa0b429b35a Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 19 Mar 2024 14:21:43 +0800 Subject: [PATCH 10/41] resolve linting problems --- src/editors/ace/modes/source.ts | 2 +- src/name-extractor/__tests__/autocomplete.ts | 36 +++++++++++++------- src/transpiler/transpiler.ts | 2 +- src/types.ts | 2 +- 4 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/editors/ace/modes/source.ts b/src/editors/ace/modes/source.ts index 92446a920..c507e581e 100644 --- a/src/editors/ace/modes/source.ts +++ b/src/editors/ace/modes/source.ts @@ -861,7 +861,7 @@ export function ModeSelector( // @ts-ignore this.$id = 'ace/mode/source' + name - }.call(Mode.prototype)) + }).call(Mode.prototype) exports.Mode = Mode } diff --git a/src/name-extractor/__tests__/autocomplete.ts b/src/name-extractor/__tests__/autocomplete.ts index f0b8eaf00..17170bf96 100644 --- a/src/name-extractor/__tests__/autocomplete.ts +++ b/src/name-extractor/__tests__/autocomplete.ts @@ -14,7 +14,8 @@ test('Test empty program does not generate names', async () => { }) test('Test simple extraction of constant and variable names', async () => { - const code: string = '\ + const code: string = + '\ const foo1 = 1;\n\ let foo2 = 2;\n\ f\ @@ -176,7 +177,8 @@ test('Test accessing parameter names inside function', async () => { // For-loops test('Test accessing local block in for-loop parameter', async () => { - const code: string = '\ + const code: string = + '\ let bar = 1;\n\ let baz = 2;\n\ for (b) {\ @@ -192,7 +194,8 @@ test('Test accessing local block in for-loop parameter', async () => { }) test('Test accessing for-loop parameter in for-loop body', async () => { - const code: string = '\ + const code: string = + '\ for (let foo=10;) {\n\ f\n\ }\ @@ -205,7 +208,8 @@ test('Test accessing for-loop parameter in for-loop body', async () => { }) test('Test that for-loop local variable cannot be accessed outside loop', async () => { - const code: string = '\ + const code: string = + '\ for (let x=1; x<10; x=x+1) {\n\ let foo = x;\n\ }\n\ @@ -221,7 +225,8 @@ test('Test that for-loop local variable cannot be accessed outside loop', async // While-loops test('Test accessing local block in while-loop parameter', async () => { - const code: string = '\ + const code: string = + '\ let bar = 1;\n\ let baz = 2;\n\ while (b) {\ @@ -237,7 +242,8 @@ test('Test accessing local block in while-loop parameter', async () => { }) test('Test that while-loop local variable cannot be accessed outside loop', async () => { - const code: string = '\ + const code: string = + '\ while (let x=1; x<10; x=x+1) {\n\ let foo = x;\n\ }\n\ @@ -253,7 +259,8 @@ test('Test that while-loop local variable cannot be accessed outside loop', asyn // Conditionals test('Test accessing local block in if-else parameter', async () => { - const code: string = '\ + const code: string = + '\ let bar = 1;\n\ let baz = 2;\n\ if (b) {\ @@ -269,7 +276,8 @@ test('Test accessing local block in if-else parameter', async () => { }) test('Test that local variable in if-block cannot be accessed in else-block', async () => { - const code: string = '\ + const code: string = + '\ if (true) {\n\ let foo = x;\n\ } else {\n\ @@ -323,7 +331,8 @@ test('Test that variable in if cannot be accessed outside if-statement', async ( // Blocks test('Test that declaration in blocks cannot be accessed outside block', async () => { - const code: string = '\ + const code: string = + '\ {\n\ let foo = 1;\n\ }\n\ @@ -337,7 +346,8 @@ test('Test that declaration in blocks cannot be accessed outside block', async ( }) test('Test that declaration outside blocks can be accessed inside block', async () => { - const code: string = '\ + const code: string = + '\ let bar = 1;\n\ {\n\ let baz = 1;\n\ @@ -397,7 +407,8 @@ test('Test that declaration inside anonymous functions can be accessed in body', }) test('Test that declaration inside anonymous functions cannot be accessed outside', async () => { - const code: string = '\ + const code: string = + '\ let foo = (bar1, bar2) => { \n\ let baz = 1;\n\ }\n\ @@ -434,7 +445,8 @@ test('Test that local and global variables are available in return statements', // Declarations test('Test that no prompts are returned when user is declaring variable', async () => { - const code: string = '\ + const code: string = + '\ let bar = 1;\n\ let b\n\ ' diff --git a/src/transpiler/transpiler.ts b/src/transpiler/transpiler.ts index e14343c61..9614c02f1 100644 --- a/src/transpiler/transpiler.ts +++ b/src/transpiler/transpiler.ts @@ -55,7 +55,7 @@ const globalIdNames = [ 'builtins' ] as const -export type NativeIds = Record +export type NativeIds = Record<(typeof globalIdNames)[number], es.Identifier> export async function transformImportDeclarations( program: es.Program, diff --git a/src/types.ts b/src/types.ts index fa933783f..0459d903a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -352,7 +352,7 @@ export type TSAllowedTypes = 'any' | 'void' export const disallowedTypes = ['bigint', 'never', 'object', 'symbol', 'unknown'] as const -export type TSDisallowedTypes = typeof disallowedTypes[number] +export type TSDisallowedTypes = (typeof disallowedTypes)[number] // All types recognised by type parser as basic types export type TSBasicType = PrimitiveType | TSAllowedTypes | TSDisallowedTypes From 3f1d4501cefa6c5cfd9e8ae74b871054788a77e3 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 19 Mar 2024 18:14:28 +0800 Subject: [PATCH 11/41] add test cases to verify proper chapter validation, decoded representation --- src/parser/__tests__/scheme-encode-decode.ts | 24 +++++++++++++- src/parser/__tests__/scheme.ts | 34 +++++++++----------- src/parser/scheme/index.ts | 17 ++++++---- 3 files changed, 50 insertions(+), 25 deletions(-) diff --git a/src/parser/__tests__/scheme-encode-decode.ts b/src/parser/__tests__/scheme-encode-decode.ts index a458f0bac..238620f22 100644 --- a/src/parser/__tests__/scheme-encode-decode.ts +++ b/src/parser/__tests__/scheme-encode-decode.ts @@ -2,11 +2,12 @@ import { Node } from 'estree' import { UnassignedVariable } from '../../errors/errors' import { decode, encode } from '../../scm-slang/src' +import { cons, set$45$cdr$33$ } from '../../scm-slang/src/stdlib/base' import { dummyExpression } from '../../utils/dummyAstCreator' import { decodeError, decodeValue } from '../scheme' describe('Scheme encoder and decoder', () => { - it('encodes and decodes strings correctly', () => { + it('encoder and decoder are proper inverses of one another', () => { const values = [ 'hello', 'hello world', @@ -36,6 +37,27 @@ describe('Scheme encoder and decoder', () => { expect(decodeValue($65$).toString()).toEqual(`function A() { }`) }) + it('decoder works on circular lists', () => { + function $65$() {} + const pair = cons($65$, 'placeholder') + set$45$cdr$33$(pair, pair) + expect(decodeValue(pair).toString()).toEqual(`function A() { },`) + }) + + it('decoder works on pairs', () => { + // and in doing so, works on pairs, lists, etc... + function $65$() {} + const pair = cons($65$, 'placeholder') + expect(decodeValue(pair).toString()).toEqual(`function A() { },placeholder`) + }) + + it('decoder works on vectors', () => { + // scheme doesn't support optimisation of circular vectors yet + function $65$() {} + const vector = [$65$, 2, 3] + expect(decodeValue(vector).toString()).toEqual(`function A() { },2,3`) + }) + it('decodes runtime errors properly', () => { const token = `😀` const dummyNode: Node = dummyExpression() diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts index 794041a1e..f723fedbb 100644 --- a/src/parser/__tests__/scheme.ts +++ b/src/parser/__tests__/scheme.ts @@ -3,7 +3,10 @@ import { mockContext } from '../../mocks/context' import { Chapter } from '../../types' import { SchemeParser } from '../scheme' -const parser = new SchemeParser(Chapter.SCHEME_1) +const parser_1 = new SchemeParser(Chapter.SCHEME_1) +const parser_2 = new SchemeParser(Chapter.SCHEME_2) +const parser_3 = new SchemeParser(Chapter.SCHEME_3) +const parser_4 = new SchemeParser(Chapter.SCHEME_4) const parser_full = new SchemeParser(Chapter.FULL_SCHEME) let context = mockContext(Chapter.SCHEME_1) let context_full = mockContext(Chapter.FULL_SCHEME) @@ -15,7 +18,7 @@ beforeEach(() => { describe('Scheme parser', () => { it('represents itself correctly', () => { - expect(parser.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) + expect(parser_1.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) }) it('throws error if given chapter is wrong', () => { @@ -26,13 +29,13 @@ describe('Scheme parser', () => { it('throws errors if option throwOnError is selected + parse error is encountered', () => { const code = `(hello))` - expect(() => parser.parse(code, context, undefined, true)).toThrow("Unexpected ')'") + expect(() => parser_1.parse(code, context, undefined, true)).toThrow("Unexpected ')'") }) it('formats tokenizer errors correctly', () => { const code = `(hello))` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) ) @@ -41,35 +44,25 @@ describe('Scheme parser', () => { it('formats parser errors correctly', () => { const code = `(define (f x)` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) ) }) - it('allows usage of builtins/preludes', () => { - const code = ` - (+ 1 2 3) - (gcd 10 15) - ` - - parser.parse(code, context) - expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) - }) - it('allows usage of imports/modules', () => { const code = `(import "rune" (show heart)) (show heart) ` - parser.parse(code, context) + parser_1.parse(code, context) expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) }) it('disallows syntax for higher chapters', () => { const code = `'(1 2 3)` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining("Syntax ''' not allowed at Scheme §1") @@ -77,9 +70,14 @@ describe('Scheme parser', () => { ) }) - it('allows syntax for lower chapters', () => { + it('allows syntax for chapters of required or higher chapter', () => { const code = `'(1 2 3)` + // regardless of how many times we parse this code in the same context, + // there should be no errors in the context as long as the chapter is 2 or higher + parser_2.parse(code, context_full) + parser_3.parse(code, context_full) + parser_4.parse(code, context_full) parser_full.parse(code, context_full) expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) }) diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index ed309f80d..1aa4845e8 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -92,8 +92,10 @@ function decodeString(str: string): string { // Given any value, decode it if and // only if an encoded value may exist in it. +// this function is used to accurately display +// values in the REPL. export function decodeValue(x: any): any { - // helper version of list_tail that ensures non-null return value + // helper version of list_tail that assumes non-null return value function list_tail(xs: List, i: number): List { if (i === 0) { return xs @@ -101,9 +103,9 @@ export function decodeValue(x: any): any { return list_tail(list$45$tail(xs), i - 1) } } - // In future: add support for decoding vectors. + if (circular$45$list$63$(x)) { - // May contain encoded strings, but we want to avoid a stack overflow. + // May contain encoded strings. let circular_pair_index = -1 const all_pairs: Pair[] = [] @@ -117,7 +119,7 @@ export function decodeValue(x: any): any { all_pairs.push(current) current = cdr(current) } - + x // assemble a new list using the elements in all_pairs let new_list = null for (let i = all_pairs.length - 1; i >= 0; i--) { @@ -136,9 +138,12 @@ export function decodeValue(x: any): any { // May contain encoded strings. return x.map(decodeValue) } else if (procedure$63$(x)) { + // copy x to avoid modifying the original object + const newX = { ...x } const newString = decodeString(x.toString()) - x.toString = () => newString - return x + // change the toString method to return the decoded string + newX.toString = () => newString + return newX } else { // string, number, boolean, null, undefined // no need to decode. From 0d45e9df612d9dedb8f3cf8e0f4056248f16df11 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Wed, 20 Mar 2024 19:55:03 +0800 Subject: [PATCH 12/41] update scm-slang --- src/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scm-slang b/src/scm-slang index 779d0354a..241d77bd0 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 779d0354aad5a560a83dd62b59d3128f25a83144 +Subproject commit 241d77bd09eb45584460cd92d44bd7361e24283e From 42e184e540fa5fbdf6f8fa4fc3ea970fc45b1a2c Mon Sep 17 00:00:00 2001 From: s-kybound Date: Wed, 20 Mar 2024 20:12:20 +0800 Subject: [PATCH 13/41] Move scheme-specific tests to scm-slang --- src/parser/__tests__/scheme-encode-decode.ts | 67 ---------------- src/parser/__tests__/scheme.ts | 84 -------------------- src/scm-slang | 2 +- 3 files changed, 1 insertion(+), 152 deletions(-) delete mode 100644 src/parser/__tests__/scheme-encode-decode.ts delete mode 100644 src/parser/__tests__/scheme.ts diff --git a/src/parser/__tests__/scheme-encode-decode.ts b/src/parser/__tests__/scheme-encode-decode.ts deleted file mode 100644 index 238620f22..000000000 --- a/src/parser/__tests__/scheme-encode-decode.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { Node } from 'estree' - -import { UnassignedVariable } from '../../errors/errors' -import { decode, encode } from '../../scm-slang/src' -import { cons, set$45$cdr$33$ } from '../../scm-slang/src/stdlib/base' -import { dummyExpression } from '../../utils/dummyAstCreator' -import { decodeError, decodeValue } from '../scheme' - -describe('Scheme encoder and decoder', () => { - it('encoder and decoder are proper inverses of one another', () => { - const values = [ - 'hello', - 'hello world', - 'scheme->JavaScript', - 'hello world!!', - 'true', - 'false', - 'null', - '1', - '😀' - ] - for (const value of values) { - expect(decode(encode(value))).toEqual(value) - } - }) - - it('decoder ignores primitives', () => { - const values = [1, 2, 3, true, false, null] - for (const value of values) { - expect(decodeValue(value)).toEqual(value) - } - }) - - it('decoder works on function toString representation', () => { - // Dummy function to test - function $65$() {} - expect(decodeValue($65$).toString()).toEqual(`function A() { }`) - }) - - it('decoder works on circular lists', () => { - function $65$() {} - const pair = cons($65$, 'placeholder') - set$45$cdr$33$(pair, pair) - expect(decodeValue(pair).toString()).toEqual(`function A() { },`) - }) - - it('decoder works on pairs', () => { - // and in doing so, works on pairs, lists, etc... - function $65$() {} - const pair = cons($65$, 'placeholder') - expect(decodeValue(pair).toString()).toEqual(`function A() { },placeholder`) - }) - - it('decoder works on vectors', () => { - // scheme doesn't support optimisation of circular vectors yet - function $65$() {} - const vector = [$65$, 2, 3] - expect(decodeValue(vector).toString()).toEqual(`function A() { },2,3`) - }) - - it('decodes runtime errors properly', () => { - const token = `😀` - const dummyNode: Node = dummyExpression() - const error = new UnassignedVariable(encode(token), dummyNode) - expect(decodeError(error).elaborate()).toContain(`😀`) - }) -}) diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts deleted file mode 100644 index f723fedbb..000000000 --- a/src/parser/__tests__/scheme.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { parseError } from '../..' -import { mockContext } from '../../mocks/context' -import { Chapter } from '../../types' -import { SchemeParser } from '../scheme' - -const parser_1 = new SchemeParser(Chapter.SCHEME_1) -const parser_2 = new SchemeParser(Chapter.SCHEME_2) -const parser_3 = new SchemeParser(Chapter.SCHEME_3) -const parser_4 = new SchemeParser(Chapter.SCHEME_4) -const parser_full = new SchemeParser(Chapter.FULL_SCHEME) -let context = mockContext(Chapter.SCHEME_1) -let context_full = mockContext(Chapter.FULL_SCHEME) - -beforeEach(() => { - context = mockContext(Chapter.SCHEME_1) - context_full = mockContext(Chapter.FULL_SCHEME) -}) - -describe('Scheme parser', () => { - it('represents itself correctly', () => { - expect(parser_1.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) - }) - - it('throws error if given chapter is wrong', () => { - expect(() => new SchemeParser(Chapter.FULL_PYTHON)).toThrow( - 'SchemeParser was not given a valid chapter!' - ) - }) - - it('throws errors if option throwOnError is selected + parse error is encountered', () => { - const code = `(hello))` - expect(() => parser_1.parse(code, context, undefined, true)).toThrow("Unexpected ')'") - }) - - it('formats tokenizer errors correctly', () => { - const code = `(hello))` - - parser_1.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) - ) - }) - - it('formats parser errors correctly', () => { - const code = `(define (f x)` - - parser_1.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) - ) - }) - - it('allows usage of imports/modules', () => { - const code = `(import "rune" (show heart)) - (show heart) - ` - - parser_1.parse(code, context) - expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) - }) - - it('disallows syntax for higher chapters', () => { - const code = `'(1 2 3)` - - parser_1.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ - message: expect.stringContaining("Syntax ''' not allowed at Scheme §1") - }) - ) - }) - - it('allows syntax for chapters of required or higher chapter', () => { - const code = `'(1 2 3)` - - // regardless of how many times we parse this code in the same context, - // there should be no errors in the context as long as the chapter is 2 or higher - parser_2.parse(code, context_full) - parser_3.parse(code, context_full) - parser_4.parse(code, context_full) - parser_full.parse(code, context_full) - expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) - }) -}) diff --git a/src/scm-slang b/src/scm-slang index 241d77bd0..596bd7e6d 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 241d77bd09eb45584460cd92d44bd7361e24283e +Subproject commit 596bd7e6d1edc6b856402843a2c0638756bdd794 From 9a912cf55c96404c9a7a7c8e7320cd078d56bc86 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Wed, 20 Mar 2024 20:20:44 +0800 Subject: [PATCH 14/41] make scheme test names more obvious --- src/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scm-slang b/src/scm-slang index 596bd7e6d..95b046b7d 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 596bd7e6d1edc6b856402843a2c0638756bdd794 +Subproject commit 95b046b7d62de6cd4ee4cda57323ae2588877e49 From 467279d0abe2db04499d8791d85a88261138d5ad Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 21 Mar 2024 14:29:57 +0800 Subject: [PATCH 15/41] Revert "Move scheme-specific tests to scm-slang" This reverts commit 42e184e540fa5fbdf6f8fa4fc3ea970fc45b1a2c. --- src/parser/__tests__/scheme-encode-decode.ts | 67 ++++++++++++++++ src/parser/__tests__/scheme.ts | 84 ++++++++++++++++++++ src/scm-slang | 2 +- 3 files changed, 152 insertions(+), 1 deletion(-) create mode 100644 src/parser/__tests__/scheme-encode-decode.ts create mode 100644 src/parser/__tests__/scheme.ts diff --git a/src/parser/__tests__/scheme-encode-decode.ts b/src/parser/__tests__/scheme-encode-decode.ts new file mode 100644 index 000000000..238620f22 --- /dev/null +++ b/src/parser/__tests__/scheme-encode-decode.ts @@ -0,0 +1,67 @@ +import { Node } from 'estree' + +import { UnassignedVariable } from '../../errors/errors' +import { decode, encode } from '../../scm-slang/src' +import { cons, set$45$cdr$33$ } from '../../scm-slang/src/stdlib/base' +import { dummyExpression } from '../../utils/dummyAstCreator' +import { decodeError, decodeValue } from '../scheme' + +describe('Scheme encoder and decoder', () => { + it('encoder and decoder are proper inverses of one another', () => { + const values = [ + 'hello', + 'hello world', + 'scheme->JavaScript', + 'hello world!!', + 'true', + 'false', + 'null', + '1', + '😀' + ] + for (const value of values) { + expect(decode(encode(value))).toEqual(value) + } + }) + + it('decoder ignores primitives', () => { + const values = [1, 2, 3, true, false, null] + for (const value of values) { + expect(decodeValue(value)).toEqual(value) + } + }) + + it('decoder works on function toString representation', () => { + // Dummy function to test + function $65$() {} + expect(decodeValue($65$).toString()).toEqual(`function A() { }`) + }) + + it('decoder works on circular lists', () => { + function $65$() {} + const pair = cons($65$, 'placeholder') + set$45$cdr$33$(pair, pair) + expect(decodeValue(pair).toString()).toEqual(`function A() { },`) + }) + + it('decoder works on pairs', () => { + // and in doing so, works on pairs, lists, etc... + function $65$() {} + const pair = cons($65$, 'placeholder') + expect(decodeValue(pair).toString()).toEqual(`function A() { },placeholder`) + }) + + it('decoder works on vectors', () => { + // scheme doesn't support optimisation of circular vectors yet + function $65$() {} + const vector = [$65$, 2, 3] + expect(decodeValue(vector).toString()).toEqual(`function A() { },2,3`) + }) + + it('decodes runtime errors properly', () => { + const token = `😀` + const dummyNode: Node = dummyExpression() + const error = new UnassignedVariable(encode(token), dummyNode) + expect(decodeError(error).elaborate()).toContain(`😀`) + }) +}) diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts new file mode 100644 index 000000000..f723fedbb --- /dev/null +++ b/src/parser/__tests__/scheme.ts @@ -0,0 +1,84 @@ +import { parseError } from '../..' +import { mockContext } from '../../mocks/context' +import { Chapter } from '../../types' +import { SchemeParser } from '../scheme' + +const parser_1 = new SchemeParser(Chapter.SCHEME_1) +const parser_2 = new SchemeParser(Chapter.SCHEME_2) +const parser_3 = new SchemeParser(Chapter.SCHEME_3) +const parser_4 = new SchemeParser(Chapter.SCHEME_4) +const parser_full = new SchemeParser(Chapter.FULL_SCHEME) +let context = mockContext(Chapter.SCHEME_1) +let context_full = mockContext(Chapter.FULL_SCHEME) + +beforeEach(() => { + context = mockContext(Chapter.SCHEME_1) + context_full = mockContext(Chapter.FULL_SCHEME) +}) + +describe('Scheme parser', () => { + it('represents itself correctly', () => { + expect(parser_1.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) + }) + + it('throws error if given chapter is wrong', () => { + expect(() => new SchemeParser(Chapter.FULL_PYTHON)).toThrow( + 'SchemeParser was not given a valid chapter!' + ) + }) + + it('throws errors if option throwOnError is selected + parse error is encountered', () => { + const code = `(hello))` + expect(() => parser_1.parse(code, context, undefined, true)).toThrow("Unexpected ')'") + }) + + it('formats tokenizer errors correctly', () => { + const code = `(hello))` + + parser_1.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) + ) + }) + + it('formats parser errors correctly', () => { + const code = `(define (f x)` + + parser_1.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) + ) + }) + + it('allows usage of imports/modules', () => { + const code = `(import "rune" (show heart)) + (show heart) + ` + + parser_1.parse(code, context) + expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) + }) + + it('disallows syntax for higher chapters', () => { + const code = `'(1 2 3)` + + parser_1.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ + message: expect.stringContaining("Syntax ''' not allowed at Scheme §1") + }) + ) + }) + + it('allows syntax for chapters of required or higher chapter', () => { + const code = `'(1 2 3)` + + // regardless of how many times we parse this code in the same context, + // there should be no errors in the context as long as the chapter is 2 or higher + parser_2.parse(code, context_full) + parser_3.parse(code, context_full) + parser_4.parse(code, context_full) + parser_full.parse(code, context_full) + expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) + }) +}) diff --git a/src/scm-slang b/src/scm-slang index 95b046b7d..65ad23d20 160000 --- a/src/scm-slang +++ b/src/scm-slang @@ -1 +1 @@ -Subproject commit 95b046b7d62de6cd4ee4cda57323ae2588877e49 +Subproject commit 65ad23d20acfad5b45147ef0373fac14694cdb8a From 2959c97376536176490c21479ca56e23ebf1064f Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 21 Mar 2024 14:42:48 +0800 Subject: [PATCH 16/41] move scm-slang to dedicated alt-lang folder --- .eslintignore | 2 +- .gitmodules | 6 +++--- .prettierignore | 2 +- .../scheme}/__tests__/scheme-encode-decode.ts | 10 +++++----- src/{parser => alt-langs/scheme}/__tests__/scheme.ts | 8 ++++---- src/{ => alt-langs/scheme}/scm-slang | 0 src/createContext.ts | 2 +- src/parser/scheme/index.ts | 4 ++-- 8 files changed, 17 insertions(+), 17 deletions(-) rename src/{parser => alt-langs/scheme}/__tests__/scheme-encode-decode.ts (85%) rename src/{parser => alt-langs/scheme}/__tests__/scheme.ts (93%) rename src/{ => alt-langs/scheme}/scm-slang (100%) diff --git a/.eslintignore b/.eslintignore index a20bc161b..2e9a9a8e1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,3 @@ /dist/ -/src/scm-slang/ +/src/alt-langs/ /src/py-slang/ diff --git a/.gitmodules b/.gitmodules index 431b95c90..b39c03d73 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "src/scm-slang"] - path = src/scm-slang - url = https://github.com/source-academy/scm-slang.git +[submodule "src/alt-langs/scheme/scm-slang"] + path = src/alt-langs/scheme/scm-slang + url = https://github.com/source-academy/scm-slang [submodule "src/py-slang"] path = src/py-slang url = https://github.com/source-academy/py-slang diff --git a/.prettierignore b/.prettierignore index 86f590c00..cb1a50835 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,3 @@ -/src/scm-slang/ +/src/alt-langs/ /src/py-slang/ /src/**/__tests__/**/__snapshots__ \ No newline at end of file diff --git a/src/parser/__tests__/scheme-encode-decode.ts b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts similarity index 85% rename from src/parser/__tests__/scheme-encode-decode.ts rename to src/alt-langs/scheme/__tests__/scheme-encode-decode.ts index 238620f22..b8f34f452 100644 --- a/src/parser/__tests__/scheme-encode-decode.ts +++ b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts @@ -1,10 +1,10 @@ import { Node } from 'estree' -import { UnassignedVariable } from '../../errors/errors' -import { decode, encode } from '../../scm-slang/src' -import { cons, set$45$cdr$33$ } from '../../scm-slang/src/stdlib/base' -import { dummyExpression } from '../../utils/dummyAstCreator' -import { decodeError, decodeValue } from '../scheme' +import { UnassignedVariable } from '../../../errors/errors' +import { decode, encode } from '../scm-slang/src' +import { cons, set$45$cdr$33$ } from '../scm-slang/src/stdlib/base' +import { dummyExpression } from '../../../utils/dummyAstCreator' +import { decodeError, decodeValue } from '../../../parser/scheme' describe('Scheme encoder and decoder', () => { it('encoder and decoder are proper inverses of one another', () => { diff --git a/src/parser/__tests__/scheme.ts b/src/alt-langs/scheme/__tests__/scheme.ts similarity index 93% rename from src/parser/__tests__/scheme.ts rename to src/alt-langs/scheme/__tests__/scheme.ts index f723fedbb..89da8bbe5 100644 --- a/src/parser/__tests__/scheme.ts +++ b/src/alt-langs/scheme/__tests__/scheme.ts @@ -1,7 +1,7 @@ -import { parseError } from '../..' -import { mockContext } from '../../mocks/context' -import { Chapter } from '../../types' -import { SchemeParser } from '../scheme' +import { parseError } from '../../..' +import { mockContext } from '../../../mocks/context' +import { Chapter } from '../../../types' +import { SchemeParser } from '../../../parser/scheme' const parser_1 = new SchemeParser(Chapter.SCHEME_1) const parser_2 = new SchemeParser(Chapter.SCHEME_2) diff --git a/src/scm-slang b/src/alt-langs/scheme/scm-slang similarity index 100% rename from src/scm-slang rename to src/alt-langs/scheme/scm-slang diff --git a/src/createContext.ts b/src/createContext.ts index 933e738dd..d1cf61275 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -1,10 +1,10 @@ // Variable determining chapter of Source is contained in this file. +import * as scheme_libs from './alt-langs/scheme/scm-slang/src/stdlib/source-scheme-library' import { GLOBAL, JSSLANG_PROPERTIES } from './constants' import { call_with_current_continuation } from './cse-machine/continuations' import * as gpu_lib from './gpu/lib' import { AsyncScheduler } from './schedulers' -import * as scheme_libs from './scm-slang/src/stdlib/source-scheme-library' import { lazyListPrelude } from './stdlib/lazyList.prelude' import * as list from './stdlib/list' import { list_to_vector } from './stdlib/list' diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index 1aa4845e8..ba0c5f899 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,6 +1,6 @@ import { Node, Program } from 'estree' -import { decode, encode, schemeParse } from '../../scm-slang/src' +import { decode, encode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' import { car, cdr, @@ -12,7 +12,7 @@ import { procedure$63$, set$45$cdr$33$, vector$63$ -} from '../../scm-slang/src/stdlib/base' +} from '../../alt-langs/scheme/scm-slang/src/stdlib/base' import { List, Pair } from '../../stdlib/list' import { Chapter, Context, ErrorType, SourceError } from '../../types' import { FatalSyntaxError } from '../errors' From a9fefb5d42e7108b7236530a0db71928988676b1 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 21 Mar 2024 15:13:04 +0800 Subject: [PATCH 17/41] remove duplicate code between scm-slang and js-slang --- .../__tests__/{scheme.ts => scheme-parser.ts} | 0 src/alt-langs/scheme/scm-slang | 2 +- src/parser/scheme/index.ts | 20 ++++--------------- 3 files changed, 5 insertions(+), 17 deletions(-) rename src/alt-langs/scheme/__tests__/{scheme.ts => scheme-parser.ts} (100%) diff --git a/src/alt-langs/scheme/__tests__/scheme.ts b/src/alt-langs/scheme/__tests__/scheme-parser.ts similarity index 100% rename from src/alt-langs/scheme/__tests__/scheme.ts rename to src/alt-langs/scheme/__tests__/scheme-parser.ts diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index 65ad23d20..ad3b2e39c 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit 65ad23d20acfad5b45147ef0373fac14694cdb8a +Subproject commit ad3b2e39c6c9cd944494bc6abf0d8fbaa11ee59d diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index ba0c5f899..9391bf019 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,6 +1,6 @@ -import { Node, Program } from 'estree' +import { Program } from 'estree' -import { decode, encode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' +import { decode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' import { car, cdr, @@ -18,7 +18,6 @@ import { Chapter, Context, ErrorType, SourceError } from '../../types' import { FatalSyntaxError } from '../errors' import { AcornOptions, Parser } from '../types' import { positionToSourceLocation } from '../utils' -const walk = require('acorn-walk') export class SchemeParser implements Parser { private chapter: number @@ -33,10 +32,8 @@ export class SchemeParser implements Parser { ): Program | null { try { // parse the scheme code - const estree = schemeParse(programStr, this.chapter) - // walk the estree and encode all identifiers - encodeTree(estree) - return estree as unknown as Program + const estree = schemeParse(programStr, this.chapter, true) + return estree as Program } catch (error) { if (error instanceof SyntaxError) { error = new FatalSyntaxError(positionToSourceLocation((error as any).loc), error.toString()) @@ -75,15 +72,6 @@ function getSchemeChapter(chapter: Chapter): number { } } -export function encodeTree(tree: Program): Program { - walk.full(tree, (node: Node) => { - if (node.type === 'Identifier') { - node.name = encode(node.name) - } - }) - return tree -} - function decodeString(str: string): string { return str.replace(/\$scheme_[\w$]+|\$\d+\$/g, match => { return decode(match) From 7089e07699561b5157f62458e05314682b97d6fb Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 21 Mar 2024 16:48:21 +0800 Subject: [PATCH 18/41] ignore alt langs coverage --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d264d489d..796b3a9fe 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "/node_modules/", "/src/typings/", "/src/utils/testing.ts", - "/src/scm-slang", + "/src/alt-langs", "/src/py-slang/" ], "reporters": [ From 8ecf27498a14468a453b03f57057b8b712d7d7af Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 2 Apr 2024 01:50:02 +0800 Subject: [PATCH 19/41] update scm-slang --- src/alt-langs/scheme/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index ad3b2e39c..e012cebcd 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit ad3b2e39c6c9cd944494bc6abf0d8fbaa11ee59d +Subproject commit e012cebcd73ea162b5436709b2821ee64aa7ff56 From 1b402b89641df63ac382c13ffaf66b62a976eb57 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 4 Apr 2024 12:28:10 +0800 Subject: [PATCH 20/41] start to add mapping functions for data --- src/alt-langs/scheme/scm-slang | 2 +- src/index.ts | 115 +++++++++++++++++++-------------- src/interpreter/closure.ts | 4 +- src/parser/scheme/index.ts | 23 ++++--- 4 files changed, 79 insertions(+), 65 deletions(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index e012cebcd..380317271 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit e012cebcd73ea162b5436709b2821ee64aa7ff56 +Subproject commit 38031727124d691bb76b67c4af55413a345bac10 diff --git a/src/index.ts b/src/index.ts index a4718f700..84c52c03d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -216,72 +216,87 @@ export async function runInContext( return runFilesInContext(files, defaultFilePath, context, options) } +function pickMapper(context: Context): (x: Result) => Result { + switch (context.chapter) { + case Chapter.SCHEME_1: + case Chapter.SCHEME_2: + case Chapter.SCHEME_3: + case Chapter.SCHEME_4: + case Chapter.FULL_SCHEME: + context.errors = context.errors.map(error => decodeError(error)) + return x => { + if (x.status === 'finished') { + return { + ...x, + value: decodeValue(x.value) + } as Finished + } + return x + } + default: + return x => x + } +} + +// this is the first entrypoint for all source files. +// as such, all mapping functions required by alternate languages +// should be defined here. export async function runFilesInContext( files: Partial>, entrypointFilePath: string, context: Context, options: RecursivePartial = {} ): Promise { - for (const filePath in files) { - const filePathError = validateFilePath(filePath) - if (filePathError !== null) { - context.errors.push(filePathError) + async function runFilesInContextHelper( + files: Partial>, + entrypointFilePath: string, + context: Context, + options: RecursivePartial = {} + ): Promise { + for (const filePath in files) { + const filePathError = validateFilePath(filePath) + if (filePathError !== null) { + context.errors.push(filePathError) + return resolvedErrorPromise + } + } + + const code = files[entrypointFilePath] + if (code === undefined) { + context.errors.push(new ModuleNotFoundError(entrypointFilePath)) return resolvedErrorPromise } - } - const code = files[entrypointFilePath] - if (code === undefined) { - context.errors.push(new ModuleNotFoundError(entrypointFilePath)) - return resolvedErrorPromise - } + if ( + context.chapter === Chapter.FULL_JS || + context.chapter === Chapter.FULL_TS || + context.chapter === Chapter.PYTHON_1 + ) { + const program = parse(code, context) + if (program === null) { + return resolvedErrorPromise + } - if ( - context.chapter === Chapter.FULL_JS || - context.chapter === Chapter.FULL_TS || - context.chapter === Chapter.PYTHON_1 - ) { - const program = parse(code, context) - if (program === null) { - return resolvedErrorPromise + const fullImportOptions = mergeImportOptions(options.importOptions) + return fullJSRunner(program, context, fullImportOptions) } - const fullImportOptions = mergeImportOptions(options.importOptions) - return fullJSRunner(program, context, fullImportOptions) - } + if (context.chapter === Chapter.HTML) { + return htmlRunner(code, context, options) + } - if (context.chapter === Chapter.HTML) { - return htmlRunner(code, context, options) - } + // FIXME: Clean up state management so that the `parseError` function is pure. + // This is not a huge priority, but it would be good not to make use of + // global state. + verboseErrors = hasVerboseErrors(code) - if (context.chapter <= +Chapter.SCHEME_1 && context.chapter >= +Chapter.FULL_SCHEME) { - // If the language is scheme, we need to format all errors and returned values first - // Use the standard runner to get the result - const evaluated: Promise = sourceFilesRunner( - files, - entrypointFilePath, - context, - options - ).then(result => { - // Format the returned value - if (result.status === 'finished') { - return { - ...result, - value: decodeValue(result.value) - } as Finished - } - return result - }) - // Format all errors in the context - context.errors = context.errors.map(error => decodeError(error)) - return evaluated + // the sourceFilesRunner + return sourceFilesRunner(files, entrypointFilePath, context, options) } - // FIXME: Clean up state management so that the `parseError` function is pure. - // This is not a huge priority, but it would be good not to make use of - // global state. - verboseErrors = hasVerboseErrors(code) - return sourceFilesRunner(files, entrypointFilePath, context, options) + return runFilesInContextHelper(files, entrypointFilePath, context, options).then( + pickMapper(context) + ) } export function resume(result: Result): Finished | ResultError | Promise { diff --git a/src/interpreter/closure.ts b/src/interpreter/closure.ts index 6f7f2c027..a781d5f57 100644 --- a/src/interpreter/closure.ts +++ b/src/interpreter/closure.ts @@ -103,10 +103,10 @@ export default class Closure extends Callable { public preDefined?: boolean /** The original node that created this Closure */ - public originalNode: es.Function + public originalNode: es.Function | es.ArrowFunctionExpression constructor( - public node: es.Function, + public node: es.Function | es.ArrowFunctionExpression, public environment: Environment, context: Context, isPredefined?: boolean diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index 9391bf019..b0a70b4ba 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,6 +1,5 @@ -import { Program } from 'estree' - -import { decode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' +import { ArrowFunctionExpression, Program } from 'estree' +import { decode, estreeDecode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' import { car, cdr, @@ -9,7 +8,6 @@ import { last$45$pair, list$45$tail, pair$63$, - procedure$63$, set$45$cdr$33$, vector$63$ } from '../../alt-langs/scheme/scm-slang/src/stdlib/base' @@ -18,6 +16,7 @@ import { Chapter, Context, ErrorType, SourceError } from '../../types' import { FatalSyntaxError } from '../errors' import { AcornOptions, Parser } from '../types' import { positionToSourceLocation } from '../utils' +import Closure from '../../interpreter/closure' export class SchemeParser implements Parser { private chapter: number @@ -107,7 +106,7 @@ export function decodeValue(x: any): any { all_pairs.push(current) current = cdr(current) } - x + // assemble a new list using the elements in all_pairs let new_list = null for (let i = all_pairs.length - 1; i >= 0; i--) { @@ -125,13 +124,13 @@ export function decodeValue(x: any): any { } else if (vector$63$(x)) { // May contain encoded strings. return x.map(decodeValue) - } else if (procedure$63$(x)) { - // copy x to avoid modifying the original object - const newX = { ...x } - const newString = decodeString(x.toString()) - // change the toString method to return the decoded string - newX.toString = () => newString - return newX + } else if (x instanceof Closure) { + const newNode = estreeDecode(x.originalNode) as ArrowFunctionExpression + + // not a big fan of mutation, but we assert we will never need the original node again anyway + x.node = newNode + x.originalNode = newNode + return x } else { // string, number, boolean, null, undefined // no need to decode. From 90de75aea0caaae893723ddeb2d90be15532a90a Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 4 Apr 2024 12:33:33 +0800 Subject: [PATCH 21/41] update python and scheme-slang --- src/alt-langs/scheme/scm-slang | 2 +- src/py-slang | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index 380317271..562a54c7e 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit 38031727124d691bb76b67c4af55413a345bac10 +Subproject commit 562a54c7e7e9c569f5c72fd92244f8a471befa2b diff --git a/src/py-slang b/src/py-slang index 15f1ac10a..821987b3e 160000 --- a/src/py-slang +++ b/src/py-slang @@ -1 +1 @@ -Subproject commit 15f1ac10a77a38b6d8590afece97fe6422fdde29 +Subproject commit 821987b3e66ed6574981ce58f4d5d43a7ccb11c1 From 40205e4cda6804b2325d46bb9afc1b3b9153bb5a Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 4 Apr 2024 14:44:29 +0800 Subject: [PATCH 22/41] destructively change data types in js-slang, especially since they are not needed in encoded form --- src/parser/scheme/index.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index b0a70b4ba..c38e932d7 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -145,11 +145,8 @@ export function decodeError(error: SourceError): SourceError { // Syntax errors are not encoded. return error } - const newExplain = decodeString(error.explain()) - const newElaborate = decodeString(error.elaborate()) - return { - ...error, - explain: () => newExplain, - elaborate: () => newElaborate - } + // mutate the error to reflect the new messages + error.explain = () => decodeString(error.explain()) + error.elaborate = () => decodeString(error.elaborate()) + return error } From 1436d4ae355cc021ee510dc50b571577334f5ad4 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 16:25:05 +0800 Subject: [PATCH 23/41] prevent js-slang from testing alternate languages - they should manage themselves --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 9afdd7775..980e24ce8 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "testRegex": "/__tests__/.*\\.ts$", "testPathIgnorePatterns": [ "/dist/", + "/src/alt-langs", ".*benchmark.*", "/__tests__/(.*/)?utils\\.ts" ], From 1d01e90d994ff4185e550ecf43ccc32a2805ba8c Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 16:26:13 +0800 Subject: [PATCH 24/41] add mapping and language-specific representations for the result type --- src/alt-langs/mapper.ts | 43 +++++++ src/alt-langs/scheme/scheme_mapper.ts | 157 ++++++++++++++++++++++++++ src/alt-langs/scheme/scm-slang | 2 +- src/index.ts | 26 +---- src/parser/scheme/index.ts | 99 +--------------- src/types.ts | 6 + 6 files changed, 212 insertions(+), 121 deletions(-) create mode 100644 src/alt-langs/mapper.ts create mode 100644 src/alt-langs/scheme/scheme_mapper.ts diff --git a/src/alt-langs/mapper.ts b/src/alt-langs/mapper.ts new file mode 100644 index 000000000..a6be74543 --- /dev/null +++ b/src/alt-langs/mapper.ts @@ -0,0 +1,43 @@ +/** + * A generic mapper for all languages. + * If required, maps the final result produced by js-slang to + * the required representation for the language. + */ + +import { Context, Result } from ".." +import { Chapter } from "../types" +import { mapErrorToScheme, mapResultToScheme } from "./scheme/scheme_mapper" + +/** + * A representation of a value in a language. + * This is used to represent the final value produced by js-slang. + * It is separate from the actual value of the result. + */ +export class Representation { + constructor(public representation: string) {} + toString() { + return this.representation + } +} + +export function mapResult(context: Context): (x: Result) => Result { + switch (context.chapter) { + case Chapter.SCHEME_1: + case Chapter.SCHEME_2: + case Chapter.SCHEME_3: + case Chapter.SCHEME_4: + case Chapter.FULL_SCHEME: + return x => { + if (x.status === 'finished') { + return mapResultToScheme(x) + } else if (x.status === "error") { + context.errors = context.errors.map(mapErrorToScheme) + } + return x + } + default: + // normally js-slang. + // there is no need for a mapper in this case. + return x => x + } +} \ No newline at end of file diff --git a/src/alt-langs/scheme/scheme_mapper.ts b/src/alt-langs/scheme/scheme_mapper.ts new file mode 100644 index 000000000..2619b2d36 --- /dev/null +++ b/src/alt-langs/scheme/scheme_mapper.ts @@ -0,0 +1,157 @@ +import { ArrowFunctionExpression, Identifier, RestElement } from "estree" +import Closure from "../../interpreter/closure" +import { decode, estreeDecode } from "./scm-slang/src" +import { boolean$63$, car, cdr, circular$45$list$63$, cons, dotted$45$list$63$, last$45$pair, list$45$tail, null$63$, number$63$, pair$63$, proper$45$list$63$, set$45$cdr$33$, vector$63$ } from "./scm-slang/src/stdlib/source-scheme-library" +import { ErrorType, Result, SourceError } from "../../types" +import { List, Pair } from "../../stdlib/list" +import { Representation } from "../mapper" + +export function mapResultToScheme(res: Result): Result { + if (res.status === "finished" || res.status === "suspended-non-det") { + return { + ...res, + value: decodeValue(res.value), + representation: showSchemeData(res.value) + } + } + return res +} + +// Given an error, decode its message if and +// only if an encoded value may exist in it. +export function mapErrorToScheme(error: SourceError): SourceError { + if (error.type === ErrorType.SYNTAX) { + // Syntax errors are not encoded. + return error + } + const newExplain = decodeString(error.explain()) + const newElaborate = decodeString(error.elaborate()) + return { + ...error, + explain: () => newExplain, + elaborate: () => newElaborate + } +} + +function showSchemeData(data: any): Representation { + return schemeVisualise(decodeValue(data)) +} + +function decodeString(str: string): string { + return str.replace(/\$scheme_[\w$]+|\$\d+\$/g, match => { + return decode(match) + }) +} + +// Given any value, change the representation of it to +// the required scheme representation. +function schemeVisualise(x: any): Representation { + function stringify(x: any): string { + if (null$63$(x)) { + return '()' + } else if (x === undefined) { + return 'undefined' + } else if (typeof x === 'string') { + return `"${x}"` + } else if (number$63$(x)) { + return x.toString() + } else if (boolean$63$(x)) { + return x ? '#t' : '#f' + } else if (x instanceof Closure) { + const node = x.originalNode + const parameters = node.params.map((param: Identifier | RestElement) => param.type === "Identifier" ? param.name : ". " + (param.argument as Identifier).name).join(' ').trim() + return `#` + } else if (circular$45$list$63$(x)) { + return '(circular list)' + } else if (dotted$45$list$63$(x)) { + let string = '(' + let current = x + while (pair$63$(current)) { + string += `${schemeVisualise(car(current))} ` + current = cdr(current) + } + return string.trim() + ` . ${schemeVisualise(current)})` + } else if (proper$45$list$63$(x)) { + let string = '(' + let current = x + while (current !== null) { + string += `${schemeVisualise(car(current))} ` + current = cdr(current) + } + return string.trim() + ')' + } else if (vector$63$(x)) { + let string = '#(' + for (let i = 0; i < x.length; i++) { + string += `${schemeVisualise(x[i])} ` + } + return string.trim() + ')' + } else { + return x.toString() + } + } + + // return an object with a toString method that returns the stringified version of x + return new Representation(stringify(x)) +} + +// Given any value, decode it if and +// only if an encoded value may exist in it. +// this function is used to accurately display +// values in the REPL. +function decodeValue(x: any): any { + // helper version of list_tail that assumes non-null return value + function list_tail(xs: List, i: number): List { + if (i === 0) { + return xs + } else { + return list_tail(list$45$tail(xs), i - 1) + } + } + + if (circular$45$list$63$(x)) { + // May contain encoded strings. + let circular_pair_index = -1 + const all_pairs: Pair[] = [] + + // iterate through all pairs in the list until we find the circular pair + let current = x + while (current !== null) { + if (all_pairs.includes(current)) { + circular_pair_index = all_pairs.indexOf(current) + break + } + all_pairs.push(current) + current = cdr(current) + } + + // assemble a new list using the elements in all_pairs + let new_list = null + for (let i = all_pairs.length - 1; i >= 0; i--) { + new_list = cons(decodeValue(car(all_pairs[i])), new_list) + } + + // finally we can set the last cdr of the new list to the circular-pair itself + + const circular_pair = list_tail(new_list, circular_pair_index) + set$45$cdr$33$(last$45$pair(new_list), circular_pair) + return new_list + } else if (pair$63$(x)) { + // May contain encoded strings. + return cons(decodeValue(car(x)), decodeValue(cdr(x))) + } else if (vector$63$(x)) { + // May contain encoded strings. + return x.map(decodeValue) + } else if (x instanceof Closure) { + const newNode = estreeDecode(x.originalNode) as ArrowFunctionExpression + + // not a big fan of mutation, but we assert we will never need the original node again anyway + x.node = newNode + x.originalNode = newNode + return x + } else { + // string, number, boolean, null, undefined + // no need to decode. + return x + } +} + diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index 562a54c7e..819379354 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit 562a54c7e7e9c569f5c72fd92244f8a471befa2b +Subproject commit 8193793541900dcbfbf2ba86e5325bd6dca0f285 diff --git a/src/index.ts b/src/index.ts index 84c52c03d..eef230d31 100644 --- a/src/index.ts +++ b/src/index.ts @@ -33,7 +33,6 @@ import { validateFilePath } from './modules/preprocessor/filePaths' import { mergeImportOptions } from './modules/utils' import { getKeywords, getProgramNames, NameDeclaration } from './name-extractor' import { parse } from './parser/parser' -import { decodeError, decodeValue } from './parser/scheme' import { fullJSRunner, hasVerboseErrors, @@ -41,6 +40,7 @@ import { resolvedErrorPromise, sourceFilesRunner } from './runner' +import { mapResult } from './alt-langs/mapper' export interface IOptions { scheduler: 'preemptive' | 'async' @@ -216,28 +216,6 @@ export async function runInContext( return runFilesInContext(files, defaultFilePath, context, options) } -function pickMapper(context: Context): (x: Result) => Result { - switch (context.chapter) { - case Chapter.SCHEME_1: - case Chapter.SCHEME_2: - case Chapter.SCHEME_3: - case Chapter.SCHEME_4: - case Chapter.FULL_SCHEME: - context.errors = context.errors.map(error => decodeError(error)) - return x => { - if (x.status === 'finished') { - return { - ...x, - value: decodeValue(x.value) - } as Finished - } - return x - } - default: - return x => x - } -} - // this is the first entrypoint for all source files. // as such, all mapping functions required by alternate languages // should be defined here. @@ -295,7 +273,7 @@ export async function runFilesInContext( } return runFilesInContextHelper(files, entrypointFilePath, context, options).then( - pickMapper(context) + mapResult(context) ) } diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index c38e932d7..30df2b836 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,22 +1,9 @@ -import { ArrowFunctionExpression, Program } from 'estree' -import { decode, estreeDecode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' -import { - car, - cdr, - circular$45$list$63$, - cons, - last$45$pair, - list$45$tail, - pair$63$, - set$45$cdr$33$, - vector$63$ -} from '../../alt-langs/scheme/scm-slang/src/stdlib/base' -import { List, Pair } from '../../stdlib/list' -import { Chapter, Context, ErrorType, SourceError } from '../../types' +import { Program } from 'estree' +import { schemeParse } from '../../alt-langs/scheme/scm-slang/src' +import { Chapter, Context } from '../../types' import { FatalSyntaxError } from '../errors' import { AcornOptions, Parser } from '../types' import { positionToSourceLocation } from '../utils' -import Closure from '../../interpreter/closure' export class SchemeParser implements Parser { private chapter: number @@ -70,83 +57,3 @@ function getSchemeChapter(chapter: Chapter): number { throw new Error(`SchemeParser was not given a valid chapter!`) } } - -function decodeString(str: string): string { - return str.replace(/\$scheme_[\w$]+|\$\d+\$/g, match => { - return decode(match) - }) -} - -// Given any value, decode it if and -// only if an encoded value may exist in it. -// this function is used to accurately display -// values in the REPL. -export function decodeValue(x: any): any { - // helper version of list_tail that assumes non-null return value - function list_tail(xs: List, i: number): List { - if (i === 0) { - return xs - } else { - return list_tail(list$45$tail(xs), i - 1) - } - } - - if (circular$45$list$63$(x)) { - // May contain encoded strings. - let circular_pair_index = -1 - const all_pairs: Pair[] = [] - - // iterate through all pairs in the list until we find the circular pair - let current = x - while (current !== null) { - if (all_pairs.includes(current)) { - circular_pair_index = all_pairs.indexOf(current) - break - } - all_pairs.push(current) - current = cdr(current) - } - - // assemble a new list using the elements in all_pairs - let new_list = null - for (let i = all_pairs.length - 1; i >= 0; i--) { - new_list = cons(decodeValue(car(all_pairs[i])), new_list) - } - - // finally we can set the last cdr of the new list to the circular-pair itself - - const circular_pair = list_tail(new_list, circular_pair_index) - set$45$cdr$33$(last$45$pair(new_list), circular_pair) - return new_list - } else if (pair$63$(x)) { - // May contain encoded strings. - return cons(decodeValue(car(x)), decodeValue(cdr(x))) - } else if (vector$63$(x)) { - // May contain encoded strings. - return x.map(decodeValue) - } else if (x instanceof Closure) { - const newNode = estreeDecode(x.originalNode) as ArrowFunctionExpression - - // not a big fan of mutation, but we assert we will never need the original node again anyway - x.node = newNode - x.originalNode = newNode - return x - } else { - // string, number, boolean, null, undefined - // no need to decode. - return x - } -} - -// Given an error, decode its message if and -// only if an encoded value may exist in it. -export function decodeError(error: SourceError): SourceError { - if (error.type === ErrorType.SYNTAX) { - // Syntax errors are not encoded. - return error - } - // mutate the error to reflect the new messages - error.explain = () => decodeString(error.explain()) - error.elaborate = () => decodeString(error.elaborate()) - return error -} diff --git a/src/types.ts b/src/types.ts index e4fc7e07d..023349846 100644 --- a/src/types.ts +++ b/src/types.ts @@ -11,6 +11,7 @@ import * as es from 'estree' import { EnvTree } from './createContext' import Heap from './cse-machine/heap' import { Control, Stash } from './cse-machine/interpreter' +import { Representation } from './alt-langs/mapper' /** * Defines functions that act as built-ins, but might rely on @@ -273,6 +274,10 @@ export interface Finished { status: 'finished' context: Context value: Value + representation?: Representation // if the returned value needs a unique representation, + // (for example if the language used is not JS), + // the display of the result will use the representation + // field instead } export interface Suspended { @@ -284,6 +289,7 @@ export interface Suspended { export type SuspendedNonDet = Omit & { status: 'suspended-non-det' } & { value: Value + representation?: Representation // never used, only kept for consistency with Finished } export interface SuspendedCseEval { From 106bb8cfb83c9d18e5b1b19a634098fe5b6e00de Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 16:28:06 +0800 Subject: [PATCH 25/41] change the command-line REPL to use representations if necessary --- src/repl/repl.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/repl/repl.ts b/src/repl/repl.ts index b3b4f7f47..e6cac488b 100644 --- a/src/repl/repl.ts +++ b/src/repl/repl.ts @@ -6,6 +6,7 @@ import { pyLanguages, scmLanguages, sourceLanguages } from '../constants' import { createContext, IOptions, parseError, runInContext } from '../index' import Closure from '../interpreter/closure' import { ExecutionMethod, Variant } from '../types' +import { Representation } from '../alt-langs/mapper' function startRepl( chapter = 1, @@ -35,7 +36,9 @@ function startRepl( eval: (cmd, unusedContext, unusedFilename, callback) => { runInContext(cmd, context, options).then(obj => { if (obj.status === 'finished' || obj.status === 'suspended-non-det') { - callback(null, obj.value) + // if the result is a representation, display the representation. + // else, default to standard value representation. + callback(null, obj.representation ? obj.representation : obj.value) } else { callback(new Error(parseError(context.errors)), undefined) } @@ -44,7 +47,9 @@ function startRepl( // set depth to a large number so that `parse()` output will not be folded, // setting to null also solves the problem, however a reference loop might crash writer: output => { - return output instanceof Closure || typeof output === 'function' + return output instanceof Closure || + typeof output === 'function' || + output instanceof Representation ? output.toString() : inspect(output, { depth: 1000, @@ -97,7 +102,7 @@ function main() { 'default' ], ['h', 'help', 'display this help'], - ['e', 'eval', "don't show REPL, only display output of evaluation"] + ['e', 'eval', "don't show REPL, only dispResultlay output of evaluation"] ]) .bindHelp() .setHelp('Usage: js-slang [PROGRAM_STRING] [OPTION]\n\n[[OPTIONS]]') From 7b4a904e3a8fb8af3898c52506154664e41cf384 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 17:25:45 +0800 Subject: [PATCH 26/41] add tests for mapper back into coverage pattern --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 537e3f135..e9d98193e 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "testRegex": "/__tests__/.*\\.ts$", "testPathIgnorePatterns": [ "/dist/", - "/src/alt-langs", + "/src/alt-langs/(?!__tests__).*/", ".*benchmark.*", "/__tests__/(.*/)?utils\\.ts" ], @@ -115,7 +115,7 @@ "/node_modules/", "/src/typings/", "/src/utils/testing.ts", - "/src/alt-langs", + "/src/alt-langs/(?!__tests__).*/", "/src/py-slang/" ], "reporters": [ From 029b5b3bf2d5851afb6f9dcce2411d06f9987442 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 17:26:24 +0800 Subject: [PATCH 27/41] fix arrays being treated as pairs in scheme --- src/alt-langs/scheme/scheme_mapper.ts | 2 +- src/alt-langs/scheme/scm-slang | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/alt-langs/scheme/scheme_mapper.ts b/src/alt-langs/scheme/scheme_mapper.ts index 2619b2d36..2f32633c8 100644 --- a/src/alt-langs/scheme/scheme_mapper.ts +++ b/src/alt-langs/scheme/scheme_mapper.ts @@ -63,7 +63,7 @@ function schemeVisualise(x: any): Representation { return `#` } else if (circular$45$list$63$(x)) { return '(circular list)' - } else if (dotted$45$list$63$(x)) { + } else if (pair$63$(x) && dotted$45$list$63$(x)) { let string = '(' let current = x while (pair$63$(current)) { diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index 819379354..d86b7b67c 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit 8193793541900dcbfbf2ba86e5325bd6dca0f285 +Subproject commit d86b7b67c9472263c8159b12515b836e969745d3 From 35cea1ec28a101d41a8b0b3fc5cfb77235a6a33f Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 17:26:50 +0800 Subject: [PATCH 28/41] add test for mapper --- src/alt-langs/__tests__/mapper.ts | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/alt-langs/__tests__/mapper.ts diff --git a/src/alt-langs/__tests__/mapper.ts b/src/alt-langs/__tests__/mapper.ts new file mode 100644 index 000000000..8c4b8374b --- /dev/null +++ b/src/alt-langs/__tests__/mapper.ts @@ -0,0 +1,32 @@ +import { mockContext } from "../../mocks/context"; +import { Chapter, Finished } from "../../types"; +import { mapResult } from "../mapper"; + +test("given source, mapper should do nothing (no mapping needed)", () => { + const context = mockContext(); + const result = { + status: "finished", + context: context, + value: 5, + } as Finished; + const mapper = mapResult(context); + expect(mapper(result)).toEqual(result); +}) + +test("given scheme, mapper should map result to scheme representation", () => { + const context = mockContext(Chapter.SCHEME_1); + const result = { + status: "finished", + context: context, + value: [1, 2, 3, 4, 5], + } as Finished; + const mapper = mapResult(context); + expect(mapper(result)).toEqual({ + status: "finished", + context: context, + value: [1, 2, 3, 4, 5], + representation: { + representation: "#(1 2 3 4 5)", + }, + }); +}) \ No newline at end of file From 1fbe3c589a0b6265fa3678252c34a669185133f9 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 17:40:09 +0800 Subject: [PATCH 29/41] undo accidental deletion of scheme parser tests --- src/parser/__tests__/scheme.ts | 86 ++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 src/parser/__tests__/scheme.ts diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts new file mode 100644 index 000000000..794041a1e --- /dev/null +++ b/src/parser/__tests__/scheme.ts @@ -0,0 +1,86 @@ +import { parseError } from '../..' +import { mockContext } from '../../mocks/context' +import { Chapter } from '../../types' +import { SchemeParser } from '../scheme' + +const parser = new SchemeParser(Chapter.SCHEME_1) +const parser_full = new SchemeParser(Chapter.FULL_SCHEME) +let context = mockContext(Chapter.SCHEME_1) +let context_full = mockContext(Chapter.FULL_SCHEME) + +beforeEach(() => { + context = mockContext(Chapter.SCHEME_1) + context_full = mockContext(Chapter.FULL_SCHEME) +}) + +describe('Scheme parser', () => { + it('represents itself correctly', () => { + expect(parser.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) + }) + + it('throws error if given chapter is wrong', () => { + expect(() => new SchemeParser(Chapter.FULL_PYTHON)).toThrow( + 'SchemeParser was not given a valid chapter!' + ) + }) + + it('throws errors if option throwOnError is selected + parse error is encountered', () => { + const code = `(hello))` + expect(() => parser.parse(code, context, undefined, true)).toThrow("Unexpected ')'") + }) + + it('formats tokenizer errors correctly', () => { + const code = `(hello))` + + parser.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) + ) + }) + + it('formats parser errors correctly', () => { + const code = `(define (f x)` + + parser.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) + ) + }) + + it('allows usage of builtins/preludes', () => { + const code = ` + (+ 1 2 3) + (gcd 10 15) + ` + + parser.parse(code, context) + expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) + }) + + it('allows usage of imports/modules', () => { + const code = `(import "rune" (show heart)) + (show heart) + ` + + parser.parse(code, context) + expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) + }) + + it('disallows syntax for higher chapters', () => { + const code = `'(1 2 3)` + + parser.parse(code, context) + expect(context.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ + message: expect.stringContaining("Syntax ''' not allowed at Scheme §1") + }) + ) + }) + + it('allows syntax for lower chapters', () => { + const code = `'(1 2 3)` + + parser_full.parse(code, context_full) + expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) + }) +}) From dba59cde2864dce19c6a174fb1a3110cca08e5b7 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 17:41:02 +0800 Subject: [PATCH 30/41] fix typo in repl, make undefined check explicit --- src/repl/repl.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/repl/repl.ts b/src/repl/repl.ts index e6cac488b..4452978c8 100644 --- a/src/repl/repl.ts +++ b/src/repl/repl.ts @@ -38,7 +38,7 @@ function startRepl( if (obj.status === 'finished' || obj.status === 'suspended-non-det') { // if the result is a representation, display the representation. // else, default to standard value representation. - callback(null, obj.representation ? obj.representation : obj.value) + callback(null, obj.representation !== undefined ? obj.representation : obj.value) } else { callback(new Error(parseError(context.errors)), undefined) } @@ -102,7 +102,7 @@ function main() { 'default' ], ['h', 'help', 'display this help'], - ['e', 'eval', "don't show REPL, only dispResultlay output of evaluation"] + ['e', 'eval', "don't show REPL, only display output of evaluation"] ]) .bindHelp() .setHelp('Usage: js-slang [PROGRAM_STRING] [OPTION]\n\n[[OPTIONS]]') From 833b1a770f76cf0c8e4a37a26c27aed8290ca0ae Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 19:54:09 +0800 Subject: [PATCH 31/41] test every version of scheme parser --- src/parser/__tests__/scheme.ts | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts index 794041a1e..54a362827 100644 --- a/src/parser/__tests__/scheme.ts +++ b/src/parser/__tests__/scheme.ts @@ -4,18 +4,32 @@ import { Chapter } from '../../types' import { SchemeParser } from '../scheme' const parser = new SchemeParser(Chapter.SCHEME_1) +const parser_2 = new SchemeParser(Chapter.SCHEME_2) +const parser_3 = new SchemeParser(Chapter.SCHEME_3) +const parser_4 = new SchemeParser(Chapter.SCHEME_4) const parser_full = new SchemeParser(Chapter.FULL_SCHEME) let context = mockContext(Chapter.SCHEME_1) +let context_2 = mockContext(Chapter.SCHEME_2) +let context_3 = mockContext(Chapter.SCHEME_3) +let context_4 = mockContext(Chapter.SCHEME_4) let context_full = mockContext(Chapter.FULL_SCHEME) beforeEach(() => { + // reset the contexts context = mockContext(Chapter.SCHEME_1) + context_2 = mockContext(Chapter.SCHEME_2) + context_3 = mockContext(Chapter.SCHEME_3) + context_4 = mockContext(Chapter.SCHEME_4) context_full = mockContext(Chapter.FULL_SCHEME) }) describe('Scheme parser', () => { it('represents itself correctly', () => { expect(parser.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) + expect(parser_2.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 2}"`) + expect(parser_3.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 3}"`) + expect(parser_4.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 4}"`) + expect(parser_full.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: Infinity}"`) }) it('throws error if given chapter is wrong', () => { @@ -77,10 +91,25 @@ describe('Scheme parser', () => { ) }) + it('disallows syntax for higher chapters (2)', () => { + const code = `#(1 2 3)` + + parser_2.parse(code, context_2) + expect(context_2.errors.slice(-1)[0]).toMatchObject( + expect.objectContaining({ + message: expect.stringContaining("Syntax '#' not allowed at Scheme §2") + }) + ) + }) + it('allows syntax for lower chapters', () => { const code = `'(1 2 3)` parser_full.parse(code, context_full) expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) + parser_4.parse(code, context_4) + expect(parseError(context_4.errors)).toMatchInlineSnapshot(`""`) + parser_3.parse(code, context_3) + expect(parseError(context_3.errors)).toMatchInlineSnapshot(`""`) }) }) From 14c48d7439743afec4f4b4d8959c4760354cd4c3 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 21:01:00 +0800 Subject: [PATCH 32/41] resolved issue that caused js-slang to ignore tests --- package.json | 4 +- .../scheme/__tests__/scheme-encode-decode.ts | 4 +- src/alt-langs/scheme/scheme_mapper.ts | 9 +- src/parser/__tests__/scheme.ts | 115 ------------------ 4 files changed, 12 insertions(+), 120 deletions(-) delete mode 100644 src/parser/__tests__/scheme.ts diff --git a/package.json b/package.json index e9d98193e..1fc8011fd 100644 --- a/package.json +++ b/package.json @@ -106,7 +106,7 @@ "testRegex": "/__tests__/.*\\.ts$", "testPathIgnorePatterns": [ "/dist/", - "/src/alt-langs/(?!__tests__).*/", + "/src/alt-langs/scheme/scm-slang", ".*benchmark.*", "/__tests__/(.*/)?utils\\.ts" ], @@ -115,7 +115,7 @@ "/node_modules/", "/src/typings/", "/src/utils/testing.ts", - "/src/alt-langs/(?!__tests__).*/", + "/src/alt-langs/scheme/scm-slang", "/src/py-slang/" ], "reporters": [ diff --git a/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts index 77d9bcde8..d7612051c 100644 --- a/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts +++ b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts @@ -4,7 +4,7 @@ import { UnassignedVariable } from '../../../errors/errors' import { decode, encode } from '../scm-slang/src' import { cons, set$45$cdr$33$ } from '../scm-slang/src/stdlib/base' import { dummyExpression } from '../../../utils/ast/dummyAstCreator' -import { decodeError, decodeValue } from '../../../parser/scheme' +import { mapErrorToScheme, decodeValue } from '../scheme_mapper' describe('Scheme encoder and decoder', () => { it('encoder and decoder are proper inverses of one another', () => { @@ -62,6 +62,6 @@ describe('Scheme encoder and decoder', () => { const token = `😀` const dummyNode: Node = dummyExpression() const error = new UnassignedVariable(encode(token), dummyNode) - expect(decodeError(error).elaborate()).toContain(`😀`) + expect(mapErrorToScheme(error).elaborate()).toContain(`😀`) }) }) diff --git a/src/alt-langs/scheme/scheme_mapper.ts b/src/alt-langs/scheme/scheme_mapper.ts index 2f32633c8..1f834dc86 100644 --- a/src/alt-langs/scheme/scheme_mapper.ts +++ b/src/alt-langs/scheme/scheme_mapper.ts @@ -98,7 +98,7 @@ function schemeVisualise(x: any): Representation { // only if an encoded value may exist in it. // this function is used to accurately display // values in the REPL. -function decodeValue(x: any): any { +export function decodeValue(x: any): any { // helper version of list_tail that assumes non-null return value function list_tail(xs: List, i: number): List { if (i === 0) { @@ -148,6 +148,13 @@ function decodeValue(x: any): any { x.node = newNode x.originalNode = newNode return x + } else if (typeof x === 'function') { + // copy x to avoid modifying the original object + const newX = { ...x } + const newString = decodeString(x.toString()) + // change the toString method to return the decoded string + newX.toString = () => newString + return newX } else { // string, number, boolean, null, undefined // no need to decode. diff --git a/src/parser/__tests__/scheme.ts b/src/parser/__tests__/scheme.ts deleted file mode 100644 index 54a362827..000000000 --- a/src/parser/__tests__/scheme.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { parseError } from '../..' -import { mockContext } from '../../mocks/context' -import { Chapter } from '../../types' -import { SchemeParser } from '../scheme' - -const parser = new SchemeParser(Chapter.SCHEME_1) -const parser_2 = new SchemeParser(Chapter.SCHEME_2) -const parser_3 = new SchemeParser(Chapter.SCHEME_3) -const parser_4 = new SchemeParser(Chapter.SCHEME_4) -const parser_full = new SchemeParser(Chapter.FULL_SCHEME) -let context = mockContext(Chapter.SCHEME_1) -let context_2 = mockContext(Chapter.SCHEME_2) -let context_3 = mockContext(Chapter.SCHEME_3) -let context_4 = mockContext(Chapter.SCHEME_4) -let context_full = mockContext(Chapter.FULL_SCHEME) - -beforeEach(() => { - // reset the contexts - context = mockContext(Chapter.SCHEME_1) - context_2 = mockContext(Chapter.SCHEME_2) - context_3 = mockContext(Chapter.SCHEME_3) - context_4 = mockContext(Chapter.SCHEME_4) - context_full = mockContext(Chapter.FULL_SCHEME) -}) - -describe('Scheme parser', () => { - it('represents itself correctly', () => { - expect(parser.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) - expect(parser_2.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 2}"`) - expect(parser_3.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 3}"`) - expect(parser_4.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 4}"`) - expect(parser_full.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: Infinity}"`) - }) - - it('throws error if given chapter is wrong', () => { - expect(() => new SchemeParser(Chapter.FULL_PYTHON)).toThrow( - 'SchemeParser was not given a valid chapter!' - ) - }) - - it('throws errors if option throwOnError is selected + parse error is encountered', () => { - const code = `(hello))` - expect(() => parser.parse(code, context, undefined, true)).toThrow("Unexpected ')'") - }) - - it('formats tokenizer errors correctly', () => { - const code = `(hello))` - - parser.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) - ) - }) - - it('formats parser errors correctly', () => { - const code = `(define (f x)` - - parser.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) - ) - }) - - it('allows usage of builtins/preludes', () => { - const code = ` - (+ 1 2 3) - (gcd 10 15) - ` - - parser.parse(code, context) - expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) - }) - - it('allows usage of imports/modules', () => { - const code = `(import "rune" (show heart)) - (show heart) - ` - - parser.parse(code, context) - expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) - }) - - it('disallows syntax for higher chapters', () => { - const code = `'(1 2 3)` - - parser.parse(code, context) - expect(context.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ - message: expect.stringContaining("Syntax ''' not allowed at Scheme §1") - }) - ) - }) - - it('disallows syntax for higher chapters (2)', () => { - const code = `#(1 2 3)` - - parser_2.parse(code, context_2) - expect(context_2.errors.slice(-1)[0]).toMatchObject( - expect.objectContaining({ - message: expect.stringContaining("Syntax '#' not allowed at Scheme §2") - }) - ) - }) - - it('allows syntax for lower chapters', () => { - const code = `'(1 2 3)` - - parser_full.parse(code, context_full) - expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) - parser_4.parse(code, context_4) - expect(parseError(context_4.errors)).toMatchInlineSnapshot(`""`) - parser_3.parse(code, context_3) - expect(parseError(context_3.errors)).toMatchInlineSnapshot(`""`) - }) -}) From d9954957c57410b9c555eaec5459506fd5c6aa97 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Mon, 8 Apr 2024 22:19:06 +0800 Subject: [PATCH 33/41] add tests for scheme mapper --- src/alt-langs/mapper.ts | 2 +- .../scheme/__tests__/scheme-encode-decode.ts | 2 +- .../scheme/__tests__/scheme-mapper.ts | 58 +++++++++++++++++++ .../{scheme_mapper.ts => scheme-mapper.ts} | 13 +++-- 4 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 src/alt-langs/scheme/__tests__/scheme-mapper.ts rename src/alt-langs/scheme/{scheme_mapper.ts => scheme-mapper.ts} (92%) diff --git a/src/alt-langs/mapper.ts b/src/alt-langs/mapper.ts index a6be74543..ffb2c5713 100644 --- a/src/alt-langs/mapper.ts +++ b/src/alt-langs/mapper.ts @@ -6,7 +6,7 @@ import { Context, Result } from ".." import { Chapter } from "../types" -import { mapErrorToScheme, mapResultToScheme } from "./scheme/scheme_mapper" +import { mapErrorToScheme, mapResultToScheme } from "./scheme/scheme-mapper" /** * A representation of a value in a language. diff --git a/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts index d7612051c..2b8193622 100644 --- a/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts +++ b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts @@ -4,7 +4,7 @@ import { UnassignedVariable } from '../../../errors/errors' import { decode, encode } from '../scm-slang/src' import { cons, set$45$cdr$33$ } from '../scm-slang/src/stdlib/base' import { dummyExpression } from '../../../utils/ast/dummyAstCreator' -import { mapErrorToScheme, decodeValue } from '../scheme_mapper' +import { mapErrorToScheme, decodeValue } from '../scheme-mapper' describe('Scheme encoder and decoder', () => { it('encoder and decoder are proper inverses of one another', () => { diff --git a/src/alt-langs/scheme/__tests__/scheme-mapper.ts b/src/alt-langs/scheme/__tests__/scheme-mapper.ts new file mode 100644 index 000000000..75c520b68 --- /dev/null +++ b/src/alt-langs/scheme/__tests__/scheme-mapper.ts @@ -0,0 +1,58 @@ +import { schemeVisualise } from "../scheme-mapper" +import { make_number } from "../scm-slang/src/stdlib/core-math" +import { circular$45$list, cons, cons$42$, list } from "../scm-slang/src/stdlib/base" + +test("schemeVisualise: should visualise null properly", () => { + expect(schemeVisualise(null).toString()).toEqual("()") +}) + +test("schemeVisualise: should visualise undefined properly", () => { + expect(schemeVisualise(undefined).toString()).toEqual("undefined") +}) + +test("schemeVisualise: should visualise strings properly", () => { + expect(schemeVisualise("hello").toString()).toEqual("\"hello\"") +}) + +test("schemeVisualise: should visualise scheme numbers properly", () => { + expect(schemeVisualise(make_number("1i")).toString()).toEqual("0+1i") +}) + +test("schemeVisualise: should visualise booleans properly", () => { + expect(schemeVisualise(true).toString()).toEqual("#t") + expect(schemeVisualise(false).toString()).toEqual("#f") +}) + +test("schemeVisualise: should visualise circular lists properly", () => { + const circularList = circular$45$list(1, 2, 3) + //expect(schemeVisualise(circularList).toString()).toEqual("#0=(1 2 3 . #0#)") + //for now, this will do + expect(schemeVisualise(circularList).toString()).toEqual("(circular list)") +}) + +test("schemeVisualise: should visualise dotted lists properly", () => { + const dottedList = cons$42$(1, 2, 3) + expect(schemeVisualise(dottedList).toString()).toEqual("(1 2 . 3)") +}) + +test("schemeVisualise: should visualise proper lists properly", () => { + const properList = list(1, 2, 3, 4) + expect(schemeVisualise(properList).toString()).toEqual("(1 2 3 4)") +}) + +test("schemeVisualise: should visualise vectors properly", () => { + const vector = [1, 2, 3, 4] + expect(schemeVisualise(vector).toString()).toEqual("#(1 2 3 4)") +}) + +test("schemeVisualise: should visualise pairs properly", () => { + const pair = cons(1, 2) + expect(schemeVisualise(pair).toString()).toEqual("(1 . 2)") +}) + +test("schemeVisualise: vectors and pairs should be distinct", () => { + const maybe_pair = [1, 2] + expect(schemeVisualise(maybe_pair).toString()).toEqual("#(1 2)") +}) + +export { schemeVisualise } diff --git a/src/alt-langs/scheme/scheme_mapper.ts b/src/alt-langs/scheme/scheme-mapper.ts similarity index 92% rename from src/alt-langs/scheme/scheme_mapper.ts rename to src/alt-langs/scheme/scheme-mapper.ts index 1f834dc86..466d1c23a 100644 --- a/src/alt-langs/scheme/scheme_mapper.ts +++ b/src/alt-langs/scheme/scheme-mapper.ts @@ -33,7 +33,7 @@ export function mapErrorToScheme(error: SourceError): SourceError { } } -function showSchemeData(data: any): Representation { +export function showSchemeData(data: any): Representation { return schemeVisualise(decodeValue(data)) } @@ -45,7 +45,7 @@ function decodeString(str: string): string { // Given any value, change the representation of it to // the required scheme representation. -function schemeVisualise(x: any): Representation { +export function schemeVisualise(x: any): Representation { function stringify(x: any): string { if (null$63$(x)) { return '()' @@ -59,11 +59,16 @@ function schemeVisualise(x: any): Representation { return x ? '#t' : '#f' } else if (x instanceof Closure) { const node = x.originalNode - const parameters = node.params.map((param: Identifier | RestElement) => param.type === "Identifier" ? param.name : ". " + (param.argument as Identifier).name).join(' ').trim() + const parameters = node.params.map( + (param: Identifier | RestElement) => param.type === "Identifier" + ? param.name + : ". " + (param.argument as Identifier).name) + .join(' ') + .trim() return `#` } else if (circular$45$list$63$(x)) { return '(circular list)' - } else if (pair$63$(x) && dotted$45$list$63$(x)) { + } else if (dotted$45$list$63$(x) && pair$63$(x)) { let string = '(' let current = x while (pair$63$(current)) { From 666a1a2eb4320d85e05baff9cba6757a08455c0c Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 09:06:11 +0800 Subject: [PATCH 34/41] Merge remote-tracking branch 'source/master' into master --- package.json | 2 +- src/alt-langs/scheme/scm-slang | 2 +- .../__snapshots__/cse-machine-heap.ts.snap | 6366 ++++++++++++++++- src/cse-machine/__tests__/cse-machine-heap.ts | 71 +- .../__tests__/cse-machine-unique-id.ts | 84 +- src/cse-machine/closure.ts | 152 + src/cse-machine/heap.ts | 16 +- src/cse-machine/interpreter.ts | 44 +- src/cse-machine/stack.ts | 58 + src/cse-machine/types.ts | 6 +- src/cse-machine/utils.ts | 132 +- src/mocks/context.ts | 15 +- src/py-slang | 2 +- .../__tests__/__snapshots__/stepper.ts.snap | 1456 +++- src/stepper/__tests__/stepper.ts | 458 ++ 15 files changed, 8596 insertions(+), 268 deletions(-) create mode 100644 src/cse-machine/closure.ts create mode 100644 src/cse-machine/stack.ts diff --git a/package.json b/package.json index 1fc8011fd..febaa405d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "js-slang", - "version": "1.0.62", + "version": "1.0.63", "license": "Apache-2.0", "description": "Javascript-based implementations of Source, written in Typescript", "keywords": [ diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index d86b7b67c..c7da3a028 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit d86b7b67c9472263c8159b12515b836e969745d3 +Subproject commit c7da3a028ae943df3df85736f19e37e3851313c5 diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap index ae1901f12..d571e7912 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Arrays and closures are correctly added to their respective environment heaps 1`] = ` +exports[`Arrays and closures are correctly added to their respective heaps 1`] = ` EnvTree { "_root": EnvTreeNode { "_children": Array [ @@ -3183,7 +3183,7 @@ EnvTree { } `; -exports[`Arrays created from in-built functions are correctly added to the environment heap 1`] = ` +exports[`Arrays created from built-in functions are correctly added to their respective heaps 1`] = ` EnvTree { "_root": EnvTreeNode { "_children": Array [ @@ -4427,7 +4427,7 @@ EnvTree { } `; -exports[`Pre-defined functions are correctly added to prelude environment heap 1`] = ` +exports[`Pre-defined functions are correctly added to prelude heap 1`] = ` EnvTree { "_root": EnvTreeNode { "_children": Array [ @@ -5570,3 +5570,6363 @@ EnvTree { }, } `; + +exports[`Variadic closures correctly add argument array to the function environment heap 1`] = ` +EnvTree { + "_root": EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 1, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 2, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 3, + }, + ], + "callee": Node { + "end": 24, + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "name": "f", + "start": 23, + "type": "Identifier", + }, + "end": 33, + "loc": SourceLocation { + "end": Position { + "column": 10, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "start": 23, + "type": "CallExpression", + }, + "head": Object { + "x": Array [ + 1, + 2, + 3, + ], + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + 2, + 3, + ], + }, + }, + "id": "2", + "name": "f", + "tail": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + "map": Map { + Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + } => EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 1, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 2, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 3, + }, + ], + "callee": Node { + "end": 24, + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "name": "f", + "start": 23, + "type": "Identifier", + }, + "end": 33, + "loc": SourceLocation { + "end": Position { + "column": 10, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "start": 23, + "type": "CallExpression", + }, + "head": Object { + "x": Array [ + 1, + 2, + 3, + ], + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + 2, + 3, + ], + }, + }, + "id": "2", + "name": "f", + "tail": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + } => EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 1, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 2, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 3, + }, + ], + "callee": Node { + "end": 24, + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "name": "f", + "start": 23, + "type": "Identifier", + }, + "end": 33, + "loc": SourceLocation { + "end": Position { + "column": 10, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "start": 23, + "type": "CallExpression", + }, + "head": Object { + "x": Array [ + 1, + 2, + 3, + ], + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + 2, + 3, + ], + }, + }, + "id": "2", + "name": "f", + "tail": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + }, + Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 1, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 2, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 3, + }, + ], + "callee": Node { + "end": 24, + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "name": "f", + "start": 23, + "type": "Identifier", + }, + "end": 33, + "loc": SourceLocation { + "end": Position { + "column": 10, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "start": 23, + "type": "CallExpression", + }, + "head": Object { + "x": Array [ + 1, + 2, + 3, + ], + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + 2, + 3, + ], + }, + }, + "id": "2", + "name": "f", + "tail": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + } => EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 1, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 2, + }, + Object { + "loc": undefined, + "type": "Literal", + "value": 3, + }, + ], + "callee": Node { + "end": 24, + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "name": "f", + "start": 23, + "type": "Identifier", + }, + "end": 33, + "loc": SourceLocation { + "end": Position { + "column": 10, + "line": 2, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "start": 23, + "type": "CallExpression", + }, + "head": Object { + "x": Array [ + 1, + 2, + 3, + ], + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + 2, + 3, + ], + }, + }, + "id": "2", + "name": "f", + "tail": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + }, + }, + "id": "0", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + }, + }, + }, +} +`; + +exports[`apply_in_underlying_javascript works correctly and adds objects to heaps 1`] = ` +EnvTree { + "_root": EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + "map": Map { + Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + } => EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + } => EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + }, + Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + } => EnvTreeNode { + "_children": Array [ + EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + }, + "parent": [Circular], + }, + ], + "environment": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + }, + }, + Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + } => EnvTreeNode { + "_children": Array [], + "environment": Object { + "callExpression": Object { + "arguments": Array [ + Object { + "loc": undefined, + "type": "Literal", + "value": 0, + }, + ], + "callee": Object { + "loc": SourceLocation { + "end": Position { + "column": 1, + "line": 5, + }, + "start": Position { + "column": 0, + "line": 2, + }, + }, + "type": "Literal", + "value": [Function], + }, + "loc": undefined, + "optional": false, + "type": "CallExpression", + }, + "head": Object { + "x": 0, + }, + "heap": Heap { + "storage": Set { + Array [ + 1, + ], + [Function], + }, + }, + "id": "50", + "name": "f", + "tail": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "a": Array [ + 1, + ], + "f": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + Array [ + 0, + null, + ], + }, + }, + "id": "47", + "name": "programEnvironment", + "tail": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "$accumulate": [Function], + "$append": [Function], + "$build_list": [Function], + "$enum_list": [Function], + "$filter": [Function], + "$length": [Function], + "$list_to_string": [Function], + "$map": [Function], + "$remove": [Function], + "$remove_all": [Function], + "$reverse": [Function], + "__access_export__": [Function], + "__access_named_export__": [Function], + "accumulate": [Function], + "append": [Function], + "build_list": [Function], + "build_stream": [Function], + "enum_list": [Function], + "enum_stream": [Function], + "equal": [Function], + "eval_stream": [Function], + "filter": [Function], + "for_each": [Function], + "integers_from": [Function], + "is_stream": [Function], + "length": [Function], + "list_ref": [Function], + "list_to_stream": [Function], + "list_to_string": [Function], + "map": [Function], + "member": [Function], + "remove": [Function], + "remove_all": [Function], + "reverse": [Function], + "stream_append": [Function], + "stream_filter": [Function], + "stream_for_each": [Function], + "stream_length": [Function], + "stream_map": [Function], + "stream_member": [Function], + "stream_ref": [Function], + "stream_remove": [Function], + "stream_remove_all": [Function], + "stream_reverse": [Function], + "stream_tail": [Function], + "stream_to_list": [Function], + }, + "heap": Heap { + "storage": Set { + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + [Function], + }, + }, + "id": "0", + "name": "prelude", + "tail": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + }, + "parent": EnvTreeNode { + "_children": Array [ + [Circular], + ], + "environment": Object { + "head": Object { + "Infinity": Infinity, + "NaN": NaN, + "apply_in_underlying_javascript": [Function], + "arity": [Function], + "array_length": [Function], + "call_cc": [Function], + "char_at": [Function], + "display": [Function], + "display_list": [Function], + "draw_data": [Function], + "error": [Function], + "get_time": [Function], + "head": [Function], + "is_array": [Function], + "is_boolean": [Function], + "is_function": [Function], + "is_list": [Function], + "is_null": [Function], + "is_number": [Function], + "is_pair": [Function], + "is_string": [Function], + "is_undefined": [Function], + "list": [Function], + "math_E": 2.718281828459045, + "math_LN10": 2.302585092994046, + "math_LN2": 0.6931471805599453, + "math_LOG10E": 0.4342944819032518, + "math_LOG2E": 1.4426950408889634, + "math_PI": 3.141592653589793, + "math_SQRT1_2": 0.7071067811865476, + "math_SQRT2": 1.4142135623730951, + "math_abs": [Function], + "math_acos": [Function], + "math_acosh": [Function], + "math_asin": [Function], + "math_asinh": [Function], + "math_atan": [Function], + "math_atan2": [Function], + "math_atanh": [Function], + "math_cbrt": [Function], + "math_ceil": [Function], + "math_clz32": [Function], + "math_cos": [Function], + "math_cosh": [Function], + "math_exp": [Function], + "math_expm1": [Function], + "math_floor": [Function], + "math_fround": [Function], + "math_hypot": [Function], + "math_imul": [Function], + "math_log": [Function], + "math_log10": [Function], + "math_log1p": [Function], + "math_log2": [Function], + "math_max": [Function], + "math_min": [Function], + "math_pow": [Function], + "math_random": [Function], + "math_round": [Function], + "math_sign": [Function], + "math_sin": [Function], + "math_sinh": [Function], + "math_sqrt": [Function], + "math_tan": [Function], + "math_tanh": [Function], + "math_trunc": [Function], + "pair": [Function], + "parse": [Function], + "parse_int": [Function], + "prompt": [Function], + "raw_display": [Function], + "set_head": [Function], + "set_tail": [Function], + "stream": [Function], + "stringify": [Function], + "tail": [Function], + "tokenize": [Function], + "undefined": undefined, + }, + "heap": Heap { + "storage": null, + }, + "id": "-1", + "name": "global", + "tail": null, + }, + "parent": null, + }, + }, + }, + }, + }, +} +`; diff --git a/src/cse-machine/__tests__/cse-machine-heap.ts b/src/cse-machine/__tests__/cse-machine-heap.ts index 590b9f8a4..ba5ac8b9c 100644 --- a/src/cse-machine/__tests__/cse-machine-heap.ts +++ b/src/cse-machine/__tests__/cse-machine-heap.ts @@ -4,37 +4,45 @@ import { Chapter } from '../../types' import { stripIndent } from '../../utils/formatters' import { sourceRunner } from '../../runner' import Heap from '../heap' -import { Array } from '../types' +import { EnvArray } from '../types' test('Heap works correctly', () => { - const heap = new Heap() - expect(heap.size()).toMatchInlineSnapshot(`0`) - expect(heap.getHeap()).toMatchInlineSnapshot(`Set {}`) + const heap1 = new Heap() + expect(heap1.size()).toMatchInlineSnapshot(`0`) + expect(heap1.getHeap()).toMatchInlineSnapshot(`Set {}`) - const arr = [0] as Array - heap.add(arr) - expect(heap.contains([0] as Array)).toMatchInlineSnapshot(`false`) - expect(heap.contains(arr)).toMatchInlineSnapshot(`true`) - heap.add(arr) - expect(heap.size()).toMatchInlineSnapshot(`1`) - expect(heap.getHeap()).toMatchInlineSnapshot(` + const arr = [0] as EnvArray + const closure = mockClosure(true) + heap1.add(arr, closure) + heap1.add(arr) + expect(heap1.contains([0] as EnvArray)).toMatchInlineSnapshot(`false`) + expect(heap1.contains(arr)).toMatchInlineSnapshot(`true`) + expect(heap1.contains(closure)).toMatchInlineSnapshot(`true`) + expect(heap1.size()).toMatchInlineSnapshot(`2`) + expect(heap1.getHeap()).toMatchInlineSnapshot(` Set { Array [ 0, ], + [Function], } `) - const closure = mockClosure() - heap.add(closure) - expect(heap.contains(closure)).toMatchInlineSnapshot(`true`) - expect(heap.size()).toMatchInlineSnapshot(`2`) - expect(heap.getHeap()).toMatchInlineSnapshot(` + const heap2 = new Heap() + expect(heap1.move(mockClosure(true), heap2)).toMatchInlineSnapshot(`false`) + expect(heap1.move(arr, heap2)).toMatchInlineSnapshot(`true`) + expect(heap1.contains(arr)).toMatchInlineSnapshot(`false`) + expect(heap1.getHeap()).toMatchInlineSnapshot(` + Set { + [Function], + } + `) + expect(heap2.contains(arr)).toMatchInlineSnapshot(`true`) + expect(heap2.getHeap()).toMatchInlineSnapshot(` Set { Array [ 0, ], - [Function], } `) }) @@ -50,11 +58,11 @@ const expectEnvTreeFrom = (code: string, hasPrelude = true) => { ).resolves } -test('Pre-defined functions are correctly added to prelude environment heap', () => { +test('Pre-defined functions are correctly added to prelude heap', () => { expectEnvTreeFrom('0;').toMatchSnapshot() }) -test('Arrays and closures are correctly added to their respective environment heaps', () => { +test('Arrays and closures are correctly added to their respective heaps', () => { expectEnvTreeFrom( stripIndent` function f(x) { @@ -70,7 +78,7 @@ test('Arrays and closures are correctly added to their respective environment he ).toMatchSnapshot() }) -test('Arrays created from in-built functions are correctly added to the environment heap', () => { +test('Arrays created from built-in functions are correctly added to their respective heaps', () => { expectEnvTreeFrom( stripIndent` pair(1, 2); @@ -80,3 +88,26 @@ test('Arrays created from in-built functions are correctly added to the environm ` ).toMatchSnapshot() }) + +test('Variadic closures correctly add argument array to the function environment heap', () => { + expectEnvTreeFrom( + stripIndent` + const f = (...x) => x; + f(1, 2, 3); + `, + false + ).toMatchSnapshot() +}) + +test('apply_in_underlying_javascript works correctly and adds objects to heaps', () => { + expectEnvTreeFrom( + stripIndent` + let a = 0; + function f(x) { + a = [1]; + return x => x; + } + apply_in_underlying_javascript(f, list(0)); + ` + ).toMatchSnapshot() +}) diff --git a/src/cse-machine/__tests__/cse-machine-unique-id.ts b/src/cse-machine/__tests__/cse-machine-unique-id.ts index 6c181ffb0..30ddc2023 100644 --- a/src/cse-machine/__tests__/cse-machine-unique-id.ts +++ b/src/cse-machine/__tests__/cse-machine-unique-id.ts @@ -5,26 +5,40 @@ import { stripIndent } from '../../utils/formatters' import { sourceRunner } from '../../runner' import { createProgramEnvironment } from '../utils' -const getContextFrom = async (code: string) => { +const getContextFrom = async (code: string, envSteps?: number) => { const context = mockContext(Chapter.SOURCE_4) const parsed = parse(code, context) - await sourceRunner(parsed!, context, false, { executionMethod: 'cse-machine' }) + await sourceRunner(parsed!, context, false, { envSteps, executionMethod: 'cse-machine' }) return context } -test("Context runtime's objectCount continues after prelude", async () => { +test("Program environment's id continues after prelude", async () => { const context = await getContextFrom('const a = list(1, 2, 3);') - // 1 prelude environment + 45 prelude closures in Source 4, - // so program environment has id of '46' + // 1 prelude environment + 46 prelude closures in Source 4, + // so program environment has id of '47' expect(context.runtime.environments[0].id).toMatchInlineSnapshot(`"47"`) }) test("Context runtime's objectCount continues after prelude", async () => { const context = await getContextFrom('const a = list(1, 2, 3);') - // 1 program environment + 3 arrays from the list function, so final objectCount is 50 + // 1 program environment + 3 arrays from the list function, so final objectCount is 51 expect(context.runtime.objectCount).toMatchInlineSnapshot(`51`) }) +test("Context runtime's objectCount continues after apply_in_underlying_javascript call", async () => { + const context = await getContextFrom( + stripIndent` + function f(...x) { + return [x]; + } + apply_in_underlying_javascript(f, list(1, 2, 3)); + ` + ) + // 1 program environment + 1 closure + 1 function environment + // 3 arrays from list + 1 array from variadic argument + 1 array from from function result + expect(context.runtime.objectCount).toMatchInlineSnapshot(`55`) +}) + test('Every environment/array/closure has a unique id', async () => { const context = await getContextFrom( stripIndent` @@ -43,62 +57,56 @@ test('Every environment/array/closure has a unique id', async () => { expect(context.runtime.environmentTree).toMatchSnapshot() // Environments: 1 prelude + 1 program + 1 function (c) + 1 block, total: 4 // Arrays: 4 arrays created manually + 4 arrays from in-built functions (pair, list), total: 8 - // Closures: 45 prelude closures + 1 closure in program (c) + 1 closure in block, total 47 - // Total count: 4 + 8 + 47 = 59 + // Closures: 46 prelude closures + 1 closure in program (c) + 1 closure in block, total 48 + // Total count: 4 + 8 + 48 = 60 expect(context.runtime.objectCount).toMatchInlineSnapshot(`60`) }) test('CSE Machine stops at the given step number', async () => { - const parsed = parse( + const context = await getContextFrom( stripIndent` let x = 0; for (let i = 0; i < 10; i = i + 1) { x = [x]; } `, - mockContext(Chapter.SOURCE_4) + 100 ) - // The above program has a total of 335 steps - // Start from steps = 1 so that the program environment always exists - for (let steps = 1; steps < 336; steps++) { - const context = mockContext(Chapter.SOURCE_4) - await sourceRunner(parsed!, context, false, { envSteps: steps, executionMethod: 'cse-machine' }) - // A simple check to ensure that the the CSE Machine does indeed stop at the given step number - if (steps === 100) { - // 7 additional environments + 2 arrays created, so object count is 47 + 7 + 2 = 56 - expect(context.runtime.objectCount).toMatchInlineSnapshot(`57`) - } - } + // 7 additional environments + 2 arrays created at step 100, so object count is 48 + 7 + 2 = 57 + expect(context.runtime.objectCount).toMatchInlineSnapshot(`57`) }) -const mockProgramEnv = createProgramEnvironment(mockContext(), false) +const programEnvName = createProgramEnvironment(mockContext(), false).name const getProgramEnv = (context: Context) => { let env: Environment | null = context.runtime.environments[0] - while (env && env.name !== mockProgramEnv.name) { + while (env && env.name !== programEnvName) { env = env.tail } return env } -const parsed = parse( - stripIndent` - let x = 0; - for (let i = 0; i < 10; i = i + 1) { - x = [x]; - } - `, - mockContext(Chapter.SOURCE_4) -) -// The above program has a total of 335 steps -// Start from steps = 1 so that the program environment always exists test('Program environment id stays the same regardless of amount of steps', async () => { - let same = true + const parsed = parse( + stripIndent` + let x = 0; + for (let i = 0; i < 10; i = i + 1) { + x = [x]; + } + `, + mockContext(Chapter.SOURCE_4) + ) + let programEnvId = '47' + // The above program has a total of 335 steps + // Start from steps = 1 so that the program environment always exists for (let steps = 1; steps < 336; steps++) { const context = mockContext(Chapter.SOURCE_4) await sourceRunner(parsed!, context, false, { envSteps: steps, executionMethod: 'cse-machine' }) - const programEnv = getProgramEnv(context) - same &&= programEnv!.id === `"46"` + const programEnv = getProgramEnv(context)! + if (programEnv.id !== programEnvId) { + programEnvId = programEnv.id + break + } } - expect(same).toMatchInlineSnapshot(`false`) + expect(programEnvId).toMatchInlineSnapshot(`"47"`) }) diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts new file mode 100644 index 000000000..42084e07a --- /dev/null +++ b/src/cse-machine/closure.ts @@ -0,0 +1,152 @@ +import { generate } from 'astring' +import * as es from 'estree' + +import { + currentEnvironment, + hasReturnStatement, + isBlockStatement, + isStatementSequence, + uniqueId +} from '../cse-machine/utils' +import { Context, Environment, StatementSequence, Value } from '../types' +import * as ast from '../utils/ast/astCreator' +import { Control, Stash, generateCSEMachineStateStream } from './interpreter' +import { envInstr } from './instrCreator' + +const closureToJS = (value: Closure, context: Context) => { + function DummyClass(this: Closure) { + const args: Value[] = [...arguments] + const node = ast.callExpression( + ast.literal(value as any, value.node.loc), + args.map(arg => ast.primitive(arg)) + ) + // Create a new CSE Machine with the same context as the current one, but with + // the control reset to only contain the call expression, and the stash emptied. + const newContext = { ...context, runtime: { ...context.runtime, debuggerOn: false } } + newContext.runtime.control = new Control() + // Also need the env instruction to return back to the current environment at the end. + // The call expression won't create one as there is only one item in the control. + newContext.runtime.control.push(envInstr(currentEnvironment(context), node), node) + newContext.runtime.stash = new Stash() + const gen = generateCSEMachineStateStream( + newContext, + newContext.runtime.control, + newContext.runtime.stash, + -1, + -1 + ) + // Run the new CSE Machine fully to obtain the result in the stash + for (const _ of gen) { + } + // Also don't forget to update object count in original context + context.runtime.objectCount = newContext.runtime.objectCount + return newContext.runtime.stash.peek() + } + Object.defineProperty(DummyClass, 'name', { + value: value.functionName + }) + Object.setPrototypeOf(DummyClass, () => undefined) + Object.defineProperty(DummyClass, 'Inherits', { + value: (Parent: Value) => { + DummyClass.prototype = Object.create(Parent.prototype) + DummyClass.prototype.constructor = DummyClass + } + }) + DummyClass.toString = () => generate(value.originalNode) + DummyClass.call = (thisArg: Value, ...args: Value[]): any => { + return DummyClass.apply(thisArg, args) + } + return DummyClass +} + +class Callable extends Function { + constructor(f: any) { + super() + return Object.setPrototypeOf(f, new.target.prototype) + } +} + +/** + * Models function value in the CSE machine. + */ +export default class Closure extends Callable { + public static makeFromArrowFunction( + node: es.ArrowFunctionExpression, + environment: Environment, + context: Context, + dummyReturn?: boolean, + predefined?: boolean + ) { + const functionBody: es.BlockStatement | StatementSequence = + !isBlockStatement(node.body) && !isStatementSequence(node.body) + ? ast.blockStatement([ast.returnStatement(node.body, node.body.loc)], node.body.loc) + : dummyReturn && !hasReturnStatement(node.body) + ? ast.blockStatement( + [ + ...node.body.body, + ast.returnStatement(ast.identifier('undefined', node.body.loc), node.body.loc) + ], + node.body.loc + ) + : node.body + + const closure = new Closure( + ast.blockArrowFunction(node.params as es.Identifier[], functionBody, node.loc), + environment, + context, + predefined + ) + + // Set the closure's node to point back at the original one + closure.originalNode = node + + return closure + } + + /** Unique ID defined for closure */ + public readonly id: string + + /** Name of the constant declaration that the closure is assigned to */ + public declaredName?: string + + /** String representation of the closure, e.g. `x => ...` */ + public functionName: string + + /** Fake closure function */ + public fun: Function + + /** Keeps track of whether the closure is a pre-defined function */ + public predefined: boolean + + /** The original node that created this Closure */ + public originalNode: es.Function + + constructor( + public node: es.ArrowFunctionExpression, + public environment: Environment, + context: Context, + isPredefined?: boolean + ) { + super(function (this: any, ...args: any[]) { + return funJS.apply(this, args) + }) + this.originalNode = node + this.id = uniqueId(context) + currentEnvironment(context).heap.add(this) + const params = this.node.params.map((o: es.Identifier | es.RestElement) => + o.type === 'RestElement' ? '...' + (o.argument as es.Identifier).name : o.name + ) + this.functionName = params.join(', ') + if (params.length !== 1 || params[0].startsWith('...')) { + this.functionName = '(' + this.functionName + ')' + } + this.functionName += ' => ...' + const funJS = closureToJS(this, context) + this.fun = funJS + this.predefined = isPredefined ?? false + } + + public toString(): string { + return generate(this.originalNode) + } +} diff --git a/src/cse-machine/heap.ts b/src/cse-machine/heap.ts index f74e3cbaa..09b4887ec 100644 --- a/src/cse-machine/heap.ts +++ b/src/cse-machine/heap.ts @@ -15,16 +15,30 @@ export default class Heap { } } + /** Checks the existence of `item` in the heap. */ contains(item: any): boolean { return this.storage?.has(item) ?? false } + /** Gets the number of items in the heap. */ size(): number { return this.storage?.size ?? 0 } + /** + * Removes `item` from current heap and adds it to `otherHeap`. + * If the current heap does not contain `item`, nothing happens. + * @returns whether the item transfer is successful + */ + move(item: HeapObject, otherHeap: Heap): boolean { + if (!this.contains(item)) return false + this.storage!.delete(item) + otherHeap.add(item) + return true + } + + /** Returns a copy of the heap's contents. */ getHeap(): Set { - // return a copy of the heap's contents return new Set(this.storage) } } diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 2cb8ea637..a7f3f6a7f 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -7,13 +7,12 @@ /* tslint:disable:max-classes-per-file */ import * as es from 'estree' -import { isArray, reverse } from 'lodash' +import { isArray, isFunction, reverse } from 'lodash' import { IOptions } from '..' import { UNKNOWN_LOCATION } from '../constants' import * as errors from '../errors/errors' import { RuntimeSourceError } from '../errors/runtimeSourceError' -import Closure from '../interpreter/closure' import { checkEditorBreakpoints } from '../stdlib/inspector' import { Context, ContiguousArrayElements, Result, type StatementSequence, Value } from '../types' import * as ast from '../utils/ast/astCreator' @@ -33,6 +32,7 @@ import { makeDummyContCallExpression } from './continuations' import * as instr from './instrCreator' +import { Stack } from './stack' import { AppInstr, ArrLitInstr, @@ -71,6 +71,7 @@ import { hasDeclarations, hasImportDeclarations, isBlockStatement, + isEnvArray, isInstr, isNode, isSimpleFunction, @@ -78,9 +79,9 @@ import { pushEnvironment, reduceConditional, setVariable, - Stack, valueProducing } from './utils' +import Closure from './closure' type CmdEvaluator = ( command: ControlItem, @@ -735,7 +736,6 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { stash: Stash, isPrelude: boolean ) { - // Reuses the Closure data structure from legacy interpreter const closure: Closure = Closure.makeFromArrowFunction( command, currentEnvironment(context), @@ -743,7 +743,6 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { true, isPrelude ) - currentEnvironment(context).heap.add(closure) stash.push(closure) }, @@ -947,11 +946,6 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { // Check for number of arguments mismatch error checkNumberOfArguments(context, func, args, command.srcNode) - // Display the pre-defined functions on the global environment if needed. - if (func.preDefined) { - context.runtime.environments[1].heap.add(func) - } - const next = control.peek() // Push ENVIRONMENT instruction if needed - if next control stack item @@ -986,17 +980,37 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { return } - // Value is a function + // Value is a built-in function // Check for number of arguments mismatch error checkNumberOfArguments(context, func, args, command.srcNode) // Directly stash result of applying pre-built functions without the CSE machine. try { const result = func(...args) - // Attach array properties and add to heap for any arrays created from built-in functions, - // examples: pair, list - if (isArray(result)) { - handleArrayCreation(context, result) + + // Recursively adds `environment` and `id` properties to any arrays created, + // and also adds them to the heap starting from the arrays that are more deeply nested. + const attachEnvToResult = (value: any) => { + // Built-in functions don't instantly create arrays with circular references, so + // there is no need to keep track of visited arrays. + if (isArray(value) && !isEnvArray(value)) { + for (const item of value) { + attachEnvToResult(item) + } + handleArrayCreation(context, value) + } else if (isFunction(value) && !{}.hasOwnProperty.call(value, 'environment')) { + // This is a special case for the `stream` built-in function, since it returns pairs + // whose last element is a function. The CSE machine on the frontend will still draw + // these functions like closures, and the tail of the "closures" will need to point + // to where `stream` was called. + // + // TODO: remove this condition if `stream` becomes a pre-defined function + Object.defineProperties(value, { + environment: { value: currentEnvironment(context), writable: true } + }) + } } + attachEnvToResult(result) + stash.push(result) } catch (error) { if (!(error instanceof RuntimeSourceError || error instanceof errors.ExceptionError)) { diff --git a/src/cse-machine/stack.ts b/src/cse-machine/stack.ts new file mode 100644 index 000000000..00dacce31 --- /dev/null +++ b/src/cse-machine/stack.ts @@ -0,0 +1,58 @@ +/** + * Stack is implemented for control and stash registers. + */ +interface IStack { + push(...items: T[]): void + pop(): T | undefined + peek(): T | undefined + size(): number + isEmpty(): boolean + getStack(): T[] +} + +export class Stack implements IStack { + // Bottom of the array is at index 0 + private storage: T[] = [] + + public constructor() {} + + public push(...items: T[]): void { + for (const item of items) { + this.storage.push(item) + } + } + + public pop(): T | undefined { + return this.storage.pop() + } + + public peek(): T | undefined { + if (this.isEmpty()) { + return undefined + } + return this.storage[this.size() - 1] + } + + public size(): number { + return this.storage.length + } + + public isEmpty(): boolean { + return this.size() == 0 + } + + public getStack(): T[] { + // return a copy of the stack's contents + return [...this.storage] + } + + public some(predicate: (value: T) => boolean): boolean { + return this.storage.some(predicate) + } + + // required for first-class continuations, + // which directly mutate this stack globally. + public setTo(otherStack: Stack): void { + this.storage = otherStack.storage + } +} diff --git a/src/cse-machine/types.ts b/src/cse-machine/types.ts index 89b2a09a1..e613cdd26 100644 --- a/src/cse-machine/types.ts +++ b/src/cse-machine/types.ts @@ -1,7 +1,7 @@ import * as es from 'estree' -import Closure from '../interpreter/closure' import { Environment, Node } from '../types' +import Closure from './closure' export enum InstrType { RESET = 'Reset', @@ -96,13 +96,13 @@ export type Instr = export type ControlItem = Node | Instr // Every array also has the properties `id` and `environment` for use in the frontend CSE Machine -export type Array = any[] & { +export type EnvArray = any[] & { readonly id: string environment: Environment } // Objects in the heap can only store arrays or closures -export type HeapObject = Array | Closure +export type HeapObject = EnvArray | Closure // Special class that cannot be found on the stash so is safe to be used // as an indicator of a breakpoint from running the CSE machine diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 88d811482..0792d3197 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -4,73 +4,14 @@ import { isArray } from 'lodash' import { Context } from '..' import * as errors from '../errors/errors' import { RuntimeSourceError } from '../errors/runtimeSourceError' -import Closure from '../interpreter/closure' import type { Environment, Node, StatementSequence, Value } from '../types' import * as ast from '../utils/ast/astCreator' import { isContinuation } from './continuations' import Heap from './heap' import * as instr from './instrCreator' import { Control } from './interpreter' -import { AppInstr, Array, ControlItem, Instr, InstrType } from './types' - -/** - * Stack is implemented for control and stash registers. - */ -interface IStack { - push(...items: T[]): void - pop(): T | undefined - peek(): T | undefined - size(): number - isEmpty(): boolean - getStack(): T[] -} - -export class Stack implements IStack { - // Bottom of the array is at index 0 - private storage: T[] = [] - - public constructor() {} - - public push(...items: T[]): void { - for (const item of items) { - this.storage.push(item) - } - } - - public pop(): T | undefined { - return this.storage.pop() - } - - public peek(): T | undefined { - if (this.isEmpty()) { - return undefined - } - return this.storage[this.size() - 1] - } - - public size(): number { - return this.storage.length - } - - public isEmpty(): boolean { - return this.size() == 0 - } - - public getStack(): T[] { - // return a copy of the stack's contents - return [...this.storage] - } - - public some(predicate: (value: T) => boolean): boolean { - return this.storage.some(predicate) - } - - // required for first-class continuations, - // which directly mutate this stack globally. - public setTo(otherStack: Stack): void { - this.storage = otherStack.storage - } -} +import { AppInstr, EnvArray, ControlItem, Instr, InstrType } from './types' +import Closure from './closure' /** * Typeguard for Instr to distinguish between program statements and instructions. @@ -162,47 +103,36 @@ export const uniqueId = (context: Context): string => { return `${context.runtime.objectCount++}` } -/** - * Helper function for `handleArrayCreation`, with an extra argument: `visited`. - * - * @param context the context used to provide the current environment and new unique id - * @param array the array to add the properties to, and to add to the current environment heap to - * @param visited a set of arrays which are already handled before, - * used to keep track of circular references - */ -const arrayCreationHelper = (context: Context, array: any[], visited: Set): void => { - if (visited.has(array) || array.hasOwnProperty('id')) { - return - } - visited.add(array) - // Nested arrays are always created first, so outer arrays are handled after nested ones - // to preserve creation order in the environment heap - for (const item of array) { - if (isArray(item)) { - arrayCreationHelper(context, item, visited) - } - } - // Properties are defined this way to prevent them from being enumerable - Object.defineProperties(array, { - id: { value: uniqueId(context) }, - // Make environment writable as there are still cases where the frontend might need to - // change the environment of an array, like when the prelude environment is merged - // into the global environment in the visualisation of the CSE Machine - environment: { value: currentEnvironment(context), writable: true } - }) - currentEnvironment(context).heap.add(array as Array) +export const isEnvArray = (item: any): item is EnvArray => { + return ( + isArray(item) && + {}.hasOwnProperty.call(item, 'id') && + {}.hasOwnProperty.call(item, 'environment') + ) } /** * Adds the properties `id` and `environment` to the given array, and adds the array to the - * current environment's heap. Recursively does this for any nested arrays first, before - * handling the current one. + * current environment's heap. Adds the array to the heap of `envOverride` instead if it's defined. * * @param context the context used to provide the current environment and new unique id - * @param array the array to add the properties to, and to add to the current environment heap to + * @param array the array to attach properties to, and for addition to the heap */ -export const handleArrayCreation = (context: Context, array: any[]): void => { - arrayCreationHelper(context, array, new Set()) +export const handleArrayCreation = ( + context: Context, + array: any[], + envOverride?: Environment +): void => { + const environment = envOverride ?? currentEnvironment(context) + // Both id and environment are non-enumerable so iterating + // through the array will not return these values + Object.defineProperties(array, { + id: { value: uniqueId(context) }, + // Make environment writable as there are cases on the frontend where + // environments of objects need to be modified + environment: { value: environment, writable: true } + }) + environment.heap.add(array as EnvArray) } /** @@ -325,7 +255,9 @@ export const createEnvironment = ( callExpression: es.CallExpression ): Environment => { const environment: Environment = { - name: isIdentifier(callExpression.callee) ? callExpression.callee.name : closure.functionName, + name: isIdentifier(callExpression.callee) + ? callExpression.callee.name + : closure.declaredName ?? closure.functionName, tail: closure.environment, head: {}, heap: new Heap(), @@ -337,7 +269,9 @@ export const createEnvironment = ( } closure.node.params.forEach((param, index) => { if (isRestElement(param)) { - environment.head[(param.argument as es.Identifier).name] = args.slice(index) + const array = args.slice(index) + handleArrayCreation(context, array, environment) + environment.head[(param.argument as es.Identifier).name] = array } else { environment.head[(param as es.Identifier).name] = args[index] } @@ -466,6 +400,10 @@ export function defineVariable( return handleRuntimeError(context, new errors.VariableRedeclaration(node, name, !constant)) } + if (constant && value instanceof Closure) { + value.declaredName = name + } + Object.defineProperty(environment.head, name, { value, writable: !constant, diff --git a/src/mocks/context.ts b/src/mocks/context.ts index 30e59780b..7e19650ad 100644 --- a/src/mocks/context.ts +++ b/src/mocks/context.ts @@ -1,7 +1,8 @@ import * as es from 'estree' import createContext, { EnvTree } from '../createContext' -import Closure from '../interpreter/closure' +import OldClosure from '../interpreter/closure' +import Closure from '../cse-machine/closure' import { createBlockEnvironment } from '../interpreter/interpreter' import { Chapter, Context, Environment, Variant } from '../types' @@ -63,19 +64,21 @@ export function mockRuntimeContext(): Context { return context } -export function mockClosure(): Closure { +export function mockClosure(cseMachineClosure: true): Closure +export function mockClosure(cseMachineClosure?: false): OldClosure +export function mockClosure(cseMachineClosure?: boolean): Closure | OldClosure { const context = createContext() - return new Closure( + return new (cseMachineClosure ? Closure : OldClosure)( { - type: 'FunctionExpression', + type: 'ArrowFunctionExpression', + expression: true, loc: null, - id: null, params: [], body: { type: 'BlockStatement', body: [] } - } as es.FunctionExpression, + } as es.ArrowFunctionExpression, mockEnvironment(context), context ) diff --git a/src/py-slang b/src/py-slang index a412b2163..821987b3e 160000 --- a/src/py-slang +++ b/src/py-slang @@ -1 +1 @@ -Subproject commit a412b2163ed93a4956a770091206e362f26b376e +Subproject commit 821987b3e66ed6574981ce58f4d5d43a7ccb11c1 diff --git a/src/stepper/__tests__/__snapshots__/stepper.ts.snap b/src/stepper/__tests__/__snapshots__/stepper.ts.snap index 554c63464..fee15d2af 100644 --- a/src/stepper/__tests__/__snapshots__/stepper.ts.snap +++ b/src/stepper/__tests__/__snapshots__/stepper.ts.snap @@ -2109,166 +2109,725 @@ undefined; " `; -exports[`Infinite recursion 1`] = ` -"function f() { - return f(); +exports[`Expressions: Binary operators And-shortcut-false test case 1`] = ` +"if (false && 1 + 2 === 1 + 2) { + 1; +} else { + 2; } -f(); -function f() { - return f(); +if (false && 1 + 2 === 1 + 2) { + 1; +} else { + 2; } -f(); -f(); +if (false) { + 1; +} else { + 2; +} -f(); +if (false) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + 2; +} -f(); +{ + 2; +} -f(); +2; -f(); +2; +" +`; -f(); +exports[`Expressions: Binary operators And-shortcut-true test case 1`] = ` +"if (true && 1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (true && 1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (3 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (3 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (3 === 5) { + 1; +} else { + 2; +} -f(); +if (3 === 5) { + 1; +} else { + 2; +} -f(); +if (false) { + 1; +} else { + 2; +} -f(); +if (false) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + 2; +} -f(); +{ + 2; +} -f(); +2; -f(); +2; +" +`; -f(); +exports[`Expressions: Binary operators Left-binary-reduce test case 1`] = ` +"if (1 + 2 + 3 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (1 + 2 + 3 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (3 + 3 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (3 + 3 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (6 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (6 === 1 + 2 + 3) { + 1; +} else { + 2; +} -f(); +if (6 === 3 + 3) { + 1; +} else { + 2; +} -f(); +if (6 === 3 + 3) { + 1; +} else { + 2; +} -f(); +if (6 === 6) { + 1; +} else { + 2; +} -f(); +if (6 === 6) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 1; +} -f(); +{ + undefined; + 1; +} -f(); +{ + 1; +} -f(); +{ + 1; +} -f(); +1; -f(); +1; +" +`; -f(); +exports[`Expressions: Binary operators Or-shortcut-false test case 1`] = ` +"if (false || 1 + 2 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (false || 1 + 2 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (1 + 2 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (1 + 2 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (3 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (3 === 1 + 2) { + 1; +} else { + 2; +} -f(); +if (3 === 3) { + 1; +} else { + 2; +} -f(); +if (3 === 3) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 1; +} -f(); +{ + undefined; + 1; +} -f(); +{ + 1; +} -f(); +{ + 1; +} -f(); +1; -f(); +1; +" +`; -f(); +exports[`Expressions: Binary operators Or-shortcut-true test case 1`] = ` +"if (true || 1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (true || 1 + 2 === 2 + 3) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +if (true) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 1; +} -f(); +{ + undefined; + 1; +} -f(); +{ + 1; +} -f(); +{ + 1; +} -f(); +1; -f(); +1; +" +`; -f(); +exports[`Expressions: Binary operators Prim-binary-reduce test case 1`] = ` +"if (1 >= 2) { + 1; +} else { + 2; +} -f(); +if (1 >= 2) { + 1; +} else { + 2; +} -f(); +if (false) { + 1; +} else { + 2; +} -f(); +if (false) { + 1; +} else { + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + undefined; + 2; +} -f(); +{ + 2; +} + +{ + 2; +} + +2; + +2; +" +`; + +exports[`Expressions: Binary operators Right-binary-reduce test case 1`] = ` +"if (1 >= 1 + 1) { + 1; +} else { + 2; +} + +if (1 >= 1 + 1) { + 1; +} else { + 2; +} + +if (1 >= 2) { + 1; +} else { + 2; +} + +if (1 >= 2) { + 1; +} else { + 2; +} + +if (false) { + 1; +} else { + 2; +} + +if (false) { + 1; +} else { + 2; +} + +{ + undefined; + 2; +} + +{ + undefined; + 2; +} + +{ + 2; +} + +{ + 2; +} + +2; + +2; +" +`; + +exports[`Expressions: conditionals Conditional-false-reduce test case 1`] = ` +"false ? 1 + 2 : 2 + 3; + +false ? 1 + 2 : 2 + 3; + +2 + 3; + +2 + 3; + +5; + +5; +" +`; + +exports[`Expressions: conditionals Conditional-predicate-reduce test case 1`] = ` +"1 + 1 === 2 ? 1 + 2 : 2 + 3; + +1 + 1 === 2 ? 1 + 2 : 2 + 3; + +2 === 2 ? 1 + 2 : 2 + 3; + +2 === 2 ? 1 + 2 : 2 + 3; + +true ? 1 + 2 : 2 + 3; + +true ? 1 + 2 : 2 + 3; + +1 + 2; + +1 + 2; + +3; + +3; +" +`; + +exports[`Expressions: conditionals Conditional-true-reduce test case 1`] = ` +"true ? 1 + 2 : 2 + 3; + +true ? 1 + 2 : 2 + 3; + +1 + 2; + +1 + 2; + +3; + +3; +" +`; + +exports[`Expresssions: Blocks Block-expression-empty-reduce test case 1`] = ` +"function foo(x) {} +foo(0); + +function foo(x) {} +foo(0); + +foo(0); + +foo(0); + +{}; + +{}; + +undefined; + +undefined; +" +`; + +exports[`Expresssions: Blocks Block-expression-intro test case 1`] = ` +"function foo(x) { + 1 + 1; +} +foo(0); + +function foo(x) { + 1 + 1; +} +foo(0); + +foo(0); + +foo(0); + +{ + 1 + 1; +}; + +{ + 1 + 1; +}; + +{ + 2; +}; + +{ + 2; +}; + +undefined; + +undefined; +" +`; + +exports[`Expresssions: Blocks Block-expression-single-reduce test case 1`] = ` +"function foo(x) { + 1; +} +foo(0); + +function foo(x) { + 1; +} +foo(0); + +foo(0); + +foo(0); + +{ + 1; +}; + +{ + 1; +}; + +undefined; + +undefined; +" +`; + +exports[`Infinite recursion 1`] = ` +"function f() { + return f(); +} +f(); + +function f() { + return f(); +} +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); f(); @@ -4114,6 +4673,739 @@ f(); f(); +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +f(); + +" +`; + +exports[`Programs Eliminate-constant-declaration test case 1 1`] = ` +"const x = 0; + +const x = 0; + + +undefined; +" +`; + +exports[`Programs Eliminate-constant-declaration test case 2 1`] = ` +"1; +const x = 0; + +1; +const x = 0; + +1; + +1; +" +`; + +exports[`Programs Eliminate-function-declaration test case 1 1`] = ` +"function foo(x) { + return 0; +} + +function foo(x) { + return 0; +} + + +undefined; +" +`; + +exports[`Programs Eliminate-function-declaration test case 2 1`] = ` +"1; +function foo(x) { + return 0; +} + +1; +function foo(x) { + return 0; +} + +1; + +1; +" +`; + +exports[`Programs Program-intro test case 1 1`] = ` +"1 + 1; + +1 + 1; + +2; + +2; +" +`; + +exports[`Programs Program-intro test case 2 1`] = ` +"1; +1 + 1; + +1; +1 + 1; + +1; +2; + +1; +2; + +2; + +2; +" +`; + +exports[`Programs Program-reduce test case 1`] = ` +"1; +2; + +1; +2; + +2; + +2; +" +`; + +exports[`Statements: Blocks Block-statement-empty-reduce test case 1 1`] = ` +"{} + +{} + + +undefined; +" +`; + +exports[`Statements: Blocks Block-statement-empty-reduce test case 2 1`] = ` +"{ + { + {} + {} + } + { + {} + {} + } +} + +{ + { + {} + {} + } + { + {} + {} + } +} + +{ + { + {} + } + { + {} + {} + } +} + +{ + { + {} + } + { + {} + {} + } +} + +{ + {} + { + {} + {} + } +} + +{ + {} + { + {} + {} + } +} + +{ + { + {} + {} + } +} + +{ + { + {} + {} + } +} + +{ + { + {} + } +} + +{ + { + {} + } +} + +{ + {} +} + +{ + {} +} + +{} + +{} + + +undefined; +" +`; + +exports[`Statements: Blocks Block-statement-intro test case 1`] = ` +"{ + 1 + 1; +} + +{ + 1 + 1; +} + +{ + 2; +} + +{ + 2; +} + +2; + +2; +" +`; + +exports[`Statements: Blocks Block-statement-single-reduce test case 1`] = ` +"{ + 1; +} + +{ + 1; +} + +1; + +1; +" +`; + +exports[`Statements: Conditionals Conditional-statement-alternative test case 1`] = ` +"if (false) { + 1; +} else { + 2; +} + +if (false) { + 1; +} else { + 2; +} + +{ + undefined; + 2; +} + +{ + undefined; + 2; +} + +{ + 2; +} + +{ + 2; +} + +2; + +2; +" +`; + +exports[`Statements: Conditionals Conditional-statement-blockexpr-alternative test case 1 1`] = ` +"function foo(x) { + if (false) { + 1; + } else { + 2; + } +} +foo(0); + +function foo(x) { + if (false) { + 1; + } else { + 2; + } +} +foo(0); + +foo(0); + +foo(0); + +{ + if (false) { + 1; + } else { + 2; + } +}; + +{ + if (false) { + 1; + } else { + 2; + } +}; + +{ + { + 2; + } +}; + +{ + { + 2; + } +}; + +{ + 2; +}; + +{ + 2; +}; + +undefined; + +undefined; +" +`; + +exports[`Statements: Conditionals Conditional-statement-blockexpr-alternative test case 2 1`] = ` +"function foo(x) { + 3; + if (false) { + 1; + } else { + 2; + } +} +foo(0); + +function foo(x) { + 3; + if (false) { + 1; + } else { + 2; + } +} +foo(0); + +foo(0); + +foo(0); + +{ + 3; + if (false) { + 1; + } else { + 2; + } +}; + +{ + 3; + if (false) { + 1; + } else { + 2; + } +}; + +{ + 3; + { + 2; + } +}; + +{ + 3; + { + 2; + } +}; + +{ + 3; + 2; +}; + +{ + 3; + 2; +}; + +{ + 2; +}; + +{ + 2; +}; + +undefined; + +undefined; +" +`; + +exports[`Statements: Conditionals Conditional-statement-blockexpr-consequent test case 1 1`] = ` +"function foo(x) { + if (true) { + 1; + } else { + 2; + } +} +foo(0); + +function foo(x) { + if (true) { + 1; + } else { + 2; + } +} +foo(0); + +foo(0); + +foo(0); + +{ + if (true) { + 1; + } else { + 2; + } +}; + +{ + if (true) { + 1; + } else { + 2; + } +}; + +{ + { + 1; + } +}; + +{ + { + 1; + } +}; + +{ + 1; +}; + +{ + 1; +}; + +undefined; + +undefined; +" +`; + +exports[`Statements: Conditionals Conditional-statement-blockexpr-consequent test case 2 1`] = ` +"function foo(x) { + 3; + if (true) { + 1; + } else { + 2; + } +} +foo(0); + +function foo(x) { + 3; + if (true) { + 1; + } else { + 2; + } +} +foo(0); + +foo(0); + +foo(0); + +{ + 3; + if (true) { + 1; + } else { + 2; + } +}; + +{ + 3; + if (true) { + 1; + } else { + 2; + } +}; + +{ + 3; + { + 1; + } +}; + +{ + 3; + { + 1; + } +}; + +{ + 3; + 1; +}; + +{ + 3; + 1; +}; + +{ + 1; +}; + +{ + 1; +}; + +undefined; + +undefined; +" +`; + +exports[`Statements: Conditionals Conditional-statement-consequent test case 1`] = ` +"if (true) { + 1; +} else { + 2; +} + +if (true) { + 1; +} else { + 2; +} + +{ + undefined; + 1; +} + +{ + undefined; + 1; +} + +{ + 1; +} + +{ + 1; +} + +1; + +1; +" +`; + +exports[`Statements: Conditionals Conditional-statement-predicate test case 1`] = ` +"if (1 + 2 + 3 === 1) {} else {} + +if (1 + 2 + 3 === 1) {} else {} + +if (3 + 3 === 1) {} else {} + +if (3 + 3 === 1) {} else {} + +if (6 === 1) {} else {} + +if (6 === 1) {} else {} + +if (false) {} else {} + +if (false) {} else {} + +{ + undefined; +} + +{ + undefined; +} + +undefined; + +undefined; +" +`; + +exports[`Statements: Constant declarations Evaluate-constant-declaration test case 1`] = ` +"const x = 1 + 2 + 3; + +const x = 1 + 2 + 3; + +const x = 3 + 3; + +const x = 3 + 3; + +const x = 6; + +const x = 6; + + +undefined; +" +`; + +exports[`Statements: Expression statements Expression-statement-reduce test case 1`] = ` +"1 + 2 + 3; + +1 + 2 + 3; + +3 + 3; + +3 + 3; + +6; + +6; " `; diff --git a/src/stepper/__tests__/stepper.ts b/src/stepper/__tests__/stepper.ts index 3f739ba23..e0d654131 100644 --- a/src/stepper/__tests__/stepper.ts +++ b/src/stepper/__tests__/stepper.ts @@ -1768,6 +1768,464 @@ describe(`Evaluation of empty code and imports`, () => { }) }) +/** + * start of stepper specification tests + */ +describe(`Programs`, () => { + //Program-intro: + test('Program-intro test case 1', async () => { + const code = `1 + 1;` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + + test('Program-intro test case 2', async () => { + const code = ` + 1; + 1 + 1; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Program-reduce: + test('Program-reduce test case', async () => { + const code = ` + 1; + 2; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Eliminate-function-declaration: + test('Eliminate-function-declaration test case 1', async () => { + const code = ` + function foo(x) { + return 0; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + + test('Eliminate-function-declaration test case 2', async () => { + const code = ` + 1; + function foo(x) { + return 0; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //Eliminate-constant-declaration: + test('Eliminate-constant-declaration test case 1', async () => { + const code = ` + const x = 0; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + + test('Eliminate-constant-declaration test case 2', async () => { + const code = ` + 1; + const x = 0; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) +}) + +describe(`Statements: Expression statements`, () => { + //Expression-statement-reduce: + test('Expression-statement-reduce test case', async () => { + const code = ` + 1 + 2 + 3; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('6;') + }) +}) + +describe(`Statements: Constant declarations`, () => { + //Evaluate-constant-declaration: + test('Evaluate-constant-declaration test case', async () => { + const code = ` + const x = 1 + 2 + 3; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) +}) + +describe(`Statements: Conditionals`, () => { + //Conditional-statement-predicate: + test('Conditional-statement-predicate test case', async () => { + const code = ` + if (1 + 2 + 3 === 1) { + + } else { + + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + //Conditional-statement-consequent: + test('Conditional-statement-consequent test case', async () => { + const code = ` + if (true) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //Conditional-statement-alternative: + test('Conditional-statement-alternative test case', async () => { + const code = ` + if (false) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Conditional-statement-blockexpr-consequent: + test('Conditional-statement-blockexpr-consequent test case 1', async () => { + const code = ` + function foo(x) { + if (true) { + 1; + } else { + 2; + } + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + + test('Conditional-statement-blockexpr-consequent test case 2', async () => { + const code = ` + function foo(x) { + 3; + if (true) { + 1; + } else { + 2; + } + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + //Conditional-statement-blockexpr-alternative: + test('Conditional-statement-blockexpr-alternative test case 1', async () => { + const code = ` + function foo(x) { + if (false) { + 1; + } else { + 2; + } + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + + test('Conditional-statement-blockexpr-alternative test case 2', async () => { + const code = ` + function foo(x) { + 3; + if (false) { + 1; + } else { + 2; + } + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) +}) + +describe(`Statements: Blocks`, () => { + //Block-statement-intro: + test('Block-statement-intro test case', async () => { + const code = ` + { + 1 + 1; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Block-statement-single-reduce: + test('Block-statement-single-reduce test case', async () => { + const code = ` + { + 1; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //Block-statement-empty-reduce: + test('Block-statement-empty-reduce test case 1', async () => { + const code = ` + { + + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + + test('Block-statement-empty-reduce test case 2', async () => { + const code = ` + { + { + { + + } + { + + } + } + + { + { + + } + { + + } + } + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) +}) + +describe(`Expresssions: Blocks`, () => { + //Block-expression-intro: + test('Block-expression-intro test case', async () => { + const code = ` + function foo(x) { + 1 + 1; + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + //Block-expression-single-reduce: + test('Block-expression-single-reduce test case', async () => { + const code = ` + function foo(x) { + 1; + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + //Block-expression-empty-reduce: + test('Block-expression-empty-reduce test case', async () => { + const code = ` + function foo(x) { + } + foo(0); + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('undefined;') + }) + /** + * Block-expression-return-reduce is not included as test cases + * This section needs further discussion + */ +}) + +describe(`Expressions: Binary operators`, () => { + //Left-binary-reduce: + test('Left-binary-reduce test case', async () => { + const code = ` + if (1 + 2 + 3 === 1 + 2 + 3) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //And-shortcut-false: + test('And-shortcut-false test case', async () => { + const code = ` + if (false && 1 + 2 === 1 + 2) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //And-shortcut-true: + test('And-shortcut-true test case', async () => { + const code = ` + if (true && 1 + 2 === 2 + 3) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Or-shortcut-true: + test('Or-shortcut-true test case', async () => { + const code = ` + if (true || 1 + 2 === 2 + 3) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //Or-shortcut-false: + test('Or-shortcut-false test case', async () => { + const code = ` + if (false || 1 + 2 === 1 + 2) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('1;') + }) + //Right-binary-reduce: + test('Right-binary-reduce test case', async () => { + const code = ` + if (1 >= 1 + 1) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) + //Prim-binary-reduce: + test('Prim-binary-reduce test case', async () => { + const code = ` + if (1 >= 2) { + 1; + } else { + 2; + } + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('2;') + }) +}) + +describe(`Expressions: conditionals`, () => { + //Conditional-predicate-reduce: + test('Conditional-predicate-reduce test case', async () => { + const code = ` + 1 + 1 === 2 ? 1 + 2 : 2 + 3; + ` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('3;') + }) + //Conditional-true-reduce: + test('Conditional-true-reduce test case', async () => { + const code = `true ? 1 + 2 : 2 + 3;` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('3;') + }) + //Conditional-false-reduce: + test('Conditional-false-reduce test case', async () => { + const code = `false ? 1 + 2 : 2 + 3;` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('5;') + }) +}) +/* +test cases to be discussed +describe(`Expressions: function application`, () => { + +}) +*/ + +//template +/* +For a section of test cases +describe(``, () => { + +}) + +For specific test cases +test('', async () => { + const code = `` + const steps = await testEvalSteps(code, mockContext()) + expect(steps.map(x => codify(x[0])).join('\n')).toMatchSnapshot() + expect(getLastStepAsString(steps)).toEqual('') +}) +*/ + +/** + * end of stepper specification tests + */ + // describe(`#1223: Stepper: Import statements cause errors`, () => { // test('import a module and invoke its functions', async () => { // const code = ` From 1390759fba177feca59674bd9725a5c8fdd1c48f Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 12:14:19 +0800 Subject: [PATCH 35/41] Add name and parameter data to builtin functions --- src/createContext.ts | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/createContext.ts b/src/createContext.ts index dd5470e39..b7f692bb4 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -225,18 +225,36 @@ export function defineBuiltin( value: Value, minArgsNeeded: undefined | number = undefined ) { + function extractName(name: string): string { + return name.split('(')[0].trim() + } + + function extractParameters(name: string): string[] { + return name + .split('(')[1] + .split(')')[0] + .split(',') + .map(s => s.trim()) + } + if (typeof value === 'function') { - const funName = name.split('(')[0].trim() + const funName = extractName(name) + const funParameters = extractParameters(name) const repr = `function ${name} {\n\t[implementation hidden]\n}` value.toString = () => repr value.minArgsNeeded = minArgsNeeded + value.funName = funName + value.funParameters = funParameters defineSymbol(context, funName, value) } else if (value instanceof LazyBuiltIn) { const wrapped = (...args: any) => value.func(...args) - const funName = name.split('(')[0].trim() + const funName = extractName(name) + const funParameters = extractParameters(name) const repr = `function ${name} {\n\t[implementation hidden]\n}` wrapped.toString = () => repr + wrapped.funName = funName + wrapped.funParameters = funParameters makeWrapper(value.func, wrapped) defineSymbol(context, funName, new LazyBuiltIn(wrapped, value.evaluateArgs)) } else { From e7ebf717c0e8de84fd5ed6880b16404f8833660b Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 12:18:11 +0800 Subject: [PATCH 36/41] Repair representation of closures and builtin functions --- src/alt-langs/scheme/scheme-mapper.ts | 25 ++++++++++++++++++++++++- src/createContext.ts | 4 ++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scheme-mapper.ts b/src/alt-langs/scheme/scheme-mapper.ts index 466d1c23a..7c7d27eab 100644 --- a/src/alt-langs/scheme/scheme-mapper.ts +++ b/src/alt-langs/scheme/scheme-mapper.ts @@ -1,5 +1,5 @@ import { ArrowFunctionExpression, Identifier, RestElement } from "estree" -import Closure from "../../interpreter/closure" +import Closure from "../../cse-machine/closure" import { decode, estreeDecode } from "./scm-slang/src" import { boolean$63$, car, cdr, circular$45$list$63$, cons, dotted$45$list$63$, last$45$pair, list$45$tail, null$63$, number$63$, pair$63$, proper$45$list$63$, set$45$cdr$33$, vector$63$ } from "./scm-slang/src/stdlib/source-scheme-library" import { ErrorType, Result, SourceError } from "../../types" @@ -46,6 +46,12 @@ function decodeString(str: string): string { // Given any value, change the representation of it to // the required scheme representation. export function schemeVisualise(x: any): Representation { + // hack: builtins are represented using an object with a toString method + // and minArgsNeeded. + // so to detect these, we use a function that checks for these + function isBuiltinFunction(x: any): boolean { + return x.minArgsNeeded !== undefined && x.toString !== undefined + } function stringify(x: any): string { if (null$63$(x)) { return '()' @@ -66,6 +72,23 @@ export function schemeVisualise(x: any): Representation { .join(' ') .trim() return `#` + } else if (isBuiltinFunction(x)) { + function decodeParams(params: string[]): string { + // if parameter starts with ... then it is a rest parameter + const convertedparams = params + .map(param => { + if (param.startsWith('...')) { + return `. ${param.slice(3)}` + } + return param + }) + .map(decodeString) + return convertedparams.join(' ') + } + // take the name and parameter out of the defined function name + const name = decodeString(x.funName) + const parameters = decodeParams(x.funParameters) + return `#` } else if (circular$45$list$63$(x)) { return '(circular list)' } else if (dotted$45$list$63$(x) && pair$63$(x)) { diff --git a/src/createContext.ts b/src/createContext.ts index b7f692bb4..a973659aa 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -230,6 +230,10 @@ export function defineBuiltin( } function extractParameters(name: string): string[] { + // if the function has no () in its name, it has no parameters + if (!name.includes('(')) { + return [] + } return name .split('(')[1] .split(')')[0] From 47f06d644e30c269d15e7acf3eac7edda3cf2816 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 12:39:10 +0800 Subject: [PATCH 37/41] update scm-slang --- src/alt-langs/scheme/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index c7da3a028..6dd2e8f2d 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit c7da3a028ae943df3df85736f19e37e3851313c5 +Subproject commit 6dd2e8f2d751da54edeb14b7874ffc3ca8961ccc From 64cffb2921b984eb3c93acc309f14f192c236db9 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 12:42:34 +0800 Subject: [PATCH 38/41] update scm-slang --- src/alt-langs/scheme/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index 6dd2e8f2d..e012cebcd 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit 6dd2e8f2d751da54edeb14b7874ffc3ca8961ccc +Subproject commit e012cebcd73ea162b5436709b2821ee64aa7ff56 From 575f49ce4de1ad327d6eed751b966d5b641cc275 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 14:06:51 +0800 Subject: [PATCH 39/41] update scm-slang --- src/alt-langs/scheme/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index e012cebcd..bb3b4ed47 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit e012cebcd73ea162b5436709b2821ee64aa7ff56 +Subproject commit bb3b4ed47a3ee74e46af221270c8d0dfbf27f243 From f92d3ea4780f176ca11195d861a781423022c1d5 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Tue, 9 Apr 2024 17:54:44 +0800 Subject: [PATCH 40/41] bump scm-slang --- src/alt-langs/scheme/scm-slang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang index bb3b4ed47..0bcb5fa2a 160000 --- a/src/alt-langs/scheme/scm-slang +++ b/src/alt-langs/scheme/scm-slang @@ -1 +1 @@ -Subproject commit bb3b4ed47a3ee74e46af221270c8d0dfbf27f243 +Subproject commit 0bcb5fa2a074ab9b7009ff98aa8d1cda2ab9a818 From 90e6c56f0436655ff5c8f0e902689861e46661a3 Mon Sep 17 00:00:00 2001 From: s-kybound Date: Thu, 11 Apr 2024 16:15:16 +0800 Subject: [PATCH 41/41] add dummy prelude for scheme --- src/alt-langs/scheme/scheme-mapper.ts | 2 +- src/createContext.ts | 8 +++++++- src/stdlib/scheme.prelude.ts | 3 +++ 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 src/stdlib/scheme.prelude.ts diff --git a/src/alt-langs/scheme/scheme-mapper.ts b/src/alt-langs/scheme/scheme-mapper.ts index 7c7d27eab..468c33870 100644 --- a/src/alt-langs/scheme/scheme-mapper.ts +++ b/src/alt-langs/scheme/scheme-mapper.ts @@ -72,7 +72,7 @@ export function schemeVisualise(x: any): Representation { .join(' ') .trim() return `#` - } else if (isBuiltinFunction(x)) { + } else if (isBuiltinFunction(x) || typeof x === 'function') { function decodeParams(params: string[]): string { // if parameter starts with ... then it is a rest parameter const convertedparams = params diff --git a/src/createContext.ts b/src/createContext.ts index 0a4917d95..fa5194f05 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -1,6 +1,7 @@ // Variable determining chapter of Source is contained in this file. import * as scheme_libs from './alt-langs/scheme/scm-slang/src/stdlib/source-scheme-library' +import { schemePrelude } from './stdlib/scheme.prelude' import { GLOBAL, JSSLANG_PROPERTIES } from './constants' import { call_with_current_continuation } from './cse-machine/continuations' import Heap from './cse-machine/heap' @@ -30,6 +31,7 @@ import { import { makeWrapper } from './utils/makeWrapper' import * as operators from './utils/operators' import { stringify } from './utils/stringify' +import { schemeVisualise } from './alt-langs/scheme/scheme-mapper' export class LazyBuiltIn { func: (...arg0: any) => any @@ -608,7 +610,7 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn */ case Chapter.SCHEME_1: // Display - defineBuiltin(context, 'display(val)', display) + defineBuiltin(context, 'display(val)', (val: any) => display(schemeVisualise(val))) defineBuiltin(context, 'newline()', () => display('')) // I/O @@ -806,6 +808,10 @@ function importPrelude(context: Context) { prelude += nonDetPrelude } + if (context.chapter === Chapter.FULL_SCHEME) { + prelude += schemePrelude + } + if (prelude !== '') { context.prelude = prelude } diff --git a/src/stdlib/scheme.prelude.ts b/src/stdlib/scheme.prelude.ts new file mode 100644 index 000000000..2562804bd --- /dev/null +++ b/src/stdlib/scheme.prelude.ts @@ -0,0 +1,3 @@ +export const schemePrelude = ` +(define call-with-current-continuation call/cc) +`