Skip to content

Commit 04faff3

Browse files
authored
Add support for returns(nothing) (#19)
1 parent 1d38800 commit 04faff3

7 files changed

Lines changed: 50 additions & 21 deletions

File tree

src/framework/Reporter.ts

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,25 +23,26 @@ export function expect(step: Step, actual: Object | void, previous?: Object): Re
2323
result.completion = Completion.succeeded;
2424
for (const expectation of step.expected ?? []) {
2525
for (const [field, entry] of Object.entries(expectation)) {
26-
const value = getValue(actual, field);
27-
if (value === undefined) {
26+
try {
27+
const value = getValue(actual, field);
28+
29+
if (entry.kind === 'primitive') {
30+
result.expectPrimitive(value, entry.value);
31+
} else if (entry.kind === 'description') {
32+
result.expectDescription(value, entry.value);
33+
} else if (entry.kind === 'comparison') {
34+
result.expectComparison(actual, value, entry.value, entry.message);
35+
} else if (entry.kind === 'behaviour') {
36+
if (previous === undefined) {
37+
result.error('Invalid test: no [previous] to compare behaviour to.');
38+
return result;
39+
}
40+
result.expectBehaviour(value, getValue(previous, field), entry.value);
41+
}
42+
} catch (e) {
2843
result.error(`Failure: ${JSON.stringify(actual)} state does not contain '${field}'.`);
2944
return result;
3045
}
31-
32-
if (entry.kind === 'primitive') {
33-
result.expectPrimitive(value, entry.value);
34-
} else if (entry.kind === 'description') {
35-
result.expectDescription(value, entry.value);
36-
} else if (entry.kind === 'comparison') {
37-
result.expectComparison(actual, value, entry.value, entry.message);
38-
} else if (entry.kind === 'behaviour') {
39-
if (previous === undefined) {
40-
result.error('Invalid test: no [previous] to compare behaviour to.');
41-
return result;
42-
}
43-
result.expectBehaviour(value, getValue(previous, field), entry.value);
44-
}
4546
}
4647
}
4748
return result;

src/framework/Testee.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {OutofPlaceSpecification, PlatformType, TestbedSpecification} from '../te
1010
import {CompileOutput, CompilerFactory} from '../manage/Compiler';
1111
import {WABT} from '../util/env';
1212
import {Completion, expect, Result, ScenarioResult, SuiteResults} from './Reporter';
13+
import {WASM} from '../sourcemap/Wasm';
1314

1415
export function timeout<T>(label: string, time: number, promise: Promise<T>): Promise<T> {
1516
if (time === 0) {
@@ -23,6 +24,10 @@ export function timeout<T>(label: string, time: number, promise: Promise<T>): Pr
2324
* @param field dot string describing the field of the value (or path)
2425
*/
2526
export function getValue(object: any, field: string): any {
27+
if (object?.type == WASM.Type.nothing) {
28+
return undefined;
29+
}
30+
2631
// convert indexes to properties + remove leading dots
2732
field = field.replace(/\[(\w+)]/g, '.$1');
2833
field = field.replace(/^\.?/, '');
@@ -32,7 +37,7 @@ export function getValue(object: any, field: string): any {
3237
object = object[accessor];
3338
} else {
3439
// specified field does not exist
35-
return undefined;
40+
throw Error(`state does not contain field ${field}`);
3641
}
3742
}
3843
return object;

src/framework/scenario/Invoker.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,24 @@ import {WASM} from '../../sourcemap/Wasm';
33
import {Message} from '../../messaging/Message';
44
import {Target} from '../Testee';
55
import Value = WASM.Value;
6+
import Type = WASM.Type;
7+
import nothing = WASM.nothing;
68

79
export class Invoker implements Step {
810
readonly title: string;
911
readonly instruction: Instruction;
1012
readonly expected?: Expectation[];
1113
readonly target?: Target;
1214

13-
constructor(func: string, args: Value[], result: Value, target?: Target) {
14-
let prefix = "";
15+
constructor(func: string, args: Value[], result: Value | undefined, target?: Target) {
16+
let prefix = '';
1517
this.instruction = invoke(func, args);
16-
this.expected = returns(result);
18+
this.expected = (result == undefined) ? returns(nothing) : returns(result);
1719
if (target !== undefined) {
1820
this.target = target;
1921
prefix = `${target === Target.supervisor ? '[supervisor] ' : '[proxy] '}`
2022
}
21-
this.title = `${prefix}CHECK: (${func} ${args.map(val => val.value).join(' ')}) returns ${result.value}`;
23+
this.title = `${prefix}CHECK: (${func} ${args.map(val => val.value).join(' ')}) returns ${result?.value ?? 'nothing'}`;
2224
}
2325
}
2426

@@ -27,5 +29,8 @@ export function invoke(func: string, args: Value[]): Instruction {
2729
}
2830

2931
export function returns(n: Value): Expectation[] {
32+
if (n.type == Type.nothing) {
33+
return [{'value': {kind: 'primitive', value: undefined} as Expected<undefined>}]
34+
}
3035
return [{'value': {kind: 'primitive', value: n.value} as Expected<number>}]
3136
}

src/messaging/Parsers.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {Ack, Exception} from './Message';
44
import {Breakpoint} from '../debug/Breakpoint';
55
import {WARDuino} from '../debug/WARDuino';
66
import State = WARDuino.State;
7+
import nothing = WASM.nothing;
78

89
export function identityParser(text: string) {
910
return stripEnd(text);
@@ -18,6 +19,9 @@ export function invokeParser(text: string): WASM.Value | Exception {
1819
return {text: text};
1920
}
2021
const stack: {value: any, type: any}[] = stateParser(text).stack!;
22+
if (stack.length == 0) {
23+
return nothing;
24+
}
2125
return stacking(stack)[stack.length - 1];
2226
}
2327

src/sourcemap/Wasm.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export namespace WASM {
44
f64,
55
i32,
66
i64,
7+
nothing,
78
unknown
89
}
910

@@ -19,6 +20,12 @@ export namespace WASM {
1920
value: number;
2021
}
2122

23+
export interface Nothing extends Value {}
24+
25+
export const nothing: Nothing = {
26+
type: Type.nothing, value: 0
27+
}
28+
2229
export function i32(n: number): WASM.Value {
2330
return {value: n, type: Type.i32};
2431
}

test/address.wast

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
(memory 1)
44
(data (i32.const 0) "abcdefghijklmnopqrstuvwxyz")
55

6+
(func (export "func-unwind-by-br")
7+
(i32.const 3) (i64.const 1) (br 0)
8+
)
9+
610
(func (export "8u_good1") (param $i i32) (result i32)
711
(i32.load8_u offset=0 (local.get $i)) ;; 97 'a'
812
)

test/test.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ steps.push(new Invoker('8u_good1', [WASM.i32(0)], WASM.i32(97)));
2929
// ✔ ((invoke "8u_good3" (i32.const 0)) (i32.const 98))
3030
steps.push(new Invoker('8u_good3', [WASM.i32(0)], WASM.i32(98)));
3131

32+
// ✔ ((invoke "func-unwind-by-br"))
33+
steps.push(new Invoker('func-unwind-by-br', [], undefined));
34+
3235
spec.test({
3336
title: `Test with address_0.wast`,
3437
program: 'test/address.wast',

0 commit comments

Comments
 (0)