summaryrefslogtreecommitdiff
path: root/src/parser/parsers.h
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-09-21 12:42:07 -0700
committerGitHub <noreply@github.com>2023-09-21 12:42:07 -0700
commitd491136eeb94b748225be50bdcc86c74cdbd154e (patch)
tree1c1633be02656af1a9c7b05a78a4e9a0928a5fad /src/parser/parsers.h
parentec0f05cb98d6a4e30375a7a6a78966d25fdb5d9c (diff)
downloadbinaryen-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.h122
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()) {