Play

Check-in [52304dc684]
Login
Overview
Comment:Removed entry: true syntax from function definition. Fixes [48cf587779].
Timelines: family | ancestors | descendants | both | module-definition
Files: files | file ages | folders
SHA3-256: 52304dc684b397917b419aa5156776c122d706e12760479e6240f7b26e52fedc
User & Date: robin.hansen on 2021-05-01 11:49:26
Other Links: branch diff | manifest | tags
Context
2021-05-03
13:50
Add function that goes through a parser AST and figures out which modules the AST depends on being p... check-in: 7d904176c1 user: robin.hansen tags: module-definition
2021-05-01
11:49
Removed entry: true syntax from function definition. Fixes [48cf587779]. check-in: 52304dc684 user: robin.hansen tags: module-definition
11:28
Parser recognizes that functions can define their own aliases and imports. check-in: 1c4627dc1c user: robin.hansen tags: module-definition
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Main.elm from [3aebcaa4ec] to [e620ef58fd].

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
..
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
..
91
92
93
94
95
96
97
98
99
100
101
port module Main exposing (main)

import Dict
import Platform exposing (Program)
import Play.Codegen as Codegen

import Play.Parser as Parser
import Play.Parser.Problem as ParserProblem
import Play.Qualifier as Qualifier
import Play.Qualifier.Problem as QualifierProblem
import Play.TypeChecker as TypeChecker
import Play.TypeChecker.Problem as TypeCheckerProblem
import Wasm
................................................................................


type alias Model =
    ()


type Msg
    = CompileString String


