Program = exprs:(ContinuationExpression / _)* { return exprs.filter(x => !Array.isArray(x)); } ContinuationExpression = RecordExpression / SelectExpression / OffsetExpression / ApplicationExpression / FixExpression / SwitchExpression / PrimitiveOperationExpression SelectExpression = SELECT _? LPAREN _? select:Integer _? COMMA _? val:Value _? COMMA _? bind:Identifier _? continuation:ContinuationExpression _? RPAREN { return { select, val, bind, continuation }; } OffsetExpression = OFFSET _? LPAREN _? offset:Integer _? COMMA _? val:Value _? COMMA _? bind:Identifier _? continuation:ContinuationExpression _? RPAREN { return { offset, val, bind, continuation }; } IdentifierList = LBRACKET _? identifiers:(ident:Identifier _? COMMA _?)* _? lastIdent:Identifier? _? RBRACKET { return identifiers.length || lastIdent ? [...identifiers.map(x => x.ident), lastIdent] : []; } ValueList = LBRACKET _? values:(value:Value _? COMMA _?)* _? lastValue:Value? _? RBRACKET { return values.length || lastValue ? [...values.map(x => x.value), lastValue] : []; } SwitchExpression = SWITCH _? LPAREN _? switchIndex:Value _? COMMA _? continuations:ContinuationList _? RPAREN { return { switchIndex, continuations }; } ApplicationExpression = APP _? LPAREN _? fn:Value _? COMMA _? args:ValueList _? RPAREN { return { fn, args }; } FixBinding = LPAREN _? fn:Identifier _? COMMA _? args:IdentifierList _? COMMA _? continuation:ContinuationExpression _? RPAREN FixBindingList = LBRACKET _ bindings:(binding:FixBinding _? COMMA _?)* _? lastBinding:FixBinding? _? RBRACKET { return bindings.length || lastBinding ? [...bindings.map(x => x.binding), lastBinding] : []; } FixExpression = FIX _? LPAREN _? fixBindings:FixBindingList _? COMMA _? continuation:ContinuationExpression _? RPAREN { return { fixBindings, continuation }; } ContinuationList = LBRACKET _? continuations:(continuation:ContinuationExpression _? COMMA _?)* _? lastContinuation:ContinuationExpression? _? RBRACKET { return lastContinuation || continuations.length ? [...continuations.map(x => x.continuation), lastContinuation] : []; } PrimitiveOperationExpression = PRIMOP _? LPAREN _? opr:PrimitiveOperation _? COMMA _? operands:ValueList _? COMMA _? resultBindings:IdentifierList _? COMMA _? continuations:ContinuationList _? RPAREN { return { opr, operands, resultBindings, continuations }; } RecordExpressionTuple = LPAREN _? variable:VarStatement _? COMMA _? offset:OffsetStatement _? RPAREN { return { variable, offset }; } RecordExpressionTupleList = LBRACKET _? records:(record:RecordExpressionTuple _? COMMA _?)* _? lastRecord:RecordExpressionTuple? _? RBRACKET { return records.length || lastRecord ? [...records.map(x => x.record), lastRecord] : []; } RecordExpression = RECORD _? LPAREN _? records:RecordExpressionTupleList _? COMMA _? address:Literal _? COMMA _? body:ContinuationExpression _? RPAREN { return { records, address, body, }; } Value = VarStatement / LabelStatement / IntStatement / RealStatement / StringStatement VarStatement = VAR _ ident:Identifier { return ident; } LabelStatement = LABEL _ ident:Identifier { return ident; } IntStatement = INT _ int:Integer { return int; } RealStatement = REAL _ real:Real { return real; } StringStatement = STRING _ string:QuotedString { return string; } AccessStatement = OffsetStatement / SelectStatement OffsetStatement = OFFP _ offset:Integer { return offset; } SelectStatement = SELP _ offset:Integer { return offset; } Identifier = name:([A-Za-z] (LETTER / DIGIT / SAFE_SYMBOL)*) { return { name: name[0] + name[1].join('') }; } PrimitiveOperation = ArithmeticOperation / ComparisonOperation / BitOperation / StoreOperation StoreOperation = STORE / UPDATE / MAKEREF / MAKEREFUNBOXED / UNBOXED_UPDATE / BOXED / SUBSCRIPT ArithmeticOperation = "+" / "-" / "/" / "*" / "**" BitOperation = ">>" / "<<" / "~" / "^" ComparisonOperation = "==" / "<=" / ">=" / "!=" / "!" / ">" / "<" Integer = digits:[0-9]+ !"." { return parseInt(digits.join(''), 10); } QuotedString = "'" content:[^']* "'" { return content.join(''); } / "\"" content:[^"]* "\"" { return content.join(''); } Real = value:("-"? [0-9]+ "." [0-9]+) { return parseFloat( value.map(x => (Array.isArray(x) ? x.join('') : x)).join(''), ); } Literal = Real / QuotedString / Integer OFFSET = "OFFSET" OFFP = "OFFp" SELP = "SELp" VAR = "VAR" INT = "INT" REAL = "REAL" STRING = "STRING" APP = "APP" RECORD = "RECORD" SELECT = "SELECT" FIX = "FIX" SWITCH = "SWITCH" PRIMOP = "PRIMOP" LABEL = "LABEL" STORE = "store" UPDATE = "update" MAKEREF = "makeref" MAKEREFUNBOXED = "makerefunboxed" UNBOXED_UPDATE = "unboxedupdate" SUBSCRIPT = "subscript" BOXED = "boxed" LETTER = [A-Za-z] SAFE_SYMBOL = "_" DIGIT = [0-9] LBRACKET = "[" RBRACKET = "]" COMMA = "," EQUALS = "=" LPAREN = "(" RPAREN = ")" _ = (" " / "\n" / "\t" / "\r\n")+