| // Copyright (c) 2026, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| import 'package:expect/expect.dart'; |
| import 'package:wasm_builder/wasm_builder.dart'; |
| |
| void main() { |
| testNoEffectTryTable(); |
| testOneOutputTryTable(); |
| testFunctionTryTable(); |
| } |
| |
| void testNoEffectTryTable() { |
| final moduleBuilder = ModuleBuilder('test', null); |
| final tagType = moduleBuilder.types.defineFunction(const [], const []); |
| final definedTag = moduleBuilder.tags.define(tagType); |
| final importedTag = moduleBuilder.tags.import('env', 'jsTag', tagType); |
| |
| final fnType = moduleBuilder.types.defineFunction(const [], const []); |
| final fn = moduleBuilder.functions.define(fnType, 'testNoEffect'); |
| final b = fn.body; |
| |
| final catchAllRefLabel = b.block(const [], const [ |
| RefType.exn(nullable: true), |
| ]); |
| final catchAllLabel = b.block(); |
| final catchRefLabel = b.block(const [], const [RefType.exn(nullable: true)]); |
| final catchLabel = b.block(); |
| |
| b.try_table([ |
| Catch(definedTag, catchLabel), |
| CatchRef(importedTag, catchRefLabel), |
| CatchAll(catchAllLabel), |
| CatchAllRef(catchAllRefLabel), |
| ]); |
| b.nop(); |
| b.end(); // end try_table |
| b.return_(); |
| |
| b.end(); // end catchLabel |
| b.return_(); |
| |
| b.end(); // end catchRefLabel |
| b.drop(); |
| b.return_(); |
| |
| b.end(); // end catchAllLabel |
| b.return_(); |
| |
| b.end(); // end catchAllRefLabel |
| b.drop(); |
| b.end(); // end function |
| fn.build(); |
| |
| final module = moduleBuilder.build(); |
| final wat = module.printAsWat(); |
| |
| Expect.isTrue(wat.contains('(tag \$env.jsTag (import "env" "jsTag"))')); |
| Expect.isTrue(wat.contains('(tag \$tag0)')); |
| Expect.isTrue( |
| wat.contains( |
| 'try_table \$label4 (catch \$tag0 \$label3) (catch_ref \$env.jsTag \$label2) ' |
| '(catch_all \$label1) (catch_all_ref \$label0)', |
| ), |
| 'Actual WAT:\n$wat', |
| ); |
| |
| // Verify round-trip serialize/deserialize preserves WAT output. |
| final serializer = Serializer(); |
| module.serialize(serializer); |
| final deserialized = Module.deserialize(Deserializer(serializer.data)); |
| Expect.equals(wat, deserialized.printAsWat()); |
| } |
| |
| void testOneOutputTryTable() { |
| final moduleBuilder = ModuleBuilder('test', null); |
| final tagType = moduleBuilder.types.defineFunction(const [ |
| NumType.i32, |
| ], const []); |
| final tag = moduleBuilder.tags.define(tagType); |
| |
| final fnType = moduleBuilder.types.defineFunction(const [], const [ |
| NumType.i32, |
| ]); |
| final fn = moduleBuilder.functions.define(fnType, 'testOneOutput'); |
| final b = fn.body; |
| |
| final catchLabel = b.block(const [], const [NumType.i32]); |
| b.try_table([Catch(tag, catchLabel)], const [], const [NumType.i32]); |
| b.i32_const(42); |
| b.end(); // end try_table |
| b.end(); // end catchLabel |
| b.end(); // end function |
| fn.build(); |
| |
| final module = moduleBuilder.build(); |
| final wat = module.printAsWat(); |
| |
| Expect.isTrue( |
| wat.contains('try_table \$label1 (result i32) (catch \$tag0 \$label0)'), |
| 'Actual WAT:\n$wat', |
| ); |
| |
| final serializer = Serializer(); |
| module.serialize(serializer); |
| final deserialized = Module.deserialize(Deserializer(serializer.data)); |
| Expect.equals(wat, deserialized.printAsWat()); |
| } |
| |
| void testFunctionTryTable() { |
| final moduleBuilder = ModuleBuilder('test', null); |
| final tagType = moduleBuilder.types.defineFunction(const [], const []); |
| moduleBuilder.tags.define(tagType); |
| |
| final fnType = moduleBuilder.types.defineFunction( |
| const [NumType.i32], |
| const [NumType.i32, NumType.i64], |
| ); |
| final fn = moduleBuilder.functions.define(fnType, 'testFunctionType'); |
| final b = fn.body; |
| |
| final catchLabel = b.block(); |
| b.local_get(b.locals[0]); |
| b.try_table([CatchAll(catchLabel)], const [NumType.i32], const [ |
| NumType.i32, |
| NumType.i64, |
| ]); |
| b.i64_const(100); |
| b.end(); // end try_table |
| b.return_(); |
| b.end(); // end catchLabel |
| b.i32_const(0); |
| b.i64_const(0); |
| b.end(); // end function |
| fn.build(); |
| |
| final module = moduleBuilder.build(); |
| final wat = module.printAsWat(); |
| |
| Expect.isTrue( |
| wat.contains( |
| 'try_table \$label1 (param i32) (result i32) (result i64) (catch_all \$label0)', |
| ), |
| 'Actual WAT:\n$wat', |
| ); |
| |
| final serializer = Serializer(); |
| module.serialize(serializer); |
| final deserialized = Module.deserialize(Deserializer(serializer.data)); |
| Expect.equals(wat, deserialized.printAsWat()); |
| } |