summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/wasm/wat-parser.cpp78
-rw-r--r--test/lit/wat-kitchen-sink.wast60
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: )