Files
plainleaf/client/space_lua/lua.grammar
T
Matouš Jan Fialka ff6854f6ee [LIQ] Add nulls first / nulls last to order by
Extend the `order by` clause with optional `nulls first` and `nulls
last` modifiers following standard SQL semantics. Each sort key can
independently specify where `nil` values should appear in the result. By
default, ascending sorts place nulls last and descending sorts place
nulls first. An explicit nulls first or nulls last overrides this
default. The `asc` keyword is also now accepted as an explicit
alternative to the default ascending direction. Documentation and tests
were updated accordingly.

Signed-off-by: Matouš Jan Fialka <mjf@mjf.cz>
2026-03-02 12:34:25 +01:00

216 lines
4.6 KiB
Plaintext

/* Based on: https://github.com/R167/lezer-lua */
@precedence {
call,
power @right,
prefix,
times @left,
plus @left,
concat @right,
shift @left,
bitand @left,
xor @left,
bitor @left,
compare @left,
and @left,
or @left
}
@top Chunk { Block }
kw<term> { @specialize[@name={term}]<identifier, term> }
ckw<term> { @extend[@name={term}]<identifier, term> }
list<term> { term ("," term)* }
Block { statement* ReturnStatement? }
ReturnStatement { kw<"return"> ExpList? ";"?}
@skip { newline | space | Comment }
statement[@isGroup=Statement] {
";" |
Label |
kw<"break"> |
Goto{ kw<"goto"> Name } |
Scope { kw<"do"> Block kw<"end"> } |
WhileStatement { kw<"while"> exp kw<"do"> Block kw<"end"> } |
RepeatStatement { kw<"repeat"> Block kw<"until"> exp } |
IfStatement |
ForStatement |
Function { kw<"function"> FuncName FuncBody } |
LocalFunction { kw<"local"> kw<"function"> Name FuncBody } |
Assign { VarList "=" ExpList } |
Local { kw<"local"> AttNameList ("=" ExpList)? } |
FunctionCall ~fcall
}
IfStatement {
kw<"if"> exp kw<"then"> Block
(kw<"elseif"> exp kw<"then"> Block)*
(kw<"else"> Block)?
kw<"end">
}
ForNumeric { Name "=" exp "," exp ("," exp)? }
ForGeneric { NameList kw<"in"> ExpList }
ForStatement {
kw<"for"> (ForNumeric | ForGeneric) kw<"do"> Block kw<"end">
}
FuncName { Name ("." Name)* (":" Name)? }
FuncBody { "(" ArgList ")" Block kw<"end"> }
NameList { list<Name> }
ExpList { list<exp> }
VarList { list<var> }
ArgList { (list<var | "...">)? }
AttNameList { list<AttName> }
AttName { Name Attrib }
Attrib { ( "<" Name ">" )? }
exp {
kw<"nil"> | kw<"true"> | kw<"false"> | "..." |
Number |
LiteralString |
prefixexp |
BinaryExpression |
UnaryExpression |
TableConstructor |
FunctionDef { kw<"function"> FuncBody } |
Query
}
Query {
kw<"query"> "[[" QueryClause* "]]"
}
QueryClause {
FromClause |
WhereClause |
OrderByClause |
SelectClause |
LimitClause |
GroupByClause |
HavingClause
}
FromClause { ckw<"from"> (Name "=")? exp }
WhereClause { ckw<"where"> exp }
LimitClause { ckw<"limit"> exp ("," exp)? }
OrderByClause { ckw<"order"> ckw<"by"> list<OrderBy> }
OrderBy { exp (ckw<"desc"> | ckw<"asc">)? (ckw<"nulls"> (ckw<"first"> | ckw<"last">))? }
SelectClause { ckw<"select"> exp }
GroupByClause { ckw<"group"> ckw<"by"> list<exp> }
HavingClause { ckw<"having"> exp }
field[@isGroup=Field] {
FieldDynamic { "[" exp "]" "=" exp } |
FieldProp { Name "=" exp } |
FieldExp { exp }
}
prefixexp {
var |
Parens { "(" exp ")" ~parens } |
FunctionCall ~fcall
}
FunctionCall { prefixexp (":" Name)? !call args }
args {
LiteralString |
TableConstructor |
funcParams[@dynamicPrecedence=1] { "(" list<exp>? ")" ~parens }
}
var {
Name | Property { (prefixexp "." Name) } | MemberExpression { (prefixexp "[" exp "]") }
}
Name { identifier }
Label { "::" Name "::" }
LiteralString { simpleString }
BinaryExpression {
exp !or kw<"or"> exp |
exp !and kw<"and"> exp |
exp !compare CompareOp exp |
exp !bitor BitOp{"|"} exp |
exp !bitand BitOp{"&"} exp |
exp !xor BitOp{"~"} exp |
exp !shift BitOp{"<<" | ">>"} exp |
exp !concat ".." exp |
exp !plus ArithOp{"+" | minus} exp |
exp !times ArithOp{"*" | "/" | "%" | "//"} exp |
exp !power ArithOp{"^"} exp
}
UnaryExpression {
!prefix kw<"not"> exp |
!prefix (ArithOp{minus} | BitOp{"~"} | LenOp{"#"}) exp
}
TableConstructor { "{" (field (fieldsep field)* fieldsep?)? "}" }
@tokens {
CompareOp { "<" | ">" | $[<>=~/!] "=" }
identifier { (std.asciiLetter | "_") (std.digit | std.asciiLetter | "_")* }
stringEscape {
"\\" ($[abfnrtz"'\\] | digit digit? digit?) |
"\\x" hex hex |
"\\u{" hex+ "}"
}
// Any sequence of characters except two consecutive ]]
longStringContent { (![\]] | $[\]] ![\]])* }
singleEqualStringContent {
(![\]] | $[\]] ![=] ![\]])* $[\]]* ![\]]*
}
doubleEqualStringContent {
(![\]] | $[\]] ![=] ![=] ![\]])* $[\]]* ![\]]*
}
simpleString {
"'" (stringEscape | ![\r\n\\'])* "'" |
'"' (stringEscape | ![\r\n\\"])* '"' |
'[[' longStringContent ']]' |
'[=[' singleEqualStringContent ']=]' |
'[==[' doubleEqualStringContent ']==]'
}
hex { $[0-9a-fA-F] }
digit { std.digit }
Number {
digit+ ("." digit+)? ($[eE] $[+\-]? digit+)? |
"0" $[xX] hex+ ("." hex+)? ($[pP] $[+\-]? digit+)?
}
Comment { "--" ![\n\r]* }
space { ($[ \t\f] | "\\" $[\n\r])+ }
newline { $[\n\r] | "\n\r" | "\r\n" }
"..."[@name=Ellipsis]
".."[@name=Concat]
@precedence { Comment, minus }
minus {"-"}
fieldsep { $[,;] }
"(" ")" "[" "]" "{" "}"
"." "," ";" ":" "::"
}