From f64da05a360bc6adf21b8d56c9e9ba126d8b3c91 Mon Sep 17 00:00:00 2001 From: Sam Vervaeck Date: Sun, 10 May 2020 11:58:07 +0200 Subject: [PATCH] Undo creation of workspaces and merge treegen with main source --- package-lock.json | 197 ++-- package.json | 3 +- src/ast.d.ts | 148 +++ src/ast.ts | 973 ------------------ .../bin/treegen.ts => src/bin/bolt-treegen.ts | 135 ++- src/bin/bolt.ts | 4 +- src/checker.ts | 9 +- src/compiler.ts | 10 +- src/emitter.ts | 14 +- src/evaluator.ts | 48 +- src/expander.ts | 72 +- src/package.ts | 7 +- src/program.ts | 79 +- src/treegen/ast-template.js | 75 ++ {treegen/src => src/treegen}/ast.ts | 25 + {treegen/src => src/treegen}/parser.d.ts | 7 +- {treegen/src => src/treegen}/parser.pegjs | 0 treegen/src/index.ts => src/treegen/util.ts | 0 src/util.ts | 66 ++ treegen/package-lock.json | 25 - treegen/src/util.ts | 49 - 21 files changed, 654 insertions(+), 1292 deletions(-) create mode 100644 src/ast.d.ts delete mode 100644 src/ast.ts rename treegen/src/bin/treegen.ts => src/bin/bolt-treegen.ts (53%) create mode 100644 src/treegen/ast-template.js rename {treegen/src => src/treegen}/ast.ts (56%) rename {treegen/src => src/treegen}/parser.d.ts (72%) rename {treegen/src => src/treegen}/parser.pegjs (100%) rename treegen/src/index.ts => src/treegen/util.ts (100%) delete mode 100644 treegen/package-lock.json delete mode 100644 treegen/src/util.ts diff --git a/package-lock.json b/package-lock.json index ba0d78b15..7e1ba1de6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,12 +5,12 @@ "requires": true, "dependencies": { "@babel/runtime-corejs3": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz", - "integrity": "sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg==", + "version": "7.9.6", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.6.tgz", + "integrity": "sha512-6toWAfaALQjt3KMZQc6fABqZwUDDuWzz+cAfPhqyEnzxvdWOAkjwPNxgF8xlmo7OWLsSjaKjsskpKHRLaMArOA==", "requires": { "core-js-pure": "^3.0.0", - "regenerator-runtime": "^0.13.2" + "regenerator-runtime": "^0.13.4" } }, "@types/chai": { @@ -73,10 +73,9 @@ "dev": true }, "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" }, "ansi-styles": { "version": "3.2.1", @@ -112,11 +111,6 @@ "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true }, - "astring": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/astring/-/astring-1.4.3.tgz", - "integrity": "sha512-yJlJU/bmN820vL+cbWShu2YQU87dBP5V7BH2N4wODapRv27A2dZtUD0LgjP9lZENvPe9XRoSyWx+pZR6qKqNBw==" - }, "at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -233,36 +227,6 @@ "string-width": "^4.2.0", "strip-ansi": "^6.0.0", "wrap-ansi": "^6.2.0" - }, - "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - } } }, "color-convert": { @@ -286,9 +250,9 @@ "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" }, "core-js-pure": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz", - "integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw==" + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz", + "integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==" }, "debug": { "version": "3.2.6", @@ -750,6 +714,15 @@ "ansi-regex": "^4.1.0" } }, + "supports-color": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", + "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, "wrap-ansi": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", @@ -885,9 +858,9 @@ "dev": true }, "pegjs": { - "version": "0.11.0-master.b7b87ea", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.11.0-master.b7b87ea.tgz", - "integrity": "sha512-fwjzNiYHRUEUe/86Aaslb/ocbbsAupOcsJz+dlPYtgp3feCDRQOLChHO924XGh7fzSJBTdFCQTzmSOQaWjCTew==" + "version": "0.11.0-master.f69239d", + "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.11.0-master.f69239d.tgz", + "integrity": "sha512-8PXSaXnLh9hw0R/SfOL1b8JSgiPv1KSl8B1h+sP0uwngmx3Vk+QdB2cuBAT1lXPbP5necVZ2Dl2t4DfR3KKbZg==" }, "picomatch": { "version": "2.2.2", @@ -910,9 +883,9 @@ "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==" }, "regenerator-runtime": { - "version": "0.13.3", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", - "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + "version": "0.13.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz", + "integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA==" }, "require-directory": { "version": "2.1.1", @@ -956,13 +929,20 @@ "dev": true }, "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", "requires": { - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^4.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + } } }, "string.prototype.trimend": { @@ -1008,12 +988,11 @@ } }, "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", "requires": { - "ansi-regex": "^3.0.0" + "ansi-regex": "^5.0.0" } }, "strip-json-comments": { @@ -1022,15 +1001,6 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, - "supports-color": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz", - "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, "to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -1072,6 +1042,33 @@ "dev": true, "requires": { "string-width": "^1.0.2 || 2" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } } }, "wrap-ansi": { @@ -1084,11 +1081,6 @@ "strip-ansi": "^6.0.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, "ansi-styles": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", @@ -1110,29 +1102,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } } } }, @@ -1172,11 +1141,6 @@ "yargs-parser": "^18.1.1" }, "dependencies": { - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==" - }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -1186,11 +1150,6 @@ "path-exists": "^4.0.0" } }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -1212,24 +1171,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" }, - "string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "requires": { - "ansi-regex": "^5.0.0" - } - }, "yargs-parser": { "version": "18.1.3", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", diff --git a/package.json b/package.json index 078306cc3..0723f9717 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "A programming language for rapid prototyping", "main": "lib/index.js", "bin": { - "bolt": "lib/bin/bolt.js" + "bolt": "lib/bin/bolt.js", + "bolt-treegen": "lib/bin/bolt-treegen.js" }, "scripts": { "test": "mocha lib/test" diff --git a/src/ast.d.ts b/src/ast.d.ts new file mode 100644 index 000000000..a01a06456 --- /dev/null +++ b/src/ast.d.ts @@ -0,0 +1,148 @@ + +export const enum SyntaxKind { + FunctionBody = 1 + BoltStringLiteral = 4 + BoltIntegerLiteral = 5 + BoltIdentifier = 7 + BoltOperator = 8 + BoltEOS = 9 + BoltComma = 10 + BoltSemi = 11 + BoltDot = 12 + BoltDotDot = 13 + BoltRArrow = 14 + BoltLArrow = 15 + BoltEqSign = 16 + BoltFnKeyword = 18 + BoltForeignKeyword = 19 + BoltLetKeyword = 20 + BoltImportKeyword = 21 + BoltPubKeyword = 22 + BoltModKeyword = 23 + BoltEnumKeyword = 24 + BoltStructKeyword = 25 + BoltNewTypeKeyword = 26 + BoltParenthesized = 28 + BoltBraced = 29 + BoltBracketed = 30 + BoltSourceElement = 31 + BoltSourceFile = 32 + BoltQualName = 33 + BoltReferenceTypeNode = 35 + BoltBindPattern = 37 + BoltTypePattern = 38 + BoltExpressionPattern = 39 + BoltTuplePatternElement = 40 + BoltTuplePattern = 41 + BoltRecordPatternField = 42 + BoltRecordPattern = 43 + BoltCallExpression = 45 + BoltYieldExpression = 46 + BoltMatchArm = 47 + BoltMatchExpression = 48 + BoltCase = 49 + BoltCaseExpression = 50 + BoltBlockExpression = 51 + BoltConstantExpression = 52 + BoltReturnStatement = 54 + BoltResumeStatement = 55 + BoltExpressionStatement = 56 + BoltModule = 57 + BoltParameter = 58 + BoltFunctionDeclaration = 60 + BoltForeignFunctionDeclaration = 61 + BoltVariableDeclaration = 62 + BoltPlainImportSymbol = 64 + BoltImportDeclaration = 65 + BoltRecordDeclarationField = 66 + BoltRecordDeclaration = 67 + JSOperator = 70 + JSIdentifier = 71 + JSPattern = 72 + JSBindPattern = 73 + JSConstantExpression = 75 + JSMemberExpression = 77 + JSCallExpression = 78 + JSBinaryExpression = 79 + JSUnaryExpression = 80 + JSNewExpression = 81 + JSSequenceExpression = 82 + JSConditionalExpression = 83 + JSReferenceExpression = 84 + JSConditionalStatement = 86 + JSSourceFile = 88 + JSSourceElement = 89 +} + +export function createFunctionBody(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltStringLiteral(value: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltIntegerLiteral(value: number, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltIdentifier(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltOperator(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltEOS(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltComma(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltSemi(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltDot(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltDotDot(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltRArrow(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltLArrow(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltEqSign(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltFnKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltForeignKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltLetKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltImportKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltPubKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltModKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltEnumKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltStructKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltNewTypeKeyword(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltParenthesized(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltBraced(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltBracketed(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltSourceElement(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltSourceFile(elements: BoltSourceElement[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltQualName(modulePath: BoltIdentifier[], name: BoltSymbol, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltReferenceTypeNode(name: BoltQualName, arguments: BoltTypeNode[] | null, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltBindPattern(name: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltTypePattern(typeNode: BoltTypeNode, nestedPattern: BoltPattern, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltExpressionPattern(expression: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltTuplePatternElement(index: number, pattern: BoltPattern, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltTuplePattern(elements: BoltTuplePatternElement[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltRecordPatternField(name: BoltIdentifier, pattern: BoltPattern, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltRecordPattern(fields: BoltRecordPatternField[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltCallExpression(operator: BoltExpression, operands: BoltExpression[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltYieldExpression(value: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltMatchArm(pattern: BoltPattern, body: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltMatchExpression(value: BoltExpression, arms: BoltMatchArm[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltCase(test: BoltExpression, result: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltCaseExpression(cases: BoltCase[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltBlockExpression(statements: BoltStatement[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltConstantExpression(value: BoltValue, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltReturnStatement(value: BoltExpression | null, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltResumeStatement(value: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltExpressionStatement(expression: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltModule(modifiers: BoltDeclarationModifiers, name: BoltQualName, elements: BoltSourceElement, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltParameter(index: number, bindings: BoltPattern, typeNode: BoltTypeNode | null, defaultValue: BoltExpression | null, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltFunctionDeclaration(modifiers: BoltDeclarationModifiers, name: BoltSymbol, params: BoltParameter[], type: BoltTypeNode | null, body: BoltExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltForeignFunctionDeclaration(modifiers: BoltDeclarationModifiers, name: BoltSymbol, params: BoltParameter[], type: BoltTypeNode | null, body: FunctionBody, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltVariableDeclaration(modifiers: BoltDeclarationModifiers, name: BoltSymbol, type: BoltTypeNode | null, value: BoltExpression | null, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltPlainImportSymbol(name: BoltQualName, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltImportDeclaration(file: string, symbols: BoltImportSymbol[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltRecordDeclarationField(name: BoltIdentifier, type: BoltTypeNode, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createBoltRecordDeclaration(name: BoltQualName, fields: BoltRecordDeclarationField[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSOperator(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSIdentifier(text: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSPattern(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSBindPattern(name: JSIdentifier, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSConstantExpression(value: BoltValue, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSMemberExpression(value: JSExpression, property: JSExpression, modifiers: JSMemberExpressionModifiers, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSCallExpression(operator: JSExpression, operands: JSExpression[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSBinaryExpression(left: JSExpression, operator: JSOperator, right: JSExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSUnaryExpression(operator: JSOperator, operand: JSExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSNewExpression(target: JSExpression, arguments: JSExpression[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSSequenceExpression(expressions: JSExpression[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSConditionalExpression(test: JSExpression, consequent: JSExpression, alternate: JSExpression, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSReferenceExpression(name: string, span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSConditionalStatement(test: JSExpression, consequent: JSStatement[], alternate: JSStatement[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSSourceFile(elements: JSSourceElement[], span: TextSpan | null = null, origNodes: SyntaxRange | null = null); +export function createJSSourceElement(span: TextSpan | null = null, origNodes: SyntaxRange | null = null); diff --git a/src/ast.ts b/src/ast.ts deleted file mode 100644 index 621e1676c..000000000 --- a/src/ast.ts +++ /dev/null @@ -1,973 +0,0 @@ - -// FIXME SyntaxBase.getSpan() does not work then [n1, n2] is given as origNode - -import * as path from "path" - -import { Stream, StreamWrapper, FastStringMap } from "./util" -import { Scanner } from "./scanner" -import { RecordType, PrimType, OptionType, VariantType, stringType, intType, boolType } from "./checker" -import { bind } from "./bindings" -import { Value } from "./evaluator" - -interface JsonArray extends Array { }; -interface JsonObject { [key: string]: Json } -type Json = null | string | boolean | number | JsonArray | JsonObject; - -export type TokenStream = Stream; - -export enum SyntaxKind { - - // Bolt language AST - - // Tokens - - StringLiteral, - IntegerLiteral, - Identifier, - Operator, - Parenthesized, - Braced, - Bracketed, - Semi, - Comma, - Colon, - Dot, - RArrow, - EqSign, - - // Keywords - - FnKeyword, - ForeignKeyword, - LetKeyword, - ImportKeyword, - PubKeyword, - ModKeyword, - EnumKeyword, - StructKeyword, - NewTypeKeyword, - - // Special nodes - - SourceFile, - Module, - QualName, - Sentence, - Param, - EOS, - - // Patterns - - BindPatt, - TypePatt, - RecordPatt, - TuplePatt, - - // Expressions - - CallExpr, - ConstExpr, - RefExpr, - MatchExpr, - - // Statements - - RetStmt, - CondStmt, - - // Type declarations - - TypeRef, - - // Declaration nodes - - VarDecl, - FuncDecl, - ImportDecl, - RecordDecl, - VariantDecl, - NewTypeDecl, - - // JavaScript AST - - // Expressions - - JSReferenceExpression, - JSCallExpression, - JSYieldExpression, - - // Statements - - JSReturnStatement, - - // Special nodes - - JSSourceFile, - - // C language AST - - // Miscellaneous elements - - CSourceFile, - -} - -export class TextFile { - - constructor(public origPath: string) { - - } - - get fullPath() { - return path.resolve(this.origPath) - } - -} - -export class TextPos { - - constructor( - public offset: number, - public line: number, - public column: number - ) { - - } - - clone() { - return new TextPos(this.offset, this.line, this.column) - } - -} - -export class TextSpan { - - constructor( - public file: TextFile, - public start: TextPos, - public end: TextPos - ) { - - } - - clone() { - return new TextSpan(this.file, this.start.clone(), this.end.clone()); - } - -} - -export type SyntaxRange = [Syntax, Syntax]; - -abstract class SyntaxBase { - - abstract kind: SyntaxKind; - - public parentNode: Syntax | null = null; - - constructor( - public span: TextSpan | null, - public origNode: SyntaxRange | null, - ) { - - } - -} - -export const fileType = new PrimType(); - -@bind('Bolt.AST.StringLiteral') -export class StringLiteral extends SyntaxBase { - - kind: SyntaxKind.StringLiteral = SyntaxKind.StringLiteral; - - constructor( - public value: string, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class IntegerLiteral extends SyntaxBase { - - kind: SyntaxKind.IntegerLiteral = SyntaxKind.IntegerLiteral; - - constructor( - public value: bigint, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - - toJSON(): Json { - return { - value: ['bigint', this.value.toString()], - span: this.span !== null ? this.span.toJSON() : null, - } - } - - *getChildren(): IterableIterator { - - } - -} - - -export enum PunctType { - Paren, - Bracket, - Brace, -} - -export class EOS extends SyntaxBase { - kind: SyntaxKind.EOS = SyntaxKind.EOS; -} - -export abstract class Punctuated extends SyntaxBase { - - constructor( - public text: string, - span: TextSpan, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - - toSentences() { - const scanner = new Scanner(this.span!.file, this.text) - return scanner.scanTokens() - } - - toTokenStream() { - const startPos = this.span!.start; - return new Scanner(this.span!.file, this.text, new TextPos(startPos.offset+1, startPos.line, startPos.column+1)); - } - -} - -export class Parenthesized extends Punctuated { - kind: SyntaxKind.Parenthesized = SyntaxKind.Parenthesized; -} - -export class Braced extends Punctuated { - kind: SyntaxKind.Braced = SyntaxKind.Braced; -} - -export class Bracketed extends Punctuated { - kind: SyntaxKind.Bracketed = SyntaxKind.Bracketed; -} - -export class Identifier extends SyntaxBase { - - kind: SyntaxKind.Identifier = SyntaxKind.Identifier; - - constructor( - public text: string, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class Operator extends SyntaxBase { - - kind: SyntaxKind.Operator = SyntaxKind.Operator; - - constructor( - public text: string, - public span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - parentNode: Syntax | null = null - ) { - super(span, origNode); - } - -} - -export class Semi extends SyntaxBase { - kind: SyntaxKind.Semi = SyntaxKind.Semi; -} - -export class Colon extends SyntaxBase { - kind: SyntaxKind.Colon = SyntaxKind.Colon; -} - -export class Comma extends SyntaxBase { - kind: SyntaxKind.Comma = SyntaxKind.Comma; -} - - -export class RArrow extends SyntaxBase { - kind: SyntaxKind.RArrow = SyntaxKind.RArrow; -} - -export class EqSign extends SyntaxBase { - kind: SyntaxKind.EqSign = SyntaxKind.EqSign; -} - -export class Dot extends SyntaxBase { - kind: SyntaxKind.Dot = SyntaxKind.Dot; -} - -export type Token - = Semi - | Comma - | Colon - | EqSign - | Dot - | RArrow - | EOS - | Identifier - | Operator - | StringLiteral - | IntegerLiteral - | Parenthesized - | Braced - | Bracketed - -export class Sentence extends SyntaxBase { - - kind: SyntaxKind.Sentence = SyntaxKind.Sentence; - - constructor( - public tokens: Token[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - - toTokenStream() { - return new StreamWrapper( - this.tokens, - () => new EOS(new TextSpan(this.getSpan().file, this.getSpan().end.clone(), this.getSpan().end.clone())) - ); - } - -} - -export class QualName extends SyntaxBase { - - kind: SyntaxKind.QualName = SyntaxKind.QualName; - - constructor( - public name: Identifier | Operator, - public path: Identifier[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - - get fullText() { - let out = '' - for (const chunk of this.path) { - out += chunk.text + '.' - } - return out + this.name.text - } - -} - -export class Param extends SyntaxBase { - - kind: SyntaxKind.Param = SyntaxKind.Param; - - constructor( - public bindings: Patt, - public typeDecl: TypeDecl | null, - public defaultValue: Expr | null, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class BindPatt extends SyntaxBase { - - kind: SyntaxKind.BindPatt = SyntaxKind.BindPatt; - - constructor( - public name: Identifier, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -// FIXME make this a node -export interface RecordPattField { - name: Identifier; - pattern: Patt, -} - -export class RecordPatt extends SyntaxBase { - - kind: SyntaxKind.RecordPatt = SyntaxKind.RecordPatt; - - constructor( - public typeDecl: TypeDecl, - public fields: RecordPattField[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class TuplePatt extends SyntaxBase { - - kind: SyntaxKind.TuplePatt = SyntaxKind.TuplePatt; - - constructor( - public elements: Patt[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class TypePatt extends SyntaxBase { - - kind: SyntaxKind.TypePatt = SyntaxKind.TypePatt; - - constructor( - public typeDecl: TypeDecl, - public pattern: Patt, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type Patt - = BindPatt - | Expr - | TypePatt - | TuplePatt - | RecordPatt - -export class RefExpr extends SyntaxBase { - - kind: SyntaxKind.RefExpr = SyntaxKind.RefExpr; - - constructor( - public name: QualName, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class CallExpr extends SyntaxBase { - - kind: SyntaxKind.CallExpr = SyntaxKind.CallExpr; - - constructor( - public operator: Expr, - public args: Expr[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -// FIXME make this a node -export type MatchArm = [Patt, Expr | Stmt[]]; - -export class MatchExpr extends SyntaxBase { - - kind: SyntaxKind.MatchExpr = SyntaxKind.MatchExpr; - - constructor( - public value: Expr, - public arms: MatchArm[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class ConstExpr extends SyntaxBase { - - kind: SyntaxKind.ConstExpr = SyntaxKind.ConstExpr; - - constructor( - public value: Value, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type Expr - = ConstExpr - | RefExpr - | CallExpr - | MatchExpr - -export class RetStmt extends SyntaxBase { - - kind: SyntaxKind.RetStmt = SyntaxKind.RetStmt; - - constructor( - public value: Expr | null, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export interface Case { - conditional: Expr, - consequent: Stmt[] -} - -export class CondStmt extends SyntaxBase { - - kind: SyntaxKind.CondStmt = SyntaxKind.CondStmt - - constructor( - public cases: Case[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type Stmt - = RetStmt - | CondStmt - -export class TypeRef extends SyntaxBase { - - kind: SyntaxKind.TypeRef = SyntaxKind.TypeRef; - - constructor( - public name: QualName, - public typeArgs: TypeDecl[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type TypeDecl - = TypeRef - -export class FuncDecl extends SyntaxBase { - - kind: SyntaxKind.FuncDecl = SyntaxKind.FuncDecl; - - constructor( - public isPublic: boolean, - public target: string, - public name: QualName, - public params: Param[], - public returnType: TypeDecl | null, - public body: Body | null, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class VarDecl extends SyntaxBase { - - kind: SyntaxKind.VarDecl = SyntaxKind.VarDecl; - - constructor( - public isMutable: boolean, - public bindings: Patt, - public typeDecl: TypeDecl | null, - public value: Expr | null, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class ImportDecl extends SyntaxBase { - - kind: SyntaxKind.ImportDecl = SyntaxKind.ImportDecl; - - constructor( - public file: string, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class RecordDecl extends SyntaxBase { - - kind: SyntaxKind.RecordDecl = SyntaxKind.RecordDecl; - - fields: Map; - - constructor( - public isPublic: boolean, - public name: QualName, - fields: Iterable<[Identifier, TypeDecl]>, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode) - this.fields = new Map(fields); - } - -} - -export class NewTypeDecl extends SyntaxBase { - - kind: SyntaxKind.NewTypeDecl = SyntaxKind.NewTypeDecl; - - constructor( - public isPublic: boolean, - public name: Identifier, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type Decl - = Sentence - | FuncDecl - | ImportDecl - | NewTypeDecl - | VarDecl - | RecordDecl - -export type Syntax - = Decl - | Expr - | Token - | Stmt - | Patt - | TypeDecl - | Module - | SourceFile - | QualName - | Param - | EOS - -export type SourceElement = (Module | Decl | Stmt | Expr); - -export class Module extends SyntaxBase { - - kind: SyntaxKind.Module = SyntaxKind.Module; - - constructor( - public isPublic: boolean, - public name: QualName, - public elements: SourceElement[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class SourceFile extends SyntaxBase { - - kind: SyntaxKind.SourceFile = SyntaxKind.SourceFile; - - constructor( - public elements: SourceElement[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export function isExpr(node: Syntax): node is Expr { - return node.kind === SyntaxKind.ConstExpr - || node.kind === SyntaxKind.CallExpr - || node.kind === SyntaxKind.MatchExpr - || node.kind === SyntaxKind.RefExpr; -} - -export class JSYieldExpression extends SyntaxBase { - - kind: SyntaxKind.JSYieldExpression = SyntaxKind.JSYieldExpression; - - constructor( - public value: JSExpression, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export class JSReferenceExpression extends SyntaxBase { - - kind: SyntaxKind.JSReferenceExpression = SyntaxKind.JSReferenceExpression; - - constructor( - public name: string, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null - ) { - super(span, origNode); - } - -} - -export class JSCallExpression extends SyntaxBase { - - kind: SyntaxKind.JSCallExpression = JSCallExpression; - - constructor( - public operator: JSExpression, - public operands: JSExpression[], - ) { - - } - -} - -export type JSExpression - = JSYieldExpression - | JSReferenceExpression - | JSCallExpression - -export type JSStatement - = JSReturnStatement - -export type JSDeclaration - = JSVariableDeclaration - | JSFunctionDeclaration - -export type JSSourceElement - = JSStatement - | JSDeclaration - -export class JSSourceFile extends SyntaxBase { - - kind: SyntaxKind.JSSourceFile = SyntaxKind.JSSourceFile; - - constructor( - public elements: JSSourceElement[], - span: TextSpan | null = null, - origNode: SyntaxRange | null = null, - ) { - super(span, origNode); - } - -} - -export type JSSyntax - = JSExpression - | JSStatement - | JSDeclaration - | JSSourceFile - -export type CSourceElement - = never - -export class CSourceFile extends SyntaxBase { - - kind: SyntaxKind.CSourceFile = SyntaxKind.CSourceFile; - - constructor( - public elements: CSourceElement, - span: TextSpan | null = null, - origNode: SyntaxRange | null = null - ) { - super(span, origNode); - } - -} - -export type CSyntax - = CSourceFile - -export type AnySyntax - = Syntax - | JSSyntax - | CSyntax - -export type AnySourceFile - = SourceFile - | JSSourceFile - | CSourceFile - -export function nodeToJSON(node: Syntax) { - - const obj: Json = { - kind: SyntaxKind[node.kind], - }; - - for (const key of Object.keys(node)) { - if (key !== 'kind' && key !== 'origNode' && key !== 'parentNode') { - const value = (node as any)[key]; - if (Array.isArray(value)) { - obj[key] = value.map(visit) - } else { - obj[key] = visit(value); - } - } - } - - return obj; - - function visit(value: any) { - if (isNode(value)) { - return nodeToJSON(node); - } else { - return value; - } - } - -} - -export function isJSNode(node: Syntax): node is JSSyntax { - return SyntaxKind[node.kind].startsWith('JS'); -} - -export function getChildren(node: Syntax) { - - const out: Syntax[] = []; - - for (const key of Object.keys(node)) { - if (key !== 'kind' && key !== 'origNode' && key !== 'parentNode') { - const value = (node as any)[key]; - if (Array.isArray(value)) { - for (const element of value) { - visit(element) - } - } else { - visit(value) - } - } - } - - return out; - - function visit(value: any) { - if (isNode(value)) { - out.push(value); - } - } - -} - -export function kindToString(kind: SyntaxKind) { - return SyntaxKind[kind]; -} - -export function isNode(value: any): value is Syntax { - return typeof value.kind === 'number' - && Object.prototype.hasOwnProperty.call(SyntaxKind, value.kind) -} - -export function getTargetLanguage(node: AnySyntax) { - switch (node.kind) { - case SyntaxKind.StringLiteral: - case SyntaxKind.IntegerLiteral: - case SyntaxKind.Identifier: - case SyntaxKind.Operator: - case SyntaxKind.Parenthesized: - case SyntaxKind.Braced: - case SyntaxKind.Bracketed: - case SyntaxKind.Semi: - case SyntaxKind.Comma: - case SyntaxKind.Colon: - case SyntaxKind.Dot: - case SyntaxKind.RArrow: - case SyntaxKind.EqSign: - case SyntaxKind.FnKeyword: - case SyntaxKind.ForeignKeyword: - case SyntaxKind.LetKeyword: - case SyntaxKind.ImportKeyword: - case SyntaxKind.PubKeyword: - case SyntaxKind.ModKeyword: - case SyntaxKind.EnumKeyword: - case SyntaxKind.StructKeyword: - case SyntaxKind.NewTypeKeyword: - case SyntaxKind.SourceFile: - case SyntaxKind.Module: - case SyntaxKind.QualName: - case SyntaxKind.Sentence: - case SyntaxKind.Param: - case SyntaxKind.EOS: - case SyntaxKind.BindPatt: - case SyntaxKind.TypePatt: - case SyntaxKind.RecordPatt: - case SyntaxKind.TuplePatt: - case SyntaxKind.CallExpr: - case SyntaxKind.ConstExpr: - case SyntaxKind.RefExpr: - case SyntaxKind.MatchExpr: - case SyntaxKind.RetStmt: - case SyntaxKind.CondStmt: - case SyntaxKind.TypeRef: - case SyntaxKind.VarDecl: - case SyntaxKind.FuncDecl: - case SyntaxKind.ImportDecl: - case SyntaxKind.RecordDecl: - case SyntaxKind.VariantDecl: - case SyntaxKind.NewTypeDecl: - return "Bolt"; - case SyntaxKind.JSReferenceExpression: - case SyntaxKind.JSCallExpression: - case SyntaxKind.JSYieldExpression: - case SyntaxKind.JSReturnStatement: - case SyntaxKind.JSSourceFile: - return "JS"; - case SyntaxKind.CSourceFile: - return "C"; - default: - throw new Error(`Could not determine language of ${SyntaxKind[node.kind]}.`); - } -} - -export function setParents(node: Syntax) { - for (const child of getChildren(node)) { - child.parentNode = node - setParents(child) - } -} - diff --git a/treegen/src/bin/treegen.ts b/src/bin/bolt-treegen.ts similarity index 53% rename from treegen/src/bin/treegen.ts rename to src/bin/bolt-treegen.ts index 9e6a3aecc..1f20e36a6 100755 --- a/treegen/src/bin/treegen.ts +++ b/src/bin/bolt-treegen.ts @@ -3,15 +3,23 @@ import * as path from "path" import * as fs from "fs" -import { parse, SyntaxError } from "../parser" -import { Declaration, NodeDeclaration, TypeDeclaration, EnumDeclaration, TypeNode, NodeField } from "../ast" +import { parse, SyntaxError } from "../treegen/parser" +import { Syntax, Declaration, NodeDeclaration, TypeDeclaration, EnumDeclaration, TypeNode, NodeField } from "../ast" import { FileWriter } from "../util" +import minimist from "minimist" -for (const filename of process.argv.slice(2)) { +const PACKAGE_ROOT = path.join(__dirname, '..', '..'); + +const argv = minimist(process.argv.slice(2)); + +const jsFilePath = argv['js-file'] ?? 'lib/ast.js'; +const dtsFilePath = argv['dts-file'] ?? 'src/ast.d.ts'; + +for (const filename of argv._) { const contents = fs.readFileSync(filename, 'utf8'); let decls: Declaration[]; try { - decls = parse(contents); + decls = parse(contents, { prefix: getFileStem(filename) }); } catch (e) { if (e instanceof SyntaxError) { console.error(`${filename}:${e.location.start.line}:${e.location.start.column}: ${e.message}`); @@ -20,22 +28,29 @@ for (const filename of process.argv.slice(2)) { throw e; } } - const generated = generateAST(decls, getFileStem(filename)); - fs.writeFileSync('src/ast-generated.js', generated, 'utf8'); + const { jsFile, dtsFile } = generateAST(decls); + fs.writeFileSync(jsFilePath, jsFile, 'utf8'); + fs.writeFileSync(dtsFilePath, dtsFile, 'utf8'); } interface FastStringMap { [key: string]: T } -function generateAST(decls: Declaration[], langName: string) { +function generateAST(decls: Declaration[]) { let jsFile = new FileWriter(); + let dtsFile = new FileWriter(); + let i; + + // Sort declarations by category const nodeDecls: NodeDeclaration[] = decls.filter(decl => decl.type === 'NodeDeclaration') as NodeDeclaration[]; const typeDecls: TypeDeclaration[] = decls.filter(decl => decl.type === 'TypeDeclaration') as TypeDeclaration[]; const enumDecls: EnumDeclaration[] = decls.filter(decl => decl.type === 'EnumDeclaration') as EnumDeclaration[]; const declByName: FastStringMap = Object.create(null); + i = 0; for (const decl of decls) { + decl.index = i++; declByName[decl.name] = decl; } @@ -52,48 +67,91 @@ function generateAST(decls: Declaration[], langName: string) { } } + // After we're done mappping parents to children, we can use isLeafNode() + // to store the nodes we will be iterating most frequently on. + + const leafNodes: NodeDeclaration[] = nodeDecls.filter(decl => isLeafNode(decl.name)); + // Write a JavaScript file that contains all AST definitions. - jsFile.write(`\nconst NODE_TYPES = [\n`); + jsFile.write(`\nconst NODE_TYPES = {\n`); jsFile.indent(); - for (const decl of decls) { + for (const decl of leafNodes) { if (decl.type === 'NodeDeclaration' && isLeafNode(decl.name)) { - jsFile.write(`'${decl.name}': new Map([\n`); + jsFile.write(`'${decl.name}': {\n`); + jsFile.indent(); + jsFile.write(`index: ${decl.index},\n`); + jsFile.write(`fields: new Map([\n`); jsFile.indent(); for (const field of getAllFields(decl)) { - jsFile.write(`[${field.name}, ${emitTypeNode(field.typeNode)}],\n`); + jsFile.write(`['${field.name}', ${JSON.stringify(jsonify(field.typeNode))}],\n`); } jsFile.dedent(); jsFile.write(']),\n'); + jsFile.dedent(); + jsFile.write('},\n'); } } jsFile.dedent(); - jsFile.write('];\n\n'); + jsFile.write('};\n\n'); - function emitTypeNode(typeNode: TypeNode): string { - console.error(typeNode); - if (typeNode.type === 'ReferenceTypeNode') { - if (hasDeclarationNamed(typeNode.name)) { - return typeNode.name; - } else if (typeNode.name === 'Bool') { - return 'boolean'; - } else if (typeNode.name === 'String') { - return 'string'; - } else if (typeNode.name === 'usize') { - return 'bigint'; - } else if (typeNode.name === 'Vec') { - return `${emitTypeNode(typeNode.typeArgs[0])}[]`; - } else if (typeNode.name === 'Option') { - return `${emitTypeNode(typeNode.typeArgs[0])} | null`; - } - } - throw new Error(`Could not emit TypeScript type for type node ${typeNode.type}.`); + jsFile.write(fs.readFileSync(path.join(PACKAGE_ROOT, 'src', 'treegen', 'ast-template.js'), 'utf8')); + + jsFile.write(`if (typeof module !== 'undefined') {\n module.exports = exported;\n}\n\n`) + + // Write corresponding TypeScript declarations + + dtsFile.write(`\nexport const enum SyntaxKind {\n`); + for (const decl of leafNodes) { + dtsFile.write(` ${decl.name} = ${decl.index}\n`); } + dtsFile.write(`}\n\n`); + + for (const decl of leafNodes) { + dtsFile.write(`export function create${decl.name}(`); + for (const field of getAllFields(decl)) { + dtsFile.write(`${field.name}: ${emitTypeScriptType(field.typeNode)}, `); + } + dtsFile.write(`span: TextSpan | null = null, origNodes: SyntaxRange | null = null);\n`); + } + + + return { + jsFile: jsFile.currentText, + dtsFile: dtsFile.currentText, + }; + + // Below are some useful functions function hasDeclarationNamed(name: string): boolean { return name in declByName; } + function emitTypeScriptType(typeNode: TypeNode): string { + if (typeNode.type === 'ReferenceTypeNode') { + if (hasDeclarationNamed(typeNode.name)) { + return typeNode.name; + } else if (typeNode.name === 'Option') { + return `${emitTypeScriptType(typeNode.typeArgs[0])} | null`; + } else if (typeNode.name === 'Vec') { + return `${emitTypeScriptType(typeNode.typeArgs[0])}[]`; + } else if (typeNode.name === 'String') { + return `string`; + } else if (typeNode.name === 'Int') { + return `bigint`; + } else if (typeNode.name === 'usize') { + return `number`; + } else if (typeNode.name === 'bool') { + return `boolean`; + } else { + throw new Error(`Could not emit TypeScript type for reference type node named ${typeNode.name}`); + } + } else if (typeNode.type === 'UnionTypeNode') { + return typeNode.elements.map(emitTypeScriptType).join(' | '); + } + //throw new Error(`Could not emit TypeScript type for type node ${typeNode.type}`); + } + function getAllFields(nodeDecl: NodeDeclaration) { let out: NodeField[] = []; pushAll(out, nodeDecl.fields); @@ -123,8 +181,6 @@ function generateAST(decls: Declaration[], langName: string) { return childrenOf[name] === undefined || childrenOf[name].length === 0; } - return jsFile.currentText; - } function pushAll(arr: T[], els: T[]): void { @@ -133,6 +189,10 @@ function pushAll(arr: T[], els: T[]): void { } } +function isNode(value: any): value is Syntax { + return typeof value === 'object' && value !== null && value.__IS_NODE; +} + function jsonify(value: any) { function visitNode(node: any) { @@ -140,7 +200,7 @@ function jsonify(value: any) { const obj: any = {}; for (const key of Object.keys(node)) { - if (key !== 'type' && key !== 'span') { + if (key !== 'type' && key !== 'span' && key !== '__IS_NODE') { const value = node[key]; if (Array.isArray(value)) { obj[key] = value.map(visit); @@ -154,7 +214,7 @@ function jsonify(value: any) { } function visit(value: any) { - if (value.__IS_NODE) { + if (isNode(value)) { return visitNode(value); } else { return value; @@ -164,6 +224,13 @@ function jsonify(value: any) { return visit(value); } +function stripSuffix(str: string, suffix: string): string { + if (!str.endsWith(suffix)) { + return str; + } + return str.substring(0, str.length-suffix.length); +} + function getFileStem(filepath: string) { return path.basename(filepath).split('.')[0]; } diff --git a/src/bin/bolt.ts b/src/bin/bolt.ts index 8a18bb5b8..4fa2a1754 100644 --- a/src/bin/bolt.ts +++ b/src/bin/bolt.ts @@ -5,11 +5,9 @@ import "source-map-support/register" import * as path from "path" import * as fs from "fs-extra" -import { spawnSync } from "child_process" import yargs from "yargs" -import { Package, loadPackage } from "../package" import { Program } from "../program" import { TextFile } from "../ast" @@ -74,7 +72,7 @@ yargs const files = toArray(args.path as string[] | string).map(filepath => new TextFile(filepath, args['work-dir'])); const program = new Program(files) - program.compile({ target: "JS" }); + program.compile("JS"); }) diff --git a/src/checker.ts b/src/checker.ts index ce0ed5bde..b438545a8 100644 --- a/src/checker.ts +++ b/src/checker.ts @@ -3,7 +3,7 @@ import { Syntax, SyntaxKind, ImportDecl, - isNode, + Patt, } from "./ast" import { FastStringMap } from "./util" @@ -130,6 +130,9 @@ export class TypeChecker { switch (node.kind) { + case SyntaxKind.RefExpr: + return anyType; + case SyntaxKind.ConstExpr: return node.value.type; @@ -222,6 +225,10 @@ export class TypeChecker { } break; + case SyntaxKind.RefExpr: + // TODO implement this + break; + case SyntaxKind.Module: case SyntaxKind.SourceFile: for (const element of node.elements) { diff --git a/src/compiler.ts b/src/compiler.ts index 9321fe045..7a304dd57 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -16,6 +16,8 @@ import { isExpr, } from "./ast" +import { Program } from "./program" + export interface CompilerOptions { target: string; } @@ -30,7 +32,7 @@ export class Compiler { readonly target: string; - constructor(public checker: TypeChecker, options: CompilerOptions) { + constructor(public program: Program, public checker: TypeChecker, options: CompilerOptions) { this.target = options.target } @@ -44,14 +46,14 @@ export class Compiler { type: 'Program', body, loc: { - source: s.getFile().path + source: s.span!.file.path } } }); } - protected compileExpr(node: Syntax, preamble: Syntax[]): Expr { - + protected compileExpr(node: Syntax, preamble: Syntax[]): JSExpression { + switch (node.kind) { case SyntaxKind.CallExpr: diff --git a/src/emitter.ts b/src/emitter.ts index f980f2878..7860b43ee 100644 --- a/src/emitter.ts +++ b/src/emitter.ts @@ -1,16 +1,10 @@ -import * as astring from "astring" - import { Syntax, SyntaxKind, isJSNode } from "./ast" export class Emitter { emit(node: Syntax) { - if (isJSNode(node)) { - return astring.generate(node) - } - switch (node.kind) { case SyntaxKind.SourceFile: @@ -28,3 +22,11 @@ export class Emitter { } } +/** + * A wrapper around `Emitter` for quick emission of AST nodes with sane defaults. + */ +export function emit(node: Syntax) { + const emitter = new Emitter(); + return emitter.emit(node); +} + diff --git a/src/evaluator.ts b/src/evaluator.ts index e6265dfd5..78563f20a 100644 --- a/src/evaluator.ts +++ b/src/evaluator.ts @@ -65,6 +65,43 @@ export class RecordWrapper extends RecordValue { } +class Environment { + + private symbols: FastStringMap = Object.create(null); + + constructor(public parentEnv: Environment | null = null) { + + } + + setValue(name: string, value: Value) { + if (name in this.symbols) { + throw new Error(`A variable with the name '${name}' already exists.`); + } + this.symbols[name] = value; + } + + updateValue(name: string, newValue: Value) { + if (!(name in this.symbols)) { + throw new Error(`Trying to update a variable '${name}' that has not been declared.`); + } + } + + lookup(name: string) { + let curr = this as Environment; + while (true) { + if (name in curr.symbols) { + return curr.symbols[name]; + } + if (curr.parentEnv === null) { + break; + } + curr = curr.parentEnv; + } + throw new Error(`A variable named '${name}' was not found.`); + } + +} + export class Evaluator { constructor(public checker: TypeChecker) { @@ -99,27 +136,30 @@ export class Evaluator { } } - eval(node: Syntax): Value { + eval(node: Syntax, env: Environment = new Environment()): Value { switch (node.kind) { case SyntaxKind.SourceFile: case SyntaxKind.Module: for (const element of node.elements) { - this.eval(element); + this.eval(element, env); } break; + case SyntaxKind.RefExpr: + return env.lookup(node.name.fullText); + case SyntaxKind.NewTypeDecl: case SyntaxKind.RecordDecl: case SyntaxKind.FuncDecl: break; case SyntaxKind.MatchExpr: - const value = this.eval(node.value); + const value = this.eval(node.value, env); for (const [pattern, result] of node.arms) { if (this.match(value, pattern)) { - return this.eval(result as Expr) + return this.eval(result as Expr, env) } } return new PrimValue(this.checker.getTypeNamed('Void')!, null); diff --git a/src/expander.ts b/src/expander.ts index 37754a83f..333f2dc05 100644 --- a/src/expander.ts +++ b/src/expander.ts @@ -2,38 +2,32 @@ // FIXME Actually, the syntax expander could make use of algebraic effects to // easily specify how the next expansion should happen. Just a thought. -import { - TokenStream, - SyntaxKind, - Syntax, - SourceFile, - Decl, - RecordPatt, - Identifier, - TypeRef, - Patt, - ConstExpr, - QualName, - TuplePatt, - BindPatt, - TypePatt, - MatchExpr, - Stmt, - Module, +import { + BoltSyntax, + createBoltRecordPattern, + createBoltIdentifier, + createBoltReferenceTypeNode, + createBoltConstantExpression, + createBoltTuplePattern, + createBoltQualName, + createBoltTypePattern, + createBoltBindPattern, + BoltPattern, } from "./ast" +import { BoltTokenStream } from "./util" import { TypeChecker } from "./checker" import { Parser, ParseError } from "./parser" import { Evaluator, TRUE, FALSE } from "./evaluator" interface Transformer { - pattern: Patt; - transform: (node: TokenStream) => Syntax; + pattern: BoltPattern; + transform: (node: BoltTokenStream) => BoltSyntax; } -function createTypeRef(text: string) { - const ids = text.split('.').map(name => new Identifier(name)) - return new TypeRef(new QualName(ids[ids.length-1], ids.slice(0, -1)), []) +function createSimpleBoltReferenceTypeNode(text: string) { + const ids = text.split('.').map(name => createBoltIdentifier(name)) + return createBoltReferenceTypeNode(createBoltQualName(ids[ids.length-1], ids.slice(0, -1)), []) } /// This is actually a hand-parsed version of the following: @@ -50,27 +44,27 @@ function createTypeRef(text: string) { /// } /// ], /// } -const PATTERN_SYNTAX: Patt = - new RecordPatt( - createTypeRef('Bolt.AST.Sentence'), +const PATTERN_SYNTAX: Pattern = + createBoltRecordPattern( + createSimpleBoltReferenceTypeNode('Bolt.AST.Sentence'), [{ - name: new Identifier('elements'), - pattern: new TuplePatt([ - new RecordPatt( - createTypeRef('Bolt.AST.Identifier'), + name: createBoltIdentifier('elements'), + pattern: createBoltTuplePattern([ + createBoltRecordPattern( + createSimpleBoltReferenceTypeNode('Bolt.AST.Identifier'), [{ - name: new Identifier('text'), - pattern: new ConstExpr('syntax') + name: createBoltIdentifier('text'), + pattern: createBoltConstantExpression('syntax') }] ), - new RecordPatt( - createTypeRef('Bolt.AST.Braced'), + createBoltRecordPattern( + createSimpleBoltReferenceTypeNode('Bolt.AST.Braced'), [{ - name: new Identifier('elements'), - pattern: new TuplePatt([ - new TypePatt(createTypeRef('Bolt.AST.Pattern'), new BindPatt(new Identifier('pattern'))), - new TypePatt(createTypeRef('Bolt.AST.RArrow'), new BindPatt(new Identifier('_'))), - new TypePatt(createTypeRef('Bolt.AST.Expr'), new BindPatt(new Identifier('expression'))) + name: createBoltIdentifier('elements'), + pattern: createBoltTuplePattern([ + createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.Pattern'), createBoltBindPattern(createBoltIdentifier('pattern'))), + createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.RArrow'), createBoltBindPattern(createBoltIdentifier('_'))), + createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.Expr'), createBoltBindPattern(createBoltIdentifier('expression'))) ]) }] ) diff --git a/src/package.ts b/src/package.ts index 3acfd1359..992d9b94e 100644 --- a/src/package.ts +++ b/src/package.ts @@ -1,12 +1,7 @@ -import { TextFile } from "./ast" - export class Package { - constructor( - public name: string | null, - public files: TextFile[], - ) { + constructor(public rootDir: string) { } diff --git a/src/program.ts b/src/program.ts index 70e547622..b06dee559 100644 --- a/src/program.ts +++ b/src/program.ts @@ -1,26 +1,34 @@ import * as path from "path" -import * as fs from "fs" +import * as fs from "fs-extra" +import * as crypto from "crypto" -import { FastStringMap } from "./util" import { Parser } from "./parser" import { TypeChecker } from "./checker" import { Evaluator } from "./evaluator" import { Expander } from "./expander" import { Scanner } from "./scanner" import { Compiler } from "./compiler" -import { TextFile, SourceFile } from "./ast" +import { emit } from "./emitter" +import { TextFile, SourceFile, AnySourceFile } from "./ast" +import { upsearchSync, FastStringMap } from "./util" +import { Package } from "./package" + +const targetExtensions: FastStringMap = { + 'JS': '.mjs' +}; export class Program { - parser: Parser - evaluator: Evaluator; - checker: TypeChecker; - expander: Expander; + public parser: Parser + public evaluator: Evaluator; + public checker: TypeChecker; + public expander: Expander; - sourceFiles = new Map(); + private sourceFiles = new Map(); + private packages: FastStringMap = Object.create(null); - constructor(public files: TextFile[]) { + constructor(files: TextFile[]) { this.checker = new TypeChecker(); this.parser = new Parser(); this.evaluator = new Evaluator(this.checker); @@ -28,19 +36,42 @@ export class Program { for (const file of files) { const contents = fs.readFileSync(file.fullPath, 'utf8'); const scanner = new Scanner(file, contents) - this.sourceFiles.set(file, scanner.scan()); + this.sourceFiles.set(file.fullPath, scanner.scan()); } } - compile(file: TextFile) { - const original = this.sourceFiles.get(file); - if (original === undefined) { - throw new Error(`File ${file.path} does not seem to be part of this Program.`) + public getPackage(filepath: string) { + filepath = path.resolve(filepath); + const projectFile = upsearchSync('Boltfile', path.dirname(filepath)); + if (projectFile === null) { + return null; } - const expanded = this.expander.getFullyExpanded(original) as SourceFile; - const compiler = new Compiler(this.checker, { target: "JS" }) - const compiled = compiler.compile(expanded) - return compiled + const projectDir = path.resolve(path.dirname(projectFile)); + if (this.packages[projectDir] !== undefined) { + return this.packages[projectDir]; + } + return this.packages[projectDir] = new Package(projectDir); + } + + public compile(target: string) { + const compiler = new Compiler(this, this.checker, { target }) + const expanded: SourceFile[] = []; + for (const [filepath, sourceFile] of this.sourceFiles) { + expanded.push(this.expander.getFullyExpanded(sourceFile) as SourceFile); + } + const compiled = compiler.compile(expanded) as AnySourceFile[]; + for (const rootNode of compiled) { + const filepath = rootNode.span!.file.fullPath; + const pkg = this.getPackage(filepath); + if (pkg !== null) { + + } + fs.writeFileSync(this.mapToTargetFile(rootNode), emit(node), 'utf8'); + } + } + + private mapToTargetFile(node: AnySourceFile) { + getFileStem(node.span.file.fullPath) + '.' + getDefaultExtension(getTargetLanguage(node.kind)); } eval(file: TextFile) { @@ -54,3 +85,15 @@ export class Program { } +function getDefaultExtension(target: string) { + if (targetExtensions[target] === undefined) { + throw new Error(`Could not derive an appropriate extension for target "${target}".`) + } + return targetExtensions[target]; +} + +function getFileStem(filepath: string): string { + const chunks = path.basename(filepath).split('.') + return chunks[chunks.length-1]; +} + diff --git a/src/treegen/ast-template.js b/src/treegen/ast-template.js new file mode 100644 index 000000000..4b198f0f4 --- /dev/null +++ b/src/treegen/ast-template.js @@ -0,0 +1,75 @@ + +const exported = {}; + +const nodeProto = { + preorder() { + + } +} + +function createNode(nodeType) { + const obj = Object.create(nodeProto); + Object.defineProperty(obj, '__IS_NODE', { + enumerable: false, + writable: false, + configurable: true, + value: true, + }); + Object.defineProperty(obj, '__NODE_TYPE', { + enumerable: false, + writable: false, + configurable: true, + value: nodeType, + }); + Object.defineProperty(obj, 'kind', { + enumerable: false, + writable: false, + configurable: true, + getter() { + return this.__NODE_TYPE.index; + } + }); + obj.span = null; + obj.origNodes = null; + return obj; +} + +for (const nodeName of Object.keys(NODE_TYPES)) { + exported[`create${nodeName}`] = function (...args) { + const nodeType = NODE_TYPES[nodeName]; + const node = createNode(nodeType); + let i = 0; + const iter = nodeType.fields[Symbol.iterator](); + for (; i < args.length; i++) { + const { done, value } = iter.next(); + if (done) { + break; + } + const [fieldName, fieldType] = value; + node[fieldName] = args[i]; + } + while (true) { + const { done, value } = iter.next(); + if (done) { + break; + } + const [fieldName, fieldType] = value; + throw new Error(`No argument provided for field '${fieldName}'`); + } + if (i < args.length) { + node.span = args[i++]; + } + if (i < args.length) { + node.origNodes = i < args.length ? args[i++] : null; + } + if (i < args.length) { + throw new Error(`Too many arguments provided to function create${nodeName}`); + } + return node; + } +} + +if (typeof module !== 'undefined') { + module.exports = exports; +} + diff --git a/treegen/src/ast.ts b/src/treegen/ast.ts similarity index 56% rename from treegen/src/ast.ts rename to src/treegen/ast.ts index 910377539..a98239956 100644 --- a/treegen/src/ast.ts +++ b/src/treegen/ast.ts @@ -20,6 +20,7 @@ export interface NodeField { } export interface NodeDeclaration { + index?: number; type: 'NodeDeclaration'; name: string; parents: string[]; @@ -32,12 +33,14 @@ export interface EnumField { } export interface EnumDeclaration { + index?: number; type: 'EnumDeclaration'; name: string; fields: EnumField[]; } export interface TypeDeclaration { + index?: number; type: 'TypeDeclaration'; name: string; typeNode: TypeNode; @@ -48,3 +51,25 @@ export type Declaration | TypeDeclaration | EnumDeclaration +export type Syntax + = Declaration + | TypeNode + | NodeField + | EnumField + +export function hasArrayType(typeNode: TypeNode) { + if (typeNode.type === 'ReferenceTypeNode') { + return typeNode.name === 'Vec' + } else if (typeNode.type === 'UnionTypeNode') { + return typeNode.elements.some(hasArrayType); + } +} + +export function isTypeOptional(typeNode: TypeNode) { + if (typeNode.type === 'ReferenceTypeNode') { + return typeNode.name === 'Option'; + } else if (typeNode.type === 'UnionTypeNode') { + return typeNode.elements.every(isTypeOptional); + } +} + diff --git a/treegen/src/parser.d.ts b/src/treegen/parser.d.ts similarity index 72% rename from treegen/src/parser.d.ts rename to src/treegen/parser.d.ts index c0e5b014a..96cc7360e 100644 --- a/treegen/src/parser.d.ts +++ b/src/treegen/parser.d.ts @@ -1,4 +1,9 @@ -export function parse(input:string):any; + +export interface ParseOptions { + [key: string]: any; +} + +export function parse(input: string, opts?: ParseOptions): any; export interface Location { line: number; diff --git a/treegen/src/parser.pegjs b/src/treegen/parser.pegjs similarity index 100% rename from treegen/src/parser.pegjs rename to src/treegen/parser.pegjs diff --git a/treegen/src/index.ts b/src/treegen/util.ts similarity index 100% rename from treegen/src/index.ts rename to src/treegen/util.ts diff --git a/src/util.ts b/src/util.ts index 44df16c32..e500d6901 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,4 +1,7 @@ +import * as path from "path" +import * as fs from "fs" + export interface FastStringMap { [key: string]: T } @@ -33,3 +36,66 @@ export class StreamWrapper { } +export function upsearchSync(filename: string, startDir = '.') { + let currDir = startDir; + while (true) { + const filePath = path.join(currDir, filename); + if (fs.existsSync(filePath)) { + return filePath + } + const { root, dir } = path.parse(currDir); + if (dir === root) { + return null; + } + currDir = dir; + } +} + +function isWhiteSpace(ch: string) { + return /[\r\t ]/.test(ch); +} + +export interface FileWriterOptions { + indentStr?: string; + startIndent?: number; + indentWidth?: number; +} + +export class FileWriter { + + public currentText = ''; + + private atBlankLine = true; + private currentIndent: number; + private indentStr: string; + private indentWidth: number; + + constructor(opts: FileWriterOptions = {}) { + this.indentStr = opts.indentStr ?? ' '; + this.indentWidth = opts.indentWidth ?? 2; + this.currentIndent = (opts.startIndent ?? 0) * this.indentWidth; + } + + public indent(count = 1) { + this.currentIndent += this.indentWidth * count; + } + + public dedent(count = 1) { + this.currentIndent -= this.indentWidth * count; + } + + public write(str: string) { + for (const ch of str) { + if (ch === '\n') { + this.atBlankLine = true; + } else if (!(this.atBlankLine && isWhiteSpace(ch))) { + if (this.atBlankLine) { + this.currentText += this.indentStr.repeat(this.currentIndent) + } + this.atBlankLine = false; + } + this.currentText += ch; + } + } + +} diff --git a/treegen/package-lock.json b/treegen/package-lock.json deleted file mode 100644 index 20aa5db96..000000000 --- a/treegen/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "name": "treegen", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@types/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", - "dev": true - }, - "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" - }, - "pegjs": { - "version": "0.11.0-master.b7b87ea", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.11.0-master.b7b87ea.tgz", - "integrity": "sha512-fwjzNiYHRUEUe/86Aaslb/ocbbsAupOcsJz+dlPYtgp3feCDRQOLChHO924XGh7fzSJBTdFCQTzmSOQaWjCTew==", - "dev": true - } - } -} diff --git a/treegen/src/util.ts b/treegen/src/util.ts deleted file mode 100644 index 55ac4e2e2..000000000 --- a/treegen/src/util.ts +++ /dev/null @@ -1,49 +0,0 @@ - -function isWhiteSpace(ch: string) { - return /[\r\t ]/.test(ch); -} - -export interface FileWriterOptions { - indentStr?: string; - startIndent?: number; - indentWidth?: number; -} - -export class FileWriter { - - public currentText = ''; - - private atBlankLine = true; - private currentIndent: number; - private indentStr: string; - private indentWidth: number; - - constructor(opts: FileWriterOptions = {}) { - this.indentStr = opts.indentStr ?? ' '; - this.indentWidth = opts.indentWidth ?? 2; - this.currentIndent = (opts.startIndent ?? 0) * this.indentWidth; - } - - public indent(count = 1) { - this.currentIndent += this.indentWidth * count; - } - - public dedent(count = 1) { - this.currentIndent -= this.indentWidth * count; - } - - public write(str: string) { - for (const ch of str) { - if (ch === '\n') { - this.atBlankLine = true; - } else if (!(this.atBlankLine && isWhiteSpace(ch))) { - if (this.atBlankLine) { - this.currentText += this.indentStr.repeat(this.currentIndent) - } - this.atBlankLine = false; - } - this.currentText += ch; - } - } - -}