From 46317e33c499a7bc3c08a5acd1380ff8605a1420 Mon Sep 17 00:00:00 2001 From: Kyriel Abad Date: Thu, 21 Mar 2024 21:09:39 +0800 Subject: [PATCH] Update parser to new scm-slang parser (#1584) * Prepare scheme files for new parser * update JS version for js-slang * proper formatting of files * fix separate program environments across REPL eval calls * remove logger messages from interpreter * Enable variadic continuations for future * Remove Infinity and NaN representation from Scheme * Change scm-slang to follow forked version * update scm-slang to newest parser * resolve linting problems * add test cases to verify proper chapter validation, decoded representation * update scm-slang * Move scheme-specific tests to scm-slang * make scheme test names more obvious * Revert "Move scheme-specific tests to scm-slang" This reverts commit 42e184e540fa5fbdf6f8fa4fc3ea970fc45b1a2c. * move scm-slang to dedicated alt-lang folder * remove duplicate code between scm-slang and js-slang * ignore alt langs coverage --------- Co-authored-by: Martin Henz --- .eslintignore | 2 +- .gitmodules | 6 +- .prettierignore | 2 +- package.json | 2 +- src/__tests__/__snapshots__/scmlib.ts.snap | 1535 ----------------- src/__tests__/scmlib.ts | 1186 ------------- .../scheme/__tests__/scheme-encode-decode.ts | 67 + .../scheme/__tests__/scheme-parser.ts} | 44 +- src/alt-langs/scheme/scm-slang | 1 + src/createContext.ts | 193 ++- .../__snapshots__/cse-machine-callcc.ts.snap | 44 +- .../__tests__/cse-machine-callcc.ts | 20 +- src/cse-machine/continuations.ts | 3 +- src/cse-machine/instrCreator.ts | 3 +- src/cse-machine/interpreter.ts | 63 +- src/cse-machine/types.ts | 4 +- src/cse-machine/utils.ts | 7 + src/parser/__tests__/scheme-encode-decode.ts | 45 - src/parser/scheme/index.ts | 88 +- src/scm-slang | 1 - tsconfig.json | 2 +- 21 files changed, 387 insertions(+), 2931 deletions(-) delete mode 100644 src/__tests__/__snapshots__/scmlib.ts.snap delete mode 100644 src/__tests__/scmlib.ts create mode 100644 src/alt-langs/scheme/__tests__/scheme-encode-decode.ts rename src/{parser/__tests__/scheme.ts => alt-langs/scheme/__tests__/scheme-parser.ts} (62%) create mode 160000 src/alt-langs/scheme/scm-slang delete mode 100644 src/parser/__tests__/scheme-encode-decode.ts delete mode 160000 src/scm-slang diff --git a/.eslintignore b/.eslintignore index a20bc161b..2e9a9a8e1 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,3 @@ /dist/ -/src/scm-slang/ +/src/alt-langs/ /src/py-slang/ diff --git a/.gitmodules b/.gitmodules index 431b95c90..b39c03d73 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,6 @@ -[submodule "src/scm-slang"] - path = src/scm-slang - url = https://github.com/source-academy/scm-slang.git +[submodule "src/alt-langs/scheme/scm-slang"] + path = src/alt-langs/scheme/scm-slang + url = https://github.com/source-academy/scm-slang [submodule "src/py-slang"] path = src/py-slang url = https://github.com/source-academy/py-slang diff --git a/.prettierignore b/.prettierignore index 86f590c00..cb1a50835 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,3 @@ -/src/scm-slang/ +/src/alt-langs/ /src/py-slang/ /src/**/__tests__/**/__snapshots__ \ No newline at end of file diff --git a/package.json b/package.json index d264d489d..796b3a9fe 100644 --- a/package.json +++ b/package.json @@ -114,7 +114,7 @@ "/node_modules/", "/src/typings/", "/src/utils/testing.ts", - "/src/scm-slang", + "/src/alt-langs", "/src/py-slang/" ], "reporters": [ diff --git a/src/__tests__/__snapshots__/scmlib.ts.snap b/src/__tests__/__snapshots__/scmlib.ts.snap deleted file mode 100644 index 6b4087707..000000000 --- a/src/__tests__/__snapshots__/scmlib.ts.snap +++ /dev/null @@ -1,1535 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Builtins work as expected 0: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? \\"a\\" \\"a\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 1: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? \\"a\\" \\"b\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 2: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eq? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 3: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(eqv? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 4: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(equal? 1 \\"1\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 5: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(equal? '(1 2 3) '(1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 6: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(+)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 7: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(+ 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 6, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 8: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(- 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 9: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(- 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 10: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(*)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 11: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(* 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 6, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 12: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(/ 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0.5, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 13: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(= 1 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 14: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 15: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(< 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 16: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(< 1 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 17: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(> 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 18: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(> 3 2 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 19: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(<= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 20: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(<= 1 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 21: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 22: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 3 2 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 23: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(>= 3 2 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 24: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 25: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number? \\"1\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 26: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(real? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 27: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(integer? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 28: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(integer? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 29: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 30: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 31: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer? 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 32: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(zero? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 33: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(zero? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 34: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(positive? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 35: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(positive? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 36: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(negative? -1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 37: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(negative? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 38: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(odd? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 39: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(odd? 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 40: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(even? 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 41: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(even? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 42: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(max 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 43: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(max)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -Infinity, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 44: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(min)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": Infinity, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 45: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(min 1 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 46: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(abs -1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 47: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(abs 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 48: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 49: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 2.5)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 50: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(quotient 5 -2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": -2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 51: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(modulo 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 52: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(modulo 5 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 53: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(remainder 5 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 54: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(remainder 5 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 55: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(gcd 32 4110 22)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 56: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(lcm 32 4110 22)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 723360, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 57: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(floor 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 58: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(ceiling 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 59: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(truncate 1.6)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 60: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(truncate 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 61: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(round 1.1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 62: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(round 1.6)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 63: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(square 4)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 16, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 64: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(exact-integer-sqrt 16)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 4, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 65: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(expt 2 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 8, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 66: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(number->string 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "1", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 67: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(boolean? (= 0 0))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 68: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(boolean? 0)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 69: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(and #t #t #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 70: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(and #t #f #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 71: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(or #f #f #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 72: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(or #f #f #f)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 73: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(not #t)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 74: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(not #f)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 75: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 76: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 77: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(make-string 3)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": " ", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 78: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(make-string 3 \\"a\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "aaa", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 79: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string \\"hi\\" \\" \\" \\"mum\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "hi mum", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 80: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-length \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 81: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-ref \\"abc\\" 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "b", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 82: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 83: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 84: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 87: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 88: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 89: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 90: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string<=? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 91: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"abc\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 92: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"def\\" \\"abc\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 93: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string>=? \\"abc\\" \\"def\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 94: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(substring \\"abc\\" 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "bc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 95: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(substring \\"abc\\" 1 2)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "b", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 96: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string-append \\"a\\" \\"b\\" \\"c\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 97: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(string->number \\"123\\")", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 123, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 98: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(procedure? (lambda (a) a))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 99: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(procedure? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 100: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(pair? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 101: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(pair? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 102: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(car (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 103: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(cdr (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 104: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list? (list 1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 105: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 106: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(null? (list))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 107: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(null? (cons 1 2))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 108: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(length (list 1 2 3))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 3, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 109: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(length (list))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 0, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 110: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list-ref (list 1 2 3) 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 2, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 111: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list->string '(\\"a\\" \\"b\\" \\"c\\"))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 112: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(list->string (string->list \\"abc\\"))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": "abc", - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 113: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(promise? (delay 1))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": true, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 114: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(promise? 1)", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": false, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 115: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(force (delay 1))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 1, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 116: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(apply + 1 2 3 4 '(5 6 7 8))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 36, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; - -exports[`Builtins work as expected 117: expectResult 1`] = ` -Object { - "alertResult": Array [], - "code": "(apply + '(5 6 7 8))", - "displayResult": Array [], - "numErrors": 0, - "parsedErrors": "", - "result": 26, - "resultStatus": "finished", - "visualiseListResult": Array [], -} -`; diff --git a/src/__tests__/scmlib.ts b/src/__tests__/scmlib.ts deleted file mode 100644 index e7f87b6f6..000000000 --- a/src/__tests__/scmlib.ts +++ /dev/null @@ -1,1186 +0,0 @@ -import { Chapter, Value } from '../types' -import { stripIndent } from '../utils/formatters' -import { expectResult, snapshotFailure } from '../utils/testing' - -test.each([ - // Scheme 1 - - // Equality predicates - [ - Chapter.SCHEME_1, - ` - (eq? "a" "a") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (eq? "a" "b") - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (eq? '(1 2 3) '(1 2 3)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (eqv? '(1 2 3) '(1 2 3)) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (equal? 1 "1") - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (equal? '(1 2 3) '(1 2 3)) - `, - true, - true - ], - - // Basic arithmetic - [ - Chapter.SCHEME_1, - ` - (+) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (+ 1 2 3) - `, - true, - 6 - ], - - [ - Chapter.SCHEME_1, - ` - (- 1) - `, - true, - -1 - ], - - [ - Chapter.SCHEME_1, - ` - (- 1 2) - `, - true, - -1 - ], - - [ - Chapter.SCHEME_1, - ` - (*) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (* 1 2 3) - `, - true, - 6 - ], - - [ - Chapter.SCHEME_1, - ` - (/ 1 2) - `, - true, - 0.5 - ], - - // Arithmetic comparisons - - [ - Chapter.SCHEME_1, - ` - (= 1 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (= 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (< 1 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (< 1 2 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (> 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (> 3 2 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (<= 1 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (<= 1 2 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (>= 1 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (>= 3 2 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (>= 3 2 2) - `, - true, - true - ], - - // Math functions - - [ - Chapter.SCHEME_1, - ` - (number? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (number? "1") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (real? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (integer? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (integer? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (exact? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer? 1.1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (zero? 0) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (zero? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (positive? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (positive? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (negative? -1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (negative? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (odd? 1) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (odd? 2) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (even? 2) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (even? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (max 1 2 3) - `, - true, - 3 - ], - - [ - Chapter.SCHEME_1, - ` - (max) - `, - true, - -Infinity - ], - - [ - Chapter.SCHEME_1, - ` - (min) - `, - true, - Infinity - ], - - [ - Chapter.SCHEME_1, - ` - (min 1 2 3) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (abs -1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (abs 1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 2) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 2.5) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (quotient 5 -2) - `, - true, - -2 - ], - - [ - Chapter.SCHEME_1, - ` - (modulo 5 2) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (modulo 5 1) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (remainder 5 2) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (remainder 5 1) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_1, - ` - (gcd 32 4110 22) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (lcm 32 4110 22) - `, - true, - 723360 - ], - - [ - Chapter.SCHEME_1, - ` - (floor 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (ceiling 1.1) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (truncate 1.6) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (truncate 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (round 1.1) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_1, - ` - (round 1.6) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_1, - ` - (square 4) - `, - true, - 16 - ], - - [ - Chapter.SCHEME_1, - ` - (exact-integer-sqrt 16) - `, - true, - 4 - ], - - [ - Chapter.SCHEME_1, - ` - (expt 2 3) - `, - true, - 8 - ], - - [ - Chapter.SCHEME_1, - ` - (number->string 1) - `, - true, - '1' - ], - - // Booleans - - [ - Chapter.SCHEME_1, - ` - (boolean? (= 0 0)) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (boolean? 0) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (and #t #t #t) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (and #t #f #t) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (or #f #f #t) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (or #f #f #f) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (not #t) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (not #f) - `, - true, - true - ], - - // Strings - - [ - Chapter.SCHEME_1, - ` - (string? "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (make-string 3) - `, - true, - ' ' - ], - - [ - Chapter.SCHEME_1, - ` - (make-string 3 "a") - `, - true, - 'aaa' - ], - - [ - Chapter.SCHEME_1, - ` - (string "hi" " " "mum") - `, - true, - 'hi mum' - ], - - [ - Chapter.SCHEME_1, - ` - (string-length "abc") - `, - true, - 3 - ], - - [ - Chapter.SCHEME_1, - ` - (string-ref "abc" 1) - `, - true, - 'b' - ], - - [ - Chapter.SCHEME_1, - ` - (string=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string=? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string>? "def" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "abc" "def") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string<=? "def" "abc") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "abc" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "def" "abc") - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (string>=? "abc" "def") - `, - true, - false - ], - - [ - Chapter.SCHEME_1, - ` - (substring "abc" 1) - `, - true, - 'bc' - ], - - [ - Chapter.SCHEME_1, - ` - (substring "abc" 1 2) - `, - true, - 'b' - ], - - [ - Chapter.SCHEME_1, - ` - (string-append "a" "b" "c") - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_1, - ` - (string->number "123") - `, - true, - 123 - ], - - // Procedures - - [ - Chapter.SCHEME_1, - ` - (procedure? (lambda (a) a)) - `, - true, - true - ], - - [ - Chapter.SCHEME_1, - ` - (procedure? 1) - `, - true, - false - ], - - // Scheme 2 - - // Pairs - - [ - Chapter.SCHEME_2, - ` - (pair? (cons 1 2)) - `, - true, - true - ], - - // FAILS 7 BELOW - - [ - Chapter.SCHEME_2, - ` - (pair? 1) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (car (cons 1 2)) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_2, - ` - (cdr (cons 1 2)) - `, - true, - 2 - ], - - [ - Chapter.SCHEME_2, - ` - (list? (list 1 2 3)) - `, - true, - true - ], - - [ - Chapter.SCHEME_2, - ` - (list? (cons 1 2)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (null? (list)) - `, - true, - true - ], - - [ - Chapter.SCHEME_2, - ` - (null? (cons 1 2)) - `, - true, - false - ], - - [ - Chapter.SCHEME_2, - ` - (length (list 1 2 3)) - `, - true, - 3 - ], - - [ - Chapter.SCHEME_2, - ` - (length (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (list-ref (list 1 2 3) 1) - `, - true, - 2 - ], - - /* FAILS. Issue with the interepreter detecting wrong arity of lambda functions: 0 - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (+ a b)) 0 (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (fold (lambda (a b) (+ a b)) 0 (list 1)) - `, - true, - 1 - ], - - [ - Chapter.SCHEME_2, - ` - (fold-right (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'cba' - ], - - [ - Chapter.SCHEME_2, - ` - (fold-right (lambda (a b) (+ a b)) 0 (list)) - `, - true, - 0 - ], - - [ - Chapter.SCHEME_2, - ` - (reduce (lambda (a b) (string-append a b)) "" (list "a" "b" "c")) - `, - true, - 'abc' - ], - - */ - - // Lists - - // Symbols - - // Strings - - [ - Chapter.SCHEME_2, - ` - (list->string '("a" "b" "c")) - `, - true, - 'abc' - ], - - [ - Chapter.SCHEME_2, - ` - (list->string (string->list "abc")) - `, - true, - 'abc' - ], - - // Scheme 3 - - // Pair mutation - - // List mutation - - // Promises - - [ - Chapter.SCHEME_3, - ` - (promise? (delay 1)) - `, - true, - true - ], - - [ - Chapter.SCHEME_3, - ` - (promise? 1) - `, - true, - false - ], - - /* FAILS. Some issues involving the interpreter detecting wrong arity of lambda functions: 0 - - [ - Chapter.SCHEME_3, - ` - (promise? (lambda (a) a)) - `, - true, - false - ], - - */ - - [ - Chapter.SCHEME_3, - ` - (force (delay 1)) - `, - true, - 1 - ], - - // Scheme 4 - - [ - Chapter.SCHEME_4, - ` - (apply + 1 2 3 4 '(5 6 7 8)) - `, - true, - 36 - ], - - [ - Chapter.SCHEME_4, - ` - (apply + '(5 6 7 8)) - `, - true, - 26 - ] -] as [Chapter, string, boolean, Value][])( - 'Builtins work as expected %#', - (chapter: Chapter, snippet: string, passing: boolean, returnValue: Value) => { - if (passing) { - return expectResult(stripIndent(snippet), { - chapter, - native: true - }).toEqual(returnValue) - } else { - return snapshotFailure(stripIndent(snippet), { chapter }, 'fails') - } - } -) diff --git a/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts new file mode 100644 index 000000000..b8f34f452 --- /dev/null +++ b/src/alt-langs/scheme/__tests__/scheme-encode-decode.ts @@ -0,0 +1,67 @@ +import { Node } from 'estree' + +import { UnassignedVariable } from '../../../errors/errors' +import { decode, encode } from '../scm-slang/src' +import { cons, set$45$cdr$33$ } from '../scm-slang/src/stdlib/base' +import { dummyExpression } from '../../../utils/dummyAstCreator' +import { decodeError, decodeValue } from '../../../parser/scheme' + +describe('Scheme encoder and decoder', () => { + it('encoder and decoder are proper inverses of one another', () => { + const values = [ + 'hello', + 'hello world', + 'scheme->JavaScript', + 'hello world!!', + 'true', + 'false', + 'null', + '1', + '๐Ÿ˜€' + ] + for (const value of values) { + expect(decode(encode(value))).toEqual(value) + } + }) + + it('decoder ignores primitives', () => { + const values = [1, 2, 3, true, false, null] + for (const value of values) { + expect(decodeValue(value)).toEqual(value) + } + }) + + it('decoder works on function toString representation', () => { + // Dummy function to test + function $65$() {} + expect(decodeValue($65$).toString()).toEqual(`function A() { }`) + }) + + it('decoder works on circular lists', () => { + function $65$() {} + const pair = cons($65$, 'placeholder') + set$45$cdr$33$(pair, pair) + expect(decodeValue(pair).toString()).toEqual(`function A() { },`) + }) + + it('decoder works on pairs', () => { + // and in doing so, works on pairs, lists, etc... + function $65$() {} + const pair = cons($65$, 'placeholder') + expect(decodeValue(pair).toString()).toEqual(`function A() { },placeholder`) + }) + + it('decoder works on vectors', () => { + // scheme doesn't support optimisation of circular vectors yet + function $65$() {} + const vector = [$65$, 2, 3] + expect(decodeValue(vector).toString()).toEqual(`function A() { },2,3`) + }) + + it('decodes runtime errors properly', () => { + const token = `๐Ÿ˜€` + const dummyNode: Node = dummyExpression() + const error = new UnassignedVariable(encode(token), dummyNode) + expect(decodeError(error).elaborate()).toContain(`๐Ÿ˜€`) + }) +}) diff --git a/src/parser/__tests__/scheme.ts b/src/alt-langs/scheme/__tests__/scheme-parser.ts similarity index 62% rename from src/parser/__tests__/scheme.ts rename to src/alt-langs/scheme/__tests__/scheme-parser.ts index 794041a1e..89da8bbe5 100644 --- a/src/parser/__tests__/scheme.ts +++ b/src/alt-langs/scheme/__tests__/scheme-parser.ts @@ -1,9 +1,12 @@ -import { parseError } from '../..' -import { mockContext } from '../../mocks/context' -import { Chapter } from '../../types' -import { SchemeParser } from '../scheme' - -const parser = new SchemeParser(Chapter.SCHEME_1) +import { parseError } from '../../..' +import { mockContext } from '../../../mocks/context' +import { Chapter } from '../../../types' +import { SchemeParser } from '../../../parser/scheme' + +const parser_1 = new SchemeParser(Chapter.SCHEME_1) +const parser_2 = new SchemeParser(Chapter.SCHEME_2) +const parser_3 = new SchemeParser(Chapter.SCHEME_3) +const parser_4 = new SchemeParser(Chapter.SCHEME_4) const parser_full = new SchemeParser(Chapter.FULL_SCHEME) let context = mockContext(Chapter.SCHEME_1) let context_full = mockContext(Chapter.FULL_SCHEME) @@ -15,7 +18,7 @@ beforeEach(() => { describe('Scheme parser', () => { it('represents itself correctly', () => { - expect(parser.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) + expect(parser_1.toString()).toMatchInlineSnapshot(`"SchemeParser{chapter: 1}"`) }) it('throws error if given chapter is wrong', () => { @@ -26,13 +29,13 @@ describe('Scheme parser', () => { it('throws errors if option throwOnError is selected + parse error is encountered', () => { const code = `(hello))` - expect(() => parser.parse(code, context, undefined, true)).toThrow("Unexpected ')'") + expect(() => parser_1.parse(code, context, undefined, true)).toThrow("Unexpected ')'") }) it('formats tokenizer errors correctly', () => { const code = `(hello))` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining("Unexpected ')'") }) ) @@ -41,35 +44,25 @@ describe('Scheme parser', () => { it('formats parser errors correctly', () => { const code = `(define (f x)` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining('Unexpected EOF') }) ) }) - it('allows usage of builtins/preludes', () => { - const code = ` - (+ 1 2 3) - (gcd 10 15) - ` - - parser.parse(code, context) - expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) - }) - it('allows usage of imports/modules', () => { const code = `(import "rune" (show heart)) (show heart) ` - parser.parse(code, context) + parser_1.parse(code, context) expect(parseError(context.errors)).toMatchInlineSnapshot(`""`) }) it('disallows syntax for higher chapters', () => { const code = `'(1 2 3)` - parser.parse(code, context) + parser_1.parse(code, context) expect(context.errors.slice(-1)[0]).toMatchObject( expect.objectContaining({ message: expect.stringContaining("Syntax ''' not allowed at Scheme ยง1") @@ -77,9 +70,14 @@ describe('Scheme parser', () => { ) }) - it('allows syntax for lower chapters', () => { + it('allows syntax for chapters of required or higher chapter', () => { const code = `'(1 2 3)` + // regardless of how many times we parse this code in the same context, + // there should be no errors in the context as long as the chapter is 2 or higher + parser_2.parse(code, context_full) + parser_3.parse(code, context_full) + parser_4.parse(code, context_full) parser_full.parse(code, context_full) expect(parseError(context_full.errors)).toMatchInlineSnapshot(`""`) }) diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang new file mode 160000 index 000000000..ad3b2e39c --- /dev/null +++ b/src/alt-langs/scheme/scm-slang @@ -0,0 +1 @@ +Subproject commit ad3b2e39c6c9cd944494bc6abf0d8fbaa11ee59d diff --git a/src/createContext.ts b/src/createContext.ts index 42c4a5563..d1cf61275 100644 --- a/src/createContext.ts +++ b/src/createContext.ts @@ -1,10 +1,10 @@ // Variable determining chapter of Source is contained in this file. +import * as scheme_libs from './alt-langs/scheme/scm-slang/src/stdlib/source-scheme-library' import { GLOBAL, JSSLANG_PROPERTIES } from './constants' import { call_with_current_continuation } from './cse-machine/continuations' import * as gpu_lib from './gpu/lib' import { AsyncScheduler } from './schedulers' -import * as scheme_libs from './scm-slang/src/stdlib/source-scheme-library' import { lazyListPrelude } from './stdlib/lazyList.prelude' import * as list from './stdlib/list' import { list_to_vector } from './stdlib/list' @@ -415,50 +415,116 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn // Introduction to mutable values, streams // Scheme pair mutation - defineBuiltin(context, 'set$45$car$33$(pair, val)', scheme_libs.set_carB) - defineBuiltin(context, 'set$45$cdr$33$(pair, val)', scheme_libs.set_cdrB) + defineBuiltin(context, 'set$45$car$33$(pair, val)', scheme_libs.set$45$car$33$) + defineBuiltin(context, 'set$45$cdr$33$(pair, val)', scheme_libs.set$45$cdr$33$) // Scheme list mutation - defineBuiltin(context, 'list$45$set$33$(xs, n, val)', scheme_libs.list_setB) + defineBuiltin(context, 'list$45$set$33$(xs, n, val)', scheme_libs.list$45$set$33$) //defineBuiltin(context, 'filter$33$(pred, xs)', scheme_libs.filterB); // Scheme promises - defineBuiltin(context, 'promise$63$()', scheme_libs.promiseQ) + defineBuiltin(context, 'make$45$promise(thunk)', scheme_libs.make$45$promise) + defineBuiltin(context, 'promise$63$(p)', scheme_libs.promise$63$) defineBuiltin(context, 'force(p)', scheme_libs.force) + // Scheme vectors + defineBuiltin(context, 'vector(...vals)', scheme_libs.vector, 0) + defineBuiltin(context, 'make$45$vector(n, val)', scheme_libs.make$45$vector, 1) + + defineBuiltin(context, 'vector$63$(v)', scheme_libs.vector$63$) + + defineBuiltin(context, 'vector$45$length(v)', scheme_libs.vector$45$length) + defineBuiltin(context, 'vector$45$empty$63$(v)', scheme_libs.vector$45$empty$63$) + + defineBuiltin(context, 'vector$45$ref(v, k)', scheme_libs.vector$45$ref) + + defineBuiltin(context, 'vector$45$set$33$(v, k, val)', scheme_libs.vector$45$set$33$) + defineBuiltin( + context, + 'vector$45$fill$33$(v, val, start, end)', + scheme_libs.vector$45$fill$33$, + 2 + ) + defineBuiltin(context, 'list$45$$62$vector(xs)', scheme_libs.list$45$$62$vector) + case Chapter.SCHEME_2: + // Splicing builtin resolvers + // defineBuiltin(context, '$36$make$45$splice(expr)', scheme_libs.make_splice) + // defineBuiltin(context, '$36$resolve$45$splice(xs)', scheme_libs.resolve_splice) + // Scheme pairs defineBuiltin(context, 'cons(left, right)', scheme_libs.cons) - defineBuiltin(context, 'pair$63$(val)', scheme_libs.pairQ) + defineBuiltin(context, 'xcons(right, left)', scheme_libs.xcons) + defineBuiltin(context, 'pair$63$(val)', scheme_libs.pair$63$) + defineBuiltin(context, 'not$45$pair$63$(val)', scheme_libs.not$45$pair$63$) defineBuiltin(context, 'car(xs)', scheme_libs.car) defineBuiltin(context, 'cdr(xs)', scheme_libs.cdr) // Scheme lists - defineBuiltin(context, 'make$45$list(n, val)', scheme_libs.make_list, 1) - defineBuiltin(context, 'list(...values)', scheme_libs.list, 0) - defineBuiltin(context, 'list$63$(val)', scheme_libs.listQ) - defineBuiltin(context, 'null$63$(val)', scheme_libs.nullQ) + defineBuiltin(context, 'list(...vals)', scheme_libs.list, 0) + defineBuiltin(context, 'list$42$(...vals)', scheme_libs.list$42$, 1) + defineBuiltin(context, 'cons$42$(...vals)', scheme_libs.cons$42$, 1) + defineBuiltin(context, 'circular$45$list(...vals)', scheme_libs.circular$45$list, 0) + defineBuiltin(context, 'make$45$list(n, val)', scheme_libs.make$45$list, 1) + + defineBuiltin(context, 'circular$45$list$63$(val)', scheme_libs.circular$45$list$63$) + defineBuiltin(context, 'proper$45$list$63$(val)', scheme_libs.proper$45$list$63$) + defineBuiltin(context, 'dotted$45$list$63$(val)', scheme_libs.dotted$45$list$63$) + defineBuiltin(context, 'null$63$(val)', scheme_libs.null$63$) + defineBuiltin(context, 'null$45$list$63$(val)', scheme_libs.null$45$list$63$) + defineBuiltin(context, 'list$63$(val)', scheme_libs.list$63$) + + defineBuiltin(context, 'list$45$tabulate(n, f)', scheme_libs.list$45$tabulate) + defineBuiltin(context, 'list$45$tail(xs, n)', scheme_libs.list$45$tail) + defineBuiltin(context, 'list$45$ref(xs, k)', scheme_libs.list$45$ref) + defineBuiltin(context, 'last(xs)', scheme_libs.last) + defineBuiltin(context, 'last$45$pair(xs)', scheme_libs.last$45$pair) + + defineBuiltin(context, 'first(xs)', scheme_libs.first) + defineBuiltin(context, 'second(xs)', scheme_libs.second) + defineBuiltin(context, 'third(xs)', scheme_libs.third) + defineBuiltin(context, 'fourth(xs)', scheme_libs.fourth) + defineBuiltin(context, 'fifth(xs)', scheme_libs.fifth) + defineBuiltin(context, 'sixth(xs)', scheme_libs.sixth) + defineBuiltin(context, 'seventh(xs)', scheme_libs.seventh) + defineBuiltin(context, 'eighth(xs)', scheme_libs.eighth) + defineBuiltin(context, 'ninth(xs)', scheme_libs.ninth) + defineBuiltin(context, 'tenth(xs)', scheme_libs.tenth) + + defineBuiltin(context, 'filter(pred, xs)', scheme_libs.filter) + defineBuiltin(context, 'map(f, ...xss)', scheme_libs.map, 2) + defineBuiltin(context, 'fold(f, init, ...xss)', scheme_libs.fold, 3) + defineBuiltin(context, 'fold$45$right(f, init, ...xss)', scheme_libs.fold$45$right, 3) + defineBuiltin(context, 'fold$45$left(f, init, ...xss)', scheme_libs.fold$45$left, 3) + defineBuiltin(context, 'reduce(f, ridentity, xs)', scheme_libs.reduce) + defineBuiltin(context, 'reduce$45$right(f, ridentity, xs)', scheme_libs.reduce$45$right) + defineBuiltin(context, 'reduce$45$left(f, ridentity, xs)', scheme_libs.reduce$45$left) + + defineBuiltin(context, 'any(xs)', scheme_libs.any) + defineBuiltin(context, 'list$45$copy(xs)', scheme_libs.list$45$copy) defineBuiltin(context, 'length(xs)', scheme_libs.length) - defineBuiltin(context, 'append(...xs)', scheme_libs.append, 0) + defineBuiltin(context, 'length$43$(xs)', scheme_libs.length$43$) + defineBuiltin(context, 'append(...xss)', scheme_libs.append, 0) + defineBuiltin(context, 'concatenate(xss)', scheme_libs.concatenate) defineBuiltin(context, 'reverse(xs)', scheme_libs.reverse) - defineBuiltin(context, 'list$45$tail(xs, n)', scheme_libs.list_tail) - defineBuiltin(context, 'list$45$ref(xs, n)', scheme_libs.list_ref) + defineBuiltin(context, 'take(xs, n)', scheme_libs.take) + defineBuiltin(context, 'take$45$right(xs, n)', scheme_libs.take$45$right) + defineBuiltin(context, 'drop(xs, n)', scheme_libs.drop) + defineBuiltin(context, 'drop$45$right(xs, n)', scheme_libs.drop$45$right) + + defineBuiltin(context, 'list$61$(eq$45$pred, ...xss)', scheme_libs.list$61$, 1) + + /* defineBuiltin(context, 'memq(item, xs)', scheme_libs.memq) defineBuiltin(context, 'memv(item, xs)', scheme_libs.memv) defineBuiltin(context, 'member(item, xs)', scheme_libs.member) defineBuiltin(context, 'assq(item, xs)', scheme_libs.assq) defineBuiltin(context, 'assv(item, xs)', scheme_libs.assv) defineBuiltin(context, 'assoc(item, xs)', scheme_libs.assoc) - defineBuiltin(context, 'list$45$copy(xs)', scheme_libs.list_copy) - defineBuiltin(context, 'map(f, ...xs)', scheme_libs.map, 1) - defineBuiltin(context, 'filter(pred, xs)', scheme_libs.filter) - defineBuiltin(context, 'fold(f, init, ...xs)', scheme_libs.fold, 2) - defineBuiltin(context, 'fold$45$right(f, init, ...xs)', scheme_libs.fold_right, 2) - defineBuiltin(context, 'reduce(f, rIdentity, xs)', scheme_libs.reduce) + */ // Scheme cxrs - // Probably can do this better. defineBuiltin(context, 'caar(xs)', scheme_libs.caar) defineBuiltin(context, 'cadr(xs)', scheme_libs.cadr) defineBuiltin(context, 'cdar(xs)', scheme_libs.cdar) @@ -489,19 +555,21 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'cddddr(xs)', scheme_libs.cddddr) // Scheme symbols - defineBuiltin(context, 'symbol$63$(val)', scheme_libs.symbolQ) - defineBuiltin(context, 'symbol$61$63$(sym1, sym2)', scheme_libs.symbolEQ) - defineBuiltin(context, 'symbol$45$$62$string(str)', scheme_libs.symbol_Gstring) - defineBuiltin(context, 'string$45$$62$symbol(sym)', scheme_libs.string_Gsymbol) + defineBuiltin(context, 'symbol$63$(val)', scheme_libs.symbol$63$) + defineBuiltin(context, 'symbol$61$$63$(sym1, sym2)', scheme_libs.symbol$61$$63$) + //defineBuiltin(context, 'symbol$45$$62$string(str)', scheme_libs.symbol_Gstring) + defineBuiltin(context, 'string$45$$62$symbol(sym)', scheme_libs.string$45$$62$symbol) + + /* // Scheme strings defineBuiltin(context, 'string$45$$62$list(str)', scheme_libs.string_Glist) defineBuiltin(context, 'list$45$$62$string(xs)', scheme_libs.list_Gstring) - + */ case Chapter.SCHEME_1: // Display defineBuiltin(context, 'display(val)', display) - defineBuiltin(context, 'newline()', scheme_libs.newline) + defineBuiltin(context, 'newline()', () => display('')) // I/O defineBuiltin(context, 'read(str)', () => prompt('')) @@ -510,42 +578,52 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'error(str, prepend = undefined)', misc.error_message, 1) // Scheme truthy and falsy value evaluator - defineBuiltin(context, '$36$true(val)', scheme_libs.$true) + defineBuiltin(context, 'truthy(val)', scheme_libs.truthy) + + // Scheme conversion from vector to list, defined here as + // it is used to support variadic functions + defineBuiltin(context, 'vector$45$$62$list(v)', scheme_libs.vector$45$$62$list) + + // Scheme function to build numbers + defineBuiltin(context, 'make_number(n)', scheme_libs.make_number) // Scheme equality predicates - defineBuiltin(context, 'eq$63$(...vals)', scheme_libs.eqQ) - defineBuiltin(context, 'eqv$63$(...vals)', scheme_libs.eqvQ) - defineBuiltin(context, 'equal$63$(...vals)', scheme_libs.equalQ) + + defineBuiltin(context, 'eq$63$(...vals)', scheme_libs.eq$63$) + defineBuiltin(context, 'eqv$63$(...vals)', scheme_libs.eqv$63$) + defineBuiltin(context, 'equal$63$(...vals)', scheme_libs.equal$63$) // Scheme basic arithmetic - defineBuiltin(context, '$43$(...vals)', scheme_libs.plus, 0) - defineBuiltin(context, '$42$(...vals)', scheme_libs.multiply, 0) - defineBuiltin(context, '$45$(...vals)', scheme_libs.minus, 1) - defineBuiltin(context, '$47$(...vals)', scheme_libs.divide, 1) + defineBuiltin(context, '$43$(...vals)', scheme_libs.$43$, 0) + defineBuiltin(context, '$42$(...vals)', scheme_libs.$42$, 0) + defineBuiltin(context, '$45$(...vals)', scheme_libs.$45$, 1) + defineBuiltin(context, '$47$(...vals)', scheme_libs.$47$, 1) // Scheme comparison - defineBuiltin(context, '$61$(...vals)', scheme_libs.E, 1) - defineBuiltin(context, '$60$(...vals)', scheme_libs.L, 1) - defineBuiltin(context, '$62$(...vals)', scheme_libs.G, 1) - defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.LE, 1) - defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.GE, 1) + defineBuiltin(context, '$61$(...vals)', scheme_libs.$61$, 2) + defineBuiltin(context, '$60$(...vals)', scheme_libs.$60$, 2) + defineBuiltin(context, '$62$(...vals)', scheme_libs.$62$, 2) + defineBuiltin(context, '$60$$61$(...vals)', scheme_libs.$60$$61$, 2) + defineBuiltin(context, '$62$$61$(...vals)', scheme_libs.$62$$61$, 2) // Scheme math functions - defineBuiltin(context, 'number$63$(val)', scheme_libs.numberQ) - defineBuiltin(context, 'complex$63$(val)', scheme_libs.complexQ) - defineBuiltin(context, 'real$63$(val)', scheme_libs.realQ) - defineBuiltin(context, 'rational$63$(val)', scheme_libs.rationalQ) - defineBuiltin(context, 'integer$63$(val)', scheme_libs.integerQ) - defineBuiltin(context, 'exact$63$(val)', scheme_libs.exactQ) - defineBuiltin(context, 'exact$45$integer$63$(val)', scheme_libs.exact_integerQ) - defineBuiltin(context, 'zero$63$(val)', scheme_libs.zeroQ) - defineBuiltin(context, 'positive$63$(val)', scheme_libs.positiveQ) - defineBuiltin(context, 'negative$63$(val)', scheme_libs.negativeQ) - defineBuiltin(context, 'odd$63$(val)', scheme_libs.oddQ) - defineBuiltin(context, 'even$63$(val)', scheme_libs.evenQ) + defineBuiltin(context, 'number$63$(val)', scheme_libs.number$63$) + defineBuiltin(context, 'complex$63$(val)', scheme_libs.complex$63$) + defineBuiltin(context, 'real$63$(val)', scheme_libs.real$63$) + defineBuiltin(context, 'rational$63$(val)', scheme_libs.rational$63$) + defineBuiltin(context, 'integer$63$(val)', scheme_libs.integer$63$) + defineBuiltin(context, 'exact$63$(val)', scheme_libs.exact$63$) + defineBuiltin(context, 'inexact$63$(val)', scheme_libs.inexact$63$) + //defineBuiltin(context, 'exact$45$integer$63$(val)', scheme_libs.exact_integerQ) + defineBuiltin(context, 'zero$63$(val)', scheme_libs.zero$63$) + defineBuiltin(context, 'positive$63$(val)', scheme_libs.positive$63$) + defineBuiltin(context, 'negative$63$(val)', scheme_libs.negative$63$) + //defineBuiltin(context, 'odd$63$(val)', scheme_libs.oddQ) + //defineBuiltin(context, 'even$63$(val)', scheme_libs.evenQ) defineBuiltin(context, 'max(...vals)', scheme_libs.max, 0) defineBuiltin(context, 'min(...vals)', scheme_libs.min, 0) defineBuiltin(context, 'abs(val)', scheme_libs.abs) + /* defineBuiltin(context, 'quotient(n, d)', scheme_libs.quotient) defineBuiltin(context, 'modulo(n, d)', scheme_libs.modulo) defineBuiltin(context, 'remainder(n, d)', scheme_libs.remainder) @@ -559,15 +637,17 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'exact$45$integer$45$sqrt(val)', scheme_libs.exact_integer_sqrt) defineBuiltin(context, 'expt(base, exp)', scheme_libs.expt) defineBuiltin(context, 'number$45$$62$string(val)', scheme_libs.number_Gstring) + */ // Scheme booleans - defineBuiltin(context, 'boolean$63$(val)', scheme_libs.booleanQ) - defineBuiltin(context, 'boolean$61$$63$(x, y)', scheme_libs.booleanEQ) + defineBuiltin(context, 'boolean$63$(val)', scheme_libs.boolean$63$) + defineBuiltin(context, 'boolean$61$$63$(x, y)', scheme_libs.boolean$61$$63$) defineBuiltin(context, 'and(...vals)', scheme_libs.and, 0) defineBuiltin(context, 'or(...vals)', scheme_libs.or, 0) defineBuiltin(context, 'not(val)', scheme_libs.not) // Scheme strings + /* defineBuiltin(context, 'string$63$(val)', scheme_libs.stringQ) defineBuiltin(context, 'make$45$string(n, char)', scheme_libs.make_string, 1) defineBuiltin(context, 'string(...vals)', scheme_libs.string, 0) @@ -584,15 +664,14 @@ export const importBuiltins = (context: Context, externalBuiltIns: CustomBuiltIn defineBuiltin(context, 'string$45$map(f, str)', scheme_libs.string_map) defineBuiltin(context, 'string$45$for$45$each(f, str)', scheme_libs.string_for_each) defineBuiltin(context, 'string$45$$62$number(str)', scheme_libs.string_Gnumber) + */ // Scheme procedures - defineBuiltin(context, 'procedure$63$(val)', scheme_libs.procedureQ) + defineBuiltin(context, 'procedure$63$(val)', scheme_libs.procedure$63$) + defineBuiltin(context, 'compose(...fns)', scheme_libs.compose, 0) // Special values defineBuiltin(context, 'undefined', undefined) - defineBuiltin(context, 'NaN', NaN) - defineBuiltin(context, 'Infinity', Infinity) - break default: //should be unreachable diff --git a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap index 73f8a048f..df1220603 100644 --- a/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap +++ b/src/cse-machine/__tests__/__snapshots__/cse-machine-callcc.ts.snap @@ -11,7 +11,10 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 10, + "result": SchemeInteger { + "numberType": 1, + "value": 10n, + }, "resultStatus": "finished", "visualiseListResult": Array [], } @@ -54,7 +57,10 @@ Object { "displayResult": Array [], "numErrors": 0, "parsedErrors": "", - "result": 2, + "result": SchemeInteger { + "numberType": 1, + "value": 2n, + }, "resultStatus": "finished", "visualiseListResult": Array [], } @@ -92,37 +98,3 @@ Object { "visualiseListResult": Array [], } `; - -exports[`cont throws error given >1 argument: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": " - (+ 1 2 (call/cc - (lambda (k) (k 3 'wrongwrongwrong!))) - 4) - ", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 3: Expected 1 arguments, but got 2.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; - -exports[`cont throws error given no arguments: expectParsedError 1`] = ` -Object { - "alertResult": Array [], - "code": " - (+ 1 2 (call/cc - (lambda (k) (k))) - 4) - ", - "displayResult": Array [], - "numErrors": 1, - "parsedErrors": "Line 3: Expected 1 arguments, but got 0.", - "result": undefined, - "resultStatus": "error", - "visualiseListResult": Array [], -} -`; diff --git a/src/cse-machine/__tests__/cse-machine-callcc.ts b/src/cse-machine/__tests__/cse-machine-callcc.ts index 24f55ad6e..a4fc3450d 100644 --- a/src/cse-machine/__tests__/cse-machine-callcc.ts +++ b/src/cse-machine/__tests__/cse-machine-callcc.ts @@ -13,7 +13,12 @@ test('basic call/cc works', () => { 4) `, optionECScm - ).toMatchInlineSnapshot(`10`) + ).toMatchInlineSnapshot(` +SchemeInteger { + "numberType": 1, + "value": 10n, +} +`) }) test('call/cc can be used to escape a computation', () => { @@ -28,7 +33,12 @@ test('call/cc can be used to escape a computation', () => { test `, optionECScm - ).toMatchInlineSnapshot(`2`) + ).toMatchInlineSnapshot(` +SchemeInteger { + "numberType": 1, + "value": 2n, +} +`) }) test('call/cc throws error given no arguments', () => { @@ -52,6 +62,10 @@ test('call/cc throws error given >1 argument', () => { ).toMatchInlineSnapshot(`"Line 2: Expected 1 arguments, but got 2."`) }) +/* +for now, continuations have variable arity but are unable to check for the "correct" +number of arguments. we will omit these tests for now + test('cont throws error given no arguments', () => { return expectParsedError( ` @@ -73,7 +87,7 @@ test('cont throws error given >1 argument', () => { optionECScm ).toMatchInlineSnapshot(`"Line 3: Expected 1 arguments, but got 2."`) }) - +*/ test('call/cc can be stored as a value', () => { return expectResult( ` diff --git a/src/cse-machine/continuations.ts b/src/cse-machine/continuations.ts index 2f0729b8e..2a4b2e0cd 100644 --- a/src/cse-machine/continuations.ts +++ b/src/cse-machine/continuations.ts @@ -50,7 +50,8 @@ export function getContinuationEnv(cn: Continuation): Environment[] { export function makeContinuation(control: Control, stash: Stash, env: Environment[]): Function { // Cast a function into a continuation - const fn: any = (x: any) => x + // a continuation may take any amount of arguments + const fn: Function = (...x: any[]) => x const cn: Continuation = fn as Continuation // Set the control, stash and environment diff --git a/src/cse-machine/instrCreator.ts b/src/cse-machine/instrCreator.ts index 731708461..2fbfe8bd3 100644 --- a/src/cse-machine/instrCreator.ts +++ b/src/cse-machine/instrCreator.ts @@ -144,7 +144,8 @@ export const genContInstr = (srcNode: Node): GenContInstr => ({ srcNode }) -export const resumeContInstr = (srcNode: Node): ResumeContInstr => ({ +export const resumeContInstr = (numOfArgs: number, srcNode: es.Node): ResumeContInstr => ({ + numOfArgs: numOfArgs, instrType: InstrType.RESUME_CONT, srcNode }) diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts index d1274de7d..6c0ac8f2a 100644 --- a/src/cse-machine/interpreter.ts +++ b/src/cse-machine/interpreter.ts @@ -48,8 +48,10 @@ import { CseError, EnvInstr, ForInstr, + GenContInstr, Instr, InstrType, + ResumeContInstr, UnOpInstr, WhileInstr } from './types' @@ -397,6 +399,42 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { declareFunctionsAndVariables(context, command, environment) } + // A strange bug occurs here when successive REPL commands are run, as they + // are each evaluated as separate programs. This causes the environment to be + // pushed multiple times. + + // As such, we need to "append" the tail environment to the current environment + // if and only if the tail environment is a previous program environment. + + const currEnv = currentEnvironment(context) + if ( + currEnv && + currEnv.name === 'programEnvironment' && + currEnv.tail && + currEnv.tail.name === 'programEnvironment' + ) { + // we need to take that tail environment and append its items to the current environment + const oldEnv = currEnv.tail + + // separate the tail environment from the environments list + currEnv.tail = oldEnv.tail + + // we will recycle the old environment's item list + // add the items from the current environment to the tail environment + // this is fine, especially as the older program will never + // need to use the old environment's items again + for (const key in currEnv.head) { + oldEnv.head[key] = currEnv.head[key] + } + + // set the current environment to the old one + // this will work across successive programs as well + + // this will also allow continuations to read newer program + // values from their "outdated" program environment + currEnv.head = oldEnv.head + } + if (command.body.length == 1) { // If program only consists of one statement, evaluate it immediately const next = command.body[0] @@ -914,17 +952,16 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { // Check for number of arguments mismatch error checkNumberOfArguments(context, func, args, command.srcNode) - // A continuation is always given a single argument - const expression: Value = args[0] - const dummyContCallExpression = makeDummyContCallExpression('f', 'cont') // Restore the state of the stash, // but replace the function application instruction with // a resume continuation instruction stash.push(func) - stash.push(expression) - control.push(instr.resumeContInstr(dummyContCallExpression)) + // we need to push the arguments back onto the stash + // as well + stash.push(...args) + control.push(instr.resumeContInstr(command.numOfArgs, dummyContCallExpression)) return } @@ -1107,7 +1144,7 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { [InstrType.BREAK_MARKER]: function () {}, [InstrType.GENERATE_CONT]: function ( - _command: Instr, + _command: GenContInstr, context: Context, control: Control, stash: Stash @@ -1128,12 +1165,16 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { }, [InstrType.RESUME_CONT]: function ( - _command: Instr, + command: ResumeContInstr, context: Context, control: Control, stash: Stash ) { - const expression = stash.pop() + // pop the arguments + const args: Value[] = [] + for (let i = 0; i < command.numOfArgs; i++) { + args.unshift(stash.pop()) + } const cn: Continuation = stash.pop() as Continuation const contControl = getContinuationControl(cn) @@ -1144,10 +1185,10 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = { control.setTo(contControl) stash.setTo(contStash) - // Push the expression given to the continuation onto the stash - stash.push(expression) + // Push the arguments given to the continuation back onto the stash + stash.push(...args) - // Restore the environment pointer to that of the continuation + // Restore the environment pointer to that of the continuation's environment context.runtime.environments = contEnv } } diff --git a/src/cse-machine/types.ts b/src/cse-machine/types.ts index 0239762a0..24ac2455d 100644 --- a/src/cse-machine/types.ts +++ b/src/cse-machine/types.ts @@ -77,7 +77,9 @@ export interface ArrLitInstr extends BaseInstr { export type GenContInstr = BaseInstr -export type ResumeContInstr = BaseInstr +export interface ResumeContInstr extends BaseInstr { + numOfArgs: number +} export type Instr = | BaseInstr diff --git a/src/cse-machine/utils.ts b/src/cse-machine/utils.ts index 6efbe1393..297c48f45 100644 --- a/src/cse-machine/utils.ts +++ b/src/cse-machine/utils.ts @@ -7,6 +7,7 @@ import { RuntimeSourceError } from '../errors/runtimeSourceError' import Closure from '../interpreter/closure' import { Environment, Frame, Node, StatementSequence, Value } from '../types' import * as ast from '../utils/astCreator' +import { isContinuation } from './continuations' import * as instr from './instrCreator' import { Control } from './interpreter' import { AppInstr, AssmtInstr, ControlItem, Instr, InstrType } from './types' @@ -490,6 +491,12 @@ export const checkNumberOfArguments = ( ) ) } + } else if (isContinuation(callee)) { + // Continuations have variadic arguments, + // and so we can let it pass + // in future, if we can somehow check the number of arguments + // expected by the continuation, we can add a check here. + return undefined } else { // Pre-built functions const hasVarArgs = callee.minArgsNeeded != undefined diff --git a/src/parser/__tests__/scheme-encode-decode.ts b/src/parser/__tests__/scheme-encode-decode.ts deleted file mode 100644 index a458f0bac..000000000 --- a/src/parser/__tests__/scheme-encode-decode.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Node } from 'estree' - -import { UnassignedVariable } from '../../errors/errors' -import { decode, encode } from '../../scm-slang/src' -import { dummyExpression } from '../../utils/dummyAstCreator' -import { decodeError, decodeValue } from '../scheme' - -describe('Scheme encoder and decoder', () => { - it('encodes and decodes strings correctly', () => { - const values = [ - 'hello', - 'hello world', - 'scheme->JavaScript', - 'hello world!!', - 'true', - 'false', - 'null', - '1', - '๐Ÿ˜€' - ] - for (const value of values) { - expect(decode(encode(value))).toEqual(value) - } - }) - - it('decoder ignores primitives', () => { - const values = [1, 2, 3, true, false, null] - for (const value of values) { - expect(decodeValue(value)).toEqual(value) - } - }) - - it('decoder works on function toString representation', () => { - // Dummy function to test - function $65$() {} - expect(decodeValue($65$).toString()).toEqual(`function A() { }`) - }) - - it('decodes runtime errors properly', () => { - const token = `๐Ÿ˜€` - const dummyNode: Node = dummyExpression() - const error = new UnassignedVariable(encode(token), dummyNode) - expect(decodeError(error).elaborate()).toContain(`๐Ÿ˜€`) - }) -}) diff --git a/src/parser/scheme/index.ts b/src/parser/scheme/index.ts index dd421cb11..9391bf019 100644 --- a/src/parser/scheme/index.ts +++ b/src/parser/scheme/index.ts @@ -1,12 +1,23 @@ -import { Node, Program } from 'estree' +import { Program } from 'estree' -import { decode, encode, schemeParse } from '../../scm-slang/src' -import { Pair } from '../../scm-slang/src/stdlib/source-scheme-library' +import { decode, schemeParse } from '../../alt-langs/scheme/scm-slang/src' +import { + car, + cdr, + circular$45$list$63$, + cons, + last$45$pair, + list$45$tail, + pair$63$, + procedure$63$, + set$45$cdr$33$, + vector$63$ +} from '../../alt-langs/scheme/scm-slang/src/stdlib/base' +import { List, Pair } from '../../stdlib/list' import { Chapter, Context, ErrorType, SourceError } from '../../types' import { FatalSyntaxError } from '../errors' import { AcornOptions, Parser } from '../types' import { positionToSourceLocation } from '../utils' -const walk = require('acorn-walk') export class SchemeParser implements Parser { private chapter: number @@ -21,10 +32,8 @@ export class SchemeParser implements Parser { ): Program | null { try { // parse the scheme code - const estree = schemeParse(programStr, this.chapter) - // walk the estree and encode all identifiers - encodeTree(estree) - return estree as unknown as Program + const estree = schemeParse(programStr, this.chapter, true) + return estree as Program } catch (error) { if (error instanceof SyntaxError) { error = new FatalSyntaxError(positionToSourceLocation((error as any).loc), error.toString()) @@ -63,15 +72,6 @@ function getSchemeChapter(chapter: Chapter): number { } } -export function encodeTree(tree: Program): Program { - walk.full(tree, (node: Node) => { - if (node.type === 'Identifier') { - node.name = encode(node.name) - } - }) - return tree -} - function decodeString(str: string): string { return str.replace(/\$scheme_[\w$]+|\$\d+\$/g, match => { return decode(match) @@ -80,18 +80,58 @@ function decodeString(str: string): string { // Given any value, decode it if and // only if an encoded value may exist in it. +// this function is used to accurately display +// values in the REPL. export function decodeValue(x: any): any { - // In future: add support for decoding vectors. - if (x instanceof Pair) { + // helper version of list_tail that assumes non-null return value + function list_tail(xs: List, i: number): List { + if (i === 0) { + return xs + } else { + return list_tail(list$45$tail(xs), i - 1) + } + } + + if (circular$45$list$63$(x)) { // May contain encoded strings. - return new Pair(decodeValue(x.car), decodeValue(x.cdr)) - } else if (x instanceof Array) { + let circular_pair_index = -1 + const all_pairs: Pair[] = [] + + // iterate through all pairs in the list until we find the circular pair + let current = x + while (current !== null) { + if (all_pairs.includes(current)) { + circular_pair_index = all_pairs.indexOf(current) + break + } + all_pairs.push(current) + current = cdr(current) + } + x + // assemble a new list using the elements in all_pairs + let new_list = null + for (let i = all_pairs.length - 1; i >= 0; i--) { + new_list = cons(decodeValue(car(all_pairs[i])), new_list) + } + + // finally we can set the last cdr of the new list to the circular-pair itself + + const circular_pair = list_tail(new_list, circular_pair_index) + set$45$cdr$33$(last$45$pair(new_list), circular_pair) + return new_list + } else if (pair$63$(x)) { + // May contain encoded strings. + return cons(decodeValue(car(x)), decodeValue(cdr(x))) + } else if (vector$63$(x)) { // May contain encoded strings. return x.map(decodeValue) - } else if (x instanceof Function) { + } else if (procedure$63$(x)) { + // copy x to avoid modifying the original object + const newX = { ...x } const newString = decodeString(x.toString()) - x.toString = () => newString - return x + // change the toString method to return the decoded string + newX.toString = () => newString + return newX } else { // string, number, boolean, null, undefined // no need to decode. diff --git a/src/scm-slang b/src/scm-slang deleted file mode 160000 index 35fe554e4..000000000 --- a/src/scm-slang +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 35fe554e473f48f1079586ea60334d83f0adaee4 diff --git a/tsconfig.json b/tsconfig.json index 3e4181868..b29b2ae4d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,7 +3,7 @@ "outDir": "./dist", "module": "commonjs", "declaration": true, - "target": "es2016", + "target": "es2020", "lib": [ "es2021.string", "es2018",