|
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