diff --git a/common/space_lua/lua.grammar b/common/space_lua/lua.grammar index 34a78092..258a0a88 100644 --- a/common/space_lua/lua.grammar +++ b/common/space_lua/lua.grammar @@ -43,7 +43,7 @@ statement[@isGroup=Statement] { IfStatement { kw<"if"> exp kw<"then"> Block (kw<"elseif"> exp kw<"then"> Block)* - (kw<"else"> Block) + (kw<"else"> Block)? kw<"end"> } @@ -63,9 +63,11 @@ list { term ("," term)* } NameList { list } ExpList { list } VarList { list } -ArgList { list } +ArgList { (list)? } -AttNameList { list } + +AttNameList { list } +AttName { Name Attrib } Attrib { ( "<" Name ">" )? } exp { diff --git a/common/space_lua/parse-lua.js b/common/space_lua/parse-lua.js new file mode 100644 index 00000000..d836a52e --- /dev/null +++ b/common/space_lua/parse-lua.js @@ -0,0 +1,22 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +import {LRParser} from "@lezer/lr" +const spec_identifier = {__proto__:null,break:16, goto:20, do:24, end:26, while:30, nil:32, true:34, false:36, or:80, and:82, not:104, function:112, repeat:120, until:122, if:126, then:128, elseif:130, else:132, for:136, in:144, local:154, return:170} +export const parser = LRParser.deserialize({ + version: 14, + states: ">YO!ZQPOOOOQO'#Cc'#CcO!UQPO'#CaO!bQPOOOOQO'#Eh'#EhO!vQQO'#CwO$YQPO'#EgOOQO'#Eg'#EgO$dQPO'#EgOOQO'#D}'#D}O%sQPO'#D|OOQO'#Ec'#EcOOQO'#EU'#EUO%xQPO'#C_OOQO'#C_'#C_QOQPOOO!UQPO'#CeO&]QPO'#CgO!vQQO'#CjO&dQPO'#DiO!vQQO'#DlO!UQPO'#DqO!UQPO'#DxO&kQPO'#EOO&sQQO'#ESO'ZQPO,58{OOQO'#Cq'#CqO!UQPO,59^O!vQQO,59`O(aQQO'#C|O(hQQO'#EmOOQO'#Ei'#EiOOQO,59f,59fO!UQPO,59fO(oQPO'#EeO,_QPO,59cOOQO'#Dc'#DcOOQO'#Dd'#DdO!vQQO'#DaOOQO'#Ee'#EeO,fQPO'#DeO,kQPO'#E]O,sQPO,5;iO!vQQO,5:hOOQO-E8S-E8SOOQO,58y,58yOOQO,59P,59PO,{QPO,59RO-QQPO,59UO-XQPO,5:TO-^QPO,5:WO-eQPO'#E|OOQO'#Du'#DuO-pQPO'#DtO-uQPO,5:]O-zQPO'#DyO,fQPO,5:dO.VQQO'#EQO/mQPO'#FOOOQO'#EP'#EPO!UQPO,5:fO1QQPO,5:jO2bQPO,5:nOOQO,5:n,5:nOOQO1G.g1G.gOOQO1G.x1G.xO2xQPO1G.zO3PQSO'#EeO4]QSO'#EhO!vQQO'#DOO7QQSO'#DQOOQO'#Ej'#EjOOQO,59h,59hO7[QSO,59hO7dQPO'#EnOOQO,5;X,5;XO8yQPO,5;XO9OQPO1G/QOOQO1G.}1G.}OOQO'#DX'#DXOOQO'#DY'#DYOOQO'#DZ'#DZOOQO'#D['#D[OOQO'#D^'#D^OOQO'#D_'#D_OOQO'#D`'#D`O!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO!vQQO,59oO:_QPO,59{O;zQQO'#DgOOQO,5:P,5:POiQQO,59kO?gQPO,59jO?nQQO1G/SO?uQSO1G/SOOQO1G/S1G/SO?}QSO,59{O!vQQO'#EWO@XQPO,5;YOOQO1G0s1G0sOOQO7+$l7+$lODUQPO1G/ZOD]QPO1G/ZOF|QPO1G/ZOGTQPO1G/ZOInQPO1G/ZOI{QPO1G/ZOK|QPO1G/ZO! cQPO1G/ZO! jQPO1G/ZO! qQPO'#EgO! {QPO'#E{OOQO'#Dh'#DhO!!TQPO,5:RO!!YQPO7+$[O!!_QPO7+%ZO!#nQPO7+%^O!#yQPO1G/yOOQO,5:u,5:uOOQO-E8X-E8XOOQO1G/z1G/zO!$QQPO7+%cOOQO,5:v,5:vOOQO-E8Y-E8YO!UQPO1G0POOQO1G0P1G0PO!$VQQO,5:mOOQO,5:x,5:xOOQO-E8[-E8[OOQO7+%l7+%lOOQO7+%p7+%pO!$[QSO1G/VO!$fQPO1G/UO!%rQSO1G/ZO!%yQSO1G/ZO!'XQSO1G/ZO!'`QSO1G/ZO!(hQSO1G/ZO!(uQSO1G/ZO!)eQSO1G/ZO!+iQSO1G/ZO!+pQSO1G/ZOOQO,5:q,5:qOOQO7+$n7+$nO!+wQQO7+$nOOQO-E8T-E8TO!,OQPO,5:rOOQO-E8U-E8UO!-eQQO'#EXO!-pQPO,5;gO&]QPO1G/mOOQO<iQQO7+$pOOQO<dAN>dO&]QPOAN>dO!.dQPO,5:tO!.kQPOAN>dO!.pQPO<kOOQOLD)jLD)jOOQO7+%z7+%zO!/ZQPOG24VO>iQQO'#DaO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59oO>iQQO,59o", + stateData: "!/e~O#TOS#UOSPOS~OSZOUQOWZOY`O[aO_bOlTO!YfO!^cO!adO!feO!ogO!whO#WPO~O#RRP~P]OgkOilOlnOoqOqmO#YjO~O`wOawObwOcwOdwOlTOqmO!UvO!YxO#WPO#YjO#euO#htO#itO~Og#ZXi#ZXl#ZXo#ZXq#ZX#Y#ZX~OvyO#_#qX~P#tOS#VXU#VXW#VXY#VX[#VX_#VXl#VX!Y#VX!^#VX!a#VX!f#VX!o#VX!w#VX#R#VX#W#VX]#VX!_#VX!c#VX!d#VX~P#tO#_{O~O#RRX]RX!_RX!cRX!dRX~P]O]RP~P]O!_RP~P]O!Y!^O#WPO~OS!aO#R!vX]!vX!_!vX!c!vX!d!vX~P!vOU!bO~O`wOawObwOcwOdwOi!gOlTOqmO!U%nO!YxO#WPO#YjO#euO#htO#itO~Ou!jO~P'`Om!mO~P!vOm#XXx#XXy#XXz#XX!P#XX#c#XX#d#XX#e#XX#f#XX#g#XX#h#XX#i#XX#j#XX#k#XX#l#XX#m#XX#n#XX[#XX!b#XXS#XX#R#XXj#XXv#XXU#XXW#XXY#XX_#XX!Y#XX!^#XX!a#XX!f#XX!o#XX!w#XX#W#XX]#XX!_#XX!c#XX!d#XX~P!bOx#POy#QOz!xO!P!|O#c!qO#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wO~Om!pO~P+ZOl#SO~OlTO#WPO~OvyO#_#qa~O]#YO~O[#ZO~P+ZO!_#[O~O!b#]O~P+ZOv#_O#_#^O!j#pX~O!j#aO~O[#bO~Og#cOo#eOl!mX~O#s#gOS!uPU!uPW!uPY!uP[!uP_!uPl!uPv!uP!Y!uP!^!uP!a!uP!f!uP!o!uP!w!uP#R!uP#W!uP#_!uP]!uP!_!uP!c!uP!d!uP~Ov#iOS#rXU#rXW#rXY#rX[#rX_#rXl#rX!Y#rX!^#rX!a#rX!f#rX!o#rX!w#rX#R#rX#W#rX#_#rX]#rX!_#rX!c#rX!d#rX~O#_#lOS!raU!raW!raY!ra[!ra_!ral!ra!Y!ra!^!ra!a!ra!f!ra!o!ra!w!ra#R!ra#W!ra]!ra!_!ra!c!ra!d!ra~OS#mO#R!va]!va!_!va!c!va!d!va~P+ZOj#nO~P+ZOu#XXx#XXy#XXz#XX!P#XX#`#XX#c#XX#d#XX#e#XX#f#XX#g#XX#h#XX#i#XX#j#XX#k#XX#l#XX#m#XX#n#XX~P!bO#_#oOg#[Xi#[Xl#[Xo#[Xq#[Xu#[Xx#[Xy#[Xz#[X!P#[X#Y#[X#`#[X#c#[X#d#[X#e#[X#f#[X#g#[X#h#[X#i#[X#j#[X#k#[X#l#[X#m#[X#n#[X~Ox%vOy%wOz%oO!P%sO#c!qO#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wO~OutX#`tX~P5|Ou#sO#`#qO~Ov#uOm#bXS#bXU#bXW#bXY#bX[#bX_#bXl#bX!Y#bX!^#bX!a#bX!f#bX!o#bX!w#bX#R#bX#W#bX]#bX!_#bX!c#bX!d#bX~P+ZOm#wO~OlnOqmO#YjO~O#n!wOx!Tay!Taz!Ta!P!Ta#c!Ta#d!Ta#e!Ta#f!Ta#g!Ta#h!Ta#i!Ta#j!Ta#k!Ta#l!Ta#m!Ta~Om!Ta[!Ta!b!TaS!Ta#R!Taj!Tav!TaU!TaW!TaY!Ta_!Tal!Ta!Y!Ta!^!Ta!a!Ta!f!Ta!o!Ta!w!Ta#W!Ta]!Ta!_!Ta!c!Ta!d!Ta~P9ZOc$TOlTO#WPOm![P~Ov#Pa#_#Pa~P#tO]RP!cRP!dRP~P]Ov#_O!j#pa~Og#cOo$bOl!ma~Ov#iOS#raU#raW#raY#ra[#ra_#ral#ra!Y#ra!^#ra!a#ra!f#ra!o#ra!w#ra#R#ra#W#ra#_#ra]#ra!_#ra!c#ra!d#ra~O`wOawObwOcwOdwOlTOqmO!U%nO!YxO#WPO#YjO#euO#htO#itO~Oj$jO~P+ZOu$uO~P'`Ou$uO#`$vO~Ou!Ta#`!Ta~P9ZOv#uOm#baS#baU#baW#baY#ba[#ba_#bal#ba!Y#ba!^#ba!a#ba!f#ba!o#ba!w#ba#R#ba#W#ba]#ba!_#ba!c#ba!d#ba~O!P!|O#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOmwixwiywizwi[wi!bwiSwi#RwijwivwiUwiWwiYwi_wilwi!Ywi!^wi!awi!fwi!owi!wwi#Wwi]wi!_wi!cwi!dwi~O#c!qO~PAlO#cwi~PAlO!P!|O#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOmwixwiywizwi#cwi#ewi[wi!bwiSwi#RwijwivwiUwiWwiYwi_wilwi!Ywi!^wi!awi!fwi!owi!wwi#Wwi]wi!_wi!cwi!dwi~O#dwi~PDdO#d!rO~PDdO#j!vO#k!vO#l!vO#m!vO#n!wOmwixwiywizwi#cwi#dwi#ewi#fwi#gwi[wi!bwiSwi#RwijwivwiUwiWwiYwi_wilwi!Ywi!^wi!awi!fwi!owi!wwi#Wwi]wi!_wi!cwi!dwi~O!P!|O#h!uO#i!uO~PG[O!Pwi#hwi#iwi~PG[O#n!wOmwixwiywi[wi!bwiSwi#RwijwivwiUwiWwiYwi_wilwi!Ywi!^wi!awi!fwi!owi!wwi#Wwi]wi!_wi!cwi!dwi~Ozwi!Pwi#cwi#dwi#ewi#fwi#gwi#hwi#iwi#jwi#kwi#lwi#mwi~PJYOz!xO!P!|O#c!qO#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOmwixwi[wi!bwiSwi#RwijwivwiUwiWwiYwi_wilwi!Ywi!^wi!awi!fwi!owi!wwi#Wwi]wi!_wi!cwi!dwi~Oy#QO~PLyOywi~PLyOv$zOm#oX~P#tOv$zOm#oX~Om$|O~O]$}O~OS!]qU!]qW!]qY!]q[!]q_!]ql!]q!Y!]q!^!]q!a!]q!f!]q!o!]q!w!]q#R!]q#W!]q]!]q!_!]q!c!]q!d!]q~P+ZO]%QO!c%PO!d%RO~Ov%SO~P+ZO]%TO~O#t%VO~Ousi#`si~P5|O#_%WO~O!P%sO#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOuwixwiywizwi#`wi~O#c!qO~P!$kO#cwi~P!$kO!P%sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOuwixwiywizwi#`wi#cwi#ewi~O#dwi~P!&QO#d!rO~P!&QO#j!vO#k!vO#l!vO#m!vO#n!wOuwixwiywizwi#`wi#cwi#dwi#ewi#fwi#gwi~O!P%sO#h!uO#i!uO~P!'gO!Pwi#hwi#iwi~P!'gO#n!wOuwixwiywi#`wi~Ozwi!Pwi#cwi#dwi#ewi#fwi#gwi#hwi#iwi#jwi#kwi#lwi#mwi~P!)SOz%oO!P%sO#c!qO#d!rO#e!sO#f!tO#g!tO#h!uO#i!uO#j!vO#k!vO#l!vO#m!vO#n!wOuwixwi#`wi~Oy%wO~P!*bOywi~P!*bOu%XO~P'`Om!zav!zaS!zaU!zaW!zaY!za[!za_!zal!za!Y!za!^!za!a!za!f!za!o!za!w!za#R!za#W!za]!za!_!za!c!za!d!za~P+ZOc%[OlTO#WPO~Ov$zOm#oa~O]%`O!c%PO!d%aO~Om!{av!{a~P#tO]%fO~O!b%hO~P+ZO]%iO~Ov%jO[!gy~P+ZOury#`ry~P5|O]%kO~O[!g!Z~P+ZOP#i~", + goto: ";d#sPPP#tP$dP$qP$dP$dPP$dPPPPPP&y'}P'}PP)ZPP*gP&yP+u+u+uPP'PPPP+{,g-V-sP.e/X/}'PP0w0w'PP1w2Q$dPP$dPPPP$dP2T2T2WP2Z$d2d$dP$d2g$d2t2w2}3QP3a3p3v3|4T4Z4a4g4mPPPP4sP5QP7h8x:^:fPP:n:tPPPPPPPPPPPP:|;P;S;aQ_OQ!PaQ!RcQ$W#ZQ$Y#]Q$_#bQ%^$|Q%c%RQ%g%aR%l%hgZO]ac#Z#]#b$|%R%a%h#[SOT]abcdhlnvy{!g!x!y!z!{!|!}#O#P#Q#S#Z#[#]#^#a#b#l#o#u$z$|%P%R%S%W%a%h%j%n%o%p%q%r%s%t%u%v%wQiQQ!O`Q!TeQ!XfS!Zg#iQ!ckW!fm#q$v%YQ!oqQ#k!^Q$[#_Q$`#cQ$c#eQ$d#gR%U$bWoRr!e!o!wwTbdhlmnv{!g!x!y!z!{!|!}#O#P#Q#[#^#a#l#o#q#u$v%P%S%W%Y%j%n%o%p%q%r%s%t%u%v%w#eSOT]abcdhlmnvy{!g!x!y!z!{!|!}#O#P#Q#S#Z#[#]#^#a#b#l#o#q#u$v$z$|%P%R%S%W%Y%a%h%j%n%o%p%q%r%s%t%u%v%w#eVOT]abcdhlmnvy{!g!x!y!z!{!|!}#O#P#Q#S#Z#[#]#^#a#b#l#o#q#u$v$z$|%P%R%S%W%Y%a%h%j%n%o%p%q%r%s%t%u%v%w!|VTbdhlmnvy{!g!x!y!z!{!|!}#O#P#Q#S#[#^#a#l#o#q#u$v$z%P%S%W%Y%j%n%o%p%q%r%s%t%u%v%wgWO]ac#Z#]#b$|%R%a%hX!im#q$v%Yp!ys!Q!S!`!d!l#p#y$Q$R$X$Z$x%b%d%m]%p!h$i$k$r$s%et!zs!Q!S!`!d!l#p#y#z#|$Q$R$X$Z$x%b%d%ma%q!h$i$k$l$n$r$s%er!{s!Q!S!`!d!l#p#y#z$Q$R$X$Z$x%b%d%m_%r!h$i$k$l$r$s%ev!|s!Q!S!`!d!l#p#y#z#{#|$Q$R$X$Z$x%b%d%mc%s!h$i$k$l$m$n$r$s%ex!}s!Q!S!`!d!l#p#y#z#{#|#}$Q$R$X$Z$x%b%d%me%t!h$i$k$l$m$n$o$r$s%ez#Os!Q!S!`!d!l#p#y#z#{#|#}$O$Q$R$X$Z$x%b%d%mg%u!h$i$k$l$m$n$o$p$r$s%e!O#Os!Q!S!`!d!l#R#p#y#z#{#|#}$O$P$Q$R$X$Z$x%b%d%mk%u!h#t$i$k$l$m$n$o$p$q$r$s%e!UvTbdhlnv{!g!x!y!z!{!|!}#O#P#Q#[#^#a#l#u%P%S%jq%nm#o#q$v%W%Y%n%o%p%q%r%s%t%u%v%wQ#TxQ#f!YR$g#kR$V#SR!WeR!VeQ#X{Q$^#aR$h#lR!YfgYO]ac#Z#]#b$|%R%a%hR!_gQ![gR$e#iR#h!Zd^Oac#Z#]#b$|%R%a%hR}]d]Oac#Z#]#b$|%R%a%hR|]Q#r!kR$w#rQ#v!lR$y#vS${$S$TR%]${Q%O$YR%_%OQ#`!TR$]#`Q#d!XR$a#dQzUR#VzQ#j![R$f#jg[O]ac#Z#]#b$|%R%a%hQsTQ!QbQ!SdQ!`hQ!dlW!hm#q$v%YW!ln{#a#lQ#RvQ#p!gQ#t%nQ#y!xQ#z!yQ#{!zQ#|!{Q#}!|Q$O!}Q$P#OQ$Q#PQ$R#QQ$X#[Q$Z#^Q$i#oQ$k%oQ$l%pQ$m%qQ$n%rQ$o%sQ$p%tQ$q%uQ$r%vQ$s%wQ$x#uQ%b%PQ%d%SQ%e%WR%m%jlRO]acy#S#Z#]#b$z$|%R%a%h!UrTbdhlnv{!g!x!y!z!{!|!}#O#P#Q#[#^#a#l#u%P%S%jq!em#o#q$v%W%Y%n%o%p%q%r%s%t%u%v%wfUO]ac#Z#]#b$|%R%a%h!vVTbdhlmnv{!g!x!y!z!{!|!}#O#P#Q#[#^#a#l#o#q#u$v%P%S%W%Y%j%n%o%p%q%r%s%t%u%v%wQ#UyQ$S#SR%Z$zUpRr!eR#x!oQ!kmV$t#q$v%YXoRr!e!oQ!nnV#W{#a#lR$U#SR!UegXO]ac#Z#]#b$|%R%a%hR!]g", + nodeNames: "⚠ Comment Chunk Block ; Label :: Name break Goto goto Scope do end WhileStatement while nil true false Ellipsis Number LiteralString Property . MemberExpression [ ] Parens ( ) FunctionCall : TableConstructor { FieldDynamic FieldProp FieldExp } , BinaryExpression or and CompareOp BitOp BitOp BitOp BitOp Concat ArithOp ArithOp ArithOp UnaryExpression not ArithOp BitOp FunctionDef function FuncBody ArgList RepeatStatement repeat until IfStatement if then elseif else ForStatement for ForNumeric ForGeneric NameList in ExpList Function FuncName LocalFunction local Assign VarList Local AttNameList AttName Attrib ReturnStatement return", + maxTerm: 128, + nodeProps: [ + ["group", -14,4,5,8,9,11,14,30,59,62,67,74,76,78,80,"Statement",-3,34,35,36,"Field"] + ], + skippedNodes: [0,1], + repeatNodeCount: 9, + tokenData: "6v~RrXY#]YZ#w[]#]]^$Upq#]rs$^uv)avw)fwx)kxy.iyz.nz{.s{|.x|}.}}!O/U!O!P/x!P!Q0_!Q!R0t!R![2Y![!]4^!]!^4k!^!_4r!_!`5U!`!a5^!c!}5p!}#O6O#O#P#n#P#Q6T#Q#R6Y#T#o5p#o#p6_#p#q6d#q#r6i#r#s6n~#bS#U~XY#][]#]pq#]#O#P#n~#qQYZ#]]^#]~#|P#T~]^$P~$UO#T~~$ZP#T~YZ$P~$aWOY$yZ]$y^r$ys#O$y#O#P%n#P;'S$y;'S;=`(O<%lO$y~$|XOY$yZ]$y^r$yrs%is#O$y#O#P%n#P;'S$y;'S;=`(O<%lO$y~%nO#Y~~%qZrs$ywx$y!Q![&d#O#P$y#T#U$y#U#V$y#Y#Z$y#b#c$y#i#j(U#l#m(w#n#o$y~&gZOY$yZ]$y^r$yrs%is!Q$y!Q!['Y![#O$y#O#P%n#P;'S$y;'S;=`(O<%lO$y~']ZOY$yZ]$y^r$yrs%is!Q$y!Q![$y![#O$y#O#P%n#P;'S$y;'S;=`(O<%lO$y~(RP;=`<%l$y~(XP#o#p([~(_R!Q![(h!c!i(h#T#Z(h~(kS!Q![(h!c!i(h#T#Z(h#q#r$y~(zR!Q![)T!c!i)T#T#Z)T~)WR!Q![$y!c!i$y#T#Z$y~)fO#l~~)kO#d~~)nWOY*WZ]*W^w*Wx#O*W#O#P*v#P;'S*W;'S;=`-W<%lO*W~*ZXOY*WZ]*W^w*Wwx%ix#O*W#O#P*v#P;'S*W;'S;=`-W<%lO*W~*yZrs*Wwx*W!Q![+l#O#P*W#T#U*W#U#V*W#Y#Z*W#b#c*W#i#j-^#l#m.P#n#o*W~+oZOY*WZ]*W^w*Wwx%ix!Q*W!Q![,b![#O*W#O#P*v#P;'S*W;'S;=`-W<%lO*W~,eZOY*WZ]*W^w*Wwx%ix!Q*W!Q![*W![#O*W#O#P*v#P;'S*W;'S;=`-W<%lO*W~-ZP;=`<%l*W~-aP#o#p-d~-gR!Q![-p!c!i-p#T#Z-p~-sS!Q![-p!c!i-p#T#Z-p#q#r*W~.SR!Q![.]!c!i.]#T#Z.]~.`R!Q![*W!c!i*W#T#Z*W~.nOl~~.sOm~~.xO#j~~.}O#h~V/UOvR#`S~/ZP#i~}!O/^~/cTP~OY/^Z]/^^;'S/^;'S;=`/r<%lO/^~/uP;=`<%l/^V/}PgT!O!P0QV0VP!PT!O!P0YQ0_OcQ~0dQ#k~!P!Q0j!_!`0o~0oO#m~T0tOzT~0yUd~!O!P1]!Q![2Y!g!h1q!z!{2k#X#Y1q#l#m2k~1`P!Q![1c~1hRd~!Q![1c!g!h1q#X#Y1q~1tQ{|1z}!O1z~1}P!Q![2Q~2VPd~!Q![2Q~2_Sd~!O!P1]!Q![2Y!g!h1q#X#Y1q~2nR!Q![2w!c!i2w#T#Z2w~2|Ud~!O!P3`!Q![2w!c!i2w!r!s4Q#T#Z2w#d#e4Q~3cR!Q![3l!c!i3l#T#Z3l~3qTd~!Q![3l!c!i3l!r!s4Q#T#Z3l#d#e4Q~4TR{|1z}!O1z!P!Q1z~4cPo~![!]4f~4kOU~V4rOSR#`SV4yQ#sQzT!^!_5P!_!`0oT5UO#fT~5ZP#_~!_!`0oV5eQ#tQzT!_!`0o!`!a5kT5pO#gT~5uR#W~!Q![5p!c!}5p#T#o5p~6TOi~~6YOj~~6_O#n~~6dOq~~6iO#c~~6nOu~~6sP#e~!_!`0o", + tokenizers: [0, 1, 2], + topRules: {"Chunk":[0,2]}, + dynamicPrecedences: {"109":1}, + specialized: [{term: 100, get: (value) => spec_identifier[value] || -1}], + tokenPrec: 2778 +}) diff --git a/common/space_lua/parse-lua.terms.js b/common/space_lua/parse-lua.terms.js new file mode 100644 index 00000000..467f3db2 --- /dev/null +++ b/common/space_lua/parse-lua.terms.js @@ -0,0 +1,28 @@ +// This file was generated by lezer-generator. You probably shouldn't edit it. +export const + Comment = 1, + Chunk = 2, + Block = 3, + Label = 5, + Name = 7, + Number = 20, + LiteralString = 21, + FunctionCall = 30, + TableConstructor = 32, + BinaryExpression = 39, + CompareOp = 42, + UnaryExpression = 51, + FuncBody = 57, + ArgList = 58, + IfStatement = 62, + ForStatement = 67, + ForNumeric = 69, + ForGeneric = 70, + NameList = 71, + ExpList = 73, + FuncName = 75, + VarList = 79, + AttNameList = 81, + AttName = 82, + Attrib = 83, + ReturnStatement = 84 diff --git a/common/space_lua/parse.test.ts b/common/space_lua/parse.test.ts index 617e2fad..abda47a4 100644 --- a/common/space_lua/parse.test.ts +++ b/common/space_lua/parse.test.ts @@ -34,9 +34,50 @@ Deno.test("Test Lua parser", () => { parse(`e(func(), func(1, 2, 3), a.b(), a.b.c:hello(), (a.b)(7))`); // Function expression - parse(`function sayHi() -print("Hi") -end`); - parse(`e(function(a, b) end)`); + parse(`e(function(a, b) test() end)`); parse(`e(function(a, b, ...) end)`); + + // Statements + parse(`do end`); + parse(`do print() end`); + parse(`::hello:: + goto hello`); + parse(`while true do print() end`); + parse(`repeat print() until false`); + parse( + `if 1 == 2 then print() elseif 1 < 2 then print2() else print3() end`, + ); + parse(`if true then print() end`); + parse(`if true then print() else print2() end`); + parse(`if true then print() elseif false then print2() end`); + + // For loops + parse(`for i = 1, 10, 1 do print(i) end`); + parse(`for i = 1, 10 do print(i) end`); + parse(`for el in each({1, 2, 3}) do print(i) end`); + parse(`for i, l in 1, pairs() do print(i) end`); + + // Function statements + parse(`function a() end`); + parse(`function a:b() end`); + parse(`function a.b.c:d() end`); + parse(`function a.b.c() end`); + parse(`function hello(a, b) end`); + parse(`function hello(a, b, ...) end`); + parse(`local function hello() end`); + + // Assignments, local variables etc. + parse(`a = 1`); + parse(`a, b = 1, 2`); + parse(`a.b.c = 1`); + parse(`a["name"] = 1`); + parse(`local a, b`); + parse(`local a = 1`); + parse(`local a = 4`); + parse(`local a, b = 1, 2`); + + // Function calls + parse(`a(1, 2, 3)`); + parse(`print "Sup"`); + parse(`e(1 + print "8")`); }); diff --git a/common/space_lua/parse.ts b/common/space_lua/parse.ts index 9b0b3496..ed5e9083 100644 --- a/common/space_lua/parse.ts +++ b/common/space_lua/parse.ts @@ -52,7 +52,7 @@ export type LuaStatement = | LuaFunctionStatement | LuaLocalFunctionStatement | LuaAssignmentStatement - | LuaLocalAssignmentStatement + | LuaLocalStatement | LuaFunctionCallStatement; export type LuaSemicolonStatement = { @@ -121,7 +121,6 @@ export type LuaLocalFunctionStatement = { export type LuaFunctionName = { type: "FunctionName"; - name: string; propNames?: string[]; colonName?: string; }; @@ -134,20 +133,30 @@ export type LuaFunctionBody = { export type LuaAssignmentStatement = { type: "Assignment"; - variables: LuaExpression[]; + variables: LuaLValue[]; expressions: LuaExpression[]; }; -export type LuaLocalAssignmentStatement = { - type: "LocalAssignment"; - names: string[]; - expressions: LuaExpression[]; +export type LuaLValue = + | LuaVariable + | LuaPropertyAccessExpression + | LuaTableAccessExpression; + +export type LuaLocalStatement = { + type: "Local"; + names: LuaAttName[]; + expressions?: LuaExpression[]; +}; + +export type LuaAttName = { + type: "AttName"; + name: string; + attribute?: string; }; export type LuaFunctionCallStatement = { type: "FunctionCallStatement"; - name: string; - args: LuaExpression[]; + call: LuaFunctionCallExpression; }; // EXPRESSIONS @@ -290,18 +299,107 @@ function parseStatement(n: CrudeAST): LuaStatement { case "Semicolon": return { type: "Semicolon" }; case "Label": - return { type: "Label", name: t[1] as string }; + return { type: "Label", name: t[2][1] as string }; case "Break": return { type: "Break" }; case "Goto": - return { type: "Goto", name: t[1] as string }; + return { type: "Goto", name: t[2][1] as string }; + case "Scope": + return parseBlock(t[2]); + case ";": + return { type: "Semicolon" }; + case "WhileStatement": + return { + type: "While", + condition: parseExpression(t[2]), + block: parseBlock(t[4]), + }; + case "RepeatStatement": + return { + type: "Repeat", + block: parseBlock(t[2]), + condition: parseExpression(t[4]), + }; + case "IfStatement": { + const conditions: { condition: LuaExpression; block: LuaBlock }[] = + []; + let elseBlock: LuaBlock | undefined = undefined; + for (let i = 1; i < t.length; i += 4) { + console.log("Looking at", t[i]); + if (t[i][0] === "if" || t[i][0] === "elseif") { + conditions.push({ + condition: parseExpression(t[i + 1]), + block: parseBlock(t[i + 3]), + }); + } else if (t[i][0] === "else") { + elseBlock = parseBlock(t[i + 1]); + } else if (t[i][0] === "end") { + break; + } else { + throw new Error(`Unknown if clause type: ${t[i][0]}`); + } + } + return { + type: "If", + conditions, + elseBlock, + }; + } + case "ForStatement": + if (t[2][0] === "ForNumeric") { + const forNumeric = t[2] as [string, ...CrudeAST[]]; + return { + type: "For", + name: forNumeric[1][1] as string, + start: parseExpression(forNumeric[3]), + end: parseExpression(forNumeric[5]), + step: forNumeric[6] + ? parseExpression(forNumeric[7]) + : undefined, + block: parseBlock(t[4]), + }; + } else { + const forGeneric = t[2] as [string, ...CrudeAST[]]; + return { + type: "ForIn", + names: parseNameList(forGeneric[1]), + expressions: parseExpList(forGeneric[3]), + block: parseBlock(t[4]), + }; + } + case "Function": + return { + type: "Function", + name: parseFunctionName(t[2]), + body: parseFunctionBody(t[3]), + }; + case "LocalFunction": + return { + type: "LocalFunction", + name: t[3][1] as string, + body: parseFunctionBody(t[4]), + }; case "FunctionCall": return { type: "FunctionCallStatement", - name: t[1][1] as string, - args: t.slice(2, -1).filter((t) => - ![",", "(", ")"].includes(t[1] as string) - ).map(parseExpression), + call: parseExpression([ + "FunctionCall", + ...t.slice(1), + ]) as LuaFunctionCallExpression, + }; + case "Assign": + return { + type: "Assignment", + variables: (t[1].slice(1) as CrudeAST[]).filter((t) => + t[0] != "," + ).map(parseLValue), + expressions: parseExpList(t[3]), + }; + case "Local": + return { + type: "Local", + names: parseAttNames(t[2]), + expressions: t[4] ? parseExpList(t[4]) : [], }; default: console.error(t); @@ -309,6 +407,82 @@ function parseStatement(n: CrudeAST): LuaStatement { } } +function parseAttNames(n: CrudeAST): LuaAttName[] { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "AttNameList") { + throw new Error(`Expected AttNameList, got ${t[0]}`); + } + return t.slice(1).filter((t) => t[0] !== ",").map(parseAttName); +} + +function parseAttName(n: CrudeAST): LuaAttName { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "AttName") { + throw new Error(`Expected AttName, got ${t[0]}`); + } + return { + type: "AttName", + name: t[1][1] as string, + attribute: t[2][2] ? t[2][2][1] as string : undefined, + }; +} + +function parseLValue(n: CrudeAST): LuaLValue { + const t = n as [string, ...CrudeAST[]]; + switch (t[0]) { + case "Name": + return { type: "Variable", name: t[1] as string }; + case "Property": + return { + type: "PropertyAccess", + object: parsePrefixExpression(t[1]), + property: t[3][1] as string, + }; + case "MemberExpression": + return { + type: "TableAccess", + object: parsePrefixExpression(t[1]), + key: parseExpression(t[3]), + }; + default: + console.error(t); + throw new Error(`Unknown lvalue type: ${t[0]}`); + } +} + +function parseFunctionName(n: CrudeAST): LuaFunctionName { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "FuncName") { + throw new Error(`Expected FunctionName, got ${t[0]}`); + } + const propNames: string[] = []; + let colonName: string | undefined = undefined; + for (let i = 1; i < t.length; i += 2) { + propNames.push(t[i][1] as string); + if (t[i + 1] && t[i + 1][0] === ":") { + colonName = t[i + 2][1] as string; + break; + } + } + return { type: "FunctionName", propNames, colonName }; +} + +function parseNameList(n: CrudeAST): string[] { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "NameList") { + throw new Error(`Expected NameList, got ${t[0]}`); + } + return t.slice(1).filter((t) => t[0] === "Name").map((t) => t[1] as string); +} + +function parseExpList(n: CrudeAST): LuaExpression[] { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "ExpList") { + throw new Error(`Expected ExpList, got ${t[0]}`); + } + return t.slice(1).filter((t) => t[0] !== ",").map(parseExpression); +} + function parseExpression(n: CrudeAST): LuaExpression { const t = n as [string, ...CrudeAST[]]; switch (t[0]) { @@ -348,17 +522,20 @@ function parseExpression(n: CrudeAST): LuaExpression { type: "FunctionCall", prefix: parsePrefixExpression(t[1]), name: t[3][1] as string, - args: t.slice(4, -1).filter((t) => - ![",", "(", ")"].includes(t[1] as string) - ).map(parseExpression), + args: parseFunctionArgs(t.slice(4)), }; } return { type: "FunctionCall", prefix: parsePrefixExpression(t[1]), - args: t.slice(3, -1).filter((t) => - ![",", "(", ")"].includes(t[1] as string) - ).map(parseExpression), + args: parseFunctionArgs(t.slice(2)), + }; + } + case "FunctionDef": { + const body = parseFunctionBody(t[2]); + return { + type: "FunctionDefinition", + body, }; } case "Name": @@ -385,6 +562,28 @@ function parseExpression(n: CrudeAST): LuaExpression { } } +function parseFunctionArgs(n: CrudeAST[]): LuaExpression[] { + console.log("Parsing function args", n); + return n.filter((t) => ![",", "(", ")"].includes(t[0])).map( + parseExpression, + ); +} + +function parseFunctionBody(n: CrudeAST): LuaFunctionBody { + const t = n as [string, ...CrudeAST[]]; + if (t[0] !== "FuncBody") { + throw new Error(`Expected FunctionBody, got ${t[0]}`); + } + return { + type: "FunctionBody", + parameters: (t[2] as CrudeAST[]).slice(1).filter((t) => + ["Name", "Ellipsis"].includes(t[0]) + ) + .map((t) => t[1] as string), + block: parseBlock(t[4]), + }; +} + function parsePrefixExpression(n: CrudeAST): LuaPrefixExpression { const t = n as [string, ...CrudeAST[]]; switch (t[0]) {