{ function concatRepeat(first, rest, restIndex) { return [first].concat(rest.map(function(item) { return item[restIndex]; })); } function unnestFunctionCalls(first, nested, last) { var callStack = nested.concat([last]); function createFunctionCall(i) { var func; if (i === 0) { func = first; } else { func = createFunctionCall(i - 1); } return { type: "functionCall", argument: callStack[i], function: func }; } return createFunctionCall(callStack.length - 1); } } start = _ expression:expression* _ { return expression; } // Character classes whitespace = "\t" / "\n" / "\r" / " " stringLiteralCharacter = !('"' / "\\") char:. { return char; } / "\\" escapableCharacter numberLiteralCharacter = [0-9.] escapableCharacter = '"' / "n" / "t" / "r" commentCharacter = [^\n\r] // Literals stringLiteral = '"' chars:stringLiteralCharacter+ '"' { return {type: "stringLiteral", value: chars.join("")} } numberLiteral = chars:numberLiteralCharacter+ { return {type: "numberLiteral", value: chars.join("")} } // Utilities _ = (whitespace / comment)* {} // Language constructs expression = additive / operand comment = "#" chars:commentCharacter* _ { return {type: "comment", text: chars.join("")} } operand = group / letBlock / stringLiteral / numberLiteral / functionDefinition / recursiveSet / set / possiblyNestedFunctionCall / identifier additive = left:subtractive _ "+" _ right:additive { return {type: "operation", operator: "+", left: left, right: right} } / subtractive subtractive = left:multiplicative _ "-" _ right:subtractive { return {type: "operation", operator: "-", left: left, right: right} } / multiplicative multiplicative = left:operand _ "*" _ right:multiplicative { return {type: "operation", operator: "*", left: left, right: right} } / operand identifier = literal:stringLiteral { return {type: "identifier", identifier: literal.value} } / chars:[a-z.]i+ { return {type: "identifier", identifier: text()} } group = "(" _ expression:expression _ ")" { return {type: "group", expression: expression} } functionDefinition = argument:functionDefinitionArgument _ ":" _ body:expression { return {type: "functionDefinition", argument: argument, body: body} } functionDefinitionArgument = identifier / setPattern //functionCallWithParens // = functionName:expression "(" // _ arg:expression // _ ")" {return {type: "functionCall", name: functionName, argument: arg} } // //functionCallWithoutParens // = functionName:expression " " // _ arg:expression {return {type: "functionCall", name: functionName, argument: arg} } // //functionCall // = functionCallWithParens // / functionCallWithoutParens possiblyNestedFunctionCall = first:expression nested:expression* last:expression { return unnestFunctionCalls(first, nested, last); } assignment = _ identifier:identifier _ "=" _ expression:expression _ ";" { return {type: "assignment", identifier: identifier, expression: expression} } assignmentList = items:assignment* { return items; } bindingList = items:assignment* { return {type: "bindings", assignments: items} } set = "{" _ items:assignmentList _ "}" { return {type: "set", assignments: items} } recursiveSet = "rec" _ setData:set { return {type: "recursiveSet", assignments: setData.assignments} } letBlock = "let" _ bindingList:bindingList _ "in" _ expression:expression { return {type: "letBlock", bindings: bindingList.assignments, expression: expression} } setPattern = "{" _ args:setPatternVariableList _ "}" { return {type: "setPattern", variables: args} } setPatternVariableList = firstItem:setPatternVariable otherItems:(_ "," _ setPatternVariable)* { return concatRepeat(firstItem, otherItems, 3); } setPatternVariable = restParameter / identifier restParameter = "..." { return {type: "restParameter"} }