diff --git a/.eslintignore b/.eslintignore
deleted file mode 100644
index 2e9a9a8e1..000000000
--- a/.eslintignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/dist/
-/src/alt-langs/
-/src/py-slang/
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 345d40c66..000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "env": {
- "browser": true,
- "es6": true,
- "node": true
- },
- "extends": [
- "plugin:@typescript-eslint/recommended",
- "plugin:@typescript-eslint/recommended-requiring-type-checking",
- "prettier"
- ],
- "ignorePatterns": ["src/**/__tests__/**", "src/**/__mocks__/**"],
- "parser": "@typescript-eslint/parser",
- "parserOptions": {
- "project": "tsconfig.json",
- "sourceType": "module"
- },
- "plugins": [
- "import",
- "@typescript-eslint"
- ],
- "rules": {
- "import/no-duplicates": ["warn", { "prefer-inline": true }],
- "import/order": "warn",
- "@typescript-eslint/no-base-to-string": "off", // TODO: Remove
- "prefer-const": "off", // TODO: Remove
- "no-var": "off", // TODO: Remove
- "@typescript-eslint/ban-ts-comment": "warn",
- "@typescript-eslint/ban-types": "off",
- "@typescript-eslint/camelcase": "off",
- "@typescript-eslint/explicit-function-return-type": "off",
- "@typescript-eslint/explicit-module-boundary-types": "off",
- "@typescript-eslint/interface-name-prefix": "off",
- "@typescript-eslint/no-duplicate-type-constituents": "off",
- "@typescript-eslint/no-empty-function": "off",
- "@typescript-eslint/no-explicit-any": "off",
- "@typescript-eslint/no-floating-promises": "off",
- "@typescript-eslint/no-implied-eval": "off",
- "@typescript-eslint/no-inferrable-types": "off",
- "@typescript-eslint/no-non-null-asserted-optional-chain": "off",
- "@typescript-eslint/no-non-null-assertion": "off",
- "@typescript-eslint/no-redundant-type-constituents": "off",
- "@typescript-eslint/no-unnecessary-type-assertion": "off",
- "@typescript-eslint/no-unsafe-argument": "off",
- "@typescript-eslint/no-unsafe-assignment": "off",
- "@typescript-eslint/no-unsafe-call": "off",
- "@typescript-eslint/no-unsafe-enum-comparison": "off",
- "@typescript-eslint/no-unsafe-member-access": "off",
- "@typescript-eslint/no-unsafe-return": "off",
- "@typescript-eslint/no-unused-vars": ["warn", { "argsIgnorePattern": "^_" }],
- "@typescript-eslint/no-var-requires": "off",
- "@typescript-eslint/require-await": "error",
- "@typescript-eslint/restrict-plus-operands": "off",
- "@typescript-eslint/restrict-template-expressions": "off",
- "@typescript-eslint/unbound-method": "off",
- "prefer-rest-params": "off"
- },
- "overrides": [{
- "files": ["src/**/__tests__/**", "src/**/__mocks__/**"],
- "plugins": ["import"],
- "rules": {
- "import/order": "warn"
- }
- }]
-}
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 469d91d2e..8dc876373 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,11 @@
node_modules
*.js
+
+# docs
!docs/jsdoc/templates/**/*.js
!docs/lib/**/*.js
+docs/source
+
*.map
dist/
.idea/
diff --git a/docs/lib/non-det.js b/docs/lib/non-det.js
deleted file mode 100644
index eb4a0761e..000000000
--- a/docs/lib/non-det.js
+++ /dev/null
@@ -1,89 +0,0 @@
-// \texttt{non-det.js START} \begin{lstlisting}
-
-/**
- * Given n
values, creates a choice point whose value is chosen,
- * at run-time, from the set e1, e2, ..., en.
- * If n
is 0, it forces the language processor to backtrack to
- * the most recent amb
expression without returning a value.
- * @param {value} e1,e2,...en - given values
- * @returns {value} a value from the given values chosen sequentially
- */
-function amb(e1, e2, ...en) {}
-
-/**
- * Given n
values, creates a choice point whose value is chosen,
- * at run-time, randomly from the set e1, e2, ..., en.
- * If n
is 0, it forces the language processor to backtrack to
- * the most recent amb
expression without returning a value.
- * Functions similarly to the amb
operator but makes choices randomly
- * instead of sequentially.
- * @param {value} e1,e2,...en - given values
- * @returns {value} a value from the given values chosen randomly
- */
-function ambR(e1, e2, ...en) {}
-
-/**
- * Prevents the language processor from backtracking any further
- * beyond the current statement.
- */
-function cut() {}
-
-/**
- * Forces the language processor to backtrack to the most recent
- * amb expression, if and only if pred
evaluates
- * to false
.
- * @param {boolean} pred - given predicate
- * @returns {string} - a message indicating that the given predicate
- * is true
- */
-function require(pred) {
- return pred ? "Satisfied require" : amb();
-}
-
-
-/**
- * Returns true if and only if P
and Q
- * satisfy the boolean equation P --> Q.
- * @param {boolean} P - antecedent of the conditional
- * @param {boolean} Q - consequent of the conditional
- * @return {boolean} - a boolean according to the truth table of
- * Material Conditional
- */
-function implication(P, Q) {
- return !P || Q;
-}
-
-/**
- * Returns true if and only if P
and Q
- * satisfy the boolean equation P <--> Q.
- * @param {boolean} P - antecedent and consequent of the conditional
- * @param {boolean} Q - antecedent and consequent of the conditional
- * @return {boolean} - a boolean according to the truth table of
- * Material Biconditional
- */
-function bi_implication(P, Q) {
- return implication(P, Q) && implication(Q, P);
-}
-
-/**
- * Nondeterministically returns an element from a given list.
- * @param {list} xs - given list
- * @returns {value} - an element from xs
- */
-function an_element_of(xs) {
- require(!is_null(xs));
- return amb(head(xs), an_element_of(tail(xs)));
-}
-
-/**
- * Nondeterministically returns an integer between n
and
- * m
(inclusively).
- * @param {number} n - lower bound
- * @param {number} m - upper bound
- * @returns {number} - a number between n and m (inclusive)
- */
-function an_integer_between(n, m) {
- return n > m ? amb() : amb(n, an_integer_between(n + 1, m));
-}
-
-// \end{lstlisting} // \texttt{non-det.js END}
diff --git a/docs/md/README_3_NON-DET.md b/docs/md/README_3_NON-DET.md
deleted file mode 100644
index 3869e0023..000000000
--- a/docs/md/README_3_NON-DET.md
+++ /dev/null
@@ -1,105 +0,0 @@
-Source §3 Non-Det is a small programming language, designed for the fourth chapter
-of the textbook
-Structure and Interpretation
-of Computer Programs, JavaScript Adaptation (SICP JS).
-
-## What is nondeterministic programming?
-Source 3 Non-Det is a version of Source 3 with a built-in search mechanism.
-Programmers can specify sets of values, and requirements that the values must satisfy.
-The program evaluator then automatically identifies the values that meet the requirements.
-
-## What names are predeclared in Source §3 Non-Det?
-
-On the right, you see all predeclared names of Source §3 Non-Det, in alphabetical
-order. Click on a name to see how it is defined and used. They come in these groups:
-
- -
- AUXILIARY: Auxiliary constants and functions
-
- -
- MISC: Miscellaneous constants and functions
-
- -
- MATH: Mathematical constants and functions
-
- -
- LISTS: Support for lists
-
- -
- PAIRMUTATORS: Mutating pairs
-
- -
- ARRAYS: Support for arrays
-
- -
- STREAMS: Support for streams
-
- -
- NON-DET: Support for nondeterminism
-
-
-
-## What can you do in Source §3 Non-Det?
-
-You can use all features of
-Source §3 and all
-features that are introduced in
-chapter 4.3 of the
-textbook.
-
-Below are the features that Source §3 Non-Det adds to Source §3.
-
-### amb operator
-A set of values can be specified with the amb
operator.
-
-In the following example, we specify two possible choices for a value we want:
-amb('hello', 'bye') + 'world!'; // 'hello world!'
-
-To obtain the next value, 'bye'
, enter the command try_again
in the playground REPL.
-This will give the result 'bye world!'
.
-
-### ambR operator
-The ambR
operator functions similarly to amb
but makes choices randomly
-instead of sequentially.
-
-Upon running the above example, we may randomly obtain the result 'hello world!'
first and 'bye world!
second
-or 'bye world!
first and 'hello world!'
second.
-
-### require function
-Requirements can be specified with the require
function.
-
-In the following example, we add the requirement that the number chosen should be greater than 3:
-const f = amb(1, 2, 3, 4, 5, 6); require(f > 3); f; // 4
-
-To obtain the next value 5
, enter the command try_again
in the playground REPL.
-Entering try_again
once more will give the final value of 6
.
-
-### cut operator
-In order to obtain only the first possible value which satisfies given requirements,
-the cut
operator can be used to prevent backtracking beyond the current statement.
-
-In the following example, we are able to obtain only a single value:
-const f = amb(1, 2, 3, 4, 5, 6); require(f > 3); cut(); f; // 4
-
-Entering try_again
in the playground REPL will not give the subsequent values that were specified,
-5
and 6
.
-
-### implication function
-The implication
function can be used to model logical implication between two boolean expressions.
-
-### bi_implication function
-The bi_implication
function can be used to model logical bi-implication between two boolean expressions.
-
-### an_element_of function
-The an_element_of
function can be used to nondeterministically obtain an element from a list.
-It functions similarly to amb
but takes in a list of choices as argument instead of the choices being arguments themselves.
-
-### an_integer_between function
-The an_integer_between
function can be used to nondeterministically obtain an integer between a specified range (inclusively).
-
-## You want the definitive specs?
-
-For our development team, we are maintaining a definitive description
-of the language, called the
-Specification of Source §3 Non-Det.
-Feel free to take a peek!
diff --git a/docs/md/README_NON-DET.md b/docs/md/README_NON-DET.md
deleted file mode 100644
index e55223fd4..000000000
--- a/docs/md/README_NON-DET.md
+++ /dev/null
@@ -1,10 +0,0 @@
-The functions in NON-DET provide useful functions for nondeterministic programs,
-as introduced in
-section
-4.3 Nondeterministic computing
-of the textbook
-Structure and Interpretation
-of Computer Programs, JavaScript Adaptation (SICP JS).
-
-On the right, you see all predeclared NON-DET functions,
-in alphabetical order. Click on a name to see how it is defined and used.
diff --git a/docs/md/README_top.md b/docs/md/README_top.md
index 94ead7bd5..95568ece6 100644
--- a/docs/md/README_top.md
+++ b/docs/md/README_top.md
@@ -70,8 +70,6 @@ the Source Academy.
#### Specification of Source §2 Typed
-#### Specification of Source §3 Non-Det
-
#### Specification of Source §3 Concurrent
#### Specification of Source §3 Typed
diff --git a/docs/source/.gitignore b/docs/source/.gitignore
deleted file mode 100644
index 241e560df..000000000
--- a/docs/source/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-*
-
diff --git a/docs/specs/Makefile b/docs/specs/Makefile
index f3fcbdedf..81b8ede94 100644
--- a/docs/specs/Makefile
+++ b/docs/specs/Makefile
@@ -1,6 +1,6 @@
PDFLATEX = latexmk -pdf
-SPECSNUMS = 1 1_lazy 1_wasm 1_type_inference 1_infinite_loop_detection 1_typed 2 2_lazy 2_typed 3_type_inference 3 3_nondet 3_concurrent 3_typed 4 4_explicitcontrol 4_gpu 4_typed styleguide 2_stepper studio_2 python_1
+SPECSNUMS = 1 1_lazy 1_wasm 1_type_inference 1_infinite_loop_detection 1_typed 2 2_lazy 2_typed 3_type_inference 3 3_concurrent 3_typed 4 4_explicitcontrol 4_gpu 4_typed styleguide 2_stepper studio_2 python_1
SPECS = $(SPECSNUMS:%=source_%)
diff --git a/docs/specs/source_3_nondet.tex b/docs/specs/source_3_nondet.tex
deleted file mode 100644
index 0cd286d23..000000000
--- a/docs/specs/source_3_nondet.tex
+++ /dev/null
@@ -1,85 +0,0 @@
-\input source_header.tex
-
-\begin{document}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- \docheader{2021}{Source}{\S 3 Non-Det}{Martin Henz, Arsalan Cheema, Anubhav}
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-\input source_intro.tex
-
-Source \S 3 Non-Det is a nondeterministic variant of Source \S 3.
-
-\section{Changes}
-
-Source \S 3 Non-Det modifies Source \S 3 by adding an automatic search mechanism into the language semantics. The language allows programmers to specify \emph{choices} and \emph{requirements}. At runtime, the search mechanism automatically resolves these requirements, and identifies all those choices that satisfy them. \newline
-
-This is achieved by supporting a new type of expression, called the \emph{choice point} expression. Every choice point expression is described by a (possibly empty) set of \emph{expressions} (known as the set of \emph{choices}). At runtime, a choice point expression can assume any value from its set of choices. A program can also include instructions that force the language processor to \emph{backtrack} to any choice point expression. \emph{Backtracking} means that the choice point expression will take on a different value from its set of choices, and the program will then be re-evaluated with this new choice. \newline
-
-A Source \S 3 Non-Det program can contain any number of choice points. Evaluating a program can hence have an exponential number of outcomes - one outcome for every combination of possible choices. The language's search mechanism, however, only returns one outcome at a time. The programmer can \emph{command} the search mechanism to re-evaluate the program with a different combination of choices. On the Source Academy Playground, this command is implemented as the magic phrase \verb#try_again#,
-which has to be entered into the REPL. \newline
-
-In the Source Academy implementation, the Source \S 3 Non-Det evaluator can only process one program at a time. If the evaluator is given a new program \textbf{before} all the outcomes of an existing program have been processed, then all remaining outcomes will be ignored. \newline
-
-Unlike the implementations of Source \S 3, the implementation of Source \S 3 Non-Det does not use a constant amount of memory for loops. Instead, memory usage increases linearly with the number of iterations. This is because each iteration can be nondeterministic. Each iteration's state must be kept in memory so that the language processor can backtrack to every iteration. Similarly, no tail call optimization is done, because every function application's state must be kept in memory to allow backtracking.
-
-Source \S 3 Non-Det currently does not support import directives.
-
-\input source_bnf.tex
-
-\newpage
-
-\input source_3_bnf_without_import.tex
-
-\newpage
-
-\input source_return
-
-\input source_import
-
-\input source_boolean_operators
-
-\input source_loops
-
-\input source_names_lang
-
-\input source_numbers
-
-\input source_strings
-
-\input source_arrays
-
-\input source_comments
-
-\input source_typing_3
-
-\input source_standard
-
-\input source_misc
-
-\input source_math
-
-\input source_nondet
-
-\input source_lists
-
-\input source_pair_mutators
-
-\input source_array_support
-
-\input source_streams
-
-\input source_js_differences
-
-\newpage
-
-\input source_list_library
-
-\newpage
-
-\input source_stream_library
-
-\newpage
-
-\input source_nondet_library
-
- \end{document}
diff --git a/docs/specs/source_nondet.tex b/docs/specs/source_nondet.tex
deleted file mode 100644
index 7620d5293..000000000
--- a/docs/specs/source_nondet.tex
+++ /dev/null
@@ -1,16 +0,0 @@
-\subsection*{Nondeterminism support}
-
-The following primitives and builtins are supported:
-
-\begin{itemize}
-\item \lstinline{amb(e1, e2, ..., en)}: \textit{primitive}, creates a choice point whose value is chosen, at runtime,
-from the set \lstinline{e1, e2, ..., en}. Note: although the usage of this primitive syntactically resembles a function application, \textit{amb} is not a function value. It is simply an operator, like the binary and unary operators. The values from the set \lstinline{(e1, e2, ..., en)} are chosen sequentially, from left-to-right.
-\item \lstinline{amb()}: applying \textit{amb} without any arguments forces the language processor to backtrack to the most recent \textit{amb expression}.
-\item \lstinline{ambR(e1, e2, ..., en)}: \textit{primitive}, creates a choice point. This is similar to \lstinline{amb}, but the values from the set \lstinline{(e1, e2, ..., en)} are chosen randomly and not sequentially.
-\item \lstinline{cut()}: \textit{primitive}, prevents the language processor from backtracking any further beyond the current statement. Note: \textit{cut} is also not a function value. It is simply an operator, like the binary and unary operators.
-\item \lstinline{require(pred)}: \textit{builtin}, forces the language processor to backtrack to the most recent \textit{amb expression}, if and only if \lstinline{pred} is false.
-\item \lstinline{an_element_of(xs)}: \textit{builtin}, nondeterministically returns an element from the list \lstinline{xs}.
-\item \lstinline{an_integer_between(n, m)}: \textit{builtin}, nondeterministically returns an integer between integers \lstinline{n} and \lstinline{m} (inclusively).
-\item \lstinline{implication(p, q)}: \textit{builtin} returns true if and only if the boolean values \lstinline{p} and \lstinline{q} satisfy the equation $P \Rightarrow Q$
-\item \lstinline{bi_implication(p, q)}: \textit{builtin} returns true if and only if the boolean values \lstinline{p} and \lstinline{q} satisfy the equation $P \Leftrightarrow Q$
-\end{itemize}
diff --git a/docs/specs/source_nondet_library.tex b/docs/specs/source_nondet_library.tex
deleted file mode 100644
index eaf5f170f..000000000
--- a/docs/specs/source_nondet_library.tex
+++ /dev/null
@@ -1,7 +0,0 @@
-\section*{Appendix: Nondeterminism library}
-
-Those nondeterminism functions that are not primitives are pre-declared as follows:
-
-\input ../lib/non-det.js
-
-
diff --git a/eslint.config.mjs b/eslint.config.mjs
new file mode 100644
index 000000000..0ba26feca
--- /dev/null
+++ b/eslint.config.mjs
@@ -0,0 +1,76 @@
+// @ts-check
+
+import tseslint from 'typescript-eslint'
+import globals from 'globals'
+
+// @ts-expect-error no type definitions for plugin
+import importPlugin from 'eslint-plugin-import'
+
+export default tseslint.config(
+ {
+ // global ignores
+ ignores: ['dist', 'src/alt-langs', 'src/py-slang', 'src/__tests__/sicp', '**/*.snap']
+ },
+ ...tseslint.configs.recommended,
+ {
+ files: ['**/*.ts*'],
+ languageOptions: {
+ globals: {
+ ...globals.node,
+ ...globals.es2016,
+ ...globals.browser
+ },
+ parser: tseslint.parser,
+ parserOptions: {
+ project: './tsconfig.json'
+ }
+ },
+ plugins: {
+ '@typescript-eslint': tseslint.plugin,
+ import: importPlugin
+ },
+ rules: {
+ 'import/no-duplicates': ['warn', { 'prefer-inline': true }],
+ 'import/order': 'warn',
+ '@typescript-eslint/no-base-to-string': 'off', // TODO: Remove
+ 'prefer-const': 'off', // TODO: Remove
+ 'no-var': 'off', // TODO: Remove
+ '@typescript-eslint/ban-ts-comment': 'warn',
+ '@typescript-eslint/ban-types': 'off',
+ '@typescript-eslint/camelcase': 'off',
+ '@typescript-eslint/explicit-function-return-type': 'off',
+ '@typescript-eslint/explicit-module-boundary-types': 'off',
+ '@typescript-eslint/interface-name-prefix': 'off',
+ '@typescript-eslint/no-duplicate-type-constituents': 'off',
+ '@typescript-eslint/no-empty-function': 'off',
+ '@typescript-eslint/no-explicit-any': 'off',
+ '@typescript-eslint/no-floating-promises': 'off',
+ '@typescript-eslint/no-implied-eval': 'off',
+ '@typescript-eslint/no-inferrable-types': 'off',
+ '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',
+ '@typescript-eslint/no-non-null-assertion': 'off',
+ '@typescript-eslint/no-redundant-type-constituents': 'off',
+ '@typescript-eslint/no-unnecessary-type-assertion': 'off',
+ '@typescript-eslint/no-unsafe-argument': 'off',
+ '@typescript-eslint/no-unsafe-assignment': 'off',
+ '@typescript-eslint/no-unsafe-call': 'off',
+ '@typescript-eslint/no-unsafe-enum-comparison': 'off',
+ '@typescript-eslint/no-unsafe-function-type': 'off',
+ '@typescript-eslint/no-unsafe-member-access': 'off',
+ '@typescript-eslint/no-unsafe-return': 'off',
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
+ '@typescript-eslint/no-var-requires': 'off',
+ '@typescript-eslint/require-await': 'error',
+ '@typescript-eslint/restrict-plus-operands': 'off',
+ '@typescript-eslint/restrict-template-expressions': 'off',
+ '@typescript-eslint/unbound-method': 'off',
+ 'prefer-rest-params': 'off'
+ }
+ },
+ {
+ files: ['**/*.js', 'src/repl/*.ts'],
+ rules: {
+ '@typescript-eslint/no-require-imports': 'off'
+ }
+ }
+)
diff --git a/package.json b/package.json
index ca7b393fe..b3a7b4c47 100644
--- a/package.json
+++ b/package.json
@@ -53,14 +53,14 @@
"scripts": {
"build": "yarn docs && yarn build:slang",
"build:slang": "tsc --project tsconfig.prod.json",
- "eslint": "eslint --ext \".ts,.tsx\" src",
+ "eslint": "eslint src",
"format": "prettier --write \"src/**/*.{ts,tsx}\"",
"format:ci": "prettier --list-different \"src/**/*.{ts,tsx}\"",
"test": "jest",
"test-coverage": "jest --coverage",
- "docs": "yarn jsdoc && yarn autocomplete",
- "jsdoc": "./scripts/jsdoc.sh",
- "autocomplete": "node ./scripts/updateAutocompleteDocs.js",
+ "docs": "node ./scripts/docs.mjs docs",
+ "jsdoc": "node ./scripts/docs.mjs",
+ "autocomplete": "node ./scripts/docs.mjs autocomplete",
"build_sicp_package": "./scripts/build_sicp_package.sh",
"publish_sicp_package": "./scripts/publish_sicp_package.sh",
"benchmark": "jest --runInBand --testPathPattern='.*benchmark.*' --testPathIgnorePatterns='/dist/'",
@@ -72,14 +72,12 @@
"@types/lodash": "^4.14.202",
"@types/node": "^20.0.0",
"@types/offscreencanvas": "^2019.7.0",
- "@typescript-eslint/eslint-plugin": "^7.3.1",
- "@typescript-eslint/parser": "^7.3.1",
"ace-builds": "^1.4.12",
"coveralls": "^3.1.0",
"escodegen": "^2.0.0",
"eslint": "^8.57.0",
- "eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "^2.29.1",
+ "globals": "^15.11.0",
"husky": "^8.0.1",
"jest": "^29.0.0",
"jest-environment-jsdom": "^29.0.0",
@@ -88,7 +86,8 @@
"jsdom": "^19.0.0",
"prettier": "^2.1.2",
"ts-jest": "^29.0.0",
- "typescript": "^4.0.3"
+ "typescript": "^4.0.3",
+ "typescript-eslint": "^8.8.1"
},
"jest": {
"snapshotFormat": {
diff --git a/scripts/updateAutocompleteDocs.js b/scripts/autocomplete.mjs
similarity index 67%
rename from scripts/updateAutocompleteDocs.js
rename to scripts/autocomplete.mjs
index 0cfb7cd61..34de8e977 100644
--- a/scripts/updateAutocompleteDocs.js
+++ b/scripts/autocomplete.mjs
@@ -1,7 +1,8 @@
-const fs = require('fs');
-const path = require('path');
-const jsdom = require('jsdom');
-const { JSDOM } = jsdom;
+// @ts-check
+
+import fs from 'fs/promises';
+import pathlib from 'path';
+import { JSDOM } from 'jsdom';
const CONST_DECL = "const";
const FUNC_DECL = "func";
@@ -18,7 +19,6 @@ const TARGETS = [
"source_2_typed",
"source_3",
"source_3_concurrent",
- "source_3_non-det",
"source_3_typed",
"source_4",
"source_4_typed",
@@ -75,15 +75,15 @@ function processFunction(namespace, element, document) {
namespace[name] = { title, description: html, meta: FUNC_DECL };
}
-function processDirGlobals(target) {
- const inFile = path.join(BASE_DIR, target, SRC_FILENAME);
+async function processDirGlobals(target) {
+ const inFile = pathlib.join(BASE_DIR, target, SRC_FILENAME);
let document;
try {
- const contents = fs.readFileSync(inFile);
+ const contents = await fs.readFile(inFile);
document = new JSDOM(contents.toString()).window.document;
} catch (err) {
console.error(inFile, "failed", err);
- return;
+ return err;
}
const names = {};
@@ -94,17 +94,33 @@ function processDirGlobals(target) {
const functions = document.getElementsByClassName('function-entry')
Array.prototype.forEach.call(functions, ele => processFunction(names, ele, document));
- fs.mkdirSync(OUT_DIR, { recursive: true })
-
- const outFile = path.join(OUT_DIR, target + '.json');
- fs.writeFileSync(outFile, JSON.stringify(names, null, 2), 'utf-8');
+ const outFile = pathlib.join(OUT_DIR, target + '.json');
+ await fs.writeFile(outFile, JSON.stringify(names, null, 2), 'utf-8')
+ return undefined
}
-if (fs.existsSync(BASE_DIR)) {
- TARGETS.forEach(processDirGlobals);
-} else {
- console.error(`
- Error: path to jsdoc html is invalid.
- Ensure that this script is run from the project root and documentation has been generated\
- `);
+export default async function autocomplete() {
+ try {
+ // Check that the BASE_DIR exists and that we can read from it
+ await fs.access(BASE_DIR, fs.constants.R_OK)
+ } catch (error) {
+ if (error.code === 'ENOENT') {
+ console.error(`
+ Error: path to jsdoc html is invalid.
+ Ensure that this script is run from the project root and documentation has been generated\
+ `);
+ } else {
+ console.error(error)
+ }
+ process.exit(1)
+ }
+
+ await fs.mkdir(OUT_DIR, { recursive: true })
+
+ // Exit with error code if the there was some error
+ const errors = await Promise.all(TARGETS.map(processDirGlobals))
+ if (errors.find(each => each !== undefined)) process.exit(1)
+
+ console.log('Finished processing autocomplete documentation')
}
+
diff --git a/scripts/autocomplete.sh b/scripts/autocomplete.sh
deleted file mode 100755
index 5a996deba..000000000
--- a/scripts/autocomplete.sh
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python3
-
-from lxml import etree, html
-from pathlib import Path
-import os
-import re
-import json
-
-CONST_DECL = "const"
-FUNC_DECL = "func"
-
-
-base_dir = f"docs{os.path.sep}source"
-src_filename = "global.html"
-out_dir = f"src{os.path.sep}editors{os.path.sep}ace{os.path.sep}docTooltip"
-
-
-def new_title_node(title):
- node = etree.Element("h4")
- node.text = title
- return node
-
-
-def build_description_html(description_div):
- description_html = html.tostring(description_div).decode("utf-8")
-
- # There's a whole bunch of newlines between sections for some reason.
- # Main reason for this is to avoid double newlines inside code blocks.
- description_html = re.sub("\n+", "\n", description_html)
-
- return description_html
-
-
-def process_constant(namespace, element):
- header = element.find('./h4')
- raw_name = "".join(header.itertext())
- fields = raw_name.split()[1:] # first result just says (constant)
-
- name = header.attrib["id"]
- title = "".join(fields)
- if not title: # Some runes have no title
- title = name
-
- title_node = new_title_node(title)
-
- description_node = element.find('./div[@class="description"]')
-
- description_div = etree.Element("div")
- description_div.append(title_node)
- description_div.append(description_node)
-
- description_html = build_description_html(description_div)
-
- namespace[name] = {"title": title,
- "description": description_html, "meta": CONST_DECL}
-
-
-def process_function(namespace, element):
- header = element.find('./h4')
- title = "".join(header.itertext())
- name = header.attrib["id"]
-
- title_node = new_title_node(title)
-
- description_node = element.find('./div[@class="description"]')
-
- description_div = etree.Element("div")
- description_div.append(title_node)
- description_div.append(description_node)
-
- description_html = build_description_html(description_div)
-
- namespace[name] = {"title": title,
- "description": description_html, "meta": FUNC_DECL}
-
-
-def process_dir_globals(target):
- infile = os.path.join(base_dir, target, src_filename)
- with open(infile, encoding="utf-8") as f:
- contents = "\n".join(f.readlines())
- try:
- tree = etree.HTML(contents)
- except Exception as e:
- print(infile, "failed", e)
- return
-
- names = {}
-
- constants = tree.findall('.//div[@class="constant-entry"]')
- for c in constants:
- process_constant(names, c)
-
- functions = tree.findall('.//div[@class="function-entry"]')
- for f in functions:
- process_function(names, f)
-
- Path(out_dir).mkdir(parents=True, exist_ok=True)
- outfile = os.path.join(out_dir, target + ".json")
- with open(outfile, "w", encoding="utf-8") as f:
- json.dump(names, f, indent=2)
-
-# Folder names for jsdoc html
-targets = [
- "source_1",
- "source_1_lazy",
- "source_1_wasm",
- "source_2",
- "source_2_lazy",
- "source_3",
- "source_3_concurrent",
- "source_3_non-det",
- "source_4",
- "source_4_explicit-control"
- "External libraries",
-]
-
-for target in targets:
- if not os.path.exists(base_dir):
- print("""\
- Error: path to jsdoc html is invalid.
- Ensure that this script is run from the project root and documentation has been generated\
- """)
- exit(1)
-
- process_dir_globals(target)
-
diff --git a/scripts/docs.mjs b/scripts/docs.mjs
new file mode 100644
index 000000000..49688195c
--- /dev/null
+++ b/scripts/docs.mjs
@@ -0,0 +1,408 @@
+// @ts-check
+
+import { execFile, fork, spawn } from 'child_process'
+import pathlib from 'path'
+import fs from 'fs/promises'
+import { Command } from 'commander'
+import process from 'process'
+import autocomplete from './autocomplete.mjs'
+
+const configs = {
+ "landing": {
+ "readme": "README_top.md",
+ "dst": "",
+ "libs": [
+ "empty.js"
+ ]
+ },
+ "Source §1": {
+ "readme": "README_1.md",
+ "dst": "source_1/",
+ "libs": [
+ "misc.js",
+ "math.js"
+ ]
+ },
+ "Source §1 Lazy": {
+ "readme": "README_1_LAZY.md",
+ "dst": "source_1_lazy/",
+ "libs": [
+ "misc.js",
+ "math.js"
+ ]
+ },
+ "Source §1 Typed": {
+ "readme": "README_1_TYPED.md",
+ "dst": "source_1_typed/",
+ "libs": [
+ "misc.js",
+ "math.js"
+ ]
+ },
+ "Source §1 WebAssembly": {
+ "readme": "README_1_WASM.md",
+ "dst": "source_1_wasm/",
+ "libs": [
+ "empty.js"
+ ]
+ },
+ "Source §2": {
+ "readme": "README_2.md",
+ "dst": "source_2/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js"
+ ]
+ },
+ "Source §2 Lazy": {
+ "readme": "README_2_LAZY.md",
+ "dst": "source_2_lazy/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js"
+ ]
+ },
+ "Source §2 Typed": {
+ "readme": "README_2_TYPED.md",
+ "dst": "source_2_typed/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js"
+ ]
+ },
+ "Source §3": {
+ "readme": "README_3.md",
+ "dst": "source_3/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js"
+ ]
+ },
+ "Source §3 Concurrent": {
+ "readme": "README_3_CONCURRENT.md",
+ "dst": "source_3_concurrent/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js",
+ "concurrency.js"
+ ]
+ },
+ "Source §3 Typed": {
+ "readme": "README_3_TYPED.md",
+ "dst": "source_3_typed/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js"
+ ]
+ },
+ "Source §4": {
+ "readme": "README_4.md",
+ "dst": "source_4/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js",
+ "mce.js"
+ ]
+ },
+ "Source §4 Explicit-Control": {
+ "readme": "README_4_EXPLICIT-CONTROL.md",
+ "dst": "source_4_explicit-control/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js",
+ "mce.js",
+ "continuation.js"
+ ]
+ },
+ "Source §4 GPU": {
+ "readme": "README_4_GPU.md",
+ "dst": "source_4_gpu/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js"
+ ]
+ },
+ "Source §4 Typed": {
+ "readme": "README_4_TYPED.md",
+ "dst": "source_4_typed/",
+ "libs": [
+ "auxiliary.js",
+ "misc.js",
+ "math.js",
+ "list.js",
+ "stream.js",
+ "array.js",
+ "pairmutator.js",
+ "mce.js"
+ ]
+ },
+ "AUXILLARY": {
+ "readme": "README_AUXILIARY.md",
+ "dst": "AUXILIARY/",
+ "libs": [
+ "auxiliary.js"
+ ]
+ },
+ "MISC": {
+ "readme": "README_MISC.md",
+ "dst": "MISC/",
+ "libs": [
+ "misc.js"
+ ]
+ },
+ "MATH": {
+ "readme": "README_MATH.md",
+ "dst": "MATH/",
+ "libs": [
+ "math.js"
+ ]
+ },
+ "LIST": {
+ "readme": "README_LISTS.md",
+ "dst": "LISTS/",
+ "libs": [
+ "list.js"
+ ]
+ },
+ "STREAMS": {
+ "readme": "README_STREAMS.md",
+ "dst": "STREAMS/",
+ "libs": [
+ "stream.js"
+ ]
+ },
+ "ARRAYS": {
+ "readme": "README_ARRAYS.md",
+ "dst": "ARRAYS/",
+ "libs": [
+ "array.js"
+ ]
+ },
+ "PAIRMUTATIONS": {
+ "readme": "README_PAIRMUTATORS.md",
+ "dst": "PAIRMUTATORS/",
+ "libs": [
+ "pairmutator.js"
+ ]
+ },
+ "CONCURRENCY": {
+ "readme": "README_CONCURRENCY.md",
+ "dst": "CONCURRENCY/",
+ "libs": [
+ "concurrency.js"
+ ]
+ },
+ "MCE": {
+ "readme": "README_MCE.md",
+ "dst": "MCE/",
+ "libs": [
+ "mce.js"
+ ]
+ },
+ "CONTINUATION": {
+ "readme": "README_CONTINUATION.md",
+ "dst": "CONTINUATION/",
+ "libs": [
+ "continuation.js"
+ ]
+ },
+ "EV3": {
+ "readme": "EV3_README.md",
+ "dst": "EV3/",
+ "libs": [
+ "ev3.js"
+ ]
+ },
+ "EXTERNAL": {
+ "readme": "README_EXTERNAL.md",
+ "dst": "External libraries",
+ "libs": [
+ "ev3.js"
+ ]
+ }
+}
+
+const config_file = 'docs/jsdoc/conf.json'
+const readmes = 'docs/md'
+const libraries = 'docs/lib'
+const out_dir = 'docs/source'
+const jsdoc = "node_modules/jsdoc/jsdoc.js"
+const template_location = "docs/jsdoc/templates/template"
+const specs_dir = "docs/specs"
+
+async function run() {
+ await fs.mkdir(out_dir, { recursive: true })
+
+ const promises = Object.entries(configs).map(([name, config]) => {
+ // Use fork to start a new instance of nodejs and run jsdoc
+ // for each configuration
+ const proc = fork(jsdoc, [
+ '-r',
+ '-t', template_location,
+ '-c', config_file,
+ '-R', pathlib.join(readmes, config.readme),
+ '-d', pathlib.join(out_dir, config.dst),
+ ...config.libs.map(each => pathlib.join(libraries, each))
+ ])
+
+ proc.on('spawn', () => console.log(`Building ${name}`))
+ return new Promise(resolve => {
+ proc.on('exit', c => {
+ if (c === 0) {
+ console.log(`Finished ${name}`)
+ } else {
+ console.error(`Error occurred with ${name}: jsdoc exited with code ${c}`)
+ }
+ resolve(c)
+ })
+
+ proc.on('error', e => {
+ console.error(`Error occurred with ${name}: `, e)
+ resolve(1)
+ })
+ })
+ })
+
+ // If some instance returned a non zero return code,
+ // exit with that return code
+ const retcodes = await Promise.all(promises)
+ const nonzeroRetcode = retcodes.find(c => c !== 0)
+
+ if (nonzeroRetcode !== undefined) process.exit(nonzeroRetcode)
+}
+
+async function prepare({ silent }) {
+ await run()
+
+ // Copy images in images directory to out_dir
+ await fs.readdir('docs/images')
+ .then(images => Promise.all(images.map(async img => {
+ const srcPath = pathlib.join('docs/images', img)
+ const dstPath = pathlib.join(out_dir, img)
+ await fs.copyFile(srcPath, dstPath)
+ console.debug(`Copied ${srcPath} to ${dstPath}`)
+ })))
+
+ const makeProc = spawn('make', { cwd: specs_dir, stdio: [
+ 'ignore',
+ silent ? 'ignore' : 'inherit',
+ 'inherit'
+ ]})
+
+ const makeretcode = await new Promise(resolve => {
+ makeProc.on('exit', resolve)
+ makeProc.on('error', e => {
+ console.error('Failed to start make: ', e)
+ process.exit(1)
+ })
+ })
+
+ if (makeretcode !== 0) process.exit(makeretcode)
+ console.log('Finished running make')
+
+ // Copy pdf files that make produced to out_dir
+ await fs.readdir(specs_dir)
+ .then(files => Promise.all(files
+ .filter(file => pathlib.extname(file) === '.pdf')
+ .map(async file => {
+ const srcPath = pathlib.join(specs_dir, file)
+ const dstPath = pathlib.join(out_dir, file)
+ await fs.copyFile(srcPath, dstPath)
+ console.debug(`Copied ${srcPath} to ${dstPath}`)
+ })
+ ))
+}
+
+async function clean() {
+ await fs.rm(out_dir, { recursive: true })
+ console.log(`Cleared ${out_dir}`)
+}
+
+/**
+ * Check that the commands are being run from the root of the git repository
+ */
+async function checkGitRoot() {
+ const gitRoot = await new Promise(resolve => {
+ execFile('git', ['rev-parse', '--show-toplevel'], (err, stdout, stderr) => {
+ const possibleError = err || stderr
+ if (possibleError) {
+ console.error(possibleError)
+ process.exit(1)
+ }
+
+ resolve(stdout.trim())
+ })})
+
+ const procDir = pathlib.relative(gitRoot, '')
+ if (procDir !== '') {
+ console.error('Please run this command from the git root directory')
+ process.exit(1)
+ }
+}
+
+await new Command()
+ .hook('preAction', checkGitRoot)
+ .addCommand(
+ new Command('run')
+ .description('Run JSDOC and build documentation')
+ .action(run),
+ { isDefault: true }
+ )
+ .addCommand(
+ new Command('prepare')
+ .option('--silent', 'Run make without outputting to stdout')
+ .action(prepare)
+ )
+ .addCommand(
+ new Command('clean')
+ .description('Clear the output directory')
+ .action(clean)
+ )
+ .addCommand(
+ new Command('autocomplete')
+ .description('Update autocomplete documentation')
+ .action(autocomplete)
+ )
+ .addCommand(
+ new Command('docs')
+ .description('Execute the \'run\' command and then the \'autocomplete\' command')
+ .action(() => run().then(autocomplete))
+ )
+ .parseAsync()
+
\ No newline at end of file
diff --git a/scripts/jsdoc.sh b/scripts/jsdoc.sh
deleted file mode 100755
index 881d62fba..000000000
--- a/scripts/jsdoc.sh
+++ /dev/null
@@ -1,339 +0,0 @@
-#! /usr/bin/env bash
-
-set -e
-
-JSDOC="node_modules/.bin/jsdoc"
-TMPL="docs/jsdoc/templates/template"
-DST="docs/source"
-MD="docs/md"
-LIB="docs/lib"
-SPECS="docs/specs"
-
-main() {
-
- if [ "$1" == "prepare" ]; then
- prepare
- elif [ "$1" == "clean" ]; then
- clean
- elif [[ "$(git rev-parse --show-toplevel 2> /dev/null)" -ef "$PWD" ]]; then
- run
- else
- echo "Please run this command from the git root directory."
- false # exit 1
- fi
-}
-
-run() {
-
- # Source landing page
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_top.md \
- -d ${DST}/ \
- ${LIB}/empty.js
-
- # Source §1
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_1.md \
- -d ${DST}/"source_1"/ \
- ${LIB}/misc.js \
- ${LIB}/math.js
-
- # Source §1 Lazy
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_1_LAZY.md \
- -d ${DST}/"source_1_lazy"/ \
- ${LIB}/misc.js \
- ${LIB}/math.js
-
- # Source §1 Typed
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_1_TYPED.md \
- -d ${DST}/"source_1_typed"/ \
- ${LIB}/misc.js \
- ${LIB}/math.js
-
- # Source §1 WebAssembly
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_1_WASM.md \
- -d ${DST}/"source_1_wasm"/ \
- ${LIB}/empty.js
-
- # Source §2
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_2.md \
- -d ${DST}/"source_2"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js
-
- # Source §2 Lazy
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_2_LAZY.md \
- -d ${DST}/"source_2_lazy"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js
-
- # Source §2 Typed
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_2_TYPED.md \
- -d ${DST}/"source_2_typed"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js
-
- # Source §3
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_3.md \
- -d ${DST}/"source_3"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js
-
- # Source §3 Concurrent
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_3_CONCURRENT.md \
- -d ${DST}/"source_3_concurrent"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js \
- ${LIB}/concurrency.js
-
- # Source §3 Non-Det
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_3_NON-DET.md \
- -d ${DST}/"source_3_non-det"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js \
- ${LIB}/non-det.js
-
- # Source §3 Typed
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_3_TYPED.md \
- -d ${DST}/"source_3_typed"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js
-
- # Source §4
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_4.md \
- -d ${DST}/"source_4"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js \
- ${LIB}/mce.js
-
- # Source §4 Explicit-Control
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_4_EXPLICIT-CONTROL.md \
- -d ${DST}/"source_4_explicit-control"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js \
- ${LIB}/mce.js \
- ${LIB}/continuation.js
-
- # Source §4 GPU
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_4_GPU.md \
- -d ${DST}/"source_4_gpu"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js
-
- # Source §4 Typed
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_4_TYPED.md \
- -d ${DST}/"source_4_typed"/ \
- ${LIB}/auxiliary.js \
- ${LIB}/misc.js \
- ${LIB}/math.js \
- ${LIB}/list.js \
- ${LIB}/stream.js \
- ${LIB}/array.js \
- ${LIB}/pairmutator.js \
- ${LIB}/mce.js
-
- # AUXILIARY
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_AUXILIARY.md \
- -d ${DST}/AUXILIARY/ \
- ${LIB}/auxiliary.js
-
- # MISC
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_MISC.md \
- -d ${DST}/MISC/ \
- ${LIB}/misc.js
-
- # MATH
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_MATH.md \
- -d ${DST}/MATH/ \
- ${LIB}/math.js
-
- # LISTS
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_LISTS.md \
- -d ${DST}/LISTS/ \
- ${LIB}/list.js
-
- # STREAMS
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_STREAMS.md \
- -d ${DST}/STREAMS/ \
- ${LIB}/stream.js
-
- # ARRAYS
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_ARRAYS.md \
- -d ${DST}/ARRAYS/ \
- ${LIB}/array.js
-
- # PAIRMUTATORS
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_PAIRMUTATORS.md \
- -d ${DST}/PAIRMUTATORS/ \
- ${LIB}/pairmutator.js
-
- # CONCURRENCY
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_CONCURRENCY.md \
- -d ${DST}/CONCURRENCY/ \
- ${LIB}/concurrency.js
-
- # NON-DET
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_NON-DET.md \
- -d ${DST}/NON-DET/ \
- ${LIB}/non-det.js
-
- # MCE
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_MCE.md \
- -d ${DST}/MCE/ \
- ${LIB}/mce.js
-
- # CONTINUATION
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_CONTINUATION.md \
- -d ${DST}/CONTINUATION/ \
- ${LIB}/continuation.js
-
- # EV3
-
- ${JSDOC} -r -t ${TMPL} \
- -c docs/jsdoc/conf.json \
- -d "${DST}/EV3/" \
- -R ${MD}/EV3_README.md \
- ${LIB}/ev3.js
-
- # External
-
- ${JSDOC} -r -t ${TMPL}/ \
- -c docs/jsdoc/conf.json \
- -R ${MD}/README_EXTERNAL.md \
- -d ${DST}/"External libraries"/ \
- ${LIB}/ev3.js
-}
-
-prepare() {
- run
- cp -r docs/images ${DST} ; \
- cd ${SPECS}; make; cp *.pdf ../source; cd ../..
-}
-
-clean() {
-
- rm -rf ${DST}/*
-
-}
-
-main $1
diff --git a/src/__tests__/non-det-interpreter.ts b/src/__tests__/non-det-interpreter.ts
deleted file mode 100644
index 8f35874cd..000000000
--- a/src/__tests__/non-det-interpreter.ts
+++ /dev/null
@@ -1,1044 +0,0 @@
-/* tslint:disable:max-line-length */
-import { IOptions, parseError, Result, resume, runInContext } from '../index'
-import { mockContext } from '../mocks/context'
-import { Context, Finished, SuspendedNonDet, Variant } from '../types'
-
-test('Empty code returns undefined', async () => {
- await testDeterministicCode('', undefined)
-})
-
-test('Unary operations', async () => {
- await testDeterministicCode('-12 - 8;', -20)
- await testDeterministicCode('!true;', false)
- await testDeterministicCode('!(false);', true)
-})
-
-test('Unary operations with non deterministic terms', async () => {
- await testNonDeterministicCode('-amb(12, 24) - 8;', [-20, -32])
- await testNonDeterministicCode('!amb(true, false);', [false, true])
-})
-
-test('Unary operations on the wrong type should cause error', async () => {
- await testDeterministicCode('!100;', 'Line 1: Expected boolean, got number.', true)
-})
-
-test('Binary operations', async () => {
- await testDeterministicCode('1 + 4 - 10 * 5;', -45)
- await testDeterministicCode('"hello" + " world" + "!";', 'hello world!')
- await testDeterministicCode('(23 % 3) * (10 / 2);', 10)
-})
-
-test('Binary operations with non deterministic terms', async () => {
- await testNonDeterministicCode('1 + amb(4) - 10 * 5;', [-45])
- await testNonDeterministicCode('amb("hello", "bye") + " world" + "!";', [
- 'hello world!',
- 'bye world!'
- ])
- await testNonDeterministicCode('amb((23 % 3), 7) * amb((10 / 2), 19 - 5);', [10, 28, 35, 98])
-})
-
-test('Binary operations on the wrong types should cause error', async () => {
- await testDeterministicCode(
- 'false + 4;',
- 'Line 1: Expected string or number on left hand side of operation, got boolean.',
- true
- )
-})
-
-test('Assignment', async () => {
- await testDeterministicCode('let a = 5; a = 10; a;', 10)
-})
-
-test('Assignment with non deterministic terms', async () => {
- await testNonDeterministicCode('let a = amb(1, 2); a = amb(4, 5); a;', [4, 5, 4, 5])
-
- await testNonDeterministicCode(
- `let num = 5;
- function reassign_num() { num = 10; return num; }
- amb(reassign_num(), num);`,
- [10, 5]
- )
-})
-
-test('Re-assignment to constant should cause error', async () => {
- await testDeterministicCode(
- `const f = 10; { f = 20; }`,
- 'Line 1: Cannot assign new value to constant f.',
- true
- )
-})
-
-test('Accessing un-declared variable should cause error', async () => {
- await testDeterministicCode(`let g = 100; f;`, 'Name f not declared.', true)
-})
-
-test('If-else and conditional expressions with non deterministic terms', async () => {
- await testNonDeterministicCode('amb(false, true) ? 4 - 10 : 6;', [6, -6])
- await testNonDeterministicCode(
- `if (amb(true, false)) {
- -100;
- } else {
- 200 / 2;
- 210;
- }`,
- [-100, 210]
- )
- await testNonDeterministicCode(
- `if (amb(100 * 2 === 2, 40 % 2 === 0)) {
- amb(false, 'test' === 'test') ? amb(false === false, false) ? "hello" : false : amb(5, "world");
- } else {
- 9 * 10 / 5;
- }`,
- [18, 5, 'world', 'hello', false]
- )
-})
-
-test('Conditional expression with non boolean predicate should cause error', async () => {
- await testDeterministicCode(
- '100 ? 5 : 5;',
- 'Line 1: Expected boolean as condition, got number.',
- true
- )
-})
-
-test('Logical expressions', async () => {
- await testDeterministicCode(`true && (false || true) && (true && false);`, false)
-
- await testDeterministicCode(
- `function foo() { return foo(); }\
- true || foo();`,
- true
- )
-
- await testDeterministicCode(
- `function foo() { return foo(); }\
- false && foo();`,
- false
- )
-})
-
-test('Logical expressions with non deterministic terms', async () => {
- await testNonDeterministicCode(
- `amb(true, false) && amb(false, true) || amb(false);
- `,
- [false, true, false]
- )
-})
-
-test('Function applications', async () => {
- await testDeterministicCode(
- `function f() {} f();
- `,
- undefined
- )
-
- await testDeterministicCode(
- `function factorial(n) {
- return n === 0 ? 1 : n * factorial(n - 1);
- }
- factorial(5);
- `,
- 120
- )
-
- await testDeterministicCode(
- 'function f(x) { function subfunction(y) { return y * 2; } return x * subfunction(10); } f(6);',
- 120
- )
-
- await testDeterministicCode(
- `function noReturnStatement_returnsUndefined() {
- 20 + 40 - 6;
- 5 - 5;
- list();
- reverse(list(1));
- }`,
- undefined
- )
-
- await testDeterministicCode(`const a = 2; a();`, 'Line 1: Calling non-function value 2.', true)
-
- await testDeterministicCode(
- `(function() {})();`,
- 'Line 1: Function expressions are not allowed',
- true
- )
-
- await testDeterministicCode(
- `function ignoreStatementsAfterReturn(n) {
- return n; return n * 2;
- }
- ignoreStatementsAfterReturn(5);
- `,
- 5
- )
-})
-
-test('Applying functions with wrong number of arguments should cause error', async () => {
- await testDeterministicCode(
- `function foo(a, b) {
- return a + b;
- }
- foo(1);
- `,
- `Line 4: Expected 2 arguments, but got 1.`,
- true
- )
-})
-
-test('Builtin list functions', async () => {
- await testDeterministicCode('pair(false, 10);', [false, 10])
- await testDeterministicCode('list();', null)
- await testDeterministicCode('list(1);', [1, null])
- await testDeterministicCode('head(list(1));', 1)
- await testDeterministicCode('tail(list(1));', null)
-})
-
-test('Builtin list functions with non deterministic terms', async () => {
- await testNonDeterministicCode('pair(amb(false, true), 10);', [
- [false, 10],
- [true, 10]
- ])
- await testNonDeterministicCode('list(amb());', [])
- await testNonDeterministicCode('list(amb(1,2));', [
- [1, null],
- [2, null]
- ])
- await testNonDeterministicCode('head(amb(list(100), list(20, 30)));', [100, 20])
-})
-
-test('Prelude list functions', async () => {
- await testDeterministicCode('is_null(null);', true)
- await testDeterministicCode('is_null(list(null));', false)
- await testDeterministicCode(
- `function increment(n) { return n + 1; }
- map(increment, list(100, 101, 200));
- `,
- [101, [102, [201, null]]]
- )
- await testDeterministicCode('append(list(5), list(6,20));', [5, [6, [20, null]]])
- await testDeterministicCode('append(list(4,5), list());', [4, [5, null]])
- await testDeterministicCode('reverse(list("hello", true, 0));', [0, [true, ['hello', null]]])
-})
-
-test('Empty amb application', async () => {
- await testNonDeterministicCode('amb();', [])
-})
-
-test('Simple amb application', async () => {
- await testNonDeterministicCode('amb(1, 4 + 5, 3 - 10);', [1, 9, -7])
-})
-
-test('Functions with non deterministic terms', async () => {
- await testNonDeterministicCode(
- `function foo() {
- return amb(true, false) ? 'a string' : amb(10, 20);
- }
- foo();`,
- ['a string', 10, 20]
- )
-})
-
-test('Functions as amb arguments', async () => {
- await testNonDeterministicCode(
- ' const is_even = num => (num % 2) === 0;\
- const add_five = num => num + 5;\
- const nondet_func = amb(is_even, add_five, num => !is_even(num));\
- nondet_func(5);\
- ',
- [false, 10, true]
- )
-})
-
-test('Combinations of amb', async () => {
- await testNonDeterministicCode('list(amb(1, 2, 3), amb("a", "b"));', [
- [1, ['a', null]],
- [1, ['b', null]],
- [2, ['a', null]],
- [2, ['b', null]],
- [3, ['a', null]],
- [3, ['b', null]]
- ])
-})
-
-test('Require operator', async () => {
- await testNonDeterministicCode(
- ' \
- function int_between(low, high) { \
- return low > high ? amb() : amb(low, int_between(low + 1, high)); \
- } \
- let integer = int_between(5, 10);\
- require(integer % 3 === 0); \
- integer;\
- ',
- [6, 9]
- )
-
- await testNonDeterministicCode(
- `const f = an_integer_between(1, 10); require(f > 3, true); f;`,
- ['Line 1: Expected 1 arguments, but got 2.'],
- true
- )
-})
-
-test('Cut operator', async () => {
- await testNonDeterministicCode(
- `const f = amb(1, 2, 3); cut(); f + amb(4, 5, 6);
- `,
- [5, 6, 7]
- )
-
- await testNonDeterministicCode(
- `const f = amb(1, 2, 3); const g = amb(4, 5, 6); cut(); f + g;
- `,
- [5]
- )
-})
-
-/* Deterministic block scoping tests taken from block-scoping.ts */
-
-test('Block statements', async () => {
- await testDeterministicCode(
- `
- function test(){
- const x = true;
- {
- const x = false;
- }
- return x;
- }
- test();
- `,
- true
- )
-
- await testDeterministicCode(
- `
- function test(){
- let x = true;
- if(true) {
- let x = false;
- } else {
- let x = false;
- }
- return x;
- }
- test();
- `,
- true
- )
-
- await testDeterministicCode(
- `
- const v = f();
- function f() {
- return 1;
- }
- v;
- `,
- 'Name f declared later in current scope but not yet assigned',
- true
- )
-
- await testDeterministicCode(
- `
- const a = 1;
- function f() {
- display(a);
- const a = 5;
- }
- f();
- `,
- 'Name a declared later in current scope but not yet assigned',
- true
- )
-
- await testDeterministicCode(
- `
- const a = 1;
- {
- a + a;
- const a = 10;
- }
- `,
- 'Name a declared later in current scope but not yet assigned',
- true
- )
-
- await testDeterministicCode(
- `
- let variable = 1;
- function test(){
- variable = 100;
- let variable = true;
- return variable;
- }
- test();
- `,
- 'Name variable not declared.',
- true
- )
-})
-
-test('ambR application', async () => {
- await testNonDeterministicCode('ambR();', [], false, true)
-
- await testNonDeterministicCode('ambR(1, 2, 3, 4, 5);', [1, 2, 3, 4, 5], false, true)
-
- await testNonDeterministicCode(
- 'ambR(ambR(4, 5, 6, 7), ambR(3, 8));',
- [4, 5, 6, 7, 3, 8],
- false,
- true
- )
-})
-
-test('Deterministic arrays', async () => {
- await testDeterministicCode(`[];`, [])
-
- await testDeterministicCode(`const a = [[1, 2], [3, [4]]]; a;`, [
- [1, 2],
- [3, [4]]
- ])
-
- await testDeterministicCode(`const a = [[[[6]]]]; a[0][0][0][0];`, 6)
-
- await testDeterministicCode(`const f = () => 2; const a = [1, f(), 3]; a;`, [1, 2, 3])
-
- await testDeterministicCode(
- `[1, 1, 1][4.4];`,
- 'Line 1: Expected array index as prop, got other number.',
- true
- )
-
- await testDeterministicCode(
- `[1, 1, 1]["str"] = 2;`,
- 'Line 1: Expected array index as prop, got string.',
- true
- )
-
- await testDeterministicCode(`4[0];`, 'Line 1: Expected object or array, got number.', true)
-})
-
-test('Non-deterministic array values', async () => {
- await testNonDeterministicCode(`const a = [amb(1, 2), amb(3, 4)]; a;`, [
- [1, 3],
- [1, 4],
- [2, 3],
- [2, 4]
- ])
-
- await testNonDeterministicCode(`const a = [1, 2, 3, 4]; a[2] = amb(10, 11, 12); a;`, [
- [1, 2, 10, 4],
- [1, 2, 11, 4],
- [1, 2, 12, 4]
- ])
-})
-
-test('Non-deterministic array objects', async () => {
- await testNonDeterministicCode(
- `const a = [1, 2]; const b = [3, 4];
- amb(a, b)[1] = 99; a;
- `,
- [
- [1, 99],
- [1, 2]
- ]
- )
-
- await testNonDeterministicCode(
- `const a = [1, 2]; const b = [3, 4];
- amb(a, b)[1] = 99; b;
- `,
- [
- [3, 4],
- [3, 99]
- ]
- )
-})
-
-test('Non-deterministic array properties', async () => {
- await testNonDeterministicCode(
- `
- const a = [100, 101, 102, 103];
- a[amb(0, 1, 2, 3)] = 999; a;
- `,
- [
- [999, 101, 102, 103],
- [100, 999, 102, 103],
- [100, 101, 999, 103],
- [100, 101, 102, 999]
- ]
- )
-})
-
-test('Material Conditional', async () => {
- await testDeterministicCode(`implication(true, true);`, true)
- await testDeterministicCode(`implication(true, false);`, false)
- await testDeterministicCode(`implication(false, true);`, true)
- await testDeterministicCode(`implication(false, false);`, true)
-})
-
-test('Material Biconditional', async () => {
- await testDeterministicCode(`bi_implication(true, true);`, true)
- await testDeterministicCode(`bi_implication(true, false);`, false)
- await testDeterministicCode(`bi_implication(false, true);`, false)
- await testDeterministicCode(`bi_implication(false, false);`, true)
-})
-
-test('While loops', async () => {
- await testDeterministicCode(
- `
- let i = 2;
- while (false) {
- i = i - 1;
- }
- i;`,
- 2
- )
-
- await testDeterministicCode(
- `
- let i = 5;
- while (i > 0) {
- i = i - 1;
- }`,
- 0
- )
-
- await testDeterministicCode(
- `
- let i = 5;
- let j = 0;
- while (i > 0 && j < 5) {
- i = i - 1;
- j = j + 2;
- }`,
- 6
- )
-
- await testDeterministicCode(
- `
- let i = 2;
- while (i) {
- i = i - 1;
- }
- i;`,
- 'Line 3: Expected boolean as condition, got number.',
- true
- )
-})
-
-test('Let statement should be block scoped in body of while loop', async () => {
- await testDeterministicCode(
- `
- let i = 2;
- let x = 5;
- while (i > 0) {
- i = i - 1;
- let x = 10;
- }
- x;`,
- 5
- )
-
- await testDeterministicCode(
- `
- let i = 2;
- while (i > 0) {
- i = i - 1;
- let x = 5;
- }
- x;`,
- 'Name x not declared.',
- true
- )
-})
-
-test('Nested while loops', async () => {
- await testDeterministicCode(
- `
- let count = 0;
- let i = 1;
- while (i > 0) {
- let j = 2;
- while (j > 0) {
- let k = 4;
- while (k > 0) {
- count = count + 1;
- k = k - 1;
- }
- j = j - 1;
- }
- i = i - 1;
- }
- count;`,
- 8
- )
-})
-
-test('Break statement in while loop body', async () => {
- await testDeterministicCode(
- `
- let i = 5;
- while (i > 0) {
- i = i - 1;
- break;
- }
- i;`,
- 4
- )
-})
-
-test('Continue statement in while loop body', async () => {
- await testDeterministicCode(
- `
- let i = 5;
- let j = 0;
- while (i > 0 && j < 5) {
- i = i - 1;
- continue;
- j = j + 2;
- }
- j;`,
- 0
- )
-})
-
-test('Return statement in while loop body', async () => {
- await testDeterministicCode(
- `
- function loopTest(i, j) {
- while (i > 0 && j > i) {
- return i * j;
- i = i - 1;
- j = j + i;
- }
- }
- loopTest(5, 10);`,
- 50
- )
-})
-
-test('Non-deterministic while loop condition', async () => {
- await testNonDeterministicCode(
- `
- let i = amb(3, 4);
- let j = 0;
- while (i > 0) {
- i = i - 1;
- j = j + 1;
- }
- j;`,
- [3, 4]
- )
-
- await testNonDeterministicCode(
- `
- let i = 1;
- let j = 2;
- let count = 0;
- while (amb(i, j) > 0) {
- i = i - 1;
- j = j - 1;
- count = count + 1;
- }
- count;`,
- [1, 2, 2, 1, 2, 2]
- ) // chosen variables: (i,i), (i,j,i), (i,j,j), (j,i), (j,j,i), (j,j,j)
-})
-
-test('Non-deterministic while loop body', async () => {
- /* number of total program values =
- (number of values from cartesian product of the statements in loop body)^
- (number of loop iterations)
- */
-
- await testNonDeterministicCode(
- `
- let i = 3;
- let count = 0;
- while (i > 0) {
- count = count + amb(0, 1);
- i = i - 1;
- }
- count;`,
- [0, 1, 1, 2, 1, 2, 2, 3]
- )
-
- await testNonDeterministicCode(
- `
- let i = 2;
- let count = 0;
- while (i > 0) {
- count = count + amb(0, 1);
- count = count + amb(0, 1);
- i = i - 1;
- }
- count;`,
- [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
- )
-})
-
-test('For loops', async () => {
- await testDeterministicCode(
- `
- let i = 0;
- for (i; i < 0; i = i + 1) {
- }
- i;
- `,
- 0
- )
-
- await testDeterministicCode(
- `
- for (let i = 0; i < 5; i = i + 1) {
- i;
- }
- `,
- 4
- )
-
- await testDeterministicCode(
- `
- let count = 0;
- for (let i = 5; i > 0; i = i - 2) {
- count = count + 1;
- }
- count;
- `,
- 3
- )
-
- await testDeterministicCode(
- `
- for (let i = 0; 2; i = i + 1) {
- }
- `,
- 'Line 2: Expected boolean as condition, got number.',
- true
- )
-})
-
-test('Let statement should be block scoped in head of for loop', async () => {
- await testDeterministicCode(
- `
- for (let i = 2; i > 0; i = i - 1) {
- }
- i;
- `,
- 'Name i not declared.',
- true
- )
-})
-
-test('Let statement should be block scoped in body of for loop', async () => {
- await testDeterministicCode(
- `
- let x = 0;
- for (x; x < 10; x = x + 1) {
- let x = 1;
- }
- x;`,
- 10
- )
-
- await testDeterministicCode(
- `
- for (let i = 2; i > 0; i = i - 1) {
- let x = 5;
- }
- x;
- `,
- 'Name x not declared.',
- true
- )
-})
-
-test('Loop control variable should be copied into for loop body', async () => {
- await testDeterministicCode(
- `
- let arr = [];
- for (let i = 0; i < 5; i = i + 1) {
- arr[i] = () => i;
- }
- arr[3]();`,
- 3
- )
-})
-
-test('Assignment to loop control variable', async () => {
- await testDeterministicCode(
- `
- for (let i = 0; i < 2; i = i + 1){
- i = i + 1;
- }
- `,
- 'Line 3: Assignment to a for loop variable in the for loop is not allowed.',
- true
- )
-
- await testDeterministicCode(
- `
- let i = 0;
- for (i; i < 2; i = i + 1){
- i = i + 1;
- }
- i;`,
- 2
- )
-})
-
-test('Nested for loops', async () => {
- await testDeterministicCode(
- `
- let count = 0;
- for (let i = 0; i < 1; i = i + 1) {
- for (let j = 0; j < 2; j = j + 1) {
- for (let k = 0; k < 4; k = k + 1) {
- count = count + 1;
- }
- }
- }
- count;
- `,
- 8
- )
-})
-
-test('Break statement in for loop body', async () => {
- await testDeterministicCode(
- `
- let count = 0;
- for (let i = 0; i < 5; i = i + 1) {
- break;
- count = count + 1;
- }
- count;`,
- 0
- )
-})
-
-test('Continue statement in for loop body', async () => {
- await testDeterministicCode(
- `
- let count = 0;
- for (let i = 0; i < 5; i = i + 1) {
- continue;
- count = count + 1;
- }
- count;`,
- 0
- )
-})
-
-test('Return statement in for loop body', async () => {
- await testDeterministicCode(
- `
- let count = 0;
- function loopTest(x) {
- for (let i = 0; i < 5; i = i + 1) {
- return x;
- count = count + 1;
- }
- }
- loopTest(10);`,
- 10
- )
-})
-
-test('Non-deterministic for loop initializer', async () => {
- await testNonDeterministicCode(
- `
- let j = 0;
- for (let i = amb(3, 4); i > 0; i = i - 1) {
- j = j + 1;
- }
- j;`,
- [3, 4]
- )
-})
-
-test('Non-deterministic for loop condition', async () => {
- await testNonDeterministicCode(
- `
- let count = 0;
- for (let i = 2; i > amb(0, 1); i = i - 1) {
- count = count + 1;
- }
- count;`,
- [2, 2, 1, 2, 2, 1]
- ) // chosen conditions: (0, 0, 0), (0, 0, 1), (0, 1), (1, 0, 0), (1, 0, 1), (1, 1)
-})
-
-test('Non-deterministic for loop update', async () => {
- await testNonDeterministicCode(
- `
- let count = 0;
- for (let i = 2; i > 0; i = i - amb(1, 2)) {
- count = count + 1;
- }
- count;`,
- [2, 2, 1]
- ) // chosen updates: (1, 1), (1, 2), (2)
-})
-
-test('Non-deterministic for loop body', async () => {
- /* number of total program values =
- (number of values from cartesian product of the statements in loop body)^
- (number of loop iterations)
- */
-
- await testNonDeterministicCode(
- `
- let count = 0;
- for (let i = 3; i > 0; i = i - 1) {
- count = count + amb(0, 1);
- }
- count;`,
- [0, 1, 1, 2, 1, 2, 2, 3]
- )
-
- await testNonDeterministicCode(
- `
- let count = 0;
- for (let i = 2; i > 0; i = i - 1) {
- count = count + amb(0, 1);
- count = count + amb(0, 1);
- }
- count;`,
- [0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4]
- )
-
- await testNonDeterministicCode(
- `
- const N = 2;
- let arr = [];
- for (let r = 0; r < N; r = r + 1) {
- arr[r] = [];
- for (let c = 0; c < N; c = c + 1) {
- arr[r][c] = an_integer_between(1, N);
- }
- }
- require(arr[0][0] === 2);
- arr;`,
- [
- [
- [2, 1],
- [1, 1]
- ],
- [
- [2, 1],
- [1, 2]
- ],
- [
- [2, 1],
- [2, 1]
- ],
- [
- [2, 1],
- [2, 2]
- ],
- [
- [2, 2],
- [1, 1]
- ],
- [
- [2, 2],
- [1, 2]
- ],
- [
- [2, 2],
- [2, 1]
- ],
- [
- [2, 2],
- [2, 2]
- ]
- ]
- )
-})
-
-// ---------------------------------- Helper functions -------------------------------------------
-
-const nonDetTestOptions = {
- executionMethod: 'interpreter'
-} as Partial
-
-export async function testDeterministicCode(
- code: string,
- expectedValue: any,
- hasError: boolean = false
-) {
- /* a deterministic program is equivalent to a non deterministic program
- that returns a single value */
- await testNonDeterministicCode(code, [expectedValue], hasError)
-}
-
-/* Assumes the error message (if any) is at the last index of expectedValues */
-export async function testNonDeterministicCode(
- code: string,
- expectedValues: any[],
- hasError: boolean = false,
- random: boolean = false
-) {
- const context: Context = makeNonDetContext()
- let result: Result = await runInContext(code, context, nonDetTestOptions)
-
- const results: any[] = []
- const numOfRuns = hasError ? expectedValues.length - 1 : expectedValues.length
- for (let i = 0; i < numOfRuns; i++) {
- if (random) {
- results.push((result as SuspendedNonDet).value)
- } else {
- expect((result as SuspendedNonDet).value).toEqual(expectedValues[i])
- }
-
- expect(result.status).toEqual('suspended-non-det')
- result = await resume(result)
- }
-
- if (random) {
- verifyRandomizedTest(results, expectedValues)
- }
-
- if (hasError) {
- verifyError(result, expectedValues, context)
- } else {
- verifyFinalResult(result)
- }
-}
-
-/* Checks the final result obtained for a test
- * Assumes the test is not erroneous
- */
-function verifyFinalResult(result: Result) {
- // all non deterministic programs have a final result whose value is undefined
- expect(result.status).toEqual('finished')
- expect((result as Finished).value).toEqual(undefined)
-}
-
-/* Checks the error obtained for an erroneous test
- * The error message is captured as the test's final result
- */
-function verifyError(result: Result, expectedValues: any[], context: Context) {
- expect(result.status).toEqual('error')
- const message: string = parseError(context.errors)
- expect(message).toEqual(expectedValues[expectedValues.length - 1])
-}
-
-/* Compares expected and obtained results after a test is run
- * Assumes the test involves randomization
- */
-function verifyRandomizedTest(results: any[], expectedValues: any[]) {
- results.sort()
- expectedValues.sort()
- expect(results).toEqual(expectedValues)
-}
-
-function makeNonDetContext() {
- const context = mockContext(3, Variant.NON_DET)
- context.executionMethod = 'interpreter'
- return context
-}
diff --git a/src/__tests__/non-det-sicp-examples.ts b/src/__tests__/non-det-sicp-examples.ts
deleted file mode 100644
index 5c8ee8896..000000000
--- a/src/__tests__/non-det-sicp-examples.ts
+++ /dev/null
@@ -1,209 +0,0 @@
-/* This file uses programs from SICP JS 4.3 as tests for the non deterministic interpreter */
-import { testNonDeterministicCode } from './non-det-interpreter'
-
-test('An element of', async () => {
- await testNonDeterministicCode(`an_element_of(list(1, 2, list(3, 4)));`, [1, 2, [3, [4, null]]])
-})
-
-test('An integer between', async () => {
- await testNonDeterministicCode('an_integer_between(5, 10);', [5, 6, 7, 8, 9, 10])
-})
-
-test('Pythagorean triple', async () => {
- await testNonDeterministicCode(
- `function a_pythagorean_triple_between(low, high) {
- const i = an_integer_between(low, high);
- const j = an_integer_between(i, high);
- const k = an_integer_between(j, high);
- require(i * i + j * j === k * k);
- return list(i, j, k);
- }
- a_pythagorean_triple_between(3, 5);`,
- [[3, [4, [5, null]]]]
- )
-})
-
-test('Multiple dwelling problem', async () => {
- await testNonDeterministicCode(
- `
- function distinct(items) {
- return is_null(items)
- ? true
- : is_null(tail(items))
- ? true
- : is_null(member(head(items), tail(items)))
- ? distinct(tail(items))
- : false;
- }
- function multiple_dwelling() {
- const baker = amb(1, 2, 3, 4, 5);
- const cooper = amb(1, 2, 3, 4, 5);
- const fletcher = amb(1, 2, 3, 4, 5);
- const miller = amb(1, 2, 3, 4, 5);
- const smith = amb(1, 2, 3, 4, 5);
- require(distinct(list(baker, cooper, fletcher, miller, smith)));
- require(!(baker === 5));
- require(!(cooper === 1));
- require(!(fletcher === 5));
- require(!(fletcher === 1));
- require((miller > cooper));
- require(!(math_abs(smith - fletcher) === 1));
- require(!(math_abs(fletcher - cooper) === 1));
- return list(list("baker", baker),
- list("cooper", cooper),
- list("fletcher", fletcher),
- list("miller", miller),
- list("smith", smith));
- }
- multiple_dwelling();`,
- [
- [
- ['baker', [3, null]],
- [
- ['cooper', [2, null]],
- [
- ['fletcher', [4, null]],
- [
- ['miller', [5, null]],
- [['smith', [1, null]], null]
- ]
- ]
- ]
- ]
- ]
- )
-})
-
-test('Language parsing', async () => {
- await testNonDeterministicCode(
- `
- let unparsed = null;
-
- const nouns = list("noun", "student", "professor", "cat", "class");
- const verbs = list("verb", "studies", "lectures", "eats", "sleeps");
- const articles = list("article", "the", "a");
- const prepositions = list("prep", "for", "to", "in", "by", "with");
-
- function parse_word(word_list) {
- require(! is_null(unparsed));
- require(member(head(unparsed), tail(word_list)) !== null);
- const found_word = head(unparsed);
- unparsed = tail(unparsed);
- return list(head(word_list), found_word);
- }
-
- function parse_prepositional_phrase() {
- return list("prep-phrase",
- parse_word(prepositions),
- parse_noun_phrase());
- }
-
- function parse_verb_phrase() {
- function maybe_extend(verb_phrase) {
- return amb(verb_phrase,
- maybe_extend(list("verb-phrase",
- verb_phrase,
- parse_prepositional_phrase())));
- }
- return maybe_extend(parse_word(verbs));
- }
-
- function parse_simple_noun_phrase() {
- return list("simple-noun-phrase",
- parse_word(articles),
- parse_word(nouns));
- }
-
- function parse_noun_phrase() {
- function maybe_extend(noun_phrase) {
- return amb(noun_phrase,
- maybe_extend(list("noun-phrase",
- noun_phrase,
- parse_prepositional_phrase())));
- }
- return maybe_extend(parse_simple_noun_phrase());
- }
-
- function parse_sentence() {
- return list("sentence",
- parse_noun_phrase(),
- parse_verb_phrase());
- }
-
- function parse_input(input) {
- unparsed = input;
- const sent = parse_sentence();
- require(is_null(unparsed));
- return sent;
- }
-
- parse_input(list("the", "student", "with", "the", "cat", "sleeps", "in", "the", "class"));
- `,
- [
- [
- 'sentence',
- [
- [
- 'noun-phrase',
- [
- [
- 'simple-noun-phrase',
- [
- ['article', ['the', null]],
- [['noun', ['student', null]], null]
- ]
- ],
- [
- [
- 'prep-phrase',
- [
- ['prep', ['with', null]],
- [
- [
- 'simple-noun-phrase',
- [
- ['article', ['the', null]],
- [['noun', ['cat', null]], null]
- ]
- ],
- null
- ]
- ]
- ],
- null
- ]
- ]
- ],
- [
- [
- 'verb-phrase',
- [
- ['verb', ['sleeps', null]],
- [
- [
- 'prep-phrase',
- [
- ['prep', ['in', null]],
- [
- [
- 'simple-noun-phrase',
- [
- ['article', ['the', null]],
- [['noun', ['class', null]], null]
- ]
- ],
- null
- ]
- ]
- ],
- null
- ]
- ]
- ],
- null
- ]
- ]
- ]
- ]
- )
-})
diff --git a/src/__tests__/stringify.ts b/src/__tests__/stringify.ts
index 60b10301f..27b846b8b 100644
--- a/src/__tests__/stringify.ts
+++ b/src/__tests__/stringify.ts
@@ -405,7 +405,7 @@ test('String representation of non literal objects is nice', () => {
test('String representation of non literal objects in nested object is nice', () => {
const errorMsg: string = 'This is an error'
const errorObj: Error = new Error(errorMsg)
- const nestedObj: Object = {
+ const nestedObj = {
data: [1, [2, errorObj], 3]
}
return expect(stringify(nestedObj)).toMatchInlineSnapshot(
diff --git a/src/alt-langs/scheme/scheme-mapper.ts b/src/alt-langs/scheme/scheme-mapper.ts
index 468c33870..cb1c3c43f 100644
--- a/src/alt-langs/scheme/scheme-mapper.ts
+++ b/src/alt-langs/scheme/scheme-mapper.ts
@@ -7,7 +7,7 @@ import { List, Pair } from "../../stdlib/list"
import { Representation } from "../mapper"
export function mapResultToScheme(res: Result): Result {
- if (res.status === "finished" || res.status === "suspended-non-det") {
+ if (res.status === "finished") {
return {
...res,
value: decodeValue(res.value),
diff --git a/src/alt-langs/scheme/scm-slang b/src/alt-langs/scheme/scm-slang
index 908574c57..23d97f8c8 160000
--- a/src/alt-langs/scheme/scm-slang
+++ b/src/alt-langs/scheme/scm-slang
@@ -1 +1 @@
-Subproject commit 908574c579487e33ef7230a8d037e3ad25c778e8
+Subproject commit 23d97f8c81bd0930570eaa26e8585cbaeb8e389c
diff --git a/src/constants.ts b/src/constants.ts
index e33dbcc44..8847cb6a8 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -38,7 +38,6 @@ export const sourceLanguages: Language[] = [
{ chapter: Chapter.SOURCE_3, variant: Variant.DEFAULT },
{ chapter: Chapter.SOURCE_3, variant: Variant.TYPED },
{ chapter: Chapter.SOURCE_3, variant: Variant.CONCURRENT },
- { chapter: Chapter.SOURCE_3, variant: Variant.NON_DET },
{ chapter: Chapter.SOURCE_4, variant: Variant.DEFAULT },
{ chapter: Chapter.SOURCE_4, variant: Variant.TYPED },
{ chapter: Chapter.SOURCE_4, variant: Variant.GPU },
diff --git a/src/createContext.ts b/src/createContext.ts
index 623c21db9..e9e392324 100644
--- a/src/createContext.ts
+++ b/src/createContext.ts
@@ -19,7 +19,6 @@ import { list_to_vector } from './stdlib/list'
import { listPrelude } from './stdlib/list.prelude'
import { localImportPrelude } from './stdlib/localImport.prelude'
import * as misc from './stdlib/misc'
-import { nonDetPrelude } from './stdlib/non-det.prelude'
import * as parser from './stdlib/parser'
import * as pylib from './stdlib/pylib'
import * as stream from './stdlib/stream'
@@ -851,10 +850,6 @@ function importPrelude(context: Context) {
prelude += streamPrelude
}
- if (context.variant === Variant.NON_DET) {
- prelude += nonDetPrelude
- }
-
if (context.chapter <= +Chapter.SCHEME_1 && context.chapter >= +Chapter.FULL_SCHEME) {
// Scheme preludes
// scheme 1 is the "highest" scheme chapter, so we can just check if it's less than or equal to scheme 1
diff --git a/src/cse-machine/interpreter.ts b/src/cse-machine/interpreter.ts
index 364fe8bbf..dfcc6ce19 100644
--- a/src/cse-machine/interpreter.ts
+++ b/src/cse-machine/interpreter.ts
@@ -102,7 +102,7 @@ export class Control extends Stack {
super()
this.numEnvDependentItems = 0
// Load program into control stack
- program ? this.push(program) : null
+ if (program) this.push(program)
}
public canAvoidEnvInstr(): boolean {
@@ -919,20 +919,17 @@ const cmdEvaluators: { [type: string]: CmdEvaluator } = {
control: Control,
stash: Stash
) {
- command.declaration
- ? defineVariable(
- context,
- command.symbol,
- stash.peek(),
- command.constant,
- command.srcNode as es.VariableDeclaration
- )
- : setVariable(
- context,
- command.symbol,
- stash.peek(),
- command.srcNode as es.AssignmentExpression
- )
+ if (command.declaration) {
+ defineVariable(
+ context,
+ command.symbol,
+ stash.peek(),
+ command.constant,
+ command.srcNode as es.VariableDeclaration
+ )
+ } else {
+ setVariable(context, command.symbol, stash.peek(), command.srcNode as es.AssignmentExpression)
+ }
},
[InstrType.UNARY_OP]: function (
diff --git a/src/editors/ace/docTooltip/index.ts b/src/editors/ace/docTooltip/index.ts
index fca24c46f..2373e165b 100644
--- a/src/editors/ace/docTooltip/index.ts
+++ b/src/editors/ace/docTooltip/index.ts
@@ -5,7 +5,6 @@ import * as source_2 from './source_2.json'
import * as source_2_typed from './source_2_typed.json'
import * as source_3 from './source_3.json'
import * as source_3_concurrent from './source_3_concurrent.json'
-import * as source_3_non_det from './source_3_non-det.json'
import * as source_3_typed from './source_3_typed.json'
import * as source_4 from './source_4.json'
import * as source_4_typed from './source_4_typed.json'
@@ -49,7 +48,6 @@ export const SourceDocumentation = {
'2_typed': resolveImportInconsistency(source_2_typed),
'3': resolveImportInconsistency(source_3),
'3_concurrent': resolveImportInconsistency(source_3_concurrent),
- '3_non-det': resolveImportInconsistency(source_3_non_det),
'3_typed': resolveImportInconsistency(source_3_typed),
'4': resolveImportInconsistency(source_4),
'4_typed': resolveImportInconsistency(source_4_typed),
diff --git a/src/editors/ace/modes/source.ts b/src/editors/ace/modes/source.ts
index 2b402101d..44a5b01cf 100644
--- a/src/editors/ace/modes/source.ts
+++ b/src/editors/ace/modes/source.ts
@@ -21,7 +21,7 @@ import { SourceDocumentation } from '../docTooltip'
export function HighlightRulesSelector(
id: number,
variant: Variant = Variant.DEFAULT,
- external: String = 'NONE',
+ external: string = 'NONE',
externalLibraries: (
| {
caption: string
diff --git a/src/errors/errors.ts b/src/errors/errors.ts
index 3ea1c41d7..b18dafac7 100644
--- a/src/errors/errors.ts
+++ b/src/errors/errors.ts
@@ -10,7 +10,7 @@ import { RuntimeSourceError } from './runtimeSourceError'
//Wrap build-in function error in SourceError
export class BuiltInFunctionError extends RuntimeSourceError {
- constructor(private explanation: String) {
+ constructor(private explanation: string) {
super(undefined)
this.explanation = explanation
}
diff --git a/src/infiniteLoops/detect.ts b/src/infiniteLoops/detect.ts
index af9b98416..680e0034d 100644
--- a/src/infiniteLoops/detect.ts
+++ b/src/infiniteLoops/detect.ts
@@ -7,6 +7,7 @@ import { getOriginalName } from './instrument'
import * as st from './state'
import { shallowConcretize } from './symbolic'
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const runAltErgo: any = require('@joeychenofficial/alt-ergo-modified')
const options = {
diff --git a/src/interpreter/interpreter-non-det.ts b/src/interpreter/interpreter-non-det.ts
deleted file mode 100644
index c4a47b7a6..000000000
--- a/src/interpreter/interpreter-non-det.ts
+++ /dev/null
@@ -1,698 +0,0 @@
-/* tslint:disable:max-classes-per-file */
-import * as es from 'estree'
-import { cloneDeep } from 'lodash'
-
-import { CUT, UNKNOWN_LOCATION } from '../constants'
-import Heap from '../cse-machine/heap'
-import { uniqueId } from '../cse-machine/utils'
-import * as errors from '../errors/errors'
-import { RuntimeSourceError } from '../errors/runtimeSourceError'
-import { Context, Environment, Node, Value } from '../types'
-import { conditionalExpression, literal, primitive } from '../utils/ast/astCreator'
-import { evaluateBinaryExpression, evaluateUnaryExpression } from '../utils/operators'
-import * as rttc from '../utils/rttc'
-import Closure from './closure'
-
-class BreakValue {}
-
-class ContinueValue {}
-
-class ReturnValue {
- constructor(public value: Value) {}
-}
-
-const createEnvironment = (
- context: Context,
- closure: Closure,
- args: Value[],
- callExpression?: es.CallExpression
-): Environment => {
- const environment: Environment = {
- name: closure.functionName, // TODO: Change this
- tail: closure.environment,
- head: {},
- heap: new Heap(),
- id: uniqueId(context)
- }
- if (callExpression) {
- environment.callExpression = {
- ...callExpression,
- arguments: args.map(primitive)
- }
- }
- closure.node.params.forEach((param, index) => {
- const ident = param as es.Identifier
- environment.head[ident.name] = args[index]
- })
- return environment
-}
-
-const createBlockEnvironment = (context: Context, name = 'blockEnvironment'): Environment => {
- return {
- name,
- tail: currentEnvironment(context),
- head: {},
- heap: new Heap(),
- thisContext: context,
- id: uniqueId(context)
- }
-}
-
-const handleRuntimeError = (context: Context, error: RuntimeSourceError): never => {
- context.errors.push(error)
- context.runtime.environments = context.runtime.environments.slice(
- -context.numberOfOuterEnvironments
- )
- throw error
-}
-
-const DECLARED_BUT_NOT_YET_ASSIGNED = Symbol('Used to implement declaration')
-
-function declareIdentifier(context: Context, name: string, node: Node) {
- const environment = currentEnvironment(context)
- if (environment.head.hasOwnProperty(name)) {
- const descriptors = Object.getOwnPropertyDescriptors(environment.head)
-
- return handleRuntimeError(
- context,
- new errors.VariableRedeclaration(node, name, descriptors[name].writable)
- )
- }
- environment.head[name] = DECLARED_BUT_NOT_YET_ASSIGNED
- return environment
-}
-
-function declareVariables(context: Context, node: es.VariableDeclaration) {
- for (const declaration of node.declarations) {
- declareIdentifier(context, (declaration.id as es.Identifier).name, node)
- }
-}
-
-function declareFunctionAndVariableIdentifiers(context: Context, node: es.BlockStatement) {
- for (const statement of node.body) {
- switch (statement.type) {
- case 'VariableDeclaration':
- declareVariables(context, statement)
- break
- case 'FunctionDeclaration':
- if (statement.id === null) {
- throw new Error(
- 'Encountered a FunctionDeclaration node without an identifier. This should have been caught when parsing.'
- )
- }
- declareIdentifier(context, statement.id.name, statement)
- break
- }
- }
-}
-
-function defineVariable(context: Context, name: string, value: Value, constant = false) {
- const environment = context.runtime.environments[0]
-
- if (environment.head[name] !== DECLARED_BUT_NOT_YET_ASSIGNED) {
- return handleRuntimeError(
- context,
- new errors.VariableRedeclaration(context.runtime.nodes[0]!, name, !constant)
- )
- }
-
- Object.defineProperty(environment.head, name, {
- value,
- writable: !constant,
- enumerable: true
- })
-
- return environment
-}
-
-function undefineVariable(context: Context, name: string) {
- const environment = context.runtime.environments[0]
-
- Object.defineProperty(environment.head, name, {
- value: DECLARED_BUT_NOT_YET_ASSIGNED,
- writable: true,
- enumerable: true
- })
-}
-
-const currentEnvironment = (context: Context) => context.runtime.environments[0]
-const popEnvironment = (context: Context) => context.runtime.environments.shift()
-const pushEnvironment = (context: Context, environment: Environment) =>
- context.runtime.environments.unshift(environment)
-
-const getVariable = (context: Context, name: string, ensureVariableAssigned: boolean) => {
- let environment: Environment | null = context.runtime.environments[0]
- while (environment) {
- if (environment.head.hasOwnProperty(name)) {
- if (environment.head[name] === DECLARED_BUT_NOT_YET_ASSIGNED) {
- if (ensureVariableAssigned) {
- return handleRuntimeError(
- context,
- new errors.UnassignedVariable(name, context.runtime.nodes[0])
- )
- } else {
- return DECLARED_BUT_NOT_YET_ASSIGNED
- }
- } else {
- return environment.head[name]
- }
- } else {
- environment = environment.tail
- }
- }
- return handleRuntimeError(context, new errors.UndefinedVariable(name, context.runtime.nodes[0]))
-}
-
-const setVariable = (context: Context, name: string, value: any) => {
- let environment: Environment | null = context.runtime.environments[0]
- while (environment) {
- if (environment.head.hasOwnProperty(name)) {
- if (environment.head[name] === DECLARED_BUT_NOT_YET_ASSIGNED) {
- break
- }
- const descriptors = Object.getOwnPropertyDescriptors(environment.head)
- if (descriptors[name].writable) {
- environment.head[name] = value
- return undefined
- }
- return handleRuntimeError(
- context,
- new errors.ConstAssignment(context.runtime.nodes[0]!, name)
- )
- } else {
- environment = environment.tail
- }
- }
- return handleRuntimeError(context, new errors.UndefinedVariable(name, context.runtime.nodes[0]))
-}
-
-const checkNumberOfArguments = (
- context: Context,
- callee: Closure,
- args: Value[],
- exp: es.CallExpression
-) => {
- if (callee.node.params.length !== args.length) {
- return handleRuntimeError(
- context,
- new errors.InvalidNumberOfArguments(exp, callee.node.params.length, args.length)
- )
- }
- return undefined
-}
-
-/**
- * Returns a random integer for a given interval (inclusive).
- */
-function randomInt(min: number, max: number): number {
- return Math.floor(Math.random() * (max - min + 1) + min)
-}
-
-function* getAmbRArgs(context: Context, call: es.CallExpression) {
- const args: Node[] = cloneDeep(call.arguments)
- while (args.length > 0) {
- const r = randomInt(0, args.length - 1)
- const arg: Node = args.splice(r, 1)[0]
-
- yield* evaluate(arg, context)
- }
-}
-
-function* getArgs(context: Context, call: es.CallExpression) {
- const args = cloneDeep(call.arguments)
- return yield* cartesianProduct(context, args as es.Expression[], [])
-}
-
-/* Given a list of non deterministic nodes, this generator returns every
- * combination of values of these nodes */
-function* cartesianProduct(
- context: Context,
- nodes: es.Expression[],
- nodeValues: Value[]
-): IterableIterator {
- if (nodes.length === 0) {
- yield nodeValues
- } else {
- const currentNode = nodes.shift()! // we need the postfix ! to tell compiler that nodes array is nonempty
- const nodeValueGenerator = evaluate(currentNode, context)
- for (const nodeValue of nodeValueGenerator) {
- nodeValues.push(nodeValue)
- yield* cartesianProduct(context, nodes, nodeValues)
- nodeValues.pop()
- }
- nodes.unshift(currentNode)
- }
-}
-
-function* getAmbArgs(context: Context, call: es.CallExpression) {
- for (const arg of call.arguments) {
- yield* evaluate(arg, context)
- }
-}
-
-function transformLogicalExpression(node: es.LogicalExpression): es.ConditionalExpression {
- if (node.operator === '&&') {
- return conditionalExpression(node.left, node.right, literal(false), node.loc)
- } else {
- return conditionalExpression(node.left, literal(true), node.right, node.loc)
- }
-}
-
-function* reduceIf(
- node: es.IfStatement | es.ConditionalExpression,
- context: Context
-): IterableIterator {
- const testGenerator = evaluate(node.test, context)
- for (const test of testGenerator) {
- const error = rttc.checkIfStatement(node, test, context.chapter)
- if (error) {
- return handleRuntimeError(context, error)
- }
- yield test ? node.consequent : node.alternate!
- }
-}
-
-export type Evaluator = (node: T, context: Context) => IterableIterator
-
-function* evaluateBlockSatement(context: Context, node: es.BlockStatement) {
- declareFunctionAndVariableIdentifiers(context, node)
- yield* evaluateSequence(context, node.body)
-}
-
-function* evaluateSequence(context: Context, sequence: es.Statement[]): IterableIterator {
- if (sequence.length === 0) {
- return yield undefined
- }
- const firstStatement = sequence[0]
- const sequenceValGenerator = evaluate(firstStatement, context)
- if (sequence.length === 1) {
- yield* sequenceValGenerator
- } else {
- sequence.shift()
- let shouldUnshift = true
- for (const sequenceValue of sequenceValGenerator) {
- // prevent unshifting of cut operator
- shouldUnshift = sequenceValue !== CUT
-
- if (
- sequenceValue instanceof ReturnValue ||
- sequenceValue instanceof BreakValue ||
- sequenceValue instanceof ContinueValue
- ) {
- yield sequenceValue
- continue
- }
-
- const res = yield* evaluateSequence(context, sequence)
- if (res === CUT) {
- // prevent unshifting of statements before cut
- shouldUnshift = false
- break
- }
- }
-
- if (shouldUnshift) sequence.unshift(firstStatement)
- else return CUT
- }
-}
-
-function* evaluateConditional(node: es.IfStatement | es.ConditionalExpression, context: Context) {
- const branchGenerator = reduceIf(node, context)
- for (const branch of branchGenerator) {
- yield* evaluate(branch, context)
- }
-}
-
-/**
- * WARNING: Do not use object literal shorthands, e.g.
- * {
- * *Literal(node: es.Literal, ...) {...},
- * *ThisExpression(node: es.ThisExpression, ..._ {...},
- * ...
- * }
- * They do not minify well, raising uncaught syntax errors in production.
- * See: https://github.com/webpack/webpack/issues/7566
- */
-// tslint:disable:object-literal-shorthand
-// prettier-ignore
-export const evaluators: { [nodeType: string]: Evaluator } = {
- /** Simple Values */
- Literal: function*(node: es.Literal, _context: Context) {
- yield node.value
- },
-
- ArrowFunctionExpression: function*(node: es.ArrowFunctionExpression, context: Context) {
- yield Closure.makeFromArrowFunction(node, currentEnvironment(context), context)
- },
-
- ArrayExpression: function*(node: es.ArrayExpression, context: Context) {
- const arrayGenerator = cartesianProduct(context, node.elements as es.Expression[], [])
- for (const array of arrayGenerator) {
- yield array.slice() // yield a new array to avoid modifying previous ones
- }
- },
-
- Identifier: function*(node: es.Identifier, context: Context) {
- return yield getVariable(context, node.name, true)
- },
-
- CallExpression: function*(node: es.CallExpression, context: Context) {
- const callee = node.callee;
- if (rttc.isIdentifier(callee)) {
- switch (callee.name) {
- case 'amb':
- return yield* getAmbArgs(context, node)
- case 'ambR':
- return yield* getAmbRArgs(context, node)
- case 'cut':
- return yield CUT
- }
- }
-
- const calleeGenerator = evaluate(node.callee, context)
- for (const calleeValue of calleeGenerator) {
- const argsGenerator = getArgs(context, node)
- for (const args of argsGenerator) {
- yield* apply(context, calleeValue, args, node, undefined)
- }
- }
- },
-
- UnaryExpression: function*(node: es.UnaryExpression, context: Context) {
- const argGenerator = evaluate(node.argument, context)
- for (const argValue of argGenerator) {
- const error = rttc.checkUnaryExpression(node, node.operator, argValue, context.chapter)
- if (error) {
- return handleRuntimeError(context, error)
- }
- yield evaluateUnaryExpression(node.operator, argValue)
- }
- return
- },
-
- BinaryExpression: function*(node: es.BinaryExpression, context: Context) {
- const pairGenerator = cartesianProduct(context, [node.left, node.right], [])
- for (const pair of pairGenerator) {
- const leftValue = pair[0]
- const rightValue = pair[1]
- const error = rttc.checkBinaryExpression(node, node.operator, context.chapter, leftValue, rightValue)
- if (error) {
- return handleRuntimeError(context, error)
- }
- yield evaluateBinaryExpression(node.operator, leftValue, rightValue)
- }
- return
- },
-
- ConditionalExpression: function*(node: es.ConditionalExpression, context: Context) {
- yield* evaluateConditional(node, context)
- },
-
- LogicalExpression: function*(node: es.LogicalExpression, context: Context) {
- const conditional: es.ConditionalExpression = transformLogicalExpression(node)
- yield* evaluateConditional(conditional, context)
- },
-
- VariableDeclaration: function*(node: es.VariableDeclaration, context: Context) {
- const declaration = node.declarations[0]
- const constant = node.kind === 'const'
- const id = declaration.id as es.Identifier
- const valueGenerator = evaluate(declaration.init!, context)
- for (const value of valueGenerator) {
- defineVariable(context, id.name, value, constant)
- yield value
- undefineVariable(context, id.name)
- }
- return undefined
- },
-
- MemberExpression: function*(node: es.MemberExpression, context: Context) {
- // es.PrivateIdentifier is a ES2022 feature
- const pairGenerator = cartesianProduct(context, [node.property as es.Expression, node.object as es.Expression], [])
- for (const pair of pairGenerator) {
- const prop = pair[0]
- const obj = pair[1]
-
- const error = rttc.checkMemberAccess(node, obj, prop)
- if (error) {
- return yield handleRuntimeError(context, error)
- }
-
- yield obj[prop]
- }
-
- return
- },
-
- AssignmentExpression: function*(node: es.AssignmentExpression, context: Context) {
- if (node.left.type === 'MemberExpression') {
- // es.PrivateIdentifier is a ES2022 feature
- const tripleGenerator = cartesianProduct(context, [node.right, node.left.property as es.Expression, node.left.object as es.Expression], [])
- for (const triple of tripleGenerator) {
- const val = triple[0]
- const prop = triple[1]
- const obj = triple[2]
-
- const error = rttc.checkMemberAccess(node, obj, prop)
- if (error) {
- return yield handleRuntimeError(context, error)
- }
- const originalElementValue = obj[prop]
- obj[prop] = val
- yield val
- obj[prop] = originalElementValue
- }
-
- return
- }
-
- const id = node.left as es.Identifier
- const originalValue = getVariable(context, id.name, false)
- const valueGenerator = evaluate(node.right, context)
- for (const value of valueGenerator) {
- setVariable(context, id.name, value)
- yield value
- setVariable(context, id.name, originalValue)
- }
- return
- },
-
- FunctionDeclaration: function*(node: es.FunctionDeclaration, context: Context) {
- const id = node.id
- if (id === null) {
- throw new Error("Encountered a FunctionDeclaration node without an identifier. This should have been caught when parsing.")
- }
- const closure = new Closure(node, currentEnvironment(context), context)
- defineVariable(context, id.name, closure, true)
- yield undefined
- undefineVariable(context, id.name)
- },
-
- IfStatement: function*(node: es.IfStatement, context: Context) {
- yield* evaluateConditional(node, context)
- },
-
- ExpressionStatement: function*(node: es.ExpressionStatement, context: Context) {
- return yield* evaluate(node.expression, context)
- },
-
- ContinueStatement: function*(_node: es.ContinueStatement, _context: Context) {
- yield new ContinueValue()
- },
-
- BreakStatement: function*(_node: es.BreakStatement, _context: Context) {
- yield new BreakValue()
- },
-
- WhileStatement: function*(node: es.WhileStatement, context: Context) {
- let value: Value // tslint:disable-line
- function* loop(): Value {
- const testGenerator = evaluate(node.test, context)
- for (const test of testGenerator) {
- const error = rttc.checkIfStatement(node.test, test, context.chapter)
- if (error) return handleRuntimeError(context, error)
-
- if (test &&
- !(value instanceof ReturnValue) &&
- !(value instanceof BreakValue)
- ) {
- const iterationValueGenerator = evaluate(cloneDeep(node.body), context)
- for (const iterationValue of iterationValueGenerator) {
- value = iterationValue
- yield* loop();
- }
- } else {
- if (value instanceof BreakValue || value instanceof ContinueValue) {
- yield undefined
- } else {
- yield value
- }
- }
- }
- }
-
- yield* loop();
- },
-
- ForStatement: function*(node: es.ForStatement, context: Context) {
- let value: Value
- function* loop(): Value {
- const testGenerator = evaluate(node.test!, context)
- for (const test of testGenerator) {
- const error = rttc.checkIfStatement(node.test!, test, context.chapter)
- if (error) return handleRuntimeError(context, error)
-
- if (test &&
- !(value instanceof ReturnValue) &&
- !(value instanceof BreakValue)
- ) {
- const iterationEnvironment = createBlockEnvironment(context, 'forBlockEnvironment')
- pushEnvironment(context, iterationEnvironment)
- for (const name in loopEnvironment.head) {
- if (loopEnvironment.head.hasOwnProperty(name)) {
- declareIdentifier(context, name, node)
- defineVariable(context, name, loopEnvironment.head[name], true)
- }
- }
-
- const iterationValueGenerator = evaluate(cloneDeep(node.body), context)
- for (const iterationValue of iterationValueGenerator) {
- value = iterationValue
- popEnvironment(context)
- const updateNode = evaluate(node.update!, context)
- for (const _update of updateNode) {
- yield* loop();
- }
-
- pushEnvironment(context, iterationEnvironment)
- }
- popEnvironment(context)
- } else {
- if (value instanceof BreakValue || value instanceof ContinueValue) {
- yield undefined
- } else {
- yield value
- }
- }
- }
- }
-
- // Create a new block scope for the loop variables
- const loopEnvironment = createBlockEnvironment(context, 'forLoopEnvironment')
- pushEnvironment(context, loopEnvironment)
-
- const initNode = node.init!
- if (initNode.type === 'VariableDeclaration') {
- declareVariables(context, initNode)
- }
-
- const initNodeGenerator = evaluate(node.init!, context)
- for (const _init of initNodeGenerator) {
- const loopGenerator = loop()
- for (const loopValue of loopGenerator) {
- popEnvironment(context)
- yield loopValue
- pushEnvironment(context, loopEnvironment)
- }
- }
-
- popEnvironment(context)
- },
-
- ReturnStatement: function*(node: es.ReturnStatement, context: Context) {
- const returnExpression = node.argument!
- const returnValueGenerator = evaluate(returnExpression, context)
- for (const returnValue of returnValueGenerator) {
- yield new ReturnValue(returnValue)
- }
- },
-
- BlockStatement: function*(node: es.BlockStatement, context: Context) {
- // Create a new environment (block scoping)
- const environment = createBlockEnvironment(context, 'blockEnvironment')
- pushEnvironment(context, environment)
-
- const resultGenerator = evaluateBlockSatement(context, node)
- for (const result of resultGenerator) {
- popEnvironment(context)
- yield result
- pushEnvironment(context, environment)
- }
- popEnvironment(context)
- },
-
- Program: function*(node: es.BlockStatement, context: Context) {
- context.numberOfOuterEnvironments += 1
- const environment = createBlockEnvironment(context, 'programEnvironment')
- pushEnvironment(context, environment)
- return yield* evaluateBlockSatement(context, node)
- }
-}
-// tslint:enable:object-literal-shorthand
-
-export function* evaluate(node: Node, context: Context) {
- const result = yield* evaluators[node.type](node, context)
- return result
-}
-
-export function* apply(
- context: Context,
- fun: Closure | Value,
- args: Value[],
- node: es.CallExpression,
- thisContext?: Value
-) {
- if (fun instanceof Closure) {
- checkNumberOfArguments(context, fun, args, node!)
- const environment = createEnvironment(context, fun, args, node)
- environment.thisContext = thisContext
- pushEnvironment(context, environment)
- const applicationValueGenerator = evaluateBlockSatement(
- context,
- cloneDeep(fun.node.body) as es.BlockStatement
- )
-
- // This function takes a value that may be a ReturnValue.
- // If so, it returns the value wrapped in the ReturnValue.
- // If not, it returns the default value.
- function unwrapReturnValue(result: any, defaultValue: any) {
- if (result instanceof ReturnValue) {
- return result.value
- } else {
- return defaultValue
- }
- }
-
- for (const applicationValue of applicationValueGenerator) {
- popEnvironment(context)
- yield unwrapReturnValue(applicationValue, undefined)
- pushEnvironment(context, environment)
- }
-
- popEnvironment(context)
- } else if (typeof fun === 'function') {
- try {
- yield fun.apply(thisContext, args)
- } catch (e) {
- // Recover from exception
- context.runtime.environments = context.runtime.environments.slice(
- -context.numberOfOuterEnvironments
- )
-
- const loc = node.loc ?? UNKNOWN_LOCATION
- if (!(e instanceof RuntimeSourceError || e instanceof errors.ExceptionError)) {
- // The error could've arisen when the builtin called a source function which errored.
- // If the cause was a source error, we don't want to include the error.
- // However if the error came from the builtin itself, we need to handle it.
- return handleRuntimeError(context, new errors.ExceptionError(e, loc))
- }
- throw e
- }
- } else {
- return handleRuntimeError(context, new errors.CallingNonFunctionValue(fun, node))
- }
-
- return
-}
-
-export { evaluate as nonDetEvaluate }
diff --git a/src/modules/loader/loaders.ts b/src/modules/loader/loaders.ts
index e9c6d508b..86085b807 100644
--- a/src/modules/loader/loaders.ts
+++ b/src/modules/loader/loaders.ts
@@ -27,9 +27,6 @@ function wrapImporter(func: (p: string) => Promise) {
For the browser, we use the function constructor to hide the import calls from
webpack so that webpack doesn't try to compile them away.
-
- Browsers automatically cache import() calls, so we add a query parameter with the
- current time to always invalidate the cache and handle the memoization ourselves
*/
return async (p: string): Promise => {
try {
@@ -123,7 +120,8 @@ export const memoizedGetModuleDocsAsync = getMemoizedDocsImporter()
const bundleAndTabImporter = wrapImporter<{ default: ModuleBundle }>(
typeof window !== 'undefined' && process.env.NODE_ENV !== 'test'
? (new Function('path', 'return import(`${path}?q=${Date.now()}`)') as any)
- : p => Promise.resolve(require(p))
+ : // eslint-disable-next-line @typescript-eslint/no-require-imports
+ p => Promise.resolve(require(p))
)
export async function loadModuleBundleAsync(
diff --git a/src/modules/preprocessor/__tests__/analyzer.ts b/src/modules/preprocessor/__tests__/analyzer.ts
index 40078d6cc..522102dd3 100644
--- a/src/modules/preprocessor/__tests__/analyzer.ts
+++ b/src/modules/preprocessor/__tests__/analyzer.ts
@@ -1,3 +1,4 @@
+import type { Program } from 'estree'
import createContext from '../../../createContext'
import {
DuplicateImportNameError,
@@ -11,7 +12,6 @@ import parseProgramsAndConstructImportGraph from '../linker'
import analyzeImportsAndExports from '../analyzer'
import { parse } from '../../../parser/parser'
import { mockContext } from '../../../mocks/context'
-import type { Program } from 'estree'
import loadSourceModules from '../../loader'
import type { SourceFiles as Files } from '../../moduleTypes'
import { objectKeys } from '../../../utils/misc'
diff --git a/src/parser/source/typed/typeParser.ts b/src/parser/source/typed/typeParser.ts
index da509f65f..ca6f9c570 100644
--- a/src/parser/source/typed/typeParser.ts
+++ b/src/parser/source/typed/typeParser.ts
@@ -223,7 +223,11 @@ const tsPlugin = (BaseParser: any) => {
this.awaitPos = 0
// Do not save awaitIdentPos to allow checking awaits nested in parameters
while (this.type !== tokTypes.parenR) {
- first ? (first = false) : this.expect(tokTypes.comma)
+ if (first) {
+ first = false
+ } else {
+ this.expect(tokTypes.comma)
+ }
if (allowTrailingComma && this.afterTrailingComma(tokTypes.parenR, true)) {
lastIsComma = true
break
@@ -325,7 +329,9 @@ const tsPlugin = (BaseParser: any) => {
}
parseTSTypeAnnotation(eatColon = true) {
- eatColon && this.expect(tokTypes.colon)
+ if (eatColon) {
+ this.expect(tokTypes.colon)
+ }
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc)
this._parseTSTypeAnnotation(node)
return this.finishNode(node, 'TSTypeAnnotation')
@@ -481,7 +487,11 @@ const tsPlugin = (BaseParser: any) => {
this.eat(tokTypes.bracketL)
let first = true
while (!this.eat(tokTypes.bracketR)) {
- first ? (first = false) : this.expect(tokTypes.comma)
+ if (first) {
+ first = false
+ } else {
+ this.expect(tokTypes.comma)
+ }
switch (this.type) {
case tokTypes.name:
const elem = this.parseTSTypeReference()
@@ -563,10 +573,13 @@ const tsPlugin = (BaseParser: any) => {
return false
}
case tokTypes.braceL:
- case tokTypes.bracketL:
- this.type === tokTypes.braceL
- ? this.parseObj(/* isPattern */ true)
- : this.parseBindingAtom()
+ case tokTypes.bracketL: {
+ if (this.type === tokTypes.braceL) {
+ this.parseObj(/* isPattern */ true)
+ } else {
+ this.parseBindingAtom()
+ }
+
switch (this.type) {
case tokTypes.colon:
case tokTypes.comma:
@@ -578,6 +591,7 @@ const tsPlugin = (BaseParser: any) => {
default:
return false
}
+ }
default:
return false
}
@@ -608,7 +622,7 @@ const tsPlugin = (BaseParser: any) => {
parseTSUnionType(first: any) {
const node = first ? this.startNodeAtNode(first) : this.startNode()
const types = []
- first && types.push(first)
+ if (first) types.push(first)
while (this.eat(tokTypes.bitwiseOR)) {
types.push(this._parseTSIntersectionTypeOrPrimaryType())
}
@@ -622,7 +636,7 @@ const tsPlugin = (BaseParser: any) => {
parseTSIntersectionType(first: any) {
const node = first ? this.startNodeAtNode(first) : this.startNode()
const types = []
- first && types.push(first)
+ if (first) types.push(first)
while (this.eat(tokTypes.bitwiseAND)) {
types.push(this._parsePrimaryType())
}
@@ -817,7 +831,11 @@ const tsPlugin = (BaseParser: any) => {
let first = true
this.next()
while (!this.eat(tokTypes.relational)) {
- first ? (first = false) : this.expect(tokTypes.comma)
+ if (first) {
+ first = false
+ } else {
+ this.expect(tokTypes.comma)
+ }
if (this._isEndOfTypeParameters()) {
break
}
@@ -834,7 +852,11 @@ const tsPlugin = (BaseParser: any) => {
this.next() // <
let first = true
while ((this.value && !this._isEndOfTypeParameters()) || this.type === tokTypes.comma) {
- first ? (first = false) : this.expect(tokTypes.comma)
+ if (first) {
+ first = false
+ } else {
+ this.expect(tokTypes.comma)
+ }
params.push(this._parseTSType())
}
@@ -934,7 +956,7 @@ const tsPlugin = (BaseParser: any) => {
if (this.type === tokTypes.colon) {
node.typeAnnotation = this.parseTSTypeAnnotation(true)
}
- this.eat(tokTypes.comma) || this.eat(tokTypes.semi)
+ if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
return this.finishNode(node, 'TSMethodSignature')
}
@@ -956,7 +978,7 @@ const tsPlugin = (BaseParser: any) => {
if (this.type === tokTypes.colon) {
node.typeAnnotation = this.parseTSTypeAnnotation(true)
}
- this.eat(tokTypes.comma) || this.eat(tokTypes.semi)
+ if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
return this.finishNode(node, 'TSPropertySignature')
}
@@ -972,7 +994,7 @@ const tsPlugin = (BaseParser: any) => {
node.index = index
this.expect(tokTypes.bracketR)
node.typeAnnotation = this.parseTSTypeAnnotation(true)
- this.eat(tokTypes.comma) || this.eat(tokTypes.semi)
+ if (!this.eat(tokTypes.comma)) this.eat(tokTypes.semi)
return this.finishNode(node, 'TSIndexSignature')
}
@@ -1041,6 +1063,7 @@ const tsPlugin = (BaseParser: any) => {
}
// acorn-class-fields plugin is needed, else parsing of some function types will not work
+// eslint-disable-next-line @typescript-eslint/no-require-imports
const TypeParser = Parser.extend(tsPlugin as any, require('acorn-class-fields'))
export default TypeParser
diff --git a/src/repl/__tests__/repl.ts b/src/repl/__tests__/repl.ts
index bf2b4b35e..b3276464d 100644
--- a/src/repl/__tests__/repl.ts
+++ b/src/repl/__tests__/repl.ts
@@ -1,5 +1,5 @@
-import type { SourceFiles } from '../../modules/moduleTypes'
import * as repl from 'repl'
+import type { SourceFiles } from '../../modules/moduleTypes'
import { Chapter } from '../../types'
import { asMockedFunc } from '../../utils/testing'
import { getReplCommand } from '../repl'
@@ -20,7 +20,8 @@ jest.mock('fs/promises', () => ({
jest.mock('path', () => {
const actualPath = jest.requireActual('path')
- const newResolve = (...args: string[]) => actualPath.resolve('/', ...args)
+ const { resolve } = jest.requireActual('path/posix')
+ const newResolve = (...args: string[]) => resolve('/', ...args)
return {
...actualPath,
resolve: newResolve
diff --git a/src/repl/index.ts b/src/repl/index.ts
index 51dfe4393..72065bc95 100644
--- a/src/repl/index.ts
+++ b/src/repl/index.ts
@@ -3,11 +3,9 @@
import { Command } from '@commander-js/extra-typings'
import { getReplCommand } from './repl'
-import { nonDetCommand } from './repl-non-det'
import { transpilerCommand } from './transpiler'
new Command()
.addCommand(transpilerCommand)
.addCommand(getReplCommand(), { isDefault: true })
- .addCommand(nonDetCommand)
.parseAsync()
diff --git a/src/repl/repl-non-det.ts b/src/repl/repl-non-det.ts
deleted file mode 100644
index 0f5d09a73..000000000
--- a/src/repl/repl-non-det.ts
+++ /dev/null
@@ -1,129 +0,0 @@
-import type fslib from 'fs/promises'
-import * as repl from 'repl' // 'repl' here refers to the module named 'repl' in index.d.ts
-import { inspect } from 'util'
-import { Command } from '@commander-js/extra-typings'
-
-import { createContext, type IOptions, parseError, type Result, resume, runInContext } from '..'
-import { CUT, TRY_AGAIN } from '../constants'
-import Closure from '../interpreter/closure'
-import { Chapter, Context, SuspendedNonDet, Variant } from '../types'
-
-const NO_MORE_VALUES_MESSAGE: string = 'There are no more values of: '
-let previousInput: string | undefined // stores the input which is then shown when there are no more values for the program
-let previousResult: Result // stores the result obtained when execution is suspended
-
-function _handleResult(
- result: Result,
- context: Context,
- callback: (err: Error | null, result: any) => void
-) {
- if (result.status === 'finished' || result.status === 'suspended-non-det') {
- previousResult = result
-
- if (result.value === CUT) result.value = undefined
- callback(null, result.value)
- } else {
- const error = new Error(parseError(context.errors))
- // we do not display the stack trace, because the stack trace points to code within this REPL
- // program, rather than the erroneous line in the user's program. Such a trace is too low level
- // to be helpful.
- error.stack = undefined
- callback(error, undefined)
- return
- }
-}
-
-function _try_again_message(): string | undefined {
- if (previousInput) {
- const message: string = NO_MORE_VALUES_MESSAGE + previousInput
- previousInput = undefined
-
- return message
- } else {
- return undefined
- }
-}
-
-function _resume(
- toResume: SuspendedNonDet,
- context: Context,
- callback: (err: Error | null, result: any) => void
-) {
- Promise.resolve(resume(toResume)).then((result: Result) => {
- if (result.status === 'finished') result.value = _try_again_message()
- _handleResult(result, context, callback)
- })
-}
-
-function _try_again(context: Context, callback: (err: Error | null, result: any) => void) {
- if (previousResult && previousResult.status === 'suspended-non-det') {
- _resume(previousResult, context, callback)
- } else {
- callback(null, _try_again_message())
- }
-}
-
-function _run(
- cmd: string,
- context: Context,
- options: Partial,
- callback: (err: Error | null, result: any) => void
-) {
- if (cmd.trim() === TRY_AGAIN) {
- _try_again(context, callback)
- } else {
- previousInput = cmd.trim()
- runInContext(cmd, context, options).then(result => {
- _handleResult(result, context, callback)
- })
- }
-}
-
-function _startRepl(chapter: Chapter = Chapter.SOURCE_1, useSubst: boolean, prelude = '') {
- // use defaults for everything
- const context = createContext(chapter, Variant.NON_DET)
- const options: Partial = {
- executionMethod: 'interpreter',
- useSubst
- }
- runInContext(prelude, context, options).then(preludeResult => {
- if (preludeResult.status === 'finished' || preludeResult.status === 'suspended-non-det') {
- console.dir(preludeResult.value, { depth: null })
-
- repl.start(
- // the object being passed as argument fits the interface ReplOptions in the repl module.
- {
- eval: (cmd, unusedContext, unusedFilename, callback) => {
- _run(cmd, context, options, callback)
- },
- // set depth to a large number so that `parse()` output will not be folded,
- // setting to null also solves the problem, however a reference loop might crash
- writer: output => {
- return output instanceof Closure || typeof output === 'function'
- ? output.toString()
- : inspect(output, {
- depth: 1000,
- colors: true
- })
- }
- }
- )
- } else {
- throw new Error(parseError(context.errors))
- }
- })
-}
-
-export const nonDetCommand = new Command('non-det')
- .option('--useSubst')
- .argument('')
- .action(async (fileName, { useSubst }) => {
- if (fileName !== undefined) {
- const fs: typeof fslib = require('fs/promises')
- const data = await fs.readFile(fileName, 'utf-8')
-
- _startRepl(Chapter.SOURCE_3, false, data)
- } else {
- _startRepl(Chapter.SOURCE_3, !!useSubst)
- }
- })
diff --git a/src/repl/utils.ts b/src/repl/utils.ts
index bd4ddeeb7..aed3ab3e3 100644
--- a/src/repl/utils.ts
+++ b/src/repl/utils.ts
@@ -65,7 +65,7 @@ export function validChapterVariant(language: Language) {
}
export function handleResult(result: Result, context: Context, verboseErrors: boolean) {
- if (result.status === 'finished' || result.status === 'suspended-non-det') {
+ if (result.status === 'finished') {
if (result.representation !== undefined) {
return result.representation
}
diff --git a/src/runner/__tests__/files.ts b/src/runner/__tests__/files.ts
index a7ec831e6..4a355cd6a 100644
--- a/src/runner/__tests__/files.ts
+++ b/src/runner/__tests__/files.ts
@@ -77,7 +77,7 @@ describe('runFilesInContext', () => {
describe('compileFiles', () => {
let context = mockContext(Chapter.SOURCE_4)
- beforeEach(async () => {
+ beforeEach(() => {
context = mockContext(Chapter.SOURCE_4)
})
diff --git a/src/runner/sourceRunner.ts b/src/runner/sourceRunner.ts
index 4ac64147d..af9fea5a2 100644
--- a/src/runner/sourceRunner.ts
+++ b/src/runner/sourceRunner.ts
@@ -12,13 +12,12 @@ import { transpileToGPU } from '../gpu/gpu'
import { isPotentialInfiniteLoop } from '../infiniteLoops/errors'
import { testForInfiniteLoop } from '../infiniteLoops/runtime'
import { evaluateProgram as evaluate } from '../interpreter/interpreter'
-import { nonDetEvaluate } from '../interpreter/interpreter-non-det'
import { transpileToLazy } from '../lazy/lazy'
import preprocessFileImports from '../modules/preprocessor'
import { defaultAnalysisOptions } from '../modules/preprocessor/analyzer'
import { defaultLinkerOptions } from '../modules/preprocessor/linker'
import { parse } from '../parser/parser'
-import { AsyncScheduler, NonDetScheduler, PreemptiveScheduler } from '../schedulers'
+import { AsyncScheduler, PreemptiveScheduler } from '../schedulers'
import {
callee,
getEvaluationSteps,
@@ -117,10 +116,7 @@ function runSubstitution(
function runInterpreter(program: es.Program, context: Context, options: IOptions): Promise {
let it = evaluate(program, context)
let scheduler: Scheduler
- if (context.variant === Variant.NON_DET) {
- it = nonDetEvaluate(program, context)
- scheduler = new NonDetScheduler()
- } else if (options.scheduler === 'async') {
+ if (options.scheduler === 'async') {
scheduler = new AsyncScheduler()
} else {
scheduler = new PreemptiveScheduler(options.steps)
diff --git a/src/schedulers.ts b/src/schedulers.ts
index 00a7d7c52..94a521f7c 100644
--- a/src/schedulers.ts
+++ b/src/schedulers.ts
@@ -35,32 +35,6 @@ export class AsyncScheduler implements Scheduler {
}
}
-export class NonDetScheduler implements Scheduler {
- public run(it: IterableIterator, context: Context): Promise {
- return new Promise((resolve, _reject) => {
- try {
- const itValue = it.next()
- if (itValue.done) {
- resolve({ status: 'finished', context, value: itValue.value })
- } else {
- resolve({
- status: 'suspended-non-det',
- it,
- scheduler: this,
- context,
- value: itValue.value
- } as Result)
- }
- } catch (e) {
- checkForStackOverflow(e, context)
- resolve({ status: 'error' })
- } finally {
- context.runtime.isRunning = false
- }
- })
- }
-}
-
export class PreemptiveScheduler implements Scheduler {
constructor(public steps: number) {}
diff --git a/src/stdlib/non-det.prelude.ts b/src/stdlib/non-det.prelude.ts
deleted file mode 100644
index 06b2c1e06..000000000
--- a/src/stdlib/non-det.prelude.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-export const nonDetPrelude = `
- function require(predicate) {
- return predicate ? "Satisfied require" : amb();
- }
-
- function an_element_of(items) {
- require(!is_null(items));
- return amb(head(items), an_element_of(tail(items)));
- }
-
- function an_integer_between(low, high) {
- return low > high ? amb() : amb(low, an_integer_between(low + 1, high));
- }
-
- /* Material Conditional */
- /* if P, then Q */
- /* P --> Q */
- function implication(P, Q) {
- return !P || Q;
- }
-
- /* Material Biconditional */
- /* (if P, then Q) AND (if Q, then P) */
- /* P <--> Q */
- function bi_implication(P, Q) {
- return implication(P, Q) && implication(Q, P);
- }
-`
diff --git a/src/stepper/__tests__/stepper.ts b/src/stepper/__tests__/stepper.ts
index e0d654131..0e6f6a3dd 100644
--- a/src/stepper/__tests__/stepper.ts
+++ b/src/stepper/__tests__/stepper.ts
@@ -50,7 +50,7 @@ describe('Test codify works on non-circular abstract syntax graphs', () => {
})
describe('Test codify works on circular abstract syntax graphs', () => {
- test('functions', async () => {
+ test('functions', () => {
const code = `
x => x();
`
diff --git a/src/types.ts b/src/types.ts
index 0fce4275a..61e3ddaeb 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -95,7 +95,6 @@ export enum Variant {
NATIVE = 'native',
WASM = 'wasm',
LAZY = 'lazy',
- NON_DET = 'non-det',
CONCURRENT = 'concurrent',
GPU = 'gpu',
EXPLICIT_CONTROL = 'explicit-control'
@@ -290,17 +289,12 @@ export interface Suspended {
context: Context
}
-export type SuspendedNonDet = Omit & { status: 'suspended-non-det' } & {
- value: Value
- representation?: Representation // never used, only kept for consistency with Finished
-}
-
export interface SuspendedCseEval {
status: 'suspended-cse-eval'
context: Context
}
-export type Result = Suspended | SuspendedNonDet | Finished | Error | SuspendedCseEval
+export type Result = Suspended | Finished | Error | SuspendedCseEval
export interface Scheduler {
run(it: IterableIterator, context: Context): Promise
diff --git a/src/validator/validator.ts b/src/validator/validator.ts
index 14fd14962..88b88e587 100644
--- a/src/validator/validator.ts
+++ b/src/validator/validator.ts
@@ -170,7 +170,7 @@ export function checkForUndefinedVariables(
) {
const preludes = context.prelude
? getFunctionDeclarationNamesInProgram(parse(context.prelude, context)!)
- : new Set()
+ : new Set()
const env = context.runtime.environments[0].head || {}
diff --git a/tsconfig.prod.json b/tsconfig.prod.json
index 0cc257b56..35361500d 100644
--- a/tsconfig.prod.json
+++ b/tsconfig.prod.json
@@ -14,5 +14,6 @@
"sicp_publish",
"src/**/__tests__/**",
"src/**/__mocks__/**",
+ "src/testing"
]
}
diff --git a/yarn.lock b/yarn.lock
index c85ca2f2f..f92a969f5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1054,7 +1054,12 @@
dependencies:
eslint-visitor-keys "^3.3.0"
-"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1":
+"@eslint-community/regexpp@^4.10.0":
+ version "4.11.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f"
+ integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==
+
+"@eslint-community/regexpp@^4.6.1":
version "4.10.0"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63"
integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==
@@ -1507,11 +1512,6 @@
"@types/tough-cookie" "*"
parse5 "^7.0.0"
-"@types/json-schema@^7.0.12":
- version "7.0.15"
- resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
- integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
-
"@types/json5@^0.0.29":
version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
@@ -1552,11 +1552,6 @@
resolved "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz"
integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==
-"@types/semver@^7.5.0":
- version "7.5.8"
- resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
- integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==
-
"@types/stack-utils@^2.0.0":
version "2.0.3"
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8"
@@ -1579,91 +1574,86 @@
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@^7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.3.1.tgz#0d8f38a6c8a1802139e62184ee7a68ed024f30a1"
- integrity sha512-STEDMVQGww5lhCuNXVSQfbfuNII5E08QWkvAw5Qwf+bj2WT+JkG1uc+5/vXA3AOYMDHVOSpL+9rcbEUiHIm2dw==
+"@typescript-eslint/eslint-plugin@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.8.1.tgz#9364b756d4d78bcbdf6fd3e9345e6924c68ad371"
+ integrity sha512-xfvdgA8AP/vxHgtgU310+WBnLB4uJQ9XdyP17RebG26rLtDrQJV3ZYrcopX91GrHmMoH8bdSwMRh2a//TiJ1jQ==
dependencies:
- "@eslint-community/regexpp" "^4.5.1"
- "@typescript-eslint/scope-manager" "7.3.1"
- "@typescript-eslint/type-utils" "7.3.1"
- "@typescript-eslint/utils" "7.3.1"
- "@typescript-eslint/visitor-keys" "7.3.1"
- debug "^4.3.4"
+ "@eslint-community/regexpp" "^4.10.0"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/type-utils" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
graphemer "^1.4.0"
- ignore "^5.2.4"
+ ignore "^5.3.1"
natural-compare "^1.4.0"
- semver "^7.5.4"
- ts-api-utils "^1.0.1"
+ ts-api-utils "^1.3.0"
-"@typescript-eslint/parser@^7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.3.1.tgz#c4ba7dc2744318a5e4506596cbc3a0086255c526"
- integrity sha512-Rq49+pq7viTRCH48XAbTA+wdLRrB/3sRq4Lpk0oGDm0VmnjBrAOVXH/Laalmwsv2VpekiEfVFwJYVk6/e8uvQw==
+"@typescript-eslint/parser@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.8.1.tgz#5952ba2a83bd52024b872f3fdc8ed2d3636073b8"
+ integrity sha512-hQUVn2Lij2NAxVFEdvIGxT9gP1tq2yM83m+by3whWFsWC+1y8pxxxHUFE1UqDu2VsGi2i6RLcv4QvouM84U+ow==
dependencies:
- "@typescript-eslint/scope-manager" "7.3.1"
- "@typescript-eslint/types" "7.3.1"
- "@typescript-eslint/typescript-estree" "7.3.1"
- "@typescript-eslint/visitor-keys" "7.3.1"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/typescript-estree" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
debug "^4.3.4"
-"@typescript-eslint/scope-manager@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.3.1.tgz#73fd0cb4211a7be23e49e5b6efec8820caa6ec36"
- integrity sha512-fVS6fPxldsKY2nFvyT7IP78UO1/I2huG+AYu5AMjCT9wtl6JFiDnsv4uad4jQ0GTFzcUV5HShVeN96/17bTBag==
+"@typescript-eslint/scope-manager@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.8.1.tgz#b4bea1c0785aaebfe3c4ab059edaea1c4977e7ff"
+ integrity sha512-X4JdU+66Mazev/J0gfXlcC/dV6JI37h+93W9BRYXrSn0hrE64IoWgVkO9MSJgEzoWkxONgaQpICWg8vAN74wlA==
dependencies:
- "@typescript-eslint/types" "7.3.1"
- "@typescript-eslint/visitor-keys" "7.3.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
-"@typescript-eslint/type-utils@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.3.1.tgz#cbf90d3d7e788466aa8a5c0ab3f46103f098aa0d"
- integrity sha512-iFhaysxFsMDQlzJn+vr3OrxN8NmdQkHks4WaqD4QBnt5hsq234wcYdyQ9uquzJJIDAj5W4wQne3yEsYA6OmXGw==
+"@typescript-eslint/type-utils@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.8.1.tgz#31f59ec46e93a02b409fb4d406a368a59fad306e"
+ integrity sha512-qSVnpcbLP8CALORf0za+vjLYj1Wp8HSoiI8zYU5tHxRVj30702Z1Yw4cLwfNKhTPWp5+P+k1pjmD5Zd1nhxiZA==
dependencies:
- "@typescript-eslint/typescript-estree" "7.3.1"
- "@typescript-eslint/utils" "7.3.1"
+ "@typescript-eslint/typescript-estree" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
debug "^4.3.4"
- ts-api-utils "^1.0.1"
+ ts-api-utils "^1.3.0"
-"@typescript-eslint/types@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.3.1.tgz#ae104de8efa4227a462c0874d856602c5994413c"
- integrity sha512-2tUf3uWggBDl4S4183nivWQ2HqceOZh1U4hhu4p1tPiIJoRRXrab7Y+Y0p+dozYwZVvLPRI6r5wKe9kToF9FIw==
+"@typescript-eslint/types@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.8.1.tgz#ebe85e0fa4a8e32a24a56adadf060103bef13bd1"
+ integrity sha512-WCcTP4SDXzMd23N27u66zTKMuEevH4uzU8C9jf0RO4E04yVHgQgW+r+TeVTNnO1KIfrL8ebgVVYYMMO3+jC55Q==
-"@typescript-eslint/typescript-estree@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.3.1.tgz#598848195fad34c7aa73f548bd00a4d4e5f5e2bb"
- integrity sha512-tLpuqM46LVkduWP7JO7yVoWshpJuJzxDOPYIVWUUZbW+4dBpgGeUdl/fQkhuV0A8eGnphYw3pp8d2EnvPOfxmQ==
+"@typescript-eslint/typescript-estree@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.8.1.tgz#34649f4e28d32ee49152193bc7dedc0e78e5d1ec"
+ integrity sha512-A5d1R9p+X+1js4JogdNilDuuq+EHZdsH9MjTVxXOdVFfTJXunKJR/v+fNNyO4TnoOn5HqobzfRlc70NC6HTcdg==
dependencies:
- "@typescript-eslint/types" "7.3.1"
- "@typescript-eslint/visitor-keys" "7.3.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/visitor-keys" "8.8.1"
debug "^4.3.4"
- globby "^11.1.0"
+ fast-glob "^3.3.2"
is-glob "^4.0.3"
- minimatch "9.0.3"
- semver "^7.5.4"
- ts-api-utils "^1.0.1"
+ minimatch "^9.0.4"
+ semver "^7.6.0"
+ ts-api-utils "^1.3.0"
-"@typescript-eslint/utils@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.3.1.tgz#fc28fd508ccf89495012561b7c02a6fdad162460"
- integrity sha512-jIERm/6bYQ9HkynYlNZvXpzmXWZGhMbrOvq3jJzOSOlKXsVjrrolzWBjDW6/TvT5Q3WqaN4EkmcfdQwi9tDjBQ==
+"@typescript-eslint/utils@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.8.1.tgz#9e29480fbfa264c26946253daa72181f9f053c9d"
+ integrity sha512-/QkNJDbV0bdL7H7d0/y0qBbV2HTtf0TIyjSDTvvmQEzeVx8jEImEbLuOA4EsvE8gIgqMitns0ifb5uQhMj8d9w==
dependencies:
"@eslint-community/eslint-utils" "^4.4.0"
- "@types/json-schema" "^7.0.12"
- "@types/semver" "^7.5.0"
- "@typescript-eslint/scope-manager" "7.3.1"
- "@typescript-eslint/types" "7.3.1"
- "@typescript-eslint/typescript-estree" "7.3.1"
- semver "^7.5.4"
+ "@typescript-eslint/scope-manager" "8.8.1"
+ "@typescript-eslint/types" "8.8.1"
+ "@typescript-eslint/typescript-estree" "8.8.1"
-"@typescript-eslint/visitor-keys@7.3.1":
- version "7.3.1"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.3.1.tgz#6ddef14a3ce2a79690f01176f5305c34d7b93d8c"
- integrity sha512-9RMXwQF8knsZvfv9tdi+4D/j7dMG28X/wMJ8Jj6eOHyHWwDW4ngQJcqEczSsqIKKjFiLFr40Mnr7a5ulDD3vmw==
+"@typescript-eslint/visitor-keys@8.8.1":
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.8.1.tgz#0fb1280f381149fc345dfde29f7542ff4e587fc5"
+ integrity sha512-0/TdC3aeRAsW7MDvYRwEc1Uwm0TIBfzjPFgg60UU2Haj5qsCs9cc3zNgY71edqE3LbWfF/WoZQd3lJoDXFQpag==
dependencies:
- "@typescript-eslint/types" "7.3.1"
- eslint-visitor-keys "^3.4.1"
+ "@typescript-eslint/types" "8.8.1"
+ eslint-visitor-keys "^3.4.3"
"@ungap/structured-clone@^1.2.0":
version "1.2.0"
@@ -1861,11 +1851,6 @@ array-includes@^3.1.7:
get-intrinsic "^1.2.4"
is-string "^1.0.7"
-array-union@^2.1.0:
- version "2.1.0"
- resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
- integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
-
array.prototype.findlastindex@^1.2.3:
version "1.2.5"
resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d"
@@ -2545,13 +2530,6 @@ diff-sequences@^29.6.3:
resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921"
integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==
-dir-glob@^3.0.1:
- version "3.0.1"
- resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
- integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
- dependencies:
- path-type "^4.0.0"
-
doctrine@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d"
@@ -2770,11 +2748,6 @@ escodegen@^2.0.0:
optionalDependencies:
source-map "~0.6.1"
-eslint-config-prettier@^9.1.0:
- version "9.1.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f"
- integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==
-
eslint-import-resolver-node@^0.3.9:
version "0.3.9"
resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac"
@@ -2970,7 +2943,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-fast-glob@^3.2.12, fast-glob@^3.2.9:
+fast-glob@^3.2.12, fast-glob@^3.3.2:
version "3.3.2"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129"
integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==
@@ -3258,6 +3231,11 @@ globals@^13.19.0:
dependencies:
type-fest "^0.20.2"
+globals@^15.11.0:
+ version "15.11.0"
+ resolved "https://registry.yarnpkg.com/globals/-/globals-15.11.0.tgz#b96ed4c6998540c6fb824b24b5499216d2438d6e"
+ integrity sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==
+
globalthis@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf"
@@ -3265,18 +3243,6 @@ globalthis@^1.0.3:
dependencies:
define-properties "^1.1.3"
-globby@^11.1.0:
- version "11.1.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b"
- integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==
- dependencies:
- array-union "^2.1.0"
- dir-glob "^3.0.1"
- fast-glob "^3.2.9"
- ignore "^5.2.0"
- merge2 "^1.4.1"
- slash "^3.0.0"
-
glsl-tokenizer@^2.1.5:
version "2.1.5"
resolved "https://registry.yarnpkg.com/glsl-tokenizer/-/glsl-tokenizer-2.1.5.tgz#1c2e78c16589933c274ba278d0a63b370c5fee1a"
@@ -3460,11 +3426,16 @@ ieee754@^1.1.13:
resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz"
integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==
-ignore@^5.2.0, ignore@^5.2.4:
+ignore@^5.2.0:
version "5.3.1"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef"
integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==
+ignore@^5.3.1:
+ version "5.3.2"
+ resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5"
+ integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==
+
import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
@@ -4506,7 +4477,7 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-merge2@^1.3.0, merge2@^1.4.1:
+merge2@^1.3.0:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@@ -4541,13 +4512,6 @@ mimic-response@^3.1.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
-minimatch@9.0.3:
- version "9.0.3"
- resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825"
- integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==
- dependencies:
- brace-expansion "^2.0.1"
-
minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
@@ -4562,6 +4526,13 @@ minimatch@^5.0.1, minimatch@^5.1.0:
dependencies:
brace-expansion "^2.0.1"
+minimatch@^9.0.4:
+ version "9.0.5"
+ resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5"
+ integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==
+ dependencies:
+ brace-expansion "^2.0.1"
+
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5:
version "1.2.6"
resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz"
@@ -4929,11 +4900,6 @@ path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-path-type@^4.0.0:
- version "4.0.0"
- resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
- integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
performance-now@^2.1.0:
version "2.1.0"
resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz"
@@ -5324,6 +5290,11 @@ semver@^7.3.5, semver@^7.5.3, semver@^7.5.4:
dependencies:
lru-cache "^6.0.0"
+semver@^7.6.0:
+ version "7.6.3"
+ resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143"
+ integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==
+
set-blocking@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7"
@@ -5698,7 +5669,7 @@ tr46@^3.0.0:
dependencies:
punycode "^2.1.1"
-ts-api-utils@^1.0.1:
+ts-api-utils@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1"
integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==
@@ -5812,6 +5783,15 @@ typed-array-length@^1.0.5:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
+typescript-eslint@^8.8.1:
+ version "8.8.1"
+ resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.8.1.tgz#b375c877b2184d883b6228170bc66f0fca847c9a"
+ integrity sha512-R0dsXFt6t4SAFjUSKFjMh4pXDtq04SsFKCVGDP3ZOzNP7itF0jBcZYU4fMsZr4y7O7V7Nc751dDeESbe4PbQMQ==
+ dependencies:
+ "@typescript-eslint/eslint-plugin" "8.8.1"
+ "@typescript-eslint/parser" "8.8.1"
+ "@typescript-eslint/utils" "8.8.1"
+
typescript@^4.0.3:
version "4.9.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"