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