Stabel

Check-in [b730446f95]
Login
Overview
Comment:Strings now work.
Timelines: family | ancestors | descendants | both | strings
Files: files | file ages | folders
SHA3-256: b730446f9517fd476906826aa067995cc17bb0765fbe4b4f5dcc5b1286564637
User & Date: robin.hansen on 2021-09-06 20:37:55
Other Links: branch diff | manifest | tags
Context
2021-09-06
20:39
String literals. [3fac68d49a]. check-in: fc3b105833 user: robin.hansen tags: trunk
20:37
Strings now work. Closed-Leaf check-in: b730446f95 user: robin.hansen tags: strings
19:36
Possible finished implementation of strings, need to verify with wasm test. check-in: a046fe223a user: robin.hansen tags: strings
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Modified src/Stabel/Codegen.elm from [a26ff5ae8f] to [8bebd10adc].

786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
            let
                indexOfId =
                    indexOf name context.inlineFunctionNames
                        |> Maybe.withDefault 0
            in
            Wasm.Batch
                [ Wasm.Commented
                    (name ++ "ref")
                    (Wasm.I32_Const indexOfId)
                , BaseModule.callStackPushFn
                ]

        ConstructType typeId members ->
            let
                typeSize =







|







786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
            let
                indexOfId =
                    indexOf name context.inlineFunctionNames
                        |> Maybe.withDefault 0
            in
            Wasm.Batch
                [ Wasm.Commented
                    ("ref: " ++ name)
                    (Wasm.I32_Const indexOfId)
                , BaseModule.callStackPushFn
                ]

        ConstructType typeId members ->
            let
                typeSize =

Modified src/Stabel/Qualifier.elm from [b3bf682249] to [546a2fca9e].

1481
1482
1483
1484
1485
1486
1487

1488
1489
1490
1491
1492
1493
1494
1495
                    -- therefore it should never be visible to the user
                    Parser.InlineFunction loc
                        [ Parser.ArrayLiteral loc <|
                            List.map (Parser.Integer loc) stringBytes
                        , Parser.ExternalFunction loc [ "string" ] "from-bytes"
                        ]
            in

            qualifyNode config currentDefName stringNode acc


isMultiFunction : Parser.FunctionDefinition -> Bool
isMultiFunction def =
    case def.implementation of
        Parser.SoloImpl _ ->
            False







>
|







1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
                    -- therefore it should never be visible to the user
                    Parser.InlineFunction loc
                        [ Parser.ArrayLiteral loc <|
                            List.map (Parser.Integer loc) stringBytes
                        , Parser.ExternalFunction loc [ "string" ] "from-bytes"
                        ]
            in
            qualifyNode config currentDefName (Parser.Function loc "!") acc
                |> qualifyNode config currentDefName stringNode


isMultiFunction : Parser.FunctionDefinition -> Bool
isMultiFunction def =
    case def.implementation of
        Parser.SoloImpl _ ->
            False

Modified src/Stabel/Wasm.elm from [00f148bec4] to [5257e9c1dc].

416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

        Unreachable ->
            Str "unreachable"

        Commented comment inst ->
            case formatInstruction inst of
                Str val ->
                    Str <| val ++ ";; " ++ comment

                BatchFormat batch ->
                    BatchFormat <| (Str <| ";; " ++ comment) :: batch

                Indent batch ->
                    Indent <| (Str <| ";; " ++ comment) :: batch








|







416
417
418
419
420
421
422
423
424
425
426
427
428
429
430

        Unreachable ->
            Str "unreachable"

        Commented comment inst ->
            case formatInstruction inst of
                Str val ->
                    Str <| val ++ " ;; " ++ comment

                BatchFormat batch ->
                    BatchFormat <| (Str <| ";; " ++ comment) :: batch

                Indent batch ->
                    Indent <| (Str <| ";; " ++ comment) :: batch

Modified src/TestCompiler.elm from [e04edc62d9] to [8b48cbd435].

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
            opts.modules
                |> List.map parseModuleSource
                |> Result.combine

        parseModuleSource mod =
            let
                fullPath =
                    mod.package ++ mod.modulePath
            in
            case Parser.run fullPath mod.source of
                Err errs ->
                    Err ( fullPath, mod.source, errs )

                Ok ast ->
                    Ok ( mod.package, mod.modulePath, ast )







