diff options
-rw-r--r-- | src/wasm/wat-parser.cpp | 78 | ||||
-rw-r--r-- | test/lit/wat-kitchen-sink.wast | 60 |
2 files changed, 135 insertions, 3 deletions
diff --git a/src/wasm/wat-parser.cpp b/src/wasm/wat-parser.cpp index 9e843271f..80e537a0e 100644 --- a/src/wasm/wat-parser.cpp +++ b/src/wasm/wat-parser.cpp @@ -81,6 +81,10 @@ struct ParseInput { lexer.setIndex(index); } + ParseInput(const ParseInput& other, size_t index) : lexer(other.lexer) { + lexer.setIndex(index); + } + bool empty() { return lexer.empty(); } std::optional<Token> peek() { @@ -108,6 +112,19 @@ struct ParseInput { return true; } + bool takeUntilParen() { + while (true) { + auto t = peek(); + if (!t) { + return false; + } + if (t->isLParen() || t->isRParen()) { + return true; + } + ++lexer; + } + } + std::optional<Name> takeID() { if (auto t = peek()) { if (auto id = t->getID()) { @@ -1610,10 +1627,65 @@ MaybeResult<typename Ctx::InstrT> instr(Ctx& ctx, ParseInput& in) { template<typename Ctx> Result<typename Ctx::InstrsT> instrs(Ctx& ctx, ParseInput& in) { auto insts = ctx.makeInstrs(); - while (auto inst = instr(ctx, in)) { - CHECK_ERR(inst); - ctx.appendInstr(insts, *inst); + + while (true) { + if (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({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 (!in.takeUntilParen()) { + return ParseInput(in, foldedInstrs.back().first) + .err("unterminated folded instruction"); + } + + if (!foldedInstrs.back().second) { + // The folded instruction we just started should end here. + foldedInstrs.back().second = in.getPos(); + } + + // We have either the start of a new folded child or the end of the last + // one. + if (in.takeLParen()) { + foldedInstrs.push_back({in.getPos(), {}}); + } else if (in.takeRParen()) { + auto [start, end] = foldedInstrs.back(); + assert(end && "Should have found end of instruction"); + foldedInstrs.pop_back(); + + ParseInput foldedIn(in, start); + if (auto inst = instr(ctx, foldedIn)) { + CHECK_ERR(inst); + ctx.appendInstr(insts, *inst); + } else { + return foldedIn.err("expected folded instruction"); + } + + if (foldedIn.getPos() != *end) { + return foldedIn.err("expected end of instruction"); + } + } else { + WASM_UNREACHABLE("expected paren"); + } + } + continue; + } + + // A non-folded instruction. + if (auto inst = instr(ctx, in)) { + CHECK_ERR(inst); + ctx.appendInstr(insts, *inst); + } else { + break; + } } + return insts; } diff --git a/test/lit/wat-kitchen-sink.wast b/test/lit/wat-kitchen-sink.wast index 09c983c5d..4ec0f4a57 100644 --- a/test/lit/wat-kitchen-sink.wast +++ b/test/lit/wat-kitchen-sink.wast @@ -121,6 +121,66 @@ (func $f4 (type 13) (local i32 i64) (local $l f32)) (func (export "f5.0") (export "f5.1") (import "mod" "f5")) + ;; CHECK: (func $nop-skate (type $void) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $nop-skate + nop + nop + unreachable + nop + nop + ) + + ;; CHECK: (func $nop-ski (type $void) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $nop-ski + (unreachable + (nop + (nop) + (nop) + (nop + (nop) + ) + ) + (nop) + ) + (nop) + ) + + ;; CHECK: (func $nop-sled (type $void) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: (unreachable) + ;; CHECK-NEXT: (nop) + ;; CHECK-NEXT: ) + (func $nop-sled + nop + (nop + (nop + (unreachable) + ) + ) + nop + (unreachable) + nop + ) + ;; CHECK: (func $use-types (type $ref|$s0|_ref|$s1|_ref|$s2|_ref|$s3|_ref|$s4|_ref|$s5|_ref|$s6|_ref|$s7|_ref|$s8|_ref|$a0|_ref|$a1|_ref|$a2|_ref|$a3|_ref|$subvoid|_ref|$submany|_=>_none) (param $0 (ref $s0)) (param $1 (ref $s1)) (param $2 (ref $s2)) (param $3 (ref $s3)) (param $4 (ref $s4)) (param $5 (ref $s5)) (param $6 (ref $s6)) (param $7 (ref $s7)) (param $8 (ref $s8)) (param $9 (ref $a0)) (param $10 (ref $a1)) (param $11 (ref $a2)) (param $12 (ref $a3)) (param $13 (ref $subvoid)) (param $14 (ref $submany)) ;; CHECK-NEXT: (nop) ;; CHECK-NEXT: ) |