|
@@ -8,6 +8,7 @@ import math
|
|
|
from tempfile import NamedTemporaryFile
|
|
|
from subprocess import call
|
|
|
import json
|
|
|
+import array
|
|
|
|
|
|
atom_end = set('()"' + whitespace)
|
|
|
|
|
@@ -61,8 +62,89 @@ def parse_typed_value(ast):
|
|
|
'i64.const': 'i64',
|
|
|
'f32.const': 'float',
|
|
|
'f64.const': 'double',
|
|
|
+ 'v128.const': 'bigint',
|
|
|
}
|
|
|
- if len(ast) == 2 and ast[0][0] in types:
|
|
|
+
|
|
|
+ v128_sizes = {
|
|
|
+ 'i8x16': 1,
|
|
|
+ 'i16x8': 2,
|
|
|
+ 'i32x4': 4,
|
|
|
+ 'i64x2': 8,
|
|
|
+ 'f32x4': 4,
|
|
|
+ 'f64x2': 8,
|
|
|
+ }
|
|
|
+ v128_format_names = {
|
|
|
+ 'i8x16': 'b',
|
|
|
+ 'i16x8': 'h',
|
|
|
+ 'i32x4': 'i',
|
|
|
+ 'i64x2': 'q',
|
|
|
+ 'f32x4': 'f',
|
|
|
+ 'f64x2': 'd',
|
|
|
+ }
|
|
|
+ v128_format_names_unsigned = {
|
|
|
+ 'i8x16': 'B',
|
|
|
+ 'i16x8': 'H',
|
|
|
+ 'i32x4': 'I',
|
|
|
+ 'i64x2': 'Q',
|
|
|
+ }
|
|
|
+
|
|
|
+ def parse_v128_chunk(num, type) -> array:
|
|
|
+ negative = 1
|
|
|
+ if num.startswith('-'):
|
|
|
+ negative = -1
|
|
|
+ num = num[1:]
|
|
|
+ elif num.startswith('+'):
|
|
|
+ num = num[1:]
|
|
|
+
|
|
|
+ # wtf spec test, split your wast tests already
|
|
|
+ while num.startswith('0') and not num.startswith('0x'):
|
|
|
+ num = num[1:]
|
|
|
+
|
|
|
+ if num == '':
|
|
|
+ num = '0'
|
|
|
+
|
|
|
+ if type.startswith('f'):
|
|
|
+ def generate():
|
|
|
+ if num == 'nan:canonical':
|
|
|
+ return float.fromhex('0x7fc00000')
|
|
|
+ if num == 'nan:arithmetic':
|
|
|
+ return float.fromhex('0x7ff00000')
|
|
|
+ if num == 'nan:signaling':
|
|
|
+ return float.fromhex('0x7ff80000')
|
|
|
+ if num.startswith('nan:'):
|
|
|
+ # FIXME: I have no idea if this is actually correct :P
|
|
|
+ rest = num[4:]
|
|
|
+ return float.fromhex('0x7ff80000') + int(rest, base=16)
|
|
|
+ if num.lower() == 'infinity':
|
|
|
+ return float.fromhex('0x7ff00000') * negative
|
|
|
+ try:
|
|
|
+ return float(num) * negative
|
|
|
+ except ValueError:
|
|
|
+ return float.fromhex(num) * negative
|
|
|
+
|
|
|
+ value = generate()
|
|
|
+ return struct.pack(f'={v128_format_names[type]}', value)
|
|
|
+ value = negative * int(num.replace('_', ''), base=0)
|
|
|
+ try:
|
|
|
+ return struct.pack(f'={v128_format_names[type]}', value)
|
|
|
+ except struct.error:
|
|
|
+ # The test format uses signed and unsigned values interchangeably, this is probably an unsigned value.
|
|
|
+ return struct.pack(f'={v128_format_names_unsigned[type]}', value)
|
|
|
+
|
|
|
+ if len(ast) >= 2 and ast[0][0] in types:
|
|
|
+ if ast[0][0] == 'v128.const':
|
|
|
+ value = array.array('b')
|
|
|
+ for i, num in enumerate(ast[2:]):
|
|
|
+ size = v128_sizes[ast[1][0]]
|
|
|
+ s = len(value)
|
|
|
+ value.frombytes(parse_v128_chunk(num[0], ast[1][0]))
|
|
|
+ assert len(value) - s == size, f'Expected {size} bytes, got {len(value) - s} bytes'
|
|
|
+
|
|
|
+ return {
|
|
|
+ 'type': types[ast[0][0]],
|
|
|
+ 'value': value.tobytes().hex()
|
|
|
+ }
|
|
|
+
|
|
|
return {"type": types[ast[0][0]], "value": ast[1][0]}
|
|
|
|
|
|
return {"type": "error"}
|
|
@@ -285,6 +367,9 @@ def genarg(spec):
|
|
|
|
|
|
def gen():
|
|
|
x = spec['value']
|
|
|
+ if spec['type'] == 'bigint':
|
|
|
+ return f"0x{x}n"
|
|
|
+
|
|
|
if spec['type'] in ('i32', 'i64'):
|
|
|
if x.startswith('0x'):
|
|
|
if spec['type'] == 'i32':
|