watr 3.3.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/bin/watr.js +83 -0
- package/dist/watr.js +1815 -0
- package/dist/watr.min.js +5 -0
- package/package.json +61 -14
- package/readme.md +42 -89
- package/src/compile.js +512 -590
- package/src/const.js +142 -56
- package/src/encode.js +89 -35
- package/src/parse.js +41 -32
- package/src/print.js +73 -12
- package/src/util.js +67 -35
- package/types/src/compile.d.ts +8 -0
- package/types/src/compile.d.ts.map +1 -0
- package/types/src/const.d.ts +87 -0
- package/types/src/const.d.ts.map +1 -0
- package/types/src/encode.d.ts +58 -0
- package/types/src/encode.d.ts.map +1 -0
- package/types/src/parse.d.ts +3 -0
- package/types/src/parse.d.ts.map +1 -0
- package/types/src/print.d.ts +16 -0
- package/types/src/print.d.ts.map +1 -0
- package/types/src/util.d.ts +18 -0
- package/types/src/util.d.ts.map +1 -0
- package/types/watr.d.ts +34 -0
- package/types/watr.d.ts.map +1 -0
- package/watr.js +233 -3
package/src/const.js
CHANGED
|
@@ -1,77 +1,163 @@
|
|
|
1
1
|
// https://webassembly.github.io/spec/core/appendix/index-instructions.html
|
|
2
|
+
// Format: 'name' or 'name handler'
|
|
3
|
+
// Immediate types: blocktype, labelidx, funcidx, typeidx, tableidx, memoryidx, globalidx, localidx, dataidx, elemidx, multi
|
|
4
|
+
// Value types: i32, i64, f32, f64, v128
|
|
2
5
|
export const INSTR = [
|
|
3
|
-
|
|
4
|
-
'
|
|
5
|
-
|
|
6
|
-
'
|
|
7
|
-
|
|
8
|
-
'
|
|
9
|
-
|
|
10
|
-
'
|
|
11
|
-
|
|
12
|
-
'
|
|
13
|
-
'i32.
|
|
6
|
+
// 0x00-0x0a: control
|
|
7
|
+
'unreachable', 'nop', 'block block', 'loop block', 'if block', 'else null', 'then null', , 'throw tagidx', , 'throw_ref',
|
|
8
|
+
// 0x0b-0x19: control
|
|
9
|
+
'end end', 'br labelidx', 'br_if labelidx', 'br_table br_table', 'return', 'call funcidx', 'call_indirect call_indirect', 'return_call funcidx', 'return_call_indirect call_indirect', 'call_ref typeidx', 'return_call_ref typeidx', , , , ,
|
|
10
|
+
// 0x1a-0x1f: parametric
|
|
11
|
+
'drop', 'select select', '', , , 'try_table try_table',
|
|
12
|
+
// 0x20-0x27: variable
|
|
13
|
+
'local.get localidx', 'local.set localidx', 'local.tee localidx', 'global.get globalidx', 'global.set globalidx', 'table.get tableidx', 'table.set tableidx', ,
|
|
14
|
+
// 0x28-0x3e: memory
|
|
15
|
+
'i32.load memarg', 'i64.load memarg', 'f32.load memarg', 'f64.load memarg',
|
|
16
|
+
'i32.load8_s memarg', 'i32.load8_u memarg', 'i32.load16_s memarg', 'i32.load16_u memarg',
|
|
17
|
+
'i64.load8_s memarg', 'i64.load8_u memarg', 'i64.load16_s memarg', 'i64.load16_u memarg', 'i64.load32_s memarg', 'i64.load32_u memarg',
|
|
18
|
+
'i32.store memarg', 'i64.store memarg', 'f32.store memarg', 'f64.store memarg',
|
|
19
|
+
'i32.store8 memarg', 'i32.store16 memarg', 'i64.store8 memarg', 'i64.store16 memarg', 'i64.store32 memarg',
|
|
20
|
+
// 0x3f-0x40: memory size/grow
|
|
21
|
+
'memory.size opt_memory', 'memory.grow opt_memory',
|
|
22
|
+
// 0x41-0x44: const
|
|
23
|
+
'i32.const i32', 'i64.const i64', 'f32.const f32', 'f64.const f64',
|
|
24
|
+
// 0x45-0x4f: i32 comparison
|
|
14
25
|
'i32.eqz', 'i32.eq', 'i32.ne', 'i32.lt_s', 'i32.lt_u', 'i32.gt_s', 'i32.gt_u', 'i32.le_s', 'i32.le_u', 'i32.ge_s', 'i32.ge_u',
|
|
26
|
+
// 0x50-0x5a: i64 comparison
|
|
15
27
|
'i64.eqz', 'i64.eq', 'i64.ne', 'i64.lt_s', 'i64.lt_u', 'i64.gt_s', 'i64.gt_u', 'i64.le_s', 'i64.le_u', 'i64.ge_s', 'i64.ge_u',
|
|
28
|
+
// 0x5b-0x60: f32 comparison
|
|
16
29
|
'f32.eq', 'f32.ne', 'f32.lt', 'f32.gt', 'f32.le', 'f32.ge',
|
|
30
|
+
// 0x61-0x66: f64 comparison
|
|
17
31
|
'f64.eq', 'f64.ne', 'f64.lt', 'f64.gt', 'f64.le', 'f64.ge',
|
|
32
|
+
// 0x67-0x78: i32 arithmetic
|
|
18
33
|
'i32.clz', 'i32.ctz', 'i32.popcnt', 'i32.add', 'i32.sub', 'i32.mul', 'i32.div_s', 'i32.div_u', 'i32.rem_s', 'i32.rem_u', 'i32.and', 'i32.or', 'i32.xor', 'i32.shl', 'i32.shr_s', 'i32.shr_u', 'i32.rotl', 'i32.rotr',
|
|
34
|
+
// 0x79-0x8a: i64 arithmetic
|
|
19
35
|
'i64.clz', 'i64.ctz', 'i64.popcnt', 'i64.add', 'i64.sub', 'i64.mul', 'i64.div_s', 'i64.div_u', 'i64.rem_s', 'i64.rem_u', 'i64.and', 'i64.or', 'i64.xor', 'i64.shl', 'i64.shr_s', 'i64.shr_u', 'i64.rotl', 'i64.rotr',
|
|
36
|
+
// 0x8b-0x98: f32 arithmetic
|
|
20
37
|
'f32.abs', 'f32.neg', 'f32.ceil', 'f32.floor', 'f32.trunc', 'f32.nearest', 'f32.sqrt', 'f32.add', 'f32.sub', 'f32.mul', 'f32.div', 'f32.min', 'f32.max', 'f32.copysign',
|
|
38
|
+
// 0x99-0xa6: f64 arithmetic
|
|
21
39
|
'f64.abs', 'f64.neg', 'f64.ceil', 'f64.floor', 'f64.trunc', 'f64.nearest', 'f64.sqrt', 'f64.add', 'f64.sub', 'f64.mul', 'f64.div', 'f64.min', 'f64.max', 'f64.copysign',
|
|
40
|
+
// 0xa7-0xc4: conversions (no immediates)
|
|
22
41
|
'i32.wrap_i64',
|
|
23
42
|
'i32.trunc_f32_s', 'i32.trunc_f32_u', 'i32.trunc_f64_s', 'i32.trunc_f64_u', 'i64.extend_i32_s', 'i64.extend_i32_u',
|
|
24
43
|
'i64.trunc_f32_s', 'i64.trunc_f32_u', 'i64.trunc_f64_s', 'i64.trunc_f64_u',
|
|
25
44
|
'f32.convert_i32_s', 'f32.convert_i32_u', 'f32.convert_i64_s', 'f32.convert_i64_u', 'f32.demote_f64',
|
|
26
45
|
'f64.convert_i32_s', 'f64.convert_i32_u', 'f64.convert_i64_s', 'f64.convert_i64_u', 'f64.promote_f32',
|
|
27
46
|
'i32.reinterpret_f32', 'i64.reinterpret_f64', 'f32.reinterpret_i32', 'f64.reinterpret_i64',
|
|
47
|
+
// 0xc0-0xc4: sign extension
|
|
28
48
|
'i32.extend8_s', 'i32.extend16_s', 'i64.extend8_s', 'i64.extend16_s', 'i64.extend32_s', , , , , , , , , , , ,
|
|
29
|
-
|
|
49
|
+
// 0xd0-0xd6: reference
|
|
50
|
+
'ref.null ref_null', 'ref.is_null', 'ref.func funcidx', 'ref.eq', 'ref.as_non_null', 'br_on_null labelidx', 'br_on_non_null labelidx',
|
|
51
|
+
// 0xd7-0xfa: padding to 0xfb (36 empty slots)
|
|
52
|
+
, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
|
|
53
|
+
// 0xfb: GC instructions (nested array for multi-byte opcodes)
|
|
54
|
+
[
|
|
55
|
+
'struct.new typeidx', 'struct.new_default typeidx', 'struct.get typeidx_field', 'struct.get_s typeidx_field', 'struct.get_u typeidx_field', 'struct.set typeidx_field',
|
|
56
|
+
'array.new typeidx', 'array.new_default typeidx', 'array.new_fixed typeidx_multi', 'array.new_data typeidx_dataidx', 'array.new_elem typeidx_elemidx',
|
|
57
|
+
'array.get typeidx', 'array.get_s typeidx', 'array.get_u typeidx', 'array.set typeidx', 'array.len', 'array.fill typeidx', 'array.copy typeidx_typeidx',
|
|
58
|
+
'array.init_data typeidx_dataidx', 'array.init_elem typeidx_elemidx', 'ref.test reftype', '', 'ref.cast reftype', '', 'br_on_cast reftype2', 'br_on_cast_fail reftype2',
|
|
59
|
+
'any.convert_extern', 'extern.convert_any', 'ref.i31', 'i31.get_s', 'i31.get_u'
|
|
60
|
+
],
|
|
30
61
|
|
|
31
|
-
//
|
|
32
|
-
|
|
62
|
+
// 0xfc: Bulk memory/table operations (nested array)
|
|
63
|
+
[
|
|
64
|
+
'i32.trunc_sat_f32_s', 'i32.trunc_sat_f32_u', 'i32.trunc_sat_f64_s', 'i32.trunc_sat_f64_u',
|
|
65
|
+
'i64.trunc_sat_f32_s', 'i64.trunc_sat_f32_u', 'i64.trunc_sat_f64_s', 'i64.trunc_sat_f64_u',
|
|
66
|
+
'memory.init dataidx_memoryidx', 'data.drop dataidx', 'memory.copy memoryidx_memoryidx', 'memory.fill memoryidx?',
|
|
67
|
+
'table.init reversed', 'elem.drop elemidx', 'table.copy tableidx_tableidx', 'table.grow tableidx', 'table.size tableidx', 'table.fill tableidx', ,
|
|
68
|
+
'i64.add128', 'i64.sub128', 'i64.mul_wide_s', 'i64.mul_wide_u'
|
|
69
|
+
],
|
|
33
70
|
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
71
|
+
// 0xfd: SIMD instructions (nested array)
|
|
72
|
+
[
|
|
73
|
+
'v128.load memarg', 'v128.load8x8_s memarg', 'v128.load8x8_u memarg', 'v128.load16x4_s memarg', 'v128.load16x4_u memarg',
|
|
74
|
+
'v128.load32x2_s memarg', 'v128.load32x2_u memarg', 'v128.load8_splat memarg', 'v128.load16_splat memarg', 'v128.load32_splat memarg',
|
|
75
|
+
'v128.load64_splat memarg', 'v128.store memarg', 'v128.const v128const', 'i8x16.shuffle shuffle',
|
|
76
|
+
'i8x16.swizzle', 'i8x16.splat', 'i16x8.splat', 'i32x4.splat', 'i64x2.splat', 'f32x4.splat', 'f64x2.splat',
|
|
77
|
+
'i8x16.extract_lane_s laneidx', 'i8x16.extract_lane_u laneidx', 'i8x16.replace_lane laneidx',
|
|
78
|
+
'i16x8.extract_lane_s laneidx', 'i16x8.extract_lane_u laneidx', 'i16x8.replace_lane laneidx',
|
|
79
|
+
'i32x4.extract_lane laneidx', 'i32x4.replace_lane laneidx', 'i64x2.extract_lane laneidx', 'i64x2.replace_lane laneidx',
|
|
80
|
+
'f32x4.extract_lane laneidx', 'f32x4.replace_lane laneidx', 'f64x2.extract_lane laneidx', 'f64x2.replace_lane laneidx',
|
|
81
|
+
'i8x16.eq', 'i8x16.ne', 'i8x16.lt_s', 'i8x16.lt_u', 'i8x16.gt_s', 'i8x16.gt_u', 'i8x16.le_s', 'i8x16.le_u', 'i8x16.ge_s', 'i8x16.ge_u',
|
|
82
|
+
'i16x8.eq', 'i16x8.ne', 'i16x8.lt_s', 'i16x8.lt_u', 'i16x8.gt_s', 'i16x8.gt_u', 'i16x8.le_s', 'i16x8.le_u', 'i16x8.ge_s', 'i16x8.ge_u',
|
|
83
|
+
'i32x4.eq', 'i32x4.ne', 'i32x4.lt_s', 'i32x4.lt_u', 'i32x4.gt_s', 'i32x4.gt_u', 'i32x4.le_s', 'i32x4.le_u', 'i32x4.ge_s', 'i32x4.ge_u',
|
|
84
|
+
'f32x4.eq', 'f32x4.ne', 'f32x4.lt', 'f32x4.gt', 'f32x4.le', 'f32x4.ge', 'f64x2.eq', 'f64x2.ne', 'f64x2.lt', 'f64x2.gt', 'f64x2.le', 'f64x2.ge',
|
|
85
|
+
'v128.not', 'v128.and', 'v128.andnot', 'v128.or', 'v128.xor', 'v128.bitselect', 'v128.any_true',
|
|
86
|
+
'v128.load8_lane memlane', 'v128.load16_lane memlane', 'v128.load32_lane memlane', 'v128.load64_lane memlane',
|
|
87
|
+
'v128.store8_lane memlane', 'v128.store16_lane memlane', 'v128.store32_lane memlane', 'v128.store64_lane memlane',
|
|
88
|
+
'v128.load32_zero memarg', 'v128.load64_zero memarg', 'f32x4.demote_f64x2_zero', 'f64x2.promote_low_f32x4',
|
|
89
|
+
'i8x16.abs', 'i8x16.neg', 'i8x16.popcnt', 'i8x16.all_true', 'i8x16.bitmask', 'i8x16.narrow_i16x8_s', 'i8x16.narrow_i16x8_u',
|
|
90
|
+
'f32x4.ceil', 'f32x4.floor', 'f32x4.trunc', 'f32x4.nearest', 'i8x16.shl', 'i8x16.shr_s', 'i8x16.shr_u',
|
|
91
|
+
'i8x16.add', 'i8x16.add_sat_s', 'i8x16.add_sat_u', 'i8x16.sub', 'i8x16.sub_sat_s', 'i8x16.sub_sat_u',
|
|
92
|
+
'f64x2.ceil', 'f64x2.floor', 'i8x16.min_s', 'i8x16.min_u', 'i8x16.max_s', 'i8x16.max_u', 'f64x2.trunc', 'i8x16.avgr_u',
|
|
93
|
+
'i16x8.extadd_pairwise_i8x16_s', 'i16x8.extadd_pairwise_i8x16_u', 'i32x4.extadd_pairwise_i16x8_s', 'i32x4.extadd_pairwise_i16x8_u',
|
|
94
|
+
'i16x8.abs', 'i16x8.neg', 'i16x8.q15mulr_sat_s', 'i16x8.all_true', 'i16x8.bitmask', 'i16x8.narrow_i32x4_s', 'i16x8.narrow_i32x4_u',
|
|
95
|
+
'i16x8.extend_low_i8x16_s', 'i16x8.extend_high_i8x16_s', 'i16x8.extend_low_i8x16_u', 'i16x8.extend_high_i8x16_u',
|
|
96
|
+
'i16x8.shl', 'i16x8.shr_s', 'i16x8.shr_u', 'i16x8.add', 'i16x8.add_sat_s', 'i16x8.add_sat_u', 'i16x8.sub', 'i16x8.sub_sat_s', 'i16x8.sub_sat_u',
|
|
97
|
+
'f64x2.nearest', 'i16x8.mul', 'i16x8.min_s', 'i16x8.min_u', 'i16x8.max_s', 'i16x8.max_u', , 'i16x8.avgr_u',
|
|
98
|
+
'i16x8.extmul_low_i8x16_s', 'i16x8.extmul_high_i8x16_s', 'i16x8.extmul_low_i8x16_u', 'i16x8.extmul_high_i8x16_u',
|
|
99
|
+
'i32x4.abs', 'i32x4.neg', , 'i32x4.all_true', 'i32x4.bitmask', , , 'i32x4.extend_low_i16x8_s', 'i32x4.extend_high_i16x8_s',
|
|
100
|
+
'i32x4.extend_low_i16x8_u', 'i32x4.extend_high_i16x8_u', 'i32x4.shl', 'i32x4.shr_s', 'i32x4.shr_u', 'i32x4.add', , , 'i32x4.sub', , , ,
|
|
101
|
+
'i32x4.mul', 'i32x4.min_s', 'i32x4.min_u', 'i32x4.max_s', 'i32x4.max_u', 'i32x4.dot_i16x8_s', ,
|
|
102
|
+
'i32x4.extmul_low_i16x8_s', 'i32x4.extmul_high_i16x8_s', 'i32x4.extmul_low_i16x8_u', 'i32x4.extmul_high_i16x8_u',
|
|
103
|
+
'i64x2.abs', 'i64x2.neg', , 'i64x2.all_true', 'i64x2.bitmask', , , 'i64x2.extend_low_i32x4_s', 'i64x2.extend_high_i32x4_s',
|
|
104
|
+
'i64x2.extend_low_i32x4_u', 'i64x2.extend_high_i32x4_u', 'i64x2.shl', 'i64x2.shr_s', 'i64x2.shr_u', 'i64x2.add', , , 'i64x2.sub', , , ,
|
|
105
|
+
'i64x2.mul', 'i64x2.eq', 'i64x2.ne', 'i64x2.lt_s', 'i64x2.gt_s', 'i64x2.le_s', 'i64x2.ge_s',
|
|
106
|
+
'i64x2.extmul_low_i32x4_s', 'i64x2.extmul_high_i32x4_s', 'i64x2.extmul_low_i32x4_u', 'i64x2.extmul_high_i32x4_u',
|
|
107
|
+
'f32x4.abs', 'f32x4.neg', , 'f32x4.sqrt', 'f32x4.add', 'f32x4.sub', 'f32x4.mul', 'f32x4.div', 'f32x4.min', 'f32x4.max', 'f32x4.pmin', 'f32x4.pmax',
|
|
108
|
+
'f64x2.abs', 'f64x2.neg', , 'f64x2.sqrt', 'f64x2.add', 'f64x2.sub', 'f64x2.mul', 'f64x2.div', 'f64x2.min', 'f64x2.max', 'f64x2.pmin', 'f64x2.pmax',
|
|
109
|
+
'i32x4.trunc_sat_f32x4_s', 'i32x4.trunc_sat_f32x4_u', 'f32x4.convert_i32x4_s', 'f32x4.convert_i32x4_u',
|
|
110
|
+
'i32x4.trunc_sat_f64x2_s_zero', 'i32x4.trunc_sat_f64x2_u_zero', 'f64x2.convert_low_i32x4_s', 'f64x2.convert_low_i32x4_u',
|
|
111
|
+
'i8x16.relaxed_swizzle', 'i32x4.relaxed_trunc_f32x4_s', 'i32x4.relaxed_trunc_f32x4_u', 'i32x4.relaxed_trunc_f64x2_s_zero',
|
|
112
|
+
'i32x4.relaxed_trunc_f64x2_u_zero', 'f32x4.relaxed_madd', 'f32x4.relaxed_nmadd', 'f64x2.relaxed_madd', 'f64x2.relaxed_nmadd',
|
|
113
|
+
'i8x16.relaxed_laneselect', 'i16x8.relaxed_laneselect', 'i32x4.relaxed_laneselect', 'i64x2.relaxed_laneselect',
|
|
114
|
+
'f32x4.relaxed_min', 'f32x4.relaxed_max', 'f64x2.relaxed_min', 'f64x2.relaxed_max',
|
|
115
|
+
'i16x8.relaxed_q15mulr_s', 'i16x8.relaxed_dot_i8x16_i7x16_s', 'i32x4.relaxed_dot_i8x16_i7x16_add_s'
|
|
116
|
+
],
|
|
117
|
+
// 0xfe: atomic/thread instructions
|
|
118
|
+
[
|
|
119
|
+
'memory.atomic.notify memarg', 'memory.atomic.wait32 memarg', 'memory.atomic.wait64 memarg', 'atomic.fence opt_memory',
|
|
120
|
+
,,,,,,,,,,,,
|
|
121
|
+
'i32.atomic.load memarg', 'i64.atomic.load memarg', 'i32.atomic.load8_u memarg', 'i32.atomic.load16_u memarg',
|
|
122
|
+
'i64.atomic.load8_u memarg', 'i64.atomic.load16_u memarg', 'i64.atomic.load32_u memarg', 'i32.atomic.store memarg',
|
|
123
|
+
'i64.atomic.store memarg', 'i32.atomic.store8 memarg', 'i32.atomic.store16 memarg', 'i64.atomic.store8 memarg',
|
|
124
|
+
'i64.atomic.store16 memarg', 'i64.atomic.store32 memarg', 'i32.atomic.rmw.add memarg', 'i64.atomic.rmw.add memarg',
|
|
125
|
+
'i32.atomic.rmw8.add_u memarg', 'i32.atomic.rmw16.add_u memarg', 'i64.atomic.rmw8.add_u memarg', 'i64.atomic.rmw16.add_u memarg',
|
|
126
|
+
'i64.atomic.rmw32.add_u memarg', 'i32.atomic.rmw.sub memarg', 'i64.atomic.rmw.sub memarg', 'i32.atomic.rmw8.sub_u memarg',
|
|
127
|
+
'i32.atomic.rmw16.sub_u memarg', 'i64.atomic.rmw8.sub_u memarg', 'i64.atomic.rmw16.sub_u memarg', 'i64.atomic.rmw32.sub_u memarg',
|
|
128
|
+
'i32.atomic.rmw.and memarg', 'i64.atomic.rmw.and memarg', 'i32.atomic.rmw8.and_u memarg', 'i32.atomic.rmw16.and_u memarg',
|
|
129
|
+
'i64.atomic.rmw8.and_u memarg', 'i64.atomic.rmw16.and_u memarg', 'i64.atomic.rmw32.and_u memarg', 'i32.atomic.rmw.or memarg',
|
|
130
|
+
'i64.atomic.rmw.or memarg', 'i32.atomic.rmw8.or_u memarg', 'i32.atomic.rmw16.or_u memarg', 'i64.atomic.rmw8.or_u memarg',
|
|
131
|
+
'i64.atomic.rmw16.or_u memarg', 'i64.atomic.rmw32.or_u memarg', 'i32.atomic.rmw.xor memarg', 'i64.atomic.rmw.xor memarg',
|
|
132
|
+
'i32.atomic.rmw8.xor_u memarg', 'i32.atomic.rmw16.xor_u memarg', 'i64.atomic.rmw8.xor_u memarg', 'i64.atomic.rmw16.xor_u memarg',
|
|
133
|
+
'i64.atomic.rmw32.xor_u memarg', 'i32.atomic.rmw.xchg memarg', 'i64.atomic.rmw.xchg memarg', 'i32.atomic.rmw8.xchg_u memarg',
|
|
134
|
+
'i32.atomic.rmw16.xchg_u memarg', 'i64.atomic.rmw8.xchg_u memarg', 'i64.atomic.rmw16.xchg_u memarg', 'i64.atomic.rmw32.xchg_u memarg',
|
|
135
|
+
'i32.atomic.rmw.cmpxchg memarg', 'i64.atomic.rmw.cmpxchg memarg', 'i32.atomic.rmw8.cmpxchg_u memarg', 'i32.atomic.rmw16.cmpxchg_u memarg',
|
|
136
|
+
'i64.atomic.rmw8.cmpxchg_u memarg', 'i64.atomic.rmw16.cmpxchg_u memarg', 'i64.atomic.rmw32.cmpxchg_u memarg'
|
|
137
|
+
]
|
|
138
|
+
]
|
|
38
139
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
'i8x16.swizzle', 'i8x16.splat', 'i16x8.splat', 'i32x4.splat', 'i64x2.splat', 'f32x4.splat', 'f64x2.splat',
|
|
42
|
-
'i8x16.extract_lane_s', 'i8x16.extract_lane_u', 'i8x16.replace_lane', 'i16x8.extract_lane_s', 'i16x8.extract_lane_u', 'i16x8.replace_lane', 'i32x4.extract_lane', 'i32x4.replace_lane', 'i64x2.extract_lane', 'i64x2.replace_lane', 'f32x4.extract_lane', 'f32x4.replace_lane', 'f64x2.extract_lane', 'f64x2.replace_lane',
|
|
43
|
-
'i8x16.eq', 'i8x16.ne', 'i8x16.lt_s', 'i8x16.lt_u', 'i8x16.gt_s', 'i8x16.gt_u', 'i8x16.le_s', 'i8x16.le_u', 'i8x16.ge_s', 'i8x16.ge_u', 'i16x8.eq', 'i16x8.ne', 'i16x8.lt_s', 'i16x8.lt_u', 'i16x8.gt_s', 'i16x8.gt_u', 'i16x8.le_s', 'i16x8.le_u', 'i16x8.ge_s', 'i16x8.ge_u', 'i32x4.eq', 'i32x4.ne', 'i32x4.lt_s', 'i32x4.lt_u', 'i32x4.gt_s', 'i32x4.gt_u', 'i32x4.le_s', 'i32x4.le_u', 'i32x4.ge_s', 'i32x4.ge_u', 'f32x4.eq', 'f32x4.ne', 'f32x4.lt', 'f32x4.gt', 'f32x4.le', 'f32x4.ge', 'f64x2.eq', 'f64x2.ne', 'f64x2.lt', 'f64x2.gt', 'f64x2.le', 'f64x2.ge', 'v128.not', 'v128.and', 'v128.andnot', 'v128.or', 'v128.xor', 'v128.bitselect', 'v128.any_true',
|
|
44
|
-
'v128.load8_lane', 'v128.load16_lane', 'v128.load32_lane', 'v128.load64_lane', 'v128.store8_lane', 'v128.store16_lane', 'v128.store32_lane', 'v128.store64_lane', 'v128.load32_zero', 'v128.load64_zero', 'f32x4.demote_f64x2_zero', 'f64x2.promote_low_f32x4',
|
|
45
|
-
'i8x16.abs', 'i8x16.neg', 'i8x16.popcnt', 'i8x16.all_true', 'i8x16.bitmask', 'i8x16.narrow_i16x8_s', 'i8x16.narrow_i16x8_u', 'f32x4.ceil', 'f32x4.floor', 'f32x4.trunc', 'f32x4.nearest', 'i8x16.shl', 'i8x16.shr_s', 'i8x16.shr_u', 'i8x16.add', 'i8x16.add_sat_s', 'i8x16.add_sat_u', 'i8x16.sub', 'i8x16.sub_sat_s', 'i8x16.sub_sat_u', 'f64x2.ceil', 'f64x2.floor', 'i8x16.min_s', 'i8x16.min_u', 'i8x16.max_s', 'i8x16.max_u', 'f64x2.trunc', 'i8x16.avgr_u',
|
|
46
|
-
'i16x8.extadd_pairwise_i8x16_s', 'i16x8.extadd_pairwise_i8x16_u', 'i32x4.extadd_pairwise_i16x8_s', 'i32x4.extadd_pairwise_i16x8_u', 'i16x8.abs', 'i16x8.neg', 'i16x8.q15mulr_sat_s', 'i16x8.all_true', 'i16x8.bitmask', 'i16x8.narrow_i32x4_s', 'i16x8.narrow_i32x4_u', 'i16x8.extend_low_i8x16_s', 'i16x8.extend_high_i8x16_s', 'i16x8.extend_low_i8x16_u', 'i16x8.extend_high_i8x16_u',
|
|
47
|
-
'i16x8.shl', 'i16x8.shr_s', 'i16x8.shr_u', 'i16x8.add', 'i16x8.add_sat_s', 'i16x8.add_sat_u', 'i16x8.sub', 'i16x8.sub_sat_s', 'i16x8.sub_sat_u', 'f64x2.nearest', 'i16x8.mul', 'i16x8.min_s', 'i16x8.min_u', 'i16x8.max_s', 'i16x8.max_u', , 'i16x8.avgr_u',
|
|
48
|
-
'i16x8.extmul_low_i8x16_s', 'i16x8.extmul_high_i8x16_s', 'i16x8.extmul_low_i8x16_u', 'i16x8.extmul_high_i8x16_u', 'i32x4.abs', 'i32x4.neg', , 'i32x4.all_true', 'i32x4.bitmask', , , 'i32x4.extend_low_i16x8_s', 'i32x4.extend_high_i16x8_s', 'i32x4.extend_low_i16x8_u', 'i32x4.extend_high_i16x8_u', 'i32x4.shl', 'i32x4.shr_s', 'i32x4.shr_u', 'i32x4.add', , , 'i32x4.sub', , , , 'i32x4.mul', 'i32x4.min_s', 'i32x4.min_u', 'i32x4.max_s', 'i32x4.max_u', 'i32x4.dot_i16x8_s', , 'i32x4.extmul_low_i16x8_s', 'i32x4.extmul_high_i16x8_s', 'i32x4.extmul_low_i16x8_u', 'i32x4.extmul_high_i16x8_u', 'i64x2.abs', 'i64x2.neg', , 'i64x2.all_true', 'i64x2.bitmask', , , 'i64x2.extend_low_i32x4_s', 'i64x2.extend_high_i32x4_s', 'i64x2.extend_low_i32x4_u', 'i64x2.extend_high_i32x4_u', 'i64x2.shl', 'i64x2.shr_s', 'i64x2.shr_u', 'i64x2.add', , , 'i64x2.sub', , , , 'i64x2.mul', 'i64x2.eq', 'i64x2.ne', 'i64x2.lt_s', 'i64x2.gt_s', 'i64x2.le_s', 'i64x2.ge_s', 'i64x2.extmul_low_i32x4_s', 'i64x2.extmul_high_i32x4_s', 'i64x2.extmul_low_i32x4_u', 'i64x2.extmul_high_i32x4_u', 'f32x4.abs', 'f32x4.neg', , 'f32x4.sqrt', 'f32x4.add', 'f32x4.sub', 'f32x4.mul', 'f32x4.div', 'f32x4.min', 'f32x4.max', 'f32x4.pmin', 'f32x4.pmax', 'f64x2.abs', 'f64x2.neg', , 'f64x2.sqrt', 'f64x2.add', 'f64x2.sub', 'f64x2.mul', 'f64x2.div', 'f64x2.min', 'f64x2.max', 'f64x2.pmin', 'f64x2.pmax', 'i32x4.trunc_sat_f32x4_s', 'i32x4.trunc_sat_f32x4_u', 'f32x4.convert_i32x4_s', 'f32x4.convert_i32x4_u', 'i32x4.trunc_sat_f64x2_s_zero', 'i32x4.trunc_sat_f64x2_u_zero', 'f64x2.convert_low_i32x4_s', 'f64x2.convert_low_i32x4_u',
|
|
49
|
-
// relaxed SIMD instructions
|
|
50
|
-
'i8x16.relaxed_swizzle', 'i32x4.relaxed_trunc_f32x4_s', 'i32x4.relaxed_trunc_f32x4_u', 'i32x4.relaxed_trunc_f64x2_s_zero', 'i32x4.relaxed_trunc_f64x2_u_zero', 'f32x4.relaxed_madd', 'f32x4.relaxed_nmadd', 'f64x2.relaxed_madd', 'f64x2.relaxed_nmadd', 'i8x16.relaxed_laneselect', 'i16x8.relaxed_laneselect', 'i32x4.relaxed_laneselect', 'i64x2.relaxed_laneselect', 'f32x4.relaxed_min', 'f32x4.relaxed_max', 'f64x2.relaxed_min', 'f64x2.relaxed_max', 'i16x8.relaxed_q15mulr_s', 'i16x8.relaxed_dot_i8x16_i7x16_s', 'i32x4.relaxed_dot_i8x16_i7x16_add_s'
|
|
51
|
-
],
|
|
52
|
-
SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, global: 6, tag: 13, export: 7, start: 8, elem: 9, datacount: 12, code: 10, data: 11 },
|
|
53
|
-
RECTYPE = { sub: 0x50, subfinal: 0x4F, rec: 0x4E },
|
|
54
|
-
DEFTYPE = { func: 0x60, struct: 0x5F, array: 0x5E, ...RECTYPE },
|
|
55
|
-
HEAPTYPE = { nofunc: 0x73, noextern: 0x72, noexn: 0x74, none: 0x71, func: 0x70, extern: 0x6F, exn: 0x75, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A },
|
|
56
|
-
REFTYPE = {
|
|
57
|
-
// absheaptype abbrs
|
|
58
|
-
nullfuncref: HEAPTYPE.nofunc,
|
|
59
|
-
nullexternref: HEAPTYPE.noextern,
|
|
60
|
-
nullexnref: HEAPTYPE.noexn,
|
|
61
|
-
nullref: HEAPTYPE.none,
|
|
62
|
-
funcref: HEAPTYPE.func,
|
|
63
|
-
externref: HEAPTYPE.extern,
|
|
64
|
-
exnref: HEAPTYPE.exn,
|
|
65
|
-
anyref: HEAPTYPE.any,
|
|
66
|
-
eqref: HEAPTYPE.eq,
|
|
67
|
-
i31ref: HEAPTYPE.i31,
|
|
68
|
-
structref: HEAPTYPE.struct,
|
|
69
|
-
arrayref: HEAPTYPE.array,
|
|
140
|
+
// Binary section type codes
|
|
141
|
+
export const SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, tag: 13, global: 6, export: 7, start: 8, elem: 9, datacount: 12, code: 10, data: 11 }
|
|
70
142
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
143
|
+
// Type codes
|
|
144
|
+
export const TYPE = {
|
|
145
|
+
// Value types
|
|
146
|
+
i8: 0x78, i16: 0x77, i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, v128: 0x7B,
|
|
147
|
+
// Heap types
|
|
148
|
+
exn: 0x69, noexn: 0x74, nofunc: 0x73, noextern: 0x72, none: 0x71, func: 0x70, extern: 0x6F, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A,
|
|
149
|
+
// Reference type abbreviations (absheaptype abbrs)
|
|
150
|
+
nullfuncref: 0x73, nullexternref: 0x72, nullexnref: 0x74, nullref: 0x71,
|
|
151
|
+
funcref: 0x70, externref: 0x6F, exnref: 0x69, anyref: 0x6E, eqref: 0x6D, i31ref: 0x6C, structref: 0x6B, arrayref: 0x6A,
|
|
152
|
+
// ref, refnull
|
|
153
|
+
ref: 0x64, // -0x1c
|
|
154
|
+
refnull: 0x63, // -0x1d
|
|
155
|
+
// Recursion group / type definition opcodes
|
|
156
|
+
sub: 0x50, subfinal: 0x4F, rec: 0x4E
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Type definition codes (different from heap types - func is 0x60 not 0x70)
|
|
160
|
+
export const DEFTYPE = { func: 0x60, struct: 0x5F, array: 0x5E, sub: 0x50, subfinal: 0x4F, rec: 0x4E }
|
|
161
|
+
|
|
162
|
+
// Import/export kind codes
|
|
163
|
+
export const KIND = { func: 0, table: 1, memory: 2, global: 3, tag: 4 }
|
package/src/encode.js
CHANGED
|
@@ -1,40 +1,75 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Binary encoding utilities for WebAssembly.
|
|
3
|
+
* @module encode
|
|
4
|
+
* @see https://webassembly.github.io/spec/core/binary/values.html
|
|
5
|
+
*/
|
|
2
6
|
|
|
3
|
-
|
|
7
|
+
import { err, intRE, sepRE } from './util.js'
|
|
4
8
|
|
|
5
|
-
|
|
9
|
+
/**
|
|
10
|
+
* Encode unsigned LEB128. Handles both 32-bit numbers and 64-bit BigInts.
|
|
11
|
+
*
|
|
12
|
+
* @param {number|bigint|string|null} n - Value to encode
|
|
13
|
+
* @param {number[]} [buffer=[]] - Output buffer
|
|
14
|
+
* @returns {number[]} Encoded bytes
|
|
15
|
+
*/
|
|
6
16
|
export const uleb = (n, buffer = []) => {
|
|
7
17
|
if (n == null) return buffer
|
|
8
|
-
if (typeof n === 'string') n = i32.parse(n)
|
|
18
|
+
if (typeof n === 'string') n = /[_x]/i.test(n) ? BigInt(n.replaceAll('_', '')) : i32.parse(n)
|
|
19
|
+
|
|
20
|
+
// Handle BigInt for 64-bit values
|
|
21
|
+
if (typeof n === 'bigint') {
|
|
22
|
+
while (true) {
|
|
23
|
+
const byte = Number(n & 0x7Fn)
|
|
24
|
+
n >>= 7n
|
|
25
|
+
if (n === 0n) {
|
|
26
|
+
buffer.push(byte)
|
|
27
|
+
break
|
|
28
|
+
}
|
|
29
|
+
buffer.push(byte | 0x80)
|
|
30
|
+
}
|
|
31
|
+
return buffer
|
|
32
|
+
}
|
|
9
33
|
|
|
10
|
-
|
|
11
|
-
|
|
34
|
+
// Handle regular numbers for 32-bit values
|
|
35
|
+
let byte = n & 0x7f
|
|
36
|
+
n >>>= 7
|
|
12
37
|
|
|
13
38
|
if (n === 0) {
|
|
14
|
-
buffer.push(byte)
|
|
15
|
-
return buffer
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
39
|
+
buffer.push(byte)
|
|
40
|
+
return buffer
|
|
41
|
+
}
|
|
42
|
+
buffer.push(byte | 0x80)
|
|
43
|
+
return uleb(n, buffer)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Encode as fixed-width 5-byte ULEB128 (canonical form).
|
|
48
|
+
* Used by some tools for predictable binary layout.
|
|
49
|
+
*
|
|
50
|
+
* @param {number} value - 32-bit unsigned value
|
|
51
|
+
* @returns {number[]} 5-byte array
|
|
52
|
+
*/
|
|
53
|
+
export function uleb5(value) {
|
|
54
|
+
const result = [];
|
|
55
|
+
for (let i = 0; i < 5; i++) {
|
|
56
|
+
let byte = value & 0x7f;
|
|
57
|
+
value >>>= 7;
|
|
58
|
+
if (i < 4) {
|
|
59
|
+
byte |= 0x80; // Set continuation bit for first 4 bytes
|
|
60
|
+
}
|
|
61
|
+
result.push(byte);
|
|
19
62
|
}
|
|
63
|
+
return result;
|
|
20
64
|
}
|
|
21
65
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
// byte |= 0x80; // Set continuation bit for first 4 bytes
|
|
30
|
-
// }
|
|
31
|
-
// result.push(byte);
|
|
32
|
-
// }
|
|
33
|
-
// return result;
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// leb
|
|
66
|
+
/**
|
|
67
|
+
* Encode signed LEB128 for i32 values.
|
|
68
|
+
*
|
|
69
|
+
* @param {number|string} n - Signed 32-bit value
|
|
70
|
+
* @param {number[]} [buffer=[]] - Output buffer
|
|
71
|
+
* @returns {number[]} Encoded bytes
|
|
72
|
+
*/
|
|
38
73
|
export function i32(n, buffer = []) {
|
|
39
74
|
if (typeof n === 'string') n = i32.parse(n)
|
|
40
75
|
|
|
@@ -56,9 +91,19 @@ const cleanInt = (v) => (!sepRE.test(v) && intRE.test(v=v.replaceAll('_',''))) ?
|
|
|
56
91
|
// alias
|
|
57
92
|
export const i8 = i32, i16 = i32
|
|
58
93
|
|
|
59
|
-
i32.parse = n =>
|
|
94
|
+
i32.parse = n => {
|
|
95
|
+
n = parseInt(cleanInt(n))
|
|
96
|
+
if (n < -0x80000000 || n > 0xffffffff) err(`i32 constant out of range`)
|
|
97
|
+
return n
|
|
98
|
+
}
|
|
60
99
|
|
|
61
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Encode signed LEB128 for i64 values (BigInt).
|
|
102
|
+
*
|
|
103
|
+
* @param {bigint|string} n - Signed 64-bit value
|
|
104
|
+
* @param {number[]} [buffer=[]] - Output buffer
|
|
105
|
+
* @returns {number[]} Encoded bytes
|
|
106
|
+
*/
|
|
62
107
|
export function i64(n, buffer = []) {
|
|
63
108
|
if (typeof n === 'string') n = i64.parse(n)
|
|
64
109
|
|
|
@@ -76,6 +121,7 @@ export function i64(n, buffer = []) {
|
|
|
76
121
|
i64.parse = n => {
|
|
77
122
|
n = cleanInt(n)
|
|
78
123
|
n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n) // can be -0x123
|
|
124
|
+
if (n < -0x8000000000000000n || n > 0xffffffffffffffffn) err(`i64 constant out of range`)
|
|
79
125
|
byteView.setBigInt64(0, n)
|
|
80
126
|
return byteView.getBigInt64(0)
|
|
81
127
|
}
|
|
@@ -84,7 +130,7 @@ const byteView = new DataView(new Float64Array(1).buffer)
|
|
|
84
130
|
|
|
85
131
|
const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
|
|
86
132
|
export function f32(input, value, idx) {
|
|
87
|
-
if (~(idx = input.indexOf('nan:'))) {
|
|
133
|
+
if (typeof input === 'string' && ~(idx = input.indexOf('nan:'))) {
|
|
88
134
|
value = i32.parse(input.slice(idx + 4))
|
|
89
135
|
value |= F32_NAN
|
|
90
136
|
if (input[0] === '-') value |= F32_SIGN
|
|
@@ -105,7 +151,7 @@ export function f32(input, value, idx) {
|
|
|
105
151
|
|
|
106
152
|
const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n
|
|
107
153
|
export function f64(input, value, idx) {
|
|
108
|
-
if (~(idx = input.indexOf('nan:'))) {
|
|
154
|
+
if (typeof input === 'string' && ~(idx = input.indexOf('nan:'))) {
|
|
109
155
|
value = i64.parse(input.slice(idx + 4))
|
|
110
156
|
value |= F64_NAN
|
|
111
157
|
if (input[0] === '-') value |= F64_SIGN
|
|
@@ -141,12 +187,20 @@ f64.parse = (input, max=Number.MAX_VALUE) => {
|
|
|
141
187
|
let [int, fract=''] = sig.split('.'); // integer and fractional parts
|
|
142
188
|
let flen = fract.length ?? 0;
|
|
143
189
|
|
|
144
|
-
//
|
|
145
|
-
|
|
146
|
-
|
|
190
|
+
// Parse integer part
|
|
191
|
+
let intVal = parseInt(int); // 0x is included in int
|
|
192
|
+
isNaN(intVal) && err()
|
|
147
193
|
|
|
148
194
|
// 0x10a.fbc = 0x10afbc * 16⁻³ = 266.9833984375
|
|
149
|
-
|
|
195
|
+
// Parse fractional part: fract / 16^flen
|
|
196
|
+
// For better precision, parse as (int + fract) / 16^flen then multiply by 16^flen for int part
|
|
197
|
+
// Equivalent to: intVal + parseInt('0x' + fract) / 16^flen
|
|
198
|
+
let fractVal = fract ? parseInt('0x' + fract) / (16 ** flen) : 0;
|
|
199
|
+
|
|
200
|
+
exp = parseInt(exp, 10);
|
|
201
|
+
|
|
202
|
+
// Combine: (int + fract) * 2^exp
|
|
203
|
+
let value = sign * (intVal + fractVal) * (2 ** exp);
|
|
150
204
|
|
|
151
205
|
// make sure it is not Infinity
|
|
152
206
|
value = Math.max(-max, Math.min(max, value))
|
package/src/parse.js
CHANGED
|
@@ -1,51 +1,60 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
const OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, SPACE = 32, DQUOTE = 34, PERIOD = 46,
|
|
4
|
-
_0 = 48, _9 = 57, SEMIC = 59, NEWLINE = 32, PLUS = 43, MINUS = 45, COLON = 58, BACKSLASH = 92, AT = 64
|
|
5
|
-
|
|
1
|
+
import { err } from "./util.js"
|
|
6
2
|
|
|
7
3
|
/**
|
|
8
4
|
* Parses a wasm text string and constructs a nested array structure (AST).
|
|
5
|
+
* Each array node has `.i` property with source offset for error reporting.
|
|
9
6
|
*
|
|
10
7
|
* @param {string} str - The input string with WAT code to parse.
|
|
11
|
-
* @param {object} options - Parse options, like comments, etc.
|
|
12
8
|
* @returns {Array} An array representing the nested syntax tree (AST).
|
|
13
9
|
*/
|
|
14
|
-
export default (str
|
|
15
|
-
let i = 0, level = [], buf = '',
|
|
16
|
-
|
|
17
|
-
const commit = () => buf && (
|
|
18
|
-
level.push(buf),
|
|
19
|
-
buf = ''
|
|
20
|
-
)
|
|
10
|
+
export default (str) => {
|
|
11
|
+
let i = 0, level = [], buf = '', q = 0, depth = 0
|
|
21
12
|
|
|
22
|
-
const
|
|
23
|
-
for (let c, root, q, id; i < str.length;) {
|
|
13
|
+
const commit = () => buf && (level.push(buf), buf = '')
|
|
24
14
|
|
|
15
|
+
const parseLevel = (pos) => {
|
|
16
|
+
level.i = pos // store start position for error reporting
|
|
17
|
+
for (let c, root, p; i < str.length;) {
|
|
25
18
|
c = str.charCodeAt(i)
|
|
26
|
-
|
|
19
|
+
|
|
20
|
+
// inside "..." or $"..."
|
|
21
|
+
if (q === 34) (buf += str[i++], c === 92 ? buf += str[i++] : c === 34 && (commit(), q = 0))
|
|
22
|
+
// inside (; ... ;) with nesting support (q=60 means depth 1, q=61 means depth 2, etc)
|
|
23
|
+
else if (q > 59) (
|
|
24
|
+
c === 40 && str.charCodeAt(i + 1) === 59 ? (q++, buf += str[i++] + str[i++]) : // nested (;
|
|
25
|
+
c === 59 && str.charCodeAt(i + 1) === 41 ? (buf += str[i++] + str[i++], --q === 59 && (commit(), q = 0)) : // ;)
|
|
27
26
|
buf += str[i++]
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
else if (c ===
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
else if (c
|
|
41
|
-
|
|
27
|
+
)
|
|
28
|
+
// inside ;; ...\n
|
|
29
|
+
else if (q < 0) (c === 10 || c === 13 ? (buf += str[i++], commit(), q = 0) : buf += str[i++])
|
|
30
|
+
// start "
|
|
31
|
+
else if (c === 34) (buf !== '$' && commit(), q = 34, buf += str[i++])
|
|
32
|
+
// start (;
|
|
33
|
+
else if (c === 40 && str.charCodeAt(i + 1) === 59) (commit(), q = 60, buf = str[i++] + str[i++])
|
|
34
|
+
// start ;;
|
|
35
|
+
else if (c === 59 && str.charCodeAt(i + 1) === 59) (commit(), q = -1, buf = str[i++] + str[i++])
|
|
36
|
+
// start (@
|
|
37
|
+
else if (c === 40 && str.charCodeAt(i + 1) === 64) (commit(), p = i, i += 2, buf = '@', depth++, (root = level).push(level = []), parseLevel(p), level = root)
|
|
38
|
+
// start (
|
|
39
|
+
else if (c === 40) (commit(), p = i++, depth++, (root = level).push(level = []), parseLevel(p), level = root)
|
|
40
|
+
// end )
|
|
41
|
+
else if (c === 41) return commit(), i++, depth--
|
|
42
|
+
// whitespace
|
|
43
|
+
else if (c <= 32) (commit(), i++)
|
|
44
|
+
// other
|
|
42
45
|
else buf += str[i++]
|
|
43
46
|
}
|
|
44
47
|
|
|
48
|
+
q < 0 && commit() // trailing line comment
|
|
45
49
|
commit()
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
parseLevel()
|
|
52
|
+
parseLevel(0)
|
|
53
|
+
|
|
54
|
+
if (q === 34) err(`Unclosed quote`, i)
|
|
55
|
+
if (q > 59) err(`Unclosed block comment`, i)
|
|
56
|
+
if (depth > 0) err(`Unclosed parenthesis`, i)
|
|
57
|
+
if (i < str.length) err(`Unexpected closing parenthesis`, i)
|
|
49
58
|
|
|
50
|
-
return level.length > 1 ? level : level[0]
|
|
59
|
+
return level.length > 1 ? level : level[0] || []
|
|
51
60
|
}
|
package/src/print.js
CHANGED
|
@@ -8,44 +8,105 @@ import parse from './parse.js';
|
|
|
8
8
|
* @param {Object} [options={}] - Optional settings for printing.
|
|
9
9
|
* @param {string} [options.indent=' '] - The string used for one level of indentation. Defaults to two spaces.
|
|
10
10
|
* @param {string} [options.newline='\n'] - The string used for line breaks. Defaults to a newline character.
|
|
11
|
+
* @param {boolean} [options.comments=false] - Whether to include comments in the output. Defaults to false.
|
|
11
12
|
* @returns {string} The formatted WAT string.
|
|
12
13
|
*/
|
|
13
14
|
export default function print(tree, options = {}) {
|
|
14
15
|
if (typeof tree === 'string') tree = parse(tree);
|
|
15
16
|
|
|
16
|
-
let { indent=' ', newline='\n' } = options;
|
|
17
|
+
let { indent=' ', newline='\n', comments=true } = options;
|
|
17
18
|
indent ||= '', newline ||= ''; // false -> str
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
// If tree[0] is a string but NOT starting with `;` (comment), it's a keyword like `module` - print as single node
|
|
21
|
+
// Otherwise it's multiple nodes (comments + module) - print each separately
|
|
22
|
+
if (typeof tree[0] === 'string' && tree[0][0] !== ';') return printNode(tree)
|
|
23
|
+
|
|
24
|
+
// Multiple top-level nodes - filter out comments if comments option is false
|
|
25
|
+
return tree
|
|
26
|
+
.filter(node => comments || !isComment(node))
|
|
27
|
+
.map(node => printNode(node))
|
|
28
|
+
.join(newline)
|
|
29
|
+
|
|
30
|
+
function isComment(node) {
|
|
31
|
+
return typeof node === 'string' && node[1] === ';'
|
|
32
|
+
}
|
|
20
33
|
|
|
21
34
|
function printNode(node, level = 0) {
|
|
22
35
|
if (!Array.isArray(node)) return node
|
|
23
36
|
|
|
24
37
|
let content = node[0]
|
|
38
|
+
if (!content) return ''
|
|
39
|
+
let afterLineComment = false // track if we just printed a line comment
|
|
40
|
+
|
|
41
|
+
// Special handling for try_table: keep catch clauses inline
|
|
42
|
+
if (content === 'try_table') {
|
|
43
|
+
let i = 1
|
|
44
|
+
// Add label if present
|
|
45
|
+
if (typeof node[i] === 'string' && node[i][0] === '$') content += ' ' + node[i++]
|
|
46
|
+
// Add blocktype if present
|
|
47
|
+
if (Array.isArray(node[i]) && (node[i][0] === 'result' || node[i][0] === 'type')) content += ' ' + printNode(node[i++], level)
|
|
48
|
+
// Add catch clauses inline
|
|
49
|
+
while (Array.isArray(node[i]) && /^catch/.test(node[i][0])) content += ' ' + printNode(node[i++], level).trim()
|
|
50
|
+
// Rest is body - print normally
|
|
51
|
+
for (; i < node.length; i++) content += Array.isArray(node[i]) ? newline + indent.repeat(level + 1) + printNode(node[i], level + 1) : ' ' + node[i]
|
|
52
|
+
return `(${content + newline + indent.repeat(level)})`
|
|
53
|
+
}
|
|
25
54
|
|
|
26
55
|
// flat node (no deep subnodes), eg. (i32.const 1), (module (export "") 1)
|
|
27
|
-
|
|
56
|
+
// not flat if contains line comments (they need their own line)
|
|
57
|
+
let flat = !!newline && node.length < 4 && !node.some(n => typeof n === 'string' && n[0] === ';' && n[1] === ';')
|
|
28
58
|
let curIndent = indent.repeat(level + 1)
|
|
29
59
|
|
|
30
60
|
for (let i = 1; i < node.length; i++) {
|
|
31
|
-
|
|
32
|
-
if (Array.isArray(node[i])) {
|
|
33
|
-
// check if it's still flat
|
|
34
|
-
if (flat) flat = node[i].every(subnode => !Array.isArray(subnode))
|
|
61
|
+
const sub = node[i].valueOf() // "\00abc\ff" strings are stored as arrays but have ._ with original value
|
|
35
62
|
|
|
36
|
-
|
|
37
|
-
|
|
63
|
+
// comments - skip if not enabled
|
|
64
|
+
if (typeof sub === 'string' && sub[1] === ';') {
|
|
65
|
+
if (!comments) continue
|
|
66
|
+
// line comments (;;) - MUST end with newline to avoid consuming following elements
|
|
67
|
+
if (sub[0] === ';') {
|
|
68
|
+
if (newline) {
|
|
69
|
+
// prettified: own line with indent, next element adds its own newline
|
|
70
|
+
content += newline + curIndent + sub.trimEnd()
|
|
71
|
+
afterLineComment = true
|
|
72
|
+
} else {
|
|
73
|
+
// minified: keep inline but must have newline after
|
|
74
|
+
const last = content[content.length - 1]
|
|
75
|
+
if (last && last !== ' ' && last !== '(') content += ' '
|
|
76
|
+
content += sub.trimEnd() + '\n'
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// block comments ((;...;)) can stay inline
|
|
80
|
+
else {
|
|
81
|
+
const last = content[content.length - 1]
|
|
82
|
+
if (last && last !== ' ' && last !== '(') content += ' '
|
|
83
|
+
content += sub.trimEnd()
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// (<keyword> ...)
|
|
87
|
+
else if (Array.isArray(sub)) {
|
|
88
|
+
if (flat) flat = sub.every(sub => !Array.isArray(sub))
|
|
89
|
+
content += newline + curIndent + printNode(sub, level + 1)
|
|
90
|
+
afterLineComment = false
|
|
38
91
|
}
|
|
39
92
|
// data chunks "\00..."
|
|
40
93
|
else if (node[0] === 'data') {
|
|
41
94
|
flat = false;
|
|
42
95
|
if (newline || content[content.length-1] !== ')') content += newline || ' '
|
|
43
|
-
content += curIndent +
|
|
96
|
+
content += curIndent + sub
|
|
97
|
+
afterLineComment = false
|
|
44
98
|
}
|
|
45
99
|
// inline nodes
|
|
46
100
|
else {
|
|
47
|
-
|
|
48
|
-
|
|
101
|
+
const last = content[content.length - 1]
|
|
102
|
+
// after line comment in prettified mode, need newline + indent
|
|
103
|
+
if (afterLineComment && newline) content += newline + curIndent
|
|
104
|
+
// after newline from line comment (minified), add indent
|
|
105
|
+
else if (last === '\n') content += ''
|
|
106
|
+
else if (last && last !== ')' && last !== ' ') content += ' '
|
|
107
|
+
else if (newline || last === ')') content += ' '
|
|
108
|
+
content += sub
|
|
109
|
+
afterLineComment = false
|
|
49
110
|
}
|
|
50
111
|
}
|
|
51
112
|
|