aboutsummaryrefslogtreecommitdiff
path: root/src/MoonP/moon_parser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/MoonP/moon_parser.cpp')
-rw-r--r--src/MoonP/moon_parser.cpp526
1 files changed, 526 insertions, 0 deletions
diff --git a/src/MoonP/moon_parser.cpp b/src/MoonP/moon_parser.cpp
new file mode 100644
index 0000000..7b5183e
--- /dev/null
+++ b/src/MoonP/moon_parser.cpp
@@ -0,0 +1,526 @@
1/* Copyright (c) 2020 Jin Li, http://www.luvfight.me
2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
5The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
7THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
8
9#include "MoonP/moon_parser.h"
10
11namespace pl = parserlib;
12
13namespace MoonP {
14
15std::unordered_set<std::string> State::luaKeywords = {
16 "and", "break", "do", "else", "elseif",
17 "end", "false", "for", "function", "if",
18 "in", "local", "nil", "not", "or",
19 "repeat", "return", "then", "true", "until",
20 "while"
21};
22
23std::unordered_set<std::string> State::keywords = {
24 "and", "break", "do", "else", "elseif",
25 "end", "false", "for", "function", "if",
26 "in", "local", "nil", "not", "or",
27 "repeat", "return", "then", "true", "until",
28 "while", // Lua keywords
29 "class", "continue", "export", "extends", "from",
30 "import", "switch", "unless", "using", "when",
31 "with" // Moon keywords
32};
33
34rule plain_space = *set(" \t");
35rule Break = nl(-expr('\r') >> '\n');
36rule Any = Break | any();
37rule White = *(set(" \t") | Break);
38rule Stop = Break | eof();
39rule Comment = "--" >> *(not_(set("\r\n")) >> Any) >> and_(Stop);
40rule Indent = *set(" \t");
41rule Space = plain_space >> -Comment;
42rule SomeSpace = +set(" \t") >> -Comment;
43rule SpaceBreak = Space >> Break;
44rule EmptyLine = SpaceBreak;
45rule AlphaNum = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_';
46rule Name = (range('a', 'z') | range('A', 'Z') | '_') >> *AlphaNum;
47rule Num =
48(
49 "0x" >>
50 +(range('0', '9') | range('a', 'f') | range('A', 'F')) >>
51 -(-set("uU") >> set("lL") >> set("lL"))
52) | (
53 +range('0', '9') >> -set("uU") >> set("lL") >> set("lL")
54) | (
55 (
56 (+range('0', '9') >> -('.' >> +range('0', '9'))) |
57 ('.' >> +range('0', '9'))
58 ) >> -(set("eE") >> -expr('-') >> +range('0', '9'))
59);
60rule Cut = false_();
61rule Seperator = true_();
62
63#define sym(str) (Space >> str)
64#define symx(str) expr(str)
65#define ensure(patt, finally) (((patt) >> (finally)) | ((finally) >> (Cut)))
66#define key(str) (Space >> str >> not_(AlphaNum))
67
68rule Variable = pl::user(Name, [](const item_t& item) {
69 State* st = reinterpret_cast<State*>(item.user_data);
70 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
71 auto it = State::keywords.find(st->buffer);
72 st->buffer.clear();
73 return it == State::keywords.end();
74});
75
76rule LuaKeyword = pl::user(Name, [](const item_t& item) {
77 State* st = reinterpret_cast<State*>(item.user_data);
78 for (auto it = item.begin; it != item.end; ++it) st->buffer += static_cast<char>(*it);
79 auto it = State::luaKeywords.find(st->buffer);
80 st->buffer.clear();
81 return it != State::luaKeywords.end();
82});
83
84rule self = expr('@');
85rule self_name = '@' >> Name;
86rule self_class = expr("@@");
87rule self_class_name = "@@" >> Name;
88
89rule SelfName = Space >> (self_class_name | self_class | self_name | self);
90rule KeyName = SelfName | Space >> Name;
91rule VarArg = Space >> "...";
92
93rule check_indent = pl::user(Indent, [](const item_t& item) {
94 int indent = 0;
95 for (input_it i = item.begin; i != item.end; ++i) {
96 switch (*i) {
97 case ' ': indent++; break;
98 case '\t': indent += 4; break;
99 }
100 }
101 State* st = reinterpret_cast<State*>(item.user_data);
102 return st->indents.top() == indent;
103});
104rule CheckIndent = and_(check_indent);
105
106rule advance = pl::user(Indent, [](const item_t& item) {
107 int indent = 0;
108 for (input_it i = item.begin; i != item.end; ++i) {
109 switch (*i) {
110 case ' ': indent++; break;
111 case '\t': indent += 4; break;
112 }
113 }
114 State* st = reinterpret_cast<State*>(item.user_data);
115 int top = st->indents.top();
116 if (top != -1 && indent > top) {
117 st->indents.push(indent);
118 return true;
119 }
120 return false;
121});
122rule Advance = and_(advance);
123
124rule push_indent = pl::user(Indent, [](const item_t& item) {
125 int indent = 0;
126 for (input_it i = item.begin; i != item.end; ++i) {
127 switch (*i) {
128 case ' ': indent++; break;
129 case '\t': indent += 4; break;
130 }
131 }
132 State* st = reinterpret_cast<State*>(item.user_data);
133 st->indents.push(indent);
134 return true;
135});
136rule PushIndent = and_(push_indent);
137
138rule PreventIndent = pl::user(true_(), [](const item_t& item) {
139 State* st = reinterpret_cast<State*>(item.user_data);
140 st->indents.push(-1);
141 return true;
142});
143
144rule PopIndent = pl::user(true_(), [](const item_t& item) {
145 State* st = reinterpret_cast<State*>(item.user_data);
146 st->indents.pop();
147 return true;
148});
149
150extern rule Block;
151
152rule InBlock = Advance >> Block >> PopIndent;
153
154extern rule NameList;
155
156rule local_flag = expr('*') | expr('^');
157rule Local = key("local") >> ((Space >> local_flag) | NameList);
158
159rule colon_import_name = sym('\\') >> Space >> Variable;
160rule ImportName = colon_import_name | Space >> Variable;
161rule ImportNameList = Seperator >> *SpaceBreak >> ImportName >> *((+SpaceBreak | sym(',') >> *SpaceBreak) >> ImportName);
162
163extern rule Exp;
164
165rule Import = key("import") >> ImportNameList >> *SpaceBreak >> key("from") >> Exp;
166rule BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum);
167
168extern rule ExpListLow, ExpList, Assign;
169
170rule Return = key("return") >> -ExpListLow;
171rule WithExp = ExpList >> -Assign;
172
173extern rule DisableDo, PopDo, Body;
174
175rule With = key("with") >> DisableDo >> ensure(WithExp, PopDo) >> -key("do") >> Body;
176rule SwitchCase = key("when") >> ExpList >> -key("then") >> Body;
177rule SwitchElse = key("else") >> Body;
178
179rule SwitchBlock = *EmptyLine >>
180 Advance >> Seperator >>
181 SwitchCase >>
182 *(+SpaceBreak >> SwitchCase) >>
183 -(+SpaceBreak >> SwitchElse) >>
184 PopIndent;
185
186rule Switch = key("switch") >>
187 DisableDo >> ensure(Exp, PopDo) >>
188 -key("do") >> -Space >> Break >> SwitchBlock;
189
190rule IfCond = Exp >> -Assign;
191rule IfElseIf = -(Break >> *EmptyLine >> CheckIndent) >> key("elseif") >> IfCond >> -key("then") >> Body;
192rule IfElse = -(Break >> *EmptyLine >> CheckIndent) >> key("else") >> Body;
193rule If = key("if") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
194rule Unless = key("unless") >> Seperator >> IfCond >> -key("then") >> Body >> *IfElseIf >> -IfElse;
195
196rule While = key("while") >> DisableDo >> ensure(Exp, PopDo) >> -key("do") >> Body;
197
198rule for_step_value = sym(',') >> Exp;
199rule for_args = Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
200
201rule For = key("for") >> DisableDo >>
202 ensure(for_args, PopDo) >>
203 -key("do") >> Body;
204
205extern rule AssignableNameList;
206
207extern rule star_exp;
208
209rule for_in = star_exp | ExpList;
210
211rule ForEach = key("for") >> AssignableNameList >> key("in") >>
212 DisableDo >> ensure(for_in, PopDo) >>
213 -key("do") >> Body;
214
215rule Do = pl::user(key("do") >> Body, [](const item_t& item)
216{
217 State* st = reinterpret_cast<State*>(item.user_data);
218 return st->doStack.empty() || st->doStack.top();
219});
220
221rule DisableDo = pl::user(true_(), [](const item_t& item)
222{
223 State* st = reinterpret_cast<State*>(item.user_data);
224 st->doStack.push(false);
225 return true;
226});
227
228rule PopDo = pl::user(true_(), [](const item_t& item)
229{
230 State* st = reinterpret_cast<State*>(item.user_data);
231 st->doStack.pop();
232 return true;
233});
234
235extern rule CompInner;
236
237rule Comprehension = sym('[') >> Exp >> CompInner >> sym(']');
238rule comp_value = sym(',') >> Exp;
239rule TblComprehension = sym('{') >> (Exp >> -comp_value) >> CompInner >> sym('}');
240
241extern rule CompForEach, CompFor, CompClause;
242
243rule CompInner = Seperator >> (CompForEach | CompFor) >> *CompClause;
244rule star_exp = sym('*') >> Exp;
245rule CompForEach = key("for") >> AssignableNameList >> key("in") >> (star_exp | Exp);
246rule CompFor = key("for") >> Space >> Variable >> sym('=') >> Exp >> sym(',') >> Exp >> -for_step_value;
247rule CompClause = CompFor | CompForEach | key("when") >> Exp;
248
249extern rule TableBlock;
250
251rule Assign = sym('=') >> Seperator >> (With | If | Switch | TableBlock | Exp >> *((sym(',') | sym(';')) >> Exp));
252
253rule update_op =
254 expr("..") |
255 expr("+") |
256 expr("-") |
257 expr("*") |
258 expr("/") |
259 expr("%") |
260 expr("or") |
261 expr("and") |
262 expr("&") |
263 expr("|") |
264 expr(">>") |
265 expr("<<");
266
267rule Update = Space >> update_op >> expr("=") >> Exp;
268
269rule BinaryOperator =
270 (expr("or") >> not_(AlphaNum)) |
271 (expr("and") >> not_(AlphaNum)) |
272 expr("<=") |
273 expr(">=") |
274 expr("~=") |
275 expr("!=") |
276 expr("==") |
277 expr("..") |
278 expr("<<") |
279 expr(">>") |
280 expr("//") |
281 set("+-*/%^><|&");
282
283extern rule AssignableChain;
284
285rule Assignable = AssignableChain | Space >> Variable | SelfName;
286
287extern rule Value;
288
289rule exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> Value;
290rule Exp = Value >> *exp_op_value;
291
292extern rule Chain, Callable, InvokeArgs;
293
294rule ChainValue = Seperator >> (Chain | Callable) >> -InvokeArgs;
295
296extern rule KeyValue, String, SimpleValue;
297
298rule simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
299rule Value = SimpleValue | simple_table | ChainValue | String;
300
301extern rule LuaString;
302
303rule single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any;
304rule SingleString = symx('\'') >> *single_string_inner >> sym('\'');
305rule interp = symx("#{") >> Exp >> sym('}');
306rule double_string_plain = expr("\\\"") | "\\\\" | not_(expr('"')) >> Any;
307rule double_string_inner = +(not_(interp) >> double_string_plain);
308rule double_string_content = double_string_inner | interp;
309rule DoubleString = symx('"') >> Seperator >> *double_string_content >> sym('"');
310rule String = Space >> (DoubleString | SingleString | LuaString);
311
312rule lua_string_open = '[' >> *expr('=') >> '[';
313rule lua_string_close = ']' >> *expr('=') >> ']';
314
315rule LuaStringOpen = pl::user(lua_string_open, [](const item_t& item)
316{
317 size_t count = std::distance(item.begin, item.end);
318 State* st = reinterpret_cast<State*>(item.user_data);
319 st->stringOpen = count;
320 return true;
321});
322
323rule LuaStringClose = pl::user(lua_string_close, [](const item_t& item)
324{
325 size_t count = std::distance(item.begin, item.end);
326 State* st = reinterpret_cast<State*>(item.user_data);
327 return st->stringOpen == count;
328});
329
330rule LuaStringContent = *(not_(LuaStringClose) >> (Break | Any));
331
332rule LuaString = pl::user(LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose, [](const item_t& item)
333{
334 State* st = reinterpret_cast<State*>(item.user_data);
335 st->stringOpen = -1;
336 return true;
337});
338
339rule Parens = sym('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')');
340rule Callable = Space >> Variable | SelfName | VarArg | Parens;
341rule FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp);
342
343rule FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) |
344 (sym('!') >> not_(expr('=')));
345
346extern rule ChainItems, DotChainItem, ColonChain;
347
348rule chain_call = (Callable | String) >> ChainItems;
349rule chain_item = and_(set(".\\")) >> ChainItems;
350rule chain_dot_chain = DotChainItem >> -ChainItems;
351
352rule Chain = chain_call | chain_item |
353 Space >> (chain_dot_chain | ColonChain);
354
355rule AssignableChain = Seperator >> Chain;
356
357extern rule ChainItem;
358
359rule chain_with_colon = +ChainItem >> -ColonChain;
360rule ChainItems = chain_with_colon | ColonChain;
361
362extern rule Invoke, Slice;
363
364rule Index = symx('[') >> Exp >> sym(']');
365rule ChainItem = Invoke | DotChainItem | Slice | Index;
366rule DotChainItem = symx('.') >> Name;
367rule ColonChainItem = symx('\\') >> (LuaKeyword | Name);
368rule invoke_chain = Invoke >> -ChainItems;
369rule ColonChain = ColonChainItem >> -invoke_chain;
370
371rule default_value = true_();
372rule Slice =
373 symx('[') >>
374 (Exp | default_value) >>
375 sym(',') >>
376 (Exp | default_value) >>
377 (sym(',') >> Exp | default_value) >>
378 sym(']');
379
380rule Invoke = Seperator >> (
381 FnArgs |
382 SingleString |
383 DoubleString |
384 and_(expr('[')) >> LuaString);
385
386extern rule TableValueList, TableLitLine;
387
388rule TableValue = KeyValue | Exp;
389
390rule table_lit_lines = SpaceBreak >> TableLitLine >> *(-sym(',') >> SpaceBreak >> TableLitLine) >> -sym(',');
391
392rule TableLit =
393 sym('{') >> Seperator >>
394 -TableValueList >>
395 -sym(',') >>
396 -table_lit_lines >>
397 White >> sym('}');
398
399rule TableValueList = TableValue >> *(sym(',') >> TableValue);
400
401rule TableLitLine =
402(
403 PushIndent >> (TableValueList >> PopIndent | PopIndent)
404) | (
405 Space
406);
407
408extern rule KeyValueLine;
409
410rule TableBlockInner = Seperator >> KeyValueLine >> *(+(SpaceBreak) >> KeyValueLine);
411rule TableBlock = +(SpaceBreak) >> Advance >> ensure(TableBlockInner, PopIndent);
412
413extern rule Statement;
414
415rule class_member_list = Seperator >> KeyValue >> *(sym(',') >> KeyValue);
416rule ClassLine = CheckIndent >> (class_member_list | Statement) >> -sym(',');
417rule ClassBlock = +(SpaceBreak) >> Advance >>Seperator >> ClassLine >> *(+(SpaceBreak) >> ClassLine) >> PopIndent;
418
419rule ClassDecl =
420 key("class") >> not_(expr(':')) >>
421 -Assignable >>
422 -(key("extends") >> PreventIndent >> ensure(Exp, PopIndent)) >>
423 -ClassBlock;
424
425rule export_values = NameList >> -(sym('=') >> ExpListLow);
426rule export_op = expr('*') | expr('^');
427rule Export = key("export") >> (ClassDecl | (Space >> export_op) | export_values);
428
429rule variable_pair = sym(':') >> not_(SomeSpace) >> Space >> Variable;
430
431rule normal_pair =
432(
433 KeyName |
434 sym('[') >> Exp >> sym(']') |
435 Space >> DoubleString |
436 Space >> SingleString
437) >>
438symx(':') >>
439(Exp | TableBlock | +(SpaceBreak) >> Exp);
440
441rule KeyValue = variable_pair | normal_pair;
442
443rule KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
444rule KeyValueLine = CheckIndent >> KeyValueList >> -sym(',');
445
446rule FnArgDef = (Space >> Variable | SelfName) >> -(sym('=') >> Exp);
447
448rule FnArgDefList = Seperator >>
449(
450 (
451 FnArgDef >>
452 *((sym(',') | Break) >> White >> FnArgDef) >>
453 -((sym(',') | Break) >> White >> VarArg)
454 ) | (
455 VarArg
456 )
457);
458
459rule outer_var_shadow = key("using") >> (NameList | Space >> expr("nil"));
460
461rule FnArgsDef = sym('(') >> White >> -FnArgDefList >> -outer_var_shadow >> White >> sym(')');
462rule fn_arrow = expr("->") | expr("=>");
463rule FunLit = -FnArgsDef >> Space >> fn_arrow >> -Body;
464
465rule NameList = Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable);
466rule NameOrDestructure = Space >> Variable | TableLit;
467rule AssignableNameList = Seperator >> NameOrDestructure >> *(sym(',') >> NameOrDestructure);
468
469rule ExpList = Seperator >> Exp >> *(sym(',') >> Exp);
470rule ExpListLow = Seperator >> Exp >> *((sym(',') | sym(';')) >> Exp);
471
472rule ArgLine = CheckIndent >> Exp >> *(sym(',') >> Exp);
473rule ArgBlock = ArgLine >> *(sym(',') >> SpaceBreak >> ArgLine) >> PopIndent;
474
475rule invoke_args_with_table =
476 sym(',') >>
477 (
478 TableBlock |
479 SpaceBreak >> Advance >> ArgBlock >> -TableBlock
480 );
481
482rule InvokeArgs =
483 not_(expr('-')) >> Seperator >>
484 (
485 Exp >> *(sym(',') >> Exp) >> -(invoke_args_with_table | TableBlock) |
486 TableBlock
487 );
488
489rule const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum);
490rule minus_exp = expr('-') >> not_(SomeSpace) >> Exp;
491rule sharp_exp = expr('#') >> Exp;
492rule tilde_exp = expr('~') >> Exp;
493rule not_exp = expr("not") >> not_(AlphaNum) >> Exp;
494rule unary_exp = minus_exp | sharp_exp | tilde_exp | not_exp;
495
496rule SimpleValue =
497 (Space >> const_value) |
498 If | Unless | Switch | With | ClassDecl | ForEach | For | While | Do |
499 (Space >> unary_exp) |
500 TblComprehension | TableLit | Comprehension | FunLit |
501 (Space >> Num);
502
503rule ExpListAssign = ExpList >> -(Update | Assign);
504
505rule if_else_line = key("if") >> Exp >> (key("else") >> Exp | default_value);
506rule unless_line = key("unless") >> Exp;
507
508rule statement_appendix = (if_else_line | unless_line | CompInner) >> Space;
509rule Statement =
510(
511 Import | While | For | ForEach |
512 Return | Local | Export | Space >> BreakLoop |
513 ExpListAssign
514) >> Space >>
515-statement_appendix;
516
517rule Body = -Space >> Break >> *EmptyLine >> InBlock | Statement;
518
519rule empty_line_stop = Space >> and_(Stop);
520rule Line = CheckIndent >> Statement | empty_line_stop;
521rule Block = Seperator >> Line >> *(+Break >> Line);
522
523rule Shebang = expr("#!") >> *(not_(Stop) >> Any);
524rule File = White >> -Shebang >> Block >> eof();
525
526} // namespace MoonP