|
|
|
@ -1,4 +1,6 @@
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: `or` operator */
|
|
|
|
|
|
|
|
|
|
let operators = [{
|
|
|
|
|
associativity: "left",
|
|
|
|
|
operators: ["call"]
|
|
|
|
@ -101,7 +103,7 @@ escapableCharacter
|
|
|
|
|
/ "t"
|
|
|
|
|
/ "r"
|
|
|
|
|
|
|
|
|
|
commentCharacter
|
|
|
|
|
inlineCommentCharacter
|
|
|
|
|
= [^\n\r]
|
|
|
|
|
|
|
|
|
|
// Literals
|
|
|
|
@ -129,14 +131,20 @@ homePath
|
|
|
|
|
storePath
|
|
|
|
|
= "<" path:([a-zA-Z0-9\.\_\-\+]+ ("/" [a-zA-Z0-9\.\_\-\+]+)*) ">" { return {type: "path", pathType: "store", storePath: path}; }
|
|
|
|
|
|
|
|
|
|
uri
|
|
|
|
|
= [a-zA-Z][a-zA-Z0-9+\-.]* ":" [a-zA-Z0-9%/?:@&=+$,\-_.!~*']+
|
|
|
|
|
|
|
|
|
|
// Utilities
|
|
|
|
|
_
|
|
|
|
|
= (whitespace / comment)* {}
|
|
|
|
|
= (whitespace / inlineComment)* {}
|
|
|
|
|
|
|
|
|
|
__
|
|
|
|
|
= whitespace+ {}
|
|
|
|
|
|
|
|
|
|
reservedWord // FIXME: Missing reserved words?
|
|
|
|
|
reservedWord
|
|
|
|
|
= name:reservedWordName (& [^a-zA-Z0-9._-]) { return name; } // FIXME: Unify identifier character set definition
|
|
|
|
|
|
|
|
|
|
reservedWordName // FIXME: Missing reserved words?
|
|
|
|
|
= "if"
|
|
|
|
|
/ "then"
|
|
|
|
|
/ "else"
|
|
|
|
@ -171,11 +179,13 @@ nonOperatorExpression
|
|
|
|
|
/ withStatement
|
|
|
|
|
/ conditional
|
|
|
|
|
/ path
|
|
|
|
|
/ identifier
|
|
|
|
|
/ uri
|
|
|
|
|
/ attributePathAlternate
|
|
|
|
|
|
|
|
|
|
comment
|
|
|
|
|
= "#" chars:commentCharacter* _ { return {type: "comment", text: chars.join("")} }
|
|
|
|
|
inlineComment
|
|
|
|
|
= "#" chars:inlineCommentCharacter* _ { return {type: "inlineComment", text: chars.join("")} }
|
|
|
|
|
|
|
|
|
|
/* FIXME: Where else to allow blockComments? Needs to be allowed everywhere, not just in expressions. */
|
|
|
|
|
blockComment
|
|
|
|
|
= "/*" segments:(! "*/" . [^*]*)* "*/" { return {type: "blockComment", text: joinBlockText(segments)} }
|
|
|
|
|
|
|
|
|
@ -187,7 +197,7 @@ functionCallOperatorExpression
|
|
|
|
|
hasAttributeOperatorExpression
|
|
|
|
|
= left:nonOperatorExpression
|
|
|
|
|
_ "?"
|
|
|
|
|
_ right:identifier { return {type: "operatorExpression", operator: "?", left: left, right: right} } // FIXME: attribute path
|
|
|
|
|
_ right:identifier { return {type: "operatorExpression", operator: "?", left: left, right: right} } /* FIXME: Is an attribute path allowed here? */
|
|
|
|
|
|
|
|
|
|
binaryOperatorExpression
|
|
|
|
|
= left:nonOperatorExpression
|
|
|
|
@ -197,22 +207,49 @@ binaryOperatorExpression
|
|
|
|
|
divisionOperatorExpression
|
|
|
|
|
= left:nonOperatorExpression
|
|
|
|
|
_ "/"
|
|
|
|
|
_ right:expression { return {type: "operatorExpression", operator: "/", left: left, right: right} }
|
|
|
|
|
_ right:expression {
|
|
|
|
|
return {type: "operatorExpression", operator: "/", left: left, right: right};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
numericallyNegatedOperatorExpression
|
|
|
|
|
= "-"
|
|
|
|
|
_ right:expression { return {type: "operatorExpression", operator: "numericalNegate", right: right} }
|
|
|
|
|
_ right:expression {
|
|
|
|
|
return {type: "operatorExpression", operator: "numericalNegate", right: right};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
booleanNegatedOperatorExpression
|
|
|
|
|
= "!"
|
|
|
|
|
_ right:expression { return {type: "operatorExpression", operator: "booleanNegate", right: right} }
|
|
|
|
|
_ right:expression {
|
|
|
|
|
return {type: "operatorExpression", operator: "booleanNegate", right: right};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attributePathAlternate
|
|
|
|
|
= attributePath:attributePath alternate:(_ "or" _ attributePathAlternate)? {
|
|
|
|
|
if (alternate != null) {
|
|
|
|
|
return {type: "attributePathAlternate", path: attributePath, alternate: alternate};
|
|
|
|
|
} else {
|
|
|
|
|
return attributePath;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attributePath
|
|
|
|
|
= firstIdentifier:attributeItem nextIdentifiers:("." attributeItem)* {
|
|
|
|
|
return {type: "attributePath", items: [firstIdentifier].concat(nextIdentifiers.map(item => item[1]))};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
attributeItem
|
|
|
|
|
= "\"" identifier:identifier "\"" { return identifier; } /* FIXME: What characters should be allowed here? */
|
|
|
|
|
/ identifier:identifier { return identifier; }
|
|
|
|
|
|
|
|
|
|
identifier
|
|
|
|
|
= identifier:(! (reservedWord [^a-z0-9._-]) identifierValue) { return {type: "identifier", identifier: identifier[1]} }
|
|
|
|
|
= identifier:(! reservedWord identifierValue) {
|
|
|
|
|
return {type: "identifier", identifier: identifier[1]};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: Quoted attributes? */
|
|
|
|
|
identifierValue
|
|
|
|
|
= literal:stringLiteral { return literal.value; }
|
|
|
|
|
/ chars:[a-z_]i [a-z0-9._-]i+ { return text(); }
|
|
|
|
|
/ chars:[a-z_]i [a-z0-9_-]i+ { return text(); }
|
|
|
|
|
|
|
|
|
|
group
|
|
|
|
|
= "("
|
|
|
|
@ -233,17 +270,18 @@ functionDefinitionArgument
|
|
|
|
|
= identifier
|
|
|
|
|
/ setPattern
|
|
|
|
|
|
|
|
|
|
/* FIXME: Is `"foo" = "bar"` valid in an assignment list? */
|
|
|
|
|
assignment
|
|
|
|
|
= identifier:identifier
|
|
|
|
|
= attributePath:attributePath
|
|
|
|
|
_ "="
|
|
|
|
|
_ expression:reorderedExpression
|
|
|
|
|
_ ";" { return {type: "assignment", identifier: identifier, expression: expression} }
|
|
|
|
|
_ ";" { return {type: "assignment", attributePath: attributePath, expression: expression} }
|
|
|
|
|
|
|
|
|
|
assignmentList
|
|
|
|
|
= _ items:((assignment / inheritStatement) _)* { return items.map(item => item[0]); }
|
|
|
|
|
= _ items:((assignment / inheritStatement / blockComment) _)* { return items.map(item => item[0]); }
|
|
|
|
|
|
|
|
|
|
bindingList
|
|
|
|
|
= items:(assignment _)* { return {type: "bindings", assignments: items.map(item => item[0])} }
|
|
|
|
|
bindingList // FIXME: Allow inherit - point at assignmentList instead?
|
|
|
|
|
= items:((assignment / blockComment) _)* { return {type: "bindings", assignments: items.map(item => item[0])} }
|
|
|
|
|
|
|
|
|
|
set
|
|
|
|
|
= "{"
|
|
|
|
@ -279,18 +317,20 @@ elseClause
|
|
|
|
|
= "else"
|
|
|
|
|
_ alternative:expression { return alternative; }
|
|
|
|
|
|
|
|
|
|
/* FIXME: What to return here? */
|
|
|
|
|
withStatement
|
|
|
|
|
= "with"
|
|
|
|
|
_ identifier:identifier
|
|
|
|
|
_ withExpression:expression
|
|
|
|
|
_ ";"
|
|
|
|
|
_ expression
|
|
|
|
|
|
|
|
|
|
inheritStatement // FIXME: Distinguish between identifiers and attribute paths?
|
|
|
|
|
inheritStatement /* FIXME: Distinguish between identifiers and attribute paths? */
|
|
|
|
|
= "inherit"
|
|
|
|
|
_ namespace:("(" identifier ")")?
|
|
|
|
|
_ identifiers:(identifier _)+
|
|
|
|
|
_ ";" { return {type: "inheritStatement", identifiers: identifiers.map(item => item[0]), namespace: maybe(namespace, 1)} }
|
|
|
|
|
_ namespace:("(" reorderedExpression ")")?
|
|
|
|
|
_ attributePaths:(attributePathAlternate _)+ /* FIXME: Is attributePathAlternate allowed here, or just attributePath? */
|
|
|
|
|
_ ";" { return {type: "inheritStatement", attributePaths: attributePaths.map(item => item[0]), namespace: maybe(namespace, 1)} }
|
|
|
|
|
|
|
|
|
|
/* FIXME: Are attribute paths allowed in set patterns? */
|
|
|
|
|
setPattern
|
|
|
|
|
= "{"
|
|
|
|
|
_ args:setPatternVariableList
|
|
|
|
|