watr 3.0.0 → 3.2.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/src/const.js CHANGED
@@ -1,16 +1,16 @@
1
1
  // https://webassembly.github.io/spec/core/appendix/index-instructions.html
2
2
  export const INSTR = [
3
- 'unreachable', 'nop', 'block:b', 'loop:b', 'if:b', 'else', 'then', , , , ,
4
- 'end', 'br:i', 'br_if:i', 'br_table:i*', 'return', 'call:i', 'call_indirect:i:i', , , , , , , , ,
5
- 'drop', 'select', 'select2:t', , , ,
6
- 'local.get:i', 'local.set:i', 'local.tee:i', 'global.get:i', 'global.set:i', 'table.get:i', 'table.set:i', ,
7
- 'i32.load:m', 'i64.load:m', 'f32.load:m', 'f64.load:m',
8
- 'i32.load8_s:m', 'i32.load8_u:m', 'i32.load16_s:m', 'i32.load16_u:m',
9
- 'i64.load8_s:m', 'i64.load8_u:m', 'i64.load16_s:m', 'i64.load16_u:m', 'i64.load32_s:m', 'i64.load32_u:m',
10
- 'i32.store:m', 'i64.store:m', 'f32.store:m', 'f64.store:m',
11
- 'i32.store8:m', 'i32.store16:m', 'i64.store8:m', 'i64.store16:m', 'i64.store32:m',
3
+ 'unreachable', 'nop', 'block', 'loop', 'if', 'else', 'then', , , , ,
4
+ 'end', 'br', 'br_if', 'br_table', 'return', 'call', 'call_indirect', 'return_call', 'return_call_indirect', 'call_ref', 'return_call_ref', , , , ,
5
+ 'drop', 'select', '', , , ,
6
+ 'local.get', 'local.set', 'local.tee', 'global.get', 'global.set', 'table.get', 'table.set', ,
7
+ 'i32.load', 'i64.load', 'f32.load', 'f64.load',
8
+ 'i32.load8_s', 'i32.load8_u', 'i32.load16_s', 'i32.load16_u',
9
+ 'i64.load8_s', 'i64.load8_u', 'i64.load16_s', 'i64.load16_u', 'i64.load32_s', 'i64.load32_u',
10
+ 'i32.store', 'i64.store', 'f32.store', 'f64.store',
11
+ 'i32.store8', 'i32.store16', 'i64.store8', 'i64.store16', 'i64.store32',
12
12
  'memory.size', 'memory.grow',
13
- 'i32.const:n', 'i64.const:n', 'f32.const:n', 'f64.const:n',
13
+ 'i32.const', 'i64.const', 'f32.const', 'f64.const',
14
14
  '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',
15
15
  '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',
16
16
  'f32.eq', 'f32.ne', 'f32.lt', 'f32.gt', 'f32.le', 'f32.ge',
@@ -26,36 +26,48 @@ export const INSTR = [
26
26
  'f64.convert_i32_s', 'f64.convert_i32_u', 'f64.convert_i64_s', 'f64.convert_i64_u', 'f64.promote_f32',
27
27
  'i32.reinterpret_f32', 'i64.reinterpret_f64', 'f32.reinterpret_i32', 'f64.reinterpret_i64',
28
28
  'i32.extend8_s', 'i32.extend16_s', 'i64.extend8_s', 'i64.extend16_s', 'i64.extend32_s', , , , , , , , , , , ,
29
- 'ref.null:t', 'ref.is_null', 'ref.func:i', , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
29
+ 'ref.null', 'ref.is_null', 'ref.func', 'ref.eq', 'ref.as_non_null', 'br_on_null', 'br_on_non_null', , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,
30
30
 
31
- // 0xFC 0xNN (0xfc shift)
32
- 'i32.trunc_sat_f32_u', 'i32.trunc_sat_f32_u', 'i32.trunc_sat_f64_s', 'i32.trunc_sat_f64_u', 'i64.trunc_sat_f32_s', 'i64.trunc_sat_f32_u', 'i64.trunc_sat_f64_s', 'i64.trunc_sat_f64_u',
33
- 'memory.init:i', 'data.drop:i', 'memory.copy', 'memory.fill', 'table.init:i:i', 'elem.drop:i', 'table.copy:i:i', 'table.grow:i', 'table.size:i', 'table.fill:i', ,
31
+ // 0xFB 0xNN (0xFB shift)
32
+ 'struct.new', 'struct.new_default', 'struct.get', 'struct.get_s', 'struct.get_u', 'struct.set', 'array.new', 'array.new_default', 'array.new_fixed', 'array.new_data', 'array.new_elem', 'array.get', 'array.get_s', 'array.get_u', 'array.set', 'array.len', 'array.fill', 'array.copy', 'array.init_data', 'array.init_elem', 'ref.test', '', 'ref.cast', '', 'br_on_cast', 'br_on_cast_fail', 'any.convert_extern', 'extern.convert_any', 'ref.i31', 'i31.get_s', 'i31.get_u', ,
34
33
 
35
- // 0xFD 0xNN (0x10f shift)
36
- 'v128.load:m', 'v128.load8x8_s:m', 'v128.load8x8_u:m', 'v128.load16x4_s:m', 'v128.load16x4_u:m', 'v128.load32x2_s:m', 'v128.load32x2_u:m', 'v128.load8_splat:m', 'v128.load16_splat:m', 'v128.load32_splat:m', 'v128.load64_splat:m', 'v128.store:m', 'v128.const:n', 'i8x16.shuffle:n:n:n:n:n:n:n:n:n:n:n:n:n:n:n:n',
34
+ // 0xFC 0xNN (0x11b shift)
35
+ 'i32.trunc_sat_f32_s', 'i32.trunc_sat_f32_u', 'i32.trunc_sat_f64_s', 'i32.trunc_sat_f64_u', 'i64.trunc_sat_f32_s', 'i64.trunc_sat_f32_u', 'i64.trunc_sat_f64_s', 'i64.trunc_sat_f64_u',
36
+ 'memory.init', 'data.drop', 'memory.copy', 'memory.fill', 'table.init', 'elem.drop', 'table.copy', 'table.grow', 'table.size', 'table.fill', ,
37
+ 'i64.add128', 'i64.sub128', 'i64.mul_wide_s', 'i64.mul_wide_u', ,
38
+
39
+ // 0xFD 0xNN (0x133 shift)
40
+ 'v128.load', 'v128.load8x8_s', 'v128.load8x8_u', 'v128.load16x4_s', 'v128.load16x4_u', 'v128.load32x2_s', 'v128.load32x2_u', 'v128.load8_splat', 'v128.load16_splat', 'v128.load32_splat', 'v128.load64_splat', 'v128.store', 'v128.const', 'i8x16.shuffle',
37
41
  'i8x16.swizzle', 'i8x16.splat', 'i16x8.splat', 'i32x4.splat', 'i64x2.splat', 'f32x4.splat', 'f64x2.splat',
38
- 'i8x16.extract_lane_s:n', 'i8x16.extract_lane_u:n', 'i8x16.replace_lane:n', 'i16x8.extract_lane_s:n', 'i16x8.extract_lane_u:n', 'i16x8.replace_lane:n', 'i32x4.extract_lane:n', 'i32x4.replace_lane:n', 'i64x2.extract_lane:n', 'i64x2.replace_lane:n', 'f32x4.extract_lane:n', 'f32x4.replace_lane:n', 'f64x2.extract_lane:n', 'f64x2.replace_lane:n',
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',
39
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',
40
- 'v128.load8_lane:m:l', 'v128.load16_lane:m:l', 'v128.load32_lane:m:l', 'v128.load64_lane:m:l', 'v128.store8_lane', 'v128.store16_lane', 'v128.store32_lane', 'v128.store64_lane', 'v128.load32_zero:m', 'v128.load64_zero:m', 'f32x4.demote_f64x2_zero', 'f64x2.promote_low_f32x4',
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',
41
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',
42
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',
43
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',
44
- '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'
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'
45
51
  ],
46
- SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, global: 6, export: 7, start: 8, elem: 9, code: 10, data: 11, datacount: 12 },
47
- TYPE = { i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, v128: 0x7B, func: 0x60, funcref: 0x70, externref: 0x6F, extern: 0x6f },
48
- KIND = { func: 0, table: 1, memory: 2, global: 3 },
49
- // FIXME: replace with formula
50
- ALIGN = {
51
- 'i32.load': 4, 'i64.load': 8, 'f32.load': 4, 'f64.load': 8,
52
- 'i32.load8_s': 1, 'i32.load8_u': 1, 'i32.load16_s': 2, 'i32.load16_u': 2,
53
- 'i64.load8_s': 1, 'i64.load8_u': 1, 'i64.load16_s': 2, 'i64.load16_u': 2, 'i64.load32_s': 4, 'i64.load32_u': 4, 'i32.store': 4,
54
- 'i64.store': 8, 'f32.store': 4, 'f64.store': 8,
55
- 'i32.store8': 1, 'i32.store16': 2, 'i64.store8': 1, 'i64.store16': 2, 'i64.store32': 4,
56
-
57
- 'v128.load': 16, 'v128.load8x8_s': 8, 'v128.load8x8_u': 8, 'v128.load16x4_s': 8, 'v128.load16x4_u': 8, 'v128.load32x2_s': 8, 'v128.load32x2_u': 8, 'v128.load8_splat': 1, 'v128.load16_splat': 2, 'v128.load32_splat': 4, 'v128.load64_splat': 8, 'v128.store': 16,
58
- 'v128.load': 16,
52
+ SECTION = { custom: 0, type: 1, import: 2, func: 3, table: 4, memory: 5, global: 6, 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, none: 0x71, func: 0x70, extern: 0x6F, any: 0x6E, eq: 0x6D, i31: 0x6C, struct: 0x6B, array: 0x6A },
56
+ REFTYPE = {
57
+ // absheaptype abbrs
58
+ nullfuncref: HEAPTYPE.nofunc,
59
+ nullexternref: HEAPTYPE.noextern,
60
+ nullref: HEAPTYPE.none,
61
+ funcref: HEAPTYPE.func,
62
+ externref: HEAPTYPE.extern,
63
+ anyref: HEAPTYPE.any,
64
+ eqref: HEAPTYPE.eq,
65
+ i31ref: HEAPTYPE.i31,
66
+ structref: HEAPTYPE.struct,
67
+ arrayref: HEAPTYPE.array,
59
68
 
60
- 'v128.load8_lane': 1, 'v128.load16_lane': 2, 'v128.load32_lane': 4, 'v128.load64_lane': 8, 'v128.store8_lane': 1, 'v128.store16_lane': 2, 'v128.store32_lane': 4, 'v128.store64_lane': 8, 'v128.load32_zero': 4, 'v128.load64_zero': 8
61
- }
69
+ // ref, refnull
70
+ ref: 0x64 /* -0x1c */, refnull: 0x63 /* -0x1d */
71
+ },
72
+ TYPE = { i8: 0x78, i16: 0x77, i32: 0x7f, i64: 0x7e, f32: 0x7d, f64: 0x7c, void: 0x40, v128: 0x7B, ...HEAPTYPE, ...REFTYPE },
73
+ KIND = { func: 0, table: 1, memory: 2, global: 3 }
package/src/encode.js CHANGED
@@ -1,3 +1,5 @@
1
+ import { err, intRE, sepRE } from './util.js'
2
+
1
3
  // encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js
