Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/parser/contexts.h
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,14 @@ struct NullInstrParserCtx {
Result<> makeStringSliceIter(Index) { return Ok{}; }
};

struct NullCtx : NullTypeParserCtx, NullInstrParserCtx {
ParseInput in;
NullCtx(const ParseInput& in) : in(in) {}
Result<> makeTypeUse(Index, std::optional<HeapTypeT>, ParamsT*, ResultsT*) {
return Ok{};
}
};

// Phase 1: Parse definition spans for top-level module elements and determine
// their indices and names.
struct ParseDeclsCtx : NullTypeParserCtx, NullInstrParserCtx {
Expand Down
81 changes: 43 additions & 38 deletions src/parser/parsers.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#define parser_parsers_h

#include "common.h"
#include "contexts.h"
#include "input.h"

namespace wasm::WATParser {
Expand Down Expand Up @@ -706,62 +707,66 @@ template<typename Ctx> MaybeResult<> instr(Ctx& ctx) {
}

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")) {
// We must have an '(' to start a folded instruction.
if (auto tok = ctx.in.peek(); !tok || !tok->isLParen()) {
return {};
}
if (auto inst = foldedBlockinstr(ctx)) {
return inst;
}
if (!ctx.in.takeLParen()) {

// Check for valid strings that look like folded instructions but are not.
if (ctx.in.peekSExprStart("then"sv) || ctx.in.peekSExprStart("else")) {
return {};
}

// 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");
}
do {
if (ctx.in.takeRParen()) {
// We've reached the end of a folded instruction. Parse it for real.
auto [start, end] = foldedInstrs.back();
if (!end) {
return ctx.in.err("unexpected end of folded instruction");
}
foldedInstrs.pop_back();

if (!foldedInstrs.back().second) {
// The folded instruction we just started should end here.
foldedInstrs.back().second = ctx.in.getPos();
WithPosition with(ctx, start);
auto inst = plaininstr(ctx);
assert(inst && "unexpectedly failed to parse instruction");
CHECK_ERR(inst);
assert(ctx.in.getPos() == *end && "expected end of instruction");
continue;
}

// We have either the start of a new folded child or the end of the last
// one.
// We're not ending an instruction, so we must be starting a new one. Maybe
// it is a block instruction.
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();
continue;
}

WithPosition with(ctx, start);
if (auto inst = plaininstr(ctx)) {
CHECK_ERR(inst);
} else {
return ctx.in.err(start, "expected folded instruction");
}
// We must be starting a new plain instruction.
if (!ctx.in.takeLParen()) {
return ctx.in.err("expected folded instruction");
}
foldedInstrs.push_back({ctx.in.getPos(), {}});

if (ctx.in.getPos() != *end) {
return ctx.in.err("expected end of instruction");
}
// Consume the span for the instruction without meaningfully parsing it yet.
// It will be parsed for real using the real context after its s-expression
// children have been found and parsed.
NullCtx nullCtx(ctx.in);
if (auto inst = plaininstr(nullCtx)) {
CHECK_ERR(inst);
ctx.in = nullCtx.in;
} else {
WASM_UNREACHABLE("expected paren");
return ctx.in.err("expected instruction");
}
}

// The folded instruction we just started ends here.
assert(!foldedInstrs.back().second);
foldedInstrs.back().second = ctx.in.getPos();
} while (!foldedInstrs.empty());

return Ok{};
}

Expand Down
Loading