|
18 | 18 | #define parser_parsers_h |
19 | 19 |
|
20 | 20 | #include "common.h" |
| 21 | +#include "contexts.h" |
21 | 22 | #include "input.h" |
22 | 23 |
|
23 | 24 | namespace wasm::WATParser { |
@@ -706,62 +707,66 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) { |
706 | 707 | } |
707 | 708 |
|
708 | 709 | template<typename Ctx> MaybeResult<> foldedinstr(Ctx& ctx) { |
709 | | - // Check for valid strings that are not instructions. |
710 | | - if (ctx.in.peekSExprStart("then"sv) || ctx.in.peekSExprStart("else")) { |
| 710 | + // We must have an '(' to start a folded instruction. |
| 711 | + if (auto tok = ctx.in.peek(); !tok || !tok->isLParen()) { |
711 | 712 | return {}; |
712 | 713 | } |
713 | | - if (auto inst = foldedBlockinstr(ctx)) { |
714 | | - return inst; |
715 | | - } |
716 | | - if (!ctx.in.takeLParen()) { |
| 714 | + |
| 715 | + // Check for valid strings that look like folded instructions but are not. |
| 716 | + if (ctx.in.peekSExprStart("then"sv) || ctx.in.peekSExprStart("else")) { |
717 | 717 | return {}; |
718 | 718 | } |
719 | 719 |
|
720 | 720 | // A stack of (start, end) position pairs defining the positions of |
721 | 721 | // instructions that need to be parsed after their folded children. |
722 | 722 | std::vector<std::pair<Index, std::optional<Index>>> foldedInstrs; |
723 | 723 |
|
724 | | - // Begin a folded instruction. Push its start position and a placeholder |
725 | | - // end position. |
726 | | - foldedInstrs.push_back({ctx.in.getPos(), {}}); |
727 | | - while (!foldedInstrs.empty()) { |
728 | | - // Consume everything up to the next paren. This span will be parsed as |
729 | | - // an instruction later after its folded children have been parsed. |
730 | | - if (!ctx.in.takeUntilParen()) { |
731 | | - return ctx.in.err(foldedInstrs.back().first, |
732 | | - "unterminated folded instruction"); |
733 | | - } |
| 724 | + do { |
| 725 | + if (ctx.in.takeRParen()) { |
| 726 | + // We've reached the end of a folded instruction. Parse it for real. |
| 727 | + auto [start, end] = foldedInstrs.back(); |
| 728 | + if (!end) { |
| 729 | + return ctx.in.err("unexpected end of folded instruction"); |
| 730 | + } |
| 731 | + foldedInstrs.pop_back(); |
734 | 732 |
|
735 | | - if (!foldedInstrs.back().second) { |
736 | | - // The folded instruction we just started should end here. |
737 | | - foldedInstrs.back().second = ctx.in.getPos(); |
| 733 | + WithPosition with(ctx, start); |
| 734 | + auto inst = plaininstr(ctx); |
| 735 | + assert(inst && "unexpectedly failed to parse instruction"); |
| 736 | + CHECK_ERR(inst); |
| 737 | + assert(ctx.in.getPos() == *end && "expected end of instruction"); |
| 738 | + continue; |
738 | 739 | } |
739 | 740 |
|
740 | | - // We have either the start of a new folded child or the end of the last |
741 | | - // one. |
| 741 | + // We're not ending an instruction, so we must be starting a new one. Maybe |
| 742 | + // it is a block instruction. |
742 | 743 | if (auto blockinst = foldedBlockinstr(ctx)) { |
743 | 744 | CHECK_ERR(blockinst); |
744 | | - } else if (ctx.in.takeLParen()) { |
745 | | - foldedInstrs.push_back({ctx.in.getPos(), {}}); |
746 | | - } else if (ctx.in.takeRParen()) { |
747 | | - auto [start, end] = foldedInstrs.back(); |
748 | | - assert(end && "Should have found end of instruction"); |
749 | | - foldedInstrs.pop_back(); |
| 745 | + continue; |
| 746 | + } |
750 | 747 |
|
751 | | - WithPosition with(ctx, start); |
752 | | - if (auto inst = plaininstr(ctx)) { |
753 | | - CHECK_ERR(inst); |
754 | | - } else { |
755 | | - return ctx.in.err(start, "expected folded instruction"); |
756 | | - } |
| 748 | + // We must be starting a new plain instruction. |
| 749 | + if (!ctx.in.takeLParen()) { |
| 750 | + return ctx.in.err("expected folded instruction"); |
| 751 | + } |
| 752 | + foldedInstrs.push_back({ctx.in.getPos(), {}}); |
757 | 753 |
|
758 | | - if (ctx.in.getPos() != *end) { |
759 | | - return ctx.in.err("expected end of instruction"); |
760 | | - } |
| 754 | + // Consume the span for the instruction without meaningfully parsing it yet. |
| 755 | + // It will be parsed for real using the real context after its s-expression |
| 756 | + // children have been found and parsed. |
| 757 | + NullCtx nullCtx(ctx.in); |
| 758 | + if (auto inst = plaininstr(nullCtx)) { |
| 759 | + CHECK_ERR(inst); |
| 760 | + ctx.in = nullCtx.in; |
761 | 761 | } else { |
762 | | - WASM_UNREACHABLE("expected paren"); |
| 762 | + return ctx.in.err("expected instruction"); |
763 | 763 | } |
764 | | - } |
| 764 | + |
| 765 | + // The folded instruction we just started ends here. |
| 766 | + assert(!foldedInstrs.back().second); |
| 767 | + foldedInstrs.back().second = ctx.in.getPos(); |
| 768 | + } while (!foldedInstrs.empty()); |
| 769 | + |
765 | 770 | return Ok{}; |
766 | 771 | } |
767 | 772 |
|
|
0 commit comments