diff --git a/src/debug/WARDuino.ts b/src/debug/WARDuino.ts index 1984683..fd1f89f 100644 --- a/src/debug/WARDuino.ts +++ b/src/debug/WARDuino.ts @@ -5,6 +5,7 @@ export namespace WARDuino { import Frame = WASM.Frame; import Table = WASM.Table; import Memory = WASM.Memory; + import Type = WASM.Type; export interface CallbackMapping { callbackid: string; @@ -77,9 +78,9 @@ export namespace WARDuino { pc_error?: number; exception_msg?: string; breakpoints?: number[]; - stack?: Value[]; + stack?: Value[]; callstack?: Frame[]; - globals?: Value[]; + globals?: Value[]; table?: Table; memory?: Memory; br_table?: BRTable; diff --git a/src/framework/Testee.ts b/src/framework/Testee.ts index e439e5c..d7a2c5a 100644 --- a/src/framework/Testee.ts +++ b/src/framework/Testee.ts @@ -27,7 +27,7 @@ export function timeout(label: string, time: number, promise: Promise): Pr * @param field dot string describing the field of the value (or path) */ export function getValue(object: any, field: string): any { - if (object?.type == WASM.Type.nothing) { + if (object?.type === WASM.Special.nothing) { return undefined; } diff --git a/src/framework/scenario/Invoker.ts b/src/framework/scenario/Invoker.ts index 14964ba..d04f373 100644 --- a/src/framework/scenario/Invoker.ts +++ b/src/framework/scenario/Invoker.ts @@ -5,6 +5,8 @@ import {Target} from '../Testee'; import Value = WASM.Value; import Type = WASM.Type; import nothing = WASM.nothing; +import Special = WASM.Special; +import Float = WASM.Float; export class Invoker implements Step { readonly title: string; @@ -28,9 +30,10 @@ export function invoke(func: string, args: Value[]): Instruction { return {kind: Kind.Request, value: Message.invoke(func, args)}; } -export function returns(n: Value): Expectation[] { - if (n.type == Type.nothing) { +export function returns(n: Value): Expectation[] { + if (n.type == Special.nothing) { return [{'value': {kind: 'primitive', value: undefined} as Expected}] } - return [{'value': {kind: 'primitive', value: n.value} as Expected}] + type R = T extends Float ? number : bigint; + return [{'value': {kind: 'primitive', value: n.value} as Expected}] } diff --git a/src/messaging/Message.ts b/src/messaging/Message.ts index e156078..4e72f8a 100644 --- a/src/messaging/Message.ts +++ b/src/messaging/Message.ts @@ -28,6 +28,8 @@ export interface Request { export namespace Message { import Inspect = WARDuino.Inspect; + import Integer = WASM.Integer; + import Float = WASM.Float; export const run: Request = { type: Interrupt.run, parser: (line: string) => { @@ -162,7 +164,7 @@ export namespace Message { } } - export function invoke(func: string, args: Value[]): Request | Exception> { + export function invoke(func: string, args: Value[]): Request | Exception> { function fidx(map: SourceMap.Mapping, func: string): number { const fidx: number | void = map.functions.find((closure: SourceMap.Closure) => closure.name === func)?.index; if (fidx === undefined) { @@ -171,15 +173,15 @@ export namespace Message { return fidx!; } - function convert(args: Value[]) { + function convert(args: Value[]) { let payload: string = ''; - args.forEach((arg: Value) => { - if (arg.type === Type.i32 || arg.type === Type.i64) { - payload += WASM.leb128(arg.value); - } else { - const buff = Buffer.alloc(arg.type === Type.f32 ? 4 : 8); - write(buff, Number(arg.value), 0, true, arg.type === Type.f32 ? 23 : 52, buff.length); // todo fix precision loss + args.forEach((arg: Value) => { + if (arg.type === Float.f32 || arg.type === Float.f64) { + const buff = Buffer.alloc(arg.type === Float.f32 ? 4 : 8); + write(buff, Number(arg.value), 0, true, arg.type === Float.f32 ? 23 : 52, buff.length); // todo fix precision loss payload += buff.toString('hex'); + } else { + payload += WASM.leb128(arg.value); } }); return payload; diff --git a/src/messaging/Parsers.ts b/src/messaging/Parsers.ts index d9f6f35..4babeff 100644 --- a/src/messaging/Parsers.ts +++ b/src/messaging/Parsers.ts @@ -6,7 +6,7 @@ import {WARDuino} from '../debug/WARDuino'; import {JSONParse} from 'json-with-bigint'; import State = WARDuino.State; import nothing = WASM.nothing; - +import Type = WASM.Type; export function identityParser(text: string) { return stripEnd(text); } @@ -15,7 +15,7 @@ export function stateParser(text: string): State { return JSONParse(text); } -export function invokeParser(text: string): WASM.Value | Exception { +export function invokeParser(text: string): WASM.Value | Exception { if (exception(text)) { return {text: text}; } @@ -60,38 +60,50 @@ export function breakpointHitParser(text: string): Breakpoint { } export function signed(value: bigint, bits = 32) { - let x = BigInt(value); + let x = value; const sign = 1n << BigInt(bits - 1); const mod = 1n << BigInt(bits); return x >= sign ? x - mod : x; } -function stacking(objects: {value: bigint, type: any}[]): WASM.Value[] { - const stacked: WASM.Value[] = []; +function extractType(object: {value: bigint | number, type: any}): Type { + if (isNaN(object.value)) return WASM.Special.nan; + if (object.value === Infinity) return WASM.Special.infinity; + return WASM.typing.get(object.type.toLowerCase()) ?? WASM.Special.unknown; +} + +function stacking(objects: {value: bigint | number, type: any}[]): WASM.Value[] { + const stacked: WASM.Value[] = []; for (const object of objects) { - const type: WASM.Type = WASM.typing.get(object.type.toLowerCase()) ?? WASM.Type.unknown; + const type: WASM.Type = extractType(object); let buff; switch (type) { - case WASM.Type.u32: - case WASM.Type.u64: + case WASM.Special.nan: + stacked.push({value: NaN, type: type}); + break; + case WASM.Special.infinity: + stacked.push({value: Infinity, type: type}); + break; + case WASM.Integer.u32: + case WASM.Integer.u64: stacked.push({value: object.value, type: type}); break; - case WASM.Type.i32: - stacked.push({value: signed(object.value, 32), type: type}); + case WASM.Integer.i32: + stacked.push({value: signed(BigInt(object.value), 32), type: type}); break; - case WASM.Type.i64: - stacked.push({value: signed(object.value, 64), type: type}); + case WASM.Integer.i64: + stacked.push({value: signed(BigInt(object.value), 64), type: type}); break; - case WASM.Type.f32: + case WASM.Float.f32: buff = Buffer.from(Number(object.value.toString(16)).toString(16), 'hex'); stacked.push({value: ieee754.read(buff, 0, false, 23, buff.length), type: type}); break; - case WASM.Type.f64: + case WASM.Float.f64: buff = Buffer.from(BigInt(object.value.toString(16)).toString(16), 'hex'); stacked.push({value: ieee754.read(buff, 0, false, 52, buff.length), type: type}); break; - case WASM.Type.unknown: + case WASM.Special.unknown: break; } } diff --git a/src/sourcemap/Wasm.ts b/src/sourcemap/Wasm.ts index a2d31af..46a3a40 100644 --- a/src/sourcemap/Wasm.ts +++ b/src/sourcemap/Wasm.ts @@ -1,57 +1,82 @@ export namespace WASM { - export enum Type { - f32, - f64, - u32, - i32, - u64, - i64, - nothing, - unknown + export enum Float { + f32 = 'f32', + f64 = 'f64' } + export enum Integer { + u32 = 'u32', + i32 = 'i32', + u64 = 'u64', + i64 = 'i64' + } + + export enum Special { + nothing = 'nothing', + nan = 'nan', + infinity = 'infinity', + unknown = 'unknown' + } + + export type Type = Float | Integer | Special; + export const typing = new Map([ - ['f32', Type.f32], - ['f64', Type.f64], - ['u32', Type.u32], - ['i32', Type.i32], - ['u64', Type.u64], - ['i64', Type.i64] + ['f32', Float.f32], + ['f64', Float.f64], + ['u32', Integer.u32], + ['i32', Integer.i32], + ['u64', Integer.u64], + ['i64', Integer.i64] ]); - export interface Value { - type: Type; - value: T; + export interface Value { + type: T; + value: T extends Integer ? bigint : number; + } + + export function equals(a: Value, b: Value): boolean { + switch (a.type) { + case Special.nan: + return b.type === Special.nan; + case Special.infinity: + return b.type === Special.infinity; + case Special.nothing: + return b.type === Special.nothing; + case Special.unknown: + return b.type === Special.unknown; + default: + return a.type === b.type && a.value === b.value; + } } - export interface Nothing extends Value {} + export interface Nothing extends Value {} export const nothing: Nothing = { - type: Type.nothing, value: 0 + type: Special.nothing, value: 0 } - export function u32(n: bigint): WASM.Value { - return {value: n, type: Type.u32}; + export function u32(n: bigint): WASM.Value { + return {value: n, type: Integer.u32}; } - export function i32(n: bigint): WASM.Value { - return {value: n, type: Type.i32}; + export function i32(n: bigint): WASM.Value { + return {value: n, type: Integer.i32}; } - export function f32(n: number): WASM.Value { - return {value: n, type: Type.f32}; + export function f32(n: number): WASM.Value { + return {value: n, type: Float.f32}; } - export function f64(n: number): WASM.Value { - return {value: n, type: Type.f64}; + export function f64(n: number): WASM.Value { + return {value: n, type: Float.f64}; } - export function u64(n: bigint): WASM.Value { - return {value: n, type: Type.u64}; + export function u64(n: bigint): WASM.Value { + return {value: n, type: Integer.u64}; } - export function i64(n: bigint): WASM.Value { - return {value: n, type: Type.i64}; + export function i64(n: bigint): WASM.Value { + return {value: n, type: Integer.i64}; } export interface Frame {