From 65c67128bf981f5ec9eff293327b75d7afe9fd68 Mon Sep 17 00:00:00 2001 From: CZX Date: Sat, 6 Apr 2024 19:33:12 +0800 Subject: [PATCH 1/8] CSE Machine fixes: - make closureToJS use CSE machine instead of interpreter - add variadic function array to heap - handle functions from `stream` - added heap move method --- .../__snapshots__/cse-machine-heap.ts.snap | 1846 ++++++++++++++++- src/cse-machine/__tests__/cse-machine-heap.ts | 58 +- .../__tests__/cse-machine-unique-id.ts | 70 +- src/cse-machine/closure.ts | 140 ++ src/cse-machine/heap.ts | 16 +- src/cse-machine/interpreter.ts | 78 +- src/cse-machine/stack.ts | 58 + src/cse-machine/types.ts | 6 +- src/cse-machine/utils.ts | 124 +- src/mocks/context.ts | 9 +- 10 files changed, 2227 insertions(+), 178 deletions(-) create mode 100644 src/cse-machine/closure.ts create mode 100644 src/cse-machine/stack.ts 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..2e954991b 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,1843 @@ 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, + }, + }, + }, + }, +} +`; diff --git a/src/cse-machine/__tests__/cse-machine-heap.ts b/src/cse-machine/__tests__/cse-machine-heap.ts index 590b9f8a4..1010d941b 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,13 @@ 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() +}) diff --git a/src/cse-machine/__tests__/cse-machine-unique-id.ts b/src/cse-machine/__tests__/cse-machine-unique-id.ts index 6c181ffb0..7d93eb40e 100644 --- a/src/cse-machine/__tests__/cse-machine-unique-id.ts +++ b/src/cse-machine/__tests__/cse-machine-unique-id.ts @@ -5,23 +5,23 @@ 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`) }) @@ -43,62 +43,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..eacc21a08 --- /dev/null +++ b/src/cse-machine/closure.ts @@ -0,0 +1,140 @@ +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 { + blockArrowFunction, + blockStatement, + callExpression, + identifier, + literal, + returnStatement +} from '../utils/ast/astCreator' +import { apply } from './interpreter' + +const closureToJS = (value: Closure, context: Context, hasDeclaredName: boolean) => { + function DummyClass(this: Closure) { + const args: Value[] = [...arguments] + const node = callExpression( + // Use function name if there is one so environments that get created will have this name. + // Else, treat the closure as a literal so it can get directly pushed into the stash next. + hasDeclaredName ? identifier(value.functionName) : literal(value as any), + args + ) + return apply(context, node) + } + 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) + ? blockStatement([returnStatement(node.body, node.body.loc)], node.body.loc) + : dummyReturn && !hasReturnStatement(node.body) + ? blockStatement( + [ + ...node.body.body, + returnStatement(identifier('undefined', node.body.loc), node.body.loc) + ], + node.body.loc + ) + : node.body + + const closure = new Closure( + 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 + + /** String representation of the closure */ + 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.Function, + 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) + let hasDeclaredName = false + if (this.node.type === 'FunctionDeclaration' && this.node.id !== null) { + this.functionName = this.node.id.name + hasDeclaredName = true + } else { + this.functionName = + (this.node.params.length === 1 ? '' : '(') + + this.node.params.map((o: es.Identifier) => o.name).join(', ') + + (this.node.params.length === 1 ? '' : ')') + + ' => ...' + } + const funJS = closureToJS(this, context, hasDeclaredName) + 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 1d52a1a06..c05a7fa44 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 { initModuleContext, loadModuleBundle } from '../modules/loader/moduleLoader' import { checkEditorBreakpoints } from '../stdlib/inspector' import { Context, ContiguousArrayElements, Result, type StatementSequence, Value } from '../types' @@ -34,6 +33,7 @@ import { makeDummyContCallExpression } from './continuations' import * as instr from './instrCreator' +import { Stack } from './stack' import { AppInstr, ArrLitInstr, @@ -72,6 +72,7 @@ import { hasDeclarations, hasImportDeclarations, isBlockStatement, + isEnvArray, isInstr, isNode, isSimpleFunction, @@ -79,9 +80,9 @@ import { pushEnvironment, reduceConditional, setVariable, - Stack, valueProducing } from './utils' +import Closure from './closure' type CmdEvaluator = ( command: ControlItem, @@ -153,6 +154,41 @@ export class Stash extends Stack { } } +/** + * Evaluates the given call expression and returns the result. If the callee is a closure, + * the given context may be mutated and more environments will be created. + * + * @param context The context to evaluate the program in. + * @param node The call expression to evaluate. + * @returns The result of running the CSE machine. + */ +export function apply( + context: Context, + node: es.CallExpression +) { + // 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(instr.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() +} + /** * Function to be called when a program is to be interpreted using * the explicit control evaluator. @@ -745,7 +781,6 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { true, isPrelude ) - currentEnvironment(context).heap.add(closure) stash.push(closure) }, @@ -949,11 +984,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 @@ -988,17 +1018,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..f065fe70f 100644 --- a/src/cse-machine/types.ts +++ b/src/cse-machine/types.ts @@ -1,6 +1,6 @@ import * as es from 'estree' -import Closure from '../interpreter/closure' +import Closure from './closure' import { Environment, Node } from '../types' export enum InstrType { @@ -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..fa8dc279a 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) } /** @@ -337,7 +267,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] } diff --git a/src/mocks/context.ts b/src/mocks/context.ts index 30e59780b..7ec37d213 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,9 +64,11 @@ 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', loc: null, From 93a30d185770cf70c289b7221be8aa21601aa611 Mon Sep 17 00:00:00 2001 From: CZX Date: Sat, 6 Apr 2024 19:35:53 +0800 Subject: [PATCH 2/8] Formatting --- src/cse-machine/interpreter.ts | 5 +---- src/cse-machine/types.ts | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index c05a7fa44..f51a85e0e 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -162,10 +162,7 @@ export class Stash extends Stack { * @param node The call expression to evaluate. * @returns The result of running the CSE machine. */ -export function apply( - context: Context, - node: es.CallExpression -) { +export function apply(context: Context, node: es.CallExpression) { // 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 } } diff --git a/src/cse-machine/types.ts b/src/cse-machine/types.ts index f065fe70f..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 './closure' import { Environment, Node } from '../types' +import Closure from './closure' export enum InstrType { RESET = 'Reset', From d00803fcf06d6c2a98a60a223236c23b24c81dc7 Mon Sep 17 00:00:00 2001 From: CZX Date: Sun, 7 Apr 2024 08:44:56 +0800 Subject: [PATCH 3/8] Add function expression to store function name --- src/cse-machine/closure.ts | 13 ++++++++----- src/cse-machine/interpreter.ts | 26 ++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index eacc21a08..378f5cf0e 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -13,6 +13,7 @@ import { blockArrowFunction, blockStatement, callExpression, + functionExpression, identifier, literal, returnStatement @@ -58,8 +59,8 @@ class Callable extends Function { * Models function value in the CSE machine. */ export default class Closure extends Callable { - public static makeFromArrowFunction( - node: es.ArrowFunctionExpression, + public static makeFromFunctionExpression( + node: es.ArrowFunctionExpression | es.FunctionExpression, environment: Environment, context: Context, dummyReturn?: boolean, @@ -79,7 +80,9 @@ export default class Closure extends Callable { : node.body const closure = new Closure( - blockArrowFunction(node.params as es.Identifier[], functionBody, node.loc), + node.type === 'FunctionExpression' + ? functionExpression(node.params as es.Identifier[], functionBody, node.loc, node.id!) + : blockArrowFunction(node.params as es.Identifier[], functionBody, node.loc), environment, context, predefined @@ -107,7 +110,7 @@ export default class Closure extends Callable { public originalNode: es.Function constructor( - public node: es.Function, + public node: es.ArrowFunctionExpression | es.FunctionExpression, public environment: Environment, context: Context, isPredefined?: boolean @@ -119,7 +122,7 @@ export default class Closure extends Callable { this.id = uniqueId(context) currentEnvironment(context).heap.add(this) let hasDeclaredName = false - if (this.node.type === 'FunctionDeclaration' && this.node.id !== null) { + if (this.node.type === 'FunctionExpression' && this.node.id != null) { this.functionName = this.node.id.name hasDeclaredName = true } else { diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 66e7e71ae..33abad31b 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -632,10 +632,11 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { control: Control ) { // Function declaration desugared into constant declaration. - const lambdaExpression: es.ArrowFunctionExpression = ast.blockArrowFunction( + const lambdaExpression: es.FunctionExpression = ast.functionExpression( command.params as es.Identifier[], command.body, - command.loc + command.loc, + command.id! ) const lambdaDeclaration: es.VariableDeclaration = ast.constantDeclaration( command.id!.name, @@ -761,6 +762,24 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { } }, + // Same as ArrowFunctionExpression, but has an `id` property to store the name of the function + FunctionExpression: function ( + command: es.FunctionExpression, + context: Context, + control: Control, + stash: Stash, + isPrelude: boolean + ) { + const closure: Closure = Closure.makeFromFunctionExpression( + command, + currentEnvironment(context), + context, + true, + isPrelude + ) + stash.push(closure) + }, + ArrowFunctionExpression: function ( command: es.ArrowFunctionExpression, context: Context, @@ -768,8 +787,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { stash: Stash, isPrelude: boolean ) { - // Reuses the Closure data structure from legacy interpreter - const closure: Closure = Closure.makeFromArrowFunction( + const closure: Closure = Closure.makeFromFunctionExpression( command, currentEnvironment(context), context, From df8bc0a32db99e7061a810458697fe17eea87072 Mon Sep 17 00:00:00 2001 From: CZX Date: Sun, 7 Apr 2024 13:21:56 +0800 Subject: [PATCH 4/8] Add function expression and fix closureToJS --- .../__snapshots__/cse-machine-heap.ts.snap | 4520 +++++++++++++++++ src/cse-machine/__tests__/cse-machine-heap.ts | 13 + .../__tests__/cse-machine-unique-id.ts | 14 + src/cse-machine/closure.ts | 7 +- src/cse-machine/utils.ts | 5 +- 5 files changed, 4556 insertions(+), 3 deletions(-) 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 2e954991b..fb52cf3fe 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap @@ -7410,3 +7410,4523 @@ EnvTree { }, } `; + +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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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, + }, + }, + "name": "f", + "type": "Identifier", + }, + "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 1010d941b..a0de93cbf 100644 --- a/src/cse-machine/__tests__/cse-machine-heap.ts +++ b/src/cse-machine/__tests__/cse-machine-heap.ts @@ -98,3 +98,16 @@ test('Variadic closures correctly add argument array to the function environment 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() +}) \ No newline at end of file diff --git a/src/cse-machine/__tests__/cse-machine-unique-id.ts b/src/cse-machine/__tests__/cse-machine-unique-id.ts index 7d93eb40e..30ddc2023 100644 --- a/src/cse-machine/__tests__/cse-machine-unique-id.ts +++ b/src/cse-machine/__tests__/cse-machine-unique-id.ts @@ -25,6 +25,20 @@ test("Context runtime's objectCount continues after prelude", async () => { 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` diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index 378f5cf0e..82308d2cd 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -26,8 +26,11 @@ const closureToJS = (value: Closure, context: Context, hasDeclaredName: boolean) const node = callExpression( // Use function name if there is one so environments that get created will have this name. // Else, treat the closure as a literal so it can get directly pushed into the stash next. - hasDeclaredName ? identifier(value.functionName) : literal(value as any), - args + hasDeclaredName + ? identifier(value.functionName, value.node.loc) + : literal(value as any, value.node.loc), + // Wrap arguments in a literal as well + args.map(arg => literal(arg)) ) return apply(context, node) } diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index fa8dc279a..43814f5da 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -213,8 +213,11 @@ export const envChanging = (command: ControlItem): boolean => { return ( type === 'Program' || type === 'BlockStatement' || + type === 'FunctionExpression' || type === 'ArrowFunctionExpression' || - (type === 'ExpressionStatement' && command.expression.type === 'ArrowFunctionExpression') + (type === 'ExpressionStatement' && + (command.expression.type === 'FunctionExpression' || + command.expression.type === 'ArrowFunctionExpression')) ) } else { const type = command.instrType From 7e37b8411ada7e9d7ee9f04c40d9932327a3910c Mon Sep 17 00:00:00 2001 From: CZX Date: Sun, 7 Apr 2024 14:23:29 +0800 Subject: [PATCH 5/8] Formatting --- src/cse-machine/__tests__/cse-machine-heap.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cse-machine/__tests__/cse-machine-heap.ts b/src/cse-machine/__tests__/cse-machine-heap.ts index a0de93cbf..ba5ac8b9c 100644 --- a/src/cse-machine/__tests__/cse-machine-heap.ts +++ b/src/cse-machine/__tests__/cse-machine-heap.ts @@ -108,6 +108,6 @@ test('apply_in_underlying_javascript works correctly and adds objects to heaps', return x => x; } apply_in_underlying_javascript(f, list(0)); - `, + ` ).toMatchSnapshot() -}) \ No newline at end of file +}) From cd6d1e6c6ae933e58079805b42deeb32f9710552 Mon Sep 17 00:00:00 2001 From: CZX Date: Mon, 8 Apr 2024 21:42:11 +0800 Subject: [PATCH 6/8] Revert function expression changes, add new `declaredName` prop to closures --- .../__snapshots__/cse-machine-heap.ts.snap | 24 ++--- src/cse-machine/closure.ts | 87 ++++++++++--------- src/cse-machine/interpreter.ts | 57 +----------- src/cse-machine/utils.ts | 13 +-- src/mocks/context.ts | 6 +- 5 files changed, 71 insertions(+), 116 deletions(-) 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 fb52cf3fe..d571e7912 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-heap.ts.snap @@ -7441,8 +7441,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, @@ -8285,8 +8285,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, @@ -9228,8 +9228,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, @@ -10190,8 +10190,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, @@ -10942,8 +10942,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, @@ -11193,8 +11193,8 @@ EnvTree { "line": 2, }, }, - "name": "f", - "type": "Identifier", + "type": "Literal", + "value": [Function], }, "loc": undefined, "optional": false, diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index 82308d2cd..ae6bc94b6 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -9,30 +9,38 @@ import { uniqueId } from '../cse-machine/utils' import { Context, Environment, StatementSequence, Value } from '../types' -import { - blockArrowFunction, - blockStatement, - callExpression, - functionExpression, - identifier, - literal, - returnStatement -} from '../utils/ast/astCreator' -import { apply } from './interpreter' +import * as ast from '../utils/ast/astCreator' +import { Control, Stash, generateCSEMachineStateStream } from './interpreter' +import { envInstr } from './instrCreator' -const closureToJS = (value: Closure, context: Context, hasDeclaredName: boolean) => { +const closureToJS = (value: Closure, context: Context) => { function DummyClass(this: Closure) { const args: Value[] = [...arguments] - const node = callExpression( - // Use function name if there is one so environments that get created will have this name. - // Else, treat the closure as a literal so it can get directly pushed into the stash next. - hasDeclaredName - ? identifier(value.functionName, value.node.loc) - : literal(value as any, value.node.loc), - // Wrap arguments in a literal as well - args.map(arg => literal(arg)) + 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 ) - return apply(context, node) + // 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 @@ -62,8 +70,8 @@ class Callable extends Function { * Models function value in the CSE machine. */ export default class Closure extends Callable { - public static makeFromFunctionExpression( - node: es.ArrowFunctionExpression | es.FunctionExpression, + public static makeFromArrowFunction( + node: es.ArrowFunctionExpression, environment: Environment, context: Context, dummyReturn?: boolean, @@ -71,21 +79,19 @@ export default class Closure extends Callable { ) { const functionBody: es.BlockStatement | StatementSequence = !isBlockStatement(node.body) && !isStatementSequence(node.body) - ? blockStatement([returnStatement(node.body, node.body.loc)], node.body.loc) + ? ast.blockStatement([ast.returnStatement(node.body, node.body.loc)], node.body.loc) : dummyReturn && !hasReturnStatement(node.body) - ? blockStatement( + ? ast.blockStatement( [ ...node.body.body, - returnStatement(identifier('undefined', node.body.loc), node.body.loc) + ast.returnStatement(ast.identifier('undefined', node.body.loc), node.body.loc) ], node.body.loc ) : node.body const closure = new Closure( - node.type === 'FunctionExpression' - ? functionExpression(node.params as es.Identifier[], functionBody, node.loc, node.id!) - : blockArrowFunction(node.params as es.Identifier[], functionBody, node.loc), + ast.blockArrowFunction(node.params as es.Identifier[], functionBody, node.loc), environment, context, predefined @@ -100,7 +106,10 @@ export default class Closure extends Callable { /** Unique ID defined for closure */ public readonly id: string - /** String representation of the closure */ + /** 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 */ @@ -113,7 +122,7 @@ export default class Closure extends Callable { public originalNode: es.Function constructor( - public node: es.ArrowFunctionExpression | es.FunctionExpression, + public node: es.ArrowFunctionExpression, public environment: Environment, context: Context, isPredefined?: boolean @@ -124,18 +133,12 @@ export default class Closure extends Callable { this.originalNode = node this.id = uniqueId(context) currentEnvironment(context).heap.add(this) - let hasDeclaredName = false - if (this.node.type === 'FunctionExpression' && this.node.id != null) { - this.functionName = this.node.id.name - hasDeclaredName = true - } else { - this.functionName = - (this.node.params.length === 1 ? '' : '(') + - this.node.params.map((o: es.Identifier) => o.name).join(', ') + - (this.node.params.length === 1 ? '' : ')') + - ' => ...' - } - const funJS = closureToJS(this, context, hasDeclaredName) + this.functionName = + (this.node.params.length === 1 ? '' : '(') + + this.node.params.map((o: es.Identifier) => o.name).join(', ') + + (this.node.params.length === 1 ? '' : ')') + + ' => ...' + const funJS = closureToJS(this, context) this.fun = funJS this.predefined = isPredefined ?? false } diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index 33abad31b..a7f3f6a7f 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -153,38 +153,6 @@ export class Stash extends Stack { } } -/** - * Evaluates the given call expression and returns the result. If the callee is a closure, - * the given context may be mutated and more environments will be created. - * - * @param context The context to evaluate the program in. - * @param node The call expression to evaluate. - * @returns The result of running the CSE machine. - */ -export function apply(context: Context, node: es.CallExpression) { - // 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(instr.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() -} - /** * Function to be called when a program is to be interpreted using * the explicit control evaluator. @@ -632,11 +600,10 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { control: Control ) { // Function declaration desugared into constant declaration. - const lambdaExpression: es.FunctionExpression = ast.functionExpression( + const lambdaExpression: es.ArrowFunctionExpression = ast.blockArrowFunction( command.params as es.Identifier[], command.body, - command.loc, - command.id! + command.loc ) const lambdaDeclaration: es.VariableDeclaration = ast.constantDeclaration( command.id!.name, @@ -762,24 +729,6 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { } }, - // Same as ArrowFunctionExpression, but has an `id` property to store the name of the function - FunctionExpression: function ( - command: es.FunctionExpression, - context: Context, - control: Control, - stash: Stash, - isPrelude: boolean - ) { - const closure: Closure = Closure.makeFromFunctionExpression( - command, - currentEnvironment(context), - context, - true, - isPrelude - ) - stash.push(closure) - }, - ArrowFunctionExpression: function ( command: es.ArrowFunctionExpression, context: Context, @@ -787,7 +736,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { stash: Stash, isPrelude: boolean ) { - const closure: Closure = Closure.makeFromFunctionExpression( + const closure: Closure = Closure.makeFromArrowFunction( command, currentEnvironment(context), context, diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 43814f5da..0792d3197 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -213,11 +213,8 @@ export const envChanging = (command: ControlItem): boolean => { return ( type === 'Program' || type === 'BlockStatement' || - type === 'FunctionExpression' || type === 'ArrowFunctionExpression' || - (type === 'ExpressionStatement' && - (command.expression.type === 'FunctionExpression' || - command.expression.type === 'ArrowFunctionExpression')) + (type === 'ExpressionStatement' && command.expression.type === 'ArrowFunctionExpression') ) } else { const type = command.instrType @@ -258,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(), @@ -401,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 7ec37d213..7e19650ad 100644 --- a/src/mocks/context.ts +++ b/src/mocks/context.ts @@ -70,15 +70,15 @@ export function mockClosure(cseMachineClosure?: boolean): Closure | OldClosure { const context = createContext() 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 ) From 7954f409ddcc9fa82587693194b28b9661e98638 Mon Sep 17 00:00:00 2001 From: CZX Date: Mon, 8 Apr 2024 22:09:04 +0800 Subject: [PATCH 7/8] Fix function name for variadic closures --- src/cse-machine/closure.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/cse-machine/closure.ts b/src/cse-machine/closure.ts index ae6bc94b6..42084e07a 100644 --- a/src/cse-machine/closure.ts +++ b/src/cse-machine/closure.ts @@ -133,11 +133,14 @@ export default class Closure extends Callable { this.originalNode = node this.id = uniqueId(context) currentEnvironment(context).heap.add(this) - this.functionName = - (this.node.params.length === 1 ? '' : '(') + - this.node.params.map((o: es.Identifier) => o.name).join(', ') + - (this.node.params.length === 1 ? '' : ')') + - ' => ...' + 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 From 77f2cdc03fd7f6d3cd05d235a34197fe910e046c Mon Sep 17 00:00:00 2001 From: henz Date: Tue, 9 Apr 2024 08:01:11 +0800 Subject: [PATCH 8/8] bumping version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ac75816f8..5e2acc4f0 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": [