diff options
author | Thomas Lively <tlively@google.com> | 2023-09-21 12:42:07 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-09-21 12:42:07 -0700 |
commit | d491136eeb94b748225be50bdcc86c74cdbd154e (patch) | |
tree | 1c1633be02656af1a9c7b05a78a4e9a0928a5fad /src/parser/parsers.h | |
parent | ec0f05cb98d6a4e30375a7a6a78966d25fdb5d9c (diff) | |
download | binaryen-d491136eeb94b748225be50bdcc86c74cdbd154e.tar.gz binaryen-d491136eeb94b748225be50bdcc86c74cdbd154e.tar.bz2 binaryen-d491136eeb94b748225be50bdcc86c74cdbd154e.zip |
[Parser] Parse if-else in the new wat parser and IRBuilder (#5963)
Parse both the straight-line and folded versions of if, including the
abbreviations that allow omitting the else clause. In the IRBuilder, generalize
the scope stack to be able to track scopes other than blocks and add methods for
visiting the beginnings of ifs and elses.
Diffstat (limited to 'src/parser/parsers.h')
-rw-r--r-- | src/parser/parsers.h | 122 |
1 files changed, 113 insertions, 9 deletions
diff --git a/src/parser/parsers.h b/src/parser/parsers.h index 5f9f23a2a..d162de58c 100644 --- a/src/parser/parsers.h +++ b/src/parser/parsers.h @@ -48,11 +48,14 @@ MaybeResult<typename Ctx::InstrT> unfoldedBlockinstr(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::InstrT> blockinstr(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::InstrT> plaininstr(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::InstrT> instr(Ctx&); -template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx&); +template<typename Ctx> +Result<typename Ctx::InstrsT> instrs(Ctx&, bool requireFolded = false); +template<typename Ctx> Result<typename Ctx::InstrsT> foldedinstrs(Ctx&); template<typename Ctx> Result<typename Ctx::ExprT> expr(Ctx&); template<typename Ctx> Result<typename Ctx::MemargT> memarg(Ctx&, uint32_t); template<typename Ctx> Result<typename Ctx::BlockTypeT> blocktype(Ctx&); template<typename Ctx> MaybeResult<typename Ctx::InstrT> block(Ctx&, bool); +template<typename Ctx> MaybeResult<typename Ctx::InstrT> ifelse(Ctx&, bool); template<typename Ctx> Result<typename Ctx::InstrT> makeUnreachable(Ctx&, Index); template<typename Ctx> Result<typename Ctx::InstrT> makeNop(Ctx&, Index); @@ -594,6 +597,9 @@ MaybeResult<typename Ctx::InstrT> foldedBlockinstr(Ctx& ctx) { if (auto i = block(ctx, true)) { return i; } + if (auto i = ifelse(ctx, true)) { + return i; + } // TODO: Other block instructions return {}; } @@ -603,6 +609,9 @@ MaybeResult<typename Ctx::InstrT> unfoldedBlockinstr(Ctx& ctx) { if (auto i = block(ctx, false)) { return i; } + if (auto i = ifelse(ctx, false)) { + return i; + } // TODO: Other block instructions return {}; } @@ -635,7 +644,7 @@ template<typename Ctx> MaybeResult<typename Ctx::InstrT> instr(Ctx& ctx) { // Check for valid strings that are not instructions. if (auto tok = ctx.in.peek()) { if (auto keyword = tok->getKeyword()) { - if (keyword == "end"sv) { + if (keyword == "end"sv || keyword == "then"sv || keyword == "else"sv) { return {}; } } @@ -650,13 +659,20 @@ template<typename Ctx> MaybeResult<typename Ctx::InstrT> instr(Ctx& ctx) { return {}; } -template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx) { +template<typename Ctx> +Result<typename Ctx::InstrsT> instrs(Ctx& ctx, bool requireFolded) { auto insts = ctx.makeInstrs(); + bool parsedFolded = false; while (true) { if (auto blockinst = foldedBlockinstr(ctx)) { CHECK_ERR(blockinst); ctx.appendInstr(insts, *blockinst); + parsedFolded = true; + if (requireFolded) { + // Do not continue to parse another sibling folded instruction. + break; + } continue; } // Parse an arbitrary number of folded instructions. @@ -686,6 +702,7 @@ template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx) { if (auto blockinst = foldedBlockinstr(ctx)) { CHECK_ERR(blockinst); ctx.appendInstr(insts, *blockinst); + parsedFolded = true; } else if (ctx.in.takeLParen()) { foldedInstrs.push_back({ctx.in.getPos(), {}}); } else if (ctx.in.takeRParen()) { @@ -697,6 +714,7 @@ template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx) { if (auto inst = plaininstr(ctx)) { CHECK_ERR(inst); ctx.appendInstr(insts, *inst); + parsedFolded = true; } else { return ctx.in.err(start, "expected folded instruction"); } @@ -708,9 +726,18 @@ template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx) { WASM_UNREACHABLE("expected paren"); } } + if (requireFolded) { + // Do not continue to parse another sibling folded instruction. + break; + } continue; } + if (requireFolded) { + // Do not continue to parse a non-folded instruction. + break; + } + // A non-folded instruction. if (auto inst = instr(ctx)) { CHECK_ERR(inst); @@ -720,9 +747,17 @@ template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx) { } } + if (requireFolded && !parsedFolded) { + return ctx.in.err("expected folded instructions"); + } + return ctx.finishInstrs(insts); } +template<typename Ctx> Result<typename Ctx::InstrsT> foldedinstrs(Ctx& ctx) { + return instrs(ctx, true); +} + template<typename Ctx> Result<typename Ctx::ExprT> expr(Ctx& ctx) { auto insts = instrs(ctx); CHECK_ERR(insts); @@ -807,7 +842,81 @@ MaybeResult<typename Ctx::InstrT> block(Ctx& ctx, bool folded) { } } - return ctx.finishBlock(pos, std::move(*insts)); + return ctx.visitEnd(pos, std::move(*insts)); +} + +// if ::= 'if' label blocktype instr1* ('else' id1? instr2*)? 'end' id2? +// | '(' 'if' label blocktype instr* '(' 'then' instr1* ')' +// ('(' 'else' instr2* ')')? ')' +template<typename Ctx> +MaybeResult<typename Ctx::InstrT> ifelse(Ctx& ctx, bool folded) { + auto pos = ctx.in.getPos(); + + if (folded) { + if (!ctx.in.takeSExprStart("if"sv)) { + return {}; + } + } else { + if (!ctx.in.takeKeyword("if"sv)) { + return {}; + } + } + + auto label = ctx.in.takeID(); + + auto type = blocktype(ctx); + CHECK_ERR(type); + + if (folded) { + CHECK_ERR(foldedinstrs(ctx)); + } + + ctx.makeIf(pos, label, *type); + + if (folded && !ctx.in.takeSExprStart("then"sv)) { + return ctx.in.err("expected 'then' before if instructions"); + } + + auto insts = instrs(ctx); + CHECK_ERR(insts); + + if (folded && !ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of then block"); + } + + if ((folded && ctx.in.takeSExprStart("else"sv)) || + (!folded && ctx.in.takeKeyword("else"sv))) { + auto id1 = ctx.in.takeID(); + if (id1 && id1 != label) { + return ctx.in.err("else label does not match if label"); + } + + ctx.visitElse(pos); + + auto elseInsts = instrs(ctx); + CHECK_ERR(elseInsts); + + if (folded && !ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of else block"); + } + } + + if (folded) { + if (!ctx.in.takeRParen()) { + return ctx.in.err("expected ')' at end of if"); + } + } else { + if (!ctx.in.takeKeyword("end"sv)) { + return ctx.in.err("expected 'end' at end of if"); + } + } + + auto id2 = ctx.in.takeID(); + if (id2 && id2 != label) { + return ctx.in.err("end label does not match if label"); + } + + return ctx.visitEnd(pos, std::move(*insts)); } template<typename Ctx> @@ -897,11 +1006,6 @@ Result<typename Ctx::InstrT> makeBlock(Ctx& ctx, Index pos) { } template<typename Ctx> -Result<typename Ctx::InstrT> makeThenOrElse(Ctx& ctx, Index pos) { - return ctx.in.err("unimplemented instruction"); -} - -template<typename Ctx> Result<typename Ctx::InstrT> makeConst(Ctx& ctx, Index pos, Type type) { assert(type.isBasic()); switch (type.getBasic()) { |