You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
3.8 KiB
JavaScript

{
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"} }