{ const { setParents, SourceFile, SyntaxKind, TuplePattern, ListPattern, Identifier, StructDefinition, StructField, EnumDefinition, EnumField, FunctionDefinition, FunctionExpression, FunctionCall, VariableDefinition, Param, MatchExpression, MatchCase, IntegerExpression, CharLiteral, StringLiteral, ReturnStatement, ExpressionStatement, ContinueStatement, BreakStatement, TypeReference, TypeAlias, MemberAccess, AssignExpression, FunctionBody } = require('./syntax') function loc() { const { start, end } = location() return { start, end, fileId: options.fileId } } function buildRightRecursive(e1, rest) { if (rest.length === 0) { return e1 } const tail = rest.slice(0, rest.length-2) const head = rest[rest.length-1] const nested = buildRightRecursive(head[3], tail) return new FunctionCall(head[1], [e1, nested], null, null, null, loc()) } function buildLeftRecursive(e1, rest) { if (rest.length === 0) { return e1 } const [head, ...tail] = rest const nested = buildLeftRecursive(head[3], tail) return new FunctionCall(head[1], [e1, nested], null, null, null, loc()) } } File = body:Statements { const sourceFile = new SourceFile(body, null, loc()) setParents(sourceFile) return sourceFile } Statements = @(__ @Statement)* __ EOS = __ ';' / _ LineComment? EOLF / _ &'}' / __ EOF IdentifierStart = [a-zA-Z] IdentifierPart = [a-zA-Z0-9] Identifier "identifier" = !ReservedWord text:$(IdentifierStart IdentifierPart*) { return new Identifier(text, null, null, null, loc()) } FunctionKeyword = 'func' !IdentifierPart ReturnKeyword = 'return' !IdentifierPart BreakKeyword = 'break' !IdentifierPart ContinueKeyword = 'continue' !IdentifierPart VariableKeyword = 'var' !IdentifierPart ConstantKeyword = 'const' !IdentifierPart MatchKeyword = 'match' !IdentifierPart ClassKeyword = 'class' !IdentifierPart TypeKeyword = 'type' !IdentifierPart StructKeyword = 'struct' !IdentifierPart Keyword = FunctionKeyword / ReturnKeyword / BreakKeyword / ContinueKeyword / VariableKeyword / ConstantKeyword / MatchKeyword ReservedWord = 'if' !IdentifierPart / 'else' !IdentifierPart / 'while' !IdentifierPart / 'loop' !IdentifierPart / Keyword TypeDecl = TypeReference TypeReference = name:Identifier { return new TypeReference(name, null, null, null, loc()) } Statement = ReturnStatement / BreakStatement / ContinueStatement / FunctionDefinition / VariableDefinition / TypeClassDefinition / StructDefinition / ExpressionStatement / TypeAlias TypeAlias = TypeKeyword __ name:Identifier __ '=' __ typeDecl:TypeDecl EOS { return new TypeAlias(name, typeDecl, null, null, null, loc()) } TypeClassDefinition = TypeKeyword __ ClassKeyword __ name:Identifier __ param:Identifier __ '{' __ members:(@FunctionSignature EOS __)* '}' EOS { return new TypeClass(name, param, members, null, null, null, loc()) } StructField = name:Identifier __ ':' __ typeDecl:TypeDecl { return new StructField(name, typeDecl, null, null, null, loc()) } StructDefinition = StructKeyword __ name:Identifier __ '{' members:(__ @StructField EOS)* __ '}' { return new StructDefinition(name, members, null, null, null, loc()) } ExpressionStatement = expression:Expr EOS { return new ExpressionStatement(expression, null, null, null, loc()) } ReturnStatement = ReturnKeyword EOS { return new ReturnStatement(expression, null, null, null, loc()) } / ReturnKeyword __ expression:Expr EOS { return new ReturnStatement(expression, null, null, null, loc()) } BreakStatement = BreakKeyword EOS { return new BreakStatement(null, null, null, null, loc()) } / keyword:BreakKeyword __ label:Identifier EOS { return BreakStatement(label, null, null, null, loc()) } ContinueStatement = ContinueKeyword EOS { return new ContinueStatement(null, null, null, null, loc()) } / ContinueKeyword __ label:Identifier EOS { return new ContinueStatement(label, null, null, null, loc()) } Param = pattern:Pattern typeDecl:(__ ':' __ @TypeDecl)? defaultValue:(__ '=' @Expr)? { return new Param(pattern, typeDecl, defaultValue, null, null, null, loc()) } OpParam = pattern:Identifier { return new Param(pattern, null, null, null, null, null, loc()) } / '(' pattern:Pattern __ typeDecl:(__ ':' __ @TypeDecl)? defaultValue:(__ '=' @Expr)? __ ')' { return new Param(pattern, typeDecl, defaultValue, null, null, null, loc()) } Pattern = TuplePattern / VarPattern / ConstPattern VarPattern = Identifier PatternList = list:(first:Pattern rest:(__ ',' __ @Pattern)* { return [first, ...rest] })? { if (list === null) return [] return list } TuplePattern = '(' elements:PatternList ')' { return new TuplePattern(elements, null, null, null, loc()) } ConstPattern = StringLiteral / CharLiteral / IntegerExpression ParamList = params:(Param (__ ',' __ @Param)*)? { if (params === null) return [] return [params[0], ...params[1]] } ArrayAccessParams = '[' pn:ParamList ']' { return [new Identifier('[]', null, null, null, loc()), pn] } FunctionSignature = p1:OpParam __ rest:ArrayAccessParams { const [name, pn] = rest return [name, [p1, ...pn]] } / name:Identifier __ '(' __ params:ParamList __ ')' { return [name, params] } / name:UnaryOperator __ p:OpParam { return [name, [p]] } / p:OpParam __ name:PostfixOperator { return [name, [p]] } / p1:OpParam __ name:BinOperator __ p2:OpParam { return [name, [p1, p2]] } FunctionBody = statements:Statements { return new FunctionBody(statements, null, null, null, loc()) } FunctionDefinition = FunctionKeyword __ sig:FunctionSignature __ ':' __ returnTypeDecl:TypeDecl __ '{' __ body:FunctionBody __ '}' EOS { const [name, params] = sig return new FunctionDefinition(name, params, returnTypeDecl, body, null, null, null, loc()) } / FunctionKeyword __ sig:FunctionSignature __ ':' __ returnTypeDecl:TypeDecl EOS { const [name, params] = sig return new FunctionDefinition(name, params, returnTypeDecl, null, null, null, null, loc()) } / FunctionKeyword __ sig:FunctionSignature __ '{' __ body:FunctionBody __ '}' EOS { const [name, params] = sig return new FunctionDefinition(name, params, null, body, null, null, null, loc()) } / FunctionKeyword __ sig:FunctionSignature EOS { const [name, params] = sig return new FunctionDefinition(name, params, null, null, null, null, null, loc()) } VariableDefinition = VariableKeyword __ pattern:Pattern EOS { return new VariableDefinition(pattern, null, null, null, null, null, loc()) } / VariableKeyword __ pattern:Pattern __ ':' __ typeDecl:TypeDecl EOS { return new VariableDefinition(pattern, pattern, null, null, null, null, loc()) } / VariableKeyword __ pattern:Pattern __ '=' __ expression:Expr EOS { return new VariableDefinition(pattern, null, expression, null, null, null, loc()) } / VariableKeyword __ pattern:Pattern __ ':' __ typeDecl:TypeDecl __ '=' __ expression:Expr EOS { return new VariableDefinition(pattern, typeDecl, expression, null, null, null, loc()) } Expr = DelimExpr DelimExpr = first:ExprNoDelim rest:(__ ',' __ @ExprNoDelim)* { if (rest.length === 0) return first return new ExpressionSequence([first, ...rest], null, null, null, loc()) } ExprNoDelim = AssignExpr LOrOperator = '||' { return new Identifier('||', null, null, null, loc()) } LAndOperator = '&&' { return new Identifier('&&', null, null, null, loc()) } BOrOperator = '|' ![|=] { return new Identifier('|', null, null, null, loc()) } BXOrOperator = '^' !'=' { return new Identifier('^', null, null, null, loc()) } BAndOperator = '&' !'&=' { return new Identifier('&', null, null, null, loc()) } EqOperator = '==' { return new Identifier('==', null, null, null, loc()) } DotOperator = '.' { return new Identifier('.', null, null, null, loc()) } ExptOperator = '**' { return new Identifier('**', null, null, null, loc()) } BinOperator = LOrOperator / LAndOperator / BOrOperator / BXOrOperator / BAndOperator / EqOperator / RelOperator / ShiftOperator / AddOperator / MulOperator / DotOperator PostfixOperator = text:$("++" / "--") { return new Identifier(text, null, null, null, loc()) } AssignOperator = text:$('=' !'=' / '+=' / '-=' / '**=' / '*=' / '/=' / '%=' / '<<=' / '>>=' / '>>>=' / '&=' / '^=' / '|=') { return new Identifier(text, null, null, null, loc()) } RelOperator = text:$("<=" / ">=" / "<" !"<" / ">" !">") { return new Identifier(text, null, null, null, loc()) } ShiftOperator = text:$("<<" !"=" / ">>>" !"=") { return new Identifier(text, null, null, null, loc()) } AddOperator = text:$("+" ![+=] / "-" ![-=]) { return new Identifier(text, null, null, null, loc()) } MulOperator = text:$("*" ![*=] / "/" !"=" / "%" !"=") { return new Identifier(text, null, null, null, loc()) } UnaryOperator = text:$("++" / "--" / "+" !"=" / "-" !"=" / "~" / "!") { return new Identifier(text, null, null, null, loc()) } AssignExpr = left:(@(MemberAccessExpr / Pattern) __ AssignOperator __)* right:LOrExpr { if (left.length === 0) return right let out = right for (let i = left.length-1; i >= 0; i--) { out = new AssignExpression(left[i], out, null, null, null, loc()) } return out } LOrExpr = first:LAndExpr rest:(__ LOrOperator __ LAndExpr)* { return buildLeftRecursive(first, rest) } LAndExpr = first:BOrExpr rest:(__ LAndOperator __ BOrExpr)* { return buildLeftRecursive(first, rest) } BOrExpr = first:BXOrExpr rest:(__ BOrOperator __ BXOrExpr)* { return buildLeftRecursive(first, rest) } BXOrExpr = first:BAndExpr rest:(__ BXOrOperator __ BAndExpr)* { return buildLeftRecursive(first, rest) } BAndExpr = first:EqExpr rest:(__ BAndOperator __ EqExpr)* { return buildLeftRecursive(first, rest) } EqExpr = first:RelExpr rest:(__ EqOperator __ RelExpr)* { return buildLeftRecursive(first, rest) } RelExpr = first:ShiftExpr rest:(__ RelOperator __ ShiftExpr)* { return buildLeftRecursive(first, rest) } ShiftExpr = first:AddExpr rest:(__ ShiftOperator __ AddExpr)* { return buildLeftRecursive(first, rest) } AddExpr = first:MulExpr rest:(__ AddOperator __ MulExpr)* { return buildLeftRecursive(first, rest) } MulExpr = first:ExptExpr rest:(__ MulOperator __ ExptExpr)* { return buildLeftRecursive(first, rest) } ExptExpr = first:UnaryExpr rest:(__ ExptOperator __ UnaryExpr)* { return buildRightRecursive(first, rest) } PostfixExpr = e:CallExpr _ operator:PostfixOperator { return new FunctionCall(operator, [e], null, null, null, loc()) } UnaryExpr = PostfixExpr / CallExpr / operator:UnaryOperator _ e:UnaryExpr { return new FunctionCall(operator, [e], null, null, null, loc()) } ArgList = args:(Expr (__ ',' __ @Expr)) { if (args === null) return args return [args[0], ...args[1]] } CallExpr = operator:ExprNoCall args:(__ '(' __ @ArgList __ ')')? { if (args === null) return operator return new FunctionCall(operator, args, null, null, null, loc()) } VarRefExpr = Identifier ASCIISpecialChar = '\\' char:. { switch (char) { case 'v': return '\v' case 'b': return '\b' case 'f': return '\f' case 'r': return '\r' case 't': return '\t' case 'b': return '\b' case 'n': return '\n' case '0': return '\0' default: return char } } EscapeSeq = ASCIISpecialChar IntegerExpression = digits:$([0-9]+) { return new IntegerExpression(Number(digits), null, null, null, loc()) } Char = EscapeSeq / . StringLiteral = '"' chars:(!'"' @Char)* '"' { return new StringLiteral(chars.join(''), null, null, null, loc()) } CharLiteral = '\'' value:Char '\'' { return new CharLiteral(value, null, null, null, loc()) } NestExpr = '(' __ @Expr __ ')' MatchCase = pattern:Pattern __ '->' __ expression:ExprNoDelim { return new MatchCase(pattern, expression, null, null, null, loc()) } MatchExpr = MatchKeyword __ expression:Expr __ '{' __ first:MatchCase rest:(__ ',' __ @MatchCase)* (__ ',')? __ '}' { return new MatchExpression(expression, [first, ...rest], null, null, null, loc()) } ArrayAccessArgs = '[' args:ArgList ']' { return [new Identifier('[]', null, null, null, loc()), args] } ExprNoCall = arg0:MemberAccessExpr rest:(__ ArrayAccessArgs)? { if (rest === null) return arg0 const [operator, argn] = rest return new FunctionCall(operator, [arg0, ...argn], null, null, null, loc()) } MemberAccessExpr = first:PrimExpr rest:(__ DotOperator __ @Identifier)* { if (rest.length === 0) { return first } return new MemberAccess(first, rest, null, null, null, loc()) } PrimExpr = NestExpr / MatchExpr / VarRefExpr / IntegerExpression / StringLiteral / CharLiteral WS "whitespace" = [\t\r\n ] BL "blank space" = [\t\r ] BlockComment = $('/*' (!'*/' (BlockComment / .))* '*/') LineComment = $('//' (!EOLF .)*) EOF "end of file" = !. EOL "end of line" = "\n" / "\r\n" / "\r" / "\u2028" / "\u2029" EOLF = EOL / EOF Comment = BlockComment / LineComment __ = (WS / Comment)* _ = (BL / BlockComment)*