| /* | |
| * Copyright 2025 WebAssembly Community Group participants | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <variant> | |
| #include "passes/stringify-walker.h" | |
| #include "wasm-type.h" | |
| #include "wasm.h" | |
| #include "gtest/gtest.h" | |
| using namespace wasm; | |
| struct FuncStart { | |
| Function* func; | |
| bool operator==(const FuncStart& other) const { return func == other.func; } | |
| }; | |
| struct BlockStart { | |
| Block* block; | |
| bool operator==(const BlockStart& other) const { | |
| return block == other.block; | |
| } | |
| }; | |
| struct IfStart { | |
| If* iff; | |
| bool operator==(const IfStart& other) const { return iff == other.iff; } | |
| }; | |
| struct ElseStart { | |
| bool operator==(const ElseStart&) const { return true; } | |
| }; | |
| struct LoopStart { | |
| Loop* loop; | |
| bool operator==(const LoopStart& other) const { return loop == other.loop; } | |
| }; | |
| struct TryStart { | |
| Try* tryy; | |
| bool operator==(const TryStart& other) const { return tryy == other.tryy; } | |
| }; | |
| struct CatchStart { | |
| Name tag; | |
| bool operator==(const CatchStart& other) const { return tag == other.tag; } | |
| }; | |
| struct CatchAllStart { | |
| bool operator==(const CatchAllStart&) const { return true; } | |
| }; | |
| struct TryTableStart { | |
| TryTable* tryt; | |
| bool operator==(const TryTableStart& other) const { | |
| return tryt == other.tryt; | |
| } | |
| }; | |
| struct End { | |
| Expression* curr; | |
| bool operator==(const End& other) const { return curr == other.curr; } | |
| }; | |
| using Delimiter = std::variant<FuncStart, | |
| BlockStart, | |
| IfStart, | |
| ElseStart, | |
| LoopStart, | |
| TryStart, | |
| CatchStart, | |
| CatchAllStart, | |
| TryTableStart, | |
| End>; | |
| using Visited = std::variant<Expression*, Delimiter>; | |
| std::ostream& operator<<(std::ostream& o, const FuncStart& v) { | |
| return o << "FuncStart(" << v.func->name << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const BlockStart& v) { | |
| return o << "BlockStart(" << v.block->name << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const IfStart& v) { | |
| return o << "IfStart(" << v.iff << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const ElseStart& v) { | |
| return o << "ElseStart"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const LoopStart& v) { | |
| return o << "LoopStart(" << v.loop->name << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const TryStart& v) { | |
| return o << "TryStart(" << v.tryy->name << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const CatchStart& v) { | |
| return o << "CatchStart(" << v.tag << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const CatchAllStart& v) { | |
| return o << "CatchAllStart"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const TryTableStart& v) { | |
| return o << "TryTableStart(" << v.tryt << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const End& v) { | |
| return o << "End(" << v.curr << ")"; | |
| } | |
| std::ostream& operator<<(std::ostream& o, const Visited& v) { | |
| std::visit([&](auto&& arg) { o << arg; }, v); | |
| return o; | |
| } | |
| struct TestStringifyWalker : StringifyWalker<TestStringifyWalker> { | |
| using SeparatorReason = StringifyWalker<TestStringifyWalker>::SeparatorReason; | |
| std::vector<Visited> visited; | |
| void visitExpression(Expression* curr) { visited.push_back(curr); } | |
| void addUniqueSymbol(SeparatorReason curr) { | |
| if (auto* func = curr.getFuncStart()) { | |
| visited.push_back(FuncStart{func->func}); | |
| } else if (auto* block = curr.getBlockStart()) { | |
| visited.push_back(BlockStart{block->block}); | |
| } else if (auto* iff = curr.getIfStart()) { | |
| visited.push_back(IfStart{iff->iff}); | |
| } else if (curr.getElseStart()) { | |
| visited.push_back(ElseStart{}); | |
| } else if (auto* loop = curr.getLoopStart()) { | |
| visited.push_back(LoopStart{loop->loop}); | |
| } else if (auto* tryy = curr.getTryStart()) { | |
| visited.push_back(TryStart{tryy->tryy}); | |
| } else if (auto* tag = curr.getCatchStart()) { | |
| visited.push_back(CatchStart{tag->tag}); | |
| } else if (curr.getCatchAllStart()) { | |
| visited.push_back(CatchAllStart{}); | |
| } else if (auto* tryt = curr.getTryTableStart()) { | |
| visited.push_back(TryTableStart{tryt->tryt}); | |
| } else if (auto* end = curr.getEnd()) { | |
| visited.push_back(End{end->curr}); | |
| } | |
| } | |
| }; | |
| TEST(StringifyWalkerTest, Nop) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func nop) | |
| auto* nop = builder.makeNop(); | |
| auto f = builder.makeFunction("func", Signature(), {}, nop); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{ | |
| Visited(FuncStart{func}), Visited(nop), Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, Add) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (i32.add | |
| // (i32.const 0) | |
| // (i32.const 1) | |
| // ) | |
| // ) | |
| auto* a = builder.makeConst(uint32_t(0)); | |
| auto* b = builder.makeConst(uint32_t(1)); | |
| auto* add = builder.makeBinary(AddInt32, a, b); | |
| auto f = builder.makeFunction("func", Signature(), {}, add); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(a), | |
| Visited(b), | |
| Visited(add), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, EmptyBlock) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (block) | |
| // ) | |
| auto* block = builder.makeBlock(); | |
| auto f = builder.makeFunction("func", Signature(), {}, block); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(block), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{block}), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, SingletonBlock) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (block | |
| // (nop) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* block = builder.makeBlock({nop}); | |
| auto f = builder.makeFunction("func", Signature(), {}, block); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(block), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{block}), | |
| Visited(nop), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, Block) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (block | |
| // (nop) | |
| // (nop) | |
| // (nop) | |
| // ) | |
| // ) | |
| auto* nop1 = builder.makeNop(); | |
| auto* nop2 = builder.makeNop(); | |
| auto* nop3 = builder.makeNop(); | |
| auto* block = builder.makeBlock({nop1, nop2, nop3}); | |
| auto f = builder.makeFunction("func", Signature(), {}, block); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(block), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{block}), | |
| Visited(nop1), | |
| Visited(nop2), | |
| Visited(nop3), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, NestedBlocks) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (block $a | |
| // (block $b | |
| // (block $c | |
| // (nop) | |
| // ) | |
| // ) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* c = builder.makeBlock({nop}); | |
| auto* b = builder.makeBlock({c}); | |
| auto* a = builder.makeBlock({b}); | |
| auto f = builder.makeFunction("func", Signature(), {}, a); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(a), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{a}), | |
| Visited(b), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{b}), | |
| Visited(c), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{c}), | |
| Visited(nop), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, MixedBlock) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (block $a | |
| // (block $b) | |
| // (nop) | |
| // (block $c) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* b = builder.makeBlock(); | |
| auto* c = builder.makeBlock(); | |
| auto* a = builder.makeBlock({b, nop, c}); | |
| auto f = builder.makeFunction("func", Signature(), {}, a); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited{FuncStart{func}}, | |
| Visited(a), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{a}), | |
| Visited(b), | |
| Visited(nop), | |
| Visited(c), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{b}), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{c}), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, AddBlocks) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (i32.add | |
| // (block (i32.const 0)) | |
| // (block (i32.const 1)) | |
| // ) | |
| // ) | |
| auto* c0 = builder.makeConst(uint32_t(0)); | |
| auto* c1 = builder.makeConst(uint32_t(1)); | |
| auto* lhs = builder.makeBlock({c0}); | |
| auto* rhs = builder.makeBlock({c1}); | |
| auto* add = builder.makeBinary(AddInt32, lhs, rhs); | |
| auto f = builder.makeFunction("func", Signature(), {}, add); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(lhs), | |
| Visited(rhs), | |
| Visited(add), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{lhs}), | |
| Visited(c0), | |
| Visited(End{nullptr}), | |
| Visited(BlockStart{rhs}), | |
| Visited(c1), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, IfElse) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (if | |
| // (i32.const 1) | |
| // (then (nop)) | |
| // (else (nop)) | |
| // ) | |
| // ) | |
| auto* cond = builder.makeConst(uint32_t(1)); | |
| auto* ifTrue = builder.makeNop(); | |
| auto* ifFalse = builder.makeNop(); | |
| auto* iff = builder.makeIf(cond, ifTrue, ifFalse); | |
| auto f = builder.makeFunction("func", Signature(), {}, iff); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(cond), | |
| Visited(iff), | |
| Visited(End{nullptr}), | |
| Visited(IfStart{iff}), | |
| Visited(ifTrue), | |
| Visited(ElseStart{}), | |
| Visited(ifFalse), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, If) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (if | |
| // (i32.const 1) | |
| // (then (nop)) | |
| // ) | |
| // ) | |
| auto* cond = builder.makeConst(uint32_t(1)); | |
| auto* ifTrue = builder.makeNop(); | |
| auto* iff = builder.makeIf(cond, ifTrue); | |
| auto f = builder.makeFunction("func", Signature(), {}, iff); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(cond), | |
| Visited(iff), | |
| Visited(End{nullptr}), | |
| Visited(IfStart{iff}), | |
| Visited(ifTrue), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, IfNestedCondition) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (if | |
| // (if | |
| // (i32.const 1) | |
| // (then (i32.const 2)) | |
| // (else (i32.const 3)) | |
| // ) | |
| // (then (nop)) | |
| // (else (nop)) | |
| // ) | |
| // ) | |
| auto* c1 = builder.makeConst(uint32_t(1)); | |
| auto* c2 = builder.makeConst(uint32_t(2)); | |
| auto* c3 = builder.makeConst(uint32_t(3)); | |
| auto* cond = builder.makeIf(c1, c2, c3); | |
| auto* ifTrue = builder.makeNop(); | |
| auto* ifFalse = builder.makeNop(); | |
| auto* iff = builder.makeIf(cond, ifTrue, ifFalse); | |
| auto f = builder.makeFunction("func", Signature(), {}, iff); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(c1), | |
| Visited(cond), | |
| Visited(iff), | |
| Visited(End{nullptr}), | |
| Visited(IfStart{cond}), | |
| Visited(c2), | |
| Visited(ElseStart{}), | |
| Visited(c3), | |
| Visited(End{nullptr}), | |
| Visited(IfStart{iff}), | |
| Visited(ifTrue), | |
| Visited(ElseStart{}), | |
| Visited(ifFalse), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, Loop) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func (loop (nop))) | |
| auto* nop = builder.makeNop(); | |
| auto* loop = builder.makeLoop("loop", nop); | |
| auto f = builder.makeFunction("func", Signature(), {}, loop); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(loop), | |
| Visited(End{nullptr}), | |
| Visited(LoopStart{loop}), | |
| Visited(nop), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, Try) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (try | |
| // (do (nop)) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| std::vector<Name> tags; | |
| std::vector<Expression*> bodies; | |
| auto* tryy = builder.makeTry(nop, tags, bodies); | |
| auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(tryy), | |
| Visited(End{nullptr}), | |
| Visited(TryStart{tryy}), | |
| Visited(nop), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, TryCatch) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (try | |
| // (do (nop)) | |
| // (catch $e (nop)) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* body = builder.makeNop(); | |
| std::vector<Name> tags{"e"}; | |
| std::vector<Expression*> bodies{body}; | |
| auto* tryy = builder.makeTry(nop, tags, bodies); | |
| auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(tryy), | |
| Visited(End{nullptr}), | |
| Visited(TryStart{tryy}), | |
| Visited(nop), | |
| Visited(CatchStart{"e"}), | |
| Visited(body), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, TryCatchAll) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (try | |
| // (do (nop)) | |
| // (catch_all (nop)) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* body = builder.makeNop(); | |
| std::vector<Name> tags; | |
| std::vector<Expression*> bodies{body}; | |
| auto* tryy = builder.makeTry(nop, tags, bodies); | |
| auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(tryy), | |
| Visited(End{nullptr}), | |
| Visited(TryStart{tryy}), | |
| Visited(nop), | |
| Visited(CatchAllStart{}), | |
| Visited(body), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| TEST(StringifyWalkerTest, TryMultipleCatch) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (try | |
| // (do (nop)) | |
| // (catch $e1 (nop)) | |
| // (catch $e2 (nop)) | |
| // (catch_all (nop)) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| auto* body1 = builder.makeNop(); | |
| auto* body2 = builder.makeNop(); | |
| auto* body3 = builder.makeNop(); | |
| std::vector<Name> tags{"e1", "e2"}; | |
| std::vector<Expression*> bodies{body1, body2, body3}; | |
| auto* tryy = builder.makeTry(nop, tags, bodies); | |
| auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(tryy), | |
| Visited(End{nullptr}), | |
| Visited(TryStart{tryy}), | |
| Visited(nop), | |
| Visited(CatchStart{"e1"}), | |
| Visited(body1), | |
| Visited(CatchStart{"e2"}), | |
| Visited(body2), | |
| Visited(CatchAllStart{}), | |
| Visited(body3), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } | |
| // TEST(StringifyWalkerTest, TryDelegate) { | |
| // Module wasm; | |
| // Builder builder(wasm); | |
| // // (func $func | |
| // // (try | |
| // // (do (nop)) | |
| // // (delegate 0) | |
| // // ) | |
| // // ) | |
| // auto* nop = builder.makeNop(); | |
| // auto* tryy = builder.makeTry(nop, DELEGATE_CALLER_TARGET); | |
| // auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| // auto* func = f.get(); | |
| // wasm.addFunction(std::move(f)); | |
| // TestStringifyWalker walker; | |
| // walker.walkModule(&wasm); | |
| // std::vector<Visited> expected{Visited(FuncStart{func}), | |
| // Visited(tryy), | |
| // Visited(End{nullptr}), | |
| // Visited(TryStart{tryy}), | |
| // Visited(nop), | |
| // Visited(Delegate{})}; | |
| // EXPECT_EQ(walker.visited, expected); | |
| // } | |
| TEST(StringifyWalkerTest, TryTable) { | |
| Module wasm; | |
| Builder builder(wasm); | |
| // (func $func | |
| // (try_table | |
| // (nop) | |
| // ) | |
| // ) | |
| auto* nop = builder.makeNop(); | |
| std::vector<Name> tags; | |
| std::vector<Name> labels; | |
| std::vector<bool> refs; | |
| auto* tryy = builder.makeTryTable(nop, tags, labels, refs); | |
| auto f = builder.makeFunction("func", Signature(), {}, tryy); | |
| auto* func = f.get(); | |
| wasm.addFunction(std::move(f)); | |
| TestStringifyWalker walker; | |
| walker.walkModule(&wasm); | |
| std::vector<Visited> expected{Visited(FuncStart{func}), | |
| Visited(tryy), | |
| Visited(End{nullptr}), | |
| Visited(TryTableStart{tryy}), | |
| Visited(nop), | |
| Visited(End{nullptr})}; | |
| EXPECT_EQ(walker.visited, expected); | |
| } |