|
// AST factories
|
|
{
|
|
const attr = (name, args) => ({ name, args })
|
|
const stmt = (stmt_type, args) => ({ type: "stmt", stmt_type, args })
|
|
const decl = (decl_type, name, attrs, args) => ({ type: "decl", decl_type, name, attrs: attrs || [], args })
|
|
const uexpr = (op, arg) => ({ type: "unary", op, arg })
|
|
const bexpr = (op, left, right) => ({ type: "binary", op, left, right })
|
|
|
|
const assocl = (head, tail) => tail.reduce((left, arg) => {
|
|
const [op, right] = arg
|
|
return bexpr(op, left, right)
|
|
}, head)
|
|
}
|
|
|
|
Program = WS @(Decl / Stmt)* WS
|
|
|
|
// Declarations
|
|
Decl = VarDecl
|
|
VarDecl = attrs:Attrs? type:Type name:Ident SEMI { return decl("var", name, attrs, { type }) }
|
|
|
|
// Statements
|
|
Stmt = @AssignStmt SEMI
|
|
AssignStmt = name:Ident ASSIGN expr:Expr { return stmt("assign", { name, expr }) }
|
|
|
|
// Expressions
|
|
Expr = BitOrExpr
|
|
|
|
BitOrExpr = head:BitXorExpr tail:(op:BitOrOp e:BitXorExpr)* { return assocl(head, tail || []) }
|
|
BitOrOp = PIPE { return "bit_or" }
|
|
|
|
BitXorExpr = head:BitAndExpr tail:(op:BitXorOp e:BitAndExpr)* { return assocl(head, tail || []) }
|
|
BitXorOp = CARET { return "bit_xor" }
|
|
|
|
BitAndExpr = head:ShiftExpr tail:(op:BitAndOp e:ShiftExpr)* { return assocl(head, tail || []) }
|
|
BitAndOp = AMPERSAND { return "bit_and" }
|
|
|
|
ShiftExpr = head:AddExpr tail:(op:ShiftOp e:AddExpr)* { return assocl(head, tail || []) }
|
|
ShiftOp = LTLT { return "shift_left" }
|
|
/ GTGT { return "shift_right" }
|
|
|
|
AddExpr = head:UnaryExpr tail:(op:AddOp e:UnaryExpr)* { return assocl(head, tail || []) }
|
|
AddOp = PLUS { return "add" }
|
|
/ MINUS { return "subtract" }
|
|
|
|
UnaryExpr = op:UnaryOp? e:BaseExpr { return op ? uexpr(op, e) : e }
|
|
UnaryOp = TILDE { return "bit_negate" }
|
|
/ MINUS { return "arith_negate" }
|
|
|
|
BaseExpr = Ident / Number / LPAREN @Expr RPAREN
|
|
|
|
// Attributes
|
|
Attrs = LATTR @AttrList RATTR
|
|
AttrList = h:Attr t:(COMMA @Attr)* { return [h].concat(t) }
|
|
/ '' { return [] }
|
|
Attr = name:Ident args:(LPAREN @AttrArgs RPAREN)? { return attr(name, args || []) }
|
|
AttrArgs = h:AttrArg t:(COMMA @AttrArg)* { return [h].concat(t) }
|
|
/ '' { return [] }
|
|
AttrArg = Ident / Number
|
|
|
|
// Types
|
|
Type = PrimitiveType
|
|
PrimitiveType = S8 / U8 / U16
|
|
|
|
// Terminals
|
|
Ident = h:[a-zA-Z_] t:[0-9a-zA-Z_]* WS { return h + t.join('') }
|
|
Number = digits:[0-9]+ WS { return parseInt(digits.join(''), 10) }
|
|
/ '0x' digits:[a-fA-F0-9]+ WS { return parseInt(digits.join(''), 16) }
|
|
/ '0b' digits:[01]+ WS { return parseInt(digits.join(''), 2) }
|
|
|
|
// Terminal keywords
|
|
S8 = @'s8' WS
|
|
U8 = @'u8' WS
|
|
U16 = @'u16' WS
|
|
|
|
// Terminal symbols
|
|
PIPE = '|' WS
|
|
CARET = '^' WS
|
|
AMPERSAND = '&' WS
|
|
LTLT = '<<' WS
|
|
GTGT = '>>' WS
|
|
PLUS = '+' WS
|
|
TILDE = '~' WS
|
|
MINUS = '-' WS
|
|
SEMI = ';' WS
|
|
ASSIGN = '<-' WS
|
|
LPAREN = '(' WS
|
|
RPAREN = ')' WS
|
|
COMMA = ',' WS
|
|
LATTR = '[[' WS
|
|
RATTR = ']]' WS
|
|
|
|
// Misc
|
|
WS = [ \t\r\n]*
|