Hello! Lezer is awesome, very cool parser.
I’m trying to add support for operator with two words:
foo or bar
index not in array
But my operators, and “not” gets splashed into identifier.
So next expressions not parsed correctly:
notor // should be indentifier.
notin // also
Here is my grammar:
@precedence {
member,
call,
pipe,
power @right,
times @left,
plus @left,
rel @left,
wordOp @left,
and @left,
or @left,
ternary @right
}
@top Program { expression* }
expression[@isGroup=Expression] {
Number |
String |
TemplateString |
Identifier |
@specialize[@name=Boolean]<Identifier, "true" | "false"> |
kw<"nil"> |
ArrayExpression {
"[" commaSep<expression> "]"
} |
ObjectExpression {
"{" commaSep<Property> "}"
} |
UnaryExpression |
ParenthesizedExpression |
MemberExpression |
BinaryExpression |
ConditionalExpression {
expression !ternary LogicOp<"?"> expression LogicOp<":"> expression
} |
BuiltinExpression |
CallExpression |
VariableDeclaration |
PointerExpression |
PipeExpression {
expression !pipe "|" (BuiltinExpression | CallExpression)
}
}
BuiltinExpression {
Builtin !call ArgList
}
CallExpression {
expression !call ArgList
}
VariableDeclaration {
kw<"let"> Identifier "=" expression semi
}
ParenthesizedExpression { "(" expression ")" }
ArgList { "(" commaSep<expression> ")" }
propName { PropertyName | ParenthesizedExpression | Number | String }
Property {
propName ":" expression
}
UnaryExpression {
(LogicOp<"not"> | LogicOp<"!"> | ArithOp<"+" | "-">)
expression
}
BinaryExpression {
expression !power (ArithOp<"**"> | ArithOp<"^">) expression |
expression !times (ArithOp<"/"> | ArithOp<"%"> | ArithOp<"*">) expression |
expression !plus ArithOp<"+" | "-"> expression |
expression !rel CompareOp expression |
expression !wordOp WordOp expression |
expression !and LogicOp<"and" | "&&"> expression |
expression !or LogicOp<"or" | "||" | "??"> expression
}
WordOp {
ckw<"in"> |
kw<"matches"> |
kw<"contains"> |
kw<"startsWith"> |
kw<"endsWith">
}
MemberExpression {
expression !member ( ("?." | ".") PropertyName | "[" expression "]")
}
PointerExpression {
Pointer |
"." PropertyName
}
commaSep<content> {
(content ("," content)*)?
}
Builtin {
kw<"all"> |
kw<"none"> |
kw<"any"> |
kw<"one"> |
kw<"filter"> |
kw<"map"> |
kw<"find"> |
kw<"findIndex"> |
kw<"findLast"> |
kw<"findLastIndex"> |
kw<"count"> |
kw<"sum"> |
kw<"groupBy"> |
kw<"sortBy"> |
kw<"reduce"> |
kw<"len"> |
kw<"type"> |
kw<"abs"> |
kw<"ceil"> |
kw<"floor"> |
kw<"round"> |
kw<"int"> |
kw<"float"> |
kw<"string"> |
kw<"trim"> |
kw<"trimPrefix"> |
kw<"trimSuffix"> |
kw<"upper"> |
kw<"lower"> |
kw<"split"> |
kw<"splitAfter"> |
kw<"replace"> |
kw<"repeat"> |
kw<"join"> |
kw<"indexOf"> |
kw<"lastIndexOf"> |
kw<"hasPrefix"> |
kw<"hasSuffix"> |
kw<"max"> |
kw<"min"> |
kw<"mean"> |
kw<"median"> |
kw<"toJSON"> |
kw<"fromJSON"> |
kw<"toBase64"> |
kw<"fromBase64"> |
kw<"now"> |
kw<"duration"> |
kw<"date"> |
kw<"timezone"> |
kw<"first"> |
kw<"last"> |
kw<"get"> |
kw<"take"> |
kw<"keys"> |
kw<"values"> |
kw<"toPairs"> |
kw<"fromPairs"> |
kw<"reverse"> |
kw<"concat"> |
kw<"sort"> |
kw<"bitand"> |
kw<"bitor"> |
kw<"bitxor"> |
kw<"bitnand"> |
kw<"bitshl"> |
kw<"bitshr"> |
kw<"bitushr"> |
kw<"bitnot">
}
kw<term> { @specialize[@name={term}]<Identifier, term> }
ckw<term> { @extend[@name={term}]<Identifier, term> }
semi { ";" }
@skip { spaces | newline | LineComment | BlockComment }
@skip {} {
TemplateString {
"`" (templateEscape | templateContent | Interpolation)* templateEnd
}
}
Interpolation { InterpolationStart expression "}" }
@local tokens {
InterpolationStart[@name="${"] { "${" }
templateEnd { "`" }
templateEscape { "\\" _ }
@else templateContent
}
@skip {} {
BlockComment { "/*" (blockCommentContent | blockCommentNewline)* blockCommentEnd }
}
@local tokens {
blockCommentEnd { "*/" }
blockCommentNewline { "\n" }
@else blockCommentContent
}
@tokens {
spaces[@export] { $[ \t]+ }
newline[@export] { $[\r\n] }
LineComment { "//" ![\n]* }
@precedence { "/*", LineComment, ArithOp<"/"> }
@precedence { "/*", LineComment, RegExp }
identifierChar { @asciiLetter | $[_$\u{a1}-\u{10ffff}] }
word { identifierChar (identifierChar | @digit)* }
Identifier { word }
PropertyName { word }
Pointer { "#" word? }
hex { @digit | $[a-fA-F] }
Number {
(@digit ("_" | @digit)* ("." ("_" | @digit)*)? | "." @digit ("_" | @digit)*)
(("e" | "E") ("+" | "-")? ("_" | @digit)+)? |
@digit ("_" | @digit)* "n" |
"0x" (hex | "_")+ "n"? |
"0b" $[01_]+ "n"? |
"0o" $[0-7_]+ "n"?
}
@precedence { Number "." }
String {
'"' (![\\\n"] | "\\" _)* '"'? |
"'" (![\\\n'] | "\\" _)* "'"?
}
ArithOp<expr> { expr }
LogicOp<expr> { expr }
CompareOp { "<" | ">" | "==" | "!=" }
@precedence { LogicOp, Identifier }
"=" "|"
"(" ")" "[" "]" "{" "}"
"." "?." "," ";" ":"
}
@detectDelim