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,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime-corejs3": {
|
"@babel/runtime-corejs3": {
|
||||||
"version": "7.8.4",
|
"version": "7.9.6",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.9.6.tgz",
|
||||||
"integrity": "sha512-+wpLqy5+fbQhvbllvlJEVRIpYj+COUWnnsm+I4jZlA8Lo7/MJmBhGTCHyk1/RWfOqBRJ2MbadddG6QltTKTlrg==",
|
"integrity": "sha512-6toWAfaALQjt3KMZQc6fABqZwUDDuWzz+cAfPhqyEnzxvdWOAkjwPNxgF8xlmo7OWLsSjaKjsskpKHRLaMArOA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"core-js-pure": "^3.0.0",
|
"core-js-pure": "^3.0.0",
|
||||||
"regenerator-runtime": "^0.13.2"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/chai": {
|
"@types/chai": {
|
||||||
|
@ -73,10 +73,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "3.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
|
@ -112,11 +111,6 @@
|
||||||
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
|
||||||
"dev": true
|
"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": {
|
"at-least-node": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||||
|
@ -233,36 +227,6 @@
|
||||||
"string-width": "^4.2.0",
|
"string-width": "^4.2.0",
|
||||||
"strip-ansi": "^6.0.0",
|
"strip-ansi": "^6.0.0",
|
||||||
"wrap-ansi": "^6.2.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": {
|
"color-convert": {
|
||||||
|
@ -286,9 +250,9 @@
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
},
|
},
|
||||||
"core-js-pure": {
|
"core-js-pure": {
|
||||||
"version": "3.6.4",
|
"version": "3.6.5",
|
||||||
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.4.tgz",
|
"resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.6.5.tgz",
|
||||||
"integrity": "sha512-epIhRLkXdgv32xIUFaaAry2wdxZYBi6bgM7cB136dzzXXa+dFyRLTZeLUJxnd8ShrmyVXBub63n2NHo2JAt8Cw=="
|
"integrity": "sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA=="
|
||||||
},
|
},
|
||||||
"debug": {
|
"debug": {
|
||||||
"version": "3.2.6",
|
"version": "3.2.6",
|
||||||
|
@ -750,6 +714,15 @@
|
||||||
"ansi-regex": "^4.1.0"
|
"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": {
|
"wrap-ansi": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
|
||||||
|
@ -885,9 +858,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pegjs": {
|
"pegjs": {
|
||||||
"version": "0.11.0-master.b7b87ea",
|
"version": "0.11.0-master.f69239d",
|
||||||
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.11.0-master.b7b87ea.tgz",
|
"resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.11.0-master.f69239d.tgz",
|
||||||
"integrity": "sha512-fwjzNiYHRUEUe/86Aaslb/ocbbsAupOcsJz+dlPYtgp3feCDRQOLChHO924XGh7fzSJBTdFCQTzmSOQaWjCTew=="
|
"integrity": "sha512-8PXSaXnLh9hw0R/SfOL1b8JSgiPv1KSl8B1h+sP0uwngmx3Vk+QdB2cuBAT1lXPbP5necVZ2Dl2t4DfR3KKbZg=="
|
||||||
},
|
},
|
||||||
"picomatch": {
|
"picomatch": {
|
||||||
"version": "2.2.2",
|
"version": "2.2.2",
|
||||||
|
@ -910,9 +883,9 @@
|
||||||
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
|
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg=="
|
||||||
},
|
},
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.13.3",
|
"version": "0.13.5",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
|
||||||
"integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw=="
|
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
|
||||||
},
|
},
|
||||||
"require-directory": {
|
"require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
|
@ -956,13 +929,20 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "2.1.1",
|
"version": "4.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||||
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-fullwidth-code-point": "^2.0.0",
|
"emoji-regex": "^8.0.0",
|
||||||
"strip-ansi": "^4.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": {
|
"string.prototype.trimend": {
|
||||||
|
@ -1008,12 +988,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "4.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-regex": "^3.0.0"
|
"ansi-regex": "^5.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"strip-json-comments": {
|
"strip-json-comments": {
|
||||||
|
@ -1022,15 +1001,6 @@
|
||||||
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
|
||||||
"dev": true
|
"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": {
|
"to-regex-range": {
|
||||||
"version": "5.0.1",
|
"version": "5.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||||
|
@ -1072,6 +1042,33 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"string-width": "^1.0.2 || 2"
|
"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": {
|
"wrap-ansi": {
|
||||||
|
@ -1084,11 +1081,6 @@
|
||||||
"strip-ansi": "^6.0.0"
|
"strip-ansi": "^6.0.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"ansi-styles": {
|
||||||
"version": "4.2.1",
|
"version": "4.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
||||||
|
@ -1110,29 +1102,6 @@
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
"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"
|
"yargs-parser": "^18.1.1"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"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": {
|
"find-up": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
|
||||||
|
@ -1186,11 +1150,6 @@
|
||||||
"path-exists": "^4.0.0"
|
"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": {
|
"locate-path": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||||
"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
|
"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": {
|
"yargs-parser": {
|
||||||
"version": "18.1.3",
|
"version": "18.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz",
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
"description": "A programming language for rapid prototyping",
|
"description": "A programming language for rapid prototyping",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
"bolt": "lib/bin/bolt.js"
|
"bolt": "lib/bin/bolt.js",
|
||||||
|
"bolt-treegen": "lib/bin/bolt-treegen.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "mocha lib/test"
|
"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 path from "path"
|
||||||
import * as fs from "fs"
|
import * as fs from "fs"
|
||||||
|
|
||||||
import { parse, SyntaxError } from "../parser"
|
import { parse, SyntaxError } from "../treegen/parser"
|
||||||
import { Declaration, NodeDeclaration, TypeDeclaration, EnumDeclaration, TypeNode, NodeField } from "../ast"
|
import { Syntax, Declaration, NodeDeclaration, TypeDeclaration, EnumDeclaration, TypeNode, NodeField } from "../ast"
|
||||||
import { FileWriter } from "../util"
|
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');
|
const contents = fs.readFileSync(filename, 'utf8');
|
||||||
let decls: Declaration[];
|
let decls: Declaration[];
|
||||||
try {
|
try {
|
||||||
decls = parse(contents);
|
decls = parse(contents, { prefix: getFileStem(filename) });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof SyntaxError) {
|
if (e instanceof SyntaxError) {
|
||||||
console.error(`${filename}:${e.location.start.line}:${e.location.start.column}: ${e.message}`);
|
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;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const generated = generateAST(decls, getFileStem(filename));
|
const { jsFile, dtsFile } = generateAST(decls);
|
||||||
fs.writeFileSync('src/ast-generated.js', generated, 'utf8');
|
fs.writeFileSync(jsFilePath, jsFile, 'utf8');
|
||||||
|
fs.writeFileSync(dtsFilePath, dtsFile, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FastStringMap<T> { [key: string]: T }
|
interface FastStringMap<T> { [key: string]: T }
|
||||||
|
|
||||||
function generateAST(decls: Declaration[], langName: string) {
|
function generateAST(decls: Declaration[]) {
|
||||||
|
|
||||||
let jsFile = new FileWriter();
|
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 nodeDecls: NodeDeclaration[] = decls.filter(decl => decl.type === 'NodeDeclaration') as NodeDeclaration[];
|
||||||
const typeDecls: TypeDeclaration[] = decls.filter(decl => decl.type === 'TypeDeclaration') as TypeDeclaration[];
|
const typeDecls: TypeDeclaration[] = decls.filter(decl => decl.type === 'TypeDeclaration') as TypeDeclaration[];
|
||||||
const enumDecls: EnumDeclaration[] = decls.filter(decl => decl.type === 'EnumDeclaration') as EnumDeclaration[];
|
const enumDecls: EnumDeclaration[] = decls.filter(decl => decl.type === 'EnumDeclaration') as EnumDeclaration[];
|
||||||
|
|
||||||
const declByName: FastStringMap<Declaration> = Object.create(null);
|
const declByName: FastStringMap<Declaration> = Object.create(null);
|
||||||
|
i = 0;
|
||||||
for (const decl of decls) {
|
for (const decl of decls) {
|
||||||
|
decl.index = i++;
|
||||||
declByName[decl.name] = decl;
|
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.
|
// Write a JavaScript file that contains all AST definitions.
|
||||||
|
|
||||||
jsFile.write(`\nconst NODE_TYPES = [\n`);
|
jsFile.write(`\nconst NODE_TYPES = {\n`);
|
||||||
jsFile.indent();
|
jsFile.indent();
|
||||||
for (const decl of decls) {
|
for (const decl of leafNodes) {
|
||||||
if (decl.type === 'NodeDeclaration' && isLeafNode(decl.name)) {
|
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();
|
jsFile.indent();
|
||||||
for (const field of getAllFields(decl)) {
|
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.dedent();
|
||||||
jsFile.write(']),\n');
|
jsFile.write(']),\n');
|
||||||
|
jsFile.dedent();
|
||||||
|
jsFile.write('},\n');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsFile.dedent();
|
jsFile.dedent();
|
||||||
jsFile.write('];\n\n');
|
jsFile.write('};\n\n');
|
||||||
|
|
||||||
function emitTypeNode(typeNode: TypeNode): string {
|
jsFile.write(fs.readFileSync(path.join(PACKAGE_ROOT, 'src', 'treegen', 'ast-template.js'), 'utf8'));
|
||||||
console.error(typeNode);
|
|
||||||
if (typeNode.type === 'ReferenceTypeNode') {
|
jsFile.write(`if (typeof module !== 'undefined') {\n module.exports = exported;\n}\n\n`)
|
||||||
if (hasDeclarationNamed(typeNode.name)) {
|
|
||||||
return typeNode.name;
|
// Write corresponding TypeScript declarations
|
||||||
} else if (typeNode.name === 'Bool') {
|
|
||||||
return 'boolean';
|
dtsFile.write(`\nexport const enum SyntaxKind {\n`);
|
||||||
} else if (typeNode.name === 'String') {
|
for (const decl of leafNodes) {
|
||||||
return 'string';
|
dtsFile.write(` ${decl.name} = ${decl.index}\n`);
|
||||||
} 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}.`);
|
|
||||||
}
|
}
|
||||||
|
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 {
|
function hasDeclarationNamed(name: string): boolean {
|
||||||
return name in declByName;
|
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) {
|
function getAllFields(nodeDecl: NodeDeclaration) {
|
||||||
let out: NodeField[] = [];
|
let out: NodeField[] = [];
|
||||||
pushAll(out, nodeDecl.fields);
|
pushAll(out, nodeDecl.fields);
|
||||||
|
@ -123,8 +181,6 @@ function generateAST(decls: Declaration[], langName: string) {
|
||||||
return childrenOf[name] === undefined || childrenOf[name].length === 0;
|
return childrenOf[name] === undefined || childrenOf[name].length === 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return jsFile.currentText;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function pushAll<T>(arr: T[], els: T[]): void {
|
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 jsonify(value: any) {
|
||||||
|
|
||||||
function visitNode(node: any) {
|
function visitNode(node: any) {
|
||||||
|
@ -140,7 +200,7 @@ function jsonify(value: any) {
|
||||||
const obj: any = {};
|
const obj: any = {};
|
||||||
|
|
||||||
for (const key of Object.keys(node)) {
|
for (const key of Object.keys(node)) {
|
||||||
if (key !== 'type' && key !== 'span') {
|
if (key !== 'type' && key !== 'span' && key !== '__IS_NODE') {
|
||||||
const value = node[key];
|
const value = node[key];
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
obj[key] = value.map(visit);
|
obj[key] = value.map(visit);
|
||||||
|
@ -154,7 +214,7 @@ function jsonify(value: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function visit(value: any) {
|
function visit(value: any) {
|
||||||
if (value.__IS_NODE) {
|
if (isNode(value)) {
|
||||||
return visitNode(value);
|
return visitNode(value);
|
||||||
} else {
|
} else {
|
||||||
return value;
|
return value;
|
||||||
|
@ -164,6 +224,13 @@ function jsonify(value: any) {
|
||||||
return visit(value);
|
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) {
|
function getFileStem(filepath: string) {
|
||||||
return path.basename(filepath).split('.')[0];
|
return path.basename(filepath).split('.')[0];
|
||||||
}
|
}
|
|
@ -5,11 +5,9 @@ import "source-map-support/register"
|
||||||
|
|
||||||
import * as path from "path"
|
import * as path from "path"
|
||||||
import * as fs from "fs-extra"
|
import * as fs from "fs-extra"
|
||||||
import { spawnSync } from "child_process"
|
|
||||||
|
|
||||||
import yargs from "yargs"
|
import yargs from "yargs"
|
||||||
|
|
||||||
import { Package, loadPackage } from "../package"
|
|
||||||
import { Program } from "../program"
|
import { Program } from "../program"
|
||||||
import { TextFile } from "../ast"
|
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 files = toArray(args.path as string[] | string).map(filepath => new TextFile(filepath, args['work-dir']));
|
||||||
const program = new Program(files)
|
const program = new Program(files)
|
||||||
program.compile({ target: "JS" });
|
program.compile("JS");
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
Syntax,
|
Syntax,
|
||||||
SyntaxKind,
|
SyntaxKind,
|
||||||
ImportDecl,
|
ImportDecl,
|
||||||
isNode,
|
Patt,
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
import { FastStringMap } from "./util"
|
import { FastStringMap } from "./util"
|
||||||
|
@ -130,6 +130,9 @@ export class TypeChecker {
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
||||||
|
case SyntaxKind.RefExpr:
|
||||||
|
return anyType;
|
||||||
|
|
||||||
case SyntaxKind.ConstExpr:
|
case SyntaxKind.ConstExpr:
|
||||||
return node.value.type;
|
return node.value.type;
|
||||||
|
|
||||||
|
@ -222,6 +225,10 @@ export class TypeChecker {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SyntaxKind.RefExpr:
|
||||||
|
// TODO implement this
|
||||||
|
break;
|
||||||
|
|
||||||
case SyntaxKind.Module:
|
case SyntaxKind.Module:
|
||||||
case SyntaxKind.SourceFile:
|
case SyntaxKind.SourceFile:
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
|
|
|
@ -16,6 +16,8 @@ import {
|
||||||
isExpr,
|
isExpr,
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
|
import { Program } from "./program"
|
||||||
|
|
||||||
export interface CompilerOptions {
|
export interface CompilerOptions {
|
||||||
target: string;
|
target: string;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +32,7 @@ export class Compiler {
|
||||||
|
|
||||||
readonly target: string;
|
readonly target: string;
|
||||||
|
|
||||||
constructor(public checker: TypeChecker, options: CompilerOptions) {
|
constructor(public program: Program, public checker: TypeChecker, options: CompilerOptions) {
|
||||||
this.target = options.target
|
this.target = options.target
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,14 +46,14 @@ export class Compiler {
|
||||||
type: 'Program',
|
type: 'Program',
|
||||||
body,
|
body,
|
||||||
loc: {
|
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) {
|
switch (node.kind) {
|
||||||
|
|
||||||
case SyntaxKind.CallExpr:
|
case SyntaxKind.CallExpr:
|
||||||
|
|
|
@ -1,16 +1,10 @@
|
||||||
|
|
||||||
import * as astring from "astring"
|
|
||||||
|
|
||||||
import { Syntax, SyntaxKind, isJSNode } from "./ast"
|
import { Syntax, SyntaxKind, isJSNode } from "./ast"
|
||||||
|
|
||||||
export class Emitter {
|
export class Emitter {
|
||||||
|
|
||||||
emit(node: Syntax) {
|
emit(node: Syntax) {
|
||||||
|
|
||||||
if (isJSNode(node)) {
|
|
||||||
return astring.generate(node)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (node.kind) {
|
switch (node.kind) {
|
||||||
|
|
||||||
case SyntaxKind.SourceFile:
|
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 {
|
export class Evaluator {
|
||||||
|
|
||||||
constructor(public checker: TypeChecker) {
|
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) {
|
switch (node.kind) {
|
||||||
|
|
||||||
case SyntaxKind.SourceFile:
|
case SyntaxKind.SourceFile:
|
||||||
case SyntaxKind.Module:
|
case SyntaxKind.Module:
|
||||||
for (const element of node.elements) {
|
for (const element of node.elements) {
|
||||||
this.eval(element);
|
this.eval(element, env);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case SyntaxKind.RefExpr:
|
||||||
|
return env.lookup(node.name.fullText);
|
||||||
|
|
||||||
case SyntaxKind.NewTypeDecl:
|
case SyntaxKind.NewTypeDecl:
|
||||||
case SyntaxKind.RecordDecl:
|
case SyntaxKind.RecordDecl:
|
||||||
case SyntaxKind.FuncDecl:
|
case SyntaxKind.FuncDecl:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SyntaxKind.MatchExpr:
|
case SyntaxKind.MatchExpr:
|
||||||
const value = this.eval(node.value);
|
const value = this.eval(node.value, env);
|
||||||
for (const [pattern, result] of node.arms) {
|
for (const [pattern, result] of node.arms) {
|
||||||
if (this.match(value, pattern)) {
|
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);
|
return new PrimValue(this.checker.getTypeNamed('Void')!, null);
|
||||||
|
|
|
@ -2,38 +2,32 @@
|
||||||
// FIXME Actually, the syntax expander could make use of algebraic effects to
|
// FIXME Actually, the syntax expander could make use of algebraic effects to
|
||||||
// easily specify how the next expansion should happen. Just a thought.
|
// easily specify how the next expansion should happen. Just a thought.
|
||||||
|
|
||||||
import {
|
import {
|
||||||
TokenStream,
|
BoltSyntax,
|
||||||
SyntaxKind,
|
createBoltRecordPattern,
|
||||||
Syntax,
|
createBoltIdentifier,
|
||||||
SourceFile,
|
createBoltReferenceTypeNode,
|
||||||
Decl,
|
createBoltConstantExpression,
|
||||||
RecordPatt,
|
createBoltTuplePattern,
|
||||||
Identifier,
|
createBoltQualName,
|
||||||
TypeRef,
|
createBoltTypePattern,
|
||||||
Patt,
|
createBoltBindPattern,
|
||||||
ConstExpr,
|
BoltPattern,
|
||||||
QualName,
|
|
||||||
TuplePatt,
|
|
||||||
BindPatt,
|
|
||||||
TypePatt,
|
|
||||||
MatchExpr,
|
|
||||||
Stmt,
|
|
||||||
Module,
|
|
||||||
} from "./ast"
|
} from "./ast"
|
||||||
|
|
||||||
|
import { BoltTokenStream } from "./util"
|
||||||
import { TypeChecker } from "./checker"
|
import { TypeChecker } from "./checker"
|
||||||
import { Parser, ParseError } from "./parser"
|
import { Parser, ParseError } from "./parser"
|
||||||
import { Evaluator, TRUE, FALSE } from "./evaluator"
|
import { Evaluator, TRUE, FALSE } from "./evaluator"
|
||||||
|
|
||||||
interface Transformer {
|
interface Transformer {
|
||||||
pattern: Patt;
|
pattern: BoltPattern;
|
||||||
transform: (node: TokenStream) => Syntax;
|
transform: (node: BoltTokenStream) => BoltSyntax;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createTypeRef(text: string) {
|
function createSimpleBoltReferenceTypeNode(text: string) {
|
||||||
const ids = text.split('.').map(name => new Identifier(name))
|
const ids = text.split('.').map(name => createBoltIdentifier(name))
|
||||||
return new TypeRef(new QualName(ids[ids.length-1], ids.slice(0, -1)), [])
|
return createBoltReferenceTypeNode(createBoltQualName(ids[ids.length-1], ids.slice(0, -1)), [])
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is actually a hand-parsed version of the following:
|
/// This is actually a hand-parsed version of the following:
|
||||||
|
@ -50,27 +44,27 @@ function createTypeRef(text: string) {
|
||||||
/// }
|
/// }
|
||||||
/// ],
|
/// ],
|
||||||
/// }
|
/// }
|
||||||
const PATTERN_SYNTAX: Patt =
|
const PATTERN_SYNTAX: Pattern =
|
||||||
new RecordPatt(
|
createBoltRecordPattern(
|
||||||
createTypeRef('Bolt.AST.Sentence'),
|
createSimpleBoltReferenceTypeNode('Bolt.AST.Sentence'),
|
||||||
[{
|
[{
|
||||||
name: new Identifier('elements'),
|
name: createBoltIdentifier('elements'),
|
||||||
pattern: new TuplePatt([
|
pattern: createBoltTuplePattern([
|
||||||
new RecordPatt(
|
createBoltRecordPattern(
|
||||||
createTypeRef('Bolt.AST.Identifier'),
|
createSimpleBoltReferenceTypeNode('Bolt.AST.Identifier'),
|
||||||
[{
|
[{
|
||||||
name: new Identifier('text'),
|
name: createBoltIdentifier('text'),
|
||||||
pattern: new ConstExpr('syntax')
|
pattern: createBoltConstantExpression('syntax')
|
||||||
}]
|
}]
|
||||||
),
|
),
|
||||||
new RecordPatt(
|
createBoltRecordPattern(
|
||||||
createTypeRef('Bolt.AST.Braced'),
|
createSimpleBoltReferenceTypeNode('Bolt.AST.Braced'),
|
||||||
[{
|
[{
|
||||||
name: new Identifier('elements'),
|
name: createBoltIdentifier('elements'),
|
||||||
pattern: new TuplePatt([
|
pattern: createBoltTuplePattern([
|
||||||
new TypePatt(createTypeRef('Bolt.AST.Pattern'), new BindPatt(new Identifier('pattern'))),
|
createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.Pattern'), createBoltBindPattern(createBoltIdentifier('pattern'))),
|
||||||
new TypePatt(createTypeRef('Bolt.AST.RArrow'), new BindPatt(new Identifier('_'))),
|
createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.RArrow'), createBoltBindPattern(createBoltIdentifier('_'))),
|
||||||
new TypePatt(createTypeRef('Bolt.AST.Expr'), new BindPatt(new Identifier('expression')))
|
createBoltTypePattern(createSimpleBoltReferenceTypeNode('Bolt.AST.Expr'), createBoltBindPattern(createBoltIdentifier('expression')))
|
||||||
])
|
])
|
||||||
}]
|
}]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
|
|
||||||
import { TextFile } from "./ast"
|
|
||||||
|
|
||||||
export class Package {
|
export class Package {
|
||||||
|
|
||||||
constructor(
|
constructor(public rootDir: string) {
|
||||||
public name: string | null,
|
|
||||||
public files: TextFile[],
|
|
||||||
) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,26 +1,34 @@
|
||||||
|
|
||||||
import * as path from "path"
|
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 { Parser } from "./parser"
|
||||||
import { TypeChecker } from "./checker"
|
import { TypeChecker } from "./checker"
|
||||||
import { Evaluator } from "./evaluator"
|
import { Evaluator } from "./evaluator"
|
||||||
import { Expander } from "./expander"
|
import { Expander } from "./expander"
|
||||||
import { Scanner } from "./scanner"
|
import { Scanner } from "./scanner"
|
||||||
import { Compiler } from "./compiler"
|
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 {
|
export class Program {
|
||||||
|
|
||||||
parser: Parser
|
public parser: Parser
|
||||||
evaluator: Evaluator;
|
public evaluator: Evaluator;
|
||||||
checker: TypeChecker;
|
public checker: TypeChecker;
|
||||||
expander: Expander;
|
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.checker = new TypeChecker();
|
||||||
this.parser = new Parser();
|
this.parser = new Parser();
|
||||||
this.evaluator = new Evaluator(this.checker);
|
this.evaluator = new Evaluator(this.checker);
|
||||||
|
@ -28,19 +36,42 @@ export class Program {
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
const contents = fs.readFileSync(file.fullPath, 'utf8');
|
const contents = fs.readFileSync(file.fullPath, 'utf8');
|
||||||
const scanner = new Scanner(file, contents)
|
const scanner = new Scanner(file, contents)
|
||||||
this.sourceFiles.set(file, scanner.scan());
|
this.sourceFiles.set(file.fullPath, scanner.scan());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(file: TextFile) {
|
public getPackage(filepath: string) {
|
||||||
const original = this.sourceFiles.get(file);
|
filepath = path.resolve(filepath);
|
||||||
if (original === undefined) {
|
const projectFile = upsearchSync('Boltfile', path.dirname(filepath));
|
||||||
throw new Error(`File ${file.path} does not seem to be part of this Program.`)
|
if (projectFile === null) {
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
const expanded = this.expander.getFullyExpanded(original) as SourceFile;
|
const projectDir = path.resolve(path.dirname(projectFile));
|
||||||
const compiler = new Compiler(this.checker, { target: "JS" })
|
if (this.packages[projectDir] !== undefined) {
|
||||||
const compiled = compiler.compile(expanded)
|
return this.packages[projectDir];
|
||||||
return compiled
|
}
|
||||||
|
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) {
|
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 {
|
export interface NodeDeclaration {
|
||||||
|
index?: number;
|
||||||
type: 'NodeDeclaration';
|
type: 'NodeDeclaration';
|
||||||
name: string;
|
name: string;
|
||||||
parents: string[];
|
parents: string[];
|
||||||
|
@ -32,12 +33,14 @@ export interface EnumField {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnumDeclaration {
|
export interface EnumDeclaration {
|
||||||
|
index?: number;
|
||||||
type: 'EnumDeclaration';
|
type: 'EnumDeclaration';
|
||||||
name: string;
|
name: string;
|
||||||
fields: EnumField[];
|
fields: EnumField[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TypeDeclaration {
|
export interface TypeDeclaration {
|
||||||
|
index?: number;
|
||||||
type: 'TypeDeclaration';
|
type: 'TypeDeclaration';
|
||||||
name: string;
|
name: string;
|
||||||
typeNode: TypeNode;
|
typeNode: TypeNode;
|
||||||
|
@ -48,3 +51,25 @@ export type Declaration
|
||||||
| TypeDeclaration
|
| TypeDeclaration
|
||||||
| EnumDeclaration
|
| 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 {
|
export interface Location {
|
||||||
line: number;
|
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> {
|
export interface FastStringMap<T> {
|
||||||
[key: string]: 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