@top Program { Query } @precedence { mulop @left addop @left binop @left and @left or @left } @skip { space } commaSep<content> { content ("," content)* } kw<term> { @specialize[@name={term}]<Identifier, term> } Query { TagIdentifier ( WhereClause | LimitClause | OrderClause | SelectClause | RenderClause )* } WhereClause { kw<"where"> Expression } LimitClause { kw<"limit"> Expression } OrderClause { Order commaSep<OrderBy> } OrderBy { Expression OrderDirection? } SelectClause { kw<"select"> commaSep<Select> } RenderClause { kw<"render"> ( kw<"each"> | kw<"all"> )? PageRef } Select { Identifier | Expression kw<"as"> Identifier } OrderDirection { OrderKW } Value { Number | String | Bool | Regex | kw<"null"> | List } Attribute { LVal "." Identifier } Call { Identifier "(" commaSep<Expression> ")" | Identifier "(" ")" } LVal { Identifier | Attribute } ParenthesizedExpression { "(" Expression ")" } LogicalExpression { Expression !and kw<"and"> Expression | Expression !or kw<"or"> Expression } Expression { Value | LVal | ParenthesizedExpression | LogicalExpression | BinExpression | Call } BinExpression { Expression !binop "<" Expression | Expression !binop "<=" Expression | Expression !binop "=" Expression | Expression !binop "!=" Expression | Expression !binop ">=" Expression | Expression !binop ">" Expression | Expression !binop "=~" Expression | Expression !binop "!=~" Expression | Expression !binop InKW Expression | Expression !mulop "*" Expression | Expression !mulop "/" Expression | Expression !mulop "%" Expression | Expression !addop "+" Expression | Expression !addop "-" Expression } List { "[" commaSep<Expression> "]" } Bool { BooleanKW } @tokens { space { std.whitespace+ } TagIdentifier { @asciiLetter (@asciiLetter | @digit | "-" | "_" | "/" )* } Identifier { @asciiLetter (@asciiLetter | @digit | "-" | "_")* } String { ("\"" | "“" | "”") ![\"”“]* ("\"" | "“" | "”") } PageRef { "[" "[" ![\]]* "]" "]" } Order { "order by" } Regex { "/" ( ![/\\\n\r] | "\\" _ )* "/"? } Number { std.digit+ } BooleanKW { "true" | "false" } InKW { "in" } OrderKW { "asc" | "desc" } @precedence { Order, BooleanKW, InKW, OrderKW, Identifier, Number } }