| Differences between
and this patch
- a/Tools/ChangeLog +85 lines
Lines 1-3 a/Tools/ChangeLog_sec1
1
2018-09-05  Myles C. Maxfield  <mmaxfield@apple.com>
2
3
        [WHLSL] The parser is too slow
4
        https://bugs.webkit.org/show_bug.cgi?id=189014
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This patch includes two changes:
9
        1. Migrate from using try/catch to simply returning the WSyntaxError. This means that
10
           each parser call has to check for this sentinel value. The lexer still can throw if
11
           it encounters an unknown token or an unmatched "/*" token (which is rare).
12
        2. After removing try/catch, making the sentinel values not inherit from Error (the
13
           Error constructor was taking lots of time)
14
        2. Previously, every time the parser failed (which is many times per expression) it was
15
           running a regex over the entire source text to figure out where the error occurred.
16
           Instead, we can preprocess the text string to find these line numbers ahead of time.
17
18
        Together, these make the parser 75x faster. Parsing the standard library goes from 2.5
19
        hours down to 2 minutes. Because it's now a reasonable length, this patch uncomments
20
        the bulk of the standard library.
21
22
        * WebGPUShadingLanguageRI/All.js:
23
        * WebGPUShadingLanguageRI/Lexer.js:
24
        (Lexer):
25
        (Lexer.prototype.lineNumberForIndex):
26
        * WebGPUShadingLanguageRI/Parse.js:
27
        (fail):
28
        (backtrackingScope):
29
        (testScope):
30
        (genericConsume):
31
        (consumeEndOfTypeArgs):
32
        (parseTerm):
33
        (parseConstexpr):
34
        (parseTypeArguments):
35
        (parseType.getAddressSpace):
36
        (parseType):
37
        (parseTypeDef):
38
        (genericParseLeft):
39
        (parseCallExpression.let.parseArguments):
40
        (isCallExpression):
41
        (parseSuffixOperator):
42
        (parsePossibleSuffix):
43
        (parsePreIncrement):
44
        (parsePossiblePrefix):
45
        (parsePossibleTernaryConditional):
46
        (parsePossibleAssignment):
47
        (parsePostIncrement):
48
        (parseEffectfulExpression):
49
        (genericParseCommaExpression):
50
        (parseEffectfulStatement):
51
        (parseReturn):
52
        (parseBreak):
53
        (parseContinue):
54
        (parseIfStatement):
55
        (parseWhile):
56
        (parseFor):
57
        (parseDo):
58
        (parseVariableDecls):
59
        (parseSwitchCase):
60
        (parseSwitchStatement):
61
        (parseStatement):
62
        (parseBlockBody):
63
        (parseBlock):
64
        (parseParameter):
65
        (parseFuncName):
66
        (parseFuncDecl):
67
        (parseFuncDef):
68
        (parseField):
69
        (parseStructType):
70
        (parseNativeFunc):
71
        (parseNative):
72
        (parseRestrictedFuncDef):
73
        (parseEnumMember):
74
        (parseEnumType):
75
        (parse):
76
        * WebGPUShadingLanguageRI/SPIRV.html:
77
        * WebGPUShadingLanguageRI/StandardLibrary.js:
78
        (let.standardLibrary):
79
        * WebGPUShadingLanguageRI/Test.html:
80
        * WebGPUShadingLanguageRI/Test.js:
81
        (checkFail.doPrep): Deleted.
82
        * WebGPUShadingLanguageRI/WLexicalError.js: Added.
83
        (WLexicalError):
84
        * WebGPUShadingLanguageRI/index.html:
85
1
2018-09-05  Woodrow Wang  <woodrow_wang@apple.com>
86
2018-09-05  Woodrow Wang  <woodrow_wang@apple.com>
2
87
3
        Added runtime feature flag for web API statistics
88
        Added runtime feature flag for web API statistics
- a/Tools/WebGPUShadingLanguageRI/All.js +1 lines
Lines 168-173 load("VariableDecl.js"); a/Tools/WebGPUShadingLanguageRI/All.js_sec1
168
load("VariableRef.js");
168
load("VariableRef.js");
169
load("VectorType.js");
169
load("VectorType.js");
170
load("VisitingSet.js");
170
load("VisitingSet.js");
171
load("WLexicalError.js");
171
load("WSyntaxError.js");
172
load("WSyntaxError.js");
172
load("WTrapError.js");
173
load("WTrapError.js");
173
load("WTypeError.js");
174
load("WTypeError.js");
- a/Tools/WebGPUShadingLanguageRI/Lexer.js -32 / +10 lines
Lines 35-40 class Lexer { a/Tools/WebGPUShadingLanguageRI/Lexer.js_sec1
35
        this._text = text;
35
        this._text = text;
36
        this._index = 0;
36
        this._index = 0;
37
        this._stack = [];
37
        this._stack = [];
38
39
        this._lineNumbers = [];
40
        let lineNumber = 1;
41
        for (let i = 0; i < this._text.length; ++i) {
42
            this._lineNumbers.push(lineNumber);
43
            if (this._text[i] == '\n')
44
                ++lineNumber;
45
        }
38
    }
46
    }
39
    
47
    
40
    get lineNumber()
48
    get lineNumber()
Lines 53-60 class Lexer { a/Tools/WebGPUShadingLanguageRI/Lexer.js_sec2
53
    
61
    
54
    lineNumberForIndex(index)
62
    lineNumberForIndex(index)
55
    {
63
    {
56
        let matches = this._text.substring(0, index).match(/\n/g);
64
        return this._lineNumbers[index] + this._lineNumberOffset;
57
        return (matches ? matches.length : 0) + this._lineNumberOffset;
58
    }
65
    }
59
    
66
    
60
    get state() { return {index: this._index, stack: this._stack.concat()}; }
67
    get state() { return {index: this._index, stack: this._stack.concat()}; }
Lines 166-200 class Lexer { a/Tools/WebGPUShadingLanguageRI/Lexer.js_sec3
166
    
173
    
167
    fail(error)
174
    fail(error)
168
    {
175
    {
169
        throw new WSyntaxError(this.originString, error);
176
        throw new WLexicalError(this.originString, error);
170
    }
171
    
172
    backtrackingScope(callback)
173
    {
174
        let state = this.state;
175
        try {
176
            return callback();
177
        } catch (e) {
178
            if (e instanceof WSyntaxError) {
179
                this.state = state;
180
                return null;
181
            }
182
            throw e;
183
        }
184
    }
185
    
186
    testScope(callback)
187
    {
188
        let state = this.state;
189
        try {
190
            callback();
191
            return true;
192
        } catch (e) {
193
            if (e instanceof WSyntaxError)
194
                return false;
195
            throw e;
196
        } finally {
197
            this.state = state;
198
        }
199
    }
177
    }
200
}
178
}
- a/Tools/WebGPUShadingLanguageRI/LexerToken.js -1 / +1 lines
Lines 70-76 class LexerToken { a/Tools/WebGPUShadingLanguageRI/LexerToken.js_sec1
70
    
70
    
71
    get originString()
71
    get originString()
72
    {
72
    {
73
        return this.origin + ":" + (this.lineNumber + 1);
73
        return this.origin + ":" + this.lineNumber;
74
    }
74
    }
75
    
75
    
76
    toString()
76
    toString()
- a/Tools/WebGPUShadingLanguageRI/Parse.js -203 / +595 lines
Lines 27-33 a/Tools/WebGPUShadingLanguageRI/Parse.js_sec1
27
function parse(program, origin, originKind, lineNumberOffset, text)
27
function parse(program, origin, originKind, lineNumberOffset, text)
28
{
28
{
29
    let lexer = new Lexer(origin, originKind, lineNumberOffset, text);
29
    let lexer = new Lexer(origin, originKind, lineNumberOffset, text);
30
    
30
31
    // The hardest part of dealing with C-like languages is parsing variable declaration statements.
31
    // The hardest part of dealing with C-like languages is parsing variable declaration statements.
32
    // Let's consider if this happens in WSL. Here are the valid statements in WSL that being with an
32
    // Let's consider if this happens in WSL. Here are the valid statements in WSL that being with an
33
    // identifier, if we assume that any expression can be a standalone statement.
33
    // identifier, if we assume that any expression can be a standalone statement.
Lines 61-92 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec2
61
    // pointers means that we can still allow function call statements - unlike in C, those cannot
61
    // pointers means that we can still allow function call statements - unlike in C, those cannot
62
    // have arbitrary expressions as the callee. The remaining two problems are solved by
62
    // have arbitrary expressions as the callee. The remaining two problems are solved by
63
    // backtracking. In all other respects, this is a simple recursive descent parser.
63
    // backtracking. In all other respects, this is a simple recursive descent parser.
64
    
64
65
    function fail(error)
66
    {
67
        return new WSyntaxError(lexer.originString, error);
68
    }
69
70
    function backtrackingScope(callback)
71
    {
72
        let state = lexer.state;
73
        let maybeError = callback();
74
        if (maybeError instanceof WSyntaxError) {
75
            lexer.state = state;
76
            return null;
77
        } else
78
            return maybeError;
79
    }
80
81
    function testScope(callback)
82
    {
83
        let state = lexer.state;
84
        let maybeError = callback();
85
        lexer.state = state;
86
        return !(maybeError instanceof WSyntaxError);
87
    }
88
65
    function genericConsume(callback, explanation)
89
    function genericConsume(callback, explanation)
66
    {
90
    {
67
        let token = lexer.next();
91
        let token = lexer.next();
68
        if (!token)
92
        if (!token)
69
            lexer.fail("Unexpected end of file");
93
            return fail("Unexpected end of file");
70
        if (!callback(token))
94
        if (!callback(token))
71
            lexer.fail("Unexpected token: " + token.text + "; expected: " + explanation);
95
            return fail("Unexpected token: " + token.text + "; expected: " + explanation);
72
        return token;
96
        return token;
73
    }
97
    }
74
    
98
75
    function consume(...texts)
99
    function consume(...texts)
76
    {
100
    {
77
        return genericConsume(token => texts.includes(token.text), texts);
101
        return genericConsume(token => texts.includes(token.text), texts);
78
    }
102
    }
79
    
103
80
    function consumeKind(kind)
104
    function consumeKind(kind)
81
    {
105
    {
82
        return genericConsume(token => token.kind == kind, kind);
106
        return genericConsume(token => token.kind == kind, kind);
83
    }
107
    }
84
    
108
85
    function assertNext(...texts)
109
    function assertNext(...texts)
86
    {
110
    {
87
        lexer.push(consume(...texts));
111
        let maybeError = consume(...texts);
112
        if (maybeError instanceof WSyntaxError)
113
            return maybeError;
114
        lexer.push(maybeError);
88
    }
115
    }
89
    
116
90
    function genericTest(callback)
117
    function genericTest(callback)
91
    {
118
    {
92
        let token = lexer.peek();
119
        let token = lexer.peek();
Lines 94-110 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec3
94
            return token;
121
            return token;
95
        return null;
122
        return null;
96
    }
123
    }
97
    
124
98
    function test(...texts)
125
    function test(...texts)
99
    {
126
    {
100
        return genericTest(token => texts.includes(token.text));
127
        return genericTest(token => texts.includes(token.text));
101
    }
128
    }
102
    
129
103
    function testKind(kind)
130
    function testKind(kind)
104
    {
131
    {
105
        return genericTest(token => token.kind == kind);
132
        return genericTest(token => token.kind == kind);
106
    }
133
    }
107
    
134
108
    function tryConsume(...texts)
135
    function tryConsume(...texts)
109
    {
136
    {
110
        let result = test(...texts);
137
        let result = test(...texts);
Lines 112-118 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec4
112
            lexer.next();
139
            lexer.next();
113
        return result;
140
        return result;
114
    }
141
    }
115
    
142
116
    function tryConsumeKind(kind)
143
    function tryConsumeKind(kind)
117
    {
144
    {
118
        let result = testKind(kind);
145
        let result = testKind(kind);
Lines 120-135 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec5
120
            lexer.next();
147
            lexer.next();
121
        return result;
148
        return result;
122
    }
149
    }
123
    
150
124
    function consumeEndOfTypeArgs()
151
    function consumeEndOfTypeArgs()
125
    {
152
    {
126
        let rightShift = tryConsume(">>");
153
        let rightShift = tryConsume(">>");
127
        if (rightShift)
154
        if (rightShift)
128
            lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">"));
155
            lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">"));
129
        else
156
        else {
130
            consume(">");
157
            let maybeError = consume(">");
158
            if (maybeError instanceof WSyntaxError)
159
                return maybeError;
160
        }
131
    }