2
4
 
3
5
  // uleb
@@ -17,6 +19,21 @@ export const uleb = (n, buffer = []) => {
17
19
  }
18
20
  }
19
21
 
22
+ // fixed-width uleb
23
+ // export function full_uleb(value) {
24
+ // const result = [];
25
+ // for (let i = 0; i < 5; i++) {
26
+ // let byte = value & 0x7f;
27
+ // value >>>= 7;
28
+ // if (i < 4) {
29
+ // byte |= 0x80; // Set continuation bit for first 4 bytes
30
+ // }
31
+ // result.push(byte);
32
+ // }
33
+ // return result;
34
+ // }
35
+
36
+
20
37
  // leb
21
38
  export function i32(n, buffer = []) {
22
39
  if (typeof n === 'string') n = i32.parse(n)
@@ -32,10 +49,14 @@ export function i32(n, buffer = []) {
32
49
  }
33
50
  return buffer
34
51
  }
52
+
53
+ // for tests complacency we check format
54
+ const cleanInt = (v) => (!sepRE.test(v) && intRE.test(v=v.replaceAll('_',''))) ? v : err(`Bad int ${v}`)
55
+
35
56
  // alias
36
57
  export const i8 = i32, i16 = i32
37
58
 
38
- i32.parse = n => parseInt(n.replaceAll('_', ''))
59
+ i32.parse = n => parseInt(cleanInt(n))
39
60
 