|







187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
            opts.modules
                |> List.map parseModuleSource
                |> Result.combine

        parseModuleSource mod =
            let
                fullPath =
                    "/" ++ mod.package ++ "/" ++ mod.modulePath
            in
            case Parser.run fullPath mod.source of
                Err errs ->
                    Err ( fullPath, mod.source, errs )

                Ok ast ->
                    Ok ( mod.package, mod.modulePath, ast )

Modified wasm_tests/compiler.wrapper.js from [897ec18e2b] to [86e63f9b44].

22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
48
49
50
51
52
53
54































55
56
57
58
59
60
61
..
81
82
83
84
85
86
87





















88
89
90
91
92
93
94
            } else {
                reject(output);
            }
        });
    });
}

exports.toProjectWat = function toWat(payload) {
    return new Promise((resolve, reject) => {
        const compiler = Compiler.Elm.TestCompiler.init({
            flags: {
                __type: 'CompileProject',
                entryPoint: payload.entryPoint,
                modules: payload.modules.map((mod) => {
                    mod.source = stripIndent(mod.source)
................................................................................
                resolve(output);
            } else {
                reject(output);
            }
        });
    });
}
































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

................................................................................
    }

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







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
..
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
...
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
            } else {
                reject(output);
            }
        });
    });
}

function toProjectWat(payload) {
    return new Promise((resolve, reject) => {
        const compiler = Compiler.Elm.TestCompiler.init({
            flags: {
                __type: 'CompileProject',
                entryPoint: payload.entryPoint,
                modules: payload.modules.map((mod) => {
                    mod.source = stripIndent(mod.source)
................................................................................
                resolve(output);
            } else {
                reject(output);
            }
        });
    });
}

exports.toProjectWat = toProjectWat;

exports.toStringWat = function toStringWat(entry, sourceCode) {
    return toProjectWat({
        entryPoint: `/author/sample/core/${entry}`,
        modules: [
            {
                package: 'stabel/standard_library',
                module: 'string',
                source: `
                    defmodule:
                    exposing: String from-bytes
                    :

                    defstruct: String
                    : content Array Int

                    def: from-bytes
                    type: (Array Int) -- String
                    : >String
                `
            },
            {
                package: 'author/sample',
                module: 'core',
                source: stripIndent(sourceCode)
            }
        ]
    });
}

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

................................................................................
    }

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

    stringElement(index) {
        // String structure => typeId | array 
        const strPointer = this.stackElement(index || 0);
        const strOffset = strPointer / 4;

        const arrayPointer = this.memoryView[strOffset + 1];
        const arrayOffset = arrayPointer / 4;

        const strLen = this.memoryView[arrayOffset];

        const content = [];
        const strValueOffset = arrayOffset + 1;
        for (let i = 0; i < strLen; i++) {
            content.push(this.memoryView[strValueOffset + i]);
        }

        const decoder = new TextDecoder();
        const strAsUtf8 = new Uint8Array(content);
        return decoder.decode(strAsUtf8);
    }

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

Added wasm_tests/string.test.js version [5d3dbc07b2].











































































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

test('Empty', async () => {
    const wat = await compiler.toStringWat('main', `
        def: main
        type: -- /string/String
        : ""
    `);

    const result = await compiler.run(wat, '/author/sample/core/main');

    expect(result.stringElement()).toBe("");
});

test('Sample', async () => {
    const wat = await compiler.toStringWat('main', `
        def: main
        type: -- /string/String
        : "This is a test"
    `);

    const result = await compiler.run(wat, '/author/sample/core/main');

    expect(result.stringElement()).toBe("This is a test");
});

test('Emoji', async () => {
    const wat = await compiler.toStringWat('main', `
        def: main
        type: -- /string/String
        : "💩"
    `);

    const result = await compiler.run(wat, '/author/sample/core/main');

    expect(result.stringElement()).toBe("💩");
});