Play

Check-in [13f590fa78]
Login
Overview
Comment:Modularize wasm test suite.
Timelines: family | ancestors | descendants | both | stack-manipulation
Files: files | file ages | folders
SHA3-256: 13f590fa7862e2e0f2124b6a32287c22456d214971925d3c94558b358aa386b7
User & Date: robin.hansen on 2020-04-10 11:06:54
Other Links: branch diff | manifest | tags
Context
2020-04-10
12:20
Solve remaining issues with type checker for generic function types. Closed-Leaf check-in: 369c9800a9 user: robin.hansen tags: stack-manipulation
11:06
Modularize wasm test suite. check-in: 13f590fa78 user: robin.hansen tags: stack-manipulation
2020-04-09
11:50
Codegen now works with additional builtins. One unit test reveals weakness in type checker. check-in: 5755611773 user: robin.hansen tags: stack-manipulation
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Added wasm_tests/basics.test.js version [981cd381d2].

























































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const compiler = require('./compiler.wrapper');

test('Simple expression', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 1 1 +
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(2);
});

test('Function calls', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 1 inc inc

        def: inc
        : 1 +
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(3);
});

Added wasm_tests/compiler.wrapper.js version [c5416ae3ae].















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
const Compiler = require('./compiler.js');
const wabt = require('wabt')();

exports.toWat = function toWat(sourceCode) {
    return new Promise((resolve, reject) => {
        const compiler = Compiler.Elm.Main.init({});

        compiler.ports.compileFinished.subscribe(([ok, output]) => {
            if (ok) {
                resolve(output);
            } else {
                reject(output);
            }
        });

        compiler.ports.compileString.send(sourceCode);
    });
}

exports.run = async function run(wat, functionName) {
    const wasmModule = wabt.parseWat('tmp', wat).toBinary({}).buffer;

    const memory = new WebAssembly.Memory({
        initial: 1
    });

    const imports = {
        host: {
            memory: memory
        }
    };

    const program = await WebAssembly.instantiate(wasmModule, imports);
    program.instance.exports[functionName]();

    return new ExecutionResult(memory.buffer);
}

class ExecutionResult {
    constructor(memoryBuffer) {
        this.memoryView = new Uint32Array(memoryBuffer, 0, 512);
    }

    stackElement(index) {
        // The first three I32 positions are used for stack and heap information
        // The fourth position is the first element of the stack
        return this.memoryView[3 + (index || 0)];
    }

    typeIdForPointer(index) {
        const pointer = this.stackElement(index || 0);
        const wordPointer = pointer / 4;
        return this.memoryView[wordPointer];
    }
}

Added wasm_tests/math.test.js version [427aff9e64].



































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
const compiler = require('./compiler.wrapper');

test('Addition', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 3 3 +
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(6);
});

test('Subtraction', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 10 1 -
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(9);
});

test('Multiplication', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 5 3 *
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(15);
});

test('Division', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 10 5 /
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(2);
});

Added wasm_tests/record.test.js version [df052b5a01].







































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const compiler = require('./compiler.wrapper');

test('Enum type', async () => {
    const wat = await compiler.toWat(`
       deftype: True 
       deftype: False

       def: main
       entry: true
       : >True
    `);

    const result = await compiler.run(wat, 'main');

    // types are sorted alphabetically, so False will get id 0, and True gets id 1.
    expect(result.typeIdForPointer()).toBe(1);
});

test('Compound type', async () => {
    const wat = await compiler.toWat(`
        deftype: Person
        : { age: Int }

        def: inc-age
        : age> 1 + >Person

        def: main
        entry: true
        : 1 >Person 19 >age inc-age age>
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(20);
});

Added wasm_tests/stack.test.js version [e6217c5cce].







































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
const compiler = require('./compiler.wrapper');

test('Square', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        type: -- Int
        : 5 square

        def: square
        type: Int -- Int
        : dup *
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(25);
});

test('Over', async() => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        type: -- Int
        : 1 2 over - + 2 =

        def: over
        type: a b -- a b a
        : swap dup rotate
    `);

    const result = await compiler.run(wat, 'main');

    expect(result.stackElement()).toBe(1);
});

Deleted wasm_tests/wasm.test.js version [1a45c6e616].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
const Compiler = require('./compiler.js');
const wabt = require('wabt')();

test('Simple expression', async () => {
    const wat = await compileToWat(`
        def: main
        entry: true
        : 1 1 +
    `);

    const result = await runCode(wat, 'main');

    expect(result.valueOnBottomOfStack()).toBe(2);
});

test('Function calls', async () => {
    const wat = await compileToWat(`
        def: main
        entry: true
        : 1 inc inc

        def: inc
        : 1 +
    `);

    const result = await runCode(wat, 'main');

    expect(result.valueOnBottomOfStack()).toBe(3);
});

test('Enum type', async () => {
    const wat = await compileToWat(`
       deftype: True 
       deftype: False

       def: main
       entry: true
       : >True
    `);

    const result = await runCode(wat, 'main');

    // types are sorted alphabetically, so False will get id 0, and True gets id 1.
    expect(result.typeIdForPointer()).toBe(1);
});

test('Compound type', async () => {
    const wat = await compileToWat(`
        deftype: Person
        : { age: Int }

        def: inc-age
        : age> 1 + >Person

        def: main
        entry: true
        : 1 >Person 19 >age inc-age age>
    `);

    const result = await runCode(wat, 'main');

    expect(result.valueOnBottomOfStack()).toBe(20);
});

test('Square', async () => {
    const wat = await compileToWat(`
        def: main
        entry: true
        type: -- Int
        : 5 square

        def: square
        type: Int -- Int
        : dup *
    `);

    const result = await runCode(wat, 'main');

    expect(result.valueOnBottomOfStack()).toBe(25);
});

test('Over', async() => {
    const wat = await compileToWat(`
        def: main
        entry: true
        type: -- Int
        : 1 2 over - + 2 =

        def: over
        type: a b -- a b a
        : swap dup rotate
    `);

    const result = await runCode(wat, 'main');

    expect(result.valueOnBottomOfStack()).toBe(1);
});

// Helpers

function compileToWat(sourceCode) {
    return new Promise((resolve, reject) => {
        const compiler = Compiler.Elm.Main.init({});

        compiler.ports.compileFinished.subscribe(([ok, output]) => {
            if (ok) {
                resolve(output);
            } else {
                reject(output);
            }
        });

        compiler.ports.compileString.send(sourceCode);
    });
}

async function runCode(wat, functionName) {
    const wasmModule = wabt.parseWat('tmp', wat).toBinary({}).buffer;

    const memory = new WebAssembly.Memory({
        initial: 1
    });

    const imports = {
        host: {
            memory: memory
        }
    };

    const program = await WebAssembly.instantiate(wasmModule, imports);
    program.instance.exports[functionName]();

    return new ExecutionResult(memory.buffer);
}

class ExecutionResult {
    constructor(memoryBuffer) {
        this.memoryView = new Uint32Array(memoryBuffer, 0, 512);
    }

    valueOnBottomOfStack() {
        // The first three I32 positions are used for stack and heap information
        // The fourth position is the first element of the stack
        return this.memoryView[3];
    }

    typeIdForPointer() {
        const pointer = this.valueOnBottomOfStack();
        const wordPointer = pointer / 4;
        return this.memoryView[wordPointer];
    }
}
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<