161
    }
132
    
162
133
    function parseTerm()
163
    function parseTerm()
134
    {
164
    {
135
        let token;
165
        let token;
Lines 140-152 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec6
140
        if (token = tryConsumeKind("intLiteral")) {
170
        if (token = tryConsumeKind("intLiteral")) {
141
            let intVersion = (+token.text) | 0;
171
            let intVersion = (+token.text) | 0;
142
            if ("" + intVersion !== token.text)
172
            if ("" + intVersion !== token.text)
143
                lexer.fail("Integer literal is not an integer: " + token.text);
173
                return fail("Integer literal is not an integer: " + token.text);
144
            return new IntLiteral(token, intVersion);
174
            return new IntLiteral(token, intVersion);
145
        }
175
        }
146
        if (token = tryConsumeKind("uintLiteral")) {
176
        if (token = tryConsumeKind("uintLiteral")) {
147
            let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0;
177
            let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0;
148
            if (uintVersion + "u" !== token.text)
178
            if (uintVersion + "u" !== token.text)
149
                lexer.fail("Integer literal is not 32-bit unsigned integer: " + token.text);
179
                return fail("Integer literal is not 32-bit unsigned integer: " + token.text);
150
            return new UintLiteral(token, uintVersion);
180
            return new UintLiteral(token, uintVersion);
151
        }
181
        }
152
        if ((token = tryConsumeKind("intHexLiteral"))
182
        if ((token = tryConsumeKind("intHexLiteral"))
Lines 162-168 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec7
162
            else
192
            else
163
                intVersion = intVersion >>> 0;
193
                intVersion = intVersion >>> 0;
164
            if (intVersion.toString(16) !== hexString)
194
            if (intVersion.toString(16) !== hexString)
165
                lexer.fail("Hex integer literal is not an integer: " + token.text);
195
                return fail("Hex integer literal is not an integer: " + token.text);
166
            if (token.kind == "intHexLiteral")
196
            if (token.kind == "intHexLiteral")
167
                return new IntLiteral(token, intVersion);
197
                return new IntLiteral(token, intVersion);
168
            return new UintLiteral(token, intVersion >>> 0);
198
            return new UintLiteral(token, intVersion >>> 0);
Lines 178-207 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec8
178
        if (token = tryConsume("true", "false"))
208
        if (token = tryConsume("true", "false"))
179
            return new BoolLiteral(token, token.text == "true");
209
            return new BoolLiteral(token, token.text == "true");
180
        // FIXME: Need support for other literals too.
210
        // FIXME: Need support for other literals too.
181
        consume("(");
211
        let maybeError = consume("(");
212
        if (maybeError instanceof WSyntaxError)
213
            return maybeError;
182
        let result = parseExpression();
214
        let result = parseExpression();
183
        consume(")");
215
        if (result instanceof WSyntaxError)
216
            return result;
217
        maybeError = consume(")");
218
        if (maybeError instanceof WSyntaxError)
219
            return maybeError;
184
        return result;
220
        return result;
185
    }
221
    }
186
    
222
187
    function parseConstexpr()
223
    function parseConstexpr()
188
    {
224
    {
189
        let token;
225
        let token;
190
        if (token = tryConsume("-"))
226
        if (token = tryConsume("-")) {
191
            return new CallExpression(token, "operator" + token.text, [parseTerm()]);
227
            let term = parseTerm();
228
            if (term instanceof WSyntaxError)
229
                return term;
230
            return new CallExpression(token, "operator" + token.text, [term]);
231
        }
192
        let left = parseTerm();
232
        let left = parseTerm();
193
        if (token = tryConsume("."))
233
        if (left instanceof WSyntaxError)
194
            left = new DotExpression(token, left, consumeKind("identifier").text);
234
            return left;
235
        if (token = tryConsume(".")) {
236
            let maybeError = consumeKind("identifier")
237
            if (maybeError instanceof WSyntaxError)
238
                return maybeError;
239
            left = new DotExpression(token, left, maybeError.text);
240
        }
195
        return left;
241
        return left;
196
    }
242
    }
197
    
243
198
    function parseTypeArguments()
244
    function parseTypeArguments()
199
    {
245
    {
200
        if (!test("<"))
246
        if (!test("<"))
201
            return [];
247
            return [];
202
248
203
        let result = [];
249
        let result = [];
204
        consume("<");
250
        let maybeError = consume("<");
251
        if (maybeError instanceof WSyntaxError)
252
            return maybeError;
205
        while (!test(">")) {
253
        while (!test(">")) {
206
            // It's possible for a constexpr or type can syntactically overlap in the single
254
            // It's possible for a constexpr or type can syntactically overlap in the single
207
            // identifier case. Let's consider the possibilities:
255
            // identifier case. Let's consider the possibilities:
Lines 214-244 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec9
214
            // In the future we'll allow constexprs to do more things, and then we'll still have
262
            // In the future we'll allow constexprs to do more things, and then we'll still have
215
            // the problem that something of the form T[1][2][3]... can either be a type or a
263
            // the problem that something of the form T[1][2][3]... can either be a type or a
216
            // constexpr, and we can figure out in the checker which it is.
264
            // constexpr, and we can figure out in the checker which it is.
217
            let typeRef = lexer.backtrackingScope(() => {
265
            let typeRef = backtrackingScope(() => {
218
                let result = consumeKind("identifier");
266
                let result = consumeKind("identifier");
219
                assertNext(",", ">", ">>");
267
                if (result instanceof WSyntaxError)
268
                    return result;
269
                let maybeError = assertNext(",", ">", ">>");
270
                if (maybeError instanceof WSyntaxError)
271
                    return maybeError;
220
                return new TypeRef(result, result.text);
272
                return new TypeRef(result, result.text);
221
            });
273
            });
222
            if (typeRef)
274
            if (typeRef)
223
                result.push(typeRef);
275
                result.push(typeRef);
224
            else {
276
            else {
225
                let constexpr = lexer.backtrackingScope(() => {
277
                let constexpr = backtrackingScope(() => {
226
                    let result = parseConstexpr();
278
                    let result = parseConstexpr();
227
                    assertNext(",", ">", ">>");
279
                    if (result instanceof WSyntaxError)
280
                        return result;
281
                    let maybeError = assertNext(",", ">", ">>");
282
                    if (maybeError instanceof WSyntaxError)
283
                        return maybeError;
228
                    return result;
284
                    return result;
229
                });
285
                });
230
                if (constexpr)
286
                if (constexpr)
231
                    result.push(constexpr);
287
                    result.push(constexpr);
232
                else
288
                else {
233
                    result.push(parseType());
289
                    let type = parseType();
290
                    if (type instanceof WSyntaxError)
291
                        return type;
292
                    result.push(type);
293
                }
234
            }
294
            }
235
            if (!tryConsume(","))
295
            if (!tryConsume(","))
236
                break;
296
                break;
237
        }
297
        }
238
        consumeEndOfTypeArgs();
298
        maybeError = consumeEndOfTypeArgs();
299
        if (maybeError instanceof WSyntaxError)
300
            return maybeError;
239
        return result;
301
        return result;
240
    }
302
    }
241
    
303
242
    function parseType()
304
    function parseType()
243
    {
305
    {
244
        let token;
306
        let token;
Lines 246-313 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec10
246
        let addressSpaceConsumed = false;
308
        let addressSpaceConsumed = false;
247
        if (token = tryConsume(...addressSpaces))
309
        if (token = tryConsume(...addressSpaces))
248
            addressSpace = token.text;
310
            addressSpace = token.text;
249
        
311
250
        let name = consumeKind("identifier");
312
        let name = consumeKind("identifier");
313
        if (name instanceof WSyntaxError)
314
            return name;
251
        let typeArguments = parseTypeArguments();
315
        let typeArguments = parseTypeArguments();
316
        if (typeArguments instanceof WSyntaxError)
317
            return typeArguments;
252
        let type = new TypeRef(name, name.text, typeArguments);
318
        let type = new TypeRef(name, name.text, typeArguments);
253
        
319
254
        function getAddressSpace()
320
        function getAddressSpace()
255
        {
321
        {
256
            addressSpaceConsumed = true;
322
            addressSpaceConsumed = true;
257
            if (addressSpace)
323
            if (addressSpace)
258
                return addressSpace;
324
                return addressSpace;
259
            return consume(...addressSpaces).text;
325
            let consumedAddressSpace = consume(...addressSpaces);
326
            if (consumedAddressSpace instanceof WSyntaxError)
327
                return consumedAddressSpace;
328
            return consumedAddressSpace.text;
260
        }
329
        }
261
        
330
262
        const typeConstructorStack = [ ];
331
        const typeConstructorStack = [ ];
263
332
264
        for (let token; token = tryConsume("*", "[");) {
333
        for (let token; token = tryConsume("*", "[");) {
265
            if (token.text == "*") {
334
            if (token.text == "*") {
266
                // Likewise, the address space must be parsed before parsing continues.
335
                // Likewise, the address space must be parsed before parsing continues.
267
                const addressSpace = getAddressSpace();
336
                const addressSpace = getAddressSpace();
337
                if (addressSpace instanceof WSyntaxError)
338
                    return addressSpace;
268
                typeConstructorStack.unshift(type => new PtrType(token, addressSpace, type));
339
                typeConstructorStack.unshift(type => new PtrType(token, addressSpace, type));
269
                continue;
340
                continue;
270
            }
341
            }
271
342
272
            if (tryConsume("]")) {
343
            if (tryConsume("]")) {
273
                const addressSpace = getAddressSpace();
344
                const addressSpace = getAddressSpace();
345
                if (addressSpace instanceof WSyntaxError)
346
                    return addressSpace;
274
                typeConstructorStack.unshift(type => new ArrayRefType(token, addressSpace, type));
347
                typeConstructorStack.unshift(type => new ArrayRefType(token, addressSpace, type));
275
                continue;
348
                continue;
276
            }
349
            }
277
350
278
            const lengthExpr = parseConstexpr();
351
            const lengthExpr = parseConstexpr();
352
            if (lengthExpr instanceof WSyntaxError)
353
                return lengthExpr;
279
            typeConstructorStack.unshift(type => new ArrayType(token, type, lengthExpr));
354
            typeConstructorStack.unshift(type => new ArrayType(token, type, lengthExpr));
280
            consume("]");
355
            let maybeError = consume("]");
356
            if (maybeError instanceof WSyntaxError)
357
                return maybeError;
281
        }
358
        }
282
359
283
        for (let constructor of typeConstructorStack)
360
        for (let constructor of typeConstructorStack)
284
            type = constructor(type);
361
            type = constructor(type);
285
362
286
        if (addressSpace && !addressSpaceConsumed)
363
        if (addressSpace && !addressSpaceConsumed)
287
            lexer.fail("Address space specified for type that does not need address space");
364
            return fail("Address space specified for type that does not need address space");
288
365
289
        return type;
366
        return type;
290
    }
367
    }
291
    
368
292
    function parseTypeDef()
369
    function parseTypeDef()
293
    {
370
    {
294
        let origin = consume("typedef");
371
        let origin = consume("typedef");
295
        let name = consumeKind("identifier").text;
372
        if (origin instanceof WSyntaxError)
296
        consume("=");
373
            return origin;
374
        let maybeError = consumeKind("identifier");
375
        if (maybeError instanceof WSyntaxError)
376
            return maybeError;
377
        let name = maybeError.text;
378
        maybeError = consume("=");
379
        if (maybeError instanceof WSyntaxError)
380
            return maybeError;
297
        let type = parseType();
381
        let type = parseType();
298
        consume(";");
382
        if (type instanceof WSyntaxError)
383
            return type;
384
        maybeError = consume(";");
385
        if (maybeError instanceof WSyntaxError)
386
            return maybeError;
299
        return new TypeDef(origin, name, type);
387
        return new TypeDef(origin, name, type);
300
    }
388
    }
301
    
389
302
    function genericParseLeft(texts, nextParser, constructor)
390
    function genericParseLeft(texts, nextParser, constructor)
303
    {
391
    {
304
        let left = nextParser();
392
        let left = nextParser();
393
        if (left instanceof WSyntaxError)
394
            return left;
305
        let token;
395
        let token;
306
        while (token = tryConsume(...texts))
396
        while (token = tryConsume(...texts))
307
            left = constructor(token, left, nextParser());
397
            left = constructor(token, left, nextParser());
308
        return left;
398
        return left;
309
    }
399
    }
310
    
400
311
    function parseLeftOperatorCall(texts, nextParser)
401
    function parseLeftOperatorCall(texts, nextParser)
312
    {
402
    {
313
        return genericParseLeft(
403
        return genericParseLeft(
Lines 315-338 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec11
315
            (token, left, right) =>
405
            (token, left, right) =>
316
                new CallExpression(token, "operator" + token.text, [left, right]));
406
                new CallExpression(token, "operator" + token.text, [left, right]));
317
    }
407
    }
318
    
408
319
    function parseCallExpression()
409
    function parseCallExpression()
320
    {
410
    {
321
        let parseArguments = function(origin, callName) {
411
        let parseArguments = function(origin, callName) {
322
            let argumentList = [];
412
            let argumentList = [];
323
            while (!test(")")) {
413
            while (!test(")")) {
324
                let argument = parsePossibleAssignment();
414
                let argument = parsePossibleAssignment();
415
                if (argument instanceof WSyntaxError)
416
                    return argument;
325
                argumentList.push(argument);
417
                argumentList.push(argument);
326
                if (!tryConsume(","))
418
                if (!tryConsume(","))
327
                    break;
419
                    break;
328
            }
420
            }
329
            consume(")");
421
            let maybeError = consume(")");
422
            if (maybeError instanceof WSyntaxError)
423
                return maybeError;
330
            return new CallExpression(origin, callName, argumentList);
424
            return new CallExpression(origin, callName, argumentList);
331
        }
425
        }
332
426
333
        let name = lexer.backtrackingScope(() => {
427
        let name = backtrackingScope(() => {
334
            let name = consumeKind("identifier");
428
            let name = consumeKind("identifier");
335
            consume("(");
429
            if (name instanceof WSyntaxError)
430
                return name;
431
            let maybeError = consume("(");
432
            if (maybeError instanceof WSyntaxError)
433
                return maybeError;
336
            return name;
434
            return name;
337
        });
435
        });
338
436
Lines 341-380 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec12
341
            return result;
439
            return result;
342
        } else {
440
        } else {
343
            let returnType = parseType();
441
            let returnType = parseType();
344
            consume("(");
442
            if (returnType instanceof WSyntaxError)
443
                return returnType;
444
            let maybeError = consume("(");
445
            if (maybeError instanceof WSyntaxError)
446
                return maybeError;
345
            let result = parseArguments(returnType.origin, "operator cast");
447
            let result = parseArguments(returnType.origin, "operator cast");
346
            result.setCastData(returnType);
448
            result.setCastData(returnType);
347
            return result;
449
            return result;
348
        }
450
        }
349
    }
451
    }
