diff options
Diffstat (limited to '')
| -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 | } | ||
