summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Lively <tlively@google.com>2023-09-21 15:33:51 -0700
committerGitHub <noreply@github.com>2023-09-21 15:33:51 -0700
commit38197b57aa5bd94a879c0203b75a35cb826db929 (patch)
treebd03181fa5e9ac804a58db2e1d65ca26d19763d7 /src
parent2c09a60ecbb0ba0276982204d8788b4343356417 (diff)
downloadbinaryen-38197b57aa5bd94a879c0203b75a35cb826db929.tar.gz
binaryen-38197b57aa5bd94a879c0203b75a35cb826db929.tar.bz2
binaryen-38197b57aa5bd94a879c0203b75a35cb826db929.zip
[Parser] Allow any number of foldedinsts in `foldedinsts` (#5965)
Somewhat counterintuitively, the text syntax for a folded `if` allows any number of folded instructions in the condition position, not just one. Update the corresponding `foldedinsts` parsing function to parse arbitrary sequences of folded instructions and add a test.
Diffstat (limited to 'src')
-rw-r--r--src/parser/input-impl.h10
-rw-r--r--src/parser/input.h1
-rw-r--r--src/parser/parsers.h128
3 files changed, 79 insertions, 60 deletions
diff --git a/src/parser/input-impl.h b/src/parser/input-impl.h
index 35a39b2f3..7ee358f12 100644
--- a/src/parser/input-impl.h
+++ b/src/parser/input-impl.h
@@ -257,6 +257,16 @@ inline bool ParseInput::takeSExprStart(std::string_view expected) {
return false;
}
+inline bool ParseInput::peekSExprStart(std::string_view expected) {
+ auto original = lexer;
+ if (!takeLParen()) {
+ return false;
+ }
+ bool ret = takeKeyword(expected);
+ lexer = original;
+ return ret;
+}
+
inline Index ParseInput::getPos() {
if (auto t = peek()) {
return lexer.getIndex() - t->span.size();
diff --git a/src/parser/input.h b/src/parser/input.h
index 5c7c57d20..5cb2bd471 100644
--- a/src/parser/input.h
+++ b/src/parser/input.h
@@ -62,6 +62,7 @@ struct ParseInput {
std::optional<std::string_view> takeString();
std::optional<Name> takeName();
bool takeSExprStart(std::string_view expected);
+ bool peekSExprStart(std::string_view expected);
Index getPos();
[[nodiscard]] Err err(Index pos, std::string reason);
diff --git a/src/parser/parsers.h b/src/parser/parsers.h
index f36f5ccfb..2dd0d9eb4 100644
--- a/src/parser/parsers.h
+++ b/src/parser/parsers.h
@@ -47,8 +47,9 @@ template<typename Ctx> MaybeResult<> unfoldedBlockinstr(Ctx&);
template<typename Ctx> MaybeResult<> blockinstr(Ctx&);
template<typename Ctx> MaybeResult<> plaininstr(Ctx&);
template<typename Ctx> MaybeResult<> instr(Ctx&);
-template<typename Ctx> Result<> foldedinstrs(Ctx&);
+template<typename Ctx> MaybeResult<> foldedinstr(Ctx&);
template<typename Ctx> Result<> instrs(Ctx&);
+template<typename Ctx> Result<> 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&);
@@ -600,88 +601,95 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) {
}
}
}
- if (auto i = blockinstr(ctx)) {
- return i;
+ if (auto inst = blockinstr(ctx)) {
+ return inst;
}
- if (auto i = plaininstr(ctx)) {
- return i;
+ if (auto inst = plaininstr(ctx)) {
+ return inst;
}
// TODO: Handle folded plain instructions as well.
return {};
}
-template<typename Ctx> Result<> foldedinstrs(Ctx& ctx) {
- if (auto blockinst = foldedBlockinstr(ctx)) {
- CHECK_ERR(blockinst);
- return Ok{};
+template<typename Ctx> MaybeResult<> foldedinstr(Ctx& ctx) {
+ // Check for valid strings that are not instructions.
+ if (ctx.in.peekSExprStart("then"sv) || ctx.in.peekSExprStart("else")) {
+ return {};
+ }
+ if (auto inst = foldedBlockinstr(ctx)) {
+ return inst;
+ }
+ if (!ctx.in.takeLParen()) {
+ return {};
}
- // Parse an arbitrary number of folded instructions.
- if (ctx.in.takeLParen()) {
- // A stack of (start, end) position pairs defining the positions of
- // instructions that need to be parsed after their folded children.
- std::vector<std::pair<Index, std::optional<Index>>> foldedInstrs;
-
- // Begin a folded instruction. Push its start position and a placeholder
- // end position.
- foldedInstrs.push_back({ctx.in.getPos(), {}});
- while (!foldedInstrs.empty()) {
- // Consume everything up to the next paren. This span will be parsed as
- // an instruction later after its folded children have been parsed.
- if (!ctx.in.takeUntilParen()) {
- return ctx.in.err(foldedInstrs.back().first,
- "unterminated folded instruction");
- }
- if (!foldedInstrs.back().second) {
- // The folded instruction we just started should end here.
- foldedInstrs.back().second = ctx.in.getPos();
- }
+ // A stack of (start, end) position pairs defining the positions of
+ // instructions that need to be parsed after their folded children.
+ std::vector<std::pair<Index, std::optional<Index>>> foldedInstrs;
- // We have either the start of a new folded child or the end of the last
- // one.
- if (auto blockinst = foldedBlockinstr(ctx)) {
- CHECK_ERR(blockinst);
- } else if (ctx.in.takeLParen()) {
- foldedInstrs.push_back({ctx.in.getPos(), {}});
- } else if (ctx.in.takeRParen()) {
- auto [start, end] = foldedInstrs.back();
- assert(end && "Should have found end of instruction");
- foldedInstrs.pop_back();
-
- WithPosition with(ctx, start);
- if (auto inst = plaininstr(ctx)) {
- CHECK_ERR(inst);
- } else {
- return ctx.in.err(start, "expected folded instruction");
- }
+ // Begin a folded instruction. Push its start position and a placeholder
+ // end position.
+ foldedInstrs.push_back({ctx.in.getPos(), {}});
+ while (!foldedInstrs.empty()) {
+ // Consume everything up to the next paren. This span will be parsed as
+ // an instruction later after its folded children have been parsed.
+ if (!ctx.in.takeUntilParen()) {
+ return ctx.in.err(foldedInstrs.back().first,
+ "unterminated folded instruction");
+ }
- if (ctx.in.getPos() != *end) {
- return ctx.in.err("expected end of instruction");
- }
+ if (!foldedInstrs.back().second) {
+ // The folded instruction we just started should end here.
+ foldedInstrs.back().second = ctx.in.getPos();
+ }
+
+ // We have either the start of a new folded child or the end of the last
+ // one.
+ if (auto blockinst = foldedBlockinstr(ctx)) {
+ CHECK_ERR(blockinst);
+ } else if (ctx.in.takeLParen()) {
+ foldedInstrs.push_back({ctx.in.getPos(), {}});
+ } else if (ctx.in.takeRParen()) {
+ auto [start, end] = foldedInstrs.back();
+ assert(end && "Should have found end of instruction");
+ foldedInstrs.pop_back();
+
+ WithPosition with(ctx, start);
+ if (auto inst = plaininstr(ctx)) {
+ CHECK_ERR(inst);
} else {
- WASM_UNREACHABLE("expected paren");
+ return ctx.in.err(start, "expected folded instruction");
+ }
+
+ if (ctx.in.getPos() != *end) {
+ return ctx.in.err("expected end of instruction");
}
+ } else {
+ WASM_UNREACHABLE("expected paren");
}
- return Ok{};
}
- return ctx.in.err("expected folded instruction");
+ return Ok{};
}
template<typename Ctx> Result<> instrs(Ctx& ctx) {
while (true) {
- // Try to parse a folded instruction tree.
- if (!foldedinstrs(ctx).getErr()) {
+ if (auto inst = instr(ctx)) {
+ CHECK_ERR(inst);
continue;
}
-
- // Otherwise parse a non-folded instruction.
- if (auto inst = instr(ctx)) {
+ if (auto inst = foldedinstr(ctx)) {
CHECK_ERR(inst);
- } else {
- break;
+ continue;
}
+ break;
}
+ return Ok{};
+}
+template<typename Ctx> Result<> foldedinstrs(Ctx& ctx) {
+ while (auto inst = foldedinstr(ctx)) {
+ CHECK_ERR(inst);
+ }
return Ok{};
}
@@ -770,7 +778,7 @@ template<typename Ctx> MaybeResult<> block(Ctx& ctx, bool folded) {
}
// if ::= 'if' label blocktype instr1* ('else' id1? instr2*)? 'end' id2?
-// | '(' 'if' label blocktype instr* '(' 'then' instr1* ')'
+// | '(' 'if' label blocktype foldedinstr* '(' 'then' instr1* ')'
// ('(' 'else' instr2* ')')? ')'
template<typename Ctx> MaybeResult<> ifelse(Ctx& ctx, bool folded) {
auto pos = ctx.in.getPos();