[WHLSL] Call expressions shouldn't have type arguments
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / Parse.js
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 function parse(program, origin, originKind, lineNumberOffset, text)
28 {
29     let lexer = new Lexer(origin, originKind, lineNumberOffset, text);
30     
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
33     // identifier, if we assume that any expression can be a standalone statement.
34     //
35     //     x;
36     //     x <binop> y;
37     //     x < y;
38     //     x < y > z;
39     //     x = y;
40     //     x.f = y;
41     //     \exp = y;
42     //     x[42] = y;
43     //     x();
44     //     x<y>();
45     //     x y;
46     //     x<y> z;
47     //     device x[] y;
48     //     x[42] y;
49     //     device x^ y;
50     //     thread x^^ y;
51     //     x^thread^thread y;
52     //     x^device^thread y;
53     //
54     // This has two problem areas:
55     //
56     //     - x<y>z can parse two different ways (as (x < y) > z or x<y> z).
57     //     - x[42] could become either an assignment or a variable declaration.
58     //     - x<y> could become either an assignment or a variable declaration.
59     //
60     // We solve the first problem by forbidding expressions as statements. The lack of function
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
63     // backtracking. In all other respects, this is a simple recursive descent parser.
64     
65     function genericConsume(callback, explanation)
66     {
67         let token = lexer.next();
68         if (!token)
69             lexer.fail("Unexpected end of file");
70         if (!callback(token))
71             lexer.fail("Unexpected token: " + token.text + "; expected: " + explanation);
72         return token;
73     }
74     
75     function consume(...texts)
76     {
77         return genericConsume(token => texts.includes(token.text), texts);
78     }
79     
80     function consumeKind(kind)
81     {
82         return genericConsume(token => token.kind == kind, kind);
83     }
84     
85     function assertNext(...texts)
86     {
87         lexer.push(consume(...texts));
88     }
89     
90     function genericTest(callback)
91     {
92         let token = lexer.peek();
93         if (token && callback(token))
94             return token;
95         return null;
96     }
97     
98     function test(...texts)
99     {
100         return genericTest(token => texts.includes(token.text));
101     }
102     
103     function testKind(kind)
104     {
105         return genericTest(token => token.kind == kind);
106     }
107     
108     function tryConsume(...texts)
109     {
110         let result = test(...texts);
111         if (result)
112             lexer.next();
113         return result;
114     }
115     
116     function tryConsumeKind(kind)
117     {
118         let result = testKind(kind);
119         if (result)
120             lexer.next();
121         return result;
122     }
123     
124     function consumeEndOfTypeArgs()
125     {
126         let rightShift = tryConsume(">>");
127         if (rightShift)
128             lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">"));
129         else
130             consume(">");
131     }
132     
133     function parseTerm()
134     {
135         let token;
136         if (token = tryConsume("null"))
137             return new NullLiteral(token);
138         if (token = tryConsumeKind("identifier"))
139             return new VariableRef(token, token.text);
140         if (token = tryConsumeKind("intLiteral")) {
141             let intVersion = (+token.text) | 0;
142             if ("" + intVersion !== token.text)
143                 lexer.fail("Integer literal is not an integer: " + token.text);
144             return new IntLiteral(token, intVersion);
145         }
146         if (token = tryConsumeKind("uintLiteral")) {
147             let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0;
148             if (uintVersion + "u" !== token.text)
149                 lexer.fail("Integer literal is not 32-bit unsigned integer: " + token.text);
150             return new UintLiteral(token, uintVersion);
151         }
152         if ((token = tryConsumeKind("intHexLiteral"))
153             || (token = tryConsumeKind("uintHexLiteral"))) {
154             let hexString = token.text.substr(2);
155             if (token.kind == "uintHexLiteral")
156                 hexString = hexString.substr(0, hexString.length - 1);
157             if (!hexString.length)
158                 throw new Error("Bad hex literal: " + token);
159             let intVersion = parseInt(hexString, 16);
160             if (token.kind == "intHexLiteral")
161                 intVersion = intVersion | 0;
162             else
163                 intVersion = intVersion >>> 0;
164             if (intVersion.toString(16) !== hexString)
165                 lexer.fail("Hex integer literal is not an integer: " + token.text);
166             if (token.kind == "intHexLiteral")
167                 return new IntLiteral(token, intVersion);
168             return new UintLiteral(token, intVersion >>> 0);
169         }
170         if (token = tryConsumeKind("floatLiteral")) {
171             let text = token.text;
172             let f = token.text.endsWith("f");
173             if (f)
174                 text = text.substring(0, text.length - 1);
175             let value = parseFloat(text);
176             return new FloatLiteral(token, Math.fround(value));
177         }
178         if (token = tryConsume("true", "false"))
179             return new BoolLiteral(token, token.text == "true");
180         // FIXME: Need support for other literals too.
181         consume("(");
182         let result = parseExpression();
183         consume(")");
184         return result;
185     }
186     
187     function parseConstexpr()
188     {
189         let token;
190         if (token = tryConsume("-"))
191             return new CallExpression(token, "operator" + token.text, [parseTerm()]);
192         let left = parseTerm();
193         if (token = tryConsume("."))
194             left = new DotExpression(token, left, consumeKind("identifier").text);
195         return left;
196     }
197     
198     function parseTypeArguments()
199     {
200         if (!test("<"))
201             return [];
202
203         let result = [];
204         consume("<");
205         while (!test(">")) {
206             // It's possible for a constexpr or type can syntactically overlap in the single
207             // identifier case. Let's consider the possibilities:
208             //
209             //     T          could be type or constexpr
210             //     T[]        only type
211             //     T[42]      only type (constexpr cannot do indexing)
212             //     42         only constexpr
213             //
214             // 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
216             // constexpr, and we can figure out in the checker which it is.
217             let typeRef = lexer.backtrackingScope(() => {
218                 let result = consumeKind("identifier");
219                 assertNext(",", ">", ">>");
220                 return new TypeRef(result, result.text);
221             });
222             if (typeRef)
223                 result.push(typeRef);
224             else {
225                 let constexpr = lexer.backtrackingScope(() => {
226                     let result = parseConstexpr();
227                     assertNext(",", ">", ">>");
228                     return result;
229                 });
230                 if (constexpr)
231                     result.push(constexpr);
232                 else
233                     result.push(parseType());
234             }
235             if (!tryConsume(","))
236                 break;
237         }
238         consumeEndOfTypeArgs();
239         return result;
240     }
241     
242     function parseType()
243     {
244         let token;
245         let addressSpace;
246         let addressSpaceConsumed = false;
247         if (token = tryConsume(...addressSpaces))
248             addressSpace = token.text;
249         
250         let name = consumeKind("identifier");
251         let typeArguments = parseTypeArguments();
252         let type = new TypeRef(name, name.text, typeArguments);
253         
254         function getAddressSpace()
255         {
256             addressSpaceConsumed = true;
257             if (addressSpace)
258                 return addressSpace;
259             return consume(...addressSpaces).text;
260         }
261         
262         while (token = tryConsume("*", "[")) {
263             if (token.text == "*") {
264                 type = new PtrType(token, getAddressSpace(), type);
265                 continue;
266             }
267             
268             if (tryConsume("]")) {
269                 type = new ArrayRefType(token, getAddressSpace(), type);
270                 continue;
271             }
272             
273             type = new ArrayType(token, type, parseConstexpr());
274             consume("]");
275         }
276         
277         if (addressSpace && !addressSpaceConsumed)
278             lexer.fail("Address space specified for type that does not need address space");
279         
280         return type;
281     }
282     
283     function parseTypeDef()
284     {
285         let origin = consume("typedef");
286         let name = consumeKind("identifier").text;
287         consume("=");
288         let type = parseType();
289         consume(";");
290         return new TypeDef(origin, name, type);
291     }
292     
293     function genericParseLeft(texts, nextParser, constructor)
294     {
295         let left = nextParser();
296         let token;
297         while (token = tryConsume(...texts))
298             left = constructor(token, left, nextParser());
299         return left;
300     }
301     
302     function parseLeftOperatorCall(texts, nextParser)
303     {
304         return genericParseLeft(
305             texts, nextParser,
306             (token, left, right) =>
307                 new CallExpression(token, "operator" + token.text, [left, right]));
308     }
309     
310     function parseCallExpression()
311     {
312         let parseArguments = function(origin, callName) {
313             let argumentList = [];
314             while (!test(")")) {
315                 let argument = parsePossibleAssignment();
316                 argumentList.push(argument);
317                 if (!tryConsume(","))
318                     break;
319             }
320             consume(")");
321             return new CallExpression(origin, callName, argumentList);
322         }
323
324         let name = lexer.backtrackingScope(() => {
325             let name = consumeKind("identifier");
326             consume("(");
327             return name;
328         });
329
330         if (name) {
331             let result = parseArguments(name, name.text);
332             return result;
333         } else {
334             let returnType = parseType();
335             consume("(");
336             let result = parseArguments(returnType.origin, "operator cast");
337             result.setCastData(returnType);
338             return result;
339         }
340     }
341     
342     function isCallExpression()
343     {
344         return lexer.testScope(() => {
345                 consumeKind("identifier");
346                 consume("(");
347             }) || lexer.testScope(() => {
348                 parseType();
349                 consume("(");
350             });
351     }
352     
353     function emitIncrement(token, old, extraArg)
354     {
355         let args = [old];
356         if (extraArg)
357             args.push(extraArg);
358         
359         let name = "operator" + token.text;
360         if (/=$/.test(name))
361             name = RegExp.leftContext;
362         
363         if (name == "operator")
364             throw new Error("Invalid name: " + name);
365         
366         return new CallExpression(token, name, args);
367     }
368     
369     function finishParsingPostIncrement(token, left)
370     {
371         let readModifyWrite = new ReadModifyWriteExpression(token, left);
372         readModifyWrite.newValueExp = emitIncrement(token, readModifyWrite.oldValueRef());
373         readModifyWrite.resultExp = readModifyWrite.oldValueRef();
374         return readModifyWrite;
375     }
376     
377     function parseSuffixOperator(left, acceptableOperators)
378     {
379         let token;
380         while (token = tryConsume(...acceptableOperators)) {
381             switch (token.text) {
382             case "++":
383             case "--":
384                 return finishParsingPostIncrement(token, left);
385             case ".":
386             case "->":
387                 if (token.text == "->")
388                     left = new DereferenceExpression(token, left);
389                 left = new DotExpression(token, left, consumeKind("identifier").text);
390                 break;
391             case "[": {
392                 let index = parseExpression();
393                 consume("]");
394                 left = new IndexExpression(token, left, index);
395                 break;
396             }
397             default:
398                 throw new Error("Bad token: " + token);
399             }
400         }
401         return left;
402     }
403     
404     function parsePossibleSuffix()
405     {
406         let acceptableOperators = ["++", "--", ".", "->", "["];
407         let limitedOperators = [".", "->", "["];
408         let left;
409         if (isCallExpression()) {
410             left = parseCallExpression();
411             acceptableOperators = limitedOperators;
412         } else
413             left = parseTerm();
414         
415         return parseSuffixOperator(left, acceptableOperators);
416     }
417     
418     function finishParsingPreIncrement(token, left, extraArg)
419     {
420         let readModifyWrite = new ReadModifyWriteExpression(token, left);
421         readModifyWrite.newValueExp = emitIncrement(token, readModifyWrite.oldValueRef(), extraArg);
422         readModifyWrite.resultExp = readModifyWrite.newValueRef();
423         return readModifyWrite;
424     }
425     
426     function parsePreIncrement()
427     {
428         let token = consume("++", "--");
429         let left = parsePossiblePrefix();
430         return finishParsingPreIncrement(token, left);
431     }
432     
433     function parsePossiblePrefix()
434     {
435         let token;
436         if (test("++", "--"))
437             return parsePreIncrement();
438         if (token = tryConsume("+", "-", "~"))
439             return new CallExpression(token, "operator" + token.text, [parsePossiblePrefix()]);
440         if (token = tryConsume("*"))
441             return new DereferenceExpression(token, parsePossiblePrefix());
442         if (token = tryConsume("&"))
443             return new MakePtrExpression(token, parsePossiblePrefix());
444         if (token = tryConsume("@"))
445             return new MakeArrayRefExpression(token, parsePossiblePrefix());
446         if (token = tryConsume("!")) {
447             let remainder = parsePossiblePrefix();
448             return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [remainder]));
449         }
450         return parsePossibleSuffix();
451     }
452     
453     function parsePossibleProduct()
454     {
455         return parseLeftOperatorCall(["*", "/", "%"], parsePossiblePrefix);
456     }
457     
458     function parsePossibleSum()
459     {
460         return parseLeftOperatorCall(["+", "-"], parsePossibleProduct);
461     }
462     
463     function parsePossibleShift()
464     {
465         return parseLeftOperatorCall(["<<", ">>"], parsePossibleSum);
466     }
467     
468     function parsePossibleRelationalInequality()
469     {
470         return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift);
471     }
472     
473     function parsePossibleRelationalEquality()
474     {
475         return genericParseLeft(
476             ["==", "!="], parsePossibleRelationalInequality,
477             (token, left, right) => {
478                 let result = new CallExpression(token, "operator==", [left, right]);
479                 if (token.text == "!=")
480                     result = new LogicalNot(token, result);
481                 return result;
482             });
483     }
484     
485     function parsePossibleBitwiseAnd()
486     {
487         return parseLeftOperatorCall(["&"], parsePossibleRelationalEquality);
488     }
489     
490     function parsePossibleBitwiseXor()
491     {
492         return parseLeftOperatorCall(["^"], parsePossibleBitwiseAnd);
493     }
494     
495     function parsePossibleBitwiseOr()
496     {
497         return parseLeftOperatorCall(["|"], parsePossibleBitwiseXor);
498     }
499     
500     function parseLeftLogicalExpression(texts, nextParser)
501     {
502         return genericParseLeft(
503             texts, nextParser,
504             (token, left, right) => new LogicalExpression(token, token.text, new CallExpression(left.origin, "bool", [left]), new CallExpression(right.origin, "bool", [right])));
505     }
506     
507     function parsePossibleLogicalAnd()
508     {
509         return parseLeftLogicalExpression(["&&"], parsePossibleBitwiseOr);
510     }
511     
512     function parsePossibleLogicalOr()
513     {
514         return parseLeftLogicalExpression(["||"], parsePossibleLogicalAnd);
515     }
516     
517     function parsePossibleTernaryConditional()
518     {
519         let predicate = parsePossibleLogicalOr();
520         let operator = tryConsume("?");
521         if (!operator)
522             return predicate;
523         return new TernaryExpression(operator, predicate, parsePossibleAssignment(), parsePossibleAssignment());
524     }
525     
526     function parsePossibleAssignment(mode)
527     {
528         let lhs = parsePossibleTernaryConditional();
529         let operator = tryConsume("=", "+=", "-=", "*=", "/=", "%=", "^=", "|=", "&=");
530         if (!operator) {
531             if (mode == "required")
532                 lexer.fail("Expected assignment: " + lexer._text.substring(lexer._index));
533             return lhs;
534         }
535         if (operator.text == "=")
536             return new Assignment(operator, lhs, parsePossibleAssignment());
537         return finishParsingPreIncrement(operator, lhs, parsePossibleAssignment());
538     }
539     
540     function parseAssignment()
541     {
542         return parsePossibleAssignment("required");
543     }
544     
545     function parsePostIncrement()
546     {
547         let left = parseSuffixOperator(parseTerm(), ".", "->", "[");
548         let token = consume("++", "--");
549         return finishParsingPostIncrement(token, left);
550     }
551     
552     function parseEffectfulExpression()
553     {
554         if (isCallExpression())
555             return parseCallExpression();
556         let preIncrement = lexer.backtrackingScope(parsePreIncrement);
557         if (preIncrement)
558             return preIncrement;
559         let postIncrement = lexer.backtrackingScope(parsePostIncrement);
560         if (postIncrement)
561             return postIncrement;
562         return parseAssignment();
563     }
564     
565     function genericParseCommaExpression(finalExpressionParser)
566     {
567         let list = [];
568         let origin = lexer.peek();
569         if (!origin)
570             lexer.fail("Unexpected end of file");
571         for (;;) {
572             let effectfulExpression = lexer.backtrackingScope(() => {
573                 parseEffectfulExpression();
574                 consume(",");
575             });
576             if (!effectfulExpression) {
577                 let final = finalExpressionParser();
578                 list.push(final);
579                 break;
580             }
581             list.push(effectfulExpression);
582         }
583         if (!list.length)
584             throw new Error("Length should never be zero");
585         if (list.length == 1)
586             return list[0];
587         return new CommaExpression(origin, list);
588     }
589     
590     function parseCommaExpression()
591     {
592         return genericParseCommaExpression(parsePossibleAssignment);
593     }
594     
595     function parseExpression()
596     {
597         return parseCommaExpression();
598     }
599     
600     function parseEffectfulStatement()
601     {
602         let result = genericParseCommaExpression(parseEffectfulExpression);
603         consume(";");
604         return result;
605     }
606     
607     function parseReturn()
608     {
609         let origin = consume("return");
610         if (tryConsume(";"))
611             return new Return(origin, null);
612         let expression = parseExpression();
613         consume(";");
614         return new Return(origin, expression);
615     }
616     
617     function parseBreak()
618     {
619         let origin = consume("break");
620         consume(";");
621         return new Break(origin);
622     }
623     
624     function parseContinue()
625     {
626         let origin = consume("continue");
627         consume(";");
628         return new Continue(origin);
629     }
630
631     function parseIfStatement()
632     {
633         let origin = consume("if");
634         consume("(");
635         let conditional = parseExpression();
636         consume(")");
637         let body = parseStatement();
638         let elseBody;
639         if (tryConsume("else"))
640             elseBody = parseStatement();
641         return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [conditional]), body, elseBody);
642     }
643
644     function parseWhile()
645     {
646         let origin = consume("while");
647         consume("(");
648         let conditional = parseExpression();
649         consume(")");
650         let body = parseStatement();
651         return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [conditional]), body);
652     }
653
654     function parseFor()
655     {
656         let origin = consume("for");
657         consume("(");
658         let initialization;
659         if (tryConsume(";"))
660             initialization = undefined;
661         else {
662             initialization = lexer.backtrackingScope(parseVariableDecls);
663             if (!initialization)
664                 initialization = parseEffectfulStatement();
665         }
666         let condition = tryConsume(";");
667         if (condition)
668             condition = undefined;
669         else {
670             condition = parseExpression();
671             consume(";");
672             condition = new CallExpression(condition.origin, "bool", [condition]);
673         }
674         let increment;
675         if (tryConsume(")"))
676             increment = undefined;
677         else {
678             increment = parseExpression();
679             consume(")");
680         }
681         let body = parseStatement();
682         return new ForLoop(origin, initialization, condition, increment, body);
683     }
684
685     function parseDo()
686     {
687         let origin = consume("do");
688         let body = parseStatement();
689         consume("while");
690         consume("(");
691         let conditional = parseExpression();
692         consume(")");
693         return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [conditional]));
694     }
695     
696     function parseVariableDecls()
697     {
698         let type = parseType();
699         let list = [];
700         do {
701             let name = consumeKind("identifier");
702             let initializer = tryConsume("=") ? parseExpression() : null;
703             list.push(new VariableDecl(name, name.text, type, initializer));
704         } while (consume(",", ";").text == ",");
705         return new CommaExpression(type.origin, list);
706     }
707     
708     function parseSwitchCase()
709     {
710         let token = consume("default", "case");
711         let value;
712         if (token.text == "case")
713             value = parseConstexpr();
714         consume(":");
715         let body = parseBlockBody("}", "default", "case");
716         return new SwitchCase(token, value, body);
717     }
718     
719     function parseSwitchStatement()
720     {
721         let origin = consume("switch");
722         consume("(");
723         let value = parseExpression();
724         consume(")");
725         consume("{");
726         let result = new SwitchStatement(origin, value);
727         while (!tryConsume("}"))
728             result.add(parseSwitchCase());
729         return result;
730     }
731     
732     function parseStatement()
733     {
734         let token = lexer.peek();
735         if (token.text == ";") {
736             lexer.next();
737             return null;
738         }
739         if (token.text == "return")
740             return parseReturn();
741         if (token.text == "break")
742             return parseBreak();
743         if (token.text == "continue")
744             return parseContinue();
745         if (token.text == "while")
746             return parseWhile();
747         if (token.text == "do")
748             return parseDo();
749         if (token.text == "for")
750             return parseFor();
751         if (token.text == "if")
752             return parseIfStatement();
753         if (token.text == "switch")
754             return parseSwitchStatement();
755         if (token.text == "trap") {
756             let origin = consume("trap");
757             consume(";");
758             return new TrapStatement(origin);
759         }
760         if (token.text == "{")
761             return parseBlock();
762         let variableDecl = lexer.backtrackingScope(parseVariableDecls);
763         if (variableDecl)
764             return variableDecl;
765         return parseEffectfulStatement();
766     }
767     
768     function parseBlockBody(...terminators)
769     {
770         let block = new Block(origin);
771         while (!test(...terminators)) {
772             let statement = parseStatement();
773             if (statement)
774                 block.add(statement);
775         }
776         return block;
777     }
778     
779     function parseBlock()
780     {
781         let origin = consume("{");
782         let block = parseBlockBody("}");
783         consume("}");
784         return block;
785     }
786     
787     function parseParameter()
788     {
789         let type = parseType();
790         let name = tryConsumeKind("identifier");
791         return new FuncParameter(type.origin, name ? name.text : null, type);
792     }
793     
794     function parseParameters()
795     {
796         consume("(");
797         let parameters = [];
798         while (!test(")")) {
799             parameters.push(parseParameter());
800             if (!tryConsume(","))
801                 break;
802         }
803         consume(")");
804         return parameters;
805     }
806     
807     function parseFuncName()
808     {
809         if (tryConsume("operator")) {
810             let token = consume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", ".", "~", "<<", ">>", "[");
811             if (token.text == "&") {
812                 if (tryConsume("[")) {
813                     consume("]");
814                     return "operator&[]";
815                 }
816                 if (tryConsume("."))
817                     return "operator&." + consumeKind("identifier").text;
818                 return "operator&";
819             }
820             if (token.text == ".") {
821                 let result = "operator." + consumeKind("identifier").text;
822                 if (tryConsume("="))
823                     result += "=";
824                 return result;
825             }
826             if (token.text == "[") {
827                 consume("]");
828                 let result = "operator[]";
829                 if (tryConsume("="))
830                     result += "=";
831                 return result;
832             }
833             return "operator" + token.text;
834         }
835         return consumeKind("identifier").text;
836     }
837
838     function parseFuncDecl()
839     {
840         let origin;
841         let returnType;
842         let name;
843         let isCast;
844         let shaderType;
845         let operatorToken = tryConsume("operator");
846         if (operatorToken) {
847             origin = operatorToken;
848             returnType = parseType();
849             name = "operator cast";
850             isCast = true;
851         } else {
852             shaderType = tryConsume("vertex", "fragment");
853             returnType = parseType();
854             if (shaderType) {
855                 origin = shaderType;
856                 shaderType = shaderType.text;
857             } else
858                 origin = returnType.origin;
859             name = parseFuncName();
860             isCast = false;
861         }
862         let parameters = parseParameters();
863         return new Func(origin, name, returnType, parameters, isCast, shaderType);
864     }
865     
866     function parseFuncDef()
867     {
868         let func = parseFuncDecl();
869         let body = parseBlock();
870         return new FuncDef(func.origin, func.name, func.returnType, func.parameters, body, func.isCast, func.shaderType);
871     }
872     
873     function parseField()
874     {
875         let type = parseType();
876         let name = consumeKind("identifier");
877         consume(";");
878         return new Field(name, name.text, type);
879     }
880     
881     function parseStructType()
882     {
883         let origin = consume("struct");
884         let name = consumeKind("identifier").text;
885         let result = new StructType(origin, name);
886         consume("{");
887         while (!tryConsume("}"))
888             result.add(parseField());
889         return result;
890     }
891     
892     function parseNativeFunc()
893     {
894         let func = parseFuncDecl();
895         consume(";");
896         return new NativeFunc(func.origin, func.name, func.returnType, func.parameters, func.isCast, func.shaderType);
897     }
898     
899     function parseNative()
900     {
901         let origin = consume("native");
902         if (tryConsume("typedef")) {
903             let name = consumeKind("identifier");
904             let args = parseTypeArguments();
905             consume(";");
906             return NativeType.create(origin, name.text, args);
907         }
908         return parseNativeFunc();
909     }
910     
911     function parseRestrictedFuncDef()
912     {
913         consume("restricted");
914         let result;
915         if (tryConsume("native"))
916             result = parseNativeFunc();
917         else
918             result = parseFuncDef();
919         result.isRestricted = true;
920         return result;
921     }
922     
923     function parseEnumMember()
924     {
925         let name = consumeKind("identifier");
926         let value = null;
927         if (tryConsume("="))
928             value = parseConstexpr();
929         return new EnumMember(name, name.text, value);
930     }
931     
932     function parseEnumType()
933     {
934         consume("enum");
935         let name = consumeKind("identifier");
936         let baseType;
937         if (tryConsume(":"))
938             baseType = parseType();
939         else
940             baseType = new TypeRef(name, "int");
941         consume("{");
942         let result = new EnumType(name, name.text, baseType);
943         while (!test("}")) {
944             result.add(parseEnumMember());
945             if (!tryConsume(","))
946                 break;
947         }
948         consume("}");
949         return result;
950     }
951     
952     for (;;) {
953         let token = lexer.peek();
954         if (!token)
955             return;
956         if (token.text == ";")
957             lexer.next();
958         else if (token.text == "typedef")
959             program.add(parseTypeDef());
960         else if (originKind == "native" && token.text == "native")
961             program.add(parseNative());
962         else if (originKind == "native" && token.text == "restricted")
963             program.add(parseRestrictedFuncDef());
964         else if (token.text == "struct")
965             program.add(parseStructType());
966         else if (token.text == "enum")
967             program.add(parseEnumType());
968         else
969             program.add(parseFuncDef());
970     }
971 }
972