WSL should support ++, --, +=, and all of those things
[WebKit-https.git] / Tools / WebGPUShadingLanguageRI / Parse.js
1 /*
2  * Copyright (C) 2017 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 parseProtocolRef()
125     {
126         let protocolToken = consumeKind("identifier");
127         return new ProtocolRef(protocolToken, protocolToken.text);
128     }
129     
130     function consumeEndOfTypeArgs()
131     {
132         let rightShift = tryConsume(">>");
133         if (rightShift)
134             lexer.push(new LexerToken(lexer, rightShift, rightShift.index, rightShift.kind, ">"));
135         else
136             consume(">");
137     }
138     
139     function parseTypeParameters()
140     {
141         if (!test("<"))
142             return [];
143         
144         let result = [];
145         consume("<");
146         while (!test(">")) {
147             let constexpr = lexer.backtrackingScope(() => {
148                 let type = parseType();
149                 let name = consumeKind("identifier");
150                 assertNext(",", ">", ">>");
151                 return new ConstexprTypeParameter(type.origin, name.text, type);
152             });
153             if (constexpr)
154                 result.push(constexpr);
155             else {
156                 let name = consumeKind("identifier");
157                 let protocol = tryConsume(":") ? parseProtocolRef() : null;
158                 result.push(new TypeVariable(name, name.text, protocol));
159             }
160             if (!tryConsume(","))
161                 break;
162         }
163         consumeEndOfTypeArgs();
164         return result;
165     }
166     
167     function parseTerm()
168     {
169         let token;
170         if (token = tryConsume("null"))
171             return new NullLiteral(token);
172         if (token = tryConsumeKind("identifier"))
173             return new VariableRef(token, token.text);
174         if (token = tryConsumeKind("intLiteral")) {
175             let intVersion = Math.floor(+token.text);
176             if ("" + intVersion !== token.text)
177                 lexer.fail("Integer literal is not an integer");
178             return new IntLiteral(token, intVersion);
179         }
180         if (token = tryConsumeKind("uintLiteral")) {
181             let uintVersion = token.text.substr(0, token.text.length - 1) >>> 0;
182             if (uintVersion + "u" !== token.text)
183                 lexer.fail("Integer literal is not 32-bit unsigned integer");
184             return new UintLiteral(token, uintVersion);
185         }
186         if (token = tryConsumeKind("doubleLiteral"))
187             return new DoubleLiteral(token, +token.text);
188         if (token = tryConsume("true", "false"))
189             return new BoolLiteral(token, token.text == "true");
190         // FIXME: Need support for float literals and probably other literals too.
191         consume("(");
192         let result = parseExpression();
193         consume(")");
194         return result;
195     }
196     
197     function parseConstexpr()
198     {
199         return parseTerm();
200     }
201     
202     function parseTypeArguments()
203     {
204         if (!test("<"))
205             return [];
206         
207         let result = [];
208         consume("<");
209         while (!test(">")) {
210             // It's possible for a constexpr or type can syntactically overlap in the single
211             // identifier case. Let's consider the possibilities:
212             //
213             //     T          could be type or constexpr
214             //     T[]        only type
215             //     T[42]      only type (constexpr cannot do indexing)
216             //     42         only constexpr
217             //
218             // In the future we'll allow constexprs to do more things, and then we'll still have
219             // the problem that something of the form T[1][2][3]... can either be a type or a
220             // constexpr, and we can figure out in the checker which it is.
221             let typeOrVariableRef = lexer.backtrackingScope(() => {
222                 let result = consumeKind("identifier");
223                 assertNext(",", ">", ">>");
224                 return new TypeOrVariableRef(result, result.text);
225             });
226             if (typeOrVariableRef)
227                 result.push(typeOrVariableRef);
228             else {
229                 let constexpr = lexer.backtrackingScope(() => {
230                     let result = parseConstexpr();
231                     assertNext(",", ">", ">>");
232                     return result;
233                 });
234                 if (constexpr)
235                     result.push(constexpr);
236                 else
237                     result.push(parseType());
238             }
239             if (!tryConsume(","))
240                 break;
241         }
242         consumeEndOfTypeArgs();
243         return result;
244     }
245     
246     function parseType()
247     {
248         let token;
249         let addressSpace;
250         let addressSpaceConsumed = false;
251         if (token = tryConsume(...addressSpaces))
252             addressSpace = token.text;
253         
254         let name = consumeKind("identifier");
255         let typeArguments = parseTypeArguments();
256         let type = new TypeRef(name, name.text, typeArguments);
257         
258         function getAddressSpace()
259         {
260             addressSpaceConsumed = true;
261             if (addressSpace)
262                 return addressSpace;
263             addressSpace = consume(...addressSpaces);
264             return addressSpace;
265         }
266         
267         while (token = tryConsume("^", "[")) {
268             if (token.text == "^") {
269                 type = new PtrType(token, getAddressSpace(), type);
270                 continue;
271             }
272             
273             if (tryConsume("]")) {
274                 type = new ArrayRefType(token, getAddressSpace(), type);
275                 continue;
276             }
277             
278             type = new ArrayType(token, type, parseConstexpr());
279             consume("]");
280         }
281         
282         if (addressSpace && !addressSpaceConsumed)
283             lexer.fail("Address space specified for type that does not need address space");
284         
285         return type;
286     }
287     
288     function parseTypeDef()
289     {
290         let origin = consume("typedef");
291         let name = consumeKind("identifier").text;
292         let typeParameters = parseTypeParameters();
293         consume("=");
294         let type = parseType();
295         consume(";");
296         return new TypeDef(origin, name, typeParameters, type);
297     }
298     
299     function genericParseLeft(texts, nextParser, constructor)
300     {
301         let left = nextParser();
302         let token;
303         while (token = tryConsume(...texts))
304             left = constructor(token, left, nextParser());
305         return left;
306     }
307     
308     function parseLeftOperatorCall(texts, nextParser)
309     {
310         return genericParseLeft(
311             texts, nextParser,
312             (token, left, right) =>
313                 new CallExpression(token, "operator" + token.text, [], [left, right]));
314     }
315     
316     function parseCallExpression()
317     {
318         let name = consumeKind("identifier");
319         let typeArguments = parseTypeArguments();
320         consume("(");
321         let argumentList = [];
322         while (!test(")")) {
323             argumentList.push(parseExpression());
324             if (!tryConsume(","))
325                 break;
326         }
327         consume(")");
328         return new CallExpression(name, name.text, typeArguments, argumentList);
329     }
330     
331     function isCallExpression()
332     {
333         return lexer.testScope(() => {
334             consumeKind("identifier");
335             parseTypeArguments();
336             consume("(");
337         });
338     }
339     
340     function emitIncrement(token, ptr, extraArg)
341     {
342         let args = [new DereferenceExpression(token, VariableRef.wrap(ptr))];
343         if (extraArg)
344             args.push(extraArg);
345         
346         let name = "operator" + token.text;
347         if (/=$/.test(name))
348             name = RegExp.leftContext;
349         
350         if (name == "operator")
351             throw new Error("Invalid name: " + name);
352         
353         return new Assignment(
354             token,
355             new DereferenceExpression(token, VariableRef.wrap(ptr)),
356             new CallExpression(token, name, [], args));
357     }
358     
359     function finishParsingPostIncrement(token, left)
360     {
361         let ptr = new LetExpression(token);
362         ptr.argument = new MakePtrExpression(token, left);
363         
364         let oldValue = new LetExpression(token);
365         oldValue.argument = new DereferenceExpression(token, VariableRef.wrap(ptr));
366         
367         ptr.body = oldValue;
368         
369         oldValue.body = new CommaExpression(token, [
370             emitIncrement(token, ptr),
371             VariableRef.wrap(oldValue)
372         ]);
373         return ptr;
374     }
375     
376     function parsePossibleSuffix()
377     {
378         if (isCallExpression())
379             return parseCallExpression();
380         
381         let left = parseTerm();
382         let token;
383         while (token = tryConsume("++", "--", ".", "->", "[")) {
384             switch (token.text) {
385             case "++":
386             case "--":
387                 left = finishParsingPostIncrement(token, left);
388                 break;
389             case ".":
390             case "->":
391                 if (token.text == "->")
392                     left = new DereferenceExpression(token, left);
393                 left = new DotExpression(token, left, consumeKind("identifier").text);
394                 break;
395             case "[": {
396                 let index = parseExpression();
397                 consume("]");
398                 left = new DereferenceExpression(
399                     token,
400                     new CallExpression(token, "operator&[]", [], [left, index]));
401                 break;
402             }
403             default:
404                 throw new Error("Bad token: " + token);
405             }
406         }
407         return left;
408     }
409     
410     function finishParsingPreIncrement(token, left, extraArg)
411     {
412         let ptr = new LetExpression(token);
413         ptr.argument = new MakePtrExpression(token, left);
414         ptr.body = new CommaExpression(token, [
415             emitIncrement(token, ptr, extraArg),
416             new DereferenceExpression(token, VariableRef.wrap(ptr))
417         ]);
418         return ptr;
419     }
420     
421     function parsePreIncrement()
422     {
423         let token = consume("++", "--");
424         let left = parsePossiblePrefix();
425         return finishParsingPreIncrement(token, left);
426     }
427     
428     function parsePossiblePrefix()
429     {
430         let token;
431         if (test("++", "--"))
432             return parsePreIncrement();
433         if (token = tryConsume("+", "-", "~"))
434             return new CallExpression(token, "operator" + token.text, [], [parsePossiblePrefix()]);
435         if (token = tryConsume("^"))
436             return new DereferenceExpression(token, parsePossiblePrefix());
437         if (token = tryConsume("&"))
438             return new MakePtrExpression(token, parsePossiblePrefix());
439         if (token = tryConsume("@"))
440             return new MakeArrayRefExpression(token, parsePossiblePrefix());
441         if (token = tryConsume("!")) {
442             let remainder = parsePossiblePrefix();
443             return new LogicalNot(token, new CallExpression(remainder.origin, "bool", [], [remainder]));
444         }
445         return parsePossibleSuffix();
446     }
447     
448     function parsePossibleProduct()
449     {
450         return parseLeftOperatorCall(["*", "/", "%"], parsePossiblePrefix);
451     }
452     
453     function parsePossibleSum()
454     {
455         return parseLeftOperatorCall(["+", "-"], parsePossibleProduct);
456     }
457     
458     function parsePossibleShift()
459     {
460         return parseLeftOperatorCall(["<<", ">>"], parsePossibleSum);
461     }
462     
463     function parsePossibleRelationalInequality()
464     {
465         return parseLeftOperatorCall(["<", ">", "<=", ">="], parsePossibleShift);
466     }
467     
468     function parsePossibleRelationalEquality()
469     {
470         return genericParseLeft(
471             ["==", "!="], parsePossibleRelationalInequality,
472             (token, left, right) => {
473                 let result = new CallExpression(token, "operator==", [], [left, right]);
474                 if (token.text == "!=")
475                     result = new LogicalNot(token, result);
476                 return result;
477             });
478     }
479     
480     function parsePossibleBitwiseAnd()
481     {
482         return parseLeftOperatorCall(["&"], parsePossibleRelationalEquality);
483     }
484     
485     function parsePossibleBitwiseXor()
486     {
487         return parseLeftOperatorCall(["^"], parsePossibleBitwiseAnd);
488     }
489     
490     function parsePossibleBitwiseOr()
491     {
492         return parseLeftOperatorCall(["|"], parsePossibleBitwiseXor);
493     }
494     
495     function parseLeftLogicalExpression(texts, nextParser)
496     {
497         return genericParseLeft(
498             texts, nextParser,
499             (token, left, right) => new LogicalExpression(token, token.text, left, right));
500     }
501     
502     function parsePossibleLogicalAnd()
503     {
504         return parseLeftLogicalExpression(["&&"], parsePossibleBitwiseOr);
505     }
506     
507     function parsePossibleLogicalOr()
508     {
509         return parseLeftLogicalExpression(["||"], parsePossibleLogicalAnd);
510     }
511     
512     function parsePossibleTernaryConditional()
513     {
514         let predicate = parsePossibleLogicalOr();
515         let operator = tryConsume("?");
516         if (!operator)
517             return predicate;
518         return new TernaryExpression(operator, predicate, parsePossibleAssignment(), parsePossibleAssignment());
519     }
520     
521     function parsePossibleAssignment(mode)
522     {
523         let lhs = parsePossibleTernaryConditional();
524         let operator = tryConsume("=", "+=", "-=", "*=", "/=", "%=", "^=", "|=", "&=");
525         if (!operator) {
526             if (mode == "required")
527                 lexer.fail("Expected assignment");
528             return lhs;
529         }
530         if (operator.text == "=")
531             return new Assignment(operator, lhs, parsePossibleAssignment());
532         return finishParsingPreIncrement(operator, lhs, parsePossibleAssignment());
533     }
534     
535     function parseAssignment()
536     {
537         return parsePossibleAssignment("required");
538     }
539     
540     function parsePostIncrement()
541     {
542         let left = parseTerm();
543         let token = consume("++", "--");
544         return finishParsingPostIncrement(token, left);
545     }
546     
547     function parseEffectfulExpression()
548     {
549         if (isCallExpression())
550             return parseCallExpression();
551         let preIncrement = lexer.backtrackingScope(parsePreIncrement);
552         if (preIncrement)
553             return preIncrement;
554         let postIncrement = lexer.backtrackingScope(parsePostIncrement);
555         if (postIncrement)
556             return postIncrement;
557         return parseAssignment();
558     }
559     
560     function genericParseCommaExpression(finalExpressionParser)
561     {
562         let list = [];
563         let origin = lexer.peek();
564         if (!origin)
565             lexer.fail("Unexpected end of file");
566         for (;;) {
567             let effectfulExpression = lexer.backtrackingScope(() => {
568                 parseEffectfulExpression();
569                 consume(",");
570             });
571             if (!effectfulExpression) {
572                 let final = finalExpressionParser();
573                 list.push(final);
574                 break;
575             }
576             list.push(effectfulExpression);
577         }
578         return new CommaExpression(origin, list);
579     }
580     
581     function parseCommaExpression()
582     {
583         return genericParseCommaExpression(parsePossibleAssignment);
584     }
585     
586     function parseExpression()
587     {
588         return parseCommaExpression();
589     }
590     
591     function parseEffectfulStatement()
592     {
593         let result = genericParseCommaExpression(parseEffectfulExpression);
594         consume(";");
595         return result;
596     }
597     
598     function parseReturn()
599     {
600         let origin = consume("return");
601         if (tryConsume(";"))
602             return new Return(origin, null);
603         let expression = parseExpression();
604         consume(";");
605         return new Return(origin, expression);
606     }
607     
608     function parseBreak()
609     {
610         let origin = consume("break");
611         consume(";");
612         return new Break(origin);
613     }
614     
615     function parseContinue()
616     {
617         let origin = consume("continue");
618         consume(";");
619         return new Continue(origin);
620     }
621
622     function parseIfStatement()
623     {
624         let origin = consume("if");
625         consume("(");
626         let conditional = parseExpression();
627         consume(")");
628         let body = parseStatement();
629         let elseBody;
630         if (tryConsume("else"))
631             elseBody = parseStatement();
632         return new IfStatement(origin, new CallExpression(conditional.origin, "bool", [], [conditional]), body, elseBody);
633     }
634
635     function parseWhile()
636     {
637         let origin = consume("while");
638         consume("(");
639         let conditional = parseExpression();
640         consume(")");
641         let body = parseStatement();
642         return new WhileLoop(origin, new CallExpression(conditional.origin, "bool", [], [conditional]), body);
643     }
644
645     function parseFor()
646     {
647         let origin = consume("for");
648         consume("(");
649         let initialization;
650         if (tryConsume(";"))
651             initialization = undefined;
652         else {
653             initialization = lexer.backtrackingScope(parseVariableDecls);
654             if (!initialization)
655                 initialization = parseEffectfulStatement();
656         }
657         let condition = tryConsume(";");
658         if (condition)
659             condition = undefined;
660         else {
661             condition = parseExpression();
662             consume(";");
663             condition = new CallExpression(condition.origin, "bool", [], [condition]);
664         }
665         let increment;
666         if (tryConsume(")"))
667             increment = undefined;
668         else {
669             increment = parseExpression();
670             consume(")");
671         }
672         let body = parseStatement();
673         return new ForLoop(origin, initialization, condition, increment, body);
674     }
675
676     function parseDo()
677     {
678         let origin = consume("do");
679         let body = parseStatement();
680         consume("while");
681         consume("(");
682         let conditional = parseExpression();
683         consume(")");
684         return new DoWhileLoop(origin, body, new CallExpression(conditional.origin, "bool", [], [conditional]));
685     }
686     
687     function parseVariableDecls()
688     {
689         let type = parseType();
690         let list = [];
691         do {
692             let name = consumeKind("identifier");
693             let initializer = tryConsume("=") ? parseExpression() : null;
694             list.push(new VariableDecl(name, name.text, type, initializer));
695         } while (consume(",", ";").text == ",");
696         return new CommaExpression(type.origin, list);
697     }
698     
699     function parseStatement()
700     {
701         let token = lexer.peek();
702         if (token.text == ";") {
703             lexer.next();
704             return null;
705         }
706         if (token.text == "return")
707             return parseReturn();
708         if (token.text == "break")
709             return parseBreak();
710         if (token.text == "continue")
711             return parseContinue();
712         if (token.text == "while")
713             return parseWhile();
714         if (token.text == "do")
715             return parseDo();
716         if (token.text == "for")
717             return parseFor();
718         if (token.text == "if")
719             return parseIfStatement();
720         if (token.text == "{")
721             return parseBlock();
722         let variableDecl = lexer.backtrackingScope(parseVariableDecls);
723         if (variableDecl)
724             return variableDecl;
725         return parseEffectfulStatement();
726     }
727     
728     function parseBlock()
729     {
730         let origin = consume("{");
731         let block = new Block(origin);
732         while (!test("}")) {
733             let statement = parseStatement();
734             if (statement)
735                 block.add(statement);
736         }
737         consume("}");
738         return block;
739     }
740     
741     function parseParameter()
742     {
743         let type = parseType();
744         let name = tryConsumeKind("identifier");
745         return new FuncParameter(type.origin, name ? name.text : null, type);
746     }
747     
748     function parseParameters()
749     {
750         consume("(");
751         let parameters = [];
752         while (!test(")")) {
753             parameters.push(parseParameter());
754             if (!tryConsume(","))
755                 break;
756         }
757         consume(")");
758         return parameters;
759     }
760     
761     function parseFuncName()
762     {
763         if (tryConsume("operator")) {
764             let token = tryConsume("+", "-", "*", "/", "%", "^", "&", "|", "<", ">", "<=", ">=", "==", "++", "--", "&");
765             if (token) {
766                 if (token.text != "&" || !tryConsume("["))
767                     return "operator" + token.text;
768                 consume("]");
769                 return "operator&[]";
770             }
771             let name = consumeKind("identifier");
772             return "operator " + name;
773         }
774         return consumeKind("identifier").text;
775     }
776
777     function parseFuncDecl()
778     {
779         let origin;
780         let returnType;
781         let name;
782         let typeParameters;
783         let isCast;
784         let operatorToken = tryConsume("operator");
785         if (operatorToken) {
786             origin = operatorToken;
787             typeParameters = parseTypeParameters();
788             returnType = parseType();
789             name = "operator cast";
790             isCast = true;
791         } else {
792             returnType = parseType();
793             origin = returnType.origin;
794             name = parseFuncName();
795             typeParameters = parseTypeParameters();
796             isCast = false;
797         }
798         let parameters = parseParameters();
799         return new Func(origin, name, returnType, typeParameters, parameters, isCast);
800     }
801
802     function parseProtocolFuncDecl()
803     {
804         let func = parseFuncDecl();
805         return new ProtocolFuncDecl(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
806     }
807     
808     function parseFuncDef()
809     {
810         let func = parseFuncDecl();
811         let body = parseBlock();
812         return new FuncDef(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, body, func.isCast);
813     }
814     
815     function parseProtocolDecl()
816     {
817         let origin = consume("protocol");
818         let name = consumeKind("identifier").text;
819         let result = new ProtocolDecl(origin, name);
820         if (tryConsume(":")) {
821             while (!test("{")) {
822                 result.addExtends(parseProtocolRef());
823                 if (!tryConsume(","))
824                     break;
825             }
826         }
827         consume("{");
828         while (!tryConsume("}")) {
829             result.add(parseProtocolFuncDecl());
830             consume(";");
831         }
832         return result;
833     }
834     
835     function parseField()
836     {
837         let type = parseType();
838         let name = consumeKind("identifier");
839         consume(";");
840         return new Field(name, name.text, type);
841     }
842     
843     function parseStructType()
844     {
845         let origin = consume("struct");
846         let name = consumeKind("identifier").text;
847         let typeParameters = parseTypeParameters();
848         let result = new StructType(origin, name, typeParameters);
849         consume("{");
850         while (!tryConsume("}"))
851             result.add(parseField());
852         return result;
853     }
854     
855     function parseNativeFunc()
856     {
857         let func = parseFuncDecl();
858         consume(";");
859         return new NativeFunc(func.origin, func.name, func.returnType, func.typeParameters, func.parameters, func.isCast);
860     }
861     
862     function parseNative()
863     {
864         let origin = consume("native");
865         let isType = lexer.backtrackingScope(() => {
866             if (tryConsume("typedef"))
867                 return "normal";
868             consume("primitive");
869             consume("typedef");
870             return "primitive";
871         });
872         if (isType) {
873             let name = consumeKind("identifier");
874             let parameters = parseTypeParameters();
875             consume(";");
876             return new NativeType(origin, name.text, isType == "primitive", parameters);
877         }
878         return parseNativeFunc();
879     }
880     
881     function parseRestrictedFuncDef()
882     {
883         consume("restricted");
884         let result;
885         if (tryConsume("native"))
886             result = parseNativeFunc();
887         else
888             result = parseFuncDef();
889         result.isRestricted = true;
890         return result;
891     }
892     
893     for (;;) {
894         let token = lexer.peek();
895         if (!token)
896             return;
897         if (token.text == ";")
898             lexer.next();
899         else if (token.text == "typedef")
900             program.add(parseTypeDef());
901         else if (originKind == "native" && token.text == "native")
902             program.add(parseNative());
903         else if (originKind == "native" && token.text == "restricted")
904             program.add(parseRestrictedFuncDef());
905         else if (token.text == "struct")
906             program.add(parseStructType());
907         else if (token.text == "enum")
908             program.add(parseEnum());
909         else if (token.text == "protocol")
910             program.add(parseProtocolDecl());
911         else
912             program.add(parseFuncDef());
913     }
914 }
915