350
    
452
351
    function isCallExpression()
453
    function isCallExpression()
352
    {
454
    {
353
        return lexer.testScope(() => {
455
        return testScope(() => {
354
                consumeKind("identifier");
456
                let maybeError = consumeKind("identifier");
355
                consume("(");
457
                if (maybeError instanceof WSyntaxError)
356
            }) || lexer.testScope(() => {
458
                    return maybeError;
357
                parseType();
459
                maybeError = consume("(");
358
                consume("(");
460
                if (maybeError instanceof WSyntaxError)
461
                    return maybeError;
462
            }) || testScope(() => {
463
                let type = parseType();
464
                if (type instanceof WSyntaxError)
465
                    return type;
466
                let maybeError = consume("(");
467
                if (maybeError instanceof WSyntaxError)
468
                    return maybeError;
359
            });
469
            });
360
    }
470
    }
361
    
471
362
    function emitIncrement(token, old, extraArg)
472
    function emitIncrement(token, old, extraArg)
363
    {
473
    {
364
        let args = [old];
474
        let args = [old];
365
        if (extraArg)
475
        if (extraArg)
366
            args.push(extraArg);
476
            args.push(extraArg);
367
        
477
368
        let name = "operator" + token.text;
478
        let name = "operator" + token.text;
369
        if (/=$/.test(name))
479
        if (/=$/.test(name))
370
            name = RegExp.leftContext;
480
            name = RegExp.leftContext;
371
        
481
372
        if (name == "operator")
482
        if (name == "operator")
373
            throw new Error("Invalid name: " + name);
483
            throw new Error("Invalid name: " + name);
374
        
484
375
        return new CallExpression(token, name, args);
485
        return new CallExpression(token, name, args);
376
    }
486
    }
377
    
487
378
    function finishParsingPostIncrement(token, left)
488
    function finishParsingPostIncrement(token, left)
379
    {
489
    {
380
        let readModifyWrite = new ReadModifyWriteExpression(token, left);
490
        let readModifyWrite = new ReadModifyWriteExpression(token, left);
Lines 382-388 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec13
382
        readModifyWrite.resultExp = readModifyWrite.oldValueRef();
492
        readModifyWrite.resultExp = readModifyWrite.oldValueRef();
383
        return readModifyWrite;
493
        return readModifyWrite;
384
    }
494
    }
385
    
495
386
    function parseSuffixOperator(left, acceptableOperators)
496
    function parseSuffixOperator(left, acceptableOperators)
387
    {
497
    {
388
        let token;
498
        let token;
Lines 395-405 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec14
395
            case "->":
505
            case "->":
396
                if (token.text == "->")
506
                if (token.text == "->")
397
                    left = new DereferenceExpression(token, left);
507
                    left = new DereferenceExpression(token, left);
398
                left = new DotExpression(token, left, consumeKind("identifier").text);
508
                let maybeError = consumeKind("identifier");
509
                if (maybeError instanceof WSyntaxError)
510
                    return maybeError;
511
                left = new DotExpression(token, left, maybeError.text);
399
                break;
512
                break;
400
            case "[": {
513
            case "[": {
401
                let index = parseExpression();
514
                let index = parseExpression();
402
                consume("]");
515
                if (index instanceof WSyntaxError)
516
                    return index;
517
                let maybeError = consume("]");
518
                if (maybeError instanceof WSyntaxError)
519
                    return maybeError;
403
                left = new IndexExpression(token, left, index);
520
                left = new IndexExpression(token, left, index);
404
                break;
521
                break;
405
            }
522
            }
Lines 409-415 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec15
409
        }
526
        }