40
61
  // bigleb
41
62
  export function i64(n, buffer = []) {
@@ -53,13 +74,13 @@ export function i64(n, buffer = []) {
53
74
  return buffer
54
75
  }
55
76
  i64.parse = n => {
56
- n = n.replaceAll('_', '')
57
- n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n)
77
+ n = cleanInt(n)
78
+ n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n) // can be -0x123
58
79
  byteView.setBigInt64(0, n)
59
- return n = byteView.getBigInt64(0)
80
+ return byteView.getBigInt64(0)
60
81
  }
61
82
 
62
- const byteView = new DataView(new BigInt64Array(1).buffer)
83
+ const byteView = new DataView(new Float64Array(1).buffer)
63
84
 
64
85
  const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000
65
86
  export function f32(input, value, idx) {
@@ -95,7 +116,7 @@ export function f64(input, value, idx) {
95
116
  byteView.setFloat64(0, value);
96
117
  }
97
118
 
98
- return [
119
+ return ([
99
120
  byteView.getUint8(7),
100
121
  byteView.getUint8(6),
101
122
  byteView.getUint8(5),
@@ -104,21 +125,39 @@ export function f64(input, value, idx) {
104
125
  byteView.getUint8(2),
105
126
  byteView.getUint8(1),
106
127
  byteView.getUint8(0)
107
- ];
128
+ ]);
108
129
  }
109
130
 
110
- f32.parse = f64.parse = input => {
111
- if (input.includes('nan')) return input[0] === '-' ? -NaN : NaN;
112
- if (input.includes('inf')) return input[0] === '-' ? -Infinity : Infinity;
113
-
131
+ f64.parse = (input, max=Number.MAX_VALUE) => {
114
132
  input = input.replaceAll('_', '')
133
+ let sign = 1;
134
+ if (input[0] === '-') sign = -1, input = input.slice(1);
135
+ else if (input[0] === '+') input = input.slice(1);
115
136
 
137
+ // ref: https://github.com/WebAssembly/wabt/blob/ea193b40d6d4a1a697d68ae855b2b3b3e263b377/src/literal.cc#L253
116
138
  // 0x1.5p3
117
- if (input.includes('0x')) {
118
- let [sig, exp] = input.split(/p/i), [dec, fract] = sig.split('.'), sign = dec[0] === '-' ? -1 : 1
119
- sig = parseInt(dec) * sign + (fract ? parseInt(fract, 16) / (16 ** fract.length) : 0)
120
- return sign * (exp ? sig * 2 ** parseInt(exp, 10) : sig);
139
+ if (input[1] === 'x') {
140
+ let [sig, exp='0'] = input.split(/p/i); // significand and exponent
141
+ let [int, fract=''] = sig.split('.'); // integer and fractional parts
142
+ let flen = fract.length ?? 0;
143
+
144
+ // FIXME: this is not accurate, it must be byte-perfect
145
+ sig = parseInt(int + fract); // 0x is included in int
146
+ exp = parseInt(exp, 10);
147
+
148
+ // 0x10a.fbc = 0x10afbc * 16⁻³ = 266.9833984375
149
+ let value = sign * sig * (2 ** (exp - 4 * flen));
150
+
151
+ // make sure it is not Infinity
152
+ value = Math.max(-max, Math.min(max, value))
153
+
154
+ return value
121
155
  }
122
156
 
123
- return parseFloat(input)
157
+ if (input.includes('nan')) return sign < 0 ? -NaN : NaN;
158
+ if (input.includes('inf')) return sign * Infinity;
159
+
160
+ return sign * parseFloat(input)
124
161
  }
162
+
163
+ f32.parse = input => f64.parse(input, 3.4028234663852886e+38)
package/src/parse.js CHANGED
@@ -1,14 +1,15 @@
1
1
  const OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, SPACE = 32, DQUOTE = 34, PERIOD = 46,
2
- _0 = 48, _9 = 57, SEMIC = 59, NEWLINE = 32, PLUS = 43, MINUS = 45, COLON = 58
2
+ _0 = 48, _9 = 57, SEMIC = 59, NEWLINE = 32, PLUS = 43, MINUS = 45, COLON = 58, BSLASH = 39
3
3
 
4
4
  /**
5
5
  * Parses a wasm text string and constructs a nested array structure (AST).
6
6
  *
7
7
  * @param {string} str - The input string with WAT code to parse.
8
+ * @param {object} options - Parse options, like comments, etc.
8
9
  * @returns {Array} An array representing the nested syntax tree (AST).
9
10
  */
10
- export default (str) => {
11
- let i = 0, level = [], buf = ''
11
+ export default (str, o={ comments: false }) => {
12
+ let i = 0, level = [], buf = '', comment = ''
12
13
 
13
14
  const commit = () => buf && (
14
15
  level.push(buf),
@@ -16,15 +17,22 @@ export default (str) => {
16
17
  )
17
18
 
18
19
  const parseLevel = () => {
19
- for (let c, root; i < str.length;) {
20
+ for (let c, root, q; i < str.length;) {
20
21
 
21
22
  c = str.charCodeAt(i)
22
- if (c === DQUOTE) commit(), buf = str.slice(i++, i = str.indexOf('"', i) + 1), commit()
23
+ if (q) {
24
+ buf += str[i++]
25
+ if (str[i-1] === '\\') buf += str[i++]
26
+ else if (c === DQUOTE) commit(), q = 0
27
+ }
28
+ else if (c === DQUOTE) {
29
+ commit(), q = c, buf += str[i++]
30
+ }
23
31
  else if (c === OPAREN) {
24
- if (str.charCodeAt(i + 1) === SEMIC) i = str.indexOf(';)', i) + 2 // (; ... ;)
32
+ if (str.charCodeAt(i + 1) === SEMIC) comment = str.slice(i, i = str.indexOf(';)', i) + 2), o.comments && level.push(comment) // (; ... ;)
25
33
  else commit(), i++, (root = level).push(level = []), parseLevel(), level = root
26
34
  }
27
- else if (c === SEMIC) i = str.indexOf('\n', i) + 1 || str.length // ; ...
35
+ else if (c === SEMIC) comment = str.slice(i, i = str.indexOf('\n', i) + 1 || str.length), o.comments && level.push(comment) // ; ...
28
36
  else if (c <= SPACE) commit(), i++
29
37
  else if (c === CPAREN) return commit(), i++
30
38
  else buf += str[i++]
package/src/print.js CHANGED
@@ -1,69 +1,57 @@
1
1
  import parse from './parse.js';
2
2
 
3
- let indent = '', newline = '\n'
4
3
 
5
4
  /**
6
- * Formats a tree or a WAT string.
5
+ * Formats a tree or a WAT (WebAssembly Text) string into a readable format.
7
6
  *
8
- * @param {string | Array} tree - The code to print. If a string is provided, it will be parsed first.
9
- * @param {Object} [options] - Printing options.
10
- * @param {string} [options.indent=' '] - The string used for one level of indentation.
11
- * @param {string} [options.newline='\n'] - The string used for line breaks.
7
+ * @param {string | Array} tree - The code to print. If a string is provided, it will be parsed into a tree structure first.
8
+ * @param {Object} [options={}] - Optional settings for printing.
9
+ * @param {string} [options.indent=' '] - The string used for one level of indentation. Defaults to two spaces.
10
+ * @param {string} [options.newline='\n'] - The string used for line breaks. Defaults to a newline character.
12
11
  * @returns {string} The formatted WAT string.
13
12
  */
14
13
  export default function print(tree, options = {}) {
15
14
  if (typeof tree === 'string') tree = parse(tree);
16
15
 
17
- ({ indent=' ', newline='\n' } = options);
18
- indent ||= '', newline ||= '';
16
+ let { indent=' ', newline='\n' } = options;
17
+ indent ||= '', newline ||= ''; // false -> str
19
18
 
20
19
  return typeof tree[0] === 'string' ? printNode(tree) : tree.map(node => printNode(node)).join(newline)
21
- }
22
20
 
23
- const INLINE = [
24
- 'param',
25
- 'local',
26
- 'drop',
27
- 'f32.const',
28
- 'f64.const',
29
- 'i32.const',
30
- 'i64.const',
31
- 'local.get',
32
- 'global.get',
33
- 'memory.size',
34
- 'result',
35
- 'export',
36
- 'unreachable',
37
- 'nop'
38
- ]
21
+ function printNode(node, level = 0) {
22
+ if (!Array.isArray(node)) return node
39
23
 
40
- function printNode(node, level = 0) {
41
- if (!Array.isArray(node)) return node + ''
24
+ let content = node[0]
42
25
 
43
- let content = node[0]
26
+ // flat node (no deep subnodes), eg. (i32.const 1), (module (export "") 1)
27
+ let flat = !!newline && node.length < 4
28
+ let curIndent = indent.repeat(level + 1)
44
29
 
45
- for (let i = 1; i < node.length; i++) {
46
- // new node doesn't need space separator, eg. [x,[y]] -> `x(y)`
47
- if (Array.isArray(node[i])) {
48
- // inline nodes like (param x)(param y)
49
- // (func (export "xxx")..., but not (func (export "a")(param "b")...
30
+ for (let i = 1; i < node.length; i++) {
31
+ // (<keyword> ...)
32
+ if (Array.isArray(node[i])) {
33
+ // check if it's still flat
34
+ if (flat) flat = node[i].every(subnode => !Array.isArray(subnode))
50
35
 
51
- if (
52
- INLINE.includes(node[i][0]) &&
53
- (!Array.isArray(node[i - 1]) || INLINE.includes(node[i - 1][0]))
54
- ) {
55
- if (!Array.isArray(node[i - 1])) content += ` `
56
- } else {
57
- content += newline
58
- if (node[i]) content += indent.repeat(level + 1)
36
+ // new line
37
+ content += newline + curIndent + printNode(node[i], level + 1)
38
+ }
39
+ // data chunks "\00..."
40
+ else if (node[0] === 'data') {
41
+ flat = false;
42
+ if (newline || content[content.length-1] !== ')') content += newline || ' '
43
+ content += curIndent + node[i]
44
+ }
45
+ // inline nodes
46
+ else {
47
+ if (newline || content[content.length-1] !== ')') content += ' '
48
+ content += node[i]
59
49
  }
60
-
61
- content += printNode(node[i], level + 1)
62
- }
63
- else {
64
- content += ` `
65
- content += node[i]
66
50
  }
51
+
52
+ // shrink unnecessary spaces
53
+ if (flat) return `(${content.replaceAll(newline + curIndent + '(', ' (')})`
54
+
55
+ return `(${content + newline + indent.repeat(level)})`
67
56
  }
68
- return `(${content})`
69
57
  }
package/src/util.js ADDED
@@ -0,0 +1,8 @@
1
+
2
+ export const err = text => { throw Error(text) }
3
+
4
+ export const clone = items => items.map(item => Array.isArray(item) ? clone(item) : item)
5
+
6
+ export const sepRE = /^_|_$|[^\da-f]_|_[^\da-f]/i
7
+
8
+ export const intRE = /^[+-]?(?:0x[\da-f]+|\d+)$/i