A "high-level" language for the Gameboy
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.

94 lines
2.7 KiB

  1. // AST factories
  2. {
  3. const attr = (name, args) => ({ name, args })
  4. const stmt = (stmt_type, args) => ({ type: "stmt", stmt_type, args })
  5. const decl = (decl_type, name, attrs, args) => ({ type: "decl", decl_type, name, attrs: attrs || [], args })
  6. const uexpr = (op, arg) => ({ type: "unary", op, arg })
  7. const bexpr = (op, left, right) => ({ type: "binary", op, left, right })
  8. const assocl = (head, tail) => tail.reduce((left, arg) => {
  9. const [op, right] = arg
  10. return bexpr(op, left, right)
  11. }, head)
  12. }
  13. Program = WS @(Decl / Stmt)* WS
  14. // Declarations
  15. Decl = VarDecl
  16. VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) }
  17. // Statements
  18. Stmt = @AssignStmt SEMI
  19. AssignStmt = name:Ident ASSIGN expr:Expr { return stmt("assign", { name, expr }) }
  20. // Expressions
  21. Expr = BitOrExpr
  22. BitOrExpr = head:BitXorExpr tail:(op:BitOrOp e:BitXorExpr)* { return assocl(head, tail || []) }
  23. BitOrOp = PIPE { return "bit_or" }
  24. BitXorExpr = head:BitAndExpr tail:(op:BitXorOp e:BitAndExpr)* { return assocl(head, tail || []) }
  25. BitXorOp = CARET { return "bit_xor" }
  26. BitAndExpr = head:ShiftExpr tail:(op:BitAndOp e:ShiftExpr)* { return assocl(head, tail || []) }
  27. BitAndOp = AMPERSAND { return "bit_and" }
  28. ShiftExpr = head:AddExpr op:ShiftOp n:Number { return bexpr(op, head, n) }
  29. / AddExpr
  30. ShiftOp = LTLT { return "shift_left" }
  31. / GTGT { return "shift_right" }
  32. AddExpr = head:UnaryExpr tail:(op:AddOp e:UnaryExpr)* { return assocl(head, tail || []) }
  33. AddOp = PLUS { return "add" }
  34. / MINUS { return "subtract" }
  35. UnaryExpr = op:UnaryOp? e:BaseExpr { return op ? uexpr(op, e) : e }
  36. UnaryOp = TILDE { return "bit_negate" }
  37. / MINUS { return "arith_negate" }
  38. BaseExpr = Ident / Number / LPAREN @Expr RPAREN
  39. // Attributes
  40. Attrs = LATTR @AttrList RATTR
  41. AttrList = h:Attr t:(COMMA @Attr)* { return [h].concat(t) }
  42. / '' { return [] }
  43. Attr = name:Ident args:(LPAREN @AttrArgs RPAREN)? { return attr(name, args || []) }
  44. AttrArgs = h:AttrArg t:(COMMA @AttrArg)* { return [h].concat(t) }
  45. / '' { return [] }
  46. AttrArg = Ident / Number
  47. // Types
  48. Type = PrimitiveType
  49. PrimitiveType = S8 / U8 / U16
  50. // Terminals
  51. Ident = h:[a-zA-Z_] t:[0-9a-zA-Z_]* WS { return h + t.join('') }
  52. Number = digits:[0-9]+ WS { return parseInt(digits.join(''), 10) }
  53. / '0x' digits:[a-fA-F0-9]+ WS { return parseInt(digits.join(''), 16) }
  54. / '0b' digits:[01]+ WS { return parseInt(digits.join(''), 2) }
  55. // Terminal keywords
  56. S8 = @'s8' WS
  57. U8 = @'u8' WS
  58. U16 = @'u16' WS
  59. // Terminal symbols
  60. PIPE = '|' WS
  61. CARET = '^' WS
  62. AMPERSAND = '&' WS
  63. LTLT = '<<' WS
  64. GTGT = '>>' WS
  65. PLUS = '+' WS
  66. TILDE = '~' WS
  67. MINUS = '-' WS
  68. SEMI = ';' WS
  69. ASSIGN = '<-' WS
  70. LPAREN = '(' WS
  71. RPAREN = ')' WS
  72. COMMA = ',' WS
  73. LATTR = '[[' WS
  74. RATTR = ']]' WS
  75. // Misc
  76. WS = [ \t\r\n]*