410
        return left;
527
        return left;
411
    }
528
    }
412
    
529
413
    function parsePossibleSuffix()
530
    function parsePossibleSuffix()
414
    {
531
    {
415
        let acceptableOperators = ["++", "--", ".", "->", "["];
532
        let acceptableOperators = ["++", "--", ".", "->", "["];
Lines 417-429 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec16
417
        let left;
534
        let left;
418
        if (isCallExpression()) {
535
        if (isCallExpression()) {
419
            left = parseCallExpression();
536
            left = parseCallExpression();
537
            if (left instanceof WSyntaxError)
538
                return left;
420
            acceptableOperators = limitedOperators;
539
            acceptableOperators = limitedOperators;
421
        } else
540
        } else {
422
            left = parseTerm();
541
            left = parseTerm();
423
        
542
            if (left instanceof WSyntaxError)
543
                return left;
544
        }
545
424
        return parseSuffixOperator(left, acceptableOperators);
546
        return parseSuffixOperator(left, acceptableOperators);
425
    }
547
    }
426
    
548
427
    function finishParsingPreIncrement(token, left, extraArg)
549
    function finishParsingPreIncrement(token, left, extraArg)
428
    {
550
    {
429
        let readModifyWrite = new ReadModifyWriteExpression(token, left);
551
        let readModifyWrite = new ReadModifyWriteExpression(token, left);
Lines 431-484 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec17
431
        readModifyWrite.resultExp = readModifyWrite.newValueRef();
553
        readModifyWrite.resultExp = readModifyWrite.newValueRef();
432
        return readModifyWrite;
554
        return readModifyWrite;
433
    }
555
    }
434
    
556
435
    function parsePreIncrement()
557
    function parsePreIncrement()
436
    {
558
    {
437
        let token = consume("++", "--");
559
        let token = consume("++", "--");
560
        if (token instanceof WSyntaxError)
561
            return token;
438
        let left = parsePossiblePrefix();
562
        let left = parsePossiblePrefix();
563
        if (left instanceof WSyntaxError)
564
            return left;
439
        return finishParsingPreIncrement(token, left);
565
        return finishParsingPreIncrement(token, left);
440
    }
566
    }
441
    
567
442
    function parsePossiblePrefix()
568
    function parsePossiblePrefix()
443
    {
569
    {
444
        let token;
570
        let token;
445
        if (test("++", "--"))
571
        if (test("++", "--"))
446
            return parsePreIncrement();
572
            return parsePreIncrement();
447
        if (token = tryConsume("+", "-", "~"))
573
        if (token = tryConsume("+", "-", "~")) {
448
            return new CallExpression(token, "operator" + token.text, [parsePossiblePrefix()]);
574
            let possiblePrefix = parsePossiblePrefix();
449
        if (token = tryConsume("*"))
575
            if (possiblePrefix instanceof WSyntaxError)
450
            return new DereferenceExpression(token, parsePossiblePrefix());
576
                return WSyntaxError;
451
        if (token = tryConsume("&"))
577
            return new CallExpression(token, "operator" + token.text, [possiblePrefix]);
452
            return new MakePtrExpression(token, parsePossiblePrefix());
578
        } if (token = tryConsume("*")) {
453
        if (token = tryConsume("@"))
579
            let possiblePrefix = parsePossiblePrefix();
454
            return new MakeArrayRefExpression(token, parsePossiblePrefix());
580
            if (possiblePrefix instanceof WSyntaxError)
455
        if (token = tryConsume("!")) {
581
                return WSyntaxError;
582
            return new DereferenceExpression(token, possiblePrefix);
583
        } if (token = tryConsume("&")) {
584
            let possiblePrefix = parsePossiblePrefix();
585
            if (possiblePrefix instanceof WSyntaxError)
586
                return WSyntaxError;
587
            return new MakePtrExpression(token, possiblePrefix);
588
        } if (token = tryConsume("@")) {
589
            let possiblePrefix = parsePossiblePrefix();
590
            if (possiblePrefix instanceof WSyntaxError)
591
                return WSyntaxError;
592
            return new MakeArrayRefExpression(token, possiblePrefix);
593
        } if (token = tryConsume("!")) {
456
            let remainder = parsePossiblePrefix();
594
            let remainder = parsePossiblePrefix();
595
            if (remainder instanceof WSyntaxError)
596
                return remainder;
457
            return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [remainder]));
597
            return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [remainder]));
458
        }
598
        }
459
        return parsePossibleSuffix();
599
        return parsePossibleSuffix();
460
    }
600
    }
461
    
601
462
    function parsePossibleProduct()
602
    function parsePossibleProduct()
463
    {
603
    {
464
        return parseLeftOperatorCall(["*", "/", "%"], parsePossiblePrefix);
604
        return parseLeftOperatorCall(["*", "/", "%"], parsePossiblePrefix);
465
    }
605
    }
466
    
606
467
    function parsePossibleSum()
607
    function parsePossibleSum()
468
    {
608
    {
469
        return parseLeftOperatorCall(["+", "-"], parsePossibleProduct);
609
        return parseLeftOperatorCall(["+", "-"], parsePossibleProduct);
470
    }
610
    }
471
    
611
472
    function parsePossibleShift()
612
    function parsePossibleShift()
473
    {
613
    {
474
        return parseLeftOperatorCall(["<<", ">>"], parsePossibleSum);
614
        return parseLeftOperatorCall(["<<", ">>"], parsePossibleSum);
475
    }
615
    }
476
    
616
477
    function parsePossibleRelationalInequality()
617
    function parsePossibleRelationalInequality()
478
    {
618
    {
479
        return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift);
619
        return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift);
480
    }
620
    }
481
    
621
482
    function parsePossibleRelationalEquality()
622
    function parsePossibleRelationalEquality()
483
    {
623
    {
484
        return genericParseLeft(
624
        return genericParseLeft(
Lines 490-589 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec18
490
                return result;
630
                return result;
491
            });
631
            });
492
    }
632
    }
493
    
633
494
    function parsePossibleBitwiseAnd()
634
    function parsePossibleBitwiseAnd()
495
    {
635
    {
496
        return parseLeftOperatorCall(["&"], parsePossibleRelationalEquality);
636
        return parseLeftOperatorCall(["&"], parsePossibleRelationalEquality);
497
    }
637
    }
498
    
638
499
    function parsePossibleBitwiseXor()
639
    function parsePossibleBitwiseXor()
500
    {
640
    {
501
        return parseLeftOperatorCall(["^"], parsePossibleBitwiseAnd);
641
        return parseLeftOperatorCall(["^"], parsePossibleBitwiseAnd);
502
    }
642
    }
503
    
643
504
    function parsePossibleBitwiseOr()
644
    function parsePossibleBitwiseOr()
505
    {
645
    {
506
        return parseLeftOperatorCall(["|"], parsePossibleBitwiseXor);
646
        return parseLeftOperatorCall(["|"], parsePossibleBitwiseXor);
507
    }
647
    }
508
    
648
509
    function parseLeftLogicalExpression(texts, nextParser)
649
    function parseLeftLogicalExpression(texts, nextParser)
510
    {
650
    {
511
        return genericParseLeft(
651
        return genericParseLeft(
512
            texts, nextParser,
652
            texts, nextParser,
513
            (token, left, right) => new LogicalExpression(token, token.text, new CallExpression(left.origin, "bool", [left]), new CallExpression(right.origin, "bool", [right])));
653
            (token, left, right) => new LogicalExpression(token, token.text, new CallExpression(left.origin, "bool", [left]), new CallExpression(right.origin, "bool", [right])));
514
    }
654
    }
515
    
655
516
    function parsePossibleLogicalAnd()
656
    function parsePossibleLogicalAnd()
517
    {
657
    {
518
        return parseLeftLogicalExpression(["&&"], parsePossibleBitwiseOr);
658
        return parseLeftLogicalExpression(["&&"], parsePossibleBitwiseOr);
519
    }
659
    }
520
    
660
521
    function parsePossibleLogicalOr()
661
    function parsePossibleLogicalOr()
522
    {
662
    {
523
        return parseLeftLogicalExpression(["||"], parsePossibleLogicalAnd);
663
        return parseLeftLogicalExpression(["||"], parsePossibleLogicalAnd);
524
    }
664
    }
525
    
665
526
    function parsePossibleTernaryConditional()
666
    function parsePossibleTernaryConditional()
527
    {
667
    {
528
        let predicate = parsePossibleLogicalOr();
668
        let predicate = parsePossibleLogicalOr();
669
        if (predicate instanceof WSyntaxError)
670
            return predicate;
529
        let operator = tryConsume("?");
671
        let operator = tryConsume("?");
530
        if (!operator)
672
        if (!operator)
531
            return predicate;
673
            return predicate;
532
        let bodyExpression = parsePossibleAssignment();
674
        let bodyExpression = parsePossibleAssignment();
533
        consume(":");
675
        if (bodyExpression instanceof WSyntaxError)
676
            return bodyExpression;
677
        let maybeError = consume(":");
678
        if (maybeError instanceof WSyntaxError)
679
            return maybeError;
534
        let elseExpression = parsePossibleAssignment();
680
        let elseExpression = parsePossibleAssignment();
681
        if (elseExpression instanceof WSyntaxError)
682
            return elseExpression;
535
        return new TernaryExpression(operator, predicate, bodyExpression, elseExpression);
683
        return new TernaryExpression(operator, predicate, bodyExpression, elseExpression);
536
    }
684
    }
537
    
685
538
    function parsePossibleAssignment(mode)
686
    function parsePossibleAssignment(mode)
