Undo creation of workspaces and merge treegen with main source
This commit is contained in:
parent
fee9139427
commit
f64da05a36
21 changed files with 654 additions and 1292 deletions
197
package-lock.json
generated
197
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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"
|
||||
|
|
148
src/ast.d.ts
vendored
Normal file
148
src/ast.d.ts
vendored
Normal file
|
@ -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);
|
973
src/ast.ts
973
src/ast.ts
|
@ -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<Json> { };
|
||||
interface JsonObject { [key: string]: Json }
|
||||
type Json = null | string | boolean | number | JsonArray | JsonObject;
|
||||
|
||||
export type TokenStream = Stream<Token>;
|
||||
|
||||
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<Syntax> {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
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<Identifier, TypeDecl>;
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
@ -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<T> { [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<Declaration> = 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<T>(arr: T[], els: T[]): void {
|
||||
|
@ -133,6 +189,10 @@ function pushAll<T>(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];
|
||||
}
|
|
@ -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");
|
||||
|
||||
})
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,43 @@ export class RecordWrapper extends RecordValue {
|
|||
|
||||
}
|
||||
|
||||
class Environment {
|
||||
|
||||
private symbols: FastStringMap<Value> = 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);
|
||||
|
|
|
@ -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')))
|
||||
])
|
||||
}]
|
||||
)
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
|
||||
import { TextFile } from "./ast"
|
||||
|
||||
export class Package {
|
||||
|
||||
constructor(
|
||||
public name: string | null,
|
||||
public files: TextFile[],
|
||||
) {
|
||||
constructor(public rootDir: string) {
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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<string> = {
|
||||
'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<TextFile, SourceFile>();
|
||||
private sourceFiles = new Map<string, SourceFile>();
|
||||
private packages: FastStringMap<Package> = 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];
|
||||
}
|
||||
|
||||
|
|
75
src/treegen/ast-template.js
Normal file
75
src/treegen/ast-template.js
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
66
src/util.ts
66
src/util.ts
|
@ -1,4 +1,7 @@
|
|||
|
||||
import * as path from "path"
|
||||
import * as fs from "fs"
|
||||
|
||||
export interface FastStringMap<T> {
|
||||
[key: string]: T
|
||||
}
|
||||
|
@ -33,3 +36,66 @@ export class StreamWrapper<T> {
|
|||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
25
treegen/package-lock.json
generated
25
treegen/package-lock.json
generated
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue