Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/framework/Verifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,5 +123,5 @@ export class Verifier {

/* eslint @typescript-eslint/no-explicit-any: off */
function deepEqual(a: any, b: any): boolean {
return a === b || (isNaN(Number(a)) && isNaN(Number(b)));
return a === b || (isNaN(Number(a)) && isNaN(Number(b))) || a.equals(b);
}
3 changes: 2 additions & 1 deletion src/framework/scenario/Invoker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Type = WASM.Type;
import nothing = WASM.nothing;
import Special = WASM.Special;
import Float = WASM.Float;
import WasmInt = WASM.WasmInt;

export class Invoker implements Step {
readonly title: string;
Expand Down Expand Up @@ -34,6 +35,6 @@ export function returns<T extends Type>(n: Value<T>): Expectation[] {
if (n.type == Special.nothing) {
return [{'value': {kind: 'primitive', value: undefined} as Expected<undefined>}]
}
type R = T extends Float ? number : bigint;
type R = T extends Float ? number : WasmInt;
return [{'value': {kind: 'primitive', value: n.value} as Expected<R>}]
}
9 changes: 5 additions & 4 deletions src/messaging/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface Request<R> {
export namespace Message {
import Inspect = WARDuino.Inspect;
import Float = WASM.Float;
import isFloat = WASM.isFloat;
export const run: Request<Ack> = {
type: Interrupt.run,
parser: (line: string) => {
Expand Down Expand Up @@ -176,12 +177,12 @@ export namespace Message {
function convert(args: Value<Type>[]) {
let payload: string = '';
args.forEach((arg: Value<Type>) => {
if (arg.type === Float.f32 || arg.type === Float.f64 || arg.type === Special.nan || arg.type === Special.infinity) {
const buff = Buffer.alloc(4);
write(buff, Number(arg.value), 0, true, 23, buff.length); // todo fix precision loss
if (isFloat(arg.type)) {
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);
payload += WASM.leb128(<number>arg.value);
}
});
return payload;
Expand Down
36 changes: 17 additions & 19 deletions src/messaging/Parsers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {WASM} from '../sourcemap/Wasm';
import * as ieee754 from 'ieee754';
import {Ack, Exception} from './Message';
import {Breakpoint} from '../debug/Breakpoint';
import {WARDuino} from '../debug/WARDuino';
import {JSONParse} from 'json-with-bigint';
import State = WARDuino.State;
import nothing = WASM.nothing;
import Type = WASM.Type;
import WasmInt = WASM.WasmInt;
import ieee754 from "ieee754";

export function identityParser(text: string) {
return stripEnd(text);
}
Expand All @@ -19,7 +21,7 @@
if (exception(text)) {
return {text: text};
}
const stack: {value: any, type: any}[] = stateParser(text).stack!;
const stack: { value: any, type: any }[] = stateParser(text).stack!;

Check failure

Code scanning / ESLint

Disallow the `any` type Error

Unexpected any. Specify a different type.

Check failure

Code scanning / ESLint

Disallow the `any` type Error

Unexpected any. Specify a different type.
if (stack.length == 0) {
return nothing;
}
Expand Down Expand Up @@ -67,42 +69,38 @@

}

function extractType(object: {value: bigint | number, type: any}): Type {
if (typeof object.value === 'number') {
if (Number.isNaN(object.value)) return WASM.Special.nan;
if (object.value === Infinity) return WASM.Special.infinity;
}
function extractType(object: { value: string, type: any }): Type {

Check failure

Code scanning / ESLint

Disallow the `any` type Error

Unexpected any. Specify a different type.
return WASM.typing.get(object.type.toLowerCase()) ?? WASM.Special.unknown;
}

function stacking(objects: {value: bigint | number, type: any}[]): WASM.Value<Type>[] {
function stacking(objects: { value: string, type: any }[]): WASM.Value<Type>[] {

Check failure

Code scanning / ESLint

Disallow the `any` type Error

Unexpected any. Specify a different type.
const stacked: WASM.Value<Type>[] = [];
for (const object of objects) {
const type: WASM.Type = extractType(object);
let buff;
switch (type) {
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});
stacked.push({
value: isNaN(Number(object.value)) ? WasmInt.nan()
: object.value === 'inf' ? WasmInt.infinity()
: object.value === '-inf' ? WasmInt.infinity(false)
: WasmInt.finite(BigInt(object.value)),
type: type
});
break;
case WASM.Integer.i32:
stacked.push({value: signed(BigInt(object.value), 32), type: type});
stacked.push({value: WasmInt.finite(signed(BigInt(object.value), 32)), type: type});
break;
case WASM.Integer.i64:
stacked.push({value: signed(BigInt(object.value), 64), type: type});
stacked.push({value: WasmInt.finite(signed(BigInt(object.value), 64)), type: type});
break;
case WASM.Float.f32:
buff = Buffer.from(Number(object.value.toString(16)).toString(16), 'hex');
buff = Buffer.from(Number(object.value).toString(16), 'hex');
stacked.push({value: ieee754.read(buff, 0, false, 23, buff.length), type: type});
break;
case WASM.Float.f64:
buff = Buffer.from(BigInt(object.value.toString(16)).toString(16), 'hex');
buff = Buffer.from(BigInt(object.value).toString(16), 'hex');
stacked.push({value: ieee754.read(buff, 0, false, 52, buff.length), type: type});
break;
case WASM.Special.unknown:
Expand Down
103 changes: 84 additions & 19 deletions src/sourcemap/Wasm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ export namespace WASM {

export enum Special {
nothing = 'nothing',
nan = 'nan',
infinity = 'infinity',
unknown = 'unknown'
}

Expand All @@ -29,17 +27,78 @@ export namespace WASM {
['i64', Integer.i64]
]);

export class WasmInt {
private constructor(
private readonly kind: 'finite' | 'inf' | 'nan',
private readonly finiteValue?: bigint,
private readonly positive: boolean = true
) {
}

static finite(value: bigint): WasmInt {
return new WasmInt('finite', value, value >= 0);
}

static infinity(positive: boolean = true): WasmInt {
return new WasmInt('inf', undefined, positive);
}

static nan(positive: boolean = true): WasmInt {
return new WasmInt('nan', undefined, positive);
}

isFinite(): boolean {
return this.kind === 'finite';
}

isInfinity(): boolean {
return this.kind === 'inf';
}

isNaN(): boolean {
return this.kind === 'nan';
}

toBigInt(): bigint {
if (this.finiteValue !== undefined) {
return this.finiteValue;
}
throw new Error(`Cannot convert ${this.toString()} to bigint.`);
}

toNumber(): number {
switch (this.kind) {
case 'finite':
return Number(this.finiteValue!);
case 'inf':
return this.positive ? Infinity : -Infinity;
case 'nan':
return this.positive ? NaN : -NaN;
}
}

equals(other: WasmInt): boolean {
return this.kind === 'finite'
? this.finiteValue === other.finiteValue
: this.kind === other.kind && this.positive === other.positive;
}

toString(): string {
if (this.kind === 'finite') {
return this.finiteValue!.toString();
}
return `${this.positive ? '' : '-'}${this.kind}`;
}
}


export interface Value<T extends Type> {
type: T;
value: T extends Integer ? bigint : number;
value: T extends Integer ? WasmInt : number;
}

export function equals<T extends Type>(a: Value<T>, b: Value<T>): 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:
Expand All @@ -56,38 +115,44 @@ export namespace WASM {
type: Special.nothing, value: 0
}

export const nan: WASM.Value<Special> = {value: NaN, type: Special.nan};
export function isInteger(type: Type): type is Integer {
return type === Integer.u32 || type === Integer.i32 || type === Integer.u64 || type === Integer.i64;
}

export const negnan: WASM.Value<Special> = {value: -NaN, type: Special.nan};
export function isFloat(type: Type): type is Float {
return type === Float.f32 || type === Float.f64;
}

export const infinity: WASM.Value<Special> = {value: Infinity, type: Special.infinity};
export function nan(type: WASM.Type, positive: boolean = true): WASM.Value<Type> {
return {value: isInteger(type) ? WasmInt.nan(positive): (positive ? NaN : -NaN), type};
}

export const neginfinity: WASM.Value<Special> = {value: -Infinity, type: Special.infinity};
export function inf(type: WASM.Type, positive: boolean = true): WASM.Value<Type> {
return {value: isInteger(type) ? WasmInt.infinity(positive): (positive ? Infinity : -Infinity), type};
}

export function u32(n: bigint): WASM.Value<Integer> {
return {value: n, type: Integer.u32};
return {value: WasmInt.finite(n), type: Integer.u32};
}

export function i32(n: bigint): WASM.Value<Integer> {
return {value: n, type: Integer.i32};
return {value: WasmInt.finite(n), type: Integer.i32};
}

const determineType: (n: number) => WASM.Type = (n: number) => n === Infinity || n === -Infinity ? Special.infinity : (isNaN(n) ? Special.nan : Float.f64);

export function f32(n: number): WASM.Value<Type> {
return {value: n, type: determineType(n)};
return {value: n, type: Float.f32};
}

export function f64(n: number): WASM.Value<Type> {
return {value: n, type: determineType(n)};
return {value: n, type: Float.f64};
}

export function u64(n: bigint): WASM.Value<Integer> {
return {value: n, type: Integer.u64};
return {value: WasmInt.finite(n), type: Integer.u64};
}

export function i64(n: bigint): WASM.Value<Integer> {
return {value: n, type: Integer.i64};
return {value: WasmInt.finite(n), type: Integer.i64};
}

export interface Frame {
Expand Down
Loading