UNPKG

watr

Version:

Ligth & fast WAT compiler

164 lines (136 loc) 4.17 kB
import { err, intRE, sepRE } from './util.js' // encoding ref: https://github.com/j-s-n/WebBS/blob/master/compiler/byteCode.js // uleb export const uleb = (n, buffer = []) => { if (n == null) return buffer if (typeof n === 'string') n = i32.parse(n) let byte = n & 0b01111111; n = n >>> 7; if (n === 0) { buffer.push(byte); return buffer; } else { buffer.push(byte | 0b10000000); return uleb(n, buffer); } } // fixed-width uleb // export function full_uleb(value) { // const result = []; // for (let i = 0; i < 5; i++) { // let byte = value & 0x7f; // value >>>= 7; // if (i < 4) { // byte |= 0x80; // Set continuation bit for first 4 bytes // } // result.push(byte); // } // return result; // } // leb export function i32(n, buffer = []) { if (typeof n === 'string') n = i32.parse(n) while (true) { const byte = Number(n & 0x7F) n >>= 7 if ((n === 0 && (byte & 0x40) === 0) || (n === -1 && (byte & 0x40) !== 0)) { buffer.push(byte) break } buffer.push((byte | 0x80)) } return buffer } // for tests complacency we check format const cleanInt = (v) => (!sepRE.test(v) && intRE.test(v=v.replaceAll('_',''))) ? v : err(`Bad int ${v}`) // alias export const i8 = i32, i16 = i32 i32.parse = n => parseInt(cleanInt(n)) // bigleb export function i64(n, buffer = []) { if (typeof n === 'string') n = i64.parse(n) while (true) { const byte = Number(n & 0x7Fn) n >>= 7n if ((n === 0n && (byte & 0x40) === 0) || (n === -1n && (byte & 0x40) !== 0)) { buffer.push(byte) break } buffer.push((byte | 0x80)) } return buffer } i64.parse = n => { n = cleanInt(n) n = n[0] === '-' ? -BigInt(n.slice(1)) : BigInt(n) // can be -0x123 byteView.setBigInt64(0, n) return byteView.getBigInt64(0) } const byteView = new DataView(new Float64Array(1).buffer) const F32_SIGN = 0x80000000, F32_NAN = 0x7f800000 export function f32(input, value, idx) { if (~(idx = input.indexOf('nan:'))) { value = i32.parse(input.slice(idx + 4)) value |= F32_NAN if (input[0] === '-') value |= F32_SIGN byteView.setInt32(0, value) } else { value = typeof input === 'string' ? f32.parse(input) : input byteView.setFloat32(0, value); } return [ byteView.getUint8(3), byteView.getUint8(2), byteView.getUint8(1), byteView.getUint8(0) ]; } const F64_SIGN = 0x8000000000000000n, F64_NAN = 0x7ff0000000000000n export function f64(input, value, idx) { if (~(idx = input.indexOf('nan:'))) { value = i64.parse(input.slice(idx + 4)) value |= F64_NAN if (input[0] === '-') value |= F64_SIGN byteView.setBigInt64(0, value) } else { value = typeof input === 'string' ? f64.parse(input) : input byteView.setFloat64(0, value); } return ([ byteView.getUint8(7), byteView.getUint8(6), byteView.getUint8(5), byteView.getUint8(4), byteView.getUint8(3), byteView.getUint8(2), byteView.getUint8(1), byteView.getUint8(0) ]); } f64.parse = (input, max=Number.MAX_VALUE) => { input = input.replaceAll('_', '') let sign = 1; if (input[0] === '-') sign = -1, input = input.slice(1); else if (input[0] === '+') input = input.slice(1); // ref: https://github.com/WebAssembly/wabt/blob/ea193b40d6d4a1a697d68ae855b2b3b3e263b377/src/literal.cc#L253 // 0x1.5p3 if (input[1] === 'x') { let [sig, exp='0'] = input.split(/p/i); // significand and exponent let [int, fract=''] = sig.split('.'); // integer and fractional parts let flen = fract.length ?? 0; // FIXME: this is not accurate, it must be byte-perfect sig = parseInt(int + fract); // 0x is included in int exp = parseInt(exp, 10); // 0x10a.fbc = 0x10afbc * 16⁻³ = 266.9833984375 let value = sign * sig * (2 ** (exp - 4 * flen)); // make sure it is not Infinity value = Math.max(-max, Math.min(max, value)) return value } if (input.includes('nan')) return sign < 0 ? -NaN : NaN; if (input.includes('inf')) return sign * Infinity; return sign * parseFloat(input) } f32.parse = input => f64.parse(input, 3.4028234663852886e+38)