539
    {
687
    {
540
        let lhs = parsePossibleTernaryConditional();
688
        let lhs = parsePossibleTernaryConditional();
689
        if (lhs instanceof WSyntaxError)
690
            return lhs;
541
        let operator = tryConsume("=", "+=", "-=", "*=", "/=", "%=", "^=", "|=", "&=");
691
        let operator = tryConsume("=", "+=", "-=", "*=", "/=", "%=", "^=", "|=", "&=");
542
        if (!operator) {
692
        if (!operator) {
543
            if (mode == "required")
693
            if (mode == "required")
544
                lexer.fail("Expected assignment: " + lexer._text.substring(lexer._index));
694
                return fail("Expected assignment: " + lexer._text.substring(lexer._index));
545
            return lhs;
695
            return lhs;
546
        }
696
        }
547
        if (operator.text == "=")
697
        if (operator.text == "=") {
548
            return new Assignment(operator, lhs, parsePossibleAssignment());
698
            let innerAssignment = parsePossibleAssignment();
549
        return finishParsingPreIncrement(operator, lhs, parsePossibleAssignment());
699
            if (innerAssignment instanceof WSyntaxError)
700
                return innerAssignment;
701
            return new Assignment(operator, lhs, innerAssignment);
702
        }
703
        let innerAssignment = parsePossibleAssignment();
704
        if (innerAssignment instanceof WSyntaxError)
705
            return innerAssignment;
706
        return finishParsingPreIncrement(operator, lhs, innerAssignment);
550
    }
707
    }
551
    
708
552
    function parseAssignment()
709
    function parseAssignment()
553
    {
710
    {
554
        return parsePossibleAssignment("required");
711
        return parsePossibleAssignment("required");
555
    }
712
    }
556
    
713
557
    function parsePostIncrement()
714
    function parsePostIncrement()
558
    {
715
    {
559
        let left = parseSuffixOperator(parseTerm(), ".", "->", "[");
716
        let term = parseTerm();
717
        if (term instanceof WSyntaxError)
718
            return term;
719
        let left = parseSuffixOperator(term, ".", "->", "[");
720
        if (left instanceof WSyntaxError)
721
            return left;
560
        let token = consume("++", "--");
722
        let token = consume("++", "--");
723
        if (token instanceof WSyntaxError)
724
            return token;
561
        return finishParsingPostIncrement(token, left);
725
        return finishParsingPostIncrement(token, left);
562
    }
726
    }
563
    
727
564
    function parseEffectfulExpression()
728
    function parseEffectfulExpression()
565
    {
729
    {
566
        if (isCallExpression())
730
        if (isCallExpression())
567
            return parseCallExpression();
731
            return parseCallExpression();
568
        let preIncrement = lexer.backtrackingScope(parsePreIncrement);
732
        let preIncrement = backtrackingScope(parsePreIncrement);
569
        if (preIncrement)
733
        if (preIncrement)
570
            return preIncrement;
734
            return preIncrement;
571
        let postIncrement = lexer.backtrackingScope(parsePostIncrement);
735
        let postIncrement = backtrackingScope(parsePostIncrement);
572
        if (postIncrement)
736
        if (postIncrement)
573
            return postIncrement;
737
            return postIncrement;
574
        return parseAssignment();
738
        return parseAssignment();
575
    }
739
    }
576
    
740
577
    function genericParseCommaExpression(finalExpressionParser)
741
    function genericParseCommaExpression(finalExpressionParser)
578
    {
742
    {
579
        let list = [];
743
        let list = [];
580
        let origin = lexer.peek();
744
        let origin = lexer.peek();
581
        if (!origin)
745
        if (!origin)
582
            lexer.fail("Unexpected end of file");
746
            return fail("Unexpected end of file");
583
        for (;;) {
747
        for (;;) {
584
            let effectfulExpression = lexer.backtrackingScope(() => {
748
            let effectfulExpression = backtrackingScope(() => {
585
                parseEffectfulExpression();
749
                let effectfulExpression = parseEffectfulExpression();
586
                consume(",");
750
                if (effectfulExpression instanceof WSyntaxError)
751
                    return effectfulExpression;
752
                let maybeError = consume(",");
753
                if (maybeError instanceof WSyntaxError)
754
                    return maybeError;
755
                return effectfulExpression;
587
            });
756
            });
588
            if (!effectfulExpression) {
757
            if (!effectfulExpression) {
589
                let final = finalExpressionParser();
758
                let final = finalExpressionParser();
Lines 598-686 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec19
598
            return list[0];
767
            return list[0];
599
        return new CommaExpression(origin, list);
768
        return new CommaExpression(origin, list);
600
    }
769
    }
601
    
770
602
    function parseCommaExpression()
771
    function parseCommaExpression()
603
    {
772
    {
604
        return genericParseCommaExpression(parsePossibleAssignment);
773
        return genericParseCommaExpression(parsePossibleAssignment);
605
    }
774
    }
606
    
775
607
    function parseExpression()
776
    function parseExpression()
608
    {
777
    {
609
        return parseCommaExpression();
778
        return parseCommaExpression();
610
    }
779
    }
611
    
780
612
    function parseEffectfulStatement()
781
    function parseEffectfulStatement()
613
    {
782
    {
614
        let result = genericParseCommaExpression(parseEffectfulExpression);
783
        let result = genericParseCommaExpression(parseEffectfulExpression);
615
        consume(";");
784
        if (result instanceof WSyntaxError)
785
            return result;
786
        let maybeError = consume(";");
787
        if (maybeError instanceof WSyntaxError)
788
            return maybeError;
616
        return result;
789
        return result;
617
    }
790
    }
618
    
791
619
    function parseReturn()
792
    function parseReturn()
620
    {
793
    {
621
        let origin = consume("return");
794
        let origin = consume("return");
795
        if (origin instanceof WSyntaxError)
796
            return origin;
622
        if (tryConsume(";"))
797
        if (tryConsume(";"))
623
            return new Return(origin, null);
798
            return new Return(origin, null);
624
        let expression = parseExpression();
799
        let expression = parseExpression();
625
        consume(";");
800
        if (expression instanceof WSyntaxError)
801
            return expression;
802
        let maybeError = consume(";");
803
        if (maybeError instanceof WSyntaxError)
804
            return maybeError;
626
        return new Return(origin, expression);
805
        return new Return(origin, expression);
627
    }
806
    }
628
    
807
629
    function parseBreak()
808
    function parseBreak()
630
    {
809
    {
631
        let origin = consume("break");
810
        let origin = consume("break");
632
        consume(";");
811
        if (origin instanceof WSyntaxError)
812
            return origin;
813
        let maybeError = consume(";");
814
        if (maybeError instanceof WSyntaxError)
815
            return maybeError;
633
        return new Break(origin);
816
        return new Break(origin);
634
    }
817
    }
635
    
818
636
    function parseContinue()
819
    function parseContinue()
637
    {
820
    {
638
        let origin = consume("continue");
821
        let origin = consume("continue");
639
        consume(";");
822
        if (origin instanceof WSyntaxError)
823
            return origin;
824
        let maybeError = consume(";");
825
        if (maybeError instanceof WSyntaxError)
826
            return maybeError;
640
        return new Continue(origin);
827
        return new Continue(origin);
641
    }
828
    }
642
829
643
    function parseIfStatement()
830
    function parseIfStatement()
644
    {
831
    {
645
        let origin = consume("if");
832
        let origin = consume("if");
646
        consume("(");
833
        if (origin instanceof WSyntaxError)
834
            return origin;
835
        let maybeError = consume("(");
836
        if (maybeError instanceof WSyntaxError)
837
            return maybeError;
647
        let conditional = parseExpression();
838
        let conditional = parseExpression();
648
        consume(")");
839
        if (conditional instanceof WSyntaxError)
840
            return conditional;
841
        maybeError = consume(")");
842
        if (maybeError instanceof WSyntaxError)
843
            return maybeError;
649
        let body = parseStatement();
844
        let body = parseStatement();
845
        if (body instanceof WSyntaxError)
846
            return body;
650
        let elseBody;
847
        let elseBody;
651
        if (tryConsume("else"))
848
        if (tryConsume("else")) {
652
            elseBody = parseStatement();
849
            elseBody = parseStatement();
850
            if (elseBody instanceof WSyntaxError)
851
                return elseBody;
852
        }
653
        return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [conditional]), body, elseBody);
853
        return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [conditional]), body, elseBody);
654
    }
854
    }
655
855
656
    function parseWhile()
856
    function parseWhile()
657
    {
857
    {
658
        let origin = consume("while");
858
        let origin = consume("while");
659
        consume("(");
859
        if (origin instanceof WSyntaxError)
860
            return origin;
861
        let maybeError = consume("(");
862
        if (maybeError instanceof WSyntaxError)
863
            return maybeError;
660
        let conditional = parseExpression();
864
        let conditional = parseExpression();
661
        consume(")");
865
        if (conditional instanceof WSyntaxError)
866
            return conditional;
867
        maybeError = consume(")");
868
        if (maybeError instanceof WSyntaxError)
869
            return maybeError;
662
        let body = parseStatement();
870
        let body = parseStatement();
871
        if (body instanceof WSyntaxError)
872
            return body;
663
        return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [conditional]), body);
873
        return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [conditional]), body);
664
    }
874
    }
665
875
666
    function parseFor()
876
    function parseFor()
