diff options
author | Li Jin <dragon-fly@qq.com> | 2017-07-05 14:30:02 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2017-07-05 14:30:02 +0800 |
commit | 2dc481058998344b7f97721d47987be3ac053768 (patch) | |
tree | 9afd61edfc6d3f079262a3086ebef8cb70943a31 /MoonParser/main.cpp | |
parent | 2d074d650ead2142857ff9f8b192b061d1506eca (diff) | |
download | yuescript-2dc481058998344b7f97721d47987be3ac053768.tar.gz yuescript-2dc481058998344b7f97721d47987be3ac053768.tar.bz2 yuescript-2dc481058998344b7f97721d47987be3ac053768.zip |
Learn PEGTL a little.
Diffstat (limited to 'MoonParser/main.cpp')
-rw-r--r-- | MoonParser/main.cpp | 1399 |
1 files changed, 1399 insertions, 0 deletions
diff --git a/MoonParser/main.cpp b/MoonParser/main.cpp new file mode 100644 index 0000000..332b1b4 --- /dev/null +++ b/MoonParser/main.cpp | |||
@@ -0,0 +1,1399 @@ | |||
1 | // | ||
2 | // main.cpp | ||
3 | // PegtlStudy | ||
4 | // | ||
5 | // Created by Li Jin on 2017/6/16. | ||
6 | // Copyright © 2017年 Li Jin. All rights reserved. | ||
7 | // | ||
8 | |||
9 | #include <iostream> | ||
10 | #include <unordered_set> | ||
11 | #include <vector> | ||
12 | #include <queue> | ||
13 | #include <stack> | ||
14 | #include "pegtl.hpp" | ||
15 | #include "pegtl/analyze.hpp" | ||
16 | #include "slice.h" | ||
17 | using namespace silly; | ||
18 | |||
19 | using namespace tao::pegtl; | ||
20 | |||
21 | namespace helloworld // with operator precedence climbing | ||
22 | { | ||
23 | struct Stack | ||
24 | { | ||
25 | Stack() | ||
26 | { | ||
27 | pushStack(); | ||
28 | } | ||
29 | void pushValue(int value) | ||
30 | { | ||
31 | _values.back().push(value); | ||
32 | } | ||
33 | void pushOp(char op) | ||
34 | { | ||
35 | _ops.back().push(op); | ||
36 | } | ||
37 | void pushStack() | ||
38 | { | ||
39 | _values.emplace_back(); | ||
40 | _ops.emplace_back(); | ||
41 | } | ||
42 | int getPriority(char op) | ||
43 | { | ||
44 | switch (op) | ||
45 | { | ||
46 | case '+': return 1; | ||
47 | case '-': return 1; | ||
48 | case '*': return 2; | ||
49 | case '/': return 2; | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | /* | ||
54 | def compute_expr(tokenizer, min_prec): | ||
55 | atom_lhs = tokenizer.get_next_token() | ||
56 | |||
57 | while True: | ||
58 | cur = tokenizer.cur_token | ||
59 | if (cur is None or OPINFO_MAP[cur.value].prec < min_prec): | ||
60 | break | ||
61 | |||
62 | op = cur.value | ||
63 | prec, assoc = OPINFO_MAP[op] | ||
64 | next_min_prec = prec + 1 if assoc == 'LEFT' else prec | ||
65 | |||
66 | atom_rhs = compute_expr(tokenizer, next_min_prec) | ||
67 | |||
68 | atom_lhs = compute_op(op, atom_lhs, atom_rhs) | ||
69 | |||
70 | return atom_lhs | ||
71 | */ | ||
72 | int parseNext(int minPrecedence) | ||
73 | { | ||
74 | int lhs = _values.back().front(); | ||
75 | _values.back().pop(); | ||
76 | |||
77 | while (true) | ||
78 | { | ||
79 | if (_ops.back().empty()) | ||
80 | { | ||
81 | break; | ||
82 | } | ||
83 | char op = _ops.back().front(); | ||
84 | if (getPriority(op) < minPrecedence) | ||
85 | { | ||
86 | break; | ||
87 | } | ||
88 | _ops.back().pop(); | ||
89 | int nextMinPrecedence = getPriority(op) + 1; | ||
90 | int rhs = parseNext(nextMinPrecedence); | ||
91 | switch (op) | ||
92 | { | ||
93 | case '+': | ||
94 | std::cout << lhs << " + " << rhs << " = " << lhs+rhs << '\n'; | ||
95 | lhs = lhs + rhs; | ||
96 | break; | ||
97 | case '-': | ||
98 | std::cout << lhs << " - " << rhs << " = " << lhs-rhs << '\n'; | ||
99 | lhs = lhs - rhs; | ||
100 | break; | ||
101 | case '*': | ||
102 | std::cout << lhs << " * " << rhs << " = " << lhs*rhs << '\n'; | ||
103 | lhs = lhs * rhs; | ||
104 | break; | ||
105 | case '/': | ||
106 | std::cout << lhs << " / " << rhs << " = " << lhs/rhs << '\n'; | ||
107 | lhs = lhs / rhs; | ||
108 | break; | ||
109 | } | ||
110 | } | ||
111 | return lhs; | ||
112 | } | ||
113 | void popStack() | ||
114 | { | ||
115 | int value = parseNext(0); | ||
116 | _values.pop_back(); | ||
117 | if (_values.empty()) | ||
118 | { | ||
119 | _values.emplace_back(); | ||
120 | } | ||
121 | _ops.pop_back(); | ||
122 | if (_ops.empty()) | ||
123 | { | ||
124 | _ops.emplace_back(); | ||
125 | } | ||
126 | pushValue(value); | ||
127 | } | ||
128 | int getValue() const | ||
129 | { | ||
130 | return _values.back().back(); | ||
131 | } | ||
132 | private: | ||
133 | std::vector<std::queue<char>> _ops; | ||
134 | std::vector<std::queue<int>> _values; | ||
135 | }; | ||
136 | |||
137 | struct number : seq<opt<one<'+', '-'>>, plus<digit>> { }; | ||
138 | |||
139 | struct expr; | ||
140 | |||
141 | struct bracket : if_must<one<'('>, expr, one<')'>> { }; | ||
142 | |||
143 | struct atomic : sor<number, bracket> { }; | ||
144 | |||
145 | struct op : one<'+', '-', '*', '/'> { }; | ||
146 | |||
147 | struct expr : list<atomic, op, space> { }; | ||
148 | |||
149 | template<typename Rule> | ||
150 | struct action : nothing<Rule> { }; | ||
151 | |||
152 | template<> | ||
153 | struct action<number> | ||
154 | { | ||
155 | template<typename Input> | ||
156 | static void apply(const Input& in, Stack& stack) | ||
157 | { | ||
158 | stack.pushValue(std::stoi(in.string())); | ||
159 | } | ||
160 | }; | ||
161 | |||
162 | template<> | ||
163 | struct action<op> | ||
164 | { | ||
165 | template<typename Input> | ||
166 | static void apply(const Input& in, Stack& stack) | ||
167 | { | ||
168 | stack.pushOp(*in.begin()); | ||
169 | } | ||
170 | }; | ||
171 | |||
172 | template<> | ||
173 | struct action<one<'('>> | ||
174 | { | ||
175 | static void apply0(Stack& stack) | ||
176 | { | ||
177 | stack.pushStack(); | ||
178 | } | ||
179 | }; | ||
180 | |||
181 | template<> | ||
182 | struct action<expr> | ||
183 | { | ||
184 | template<typename Input> | ||
185 | static void apply(const Input& in, Stack& stack) | ||
186 | { | ||
187 | stack.popStack(); | ||
188 | } | ||
189 | }; | ||
190 | |||
191 | } // namespace hello | ||
192 | |||
193 | namespace moon | ||
194 | { | ||
195 | struct State | ||
196 | { | ||
197 | State() | ||
198 | { | ||
199 | indents.push(0); | ||
200 | stringOpen = -1; | ||
201 | } | ||
202 | size_t stringOpen; | ||
203 | std::stack<int> indents; | ||
204 | std::stack<bool> doStack; | ||
205 | std::unordered_set<std::string> keywords = | ||
206 | { | ||
207 | "and", "while", "else", "using", "continue", | ||
208 | "local", "not", "then", "return", "from", | ||
209 | "extends", "for", "do", "or", "export", | ||
210 | "class", "in", "unless", "when", "elseif", | ||
211 | "switch", "break", "if", "with", "import" | ||
212 | }; | ||
213 | }; | ||
214 | |||
215 | struct White : star<one<' ', '\t', '\r', '\n'>> {}; | ||
216 | struct plain_space : star<one<' ', '\t'>> {}; | ||
217 | struct Break : seq<opt<one<'\r'>>, one<'\n'>> {}; | ||
218 | struct Stop : sor<Break, eof> {}; | ||
219 | struct Comment : seq<string<'-', '-'>, star<not_one<'\r', '\n'>>, Stop> {}; | ||
220 | struct Indent : star<one<' ', '\t'>> {}; | ||
221 | struct Space : seq<plain_space, opt<Comment>> {}; | ||
222 | struct SomeSpace : seq<plus<blank>, opt<Comment>> {}; | ||
223 | struct SpaceBreak : seq<Space, Break> {}; | ||
224 | typedef SpaceBreak EmptyLine; | ||
225 | struct AlphaNum : ranges<'a', 'z', 'A', 'Z', '0', '9', '_', '_'> {}; | ||
226 | struct _Name : seq<ranges<'a', 'z', 'A', 'Z', '_', '_'>, star<AlphaNum>> {}; | ||
227 | struct SpaceName : seq<Space, _Name> {}; | ||
228 | struct _Num : sor< | ||
229 | seq< | ||
230 | string<'0' ,'x'>, | ||
231 | plus<ranges<'0', '9', 'a', 'f', 'A', 'F'>>, | ||
232 | opt<seq< | ||
233 | opt<one<'u', 'U'>>, one<'l', 'L'>, one<'l', 'L'> | ||
234 | >> | ||
235 | >, | ||
236 | seq< | ||
237 | plus<range<'0', '9'>>, | ||
238 | seq< | ||
239 | opt<one<'u', 'U'>>, one<'l', 'L'>, one<'l', 'L'> | ||
240 | > | ||
241 | >, | ||
242 | seq< | ||
243 | sor< | ||
244 | seq< | ||
245 | plus<range<'0', '9'>>, | ||
246 | opt<seq< | ||
247 | one<'.'>, plus<range<'0', '9'>> | ||
248 | >> | ||
249 | >, | ||
250 | seq< | ||
251 | one<'.'>, | ||
252 | plus<range<'0', '9'>> | ||
253 | > | ||
254 | >, | ||
255 | opt<seq< | ||
256 | one<'e', 'E'>, opt<one<'-'>>, plus<range<'0', '9'>> | ||
257 | >> | ||
258 | > | ||
259 | > {}; | ||
260 | struct Num : seq<Space, _Num> {}; | ||
261 | |||
262 | struct Cut : failure {}; | ||
263 | |||
264 | template<char... Cs> struct sym : seq<Space, string<Cs...>> {}; | ||
265 | template<char... Cs> struct symx : string<Cs...> {}; | ||
266 | |||
267 | template<typename patt, typename finally> | ||
268 | struct ensure : sor<seq<patt, finally>, seq<finally, Cut>> {}; | ||
269 | |||
270 | template<char... Cs> struct key : seq<Space, string<Cs...>, not_at<AlphaNum>> {}; | ||
271 | template<char... Cs> struct op : seq<Space, string<Cs...>, not_at<AlphaNum>> {}; | ||
272 | |||
273 | struct Name | ||
274 | { | ||
275 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
276 | |||
277 | template<apply_mode A, rewind_mode M, | ||
278 | template<typename...> class Action, | ||
279 | template<typename...> class Control, | ||
280 | typename Input> | ||
281 | static bool match(Input& in, const State& st) | ||
282 | { | ||
283 | const char* current = in.current(); | ||
284 | if (SpaceName::match<A, M, Action, Control>(in, st)) | ||
285 | { | ||
286 | auto name = slice::Slice(current, in.current() - current + 1); | ||
287 | name.trimSpace(); | ||
288 | auto it = st.keywords.find(name); | ||
289 | if (it == st.keywords.end()) | ||
290 | { | ||
291 | return true; | ||
292 | } | ||
293 | } | ||
294 | return false; | ||
295 | } | ||
296 | }; | ||
297 | |||
298 | struct self : one<'@'> {}; | ||
299 | struct self_name : seq<one<'@'>, _Name> {}; | ||
300 | struct self_class : string<'@', '@'> {}; | ||
301 | struct self_class_name : seq<string<'@', '@'>, _Name> {}; | ||
302 | |||
303 | struct SelfName : seq<Space, sor<self_class_name, self_class, self_name, self>> {}; | ||
304 | struct KeyName : sor<SelfName, SpaceName> {}; | ||
305 | struct VarArg : seq<Space, string<'.', '.', '.'>> {}; | ||
306 | |||
307 | struct CheckIndent | ||
308 | { | ||
309 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
310 | |||
311 | template<apply_mode A, rewind_mode M, | ||
312 | template<typename...> class Action, | ||
313 | template<typename...> class Control, | ||
314 | typename Input> | ||
315 | static bool match(Input& in, const State& st) | ||
316 | { | ||
317 | const char* current = in.current(); | ||
318 | if (Indent::match<A, M, Action, Control>(in, st)) | ||
319 | { | ||
320 | int indent = 0; | ||
321 | for (const char* ch = current; ch < in.current(); ch++) | ||
322 | { | ||
323 | switch (*ch) | ||
324 | { | ||
325 | case ' ': indent++; break; | ||
326 | case '\t': indent += 4; break; | ||
327 | } | ||
328 | } | ||
329 | return st.indents.top() == indent; | ||
330 | } | ||
331 | return false; | ||
332 | } | ||
333 | }; | ||
334 | |||
335 | struct Advance | ||
336 | { | ||
337 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
338 | |||
339 | template<apply_mode A, rewind_mode M, | ||
340 | template<typename...> class Action, | ||
341 | template<typename...> class Control, | ||
342 | typename Input> | ||
343 | static bool match(Input& in, State& st) | ||
344 | { | ||
345 | const char* current = in.current(); | ||
346 | if (Indent::match<A, M, Action, Control>(in)) | ||
347 | { | ||
348 | int indent = 0; | ||
349 | for (const char* ch = current; ch < in.current(); ch++) | ||
350 | { | ||
351 | switch (*ch) | ||
352 | { | ||
353 | case ' ': indent++; break; | ||
354 | case '\t': indent += 4; break; | ||
355 | } | ||
356 | } | ||
357 | int top = st.indents.top(); | ||
358 | if (top != -1 && indent > top) | ||
359 | { | ||
360 | st.indents.push(indent); | ||
361 | } | ||
362 | return true; | ||
363 | } | ||
364 | return false; | ||
365 | } | ||
366 | }; | ||
367 | |||
368 | struct PushIndent | ||
369 | { | ||
370 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
371 | |||
372 | template<apply_mode A, rewind_mode M, | ||
373 | template<typename...> class Action, | ||
374 | template<typename...> class Control, | ||
375 | typename Input> | ||
376 | static bool match(Input& in, State& st) | ||
377 | { | ||
378 | const char* current = in.current(); | ||
379 | if (Indent::match<A, M, Action, Control>(in)) | ||
380 | { | ||
381 | int indent = 0; | ||
382 | for (const char* ch = current; ch < in.current(); ch++) | ||
383 | { | ||
384 | switch (*ch) | ||
385 | { | ||
386 | case ' ': indent++; break; | ||
387 | case '\t': indent += 4; break; | ||
388 | } | ||
389 | } | ||
390 | st.indents.push(indent); | ||
391 | return true; | ||
392 | } | ||
393 | return false; | ||
394 | } | ||
395 | }; | ||
396 | |||
397 | struct PreventIndent | ||
398 | { | ||
399 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
400 | |||
401 | template<apply_mode A, rewind_mode M, | ||
402 | template<typename...> class Action, | ||
403 | template<typename...> class Control, | ||
404 | typename Input> | ||
405 | static bool match(Input& in, State& st) | ||
406 | { | ||
407 | st.indents.push(-1); | ||
408 | return true; | ||
409 | } | ||
410 | }; | ||
411 | |||
412 | struct PopIndent | ||
413 | { | ||
414 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
415 | |||
416 | template<apply_mode A, rewind_mode M, | ||
417 | template<typename...> class Action, | ||
418 | template<typename...> class Control, | ||
419 | typename Input> | ||
420 | static bool match(Input& in, State& st) | ||
421 | { | ||
422 | if (st.indents.size() > 1) st.indents.pop(); | ||
423 | return true; | ||
424 | } | ||
425 | }; | ||
426 | |||
427 | struct Block; | ||
428 | |||
429 | struct InBlock : seq<Advance, Block, PopIndent> {}; | ||
430 | |||
431 | struct NameList; | ||
432 | |||
433 | struct Local : seq<key<'l', 'o', 'c', 'a', 'l'>, sor<sor<op<'*'>, op<'^'>>>, NameList> {}; | ||
434 | |||
435 | struct colon_import_name : seq<one<'\\'>, Name> {}; | ||
436 | struct ImportName : sor<colon_import_name, Name> {}; | ||
437 | struct ImportNameList : seq< | ||
438 | star<SpaceBreak>, | ||
439 | ImportName, | ||
440 | star< | ||
441 | sor<plus<SpaceBreak>, seq<sym<','>, star<SpaceBreak>>>, | ||
442 | ImportName | ||
443 | > | ||
444 | > {}; | ||
445 | |||
446 | struct Exp; | ||
447 | |||
448 | struct Import : seq<key<'i', 'm', 'p', 'o', 'r', 't'>, ImportNameList, star<SpaceBreak>, key<'f', 'r', 'o', 'm'>, Exp> {}; | ||
449 | |||
450 | struct BreakLoop : sor<key<'b', 'r', 'e', 'a', 'k'>, key<'c', 'o', 'n', 't', 'i', 'n', 'u', 'e'>> {}; | ||
451 | |||
452 | struct ExpListLow; | ||
453 | |||
454 | struct ExpList; | ||
455 | struct Assign; | ||
456 | |||
457 | struct Return : seq<key<'r', 'e', 't', 'u', 'r', 'n'>, sor<ExpListLow, success>> {}; | ||
458 | struct WithExp : seq<ExpList, opt<Assign>> {}; | ||
459 | |||
460 | struct DisableDo; | ||
461 | struct PopDo; | ||
462 | struct Body; | ||
463 | |||
464 | struct With : seq<key<'w', 'i', 't', 'h'>, DisableDo, ensure<WithExp, PopDo>, opt<key<'d', 'o'>>, Body> {}; | ||
465 | |||
466 | struct SwitchCase : seq<key<'w', 'h', 'e', 'n'>, ExpList, opt<key<'t', 'h', 'e', 'n'>>, Body> {}; | ||
467 | struct SwitchElse : seq<key<'e', 'l', 's', 'e'>, Body> {}; | ||
468 | struct SwitchBlock : seq< | ||
469 | star<EmptyLine>, | ||
470 | Advance, | ||
471 | seq< | ||
472 | SwitchCase, | ||
473 | star<plus<Break>, SwitchCase>, | ||
474 | opt<plus<Break>, SwitchElse> | ||
475 | >, | ||
476 | PopIndent | ||
477 | > {}; | ||
478 | struct Switch : seq<key<'s', 'w', 'i', 't', 'c', 'h'>, DisableDo, ensure<Exp, PopDo>, opt<key<'d', 'o'>>, opt<Space>, Break, SwitchBlock> {}; | ||
479 | |||
480 | struct IfCond : seq<Exp, opt<Assign>> {}; | ||
481 | |||
482 | struct IfElse : seq< | ||
483 | opt<Break, star<EmptyLine>, CheckIndent>, | ||
484 | string<'e', 'l', 's', 'e'>, Body | ||
485 | > {}; | ||
486 | struct IfElseIf : seq< | ||
487 | opt<Break, star<EmptyLine>, CheckIndent>, | ||
488 | key<'e', 'l', 's', 'e', 'i', 'f'>, IfCond, | ||
489 | opt<key<'t', 'h', 'e', 'n'>>, Body | ||
490 | > {}; | ||
491 | |||
492 | struct If : seq<key<'i', 'f'>, IfCond, opt<key<'t', 'h', 'e', 'n'>>, Body, star<IfElseIf>, opt<IfElse>> {}; | ||
493 | struct Unless : seq<key<'u', 'n', 'l', 'e', 's', 's'>, IfCond, opt<key<'t', 'h', 'e', 'n'>>, Body, star<IfElseIf>, opt<IfElse>> {}; | ||
494 | |||
495 | struct While : seq<key<'w', 'h', 'i', 'l', 'e'>, DisableDo, ensure<Exp, PopDo>, opt<key<'d','o'>>, Body> {}; | ||
496 | struct For : seq<key<'f', 'o', 'r'>, DisableDo, | ||
497 | ensure< | ||
498 | seq< | ||
499 | Name, sym<'='>, | ||
500 | seq<Exp, sym<','>, Exp, opt<sym<','>, Exp>> | ||
501 | >, | ||
502 | PopDo | ||
503 | >, | ||
504 | opt<key<'d', 'o'>>, Body> {}; | ||
505 | |||
506 | struct AssignableNameList; | ||
507 | |||
508 | struct ForEach : seq< | ||
509 | key<'f', 'o', 'r'>, | ||
510 | AssignableNameList, | ||
511 | key<'i', 'n'>, | ||
512 | DisableDo, | ||
513 | ensure< | ||
514 | sor< | ||
515 | seq<sym<'*'>, Exp>, ExpList | ||
516 | >, | ||
517 | PopDo | ||
518 | > | ||
519 | > {}; | ||
520 | |||
521 | struct Do | ||
522 | { | ||
523 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
524 | |||
525 | template<apply_mode A, rewind_mode M, | ||
526 | template<typename...> class Action, | ||
527 | template<typename...> class Control, | ||
528 | typename Input> | ||
529 | static bool match(Input& in, State& st) | ||
530 | { | ||
531 | if (seq<key<'d', 'o'>, Body>::match<A, M, Action, Control>(in, st)) | ||
532 | { | ||
533 | if (st.doStack.empty() || st.doStack.top()) | ||
534 | { | ||
535 | return true; | ||
536 | } | ||
537 | } | ||
538 | return false; | ||
539 | } | ||
540 | }; | ||
541 | |||
542 | struct DisableDo | ||
543 | { | ||
544 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
545 | |||
546 | template<apply_mode A, rewind_mode M, | ||
547 | template<typename...> class Action, | ||
548 | template<typename...> class Control, | ||
549 | typename Input> | ||
550 | static bool match(Input& in, State& st) | ||
551 | { | ||
552 | st.doStack.push(false); | ||
553 | return true; | ||
554 | } | ||
555 | }; | ||
556 | |||
557 | struct PopDo | ||
558 | { | ||
559 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
560 | |||
561 | template<apply_mode A, rewind_mode M, | ||
562 | template<typename...> class Action, | ||
563 | template<typename...> class Control, | ||
564 | typename Input> | ||
565 | static bool match(Input& in, State& st) | ||
566 | { | ||
567 | st.doStack.pop(); | ||
568 | return true; | ||
569 | } | ||
570 | }; | ||
571 | |||
572 | struct CompInner; | ||
573 | |||
574 | struct Comprehension : seq<sym<'['>, Exp, CompInner, sym<']'>> {}; | ||
575 | struct TblComprehension : seq<sym<'{'>, seq<Exp, opt<sym<','>, Exp>>, CompInner, sym<'}'>> {}; | ||
576 | |||
577 | struct CompForEach; | ||
578 | struct CompFor; | ||
579 | struct CompClause; | ||
580 | |||
581 | struct CompInner : seq<sor<CompForEach, CompFor>, star<CompClause>> {}; | ||
582 | struct CompForEach : seq< | ||
583 | key<'f', 'o', 'r'>, | ||
584 | AssignableNameList, | ||
585 | key<'i', 'n'>, | ||
586 | sor< | ||
587 | seq<sym<'*'>, Exp>, Exp | ||
588 | > | ||
589 | > {}; | ||
590 | struct CompFor : seq<key<'f', 'o', 'r'>, Name, sym<'='>, seq<Exp, sym<','>, Exp, opt<sym<','>, Exp>>> {}; | ||
591 | struct CompClause : sor<CompFor, CompForEach, seq<key<'w', 'h', 'e', 'n'>, Exp>> {}; | ||
592 | |||
593 | struct TableBlock; | ||
594 | |||
595 | struct Assign : seq<sym<'='>, sor<With, If, Switch, TableBlock, ExpListLow>> {}; | ||
596 | |||
597 | struct Update : seq<sor< | ||
598 | sym<'.', '.', '='>, | ||
599 | sym<'+', '='>, | ||
600 | sym<'-', '='>, | ||
601 | sym<'*', '='>, | ||
602 | sym<'/', '='>, | ||
603 | sym<'%', '='>, | ||
604 | sym<'o', 'r', '='>, | ||
605 | sym<'a', 'n', 'd', '='>, | ||
606 | sym<'&', '='>, | ||
607 | sym<'|', '='>, | ||
608 | sym<'>', '>', '='>, | ||
609 | sym<'<', '<', '='> | ||
610 | >, Exp> {}; | ||
611 | |||
612 | struct CharOperators : seq<Space, one<'+', '-', '*' ,'/', '%', '^', '>', '<', '|', '&'>> {}; | ||
613 | struct WordOperators : sor< | ||
614 | op<'o', 'r'>, | ||
615 | op<'a', 'n', 'd'>, | ||
616 | op<'<', '='>, | ||
617 | op<'>', '='>, | ||
618 | op<'~', '='>, | ||
619 | op<'!', '='>, | ||
620 | op<'=', '='>, | ||
621 | op<'.', '.'>, | ||
622 | op<'<', '<'>, | ||
623 | op<'>', '>'>, | ||
624 | op<'/', '/'>> {}; | ||
625 | struct BinaryOperator : seq<sor<CharOperators, WordOperators>, star<SpaceBreak>> {}; | ||
626 | |||
627 | struct Chain; | ||
628 | |||
629 | struct Assignable : sor<Chain, Name, SelfName> {}; | ||
630 | |||
631 | struct Value; | ||
632 | |||
633 | struct Exp : seq<Value, star<BinaryOperator, Value>> {}; | ||
634 | |||
635 | struct Callable; | ||
636 | struct InvokeArgs; | ||
637 | |||
638 | struct ChainValue : seq<sor<Chain, Callable>, opt<InvokeArgs>> {}; | ||
639 | |||
640 | struct KeyValueList; | ||
641 | struct String; | ||
642 | struct SimpleValue; | ||
643 | |||
644 | struct Value : sor<String, SimpleValue, KeyValueList, ChainValue> {}; | ||
645 | struct SliceValue : Exp {}; | ||
646 | |||
647 | struct LuaString; | ||
648 | |||
649 | struct single_string_inner : sor<string<'\\','\''>, string<'\\', '\\'>, not_one<'\''>> {}; | ||
650 | struct SingleString : seq<symx<'\''>, star<single_string_inner>, sym<'\''>> {}; | ||
651 | struct interp : seq<symx<'#', '{'>, Exp, sym<'}'>> {}; | ||
652 | struct double_string_plain : sor<string<'\\','\"'>, string<'\\', '\\'>, not_one<'\"'>> {}; | ||
653 | struct double_string_inner : plus<seq<not_at<interp>, double_string_plain>> {}; | ||
654 | struct DoubleString : seq<symx<'\"'>, star<sor<double_string_inner, interp>>, sym<'\"'>> {}; | ||
655 | struct String : sor<seq<Space, DoubleString>, seq<Space, SingleString>, LuaString> {}; | ||
656 | |||
657 | struct lua_string_open : seq<one<'['>, star<one<'='>>, one<'['>> {}; | ||
658 | struct lua_string_close : seq<one<']'>, star<one<'='>>, one<']'>> {}; | ||
659 | |||
660 | struct LuaStringOpen | ||
661 | { | ||
662 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
663 | |||
664 | template<apply_mode A, rewind_mode M, | ||
665 | template<typename...> class Action, | ||
666 | template<typename...> class Control, | ||
667 | typename Input> | ||
668 | static bool match(Input& in, State& st) | ||
669 | { | ||
670 | const char* current = in.current(); | ||
671 | if (lua_string_open::match<A, M, Action, Control>(in, st)) | ||
672 | { | ||
673 | st.stringOpen = in.current() - current + 1; | ||
674 | return true; | ||
675 | } | ||
676 | return false; | ||
677 | } | ||
678 | }; | ||
679 | |||
680 | struct LuaStringClose | ||
681 | { | ||
682 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
683 | |||
684 | template<apply_mode A, rewind_mode M, | ||
685 | template<typename...> class Action, | ||
686 | template<typename...> class Control, | ||
687 | typename Input> | ||
688 | static bool match(Input& in, State& st) | ||
689 | { | ||
690 | const char* current = in.current(); | ||
691 | if (lua_string_close::match<A, M, Action, Control>(in, st)) | ||
692 | { | ||
693 | return st.stringOpen == in.current() - current + 1; | ||
694 | } | ||
695 | return false; | ||
696 | } | ||
697 | }; | ||
698 | |||
699 | struct LuaStringContent : star<not_at<LuaStringClose>, any> {}; | ||
700 | |||
701 | struct LuaString | ||
702 | { | ||
703 | using analyze_t = analysis::generic<analysis::rule_type::ANY>; | ||
704 | |||
705 | template<apply_mode A, rewind_mode M, | ||
706 | template<typename...> class Action, | ||
707 | template<typename...> class Control, | ||
708 | typename Input> | ||
709 | static bool match(Input& in, State& st) | ||
710 | { | ||
711 | bool result = seq<LuaStringOpen, opt<Break>, LuaStringContent, LuaStringClose>::match<A, M, Action, Control>(in, st); | ||
712 | st.stringOpen = -1; | ||
713 | return result; | ||
714 | } | ||
715 | }; | ||
716 | |||
717 | struct Parens : seq<sym<'('>, star<SpaceBreak>, Exp, star<SpaceBreak>, sym<')'>> {}; | ||
718 | struct Callable : sor<Name, SelfName, VarArg, Parens> {}; | ||
719 | |||
720 | struct FnArgsExpList : seq<Exp, star<sor<Break, one<','>>, White, Exp>> {}; | ||
721 | struct FnArgs : sor< | ||
722 | seq<symx<'('>, star<SpaceBreak>, opt<FnArgsExpList>, star<SpaceBreak>, sym<')'>>, | ||
723 | seq<sym<'!'>, not_at<one<'='>>> | ||
724 | > {}; | ||
725 | |||
726 | struct ChainItems; | ||
727 | struct DotChainItem; | ||
728 | struct ColonChain; | ||
729 | |||
730 | struct Chain : sor< | ||
731 | seq<sor<Callable, String, not_one<'.', '\\'>>, ChainItems>, | ||
732 | seq<Space, | ||
733 | sor< | ||
734 | seq<DotChainItem, opt<ChainItems>>, | ||
735 | ColonChain | ||
736 | > | ||
737 | > | ||
738 | > {}; | ||
739 | |||
740 | struct ChainItem; | ||
741 | |||
742 | struct ChainItems : sor< | ||
743 | seq<plus<ChainItem>, opt<ColonChain>>, | ||
744 | ColonChain | ||
745 | > {}; | ||
746 | |||
747 | struct Invoke; | ||
748 | struct Slice; | ||
749 | |||
750 | struct ChainItem : sor< | ||
751 | Invoke, | ||
752 | DotChainItem, | ||
753 | Slice, | ||
754 | seq<symx<'['>, Exp, sym<']'>> | ||
755 | > {}; | ||
756 | |||
757 | struct DotChainItem : seq<symx<'.'>, _Name> {}; | ||
758 | struct ColonChainItem : seq<symx<'\\'>, _Name> {}; | ||
759 | struct ColonChain : seq< | ||
760 | ColonChainItem, | ||
761 | opt<Invoke, opt<ChainItems>> | ||
762 | > {}; | ||
763 | |||
764 | struct SliceOne : success {}; | ||
765 | struct SliceTwo : success {}; | ||
766 | struct Slice : seq< | ||
767 | symx<'['>, sor<SliceValue, SliceOne>, sym<','>, sor<SliceValue, SliceTwo>, opt<sym<','>, SliceValue>, sym<']'>> {}; | ||
768 | |||
769 | struct Invoke : sor< | ||
770 | FnArgs, | ||
771 | SingleString, | ||
772 | DoubleString, | ||
773 | seq<at<one<'['>>, LuaString> | ||
774 | > {}; | ||
775 | |||
776 | struct KeyValue; | ||
777 | struct TableValueList; | ||
778 | struct TableLitLine; | ||
779 | |||
780 | struct TableValue : sor<KeyValue, Exp> {}; | ||
781 | struct TableLit : seq< | ||
782 | sym<'{'>, | ||
783 | seq< | ||
784 | opt<TableValueList>, opt<sym<','>>, | ||
785 | opt< | ||
786 | SpaceBreak, TableLitLine, | ||
787 | star<opt<sym<','>>, SpaceBreak, TableLitLine>, | ||
788 | opt<sym<','>> | ||
789 | > | ||
790 | >, | ||
791 | White, sym<'}'> | ||
792 | > {}; | ||
793 | |||
794 | struct TableValueList : seq<TableValue, star<sym<','>, TableValue>> {}; | ||
795 | struct TableLitLine : sor< | ||
796 | seq<PushIndent, sor<seq<TableValueList, PopIndent>, seq<PopIndent, Cut>>>, | ||
797 | Space | ||
798 | > {}; | ||
799 | |||
800 | struct KeyValueLine; | ||
801 | |||
802 | struct TableBlockInner : seq<KeyValueLine, star<plus<SpaceBreak>, KeyValueLine>> {}; | ||
803 | struct TableBlock : seq<plus<SpaceBreak>, Advance, ensure<TableBlockInner, PopIndent>> {}; | ||
804 | |||
805 | struct Statement; | ||
806 | |||
807 | struct ClassLine : seq< | ||
808 | CheckIndent, | ||
809 | seq< | ||
810 | sor<KeyValueList, Statement, Exp>, | ||
811 | opt<sym<','>> | ||
812 | > | ||
813 | > {}; | ||
814 | |||
815 | struct ClassBlock : seq<plus<SpaceBreak>, Advance, ClassLine, star<plus<SpaceBreak>, ClassLine>, PopIndent> {}; | ||
816 | |||
817 | struct class_no_derive : success {}; | ||
818 | struct class_no_extend : success {}; | ||
819 | struct class_no_body : success {}; | ||
820 | struct ClassDecl : seq< | ||
821 | string<'c', 'l', 'a', 's', 's'>, | ||
822 | not_at<one<':'>>, | ||
823 | sor<Assignable, class_no_derive>, | ||
824 | opt<sor<string<'e', 'x', 't', 'e', 'n', 'd', 's'>, PreventIndent, ensure<Exp, PopIndent>, class_no_extend>>, | ||
825 | sor<ClassBlock, class_no_body> | ||
826 | > {}; | ||
827 | |||
828 | struct Export : seq< | ||
829 | string<'e', 'x', 'p', 'o', 'r', 't'>, | ||
830 | sor< | ||
831 | ClassDecl, | ||
832 | op<'*'>, | ||
833 | op<'^'>, | ||
834 | seq<NameList, opt<sym<'='>, ExpListLow>> | ||
835 | > | ||
836 | > {}; | ||
837 | |||
838 | struct KeyValue : sor< | ||
839 | seq<sym<':'>, not_at<SomeSpace>, Name>, | ||
840 | seq< | ||
841 | sor< | ||
842 | KeyName, | ||
843 | seq<sym<'['>, Exp, sym<']'>>, | ||
844 | seq<Space, DoubleString>, | ||
845 | seq<Space, SingleString> | ||
846 | >, | ||
847 | symx<':'>, | ||
848 | sor< | ||
849 | Exp, TableBlock, seq<plus<SpaceBreak>, Exp> | ||
850 | > | ||
851 | > | ||
852 | > {}; | ||
853 | |||
854 | struct KeyValueList : seq<KeyValue, star<sym<','>, KeyValue>> {}; | ||
855 | struct KeyValueLine : seq<CheckIndent, KeyValueList, opt<sym<','>>> {}; | ||
856 | |||
857 | struct FnArgDef : seq<sor<Name, SelfName>, opt<sym<'='>, Exp>> {}; | ||
858 | |||
859 | struct FnArgDefList : sor< | ||
860 | seq< | ||
861 | FnArgDef, | ||
862 | star<sor<sym<','>, Break>, White, FnArgDef>, | ||
863 | star<sor<sym<','>, Break>, White, VarArg> | ||
864 | >, | ||
865 | VarArg | ||
866 | > {}; | ||
867 | |||
868 | struct outer_value_shadow : seq<string<'u', 's', 'i', 'n', 'g'>, sor<NameList, seq<Space, string<'n', 'i', 'l'>>>> {}; | ||
869 | struct outer_value_no_shadowing : success {}; | ||
870 | struct without_args_def : success {}; | ||
871 | |||
872 | struct FnArgsDef : sor< | ||
873 | seq<sym<'('>, White, opt<FnArgDefList>, | ||
874 | sor< | ||
875 | outer_value_shadow, | ||
876 | outer_value_no_shadowing | ||
877 | >, | ||
878 | White, sym<')'> | ||
879 | >, | ||
880 | without_args_def | ||
881 | > {}; | ||
882 | |||
883 | struct FunLit : seq<FnArgsDef, sor<sym<'-', '>'>, sym<'=', '>'>>, sor<Body, success>> {}; | ||
884 | |||
885 | struct NameList : seq<Name, star<sym<','>, Name>> {}; | ||
886 | struct NameOrDestructure : sor<Name, TableLit> {}; | ||
887 | struct AssignableNameList : seq<NameOrDestructure, star<sym<','>, NameOrDestructure>> {}; | ||
888 | |||
889 | struct ExpList : seq<Exp, star<sym<','>, Exp>> {}; | ||
890 | struct ExpListLow : seq<Exp, star<sor<sym<','>, sym<';'>, Exp>>> {}; | ||
891 | |||
892 | struct ArgLine : seq<CheckIndent, ExpList> {}; | ||
893 | struct ArgBlock : seq<ArgLine, star<sym<','>, SpaceBreak, ArgLine>, PopIndent> {}; | ||
894 | |||
895 | struct InvokeArgs : seq< | ||
896 | at<not_one<'-'>>, | ||
897 | sor< | ||
898 | seq< | ||
899 | ExpList, | ||
900 | opt<sor< | ||
901 | seq< | ||
902 | sym<','>, | ||
903 | sor< | ||
904 | TableBlock, seq<SpaceBreak, Advance, ArgBlock, opt<TableBlock>> | ||
905 | > | ||
906 | >, | ||
907 | TableBlock | ||
908 | >> | ||
909 | >, | ||
910 | TableBlock | ||
911 | > | ||
912 | > {}; | ||
913 | |||
914 | struct SimpleValue : sor< | ||
915 | key<'n', 'i', 'l'>, | ||
916 | key<'t', 'r', 'u', 'e'>, | ||
917 | key<'f', 'a', 'l', 's', 'e'>, | ||
918 | If, Unless, Switch, With, ClassDecl, ForEach, For, While, Do, | ||
919 | seq<sym<'-'>, not_at<SomeSpace>, Exp>, | ||
920 | seq<sym<'#'>, Exp>, | ||
921 | seq<sym<'~'>, Exp>, | ||
922 | seq<key<'n', 'o', 't'>, Exp>, | ||
923 | TblComprehension, | ||
924 | TableLit, | ||
925 | Comprehension, | ||
926 | FunLit, | ||
927 | Num | ||
928 | > {}; | ||
929 | |||
930 | struct Assignment : seq< | ||
931 | ExpList, | ||
932 | sor<Update, Assign> | ||
933 | > {}; | ||
934 | |||
935 | struct Sentence : sor< | ||
936 | Import, While, With, For, ForEach, | ||
937 | Switch, Return, Local, Export, BreakLoop, | ||
938 | Assignment, ExpList | ||
939 | > {}; | ||
940 | |||
941 | struct Statement : seq< | ||
942 | Sentence, | ||
943 | Space, | ||
944 | opt< | ||
945 | sor< | ||
946 | seq< | ||
947 | key<'i', 'f'>, Exp, | ||
948 | opt< | ||
949 | key<'e', 'l', 's', 'e'>, Exp | ||
950 | >, | ||
951 | Space | ||
952 | >, | ||
953 | seq<key<'u', 'n', 'l', 'e', 's', 's'>, Exp>, | ||
954 | CompInner | ||
955 | >, | ||
956 | Space | ||
957 | > | ||
958 | > {}; | ||
959 | |||
960 | struct Body : sor< | ||
961 | seq<opt<Space>, Break, star<EmptyLine>, InBlock>, | ||
962 | Statement | ||
963 | > {}; | ||
964 | |||
965 | struct Line : sor< | ||
966 | seq<CheckIndent, Statement>, | ||
967 | seq<Space, at<Stop>> | ||
968 | > {}; | ||
969 | |||
970 | struct Block : seq<Line, star<plus<Break>, Line>> {}; | ||
971 | |||
972 | struct BlockWithEnd : seq<Block, eolf> {}; | ||
973 | |||
974 | template<typename Rule> | ||
975 | struct action : nothing<Rule> {}; | ||
976 | |||
977 | template<> | ||
978 | struct action<Assignment> | ||
979 | { | ||
980 | template<typename Input> | ||
981 | static void apply(const Input& in, State&) | ||
982 | { | ||
983 | std::cout << "Assignment: " << in.string() << '\n'; | ||
984 | } | ||
985 | }; | ||
986 | |||
987 | template<> | ||
988 | struct action<Return> | ||
989 | { | ||
990 | template<typename Input> | ||
991 | static void apply(const Input& in, State&) | ||
992 | { | ||
993 | std::cout << "Return: " << in.string() << "\n\n"; | ||
994 | } | ||
995 | }; | ||
996 | } | ||
997 | |||
998 | int main() | ||
999 | { | ||
1000 | analyze<moon::BlockWithEnd>(); | ||
1001 | moon::State state; | ||
1002 | string_input<> inName(R"xoxo( | ||
1003 | debug_grammar = false | ||
1004 | lpeg = require "lpeg" | ||
1005 | |||
1006 | lpeg.setmaxstack 10000 -- whoa | ||
1007 | |||
1008 | err_msg = "Failed to parse:%s\n [%d] >> %s" | ||
1009 | |||
1010 | import Stack from require "moonscript.data" | ||
1011 | import trim, pos_to_line, get_line from require "moonscript.util" | ||
1012 | import unpack from require "moonscript.util" | ||
1013 | import wrap_env from require "moonscript.parse.env" | ||
1014 | |||
1015 | { | ||
1016 | :R, :S, :V, :P, :C, :Ct, :Cmt, :Cg, :Cb, :Cc | ||
1017 | } = lpeg | ||
1018 | |||
1019 | { | ||
1020 | :White, :Break, :Stop, :Comment, :Space, :SomeSpace, :SpaceBreak, :EmptyLine, | ||
1021 | :AlphaNum, :Num, :Shebang, :L | ||
1022 | Name: _Name | ||
1023 | } = require "moonscript.parse.literals" | ||
1024 | |||
1025 | SpaceName = Space * _Name | ||
1026 | Num = Space * (Num / (v) -> {"number", v}) | ||
1027 | |||
1028 | { | ||
1029 | :Indent, :Cut, :ensure, :extract_line, :mark, :pos, :flatten_or_mark, | ||
1030 | :is_assignable, :check_assignable, :format_assign, :format_single_assign, | ||
1031 | :sym, :symx, :simple_string, :wrap_func_arg, :join_chain, | ||
1032 | :wrap_decorator, :check_lua_string, :self_assign, :got | ||
1033 | |||
1034 | } = require "moonscript.parse.util" | ||
1035 | |||
1036 | |||
1037 | build_grammar = wrap_env debug_grammar, (root) -> | ||
1038 | _indent = Stack 0 | ||
1039 | _do_stack = Stack 0 | ||
1040 | |||
1041 | state = { | ||
1042 | -- last pos we saw, used to report error location | ||
1043 | last_pos: 0 | ||
1044 | } | ||
1045 | |||
1046 | check_indent = (str, pos, indent) -> | ||
1047 | state.last_pos = pos | ||
1048 | _indent\top! == indent | ||
1049 | |||
1050 | advance_indent = (str, pos, indent) -> | ||
1051 | top = _indent\top! | ||
1052 | if top != -1 and indent > top | ||
1053 | _indent\push indent | ||
1054 | true | ||
1055 | |||
1056 | push_indent = (str, pos, indent) -> | ||
1057 | _indent\push indent | ||
1058 | true | ||
1059 | |||
1060 | pop_indent = -> | ||
1061 | assert _indent\pop!, "unexpected outdent" | ||
1062 | true | ||
1063 | |||
1064 | check_do = (str, pos, do_node) -> | ||
1065 | top = _do_stack\top! | ||
1066 | if top == nil or top | ||
1067 | return true, do_node | ||
1068 | false | ||
1069 | |||
1070 | disable_do = -> | ||
1071 | _do_stack\push false | ||
1072 | true | ||
1073 | |||
1074 | pop_do = -> | ||
1075 | assert _do_stack\pop! != nil, "unexpected do pop" | ||
1076 | true | ||
1077 | |||
1078 | DisableDo = Cmt "", disable_do | ||
1079 | PopDo = Cmt "", pop_do | ||
1080 | |||
1081 | keywords = {} | ||
1082 | key = (chars) -> | ||
1083 | keywords[chars] = true | ||
1084 | Space * chars * -AlphaNum | ||
1085 | |||
1086 | op = (chars) -> | ||
1087 | patt = Space * C chars | ||
1088 | -- it's a word, treat like keyword | ||
1089 | if chars\match "^%w*$" | ||
1090 | keywords[chars] = true | ||
1091 | patt *= -AlphaNum | ||
1092 | |||
1093 | patt | ||
1094 | |||
1095 | Name = Cmt(SpaceName, (str, pos, name) -> | ||
1096 | return false if keywords[name] | ||
1097 | true | ||
1098 | ) / trim | ||
1099 | |||
1100 | SelfName = Space * "@" * ( | ||
1101 | "@" * (_Name / mark"self_class" + Cc"self.__class") + | ||
1102 | _Name / mark"self" + | ||
1103 | Cc"self" -- @ by itself | ||
1104 | ) | ||
1105 | |||
1106 | KeyName = SelfName + Space * _Name / mark"key_literal" | ||
1107 | VarArg = Space * P"..." / trim | ||
1108 | |||
1109 | g = P { | ||
1110 | root or File | ||
1111 | File: Shebang^-1 * (Block + Ct"") | ||
1112 | Block: Ct(Line * (Break^1 * Line)^0) | ||
1113 | CheckIndent: Cmt(Indent, check_indent), -- validates line is in correct indent | ||
1114 | Line: (CheckIndent * Statement + Space * L(Stop)) | ||
1115 | |||
1116 | Statement: pos( | ||
1117 | Import + While + With + For + ForEach + Switch + Return + | ||
1118 | Local + Export + BreakLoop + | ||
1119 | Ct(ExpList) * (Update + Assign)^-1 / format_assign | ||
1120 | ) * Space * (( | ||
1121 | -- statement decorators | ||
1122 | key"if" * Exp * (key"else" * Exp)^-1 * Space / mark"if" + | ||
1123 | key"unless" * Exp / mark"unless" + | ||
1124 | CompInner / mark"comprehension" | ||
1125 | ) * Space)^-1 / wrap_decorator | ||
1126 | |||
1127 | Body: Space^-1 * Break * EmptyLine^0 * InBlock + Ct(Statement) -- either a statement, or an indented block | ||
1128 | |||
1129 | Advance: L Cmt(Indent, advance_indent) -- Advances the indent, gives back whitespace for CheckIndent | ||
1130 | PushIndent: Cmt(Indent, push_indent) | ||
1131 | PreventIndent: Cmt(Cc(-1), push_indent) | ||
1132 | PopIndent: Cmt("", pop_indent) | ||
1133 | InBlock: Advance * Block * PopIndent | ||
1134 | |||
1135 | Local: key"local" * ((op"*" + op"^") / mark"declare_glob" + Ct(NameList) / mark"declare_with_shadows") | ||
1136 | |||
1137 | Import: key"import" * Ct(ImportNameList) * SpaceBreak^0 * key"from" * Exp / mark"import" | ||
1138 | ImportName: (sym"\\" * Ct(Cc"colon" * Name) + Name) | ||
1139 | ImportNameList: SpaceBreak^0 * ImportName * ((SpaceBreak^1 + sym"," * SpaceBreak^0) * ImportName)^0 | ||
1140 | |||
1141 | BreakLoop: Ct(key"break"/trim) + Ct(key"continue"/trim) | ||
1142 | |||
1143 | Return: key"return" * (ExpListLow/mark"explist" + C"") / mark"return" | ||
1144 | |||
1145 | WithExp: Ct(ExpList) * Assign^-1 / format_assign | ||
1146 | With: key"with" * DisableDo * ensure(WithExp, PopDo) * key"do"^-1 * Body / mark"with" | ||
1147 | |||
1148 | Switch: key"switch" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Space^-1 * Break * SwitchBlock / mark"switch" | ||
1149 | |||
1150 | SwitchBlock: EmptyLine^0 * Advance * Ct(SwitchCase * (Break^1 * SwitchCase)^0 * (Break^1 * SwitchElse)^-1) * PopIndent | ||
1151 | SwitchCase: key"when" * Ct(ExpList) * key"then"^-1 * Body / mark"case" | ||
1152 | SwitchElse: key"else" * Body / mark"else" | ||
1153 | |||
1154 | IfCond: Exp * Assign^-1 / format_single_assign | ||
1155 | |||
1156 | IfElse: (Break * EmptyLine^0 * CheckIndent)^-1 * key"else" * Body / mark"else" | ||
1157 | IfElseIf: (Break * EmptyLine^0 * CheckIndent)^-1 * key"elseif" * pos(IfCond) * key"then"^-1 * Body / mark"elseif" | ||
1158 | |||
1159 | If: key"if" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"if" | ||
1160 | Unless: key"unless" * IfCond * key"then"^-1 * Body * IfElseIf^0 * IfElse^-1 / mark"unless" | ||
1161 | |||
1162 | While: key"while" * DisableDo * ensure(Exp, PopDo) * key"do"^-1 * Body / mark"while" | ||
1163 | |||
1164 | For: key"for" * DisableDo * ensure(Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1), PopDo) * | ||
1165 | key"do"^-1 * Body / mark"for" | ||
1166 | |||
1167 | ForEach: key"for" * Ct(AssignableNameList) * key"in" * DisableDo * ensure(Ct(sym"*" * Exp / mark"unpack" + ExpList), PopDo) * key"do"^-1 * Body / mark"foreach" | ||
1168 | |||
1169 | Do: key"do" * Body / mark"do" | ||
1170 | |||
1171 | Comprehension: sym"[" * Exp * CompInner * sym"]" / mark"comprehension" | ||
1172 | |||
1173 | TblComprehension: sym"{" * Ct(Exp * (sym"," * Exp)^-1) * CompInner * sym"}" / mark"tblcomprehension" | ||
1174 | |||
1175 | CompInner: Ct((CompForEach + CompFor) * CompClause^0) | ||
1176 | CompForEach: key"for" * Ct(AssignableNameList) * key"in" * (sym"*" * Exp / mark"unpack" + Exp) / mark"foreach" | ||
1177 | CompFor: key "for" * Name * sym"=" * Ct(Exp * sym"," * Exp * (sym"," * Exp)^-1) / mark"for" | ||
1178 | CompClause: CompFor + CompForEach + key"when" * Exp / mark"when" | ||
1179 | |||
1180 | Assign: sym"=" * (Ct(With + If + Switch) + Ct(TableBlock + ExpListLow)) / mark"assign" | ||
1181 | Update: ((sym"..=" + sym"+=" + sym"-=" + sym"*=" + sym"/=" + sym"%=" + sym"or=" + sym"and=" + sym"&=" + sym"|=" + sym">>=" + sym"<<=") / trim) * Exp / mark"update" | ||
1182 | |||
1183 | CharOperators: Space * C(S"+-*/%^><|&") | ||
1184 | WordOperators: op"or" + op"and" + op"<=" + op">=" + op"~=" + op"!=" + op"==" + op".." + op"<<" + op">>" + op"//" | ||
1185 | BinaryOperator: (WordOperators + CharOperators) * SpaceBreak^0 | ||
1186 | |||
1187 | Assignable: Cmt(Chain, check_assignable) + Name + SelfName | ||
1188 | Exp: Ct(Value * (BinaryOperator * Value)^0) / flatten_or_mark"exp" | ||
1189 | |||
1190 | SimpleValue: | ||
1191 | If + Unless + | ||
1192 | Switch + | ||
1193 | With + | ||
1194 | ClassDecl + | ||
1195 | ForEach + For + While + | ||
1196 | Cmt(Do, check_do) + | ||
1197 | sym"-" * -SomeSpace * Exp / mark"minus" + | ||
1198 | sym"#" * Exp / mark"length" + | ||
1199 | sym"~" * Exp / mark"bitnot" + | ||
1200 | key"not" * Exp / mark"not" + | ||
1201 | TblComprehension + | ||
1202 | TableLit + | ||
1203 | Comprehension + | ||
1204 | FunLit + | ||
1205 | Num | ||
1206 | |||
1207 | -- a function call or an object access | ||
1208 | ChainValue: (Chain + Callable) * Ct(InvokeArgs^-1) / join_chain | ||
1209 | |||
1210 | Value: pos( | ||
1211 | SimpleValue + | ||
1212 | Ct(KeyValueList) / mark"table" + | ||
1213 | ChainValue + | ||
1214 | String) | ||
1215 | |||
1216 | SliceValue: Exp | ||
1217 | |||
1218 | String: Space * DoubleString + Space * SingleString + LuaString | ||
1219 | SingleString: simple_string("'") | ||
1220 | DoubleString: simple_string('"', true) | ||
1221 | |||
1222 | LuaString: Cg(LuaStringOpen, "string_open") * Cb"string_open" * Break^-1 * | ||
1223 | C((1 - Cmt(C(LuaStringClose) * Cb"string_open", check_lua_string))^0) * | ||
1224 | LuaStringClose / mark"string" | ||
1225 | |||
1226 | LuaStringOpen: sym"[" * P"="^0 * "[" / trim | ||
1227 | LuaStringClose: "]" * P"="^0 * "]" | ||
1228 | |||
1229 | Callable: pos(Name / mark"ref") + SelfName + VarArg + Parens / mark"parens" | ||
1230 | Parens: sym"(" * SpaceBreak^0 * Exp * SpaceBreak^0 * sym")" | ||
1231 | |||
1232 | FnArgs: symx"(" * SpaceBreak^0 * Ct(FnArgsExpList^-1) * SpaceBreak^0 * sym")" + sym"!" * -P"=" * Ct"" | ||
1233 | FnArgsExpList: Exp * ((Break + sym",") * White * Exp)^0 | ||
1234 | |||
1235 | Chain: (Callable + String + -S".\\") * ChainItems / mark"chain" + | ||
1236 | Space * (DotChainItem * ChainItems^-1 + ColonChain) / mark"chain" | ||
1237 | |||
1238 | ChainItems: ChainItem^1 * ColonChain^-1 + ColonChain | ||
1239 | |||
1240 | ChainItem: | ||
1241 | Invoke + | ||
1242 | DotChainItem + | ||
1243 | Slice + | ||
1244 | symx"[" * Exp/mark"index" * sym"]" | ||
1245 | |||
1246 | DotChainItem: symx"." * _Name/mark"dot" | ||
1247 | ColonChainItem: symx"\\" * _Name / mark"colon" | ||
1248 | ColonChain: ColonChainItem * (Invoke * ChainItems^-1)^-1 | ||
1249 | |||
1250 | Slice: symx"[" * (SliceValue + Cc(1)) * sym"," * (SliceValue + Cc"") * | ||
1251 | (sym"," * SliceValue)^-1 *sym"]" / mark"slice" | ||
1252 | |||
1253 | Invoke: FnArgs / mark"call" + | ||
1254 | SingleString / wrap_func_arg + | ||
1255 | DoubleString / wrap_func_arg + | ||
1256 | L(P"[") * LuaString / wrap_func_arg | ||
1257 | |||
1258 | TableValue: KeyValue + Ct(Exp) | ||
1259 | |||
1260 | TableLit: sym"{" * Ct( | ||
1261 | TableValueList^-1 * sym","^-1 * | ||
1262 | (SpaceBreak * TableLitLine * (sym","^-1 * SpaceBreak * TableLitLine)^0 * sym","^-1)^-1 | ||
1263 | ) * White * sym"}" / mark"table" | ||
1264 | |||
1265 | TableValueList: TableValue * (sym"," * TableValue)^0 | ||
1266 | TableLitLine: PushIndent * ((TableValueList * PopIndent) + (PopIndent * Cut)) + Space | ||
1267 | |||
1268 | -- the unbounded table | ||
1269 | TableBlockInner: Ct(KeyValueLine * (SpaceBreak^1 * KeyValueLine)^0) | ||
1270 | TableBlock: SpaceBreak^1 * Advance * ensure(TableBlockInner, PopIndent) / mark"table" | ||
1271 | |||
1272 | ClassDecl: key"class" * -P":" * (Assignable + Cc(nil)) * (key"extends" * PreventIndent * ensure(Exp, PopIndent) + C"")^-1 * (ClassBlock + Ct("")) / mark"class" | ||
1273 | |||
1274 | ClassBlock: SpaceBreak^1 * Advance * | ||
1275 | Ct(ClassLine * (SpaceBreak^1 * ClassLine)^0) * PopIndent | ||
1276 | ClassLine: CheckIndent * (( | ||
1277 | KeyValueList / mark"props" + | ||
1278 | Statement / mark"stm" + | ||
1279 | Exp / mark"stm" | ||
1280 | ) * sym","^-1) | ||
1281 | |||
1282 | Export: key"export" * ( | ||
1283 | Cc"class" * ClassDecl + | ||
1284 | op"*" + op"^" + | ||
1285 | Ct(NameList) * (sym"=" * Ct(ExpListLow))^-1) / mark"export" | ||
1286 | |||
1287 | KeyValue: (sym":" * -SomeSpace * Name * lpeg.Cp!) / self_assign + | ||
1288 | Ct( | ||
1289 | (KeyName + sym"[" * Exp * sym"]" +Space * DoubleString + Space * SingleString) * | ||
1290 | symx":" * | ||
1291 | (Exp + TableBlock + SpaceBreak^1 * Exp) | ||
1292 | ) | ||
1293 | |||
1294 | KeyValueList: KeyValue * (sym"," * KeyValue)^0 | ||
1295 | KeyValueLine: CheckIndent * KeyValueList * sym","^-1 | ||
1296 | |||
1297 | FnArgsDef: sym"(" * White * Ct(FnArgDefList^-1) * | ||
1298 | (key"using" * Ct(NameList + Space * "nil") + Ct"") * | ||
1299 | White * sym")" + Ct"" * Ct"" | ||
1300 | |||
1301 | FnArgDefList: FnArgDef * ((sym"," + Break) * White * FnArgDef)^0 * ((sym"," + Break) * White * Ct(VarArg))^0 + Ct(VarArg) | ||
1302 | FnArgDef: Ct((Name + SelfName) * (sym"=" * Exp)^-1) | ||
1303 | |||
1304 | FunLit: FnArgsDef * | ||
1305 | (sym"->" * Cc"slim" + sym"=>" * Cc"fat") * | ||
1306 | (Body + Ct"") / mark"fndef" | ||
1307 | |||
1308 | NameList: Name * (sym"," * Name)^0 | ||
1309 | NameOrDestructure: Name + TableLit | ||
1310 | AssignableNameList: NameOrDestructure * (sym"," * NameOrDestructure)^0 | ||
1311 | |||
1312 | ExpList: Exp * (sym"," * Exp)^0 | ||
1313 | ExpListLow: Exp * ((sym"," + sym";") * Exp)^0 | ||
1314 | |||
1315 | -- open args | ||
1316 | InvokeArgs: -P"-" * (ExpList * (sym"," * (TableBlock + SpaceBreak * Advance * ArgBlock * TableBlock^-1) + TableBlock)^-1 + TableBlock) | ||
1317 | ArgBlock: ArgLine * (sym"," * SpaceBreak * ArgLine)^0 * PopIndent | ||
1318 | ArgLine: CheckIndent * ExpList | ||
1319 | } | ||
1320 | |||
1321 | g, state | ||
1322 | |||
1323 | file_parser = -> | ||
1324 | g, state = build_grammar! | ||
1325 | file_grammar = White * g * White * -1 | ||
1326 | |||
1327 | { | ||
1328 | match: (str) => | ||
1329 | local tree | ||
1330 | _, err = xpcall (-> | ||
1331 | tree = file_grammar\match str | ||
1332 | ), (err) -> | ||
1333 | debug.traceback err, 2 | ||
1334 | |||
1335 | -- regular error, let it bubble up | ||
1336 | if type(err) == "string" | ||
1337 | return nil, err | ||
1338 | |||
1339 | unless tree | ||
1340 | local msg | ||
1341 | err_pos = state.last_pos | ||
1342 | |||
1343 | if err | ||
1344 | node, msg = unpack err | ||
1345 | msg = " " .. msg if msg | ||
1346 | err_pos = node[-1] | ||
1347 | |||
1348 | line_no = pos_to_line str, err_pos | ||
1349 | line_str = get_line(str, line_no) or "" | ||
1350 | return nil, err_msg\format msg or "", line_no, trim line_str | ||
1351 | |||
1352 | tree | ||
1353 | } | ||
1354 | |||
1355 | { | ||
1356 | :extract_line | ||
1357 | :build_grammar | ||
1358 | |||
1359 | -- parse a string as a file | ||
1360 | -- returns tree, or nil and error message | ||
1361 | string: (str) -> file_parser!\match str | ||
1362 | } | ||
1363 | )xoxo", "abc"); | ||
1364 | try | ||
1365 | { | ||
1366 | if (parse<must<moon::BlockWithEnd>, moon::action>(inName, state)) | ||
1367 | { | ||
1368 | std::cout << "matched.\n"; | ||
1369 | } | ||
1370 | else | ||
1371 | { | ||
1372 | std::cout << "not matched.\n"; | ||
1373 | } | ||
1374 | } | ||
1375 | catch (parse_error e) | ||
1376 | { | ||
1377 | std::cout << e.what() << '\n'; | ||
1378 | } | ||
1379 | /* | ||
1380 | analyze<hello::expr>(); | ||
1381 | const char* text = "1 + 2 + 3 * 4 / 2"; | ||
1382 | string_input<> in(text, "abc"); | ||
1383 | try | ||
1384 | { | ||
1385 | hello::Stack stack; | ||
1386 | if (parse<hello::expr, hello::action>(in, stack)) | ||
1387 | { | ||
1388 | std::cout << text << " = " << stack.getValue() << '\n'; | ||
1389 | } | ||
1390 | return 0; | ||
1391 | } | ||
1392 | catch (parse_error e) | ||
1393 | { | ||
1394 | std::cout << e.what() << '\n'; | ||
1395 | return 1; | ||
1396 | } | ||
1397 | */ | ||
1398 | return 0; | ||
1399 | } | ||