|
|
@ -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 |
|
|
|