667
    {
877
    {
668
        let origin = consume("for");
878
        let origin = consume("for");
669
        consume("(");
879
        if (origin instanceof WSyntaxError)
880
            return origin;
881
        let maybeError = consume("(");
882
        if (maybeError instanceof WSyntaxError)
883
            return maybeError;
670
        let initialization;
884
        let initialization;
671
        if (tryConsume(";"))
885
        if (tryConsume(";"))
672
            initialization = undefined;
886
            initialization = undefined;
673
        else {
887
        else {
674
            initialization = lexer.backtrackingScope(parseVariableDecls);
888
            initialization = backtrackingScope(parseVariableDecls);
675
            if (!initialization)
889
            if (!initialization) {
676
                initialization = parseEffectfulStatement();
890
                initialization = parseEffectfulStatement();
891
                if (initialization instanceof WSyntaxError)
892
                    return initialization;
893
            }
677
        }
894
        }
678
        let condition = tryConsume(";");
895
        let condition = tryConsume(";");
679
        if (condition)
896
        if (condition)
680
            condition = undefined;
897
            condition = undefined;
681
        else {
898
        else {
682
            condition = parseExpression();
899
            condition = parseExpression();
683
            consume(";");
900
            if (condition instanceof WSyntaxError)
901
                return condition;
902
            maybeError = consume(";");
903
            if (maybeError instanceof WSyntaxError)
904
                return maybeError;
684
            condition = new CallExpression(condition.origin, "bool", [condition]);
905
            condition = new CallExpression(condition.origin, "bool", [condition]);
685
        }
906
        }
686
        let increment;
907
        let increment;
Lines 688-746 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec20
688
            increment = undefined;
909
            increment = undefined;
689
        else {
910
        else {
690
            increment = parseExpression();
911
            increment = parseExpression();
691
            consume(")");
912
            if (increment instanceof WSyntaxError)
913
                return increment;
914
            maybeError = consume(")");
915
            if (maybeError instanceof WSyntaxError)
916
                return maybeError;
692
        }
917
        }
693
        let body = parseStatement();
918
        let body = parseStatement();
919
        if (body instanceof WSyntaxError)
920
            return body;
694
        return new ForLoop(origin, initialization, condition, increment, body);
921
        return new ForLoop(origin, initialization, condition, increment, body);
695
    }
922
    }
696
923
697
    function parseDo()
924
    function parseDo()
698
    {
925
    {
699
        let origin = consume("do");
926
        let origin = consume("do");
927
        if (origin instanceof WSyntaxError)
928
            return origin;
700
        let body = parseStatement();
929
        let body = parseStatement();
701
        consume("while");
930
        if (body instanceof WSyntaxError)
702
        consume("(");
931
            return body;
932
        let maybeError = consume("while");
933
        if (maybeError instanceof WSyntaxError)
934
            return maybeError;
935
        maybeError = consume("(");
936
        if (maybeError instanceof WSyntaxError)
937
            return maybeError;
703
        let conditional = parseExpression();
938
        let conditional = parseExpression();
704
        consume(")");
939
        if (conditional instanceof WSyntaxError)
940
            return conditional;
941
        maybeError = consume(")");
942
        if (maybeError instanceof WSyntaxError)
943
            return maybeError;
705
        return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [conditional]));
944
        return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [conditional]));
706
    }
945
    }
707
    
946
708
    function parseVariableDecls()
947
    function parseVariableDecls()
709
    {
948
    {
710
        let type = parseType();
949
        let type = parseType();
950
        if (type instanceof WSyntaxError)
951
            return type;
711
        let list = [];
952
        let list = [];
712
        do {
953
        do {
713
            let name = consumeKind("identifier");
954
            let name = consumeKind("identifier");
955
            if (name instanceof WSyntaxError)
956
                return name;
714
            let initializer = tryConsume("=") ? parseExpression() : null;
957
            let initializer = tryConsume("=") ? parseExpression() : null;
958
            if (initializer instanceof WSyntaxError)
959
                return initializer;
715
            list.push(new VariableDecl(name, name.text, type, initializer));
960
            list.push(new VariableDecl(name, name.text, type, initializer));
716
        } while (consume(",", ";").text == ",");
961
            let maybeError = consume(",", ";");
962
            if (maybeError instanceof WSyntaxError)
963
                return maybeError;
964
            if (maybeError.text != ",")
965
                break;
966
        } while (true);
717
        return new CommaExpression(type.origin, list);
967
        return new CommaExpression(type.origin, list);
718
    }
968
    }
719
    
969
720
    function parseSwitchCase()
970
    function parseSwitchCase()
721
    {
971
    {
722
        let token = consume("default", "case");
972
        let token = consume("default", "case");
973
        if (token instanceof WSyntaxError)
974
            return token;
723
        let value;
975
        let value;
724
        if (token.text == "case")
976
        if (token.text == "case") {
725
            value = parseConstexpr();
977
            value = parseConstexpr();
726
        consume(":");
978
            if (value instanceof WSyntaxError)
979
                return value;
980
        }
981
        let maybeError = consume(":");
982
        if (maybeError instanceof WSyntaxError)
983
            return maybeError;
727
        let body = parseBlockBody("}", "default", "case");
984
        let body = parseBlockBody("}", "default", "case");
985
        if (body instanceof WSyntaxError)
986
            return body;
728
        return new SwitchCase(token, value, body);
987
        return new SwitchCase(token, value, body);
729
    }
988
    }
730
    
989
731
    function parseSwitchStatement()
990
    function parseSwitchStatement()
732
    {
991
    {
733
        let origin = consume("switch");
992
        let origin = consume("switch");
734
        consume("(");
993
        if (origin instanceof WSyntaxError)
994
            return origin;
995
        let maybeError = consume("(");
996
        if (maybeError instanceof WSyntaxError)
997
            return maybeError;
735
        let value = parseExpression();
998
        let value = parseExpression();
736
        consume(")");
999
        if (value instanceof WSyntaxError)
737
        consume("{");
1000
            return value;
1001
        maybeError = consume(")");
1002
        if (maybeError instanceof WSyntaxError)
1003
            return maybeError;
1004
        maybeError = consume("{");
1005
        if (maybeError instanceof WSyntaxError)
1006
            return maybeError;
738
        let result = new SwitchStatement(origin, value);
1007
        let result = new SwitchStatement(origin, value);
739
        while (!tryConsume("}"))
1008
        while (!tryConsume("}")) {
740
            result.add(parseSwitchCase());
1009
            let switchCase = parseSwitchCase();
1010
            if (switchCase instanceof WSyntaxError)
1011
                return switchCase;
1012
            result.add(switchCase);
1013
        }
741
        return result;
1014
        return result;
742
    }
1015
    }
743
    
1016
744
    function parseStatement()
1017
    function parseStatement()
745
    {
1018
    {
746
        let token = lexer.peek();
1019
        let token = lexer.peek();
Lines 766-842 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec21
766
            return parseSwitchStatement();
1039
            return parseSwitchStatement();
767
        if (token.text == "trap") {
1040
        if (token.text == "trap") {
768
            let origin = consume("trap");
1041
            let origin = consume("trap");
1042
            if (origin instanceof WSyntaxError)
1043
                return origin;
769
            consume(";");
1044
            consume(";");
770
            return new TrapStatement(origin);
1045
            return new TrapStatement(origin);
771
        }
1046
        }
772
        if (token.text == "{")
1047
        if (token.text == "{")
773
            return parseBlock();
1048
            return parseBlock();
774
        let variableDecl = lexer.backtrackingScope(parseVariableDecls);
1049
        let variableDecl = backtrackingScope(parseVariableDecls);
775
        if (variableDecl)
1050
        if (variableDecl)
776
            return variableDecl;
1051
            return variableDecl;
777
        return parseEffectfulStatement();
1052
        return parseEffectfulStatement();
778
    }
1053
    }
779
    
1054
780
    function parseBlockBody(...terminators)
1055
    function parseBlockBody(...terminators)
781
    {
1056
    {
782
        let block = new Block(origin);
1057
        let block = new Block(origin);
783
        while (!test(...terminators)) {
1058
        while (!test(...terminators)) {
784
            let statement = parseStatement();
1059
            let statement = parseStatement();
1060
            if (statement instanceof WSyntaxError)
1061
                return statement;
785
            if (statement)
1062
            if (statement)
786
                block.add(statement);
1063
                block.add(statement);
787
        }
1064
        }
788
        return block;
1065
        return block;
789
    }
1066
    }
790
    
1067
791
    function parseBlock()
1068
    function parseBlock()
792
    {
1069
    {
793
        let origin = consume("{");
1070
        let origin = consume("{");
1071
        if (origin instanceof WSyntaxError)
1072
            return origin;
794
        let block = parseBlockBody("}");
1073
        let block = parseBlockBody("}");
795
        consume("}");
1074
        if (block instanceof WSyntaxError)
1075
            return block;
1076
        let maybeError = consume("}");
1077
        if (maybeError instanceof WSyntaxError)
1078
            return maybeError;
796
        return block;
1079
        return block;
797
    }
1080
    }
798
    
1081
799
    function parseParameter()
1082
    function parseParameter()
800
    {
1083
    {
801
        let type = parseType();
1084
        let type = parseType();
1085
        if (type instanceof WSyntaxError)
1086
            return type;
802
        let name = tryConsumeKind("identifier");
1087
        let name = tryConsumeKind("identifier");
803
        return new FuncParameter(type.origin, name ? name.text : null, type);
1088
        return new FuncParameter(type.origin, name ? name.text : null, type);
804
    }
1089
    }
805
    
1090
806
    function parseParameters()
1091
    function parseParameters()
807
    {
1092
    {
808
        consume("(");
1093
        let maybeError = consume("(");
1094
        if (maybeError instanceof WSyntaxError)
1095
            return maybeError;
809
        let parameters = [];
1096
        let parameters = [];
810
        while (!test(")")) {
1097
        while (!test(")")) {
811
            parameters.push(parseParameter());
1098
            let parameter = parseParameter();
1099
            if (parameter instanceof WSyntaxError)
1100
                return parameter;
1101
            parameters.push(parameter);
812
            if (!tryConsume(","))
1102
            if (!tryConsume(","))
813
                break;
1103
                break;
814
        }
1104
        }
815
        consume(")");
1105
        maybeError = consume(")");
1106
        if (maybeError instanceof WSyntaxError)
1107
            return maybeError;
816
        return parameters;
1108
        return parameters;
817
    }
1109
    }
818
    
1110
819
    function parseFuncName()
1111
    function parseFuncName()
