A templating language that looks like Lisp and compiles to HTML
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parser.js 2.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. const Error = require("./Error");
  2. const AST = require("./ast");
  3. const tokenTypes = require("./tokenTypes");
  4. module.exports = class Parser {
  5. constructor(tokenStream) {
  6. this.tokenStream = tokenStream;
  7. }
  8. parse() {
  9. let tree = [];
  10. while (this.tokenStream.peek().type !== tokenTypes.EOF) {
  11. tree.push(this.expr());
  12. if (this.tokenStream.error) {
  13. return {
  14. error: this.tokenStream.error
  15. };
  16. }
  17. }
  18. return tree;
  19. }
  20. expr() {
  21. let token = this.tokenStream.peek();
  22. switch (token.type) {
  23. case tokenTypes.ATTRIBUTE:
  24. return this.attribute();
  25. case tokenTypes.BOOLEAN:
  26. return this.bool();
  27. case tokenTypes.IDENTIFIER:
  28. return this.identifier();
  29. case tokenTypes.NUMBER:
  30. return this.number();
  31. case tokenTypes.QUOTE:
  32. return this.string();
  33. case tokenTypes.SYMBOL:
  34. return this.symbol();
  35. case tokenTypes.OPAREN:
  36. return this.form();
  37. default:
  38. this.tokenStream.error = `Unexpected ${token.type} on line ${
  39. token.line
  40. }`;
  41. break;
  42. }
  43. }
  44. form() {
  45. this.tokenStream.eat(tokenTypes.OPAREN);
  46. let node = new AST.Application();
  47. node.functionName = this.identifier();
  48. node.args = [];
  49. while (this.tokenStream.peek().type !== tokenTypes.CPAREN) {
  50. node.args.push(this.expr());
  51. }
  52. this.tokenStream.eat(tokenTypes.CPAREN);
  53. return node;
  54. }
  55. attribute() {
  56. return new AST.Attribute({
  57. name: this.tokenStream.eat(tokenTypes.ATTRIBUTE).value,
  58. value: this.expr()
  59. });
  60. }
  61. bool() {
  62. return new AST.Boolean({
  63. value: this.tokenStream.eat(tokenTypes.BOOLEAN).value
  64. });
  65. }
  66. identifier() {
  67. return new AST.Identifier({
  68. name: this.tokenStream.eat(tokenTypes.IDENTIFIER).value
  69. });
  70. }
  71. number() {
  72. return new AST.Number({
  73. value: this.tokenStream.eat(tokenTypes.NUMBER).value
  74. });
  75. }
  76. string() {
  77. this.tokenStream.eat(tokenTypes.QUOTE);
  78. let value = "";
  79. if (this.tokenStream.peek().type === tokenTypes.LITERAL) {
  80. value = this.tokenStream.eat(tokenTypes.LITERAL).value;
  81. }
  82. let node = new AST.String({
  83. value: value
  84. });
  85. this.tokenStream.eat(tokenTypes.QUOTE);
  86. return node;
  87. }
  88. symbol() {
  89. return new AST.Symbol({
  90. value: this.tokenStream.eat(tokenTypes.SYMBOL).value
  91. });
  92. }
  93. };