main : Program () Model Msg
main =
    Platform.worker
        { init = init
        , update = update
................................................................................
    , Cmd.none
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg _ =
    case msg of
        CompileString sourceCode ->
            case compile sourceCode of
                Ok wasm ->
                    ( ()
                    , compileFinished ( True, Wasm.toString wasm )
                    )

                Err errmsg ->
                    ( ()
                    , compileFinished ( False, "Compilation failed:\n\n" ++ errmsg )
                    )


compile : String -> Result String Wasm.Module
compile sourceCode =
    case Parser.run sourceCode of
        Err parserErrors ->
            formatErrors (ParserProblem.toString sourceCode) parserErrors

        Ok ast ->
            let
                qualifierResult =
                    Qualifier.run
                        { packageName = ""
                        , modulePath = ""
                        , ast = ast
                        , externalModules = Dict.empty
                        }




            in
            case qualifierResult of
                Err qualifierErrors ->
                    formatErrors (QualifierProblem.toString sourceCode) qualifierErrors

                Ok qualifiedAst ->
                    case TypeChecker.run qualifiedAst of
................................................................................


subscriptions : Model -> Sub Msg
subscriptions _ =
    compileString CompileString


port compileString : (String -> msg) -> Sub msg


port compileFinished : ( Bool, String ) -> Cmd msg





>







 







|







 







|
|











|
|













>
>
>
>







 







|



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
..
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
..
96
97
98
99
100
101
102
103
104
105
106
port module Main exposing (main)

import Dict
import Platform exposing (Program)
import Play.Codegen as Codegen
import Play.Data.Metadata as Metadata
import Play.Parser as Parser
import Play.Parser.Problem as ParserProblem
import Play.Qualifier as Qualifier
import Play.Qualifier.Problem as QualifierProblem
import Play.TypeChecker as TypeChecker
import Play.TypeChecker.Problem as TypeCheckerProblem
import Wasm
................................................................................


type alias Model =
    ()


type Msg
    = CompileString ( String, String )


main : Program () Model Msg
main =
    Platform.worker
        { init = init
        , update = update
................................................................................
    , Cmd.none
    )


update : Msg -> Model -> ( Model, Cmd Msg )
update msg _ =
    case msg of
        CompileString ( entry, sourceCode ) ->
            case compile entry sourceCode of
                Ok wasm ->
                    ( ()
                    , compileFinished ( True, Wasm.toString wasm )
                    )

                Err errmsg ->
                    ( ()
                    , compileFinished ( False, "Compilation failed:\n\n" ++ errmsg )
                    )


compile : String -> String -> Result String Wasm.Module
compile entry sourceCode =
    case Parser.run sourceCode of
        Err parserErrors ->
            formatErrors (ParserProblem.toString sourceCode) parserErrors

        Ok ast ->
            let
                qualifierResult =
                    Qualifier.run
                        { packageName = ""
                        , modulePath = ""
                        , ast = ast
                        , externalModules = Dict.empty
                        }
                        |> Result.map (\qast -> { qast | words = Dict.update entry (Maybe.map setEntryPoint) qast.words })

                setEntryPoint word =
                    { word | metadata = Metadata.asEntryPoint word.metadata }
            in
            case qualifierResult of
                Err qualifierErrors ->
                    formatErrors (QualifierProblem.toString sourceCode) qualifierErrors

                Ok qualifiedAst ->
                    case TypeChecker.run qualifiedAst of
................................................................................


subscriptions : Model -> Sub Msg
subscriptions _ =
    compileString CompileString


port compileString : (( String, String ) -> msg) -> Sub msg


port compileFinished : ( Bool, String ) -> Cmd msg

Modified src/Play/Parser.elm from [e45ec7b76a] to [53bc1d6feb].

661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
            def.metadata
    in
    Parser.oneOf
        [ Parser.succeed (\typeSign -> Parser.Loop { def | metadata = { metadata | type_ = TypeSignature.UserProvided typeSign } })
            |. Parser.keyword (Token "type:" NoProblem)
            |. noiseParser
            |= typeSignatureParser
        , Parser.succeed (Parser.Loop { def | metadata = { metadata | isEntryPoint = True } })
            |. Parser.keyword (Token "entry:" NoProblem)
            |. noiseParser
            |. Parser.keyword (Token "true" NoProblem)
            |. noiseParser
        , Parser.succeed (\alias value -> Parser.Loop { def | metadata = Metadata.withAlias alias value def.metadata })
            |. Parser.keyword (Token "alias:" NoProblem)
            |. noiseParser
            |= symbolParser
            |. noiseParser
            |= modulePathStringParser
            |. noiseParser







<
<
<
<
<







661
662
663
664
665
666
667





668
669
670
671
672
673
674
            def.metadata
    in
    Parser.oneOf
        [ Parser.succeed (\typeSign -> Parser.Loop { def | metadata = { metadata | type_ = TypeSignature.UserProvided typeSign } })
            |. Parser.keyword (Token "type:" NoProblem)
            |. noiseParser
            |= typeSignatureParser





        , Parser.succeed (\alias value -> Parser.Loop { def | metadata = Metadata.withAlias alias value def.metadata })
            |. Parser.keyword (Token "alias:" NoProblem)
            |. noiseParser
            |= symbolParser
            |. noiseParser
            |= modulePathStringParser
            |. noiseParser

Modified tests/Test/Parser.elm from [becf04c12a] to [957dee712d].

24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
...
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
...
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
                        : 1 +

                        def: dec
                        type: Int -- Int
                        : 1 -

                        def: main
                        entry: true
                        : 1 inc inc dec 2 =
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                            [ AST.Integer emptyRange 1
                                            , AST.Word emptyRange "-"
                                            ]
                                  }
                                , { name = "main"
                                  , metadata =
                                        Metadata.default
                                            |> Metadata.asEntryPoint
                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Word emptyRange "inc"
                                            , AST.Word emptyRange "inc"
                                            , AST.Word emptyRange "dec"
                                            , AST.Integer emptyRange 2
................................................................................
                    source =
                        """
                        def: apply-to-num
                        type: Int [ Int -- Int ] -- Int
                        : !

                        def: main
                        entry: true
                        : 1 [ 1 + ] apply-to-num
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                                [ Type.Int ]
                                  , implementation =
                                        SoloImpl
                                            [ AST.Word emptyRange "!"
                                            ]
                                  }
                                , { name = "main"
                                  , metadata =
                                        Metadata.default
                                            |> Metadata.asEntryPoint
                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Quotation
                                                emptyRange
                                                [ AST.Integer emptyRange 1
                                                , AST.Word emptyRange "+"
................................................................................
                    source =
                        """
                        def: apply-to-num
                        type: a... [ a... -- b... ] -- b...
                        : !

                        def: main
                        entry: true
                        : 1 [ 1 + ] apply-to-num
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                                [ Type.StackRange "b" ]
                                  , implementation =
                                        SoloImpl
                                            [ AST.Word emptyRange "!"
                                            ]
                                  }
                                , { name = "main"
                                  , metadata =
                                        Metadata.default
                                            |> Metadata.asEntryPoint
                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Quotation emptyRange
                                                [ AST.Integer emptyRange 1
                                                , AST.Word emptyRange "+"
                                                ]







<







 







<







 







<







 







<
|
<







 







<







 







<
|
<







24
25
26
27
28
29
30

31
32
33
34
35
36
37
..
53
54
55
56
57
58
59

60
61
62
63
64
65
66
...
499
500
501
502
503
504
505

506
507
508
509
510
511
512
...
521
522
523
524
525
526
527

528

529
530
531
532
533
534
535
...
552
553
554
555
556
557
558

559
560
561
562
563
564
565
...
577
578
579
580
581
582
583

584

585
586
587
588
589
590
591
                        : 1 +

                        def: dec
                        type: Int -- Int
                        : 1 -

                        def: main

                        : 1 inc inc dec 2 =
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                            [ AST.Integer emptyRange 1
                                            , AST.Word emptyRange "-"
                                            ]
                                  }
                                , { name = "main"
                                  , metadata =
                                        Metadata.default

                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Word emptyRange "inc"
                                            , AST.Word emptyRange "inc"
                                            , AST.Word emptyRange "dec"
                                            , AST.Integer emptyRange 2
................................................................................
                    source =
                        """
                        def: apply-to-num
                        type: Int [ Int -- Int ] -- Int
                        : !

                        def: main

                        : 1 [ 1 + ] apply-to-num
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                                [ Type.Int ]
                                  , implementation =
                                        SoloImpl
                                            [ AST.Word emptyRange "!"
                                            ]
                                  }
                                , { name = "main"

                                  , metadata = Metadata.default

                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Quotation
                                                emptyRange
                                                [ AST.Integer emptyRange 1
                                                , AST.Word emptyRange "+"
................................................................................
                    source =
                        """
                        def: apply-to-num
                        type: a... [ a... -- b... ] -- b...
                        : !

                        def: main

                        : 1 [ 1 + ] apply-to-num
                        """

                    expectedAst =
                        { moduleDefinition = AST.emptyModuleDefinition
                        , types = Dict.empty
                        , words =
................................................................................
                                                [ Type.StackRange "b" ]
                                  , implementation =
                                        SoloImpl
                                            [ AST.Word emptyRange "!"
                                            ]
                                  }
                                , { name = "main"

                                  , metadata = Metadata.default

                                  , implementation =
                                        SoloImpl
                                            [ AST.Integer emptyRange 1
                                            , AST.Quotation emptyRange
                                                [ AST.Integer emptyRange 1
                                                , AST.Word emptyRange "+"
                                                ]

Modified wasm_tests/basics.test.js from [981cd381d2] to [aa9864714d].

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);
});



|

<









|

<










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
const compiler = require('./compiler.wrapper');

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

        : 1 1 +
    `);

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

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

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

        : 1 inc inc

        def: inc
        : 1 +
    `);

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

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

Modified wasm_tests/compiler.wrapper.js from [527dbd0b5f] to [8661e0e665].

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const Compiler = require('./compiler.js');
const wabtInit = require('wabt');
const stripIndent = require('strip-indent');

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(stripIndent(sourceCode));
    });
}

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





|











|







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const Compiler = require('./compiler.js');
const wabtInit = require('wabt');
const stripIndent = require('strip-indent');

exports.toWat = function toWat(entry, 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([entry, stripIndent(sourceCode)]);
    });
}

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

Modified wasm_tests/math.test.js from [3440282ac4] to [b8ebd73e94].

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 div
    `);

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

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



|

<









|

<









|

<









|

<







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
const compiler = require('./compiler.wrapper');

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

        : 3 3 +
    `);

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

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

test('Subtraction', async () => {
    const wat = await compiler.toWat('main', `
        def: main

        : 10 1 -
    `);

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

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

test('Multiplication', async () => {
    const wat = await compiler.toWat('main', `
        def: main

        : 5 3 *
    `);

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

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

test('Division', async () => {
    const wat = await compiler.toWat('main', `
        def: main

        : 10 5 div
    `);

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

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

Modified wasm_tests/multiword.test.js from [aadc36f12d] to [2577567c39].

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
..
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
...
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
...
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
...
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
const compiler = require('./compiler.wrapper');

test('Simple case', async () => {
    const wat = await compiler.toWat(`
        defunion: Bool
        : True
        : False

        defstruct: True
        defstruct: False

................................................................................
        defmulti: to-int
        : True
          drop 100
        : False
          drop 75

        def: main
        entry: true
        : True to-int 
          False to-int 
          -
    `);

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

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

// Same as above, but without an explicit False branch.
test('Default branch', async () => {
    const wat = await compiler.toWat(`
        defunion: Bool
        : True 
        : False

        defstruct: True
        defstruct: False

        defmulti: to-int
        : True
          drop 100
        else: drop 75

        def: main
        entry: true
        : True to-int 
          False to-int 
          -
    `);

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

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

test('Multiple arguments', async () => {
    const wat = await compiler.toWat(`
        defunion: Beings
        : Person 
        : Dog

        defstruct: Person
        : age Int

................................................................................
        defmulti: get-man-age
        : Person
          age>
        : Dog
          man-years>

        def: main
        entry: true
        : 18 >Person 10 add-to-age 
          0 >Dog 2 add-to-age 
          get-man-age swap 
          get-man-age swap 
          -
    `);

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

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

test('Generic arguments', async () => {
    const wat = await compiler.toWat(`
        defunion: List a
        : NonEmptyList a 
        : EmptyList

        defstruct: NonEmptyList a
        : first a
        : rest List a
................................................................................
        defmulti: first-or-default
        : NonEmptyList
          drop first>
        : EmptyList
          swap drop

        def: main
        entry: true
        : 1 EmptyList >NonEmptyList
          0 first-or-default
    `);

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

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

test('Recursive word', async () => {
    const wat = await compiler.toWat(`
        defunion: List a
        : NonEmptyList a 
        : EmptyList

        defstruct: NonEmptyList a
        : first a
        : rest List a
................................................................................
        type: (List a) Int -- Int
        : NonEmptyList
          swap dup first> rotate rest> rotate + sum-helper
        : EmptyList
          swap drop

        def: main
        entry: true
        : 1 2 3 EmptyList >NonEmptyList >NonEmptyList >NonEmptyList
          sum
    `);

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

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

test('Int case', async () => {
    const wat = await compiler.toWat(`
        defunion: IntParseResult
        : Int
        : NoInt

        defstruct: NoInt

        defmulti: double
        : Int
          2 *
        : NoInt
          drop 0

        def: main
        entry: true
        : 4 double
    `);

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

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

test('Int match', async () => {
    const wat = await compiler.toWat(`
        defmulti: double
        : Int( value 0 )
          drop 2
        : Int
          2 *

        def: main
        entry: true
        : 0 double
    `);

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

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

test('Int match (reverse)', async () => {
    const wat = await compiler.toWat(`
        defmulti: double
        : Int( value 0 )
          drop 2
        : Int
          2 *

        def: main
        entry: true
        : 6 double
    `);

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

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

test('Correct Int boxing behaviour', async () => {
    const wat = await compiler.toWat(`
        defmulti: add
        : Int( value 0 )
          swap 
          drop 2
          swap
          +
        : Int
          +

        def: main
        entry: true
        : 10 6 add
    `);

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

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

test('Correct Int boxing behaviour when mismatch between word input size and stack size', async () => {
    const wat = await compiler.toWat(`
        defstruct: Nil

        defmulti: inc-zero
        : Int( value 0 )
          swap 
          drop 1
          swap
        : Int

        def: main
        entry: true
        : 0 Nil inc-zero
          drop 
    `);

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

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

test('Generic case', async () => {
    const wat = await compiler.toWat(`
        defunion: Maybe a
        : a
        : Nil

        defstruct: Nil

        defmulti: map
................................................................................
        type: (Maybe a) a -- a
        : a
          drop
        : Nil
          swap drop

        def: main
        entry: true
        : 10
          [ 1 - ] map
          0 with-default
    `);

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

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



|







 







<












|













<











|







 







<













|







 







<










|







 







<










|













<









|







<









|







<









|










<









|










<










|







 







<









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
..
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
...
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
...
141
142
143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171

172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205

206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225

226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245

246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
...
271
272
273
274
275
276
277

278
279
280
281
282
283
284
285
286
const compiler = require('./compiler.wrapper');

test('Simple case', async () => {
    const wat = await compiler.toWat('main', `
        defunion: Bool
        : True
        : False

        defstruct: True
        defstruct: False

................................................................................
        defmulti: to-int
        : True
          drop 100
        : False
          drop 75

        def: main

        : True to-int 
          False to-int 
          -
    `);

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

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

// Same as above, but without an explicit False branch.
test('Default branch', async () => {
    const wat = await compiler.toWat('main', `
        defunion: Bool
        : True 
        : False

        defstruct: True
        defstruct: False

        defmulti: to-int
        : True
          drop 100
        else: drop 75

        def: main

        : True to-int 
          False to-int 
          -
    `);

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

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

test('Multiple arguments', async () => {
    const wat = await compiler.toWat('main', `
        defunion: Beings
        : Person 
        : Dog

        defstruct: Person
        : age Int

................................................................................
        defmulti: get-man-age
        : Person
          age>
        : Dog
          man-years>

        def: main

        : 18 >Person 10 add-to-age 
          0 >Dog 2 add-to-age 
          get-man-age swap 
          get-man-age swap 
          -
    `);

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

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

test('Generic arguments', async () => {
    const wat = await compiler.toWat('main', `
        defunion: List a
        : NonEmptyList a 
        : EmptyList

        defstruct: NonEmptyList a
        : first a
        : rest List a
................................................................................
        defmulti: first-or-default
        : NonEmptyList
          drop first>
        : EmptyList
          swap drop

        def: main

        : 1 EmptyList >NonEmptyList
          0 first-or-default
    `);

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

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

test('Recursive word', async () => {
    const wat = await compiler.toWat('main', `
        defunion: List a
        : NonEmptyList a 
        : EmptyList

        defstruct: NonEmptyList a
        : first a
        : rest List a
................................................................................
        type: (List a) Int -- Int
        : NonEmptyList
          swap dup first> rotate rest> rotate + sum-helper
        : EmptyList
          swap drop

        def: main

        : 1 2 3 EmptyList >NonEmptyList >NonEmptyList >NonEmptyList
          sum
    `);

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

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

test('Int case', async () => {
    const wat = await compiler.toWat('main', `
        defunion: IntParseResult
        : Int
        : NoInt

        defstruct: NoInt

        defmulti: double
        : Int
          2 *
        : NoInt
          drop 0

        def: main

        : 4 double
    `);

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

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

test('Int match', async () => {
    const wat = await compiler.toWat('main', `
        defmulti: double
        : Int( value 0 )
          drop 2
        : Int
          2 *

        def: main

        : 0 double
    `);

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

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

test('Int match (reverse)', async () => {
    const wat = await compiler.toWat('main', `
        defmulti: double
        : Int( value 0 )
          drop 2
        : Int
          2 *

        def: main

        : 6 double
    `);

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

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

test('Correct Int boxing behaviour', async () => {
    const wat = await compiler.toWat('main', `
        defmulti: add
        : Int( value 0 )
          swap 
          drop 2
          swap
          +
        : Int
          +

        def: main

        : 10 6 add
    `);

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

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

test('Correct Int boxing behaviour when mismatch between word input size and stack size', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Nil

        defmulti: inc-zero
        : Int( value 0 )
          swap 
          drop 1
          swap
        : Int

        def: main

        : 0 Nil inc-zero
          drop 
    `);

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

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

test('Generic case', async () => {
    const wat = await compiler.toWat('main', `
        defunion: Maybe a
        : a
        : Nil

        defstruct: Nil

        defmulti: map
................................................................................
        type: (Maybe a) a -- a
        : a
          drop
        : Nil
          swap drop

        def: main

        : 10
          [ 1 - ] map
          0 with-default
    `);

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

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

Modified wasm_tests/pattern_match.test.js from [72e613569d] to [57e7981f91].

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
const compiler = require('./compiler.wrapper');

test('Basic pattern match', async () => {
    const wat = await compiler.toWat(`
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        : Box
          drop 0

        def: main
        entry: true
        : 0 >Box not
    `);

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

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

test('Basic pattern match with default implementation', async () => {
    const wat = await compiler.toWat(`
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 0 >Box not
    `);

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

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

test('Basic pattern match reverse case', async () => {
    const wat = await compiler.toWat(`
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 1 >Box not
    `);

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

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

test('Multiple arguments', async () => {
    const wat = await compiler.toWat(`




















        defstruct: Point
        : first Int
        : second Int

        defmulti: origo?
        : Point( first 0 second 0 )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 0 0 >Point origo?
    `);

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

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

test('Multiple arguments reverse case', async () => {
    const wat = await compiler.toWat(`
        defstruct: Point
        : first Int
        : second Int

        defmulti: origo?
        : Point( first 0 second 0 )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 0 1 >Point origo?
    `);

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

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

test('Recursive match', async () => {
    const wat = await compiler.toWat(`
        defstruct: Box
        : value Int

        defstruct: BoxOfBox
        : box Box

        defmulti: deep-one?
        : BoxOfBox( box Box( value 1 ) )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 1 >Box >BoxOfBox deep-one?
    `);

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

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

test('Recursive match reverse case', async () => {
    const wat = await compiler.toWat(`
        defstruct: Box
        : value Int

        defstruct: BoxOfBox
        : box Box

        defmulti: deep-one?
        : BoxOfBox( box Box( value 1 ) )
          drop 1
        else: drop 0

        def: main
        entry: true
        : 2 >Box >BoxOfBox deep-one?
    `);

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

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



|










<









|









<









|









<









|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>










<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<









|












<









|












<







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
const compiler = require('./compiler.wrapper');

test('Basic pattern match', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        : Box
          drop 0

        def: main

        : 0 >Box not
    `);

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

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

test('Basic pattern match with default implementation', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        else: drop 0

        def: main

        : 0 >Box not
    `);

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

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

test('Basic pattern match reverse case', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Box
        : value Int

        defmulti: not
        : Box( value 0 )
          drop 1
        else: drop 0

        def: main

        : 1 >Box not
    `);

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

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

test('Multiple arguments', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Point
        : first Int
        : second Int

        defmulti: origo?
        : Point( first 0 second 0 )
          drop 1
        else: drop 0

        def: main
        : 0 0 >Point origo?
    `);

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

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

test('Multiple arguments reverse case', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Point
        : first Int
        : second Int

        defmulti: origo?
        : Point( first 0 second 0 )
          drop 1
        else: drop 0

        def: main






















        : 0 1 >Point origo?
    `);

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

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

test('Recursive match', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Box
        : value Int

        defstruct: BoxOfBox
        : box Box

        defmulti: deep-one?
        : BoxOfBox( box Box( value 1 ) )
          drop 1
        else: drop 0

        def: main

        : 1 >Box >BoxOfBox deep-one?
    `);

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

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

test('Recursive match reverse case', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Box
        : value Int

        defstruct: BoxOfBox
        : box Box

        defmulti: deep-one?
        : BoxOfBox( box Box( value 1 ) )
          drop 1
        else: drop 0

        def: main

        : 2 >Box >BoxOfBox deep-one?
    `);

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

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

Modified wasm_tests/quotes.test.js from [8233315f50] to [97846aa4b6].

1
2
3
4
5
6
7
8
9
10
11
12
13
..
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
const compiler = require('./compiler.wrapper');

test('Basic quotation', async () => {
    const wat = await compiler.toWat(`
        def: main
        entry: true
        : 2 [ inc dec dec ] !

        def: inc
        : 1 +

        def: dec
        : 1 -
................................................................................

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

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

test('Basic quotation', async () => {
    const wat = await compiler.toWat(`
        defstruct: Coordinate
        : x Int
        : y Int

        def: update-x
        type: Coordinate [ Int -- Int ] -- Coordinate
        : swap
          dup x>
          -rotate
          !
          >x

        def: main
        entry: true
        : 1 2 >Coordinate
          [ 1 + ] update-x
          x>
    `);

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

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



|

<







 







|













<









1
2
3
4
5

6
7
8
9
10
11
12
..
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
const compiler = require('./compiler.wrapper');

test('Basic quotation', async () => {
    const wat = await compiler.toWat('main', `
        def: main

        : 2 [ inc dec dec ] !

        def: inc
        : 1 +

        def: dec
        : 1 -
................................................................................

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

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

test('Basic quotation', async () => {
    const wat = await compiler.toWat('main', `
        defstruct: Coordinate
        : x Int
        : y Int

        def: update-x
        type: Coordinate [ Int -- Int ] -- Coordinate
        : swap
          dup x>
          -rotate
          !
          >x

        def: main

        : 1 2 >Coordinate
          [ 1 + ] update-x
          x>
    `);

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

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

Modified wasm_tests/record.test.js from [203aebee22] to [6889e1e1fa].

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(`
       defstruct: True 
       defstruct: 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(`
        defstruct: 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);
});



|




<










|







<







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
const compiler = require('./compiler.wrapper');

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

       def: main

       : 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('main', `
        defstruct: Person
        : age Int

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

        def: main

        : 1 >Person 19 >age inc-age age>
    `);

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

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

Modified wasm_tests/stack.test.js from [493c219118] to [ba1b453211].

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
..
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
    `);
................................................................................

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

test('Under', async() => {
    // Not sure if under is actually a known function in forth
    // This is mainly to test -rotate
    const wat = await compiler.toWat(`
        def: main
        entry: true
        type: -- Int
        : 1 2 under - + 3 =

        def: under
        type: a b -- b b a
        : dup -rotate
    `);

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

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



|

<







 







|

<







 







|

<












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
..
31
32
33
34
35
36
37
38
39

40
41
42
43
44
45
46
47
48
49
50
51
const compiler = require('./compiler.wrapper');

test('Square', async () => {
    const wat = await compiler.toWat('main', `
        def: main

        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('main', `
        def: main

        type: -- Int
        : 1 2 over - + 2 =

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

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

test('Under', async() => {
    // Not sure if under is actually a known function in forth
    // This is mainly to test -rotate
    const wat = await compiler.toWat('main', `
        def: main

        type: -- Int
        : 1 2 under - + 3 =

        def: under
        type: a b -- b b a
        : dup -rotate
    `);

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

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