820
    {
1112
    {
821
        if (tryConsume("operator")) {
1113
        if (tryConsume("operator")) {
822
            let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", ".", "~", "<<", ">>", "[");
1114
            let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", ".", "~", "<<", ">>", "[");
1115
            if (token instanceof WSyntaxError)
1116
                return token;
823
            if (token.text == "&") {
1117
            if (token.text == "&") {
824
                if (tryConsume("[")) {
1118
                if (tryConsume("[")) {
825
                    consume("]");
1119
                    let maybeError = consume("]");
1120
                    if (maybeError instanceof WSyntaxError)
1121
                        return maybeError;
826
                    return "operator&[]";
1122
                    return "operator&[]";
827
                }
1123
                }
828
                if (tryConsume("."))
1124
                if (tryConsume(".")) {
829
                    return "operator&." + consumeKind("identifier").text;
1125
                    let maybeError = consumeKind("identifier");
1126
                    if (maybeError instanceof WSyntaxError)
1127
                        return maybeError;
1128
                    return "operator&." + maybeError.text;
1129
                }
830
                return "operator&";
1130
                return "operator&";
831
            }
1131
            }
832
            if (token.text == ".") {
1132
            if (token.text == ".") {
833
                let result = "operator." + consumeKind("identifier").text;
1133
                let maybeError = consumeKind("identifier");
1134
                if (maybeError instanceof WSyntaxError)
1135
                    return maybeError;
1136
                let result = "operator." + maybeError.text;
834
                if (tryConsume("="))
1137
                if (tryConsume("="))
835
                    result += "=";
1138
                    result += "=";
836
                return result;
1139
                return result;
837
            }
1140
            }
838
            if (token.text == "[") {
1141
            if (token.text == "[") {
839
                consume("]");
1142
                let maybeError = consume("]");
1143
                if (maybeError instanceof WSyntaxError)
1144
                    return maybeError;
840
                let result = "operator[]";
1145
                let result = "operator[]";
841
                if (tryConsume("="))
1146
                if (tryConsume("="))
842
                    result += "=";
1147
                    result += "=";
Lines 844-850 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec22
844
            }
1149
            }
845
            return "operator" + token.text;
1150
            return "operator" + token.text;
846
        }
1151
        }
847
        return consumeKind("identifier").text;
1152
        let maybeError = consumeKind("identifier");
1153
        if (maybeError instanceof WSyntaxError)
1154
            return maybeError;
1155
        return maybeError.text;
848
    }
1156
    }
849
1157
850
    function parseFuncDecl()
1158
    function parseFuncDecl()
Lines 858-984 function parse(program, origin, originKind, lineNumberOffset, text) a/Tools/WebGPUShadingLanguageRI/Parse.js_sec23
858
        if (operatorToken) {
1166
        if (operatorToken) {
859
            origin = operatorToken;
1167
            origin = operatorToken;
860
            returnType = parseType();
1168
            returnType = parseType();
1169
            if (returnType instanceof WSyntaxError)
1170
                return returnType;
861
            name = "operator cast";
1171
            name = "operator cast";
862
            isCast = true;
1172
            isCast = true;
863
        } else {
1173
        } else {
864
            shaderType = tryConsume("vertex", "fragment");
1174
            shaderType = tryConsume("vertex", "fragment");
865
            returnType = parseType();
1175
            returnType = parseType();
1176
            if (returnType instanceof WSyntaxError)
1177
                return returnType;
866
            if (shaderType) {
1178
            if (shaderType) {
867
                origin = shaderType;
1179
                origin = shaderType;
868
                shaderType = shaderType.text;
1180
                shaderType = shaderType.text;
869
            } else
1181
            } else
870
                origin = returnType.origin;
1182
                origin = returnType.origin;
871
            name = parseFuncName();
1183
            name = parseFuncName();
1184
            if (name instanceof WSyntaxError)
1185
                return name;
872
            isCast = false;
1186
            isCast = false;
873
        }
1187
        }
874
        let parameters = parseParameters();
1188
        let parameters = parseParameters();
1189
        if (parameters instanceof WSyntaxError)
1190
            return parameters;
875
        return new Func(origin, name, returnType, parameters, isCast, shaderType);
1191
        return new Func(origin, name, returnType, parameters, isCast, shaderType);
876
    }
1192
    }
877
    
1193
878
    function parseFuncDef()
1194
    function parseFuncDef()
879
    {
1195
    {
880
        let func = parseFuncDecl();
1196
        let func = parseFuncDecl();
1197
        if (func instanceof WSyntaxError)
1198
            return func;
881
        let body = parseBlock();
1199
        let body = parseBlock();
1200
        if (body instanceof WSyntaxError)
1201
            return body;
882
        return new FuncDef(func.origin, func.name, func.returnType, func.parameters, body, func.isCast, func.shaderType);
1202
        return new FuncDef(func.origin, func.name, func.returnType, func.parameters, body, func.isCast, func.shaderType);
883
    }
1203
    }
884
    
1204
885
    function parseField()
1205
    function parseField()
886
    {
1206
    {
887
        let type = parseType();
1207
        let type = parseType();
1208
        if (type instanceof WSyntaxError)
1209
            return type;
888
        let name = consumeKind("identifier");
1210
        let name = consumeKind("identifier");
889
        consume(";");
1211
        if (name instanceof WSyntaxError)
1212
            return name;
1213
        let maybeError = consume(";");
1214
        if (maybeError instanceof WSyntaxError)
1215
            return maybeError;
890
        return new Field(name, name.text, type);
1216
        return new Field(name, name.text, type);
891
    }
1217
    }
892
    
1218
893
    function parseStructType()
1219
    function parseStructType()
894
    {
1220
    {
895
        let origin = consume("struct");
1221
        let origin = consume("struct");
896
        let name = consumeKind("identifier").text;
1222
        if (origin instanceof WSyntaxError)
897
        let result = new StructType(origin, name);
1223
            return origin;
898
        consume("{");
1224
        let name = consumeKind("identifier");
899
        while (!tryConsume("}"))
1225
        if (name instanceof WSyntaxError)
900
            result.add(parseField());
1226
            return name;
1227
        let result = new StructType(origin, name.text);
1228
        let maybeError = consume("{");
1229
        if (maybeError instanceof WSyntaxError)
1230
            return maybeError;
1231
        while (!tryConsume("}")) {
1232
            let field = parseField();
1233
            if (field instanceof WSyntaxError)
1234
                return field;
1235
            result.add(field);
1236
        }
901
        return result;
1237
        return result;
902
    }
1238
    }
903
    
1239
904
    function parseNativeFunc()
1240
    function parseNativeFunc()
905
    {
1241
    {
906
        let func = parseFuncDecl();
1242
        let func = parseFuncDecl();
907
        consume(";");
1243
        if (func instanceof WSyntaxError)
1244
            return func;
1245
        let maybeError = consume(";");
1246
        if (maybeError instanceof WSyntaxError)
1247
            return maybeError;
908
        return new NativeFunc(func.origin, func.name, func.returnType, func.parameters, func.isCast, func.shaderType);
1248
        return new NativeFunc(func.origin, func.name, func.returnType, func.parameters, func.isCast, func.shaderType);
909
    }
1249
    }
910
    
1250
911
    function parseNative()
1251
    function parseNative()
912
    {
1252
    {
913
        let origin = consume("native");
1253
        let origin = consume("native");
1254
        if (origin instanceof WSyntaxError)
1255
            return origin;
914
        if (tryConsume("typedef")) {
1256
        if (tryConsume("typedef")) {
915
            let name = consumeKind("identifier");
1257
            let name = consumeKind("identifier");
1258
            if (name instanceof WSyntaxError)
1259
                return name;
916
            let args = parseTypeArguments();
1260
            let args = parseTypeArguments();
917
            consume(";");
1261
            if (args instanceof WSyntaxError)
1262
                return args;
1263
            let maybeError = consume(";");
1264
            if (maybeError instanceof WSyntaxError)
1265
                return maybeError;
918
            return NativeType.create(origin, name.text, args);
1266
            return NativeType.create(origin, name.text, args);
919
        }
1267
        }
920
        return parseNativeFunc();
1268
        return parseNativeFunc();
921
    }
1269
    }
922
    
1270
923
    function parseRestrictedFuncDef()
1271
    function parseRestrictedFuncDef()
924
    {
1272
    {
925
        consume("restricted");
1273
        let maybeError = consume("restricted");
1274
        if (maybeError instanceof WSyntaxError)
1275
            return maybeError;
926
        let result;
1276
        let result;
927
        if (tryConsume("native"))
1277
        if (tryConsume("native")) {
928
            result = parseNativeFunc();
1278
            result = parseNativeFunc();
929
        else
1279
            if (result instanceof WSyntaxError)
1280
                return result;
1281
        } else {
930
            result = parseFuncDef();
1282
            result = parseFuncDef();
1283
            if (result instanceof WSyntaxError)
1284
                return result;
1285
        }
931
        result.isRestricted = true;
1286
        result.isRestricted = true;
932
        return result;
1287
        return result;
933
    }
1288
    }
934
    
1289
935
    function parseEnumMember()
1290
    function parseEnumMember()
936
    {
1291
    {
937
        let name = consumeKind("identifier");
1292
        let name = consumeKind("identifier");
1293
        if (name instanceof WSyntaxError)
1294
            return name;
938
        let value = null;
1295
        let value = null;
939
        if (tryConsume("="))
1296
        if (tryConsume("=")) {
940
            value = parseConstexpr();
1297
            value = parseConstexpr();
1298
            if (value instanceof WSyntaxError)
1299
                return value;
1300
        }
941
        return new EnumMember(name, name.text, value);
1301
        return new EnumMember(name, name.text, value);
942
    }
1302
    }
943
    
1303
944
    function parseEnumType()
1304
    function parseEnumType()
945
    {
1305
    {
946
        consume("enum");
1306
        let maybeError = consume("enum");
1307
        if (maybeError instanceof WSyntaxError)
1308
            return maybeError;
947
        let name = consumeKind("identifier");
1309
        let name = consumeKind("identifier");
1310
        if (name instanceof WSyntaxError)
1311
            return name;
948
        let baseType;
1312
        let baseType;
949
        if (tryConsume(":"))
1313
        if (tryConsume(":")) {
950
            baseType = parseType();
1314
            baseType = parseType();
951
        else
1315
            if (baseType instanceof WSyntaxError)
1316
                return baseType;
1317
        } else
952
            baseType = new TypeRef(name, "int");
1318
            baseType = new TypeRef(name, "int");
953
        consume("{");
1319
        maybeError = consume("{");
1320
        if (maybeError instanceof WSyntaxError)
1321
            return maybeError;
954
        let result = new EnumType(name, name.text, baseType);
1322
        let result = new EnumType(name, name.text, baseType);
955
        while (!test("}")) {
1323
        while (!test("}")) {
956
            result.add(parseEnumMember());
1324
            let enumMember = parseEnumMember();
1325
            if (enumMember instanceof WSyntaxError)
1326
                return enumMember;
1327
            result.add(enumMember);
957
            if (!tryConsume(","))
1328
            if (!tryConsume(","))
958
                break;
1329
                break;
959
        }
1330
        }
960
        consume("}");
1331
        maybeError = consume("}");
1332
        if (maybeError instanceof WSyntaxError)
1333
            return maybeError;
961
        return result;
1334
        return result;
962
    }
1335
    }
963
    
1336
964
    for (;;) {
1337
    for (;;) {
965
        let token = lexer.peek();
1338
        let token = lexer.peek();
966
        if (!token)
1339
        if (!token)
967
            return;
1340
            return;
968
        if (token.text == ";")
1341
        if (token.text == ";")
969
            lexer.next();
1342
            lexer.next();
970
        else if (token.text == "typedef")
1343
        else if (token.text == "typedef") {
971
            program.add(parseTypeDef());
1344
            let typeDef = parseTypeDef();
972
        else if (originKind == "native" && token.text == "native")
1345
            if (typeDef instanceof WSyntaxError)
973
            program.add(parseNative());
1346
                throw typeDef;
974
        else if (originKind == "native" && token.text == "restricted")
1347
            program.add(typeDef);
975
            program.add(parseRestrictedFuncDef());
1348
        } else if (originKind == "native" && token.text == "native") {
976
        else if (token.text == "struct")
1349
            let native = parseNative();
977
            program.add(parseStructType());
1350
            if (native instanceof WSyntaxError)
978
        else if (token.text == "enum")
1351
                throw native;
979
            program.add(parseEnumType());
1352
            program.add(native);
980
        else
1353
        } else if (originKind == "native" && token.text == "restricted") {
981
            program.add(parseFuncDef());
1354
            let restrictedFuncDef = parseRestrictedFuncDef();
1355
            if (restrictedFuncDef instanceof WSyntaxError)
1356
                throw restrictedFuncDef;
1357
            program.add(restrictedFuncDef);
1358
        } else if (token.text == "struct") {
1359
            let struct = parseStructType();
1360
            if (struct instanceof WSyntaxError)
1361
                throw struct;
1362
            program.add(struct);
1363
        } else if (token.text == "enum") {
1364
            let enumType = parseEnumType();
1365
            if (enumType instanceof WSyntaxError)
1366
                throw enumType;
1367
            program.add(enumType);
1368
        } else {
1369
            let funcDef = parseFuncDef();
1370
            if (funcDef instanceof WSyntaxError)
1371
                throw funcDef;
1372
            program.add(funcDef);
1373
        }
982
    }
1374
    }
983
}
1375
}
984
1376
- a/Tools/WebGPUShadingLanguageRI/SPIRV.html +1 lines
Lines 151-156 td { a/Tools/WebGPUShadingLanguageRI/SPIRV.html_sec1
151
    <script src="VariableRef.js"></script>
151
    <script src="VariableRef.js"></script>
152
    <script src="VectorType.js"></script>
152
    <script src="VectorType.js"></script>
153
    <script src="VisitingSet.js"></script>
153
    <script src="VisitingSet.js"></script>
154
    <script src="WLexicalError.js"></script>
154
    <script src="WSyntaxError.js"></script>
155
    <script src="WSyntaxError.js"></script>
155
    <script src="WTrapError.js"></script>
156
    <script src="WTrapError.js"></script>
156
    <script src="WTypeError.js"></script>
157
    <script src="WTypeError.js"></script>
- a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js -4 / +2 lines
Lines 773-780 let standardLibrary = (function() { a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js_sec1
773
            }
773
            }
774
            return result;
774
            return result;
775
        }
775
        }
776
        
776
777
        /*
778
        for (let type of [`bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
777
        for (let type of [`bool`, `uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
779
            for (let size of [2, 3, 4]) {
778
            for (let size of [2, 3, 4]) {
780
                for (let maxValue of [2, 3, 4]) {
779
                for (let maxValue of [2, 3, 4]) {
Lines 1889-1895 let standardLibrary = (function() { a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js_sec2
1889
            }
1888
            }
1890
        }
1889
        }
1891
        print();
1890
        print();
1892
        
1891
        /*
1893
        for (let type of [`uint`, `int`]) {
1892
        for (let type of [`uint`, `int`]) {
1894
            for (let functionName of [`Add`, `And`, `Exchange`, `Max`, `Min`, `Or`, `Xor`]) {
1893
            for (let functionName of [`Add`, `And`, `Exchange`, `Max`, `Min`, `Or`, `Xor`]) {
1895
                print(`native void Interlocked${functionName}(thread atomic_${type}*, ${type}, thread ${type}*);`);
1894
                print(`native void Interlocked${functionName}(thread atomic_${type}*, ${type}, thread ${type}*);`);
Lines 1898-1904 let standardLibrary = (function() { a/Tools/WebGPUShadingLanguageRI/StandardLibrary.js_sec3
1898
        }
1897
        }
1899
        print();
1898
        print();
1900
        */
1899
        */
1901
1902
        for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
1900
        for (let type of [`uchar`, `ushort`, `uint`, `char`, `short`, `int`, `half`, `float`]) {
1903
            for (let length of [``, `2`, `3`, `4`]) {
1901
            for (let length of [``, `2`, `3`, `4`]) {
1904
                print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location);`);
1902
                print(`native ${type}${length} Sample(Texture1D<${type}${length}>, sampler, float location);`);
- a/Tools/WebGPUShadingLanguageRI/Test.html +1 lines
Lines 145-150 a/Tools/WebGPUShadingLanguageRI/Test.html_sec1
145
<script src="VariableRef.js"></script>
145
<script src="VariableRef.js"></script>
146
<script src="VectorType.js"></script>
146
<script src="VectorType.js"></script>
147
<script src="VisitingSet.js"></script>
147
<script src="VisitingSet.js"></script>
148
<script src="WLexicalError.js"></script>
148
<script src="WSyntaxError.js"></script>
149
<script src="WSyntaxError.js"></script>
149
<script src="WTrapError.js"></script>
150
<script src="WTrapError.js"></script>
150
<script src="WTypeError.js"></script>
151
<script src="WTypeError.js"></script>
- a/Tools/WebGPUShadingLanguageRI/Test.js -18 / +17 lines
Lines 329-351 tests = new Proxy({}, { a/Tools/WebGPUShadingLanguageRI/Test.js_sec1
329
    }
329
    }
330
});
330
});
331
331
332
tests.commentParsing = function() {
333
    let program = doPrep(`
334
        /* this comment
335
        runs over multiple lines */
336
        bool foo() { return true; }
337
    `);
338
    checkBool(program, callFunction(program, "foo", []), true);
339
340
    checkFail(
341
        () => doPrep(`
342
        /* this comment
343
        runs over multiple lines
344
        bool foo() { return true; }
345
        `),
346
        (e) => e instanceof WSyntaxError);
347
}
348
349
tests.ternaryExpression = function() {
332
tests.ternaryExpression = function() {
350
    let program = doPrep(`
333
    let program = doPrep(`
351
        int foo(int x)
334
        int foo(int x)
Lines 7626-7631 tests.textureGather = function() { a/Tools/WebGPUShadingLanguageRI/Test.js_sec2
7626
    // FIXME: Gather other components
7609
    // FIXME: Gather other components
7627
}
7610
}
7628
7611
7612
tests.commentParsing = function() {
7613
    let program = doPrep(`
7614
        /* this comment
7615
        runs over multiple lines */
7616
        bool foo() { return true; }
7617
    `);
7618
    checkBool(program, callFunction(program, "foo", []), true);
7619
7620
    checkFail(
7621
        () => doPrep(`
7622
        /* this comment
7623
        runs over multiple lines
7624
        bool foo() { return true; }
7625
        `),
7626
        (e) => e instanceof WLexicalError);
7627
}
7628
7629
okToTest = true;
7629
okToTest = true;
7630
7630
7631
let testFilter = /.*/; // run everything by default
7631
let testFilter = /.*/; // run everything by default
Lines 7683-7686 if (!this.window) { a/Tools/WebGPUShadingLanguageRI/Test.js_sec3
7683
    for (let _ of doTest(testFilter)) { }
7683
    for (let _ of doTest(testFilter)) { }
7684
}
7684
}
7685
7685
7686
- a/Tools/WebGPUShadingLanguageRI/WLexicalError.js +35 lines
Line 0 a/Tools/WebGPUShadingLanguageRI/WLexicalError.js_sec1
1
/*
2
 * Copyright (C) 2018 Apple Inc. All rights reserved.
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24
 */
25
"use strict";
26
27
class WLexicalError extends Error {
28
    constructor(originString, message)
29
    {
30
        super("Lexical error at " + originString + ": " + message);
31
        this.originString = originString;
32
        this.syntaxErrorMessage = message;
33
    }
34
}
35
- a/Tools/WebGPUShadingLanguageRI/WSyntaxError.js -2 / +2 lines
Lines 24-33 a/Tools/WebGPUShadingLanguageRI/WSyntaxError.js_sec1
24
 */
24
 */
25
"use strict";
25
"use strict";
26
26
27
class WSyntaxError extends Error {
27
class WSyntaxError {
28
    constructor(originString, message)
28
    constructor(originString, message)
29
    {
29
    {
30
        super("Syntax error at " + originString + ": " + message);
30
        this.payload = "Syntax error at " + originString + ": " + message;
31
        this.originString = originString;
31
        this.originString = originString;
32
        this.syntaxErrorMessage = message;
32
        this.syntaxErrorMessage = message;
33
    }
33
    }
- a/Tools/WebGPUShadingLanguageRI/index.html +1 lines
Lines 145-150 a/Tools/WebGPUShadingLanguageRI/index.html_sec1
145
<script src="VariableRef.js"></script>
145
<script src="VariableRef.js"></script>
146
<script src="VectorType.js"></script>
146
<script src="VectorType.js"></script>
147
<script src="VisitingSet.js"></script>
147
<script src="VisitingSet.js"></script>
148
<script src="WLexicalError.js"></script>
148
<script src="WSyntaxError.js"></script>
149
<script src="WSyntaxError.js"></script>
149
<script src="WTrapError.js"></script>
150
<script src="WTrapError.js"></script>
150
<script src="WTypeError.js"></script>
151
<script src="WTypeError.js"></script>

Return to Bug 189014