Include log level in log messages
[delight/core.git] / dmd2 / parse.c
blob17fc25c78382cf040961ba1403e75dd8519bdd23
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2008 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, September 2007
17 #include <stdio.h>
18 #include <assert.h>
20 #include "mem.h"
21 #include "lexer.h"
22 #include "parse.h"
23 #include "init.h"
24 #include "attrib.h"
25 #include "cond.h"
26 #include "mtype.h"
27 #include "template.h"
28 #include "staticassert.h"
29 #include "expression.h"
30 #include "statement.h"
31 #include "module.h"
32 #include "dsymbol.h"
33 #include "import.h"
34 #include "declaration.h"
35 #include "aggregate.h"
36 #include "enum.h"
37 #include "id.h"
38 #include "version.h"
39 #ifdef IN_GCC
40 #include "d-dmd-gcc.h"
41 #endif
43 // How multiple declarations are parsed.
44 // If 1, treat as C.
45 // If 0, treat:
46 // int *p, i;
47 // as:
48 // int* p;
49 // int* i;
50 #define CDECLSYNTAX 0
52 // Support C cast syntax:
53 // (type)(expression)
54 #define CCASTSYNTAX 1
56 // Support postfix C array declarations, such as
57 // int a[3][4];
58 #define CARRAYDECL 1
61 Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
62 : Lexer(module, base, 0, length, doDocComment, 0)
64 //printf("Parser::Parser()\n");
65 md = NULL;
66 linkage = LINKd;
67 endloc = 0;
68 inBrackets = 0;
69 //nextToken(); // start up the scanner
72 Array *Parser::parseModule()
74 Array *decldefs;
76 // ModuleDeclation leads off
77 if (token.value == TOKmodule)
79 unsigned char *comment = token.blockComment;
81 nextToken();
82 if (token.value != TOKidentifier)
83 { error("Identifier expected following module");
84 goto Lerr;
86 else
88 Array *a = NULL;
89 Identifier *id;
91 id = token.ident;
92 while (nextToken() == TOKdot)
94 if (!a)
95 a = new Array();
96 a->push(id);
97 nextToken();
98 if (token.value != TOKidentifier)
99 { error("Identifier expected following package");
100 goto Lerr;
102 id = token.ident;
105 md = new ModuleDeclaration(a, id);
107 if (token.value != TOKsemicolon)
108 error("';' expected following module declaration instead of %s", token.toChars());
109 nextToken();
110 addComment(mod, comment);
114 decldefs = parseDeclDefs(0);
115 if (token.value != TOKeof)
116 { error("unrecognized declaration");
117 goto Lerr;
119 return decldefs;
121 Lerr:
122 while (token.value != TOKsemicolon && token.value != TOKeof)
123 nextToken();
124 nextToken();
125 return new Array();
128 Array *Parser::parseDeclDefs(int once)
129 { Dsymbol *s;
130 Array *decldefs;
131 Array *a;
132 Array *aelse;
133 enum PROT prot;
134 unsigned stc;
135 unsigned storageClass;
136 Condition *condition;
137 unsigned char *comment;
139 //printf("Parser::parseDeclDefs()\n");
140 decldefs = new Array();
143 comment = token.blockComment;
144 storageClass = 0;
145 switch (token.value)
147 case TOKenum:
148 { /* Determine if this is a manifest constant declaration,
149 * or a conventional enum.
151 Token *t = peek(&token);
152 if (t->value == TOKlcurly || t->value == TOKcolon)
153 s = parseEnum();
154 else if (t->value != TOKidentifier)
155 goto Ldeclaration;
156 else
158 t = peek(t);
159 if (t->value == TOKlcurly || t->value == TOKcolon ||
160 t->value == TOKsemicolon)
161 s = parseEnum();
162 else
163 goto Ldeclaration;
165 break;
168 case TOKstruct:
169 case TOKunion:
170 case TOKclass:
171 case TOKinterface:
172 s = parseAggregate();
173 break;
175 case TOKimport:
176 s = parseImport(decldefs, 0);
177 break;
179 case TOKtemplate:
180 s = (Dsymbol *)parseTemplateDeclaration();
181 break;
183 case TOKmixin:
184 { Loc loc = this->loc;
185 if (peek(&token)->value == TOKlparen)
186 { // mixin(string)
187 nextToken();
188 check(TOKlparen, "mixin");
189 Expression *e = parseAssignExp();
190 check(TOKrparen);
191 check(TOKsemicolon);
192 s = new CompileDeclaration(loc, e);
193 break;
195 s = parseMixin();
196 break;
199 CASE_BASIC_TYPES:
200 case TOKalias:
201 case TOKtypedef:
202 case TOKidentifier:
203 case TOKtypeof:
204 case TOKdot:
205 Ldeclaration:
206 a = parseDeclarations();
207 decldefs->append(a);
208 continue;
210 case TOKthis:
211 s = parseCtor();
212 break;
214 case TOKassign:
215 s = parsePostBlit();
216 break;
218 case TOKtilde:
219 s = parseDtor();
220 break;
222 case TOKinvariant:
223 { Token *t;
224 t = peek(&token);
225 if (t->value == TOKlparen)
227 if (peek(t)->value == TOKrparen)
228 // invariant() forms start of class invariant
229 s = parseInvariant();
230 else
231 // invariant(type)
232 goto Ldeclaration;
234 else
236 stc = STCinvariant;
237 goto Lstc;
239 break;
242 case TOKunittest:
243 s = parseUnitTest();
244 break;
246 case TOKnew:
247 s = parseNew();
248 break;
250 case TOKdelete:
251 s = parseDelete();
252 break;
254 case TOKeof:
255 case TOKrcurly:
256 return decldefs;
258 case TOKstatic:
259 nextToken();
260 if (token.value == TOKthis)
261 s = parseStaticCtor();
262 else if (token.value == TOKtilde)
263 s = parseStaticDtor();
264 else if (token.value == TOKassert)
265 s = parseStaticAssert();
266 else if (token.value == TOKif)
267 { condition = parseStaticIfCondition();
268 a = parseBlock();
269 aelse = NULL;
270 if (token.value == TOKelse)
271 { nextToken();
272 aelse = parseBlock();
274 s = new StaticIfDeclaration(condition, a, aelse);
275 break;
277 else if (token.value == TOKimport)
279 s = parseImport(decldefs, 1);
281 else
282 { stc = STCstatic;
283 goto Lstc2;
285 break;
287 case TOKconst:
288 if (peek(&token)->value == TOKlparen)
289 goto Ldeclaration;
290 stc = STCconst;
291 goto Lstc;
293 case TOKfinal: stc = STCfinal; goto Lstc;
294 case TOKauto: stc = STCauto; goto Lstc;
295 case TOKscope: stc = STCscope; goto Lstc;
296 case TOKoverride: stc = STCoverride; goto Lstc;
297 case TOKabstract: stc = STCabstract; goto Lstc;
298 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
299 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
300 case TOKnothrow: stc = STCnothrow; goto Lstc;
301 case TOKpure: stc = STCpure; goto Lstc;
302 case TOKtls: stc = STCtls; goto Lstc;
303 //case TOKmanifest: stc = STCmanifest; goto Lstc;
305 Lstc:
306 if (storageClass & stc)
307 error("redundant storage class %s", Token::toChars(token.value));
309 unsigned u = storageClass | stc;
310 u &= STCconst | STCinvariant | STCmanifest;
311 if (u & (u - 1))
312 error("conflicting storage class %s", Token::toChars(token.value));
314 nextToken();
315 Lstc2:
316 storageClass |= stc;
317 switch (token.value)
319 case TOKconst:
320 case TOKinvariant:
321 // If followed by a (, it is not a storage class
322 if (peek(&token)->value == TOKlparen)
323 break;
324 if (token.value == TOKconst)
325 stc = STCconst;
326 else
327 stc = STCinvariant;
328 goto Lstc;
329 case TOKfinal: stc = STCfinal; goto Lstc;
330 case TOKauto: stc = STCauto; goto Lstc;
331 case TOKscope: stc = STCscope; goto Lstc;
332 case TOKoverride: stc = STCoverride; goto Lstc;
333 case TOKabstract: stc = STCabstract; goto Lstc;
334 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
335 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
336 case TOKnothrow: stc = STCnothrow; goto Lstc;
337 case TOKpure: stc = STCpure; goto Lstc;
338 case TOKtls: stc = STCtls; goto Lstc;
339 //case TOKmanifest: stc = STCmanifest; goto Lstc;
340 default:
341 break;
344 /* Look for auto initializers:
345 * storage_class identifier = initializer;
347 if (token.value == TOKidentifier &&
348 peek(&token)->value == TOKassign)
350 while (1)
352 Identifier *ident = token.ident;
353 nextToken();
354 nextToken();
355 Initializer *init = parseInitializer();
356 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
357 v->storage_class = storageClass;
358 s = v;
359 if (token.value == TOKsemicolon)
361 nextToken();
363 else if (token.value == TOKcomma)
365 nextToken();
366 if (token.value == TOKidentifier &&
367 peek(&token)->value == TOKassign)
369 decldefs->push(s);
370 addComment(s, comment);
371 continue;
373 else
374 error("Identifier expected following comma");
376 else
377 error("semicolon expected following auto declaration, not '%s'", token.toChars());
378 break;
381 else
382 { a = parseBlock();
383 s = new StorageClassDeclaration(storageClass, a);
385 break;
387 case TOKextern:
388 if (peek(&token)->value != TOKlparen)
389 { stc = STCextern;
390 goto Lstc;
393 enum LINK linksave = linkage;
394 linkage = parseLinkage();
395 a = parseBlock();
396 s = new LinkDeclaration(linkage, a);
397 linkage = linksave;
398 break;
400 case TOKprivate: prot = PROTprivate; goto Lprot;
401 case TOKpackage: prot = PROTpackage; goto Lprot;
402 case TOKprotected: prot = PROTprotected; goto Lprot;
403 case TOKpublic: prot = PROTpublic; goto Lprot;
404 case TOKexport: prot = PROTexport; goto Lprot;
406 Lprot:
407 nextToken();
408 switch (token.value)
410 case TOKprivate:
411 case TOKpackage:
412 case TOKprotected:
413 case TOKpublic:
414 case TOKexport:
415 error("redundant protection attribute");
416 break;
418 a = parseBlock();
419 s = new ProtDeclaration(prot, a);
420 break;
422 case TOKalign:
423 { unsigned n;
425 s = NULL;
426 nextToken();
427 if (token.value == TOKlparen)
429 nextToken();
430 if (token.value == TOKint32v)
431 n = (unsigned)token.uns64value;
432 else
433 { error("integer expected, not %s", token.toChars());
434 n = 1;
436 nextToken();
437 check(TOKrparen);
439 else
440 n = global.structalign; // default
442 a = parseBlock();
443 s = new AlignDeclaration(n, a);
444 break;
447 case TOKpragma:
448 { Identifier *ident;
449 Expressions *args = NULL;
451 nextToken();
452 check(TOKlparen);
453 if (token.value != TOKidentifier)
454 { error("pragma(identifier expected");
455 goto Lerror;
457 ident = token.ident;
458 nextToken();
459 if (token.value == TOKcomma)
460 args = parseArguments(); // pragma(identifier, args...)
461 else
462 check(TOKrparen); // pragma(identifier)
464 if (token.value == TOKsemicolon)
465 a = NULL;
466 else
467 a = parseBlock();
468 s = new PragmaDeclaration(loc, ident, args, a);
469 break;
472 case TOKdebug:
473 nextToken();
474 if (token.value == TOKassign)
476 nextToken();
477 if (token.value == TOKidentifier)
478 s = new DebugSymbol(loc, token.ident);
479 else if (token.value == TOKint32v)
480 s = new DebugSymbol(loc, (unsigned)token.uns64value);
481 else
482 { error("identifier or integer expected, not %s", token.toChars());
483 s = NULL;
485 nextToken();
486 if (token.value != TOKsemicolon)
487 error("semicolon expected");
488 nextToken();
489 break;
492 condition = parseDebugCondition();
493 goto Lcondition;
495 case TOKversion:
496 nextToken();
497 if (token.value == TOKassign)
499 nextToken();
500 if (token.value == TOKidentifier)
501 s = new VersionSymbol(loc, token.ident);
502 else if (token.value == TOKint32v)
503 s = new VersionSymbol(loc, (unsigned)token.uns64value);
504 else
505 { error("identifier or integer expected, not %s", token.toChars());
506 s = NULL;
508 nextToken();
509 if (token.value != TOKsemicolon)
510 error("semicolon expected");
511 nextToken();
512 break;
514 condition = parseVersionCondition();
515 goto Lcondition;
517 Lcondition:
518 a = parseBlock();
519 aelse = NULL;
520 if (token.value == TOKelse)
521 { nextToken();
522 aelse = parseBlock();
524 s = new ConditionalDeclaration(condition, a, aelse);
525 break;
527 case TOKsemicolon: // empty declaration
528 nextToken();
529 continue;
531 default:
532 error("Declaration expected, not '%s'",token.toChars());
533 Lerror:
534 while (token.value != TOKsemicolon && token.value != TOKeof)
535 nextToken();
536 nextToken();
537 s = NULL;
538 continue;
540 if (s)
541 { decldefs->push(s);
542 addComment(s, comment);
544 } while (!once);
545 return decldefs;
549 /********************************************
550 * Parse declarations after an align, protection, or extern decl.
553 Array *Parser::parseBlock()
555 Array *a = NULL;
556 Dsymbol *s;
558 //printf("parseBlock()\n");
559 switch (token.value)
561 case TOKsemicolon:
562 error("declaration expected following attribute, not ';'");
563 nextToken();
564 break;
566 case TOKlcurly:
567 nextToken();
568 a = parseDeclDefs(0);
569 if (token.value != TOKrcurly)
570 { /* { */
571 error("matching '}' expected, not %s", token.toChars());
573 else
574 nextToken();
575 break;
577 case TOKcolon:
578 nextToken();
579 #if 0
580 a = NULL;
581 #else
582 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
583 #endif
584 break;
586 default:
587 a = parseDeclDefs(1);
588 break;
590 return a;
593 /**********************************
594 * Parse a static assertion.
597 StaticAssert *Parser::parseStaticAssert()
599 Loc loc = this->loc;
600 Expression *exp;
601 Expression *msg = NULL;
603 //printf("parseStaticAssert()\n");
604 nextToken();
605 check(TOKlparen);
606 exp = parseAssignExp();
607 if (token.value == TOKcomma)
608 { nextToken();
609 msg = parseAssignExp();
611 check(TOKrparen);
612 check(TOKsemicolon);
613 return new StaticAssert(loc, exp, msg);
616 /***********************************
617 * Parse typeof(expression).
618 * Current token is on the 'typeof'.
621 TypeQualified *Parser::parseTypeof()
622 { TypeQualified *t;
623 Loc loc = this->loc;
625 nextToken();
626 check(TOKlparen);
627 if (token.value == TOKreturn) // typeof(return)
629 nextToken();
630 t = new TypeReturn(loc);
632 else
633 { Expression *exp = parseExpression(); // typeof(expression)
634 t = new TypeTypeof(loc, exp);
636 check(TOKrparen);
637 return t;
640 /***********************************
641 * Parse extern (linkage)
642 * The parser is on the 'extern' token.
645 enum LINK Parser::parseLinkage()
647 enum LINK link = LINKdefault;
648 nextToken();
649 assert(token.value == TOKlparen);
650 nextToken();
651 if (token.value == TOKidentifier)
652 { Identifier *id = token.ident;
654 nextToken();
655 if (id == Id::Windows)
656 link = LINKwindows;
657 else if (id == Id::Pascal)
658 link = LINKpascal;
659 else if (id == Id::D)
660 link = LINKd;
661 else if (id == Id::C)
663 link = LINKc;
664 if (token.value == TOKplusplus)
665 { link = LINKcpp;
666 nextToken();
669 else if (id == Id::System)
671 #ifdef IN_GCC
672 link = d_gcc_is_target_win32() ? LINKwindows : LINKc;
673 #else
674 #if _WIN32
675 link = LINKwindows;
676 #else
677 link = LINKc;
678 #endif
679 #endif
681 else
683 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
684 link = LINKd;
687 else
689 link = LINKd; // default
691 check(TOKrparen);
692 return link;
695 /**************************************
696 * Parse a debug conditional
699 Condition *Parser::parseDebugCondition()
701 Condition *c;
703 if (token.value == TOKlparen)
705 nextToken();
706 unsigned level = 1;
707 Identifier *id = NULL;
709 if (token.value == TOKidentifier)
710 id = token.ident;
711 else if (token.value == TOKint32v)
712 level = (unsigned)token.uns64value;
713 else
714 error("identifier or integer expected, not %s", token.toChars());
715 nextToken();
716 check(TOKrparen);
717 c = new DebugCondition(mod, level, id);
719 else
720 c = new DebugCondition(mod, 1, NULL);
721 return c;
725 /**************************************
726 * Parse a version conditional
729 Condition *Parser::parseVersionCondition()
731 Condition *c;
732 unsigned level = 1;
733 Identifier *id = NULL;
735 if (token.value == TOKlparen)
737 nextToken();
738 if (token.value == TOKidentifier)
739 id = token.ident;
740 else if (token.value == TOKint32v)
741 level = (unsigned)token.uns64value;
742 #if V2
743 /* Allow:
744 * version (unittest)
745 * even though unittest is a keyword
747 else if (token.value == TOKunittest)
748 id = Lexer::idPool(Token::toChars(TOKunittest));
749 #endif
750 else
751 error("identifier or integer expected, not %s", token.toChars());
752 nextToken();
753 check(TOKrparen);
756 else
757 error("(condition) expected following version");
758 c = new VersionCondition(mod, level, id);
759 return c;
763 /***********************************************
764 * static if (expression)
765 * body
766 * else
767 * body
770 Condition *Parser::parseStaticIfCondition()
771 { Expression *exp;
772 Condition *condition;
773 Array *aif;
774 Array *aelse;
775 Loc loc = this->loc;
777 nextToken();
778 if (token.value == TOKlparen)
780 nextToken();
781 exp = parseAssignExp();
782 check(TOKrparen);
784 else
785 { error("(expression) expected following static if");
786 exp = NULL;
788 condition = new StaticIfCondition(loc, exp);
789 return condition;
793 /*****************************************
794 * Parse a constructor definition:
795 * this(arguments) { body }
796 * or postblit:
797 * this(this) { body }
798 * Current token is 'this'.
801 FuncDeclaration *Parser::parseCtor()
803 Loc loc = this->loc;
805 nextToken();
806 if (token.value == TOKlparen && peek(&token)->value == TOKthis)
807 { // this(this) { ... }
808 nextToken();
809 nextToken();
810 check(TOKrparen);
811 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
812 parseContracts(f);
813 return f;
815 int varargs;
816 Arguments *arguments = parseParameters(&varargs);
817 CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs);
818 parseContracts(f);
819 return f;
822 /*****************************************
823 * Parse a postblit definition:
824 * =this() { body }
825 * Current token is '='.
828 PostBlitDeclaration *Parser::parsePostBlit()
830 Loc loc = this->loc;
832 nextToken();
833 check(TOKthis);
834 check(TOKlparen);
835 check(TOKrparen);
837 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
838 parseContracts(f);
839 return f;
842 /*****************************************
843 * Parse a destructor definition:
844 * ~this() { body }
845 * Current token is '~'.
848 DtorDeclaration *Parser::parseDtor()
850 DtorDeclaration *f;
851 Loc loc = this->loc;
853 nextToken();
854 check(TOKthis);
855 check(TOKlparen);
856 check(TOKrparen);
858 f = new DtorDeclaration(loc, 0);
859 parseContracts(f);
860 return f;
863 /*****************************************
864 * Parse a static constructor definition:
865 * static this() { body }
866 * Current token is 'this'.
869 StaticCtorDeclaration *Parser::parseStaticCtor()
871 StaticCtorDeclaration *f;
872 Loc loc = this->loc;
874 nextToken();
875 check(TOKlparen);
876 check(TOKrparen);
878 f = new StaticCtorDeclaration(loc, 0);
879 parseContracts(f);
880 return f;
883 /*****************************************
884 * Parse a static destructor definition:
885 * static ~this() { body }
886 * Current token is '~'.
889 StaticDtorDeclaration *Parser::parseStaticDtor()
891 StaticDtorDeclaration *f;
892 Loc loc = this->loc;
894 nextToken();
895 check(TOKthis);
896 check(TOKlparen);
897 check(TOKrparen);
899 f = new StaticDtorDeclaration(loc, 0);
900 parseContracts(f);
901 return f;
904 /*****************************************
905 * Parse an invariant definition:
906 * invariant { body }
907 * Current token is 'invariant'.
910 InvariantDeclaration *Parser::parseInvariant()
912 InvariantDeclaration *f;
913 Loc loc = this->loc;
915 nextToken();
917 // () are optional
918 if (token.value == TOKlparen)
919 { nextToken();
920 check(TOKrparen);
923 f = new InvariantDeclaration(loc, 0);
924 f->fbody = parseStatement(PScurly);
925 return f;
928 /*****************************************
929 * Parse a unittest definition:
930 * unittest { body }
931 * Current token is 'unittest'.
934 UnitTestDeclaration *Parser::parseUnitTest()
936 UnitTestDeclaration *f;
937 Statement *body;
938 Loc loc = this->loc;
940 nextToken();
942 body = parseStatement(PScurly);
944 f = new UnitTestDeclaration(loc, this->loc);
945 f->fbody = body;
946 return f;
949 /*****************************************
950 * Parse a new definition:
951 * new(arguments) { body }
952 * Current token is 'new'.
955 NewDeclaration *Parser::parseNew()
957 NewDeclaration *f;
958 Arguments *arguments;
959 int varargs;
960 Loc loc = this->loc;
962 nextToken();
963 arguments = parseParameters(&varargs);
964 f = new NewDeclaration(loc, 0, arguments, varargs);
965 parseContracts(f);
966 return f;
969 /*****************************************
970 * Parse a delete definition:
971 * delete(arguments) { body }
972 * Current token is 'delete'.
975 DeleteDeclaration *Parser::parseDelete()
977 DeleteDeclaration *f;
978 Arguments *arguments;
979 int varargs;
980 Loc loc = this->loc;
982 nextToken();
983 arguments = parseParameters(&varargs);
984 if (varargs)
985 error("... not allowed in delete function parameter list");
986 f = new DeleteDeclaration(loc, 0, arguments);
987 parseContracts(f);
988 return f;
991 /**********************************************
992 * Parse parameter list.
995 Arguments *Parser::parseParameters(int *pvarargs)
997 Arguments *arguments = new Arguments();
998 int varargs = 0;
999 int hasdefault = 0;
1001 check(TOKlparen);
1002 while (1)
1003 { Type *tb;
1004 Identifier *ai;
1005 Type *at;
1006 Argument *a;
1007 unsigned storageClass;
1008 unsigned stc;
1009 Expression *ae;
1011 ai = NULL;
1012 storageClass = 0; // parameter is "in" by default
1013 for (;1; nextToken())
1015 switch (token.value)
1017 case TOKrparen:
1018 break;
1020 case TOKdotdotdot:
1021 varargs = 1;
1022 nextToken();
1023 break;
1025 case TOKconst:
1026 if (peek(&token)->value == TOKlparen)
1027 goto Ldefault;
1028 stc = STCconst;
1029 goto L2;
1031 case TOKinvariant:
1032 if (peek(&token)->value == TOKlparen)
1033 goto Ldefault;
1034 stc = STCinvariant;
1035 goto L2;
1037 case TOKin: stc = STCin; goto L2;
1038 case TOKout: stc = STCout; goto L2;
1039 case TOKinout:
1040 case TOKref: stc = STCref; goto L2;
1041 case TOKlazy: stc = STClazy; goto L2;
1042 case TOKscope: stc = STCscope; goto L2;
1043 case TOKfinal: stc = STCfinal; goto L2;
1044 case TOKstatic: stc = STCstatic; goto L2;
1046 if (storageClass & stc ||
1047 (storageClass & STCin && stc & (STCconst | STCscope)) ||
1048 (stc & STCin && storageClass & (STCconst | STCscope))
1050 error("redundant storage class %s", Token::toChars(token.value));
1051 storageClass |= stc;
1053 unsigned u = storageClass & (STCconst | STCinvariant);
1054 if (u & (u - 1))
1055 error("conflicting storage class %s", Token::toChars(token.value));
1057 continue;
1059 default:
1060 Ldefault:
1061 stc = storageClass & (STCin | STCout | STCref | STClazy);
1062 if (stc & (stc - 1)) // if stc is not a power of 2
1063 error("incompatible parameter storage classes");
1064 if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1065 error("out cannot be const");
1066 if ((storageClass & (STCinvariant | STCout)) == (STCinvariant | STCout))
1067 error("out cannot be invariant");
1068 if ((storageClass & STCscope) &&
1069 (storageClass & (STCref | STCout)))
1070 error("scope cannot be ref or out");
1071 at = parseType(&ai);
1072 ae = NULL;
1073 if (token.value == TOKassign) // = defaultArg
1074 { nextToken();
1075 ae = parseDefaultInitExp();
1076 hasdefault = 1;
1078 else
1079 { if (hasdefault)
1080 error("default argument expected for %s",
1081 ai ? ai->toChars() : at->toChars());
1083 if (token.value == TOKdotdotdot)
1084 { /* This is:
1085 * at ai ...
1088 if (storageClass & (STCout | STCref))
1089 error("variadic argument cannot be out or ref");
1090 varargs = 2;
1091 a = new Argument(storageClass, at, ai, ae);
1092 arguments->push(a);
1093 nextToken();
1094 break;
1096 a = new Argument(storageClass, at, ai, ae);
1097 arguments->push(a);
1098 if (token.value == TOKcomma)
1099 { nextToken();
1100 goto L1;
1102 break;
1104 break;
1106 break;
1108 L1: ;
1110 check(TOKrparen);
1111 *pvarargs = varargs;
1112 return arguments;
1116 /*************************************
1119 EnumDeclaration *Parser::parseEnum()
1120 { EnumDeclaration *e;
1121 Identifier *id;
1122 Type *memtype;
1123 Loc loc = this->loc;
1125 //printf("Parser::parseEnum()\n");
1126 nextToken();
1127 if (token.value == TOKidentifier)
1128 { id = token.ident;
1129 nextToken();
1131 else
1132 id = NULL;
1134 if (token.value == TOKcolon)
1136 nextToken();
1137 memtype = parseBasicType();
1138 memtype = parseDeclarator(memtype, NULL, NULL);
1140 else
1141 memtype = NULL;
1143 e = new EnumDeclaration(loc, id, memtype);
1144 if (token.value == TOKsemicolon && id)
1145 nextToken();
1146 else if (token.value == TOKlcurly)
1148 //printf("enum definition\n");
1149 e->members = new Array();
1150 nextToken();
1151 unsigned char *comment = token.blockComment;
1152 while (token.value != TOKrcurly)
1154 /* Can take the following forms:
1155 * 1. ident
1156 * 2. ident = value
1157 * 3. type ident = value
1160 loc = this->loc;
1162 Type *type = NULL;
1163 Identifier *ident;
1164 Token *tp = peek(&token);
1165 if (token.value == TOKidentifier &&
1166 (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
1168 ident = token.ident;
1169 type = NULL;
1170 nextToken();
1172 else
1174 type = parseType(&ident, NULL);
1175 if (id || memtype)
1176 error("type only allowed if anonymous enum and no enum type");
1179 Expression *value;
1180 if (token.value == TOKassign)
1182 nextToken();
1183 value = parseAssignExp();
1185 else
1186 { value = NULL;
1187 if (type)
1188 error("if type, there must be an initializer");
1191 EnumMember *em = new EnumMember(loc, ident, value, type);
1192 e->members->push(em);
1194 if (token.value == TOKrcurly)
1196 else
1197 { addComment(em, comment);
1198 comment = NULL;
1199 check(TOKcomma);
1201 addComment(em, comment);
1202 comment = token.blockComment;
1204 nextToken();
1206 else
1207 error("enum declaration is invalid");
1208 //printf("-parseEnum() %s\n", e->toChars());
1209 return e;
1212 Dsymbol *Parser::parseAggregate()
1213 { AggregateDeclaration *a = NULL;
1214 int anon = 0;
1215 enum TOK tok;
1216 Identifier *id;
1217 TemplateParameters *tpl = NULL;
1219 //printf("Parser::parseAggregate()\n");
1220 tok = token.value;
1221 nextToken();
1222 if (token.value != TOKidentifier)
1223 { id = NULL;
1225 else
1226 { id = token.ident;
1227 nextToken();
1229 if (token.value == TOKlparen)
1230 { // Class template declaration.
1232 // Gather template parameter list
1233 tpl = parseTemplateParameterList();
1237 Loc loc = this->loc;
1238 switch (tok)
1239 { case TOKclass:
1240 case TOKinterface:
1242 if (!id)
1243 error("anonymous classes not allowed");
1245 // Collect base class(es)
1246 BaseClasses *baseclasses = NULL;
1247 if (token.value == TOKcolon)
1249 nextToken();
1250 baseclasses = parseBaseClasses();
1252 if (token.value != TOKlcurly)
1253 error("members expected");
1256 if (tok == TOKclass)
1257 a = new ClassDeclaration(loc, id, baseclasses);
1258 else
1259 a = new InterfaceDeclaration(loc, id, baseclasses);
1260 break;
1263 case TOKstruct:
1264 if (id)
1265 a = new StructDeclaration(loc, id);
1266 else
1267 anon = 1;
1268 break;
1270 case TOKunion:
1271 if (id)
1272 a = new UnionDeclaration(loc, id);
1273 else
1274 anon = 2;
1275 break;
1277 default:
1278 assert(0);
1279 break;
1281 if (a && token.value == TOKsemicolon)
1282 { nextToken();
1284 else if (token.value == TOKlcurly)
1286 //printf("aggregate definition\n");
1287 nextToken();
1288 Array *decl = parseDeclDefs(0);
1289 if (token.value != TOKrcurly)
1290 error("} expected following member declarations in aggregate");
1291 nextToken();
1292 if (anon)
1294 /* Anonymous structs/unions are more like attributes.
1296 return new AnonDeclaration(loc, anon - 1, decl);
1298 else
1299 a->members = decl;
1301 else
1303 error("{ } expected following aggregate declaration");
1304 a = new StructDeclaration(loc, NULL);
1307 if (tpl)
1308 { Array *decldefs;
1309 TemplateDeclaration *tempdecl;
1311 // Wrap a template around the aggregate declaration
1312 decldefs = new Array();
1313 decldefs->push(a);
1314 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
1315 return tempdecl;
1318 return a;
1321 /*******************************************
1324 BaseClasses *Parser::parseBaseClasses()
1326 BaseClasses *baseclasses = new BaseClasses();
1328 for (; 1; nextToken())
1330 enum PROT protection = PROTpublic;
1331 switch (token.value)
1333 case TOKprivate:
1334 protection = PROTprivate;
1335 nextToken();
1336 break;
1337 case TOKpackage:
1338 protection = PROTpackage;
1339 nextToken();
1340 break;
1341 case TOKprotected:
1342 protection = PROTprotected;
1343 nextToken();
1344 break;
1345 case TOKpublic:
1346 protection = PROTpublic;
1347 nextToken();
1348 break;
1350 if (token.value == TOKidentifier)
1352 BaseClass *b = new BaseClass(parseBasicType(), protection);
1353 baseclasses->push(b);
1354 if (token.value != TOKcomma)
1355 break;
1357 else
1359 error("base classes expected instead of %s", token.toChars());
1360 return NULL;
1363 return baseclasses;
1366 /**************************************
1367 * Parse a TemplateDeclaration.
1370 TemplateDeclaration *Parser::parseTemplateDeclaration()
1372 TemplateDeclaration *tempdecl;
1373 Identifier *id;
1374 TemplateParameters *tpl;
1375 Array *decldefs;
1376 Loc loc = this->loc;
1378 nextToken();
1379 if (token.value != TOKidentifier)
1380 { error("TemplateIdentifier expected following template");
1381 goto Lerr;
1383 id = token.ident;
1384 nextToken();
1385 tpl = parseTemplateParameterList();
1386 if (!tpl)
1387 goto Lerr;
1389 if (token.value != TOKlcurly)
1390 { error("members of template declaration expected");
1391 goto Lerr;
1393 else
1395 nextToken();
1396 decldefs = parseDeclDefs(0);
1397 if (token.value != TOKrcurly)
1398 { error("template member expected");
1399 goto Lerr;
1401 nextToken();
1404 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs);
1405 return tempdecl;
1407 Lerr:
1408 return NULL;
1411 /******************************************
1412 * Parse template parameter list.
1413 * Input:
1414 * flag 0: parsing "( list )"
1415 * 1: parsing non-empty "list )"
1418 TemplateParameters *Parser::parseTemplateParameterList(int flag)
1420 TemplateParameters *tpl = new TemplateParameters();
1422 if (!flag && token.value != TOKlparen)
1423 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1424 goto Lerr;
1426 nextToken();
1428 // Get array of TemplateParameters
1429 if (flag || token.value != TOKrparen)
1430 { int isvariadic = 0;
1432 while (1)
1433 { TemplateParameter *tp;
1434 Identifier *tp_ident = NULL;
1435 Type *tp_spectype = NULL;
1436 Type *tp_valtype = NULL;
1437 Type *tp_defaulttype = NULL;
1438 Expression *tp_specvalue = NULL;
1439 Expression *tp_defaultvalue = NULL;
1440 Token *t;
1442 // Get TemplateParameter
1444 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1445 t = peek(&token);
1446 if (token.value == TOKalias)
1447 { // AliasParameter
1448 nextToken();
1449 if (token.value != TOKidentifier)
1450 { error("Identifier expected for template parameter");
1451 goto Lerr;
1453 tp_ident = token.ident;
1454 nextToken();
1455 if (token.value == TOKcolon) // : Type
1457 nextToken();
1458 tp_spectype = parseType();
1460 if (token.value == TOKassign) // = Type
1462 nextToken();
1463 tp_defaulttype = parseType();
1465 tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1467 else if (t->value == TOKcolon || t->value == TOKassign ||
1468 t->value == TOKcomma || t->value == TOKrparen)
1469 { // TypeParameter
1470 if (token.value != TOKidentifier)
1471 { error("Identifier expected for template parameter");
1472 goto Lerr;
1474 tp_ident = token.ident;
1475 nextToken();
1476 if (token.value == TOKcolon) // : Type
1478 nextToken();
1479 tp_spectype = parseType();
1481 if (token.value == TOKassign) // = Type
1483 nextToken();
1484 tp_defaulttype = parseType();
1486 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1488 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1489 { // ident...
1490 if (isvariadic)
1491 error("variadic template parameter must be last");
1492 isvariadic = 1;
1493 tp_ident = token.ident;
1494 nextToken();
1495 nextToken();
1496 tp = new TemplateTupleParameter(loc, tp_ident);
1498 else if (token.value == TOKthis)
1499 { // ThisParameter
1500 nextToken();
1501 if (token.value != TOKidentifier)
1502 { error("Identifier expected for template parameter");
1503 goto Lerr;
1505 tp_ident = token.ident;
1506 nextToken();
1507 if (token.value == TOKcolon) // : Type
1509 nextToken();
1510 tp_spectype = parseType();
1512 if (token.value == TOKassign) // = Type
1514 nextToken();
1515 tp_defaulttype = parseType();
1517 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1519 else
1520 { // ValueParameter
1521 tp_valtype = parseType(&tp_ident);
1522 if (!tp_ident)
1524 error("no identifier for template value parameter");
1525 tp_ident = new Identifier("error", TOKidentifier);
1527 if (token.value == TOKcolon) // : CondExpression
1529 nextToken();
1530 tp_specvalue = parseCondExp();
1532 if (token.value == TOKassign) // = CondExpression
1534 nextToken();
1535 tp_defaultvalue = parseDefaultInitExp();
1537 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1539 tpl->push(tp);
1540 if (token.value != TOKcomma)
1541 break;
1542 nextToken();
1545 check(TOKrparen);
1546 Lerr:
1547 return tpl;
1550 /******************************************
1551 * Parse template mixin.
1552 * mixin Foo;
1553 * mixin Foo!(args);
1554 * mixin a.b.c!(args).Foo!(args);
1555 * mixin Foo!(args) identifier;
1556 * mixin typeof(expr).identifier!(args);
1559 Dsymbol *Parser::parseMixin()
1561 TemplateMixin *tm;
1562 Identifier *id;
1563 Type *tqual;
1564 Objects *tiargs;
1565 Array *idents;
1567 //printf("parseMixin()\n");
1568 nextToken();
1569 tqual = NULL;
1570 if (token.value == TOKdot)
1572 id = Id::empty;
1574 else
1576 if (token.value == TOKtypeof)
1578 tqual = parseTypeof();
1579 check(TOKdot);
1581 if (token.value != TOKidentifier)
1583 error("identifier expected, not %s", token.toChars());
1584 goto Lerr;
1586 id = token.ident;
1587 nextToken();
1590 idents = new Array();
1591 while (1)
1593 tiargs = NULL;
1594 if (token.value == TOKnot)
1596 nextToken();
1597 tiargs = parseTemplateArgumentList();
1600 if (token.value != TOKdot)
1601 break;
1603 if (tiargs)
1604 { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1605 tempinst->tiargs = tiargs;
1606 id = (Identifier *)tempinst;
1607 tiargs = NULL;
1609 idents->push(id);
1611 nextToken();
1612 if (token.value != TOKidentifier)
1613 { error("identifier expected following '.' instead of '%s'", token.toChars());
1614 break;
1616 id = token.ident;
1617 nextToken();
1619 idents->push(id);
1621 if (token.value == TOKidentifier)
1623 id = token.ident;
1624 nextToken();
1626 else
1627 id = NULL;
1629 tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1630 if (token.value != TOKsemicolon)
1631 error("';' expected after mixin");
1632 nextToken();
1634 return tm;
1636 Lerr:
1637 return NULL;
1640 /******************************************
1641 * Parse template argument list.
1642 * Input:
1643 * current token is opening '('
1644 * Output:
1645 * current token is one after closing ')'
1648 Objects *Parser::parseTemplateArgumentList()
1650 //printf("Parser::parseTemplateArgumentList()\n");
1651 if (token.value != TOKlparen)
1652 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1653 return new Objects();
1655 return parseTemplateArgumentList2();
1658 Objects *Parser::parseTemplateArgumentList2()
1660 Objects *tiargs = new Objects();
1661 nextToken();
1663 // Get TemplateArgumentList
1664 if (token.value != TOKrparen)
1666 while (1)
1668 // See if it is an Expression or a Type
1669 if (isDeclaration(&token, 0, TOKreserved, NULL))
1670 { // Type
1671 Type *ta;
1673 // Get TemplateArgument
1674 ta = parseType();
1675 tiargs->push(ta);
1677 else
1678 { // Expression
1679 Expression *ea;
1681 ea = parseAssignExp();
1682 tiargs->push(ea);
1684 if (token.value != TOKcomma)
1685 break;
1686 nextToken();
1689 check(TOKrparen, "template argument list");
1690 return tiargs;
1693 Import *Parser::parseImport(Array *decldefs, int isstatic)
1694 { Import *s;
1695 Identifier *id;
1696 Identifier *aliasid = NULL;
1697 Array *a;
1698 Loc loc;
1700 //printf("Parser::parseImport()\n");
1704 nextToken();
1705 if (token.value != TOKidentifier)
1706 { error("Identifier expected following import");
1707 break;
1710 loc = this->loc;
1711 a = NULL;
1712 id = token.ident;
1713 nextToken();
1714 if (!aliasid && token.value == TOKassign)
1716 aliasid = id;
1717 goto L1;
1719 while (token.value == TOKdot)
1721 if (!a)
1722 a = new Array();
1723 a->push(id);
1724 nextToken();
1725 if (token.value != TOKidentifier)
1726 { error("Identifier expected following package");
1727 break;
1729 id = token.ident;
1730 nextToken();
1733 s = new Import(loc, a, token.ident, aliasid, isstatic);
1734 decldefs->push(s);
1736 /* Look for
1737 * : alias=name, alias=name;
1738 * syntax.
1740 if (token.value == TOKcolon)
1743 { Identifier *name;
1744 Identifier *alias;
1746 nextToken();
1747 if (token.value != TOKidentifier)
1748 { error("Identifier expected following :");
1749 break;
1751 alias = token.ident;
1752 nextToken();
1753 if (token.value == TOKassign)
1755 nextToken();
1756 if (token.value != TOKidentifier)
1757 { error("Identifier expected following %s=", alias->toChars());
1758 break;
1760 name = token.ident;
1761 nextToken();
1763 else
1764 { name = alias;
1765 alias = NULL;
1767 s->addAlias(name, alias);
1768 } while (token.value == TOKcomma);
1769 break; // no comma-separated imports of this form
1772 aliasid = NULL;
1773 } while (token.value == TOKcomma);
1775 if (token.value == TOKsemicolon)
1776 nextToken();
1777 else
1779 error("';' expected");
1780 nextToken();
1783 return NULL;
1786 Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
1787 { Type *t;
1789 if (token.value == TOKconst && peek(&token)->value != TOKlparen)
1791 nextToken();
1792 /* const type
1794 t = parseType(pident, tpl);
1795 t = t->makeConst();
1796 return t;
1798 else if (token.value == TOKinvariant && peek(&token)->value != TOKlparen)
1800 nextToken();
1801 /* invariant type
1803 t = parseType(pident, tpl);
1804 t = t->makeInvariant();
1805 return t;
1807 else
1808 t = parseBasicType();
1809 t = parseDeclarator(t, pident, tpl);
1810 return t;
1813 Type *Parser::parseBasicType()
1814 { Type *t;
1815 Identifier *id;
1816 TypeQualified *tid;
1817 TemplateInstance *tempinst;
1819 //printf("parseBasicType()\n");
1820 switch (token.value)
1822 CASE_BASIC_TYPES_X(t):
1823 nextToken();
1824 break;
1826 case TOKidentifier:
1827 id = token.ident;
1828 nextToken();
1829 if (token.value == TOKnot)
1831 nextToken();
1832 tempinst = new TemplateInstance(loc, id);
1833 tempinst->tiargs = parseTemplateArgumentList();
1834 tid = new TypeInstance(loc, tempinst);
1835 goto Lident2;
1837 Lident:
1838 tid = new TypeIdentifier(loc, id);
1839 Lident2:
1840 while (token.value == TOKdot)
1841 { nextToken();
1842 if (token.value != TOKidentifier)
1843 { error("identifier expected following '.' instead of '%s'", token.toChars());
1844 break;
1846 id = token.ident;
1847 nextToken();
1848 if (token.value == TOKnot)
1850 nextToken();
1851 tempinst = new TemplateInstance(loc, id);
1852 tempinst->tiargs = parseTemplateArgumentList();
1853 tid->addIdent((Identifier *)tempinst);
1855 else
1856 tid->addIdent(id);
1858 t = tid;
1859 break;
1861 case TOKdot:
1862 id = Id::empty;
1863 goto Lident;
1865 case TOKtypeof:
1867 tid = parseTypeof();
1868 goto Lident2;
1871 case TOKconst:
1872 // const(type)
1873 nextToken();
1874 check(TOKlparen);
1875 t = parseType();
1876 check(TOKrparen);
1877 t = t->makeConst();
1878 break;
1880 case TOKinvariant:
1881 // invariant(type)
1882 nextToken();
1883 check(TOKlparen);
1884 t = parseType();
1885 check(TOKrparen);
1886 t = t->makeInvariant();
1887 break;
1889 default:
1890 error("basic type expected, not %s", token.toChars());
1891 t = Type::tint32;
1892 break;
1894 return t;
1897 Type *Parser::parseBasicType2(Type *t)
1899 Type *ts;
1900 Type *ta;
1902 //printf("parseBasicType2()\n");
1903 while (1)
1905 switch (token.value)
1907 case TOKmul:
1908 t = new TypePointer(t);
1909 nextToken();
1910 continue;
1912 case TOKlbracket:
1913 // Handle []. Make sure things like
1914 // int[3][1] a;
1915 // is (array[1] of array[3] of int)
1916 nextToken();
1917 if (token.value == TOKrbracket)
1919 t = new TypeDArray(t); // []
1920 nextToken();
1922 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
1923 { // It's an associative array declaration
1924 Type *index;
1926 //printf("it's an associative array\n");
1927 index = parseType(); // [ type ]
1928 t = new TypeAArray(t, index);
1929 check(TOKrbracket);
1931 else
1933 //printf("it's [expression]\n");
1934 inBrackets++;
1935 Expression *e = parseExpression(); // [ expression ]
1936 if (token.value == TOKslice)
1937 { Expression *e2;
1939 nextToken();
1940 e2 = parseExpression(); // [ exp .. exp ]
1941 t = new TypeSlice(t, e, e2);
1943 else
1944 t = new TypeSArray(t,e);
1945 inBrackets--;
1946 check(TOKrbracket);
1948 continue;
1950 case TOKdelegate:
1951 case TOKfunction:
1952 { // Handle delegate declaration:
1953 // t delegate(parameter list)
1954 // t function(parameter list)
1955 Arguments *arguments;
1956 int varargs;
1957 bool ispure = false;
1958 bool isnothrow = false;
1959 enum TOK save = token.value;
1961 nextToken();
1962 arguments = parseParameters(&varargs);
1963 while (1)
1965 if (token.value == TOKpure)
1966 ispure = true;
1967 else if (token.value == TOKnothrow)
1968 isnothrow = true;
1969 else
1970 break;
1971 nextToken();
1973 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
1974 tf->ispure = ispure;
1975 tf->isnothrow = isnothrow;
1976 if (save == TOKdelegate)
1977 t = new TypeDelegate(tf);
1978 else
1979 t = new TypePointer(tf); // pointer to function
1980 continue;
1983 default:
1984 ts = t;
1985 break;
1987 break;
1989 return ts;
1992 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
1993 { Type *ts;
1995 //printf("parseDeclarator(tpl = %p)\n", tpl);
1996 t = parseBasicType2(t);
1998 switch (token.value)
2001 case TOKidentifier:
2002 if (pident)
2003 *pident = token.ident;
2004 else
2005 error("unexpected identifer '%s' in declarator", token.ident->toChars());
2006 ts = t;
2007 nextToken();
2008 break;
2010 case TOKlparen:
2011 /* Parse things with parentheses around the identifier, like:
2012 * int (*ident[3])[]
2013 * although the D style would be:
2014 * int[]*[3] ident
2016 nextToken();
2017 ts = parseDeclarator(t, pident);
2018 check(TOKrparen);
2019 break;
2021 default:
2022 ts = t;
2023 break;
2026 while (1)
2028 switch (token.value)
2030 #if CARRAYDECL
2031 /* Support C style array syntax:
2032 * int ident[]
2033 * as opposed to D-style:
2034 * int[] ident
2036 case TOKlbracket:
2037 { // This is the old C-style post [] syntax.
2038 TypeNext *ta;
2039 nextToken();
2040 if (token.value == TOKrbracket)
2041 { // It's a dynamic array
2042 ta = new TypeDArray(t); // []
2043 nextToken();
2045 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2046 { // It's an associative array
2048 //printf("it's an associative array\n");
2049 Type *index = parseType(); // [ type ]
2050 check(TOKrbracket);
2051 ta = new TypeAArray(t, index);
2053 else
2055 //printf("It's a static array\n");
2056 Expression *e = parseExpression(); // [ expression ]
2057 ta = new TypeSArray(t, e);
2058 check(TOKrbracket);
2061 /* Insert ta into
2062 * ts -> ... -> t
2063 * so that
2064 * ts -> ... -> ta -> t
2066 Type **pt;
2067 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2069 *pt = ta;
2070 continue;
2072 #endif
2073 case TOKlparen:
2075 if (tpl)
2077 /* Look ahead to see if this is (...)(...),
2078 * i.e. a function template declaration
2080 if (peekPastParen(&token)->value == TOKlparen)
2082 //printf("function template declaration\n");
2084 // Gather template parameter list
2085 *tpl = parseTemplateParameterList();
2089 int varargs;
2090 Arguments *arguments = parseParameters(&varargs);
2091 Type *tf = new TypeFunction(arguments, t, varargs, linkage);
2093 /* Parse const/invariant/nothrow postfix
2095 while (1)
2097 switch (token.value)
2099 case TOKconst:
2100 tf = tf->makeConst();
2101 nextToken();
2102 continue;
2104 case TOKinvariant:
2105 tf = tf->makeInvariant();
2106 nextToken();
2107 continue;
2109 case TOKnothrow:
2110 ((TypeFunction *)tf)->isnothrow = 1;
2111 nextToken();
2112 continue;
2114 case TOKpure:
2115 ((TypeFunction *)tf)->ispure = 1;
2116 nextToken();
2117 continue;
2119 break;
2122 /* Insert tf into
2123 * ts -> ... -> t
2124 * so that
2125 * ts -> ... -> tf -> t
2127 Type **pt;
2128 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2130 *pt = tf;
2131 break;
2134 break;
2137 return ts;
2140 /**********************************
2141 * Return array of Declaration *'s.
2144 Array *Parser::parseDeclarations()
2146 enum STC storage_class;
2147 enum STC stc;
2148 Type *ts;
2149 Type *t;
2150 Type *tfirst;
2151 Identifier *ident;
2152 Array *a;
2153 enum TOK tok;
2154 unsigned char *comment = token.blockComment;
2155 enum LINK link = linkage;
2157 //printf("parseDeclarations() %s\n", token.toChars());
2158 switch (token.value)
2160 case TOKtypedef:
2161 case TOKalias:
2162 tok = token.value;
2163 nextToken();
2164 break;
2166 default:
2167 tok = TOKreserved;
2168 break;
2171 storage_class = STCundefined;
2172 while (1)
2174 switch (token.value)
2176 case TOKconst:
2177 if (peek(&token)->value == TOKlparen)
2178 break;
2179 stc = STCconst;
2180 goto L1;
2182 case TOKinvariant:
2183 if (peek(&token)->value == TOKlparen)
2184 break;
2185 stc = STCinvariant;
2186 goto L1;
2188 case TOKstatic: stc = STCstatic; goto L1;
2189 case TOKfinal: stc = STCfinal; goto L1;
2190 case TOKauto: stc = STCauto; goto L1;
2191 case TOKscope: stc = STCscope; goto L1;
2192 case TOKoverride: stc = STCoverride; goto L1;
2193 case TOKabstract: stc = STCabstract; goto L1;
2194 case TOKsynchronized: stc = STCsynchronized; goto L1;
2195 case TOKdeprecated: stc = STCdeprecated; goto L1;
2196 case TOKnothrow: stc = STCnothrow; goto L1;
2197 case TOKpure: stc = STCpure; goto L1;
2198 case TOKtls: stc = STCtls; goto L1;
2199 case TOKenum: stc = STCmanifest; goto L1;
2201 if (storage_class & stc)
2202 error("redundant storage class '%s'", token.toChars());
2203 storage_class = (STC) (storage_class | stc);
2205 unsigned u = storage_class;
2206 u &= STCconst | STCinvariant | STCmanifest;
2207 if (u & (u - 1))
2208 error("conflicting storage class %s", Token::toChars(token.value));
2210 nextToken();
2211 continue;
2213 case TOKextern:
2214 if (peek(&token)->value != TOKlparen)
2215 { stc = STCextern;
2216 goto L1;
2219 link = parseLinkage();
2220 continue;
2222 default:
2223 break;
2225 break;
2228 a = new Array();
2230 /* Look for auto initializers:
2231 * storage_class identifier = initializer;
2233 while (storage_class &&
2234 token.value == TOKidentifier &&
2235 peek(&token)->value == TOKassign)
2237 ident = token.ident;
2238 nextToken();
2239 nextToken();
2240 Initializer *init = parseInitializer();
2241 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2242 v->storage_class = storage_class;
2243 a->push(v);
2244 if (token.value == TOKsemicolon)
2246 nextToken();
2247 addComment(v, comment);
2249 else if (token.value == TOKcomma)
2251 nextToken();
2252 if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
2254 error("Identifier expected following comma");
2256 else
2257 continue;
2259 else
2260 error("semicolon expected following auto declaration, not '%s'", token.toChars());
2261 return a;
2264 if (token.value == TOKclass)
2265 { AggregateDeclaration *s;
2267 s = (AggregateDeclaration *)parseAggregate();
2268 s->storage_class |= storage_class;
2269 a->push(s);
2270 addComment(s, comment);
2271 return a;
2274 ts = parseBasicType();
2275 ts = parseBasicType2(ts);
2276 tfirst = NULL;
2278 while (1)
2280 Loc loc = this->loc;
2281 TemplateParameters *tpl = NULL;
2283 ident = NULL;
2284 t = parseDeclarator(ts, &ident, &tpl);
2285 assert(t);
2286 if (!tfirst)
2287 tfirst = t;
2288 else if (t != tfirst)
2289 error("multiple declarations must have the same type, not %s and %s",
2290 tfirst->toChars(), t->toChars());
2291 if (!ident)
2292 error("no identifier for declarator %s", t->toChars());
2294 if (tok == TOKtypedef || tok == TOKalias)
2295 { Declaration *v;
2296 Initializer *init;
2298 init = NULL;
2299 if (token.value == TOKassign)
2301 nextToken();
2302 init = parseInitializer();
2304 if (tok == TOKtypedef)
2305 v = new TypedefDeclaration(loc, ident, t, init);
2306 else
2307 { if (init)
2308 error("alias cannot have initializer");
2309 v = new AliasDeclaration(loc, ident, t);
2311 v->storage_class = storage_class;
2312 if (link == linkage)
2313 a->push(v);
2314 else
2316 Array *ax = new Array();
2317 ax->push(v);
2318 Dsymbol *s = new LinkDeclaration(link, ax);
2319 a->push(s);
2321 switch (token.value)
2322 { case TOKsemicolon:
2323 nextToken();
2324 addComment(v, comment);
2325 break;
2327 case TOKcomma:
2328 nextToken();
2329 addComment(v, comment);
2330 continue;
2332 default:
2333 error("semicolon expected to close %s declaration", Token::toChars(tok));
2334 break;
2337 else if (t->ty == Tfunction)
2338 { FuncDeclaration *f;
2339 Dsymbol *s;
2341 f = new FuncDeclaration(loc, 0, ident, storage_class, t);
2342 addComment(f, comment);
2343 parseContracts(f);
2344 addComment(f, NULL);
2345 if (link == linkage)
2347 s = f;
2349 else
2351 Array *ax = new Array();
2352 ax->push(f);
2353 s = new LinkDeclaration(link, ax);
2355 if (tpl) // it's a function template
2356 { Array *decldefs;
2357 TemplateDeclaration *tempdecl;
2359 // Wrap a template around the aggregate declaration
2360 decldefs = new Array();
2361 decldefs->push(s);
2362 tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs);
2363 s = tempdecl;
2365 addComment(s, comment);
2366 a->push(s);
2368 else
2369 { VarDeclaration *v;
2370 Initializer *init;
2372 init = NULL;
2373 if (token.value == TOKassign)
2375 nextToken();
2376 init = parseInitializer();
2378 v = new VarDeclaration(loc, t, ident, init);
2379 v->storage_class = storage_class;
2380 if (link == linkage)
2381 a->push(v);
2382 else
2384 Array *ax = new Array();
2385 ax->push(v);
2386 Dsymbol *s = new LinkDeclaration(link, ax);
2387 a->push(s);
2389 switch (token.value)
2390 { case TOKsemicolon:
2391 nextToken();
2392 addComment(v, comment);
2393 break;
2395 case TOKcomma:
2396 nextToken();
2397 addComment(v, comment);
2398 continue;
2400 default:
2401 error("semicolon expected, not '%s'", token.toChars());
2402 break;
2405 break;
2407 return a;
2410 /*****************************************
2411 * Parse contracts following function declaration.
2414 void Parser::parseContracts(FuncDeclaration *f)
2416 Type *tb;
2417 enum LINK linksave = linkage;
2419 // The following is irrelevant, as it is overridden by sc->linkage in
2420 // TypeFunction::semantic
2421 linkage = LINKd; // nested functions have D linkage
2423 switch (token.value)
2425 case TOKlcurly:
2426 if (f->frequire || f->fensure)
2427 error("missing body { ... } after in or out");
2428 f->fbody = parseStatement(PSsemi);
2429 f->endloc = endloc;
2430 break;
2432 case TOKbody:
2433 nextToken();
2434 f->fbody = parseStatement(PScurly);
2435 f->endloc = endloc;
2436 break;
2438 case TOKsemicolon:
2439 if (f->frequire || f->fensure)
2440 error("missing body { ... } after in or out");
2441 nextToken();
2442 break;
2444 #if 0 // Do we want this for function declarations, so we can do:
2445 // int x, y, foo(), z;
2446 case TOKcomma:
2447 nextToken();
2448 continue;
2449 #endif
2451 #if 0 // Dumped feature
2452 case TOKthrow:
2453 if (!f->fthrows)
2454 f->fthrows = new Array();
2455 nextToken();
2456 check(TOKlparen);
2457 while (1)
2459 tb = parseBasicType();
2460 f->fthrows->push(tb);
2461 if (token.value == TOKcomma)
2462 { nextToken();
2463 continue;
2465 break;
2467 check(TOKrparen);
2468 goto L1;
2469 #endif
2471 case TOKin:
2472 nextToken();
2473 if (f->frequire)
2474 error("redundant 'in' statement");
2475 f->frequire = parseStatement(PScurly | PSscope);
2476 goto L1;
2478 case TOKout:
2479 // parse: out (identifier) { statement }
2480 nextToken();
2481 if (token.value != TOKlcurly)
2483 check(TOKlparen);
2484 if (token.value != TOKidentifier)
2485 error("(identifier) following 'out' expected, not %s", token.toChars());
2486 f->outId = token.ident;
2487 nextToken();
2488 check(TOKrparen);
2490 if (f->fensure)
2491 error("redundant 'out' statement");
2492 f->fensure = parseStatement(PScurly | PSscope);
2493 goto L1;
2495 default:
2496 error("semicolon expected following function declaration");
2497 break;
2499 linkage = linksave;
2502 /*****************************************
2505 Initializer *Parser::parseInitializer()
2507 StructInitializer *is;
2508 ArrayInitializer *ia;
2509 ExpInitializer *ie;
2510 Expression *e;
2511 Identifier *id;
2512 Initializer *value;
2513 int comma;
2514 Loc loc = this->loc;
2515 Token *t;
2516 int braces;
2518 switch (token.value)
2520 case TOKlcurly:
2521 /* Scan ahead to see if it is a struct initializer or
2522 * a function literal.
2523 * If it contains a ';', it is a function literal.
2524 * Treat { } as a struct initializer.
2526 braces = 1;
2527 for (t = peek(&token); 1; t = peek(t))
2529 switch (t->value)
2531 case TOKsemicolon:
2532 case TOKreturn:
2533 goto Lexpression;
2535 case TOKlcurly:
2536 braces++;
2537 continue;
2539 case TOKrcurly:
2540 if (--braces == 0)
2541 break;
2542 continue;
2544 case TOKeof:
2545 break;
2547 default:
2548 continue;
2550 break;
2553 is = new StructInitializer(loc);
2554 nextToken();
2555 comma = 0;
2556 while (1)
2558 switch (token.value)
2560 case TOKidentifier:
2561 if (comma == 1)
2562 error("comma expected separating field initializers");
2563 t = peek(&token);
2564 if (t->value == TOKcolon)
2566 id = token.ident;
2567 nextToken();
2568 nextToken(); // skip over ':'
2570 else
2571 { id = NULL;
2573 value = parseInitializer();
2574 is->addInit(id, value);
2575 comma = 1;
2576 continue;
2578 case TOKcomma:
2579 nextToken();
2580 comma = 2;
2581 continue;
2583 case TOKrcurly: // allow trailing comma's
2584 nextToken();
2585 break;
2587 case TOKeof:
2588 error("found EOF instead of initializer");
2589 break;
2591 default:
2592 value = parseInitializer();
2593 is->addInit(NULL, value);
2594 comma = 1;
2595 continue;
2596 //error("found '%s' instead of field initializer", token.toChars());
2597 //break;
2599 break;
2601 return is;
2603 case TOKlbracket:
2604 ia = new ArrayInitializer(loc);
2605 nextToken();
2606 comma = 0;
2607 while (1)
2609 switch (token.value)
2611 default:
2612 if (comma == 1)
2613 { error("comma expected separating array initializers, not %s", token.toChars());
2614 nextToken();
2615 break;
2617 e = parseAssignExp();
2618 if (!e)
2619 break;
2620 if (token.value == TOKcolon)
2622 nextToken();
2623 value = parseInitializer();
2625 else
2626 { value = new ExpInitializer(e->loc, e);
2627 e = NULL;
2629 ia->addInit(e, value);
2630 comma = 1;
2631 continue;
2633 case TOKlcurly:
2634 case TOKlbracket:
2635 if (comma == 1)
2636 error("comma expected separating array initializers, not %s", token.toChars());
2637 value = parseInitializer();
2638 ia->addInit(NULL, value);
2639 comma = 1;
2640 continue;
2642 case TOKcomma:
2643 nextToken();
2644 comma = 2;
2645 continue;
2647 case TOKrbracket: // allow trailing comma's
2648 nextToken();
2649 break;
2651 case TOKeof:
2652 error("found '%s' instead of array initializer", token.toChars());
2653 break;
2655 break;
2657 return ia;
2659 case TOKvoid:
2660 t = peek(&token);
2661 if (t->value == TOKsemicolon || t->value == TOKcomma)
2663 nextToken();
2664 return new VoidInitializer(loc);
2666 goto Lexpression;
2668 default:
2669 Lexpression:
2670 e = parseAssignExp();
2671 ie = new ExpInitializer(loc, e);
2672 return ie;
2676 /*****************************************
2677 * Parses default argument initializer expression that is an assign expression,
2678 * with special handling for __FILE__ and __LINE__.
2681 Expression *Parser::parseDefaultInitExp()
2683 if (token.value == TOKfile ||
2684 token.value == TOKline)
2686 Token *t = peek(&token);
2687 if (t->value == TOKcomma || t->value == TOKrparen)
2688 { Expression *e;
2690 if (token.value == TOKfile)
2691 e = new FileInitExp(loc);
2692 else
2693 e = new LineInitExp(loc);
2694 nextToken();
2695 return e;
2699 Expression *e = parseAssignExp();
2700 return e;
2703 /*****************************************
2704 * Input:
2705 * flags PSxxxx
2708 Statement *Parser::parseStatement(int flags)
2709 { Statement *s;
2710 Token *t;
2711 Condition *condition;
2712 Statement *ifbody;
2713 Statement *elsebody;
2714 Loc loc = this->loc;
2716 //printf("parseStatement()\n");
2718 if (flags & PScurly && token.value != TOKlcurly)
2719 error("statement expected to be { }, not %s", token.toChars());
2721 switch (token.value)
2723 case TOKidentifier:
2724 // Need to look ahead to see if it is a declaration, label, or expression
2725 t = peek(&token);
2726 if (t->value == TOKcolon)
2727 { // It's a label
2728 Identifier *ident;
2730 ident = token.ident;
2731 nextToken();
2732 nextToken();
2733 s = parseStatement(PSsemi);
2734 s = new LabelStatement(loc, ident, s);
2735 break;
2737 // fallthrough to TOKdot
2738 case TOKdot:
2739 case TOKtypeof:
2740 if (isDeclaration(&token, 2, TOKreserved, NULL))
2741 goto Ldeclaration;
2742 else
2743 goto Lexp;
2744 break;
2746 case TOKassert:
2747 case TOKthis:
2748 case TOKsuper:
2749 case TOKint32v:
2750 case TOKuns32v:
2751 case TOKint64v:
2752 case TOKuns64v:
2753 case TOKfloat32v:
2754 case TOKfloat64v:
2755 case TOKfloat80v:
2756 case TOKimaginary32v:
2757 case TOKimaginary64v:
2758 case TOKimaginary80v:
2759 case TOKcharv:
2760 case TOKwcharv:
2761 case TOKdcharv:
2762 case TOKnull:
2763 case TOKtrue:
2764 case TOKfalse:
2765 case TOKstring:
2766 case TOKlparen:
2767 case TOKcast:
2768 case TOKmul:
2769 case TOKmin:
2770 case TOKadd:
2771 case TOKplusplus:
2772 case TOKminusminus:
2773 case TOKnew:
2774 case TOKdelete:
2775 case TOKdelegate:
2776 case TOKfunction:
2777 case TOKtypeid:
2778 case TOKis:
2779 case TOKlbracket:
2780 case TOKtraits:
2781 case TOKfile:
2782 case TOKline:
2783 Lexp:
2784 { Expression *exp;
2786 exp = parseExpression();
2787 check(TOKsemicolon, "statement");
2788 s = new ExpStatement(loc, exp);
2789 break;
2792 case TOKstatic:
2793 { // Look ahead to see if it's static assert() or static if()
2794 Token *t;
2796 t = peek(&token);
2797 if (t->value == TOKassert)
2799 nextToken();
2800 s = new StaticAssertStatement(parseStaticAssert());
2801 break;
2803 if (t->value == TOKif)
2805 nextToken();
2806 condition = parseStaticIfCondition();
2807 goto Lcondition;
2809 goto Ldeclaration;
2812 CASE_BASIC_TYPES:
2813 case TOKtypedef:
2814 case TOKalias:
2815 case TOKconst:
2816 case TOKauto:
2817 case TOKextern:
2818 case TOKfinal:
2819 case TOKinvariant:
2820 // case TOKtypeof:
2821 Ldeclaration:
2822 { Array *a;
2824 a = parseDeclarations();
2825 if (a->dim > 1)
2827 Statements *as = new Statements();
2828 as->reserve(a->dim);
2829 for (int i = 0; i < a->dim; i++)
2831 Dsymbol *d = (Dsymbol *)a->data[i];
2832 s = new DeclarationStatement(loc, d);
2833 as->push(s);
2835 s = new CompoundStatement(loc, as);
2837 else if (a->dim == 1)
2839 Dsymbol *d = (Dsymbol *)a->data[0];
2840 s = new DeclarationStatement(loc, d);
2842 else
2843 assert(0);
2844 if (flags & PSscope)
2845 s = new ScopeStatement(loc, s);
2846 break;
2849 case TOKstruct:
2850 case TOKunion:
2851 case TOKclass:
2852 case TOKinterface:
2853 { Dsymbol *d;
2855 d = parseAggregate();
2856 s = new DeclarationStatement(loc, d);
2857 break;
2860 case TOKenum:
2861 { /* Determine if this is a manifest constant declaration,
2862 * or a conventional enum.
2864 Dsymbol *d;
2865 Token *t = peek(&token);
2866 if (t->value == TOKlcurly || t->value == TOKcolon)
2867 d = parseEnum();
2868 else if (t->value != TOKidentifier)
2869 goto Ldeclaration;
2870 else
2872 t = peek(t);
2873 if (t->value == TOKlcurly || t->value == TOKcolon ||
2874 t->value == TOKsemicolon)
2875 d = parseEnum();
2876 else
2877 goto Ldeclaration;
2879 s = new DeclarationStatement(loc, d);
2880 break;
2883 case TOKmixin:
2884 { t = peek(&token);
2885 if (t->value == TOKlparen)
2886 { // mixin(string)
2887 nextToken();
2888 check(TOKlparen, "mixin");
2889 Expression *e = parseAssignExp();
2890 check(TOKrparen);
2891 check(TOKsemicolon);
2892 s = new CompileStatement(loc, e);
2893 break;
2895 Dsymbol *d = parseMixin();
2896 s = new DeclarationStatement(loc, d);
2897 break;
2900 case TOKlcurly:
2901 { Statements *statements;
2903 nextToken();
2904 statements = new Statements();
2905 while (token.value != TOKrcurly)
2907 statements->push(parseStatement(PSsemi | PScurlyscope));
2909 endloc = this->loc;
2910 s = new CompoundStatement(loc, statements);
2911 if (flags & (PSscope | PScurlyscope))
2912 s = new ScopeStatement(loc, s);
2913 nextToken();
2914 break;
2917 case TOKwhile:
2918 { Expression *condition;
2919 Statement *body;
2921 nextToken();
2922 check(TOKlparen);
2923 condition = parseExpression();
2924 check(TOKrparen);
2925 body = parseStatement(PSscope);
2926 s = new WhileStatement(loc, condition, body);
2927 break;
2930 case TOKsemicolon:
2931 if (!(flags & PSsemi))
2932 error("use '{ }' for an empty statement, not a ';'");
2933 nextToken();
2934 s = new ExpStatement(loc, NULL);
2935 break;
2937 case TOKdo:
2938 { Statement *body;
2939 Expression *condition;
2941 nextToken();
2942 body = parseStatement(PSscope);
2943 check(TOKwhile);
2944 check(TOKlparen);
2945 condition = parseExpression();
2946 check(TOKrparen);
2947 s = new DoStatement(loc, body, condition);
2948 break;
2951 case TOKfor:
2953 Statement *init;
2954 Expression *condition;
2955 Expression *increment;
2956 Statement *body;
2958 nextToken();
2959 check(TOKlparen);
2960 if (token.value == TOKsemicolon)
2961 { init = NULL;
2962 nextToken();
2964 else
2965 { init = parseStatement(0);
2967 if (token.value == TOKsemicolon)
2969 condition = NULL;
2970 nextToken();
2972 else
2974 condition = parseExpression();
2975 check(TOKsemicolon, "for condition");
2977 if (token.value == TOKrparen)
2978 { increment = NULL;
2979 nextToken();
2981 else
2982 { increment = parseExpression();
2983 check(TOKrparen);
2985 body = parseStatement(PSscope);
2986 s = new ForStatement(loc, init, condition, increment, body);
2987 if (init)
2988 s = new ScopeStatement(loc, s);
2989 break;
2992 case TOKforeach:
2993 case TOKforeach_reverse:
2995 enum TOK op = token.value;
2996 Arguments *arguments;
2998 Statement *d;
2999 Statement *body;
3000 Expression *aggr;
3002 nextToken();
3003 check(TOKlparen);
3005 arguments = new Arguments();
3007 while (1)
3009 Type *tb;
3010 Identifier *ai = NULL;
3011 Type *at;
3012 unsigned storageClass;
3013 Argument *a;
3015 storageClass = 0;
3016 if (token.value == TOKinout || token.value == TOKref)
3017 { storageClass = STCref;
3018 nextToken();
3020 if (token.value == TOKidentifier)
3022 Token *t = peek(&token);
3023 if (t->value == TOKcomma || t->value == TOKsemicolon)
3024 { ai = token.ident;
3025 at = NULL; // infer argument type
3026 nextToken();
3027 goto Larg;
3030 at = parseType(&ai);
3031 if (!ai)
3032 error("no identifier for declarator %s", at->toChars());
3033 Larg:
3034 a = new Argument(storageClass, at, ai, NULL);
3035 arguments->push(a);
3036 if (token.value == TOKcomma)
3037 { nextToken();
3038 continue;
3040 break;
3042 check(TOKsemicolon);
3044 aggr = parseExpression();
3045 if (token.value == TOKslice && arguments->dim == 1)
3047 Argument *a = (Argument *)arguments->data[0];
3048 delete arguments;
3049 nextToken();
3050 Expression *upr = parseExpression();
3051 check(TOKrparen);
3052 body = parseStatement(0);
3053 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3055 else
3057 check(TOKrparen);
3058 body = parseStatement(0);
3059 s = new ForeachStatement(loc, op, arguments, aggr, body);
3061 break;
3064 case TOKif:
3065 { Argument *arg = NULL;
3066 Expression *condition;
3067 Statement *ifbody;
3068 Statement *elsebody;
3070 nextToken();
3071 check(TOKlparen);
3073 if (token.value == TOKauto)
3075 nextToken();
3076 if (token.value == TOKidentifier)
3078 Token *t = peek(&token);
3079 if (t->value == TOKassign)
3081 arg = new Argument(0, NULL, token.ident, NULL);
3082 nextToken();
3083 nextToken();
3085 else
3086 { error("= expected following auto identifier");
3087 goto Lerror;
3090 else
3091 { error("identifier expected following auto");
3092 goto Lerror;
3095 else if (isDeclaration(&token, 2, TOKassign, NULL))
3097 Type *at;
3098 Identifier *ai;
3100 at = parseType(&ai);
3101 check(TOKassign);
3102 arg = new Argument(0, at, ai, NULL);
3105 // Check for " ident;"
3106 else if (token.value == TOKidentifier)
3108 Token *t = peek(&token);
3109 if (t->value == TOKcomma || t->value == TOKsemicolon)
3111 arg = new Argument(0, NULL, token.ident, NULL);
3112 nextToken();
3113 nextToken();
3114 if (1 || !global.params.useDeprecated)
3115 error("if (v; e) is deprecated, use if (auto v = e)");
3119 condition = parseExpression();
3120 check(TOKrparen);
3121 ifbody = parseStatement(PSscope);
3122 if (token.value == TOKelse)
3124 nextToken();
3125 elsebody = parseStatement(PSscope);
3127 else
3128 elsebody = NULL;
3129 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3130 break;
3133 case TOKscope:
3134 if (peek(&token)->value != TOKlparen)
3135 goto Ldeclaration; // scope used as storage class
3136 nextToken();
3137 check(TOKlparen);
3138 if (token.value != TOKidentifier)
3139 { error("scope identifier expected");
3140 goto Lerror;
3142 else
3143 { TOK t = TOKon_scope_exit;
3144 Identifier *id = token.ident;
3146 if (id == Id::exit)
3147 t = TOKon_scope_exit;
3148 else if (id == Id::failure)
3149 t = TOKon_scope_failure;
3150 else if (id == Id::success)
3151 t = TOKon_scope_success;
3152 else
3153 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3154 nextToken();
3155 check(TOKrparen);
3156 Statement *st = parseStatement(PScurlyscope);
3157 s = new OnScopeStatement(loc, t, st);
3158 break;
3161 case TOKdebug:
3162 nextToken();
3163 condition = parseDebugCondition();
3164 goto Lcondition;
3166 case TOKversion:
3167 nextToken();
3168 condition = parseVersionCondition();
3169 goto Lcondition;
3171 Lcondition:
3172 ifbody = parseStatement(0 /*PSsemi*/);
3173 elsebody = NULL;
3174 if (token.value == TOKelse)
3176 nextToken();
3177 elsebody = parseStatement(0 /*PSsemi*/);
3179 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3180 break;
3182 case TOKpragma:
3183 { Identifier *ident;
3184 Expressions *args = NULL;
3185 Statement *body;
3187 nextToken();
3188 check(TOKlparen);
3189 if (token.value != TOKidentifier)
3190 { error("pragma(identifier expected");
3191 goto Lerror;
3193 ident = token.ident;
3194 nextToken();
3195 if (token.value == TOKcomma)
3196 args = parseArguments(); // pragma(identifier, args...);
3197 else
3198 check(TOKrparen); // pragma(identifier);
3199 if (token.value == TOKsemicolon)
3200 { nextToken();
3201 body = NULL;
3203 else
3204 body = parseStatement(PSsemi);
3205 s = new PragmaStatement(loc, ident, args, body);
3206 break;
3209 case TOKswitch:
3210 { Expression *condition;
3211 Statement *body;
3213 nextToken();
3214 check(TOKlparen);
3215 condition = parseExpression();
3216 check(TOKrparen);
3217 body = parseStatement(PSscope);
3218 s = new SwitchStatement(loc, condition, body);
3219 break;
3222 case TOKcase:
3223 { Expression *exp;
3224 Statements *statements;
3225 Array cases; // array of Expression's
3227 while (1)
3229 nextToken();
3230 exp = parseAssignExp();
3231 cases.push(exp);
3232 if (token.value != TOKcomma)
3233 break;
3235 check(TOKcolon);
3237 statements = new Statements();
3238 while (token.value != TOKcase &&
3239 token.value != TOKdefault &&
3240 token.value != TOKrcurly)
3242 statements->push(parseStatement(PSsemi | PScurlyscope));
3244 s = new CompoundStatement(loc, statements);
3245 s = new ScopeStatement(loc, s);
3247 // Keep cases in order by building the case statements backwards
3248 for (int i = cases.dim; i; i--)
3250 exp = (Expression *)cases.data[i - 1];
3251 s = new CaseStatement(loc, exp, s);
3253 break;
3256 case TOKdefault:
3258 Statements *statements;
3260 nextToken();
3261 check(TOKcolon);
3263 statements = new Statements();
3264 while (token.value != TOKcase &&
3265 token.value != TOKdefault &&
3266 token.value != TOKrcurly)
3268 statements->push(parseStatement(PSsemi | PScurlyscope));
3270 s = new CompoundStatement(loc, statements);
3271 s = new ScopeStatement(loc, s);
3272 s = new DefaultStatement(loc, s);
3273 break;
3276 case TOKreturn:
3277 { Expression *exp;
3279 nextToken();
3280 if (token.value == TOKsemicolon)
3281 exp = NULL;
3282 else
3283 exp = parseExpression();
3284 check(TOKsemicolon, "return statement");
3285 s = new ReturnStatement(loc, exp);
3286 break;
3289 case TOKbreak:
3290 { Identifier *ident;
3292 nextToken();
3293 if (token.value == TOKidentifier)
3294 { ident = token.ident;
3295 nextToken();
3297 else
3298 ident = NULL;
3299 check(TOKsemicolon, "break statement");
3300 s = new BreakStatement(loc, ident);
3301 break;
3304 case TOKcontinue:
3305 { Identifier *ident;
3307 nextToken();
3308 if (token.value == TOKidentifier)
3309 { ident = token.ident;
3310 nextToken();
3312 else
3313 ident = NULL;
3314 check(TOKsemicolon, "continue statement");
3315 s = new ContinueStatement(loc, ident);
3316 break;
3319 case TOKgoto:
3320 { Identifier *ident;
3322 nextToken();
3323 if (token.value == TOKdefault)
3325 nextToken();
3326 s = new GotoDefaultStatement(loc);
3328 else if (token.value == TOKcase)
3330 Expression *exp = NULL;
3332 nextToken();
3333 if (token.value != TOKsemicolon)
3334 exp = parseExpression();
3335 s = new GotoCaseStatement(loc, exp);
3337 else
3339 if (token.value != TOKidentifier)
3340 { error("Identifier expected following goto");
3341 ident = NULL;
3343 else
3344 { ident = token.ident;
3345 nextToken();
3347 s = new GotoStatement(loc, ident);
3349 check(TOKsemicolon, "goto statement");
3350 break;
3353 case TOKsynchronized:
3354 { Expression *exp;
3355 Statement *body;
3357 nextToken();
3358 if (token.value == TOKlparen)
3360 nextToken();
3361 exp = parseExpression();
3362 check(TOKrparen);
3364 else
3365 exp = NULL;
3366 body = parseStatement(PSscope);
3367 s = new SynchronizedStatement(loc, exp, body);
3368 break;
3371 case TOKwith:
3372 { Expression *exp;
3373 Statement *body;
3375 nextToken();
3376 check(TOKlparen);
3377 exp = parseExpression();
3378 check(TOKrparen);
3379 body = parseStatement(PSscope);
3380 s = new WithStatement(loc, exp, body);
3381 break;
3384 case TOKtry:
3385 { Statement *body;
3386 Array *catches = NULL;
3387 Statement *finalbody = NULL;
3389 nextToken();
3390 body = parseStatement(PSscope);
3391 while (token.value == TOKcatch)
3393 Statement *handler;
3394 Catch *c;
3395 Type *t;
3396 Identifier *id;
3397 Loc loc = this->loc;
3399 nextToken();
3400 if (token.value == TOKlcurly)
3402 t = NULL;
3403 id = NULL;
3405 else
3407 check(TOKlparen);
3408 id = NULL;
3409 t = parseType(&id);
3410 check(TOKrparen);
3412 handler = parseStatement(0);
3413 c = new Catch(loc, t, id, handler);
3414 if (!catches)
3415 catches = new Array();
3416 catches->push(c);
3419 if (token.value == TOKfinally)
3420 { nextToken();
3421 finalbody = parseStatement(0);
3424 s = body;
3425 if (!catches && !finalbody)
3426 error("catch or finally expected following try");
3427 else
3428 { if (catches)
3429 s = new TryCatchStatement(loc, body, catches);
3430 if (finalbody)
3431 s = new TryFinallyStatement(loc, s, finalbody);
3433 break;
3436 case TOKthrow:
3437 { Expression *exp;
3439 nextToken();
3440 exp = parseExpression();
3441 check(TOKsemicolon, "throw statement");
3442 s = new ThrowStatement(loc, exp);
3443 break;
3446 case TOKvolatile:
3447 nextToken();
3448 s = parseStatement(PSsemi | PScurlyscope);
3449 if (!global.params.useDeprecated)
3450 error("volatile statements deprecated; used synchronized statements instead");
3451 s = new VolatileStatement(loc, s);
3452 break;
3454 case TOKasm:
3455 { Statements *statements;
3456 Identifier *label;
3457 Loc labelloc;
3458 Token *toklist;
3459 Token **ptoklist;
3461 // Parse the asm block into a sequence of AsmStatements,
3462 // each AsmStatement is one instruction.
3463 // Separate out labels.
3464 // Defer parsing of AsmStatements until semantic processing.
3466 nextToken();
3467 #if GDC_EXTENDED_ASM_SYNTAX
3468 if (token.value == TOKlparen)
3470 nextToken();
3471 s = parseExtAsm(1);
3472 break;
3474 #endif
3475 check(TOKlcurly);
3476 toklist = NULL;
3477 ptoklist = &toklist;
3478 label = NULL;
3479 statements = new Statements();
3480 while (1)
3482 switch (token.value)
3484 case TOKidentifier:
3485 if (!toklist)
3487 // Look ahead to see if it is a label
3488 t = peek(&token);
3489 if (t->value == TOKcolon)
3490 { // It's a label
3491 label = token.ident;
3492 labelloc = this->loc;
3493 nextToken();
3494 nextToken();
3495 continue;
3498 goto Ldefault;
3500 case TOKrcurly:
3501 if (toklist || label)
3503 error("asm statements must end in ';'");
3505 break;
3507 case TOKsemicolon:
3508 s = NULL;
3509 if (toklist || label)
3510 { // Create AsmStatement from list of tokens we've saved
3511 s = new AsmStatement(this->loc, toklist);
3512 toklist = NULL;
3513 ptoklist = &toklist;
3514 if (label)
3515 { s = new LabelStatement(labelloc, label, s);
3516 label = NULL;
3518 statements->push(s);
3520 nextToken();
3521 continue;
3523 case TOKeof:
3524 /* { */
3525 error("matching '}' expected, not end of file");
3526 break;
3528 case TOKlparen:
3529 case TOKstring:
3530 // If the first token is a string or '(', parse as extended asm.
3531 if (! toklist)
3533 s = parseExtAsm(0);
3534 statements->push(s);
3535 continue;
3537 // ...else, drop through.
3539 default:
3540 Ldefault:
3541 *ptoklist = new Token();
3542 memcpy(*ptoklist, &token, sizeof(Token));
3543 ptoklist = &(*ptoklist)->next;
3544 *ptoklist = NULL;
3546 nextToken();
3547 continue;
3549 break;
3551 s = new CompoundStatement(loc, statements);
3552 nextToken();
3553 break;
3556 default:
3557 error("found '%s' instead of statement", token.toChars());
3558 goto Lerror;
3560 Lerror:
3561 while (token.value != TOKrcurly &&
3562 token.value != TOKsemicolon &&
3563 token.value != TOKeof)
3564 nextToken();
3565 if (token.value == TOKsemicolon)
3566 nextToken();
3567 s = NULL;
3568 break;
3571 return s;
3574 Statement *Parser::parseExtAsm(int expect_rparen)
3576 Expression * insnTemplate;
3577 Expressions * args = NULL;
3578 Array * argNames = NULL;
3579 Expressions * argConstraints = NULL;
3580 int nOutputArgs = 0;
3581 Expressions * clobbers = NULL;
3582 bool isInputPhase = false; // Output operands first, then input.
3584 insnTemplate = parseExpression();
3585 if (token.value == TOKrparen || token.value == TOKsemicolon)
3586 goto Ldone;
3587 check(TOKcolon);
3588 while (1) {
3589 Expression * arg = NULL;
3590 Identifier * name = NULL;
3591 Expression * constraint = NULL;
3593 switch (token.value)
3595 case TOKsemicolon:
3596 case TOKrparen:
3597 goto Ldone;
3599 case TOKcolon:
3600 nextToken();
3601 goto LnextPhase;
3603 case TOKeof:
3604 error("unterminated statement");
3606 case TOKlbracket:
3607 nextToken();
3608 if (token.value == TOKidentifier)
3610 name = token.ident;
3611 nextToken();
3613 else
3614 error("expected identifier after '['");
3615 check(TOKrbracket);
3616 // drop through
3617 default:
3618 constraint = parsePrimaryExp();
3619 if (constraint->op != TOKstring)
3620 error("expected constant string constraint for operand");
3621 arg = parseAssignExp();
3622 if (! args)
3624 args = new Expressions;
3625 argConstraints = new Expressions;
3626 argNames = new Array;
3628 args->push(arg);
3629 argNames->push(name);
3630 argConstraints->push(constraint);
3631 if (! isInputPhase)
3632 nOutputArgs++;
3634 if (token.value == TOKcomma)
3635 nextToken();
3636 break;
3638 continue;
3639 LnextPhase:
3640 if (! isInputPhase)
3641 isInputPhase = true;
3642 else
3643 break;
3646 while (1)
3648 Expression * clobber;
3650 switch (token.value)
3652 case TOKsemicolon:
3653 case TOKrparen:
3654 goto Ldone;
3656 case TOKeof:
3657 error("unterminated statement");
3659 default:
3660 clobber = parseAssignExp();
3661 if (clobber->op != TOKstring)
3662 error("expected constant string constraint for clobber name");
3663 if (! clobbers)
3664 clobbers = new Expressions;
3665 clobbers->push(clobber);
3667 if (token.value == TOKcomma)
3668 nextToken();
3669 break;
3672 Ldone:
3673 if (expect_rparen)
3674 check(TOKrparen);
3675 else
3676 check(TOKsemicolon);
3678 return new ExtAsmStatement(loc, insnTemplate, args, argNames,
3679 argConstraints, nOutputArgs, clobbers);
3682 void Parser::check(enum TOK value)
3684 check(loc, value);
3687 void Parser::check(Loc loc, enum TOK value)
3689 if (token.value != value)
3690 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
3691 nextToken();
3694 void Parser::check(enum TOK value, char *string)
3696 if (token.value != value)
3697 error("found '%s' when expecting '%s' following '%s'",
3698 token.toChars(), Token::toChars(value), string);
3699 nextToken();
3702 /************************************
3703 * Determine if the scanner is sitting on the start of a declaration.
3704 * Input:
3705 * needId 0 no identifier
3706 * 1 identifier optional
3707 * 2 must have identifier
3710 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
3712 int haveId = 0;
3714 if ((t->value == TOKconst || t->value == TOKinvariant) &&
3715 peek(t)->value != TOKlparen)
3716 { /* const type
3717 * invariant type
3719 t = peek(t);
3722 if (!isBasicType(&t))
3723 return FALSE;
3724 if (!isDeclarator(&t, &haveId, endtok))
3725 return FALSE;
3726 if ( needId == 1 ||
3727 (needId == 0 && !haveId) ||
3728 (needId == 2 && haveId))
3729 { if (pt)
3730 *pt = t;
3731 return TRUE;
3733 else
3734 return FALSE;
3737 int Parser::isBasicType(Token **pt)
3739 // This code parallels parseBasicType()
3740 Token *t = *pt;
3741 Token *t2;
3742 int parens;
3743 int haveId = 0;
3745 switch (t->value)
3747 CASE_BASIC_TYPES:
3748 t = peek(t);
3749 break;
3751 case TOKidentifier:
3752 t = peek(t);
3753 if (t->value == TOKnot)
3755 goto L4;
3757 goto L3;
3758 while (1)
3761 t = peek(t);
3763 if (t->value == TOKdot)
3765 Ldot:
3766 t = peek(t);
3767 if (t->value != TOKidentifier)
3768 goto Lfalse;
3769 t = peek(t);
3770 if (t->value != TOKnot)
3771 goto L3;
3773 t = peek(t);
3774 if (t->value != TOKlparen)
3775 goto Lfalse;
3776 if (!skipParens(t, &t))
3777 goto Lfalse;
3779 else
3780 break;
3782 break;
3784 case TOKdot:
3785 goto Ldot;
3787 case TOKtypeof:
3788 /* typeof(exp).identifier...
3790 t = peek(t);
3791 if (t->value != TOKlparen)
3792 goto Lfalse;
3793 if (!skipParens(t, &t))
3794 goto Lfalse;
3795 goto L2;
3797 case TOKconst:
3798 case TOKinvariant:
3799 // const(type) or invariant(type)
3800 t = peek(t);
3801 if (t->value != TOKlparen)
3802 goto Lfalse;
3803 t = peek(t);
3804 if (!isDeclaration(t, 0, TOKrparen, &t))
3805 goto Lfalse;
3806 t = peek(t);
3807 break;
3809 default:
3810 goto Lfalse;
3812 *pt = t;
3813 return TRUE;
3815 Lfalse:
3816 return FALSE;
3819 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
3820 { // This code parallels parseDeclarator()
3821 Token *t = *pt;
3822 int parens;
3824 //printf("Parser::isDeclarator()\n");
3825 //t->print();
3826 if (t->value == TOKassign)
3827 return FALSE;
3829 while (1)
3831 parens = FALSE;
3832 switch (t->value)
3834 case TOKmul:
3835 case TOKand:
3836 t = peek(t);
3837 continue;
3839 case TOKlbracket:
3840 t = peek(t);
3841 if (t->value == TOKrbracket)
3843 t = peek(t);
3845 else if (isDeclaration(t, 0, TOKrbracket, &t))
3846 { // It's an associative array declaration
3847 t = peek(t);
3849 else
3851 // [ expression ]
3852 // [ expression .. expression ]
3853 if (!isExpression(&t))
3854 return FALSE;
3855 if (t->value == TOKslice)
3856 { t = peek(t);
3857 if (!isExpression(&t))
3858 return FALSE;
3860 if (t->value != TOKrbracket)
3861 return FALSE;
3862 t = peek(t);
3864 continue;
3866 case TOKidentifier:
3867 if (*haveId)
3868 return FALSE;
3869 *haveId = TRUE;
3870 t = peek(t);
3871 break;
3873 case TOKlparen:
3874 t = peek(t);
3876 if (t->value == TOKrparen)
3877 return FALSE; // () is not a declarator
3879 /* Regard ( identifier ) as not a declarator
3880 * BUG: what about ( *identifier ) in
3881 * f(*p)(x);
3882 * where f is a class instance with overloaded () ?
3883 * Should we just disallow C-style function pointer declarations?
3885 if (t->value == TOKidentifier)
3886 { Token *t2 = peek(t);
3887 if (t2->value == TOKrparen)
3888 return FALSE;
3892 if (!isDeclarator(&t, haveId, TOKrparen))
3893 return FALSE;
3894 t = peek(t);
3895 parens = TRUE;
3896 break;
3898 case TOKdelegate:
3899 case TOKfunction:
3900 t = peek(t);
3901 if (!isParameters(&t))
3902 return FALSE;
3903 continue;
3905 break;
3908 while (1)
3910 switch (t->value)
3912 #if CARRAYDECL
3913 case TOKlbracket:
3914 parens = FALSE;
3915 t = peek(t);
3916 if (t->value == TOKrbracket)
3918 t = peek(t);
3920 else if (isDeclaration(t, 0, TOKrbracket, &t))
3921 { // It's an associative array declaration
3922 t = peek(t);
3924 else
3926 // [ expression ]
3927 if (!isExpression(&t))
3928 return FALSE;
3929 if (t->value != TOKrbracket)
3930 return FALSE;
3931 t = peek(t);
3933 continue;
3934 #endif
3936 case TOKlparen:
3937 parens = FALSE;
3938 if (!isParameters(&t))
3939 return FALSE;
3940 if (t->value == TOKconst || t->value == TOKinvariant)
3941 t = peek(t);
3942 continue;
3944 // Valid tokens that follow a declaration
3945 case TOKrparen:
3946 case TOKrbracket:
3947 case TOKassign:
3948 case TOKcomma:
3949 case TOKsemicolon:
3950 case TOKlcurly:
3951 case TOKin:
3952 // The !parens is to disallow unnecessary parentheses
3953 if (!parens && (endtok == TOKreserved || endtok == t->value))
3954 { *pt = t;
3955 return TRUE;
3957 return FALSE;
3959 default:
3960 return FALSE;
3966 int Parser::isParameters(Token **pt)
3967 { // This code parallels parseParameters()
3968 Token *t = *pt;
3969 int tmp;
3971 //printf("isParameters()\n");
3972 if (t->value != TOKlparen)
3973 return FALSE;
3975 t = peek(t);
3976 for (;1; t = peek(t))
3978 switch (t->value)
3980 case TOKrparen:
3981 break;
3983 case TOKdotdotdot:
3984 t = peek(t);
3985 break;
3987 case TOKin:
3988 case TOKout:
3989 case TOKinout:
3990 case TOKref:
3991 case TOKlazy:
3992 case TOKconst:
3993 case TOKinvariant:
3994 case TOKfinal:
3995 case TOKstatic:
3996 continue;
3998 default:
3999 if (!isBasicType(&t))
4000 return FALSE;
4001 tmp = FALSE;
4002 if (t->value != TOKdotdotdot &&
4003 !isDeclarator(&t, &tmp, TOKreserved))
4004 return FALSE;
4005 if (t->value == TOKassign)
4006 { t = peek(t);
4007 if (!isExpression(&t))
4008 return FALSE;
4010 if (t->value == TOKdotdotdot)
4012 t = peek(t);
4013 break;
4015 if (t->value == TOKcomma)
4017 continue;
4019 break;
4021 break;
4023 if (t->value != TOKrparen)
4024 return FALSE;
4025 t = peek(t);
4026 *pt = t;
4027 return TRUE;
4030 int Parser::isExpression(Token **pt)
4032 // This is supposed to determine if something is an expression.
4033 // What it actually does is scan until a closing right bracket
4034 // is found.
4036 Token *t = *pt;
4037 int brnest = 0;
4038 int panest = 0;
4039 int curlynest = 0;
4041 for (;; t = peek(t))
4043 switch (t->value)
4045 case TOKlbracket:
4046 brnest++;
4047 continue;
4049 case TOKrbracket:
4050 if (--brnest >= 0)
4051 continue;
4052 break;
4054 case TOKlparen:
4055 panest++;
4056 continue;
4058 case TOKcomma:
4059 if (brnest || panest)
4060 continue;
4061 break;
4063 case TOKrparen:
4064 if (--panest >= 0)
4065 continue;
4066 break;
4068 case TOKlcurly:
4069 curlynest++;
4070 continue;
4072 case TOKrcurly:
4073 if (--curlynest >= 0)
4074 continue;
4075 return FALSE;
4077 case TOKslice:
4078 if (brnest)
4079 continue;
4080 break;
4082 case TOKsemicolon:
4083 if (curlynest)
4084 continue;
4085 return FALSE;
4087 case TOKeof:
4088 return FALSE;
4090 default:
4091 continue;
4093 break;
4096 *pt = t;
4097 return TRUE;
4100 /**********************************************
4101 * Skip over
4102 * instance foo.bar(parameters...)
4103 * Output:
4104 * if (pt), *pt is set to the token following the closing )
4105 * Returns:
4106 * 1 it's valid instance syntax
4107 * 0 invalid instance syntax
4110 int Parser::isTemplateInstance(Token *t, Token **pt)
4112 t = peek(t);
4113 if (t->value != TOKdot)
4115 if (t->value != TOKidentifier)
4116 goto Lfalse;
4117 t = peek(t);
4119 while (t->value == TOKdot)
4121 t = peek(t);
4122 if (t->value != TOKidentifier)
4123 goto Lfalse;
4124 t = peek(t);
4126 if (t->value != TOKlparen)
4127 goto Lfalse;
4129 // Skip over the template arguments
4130 while (1)
4132 while (1)
4134 t = peek(t);
4135 switch (t->value)
4137 case TOKlparen:
4138 if (!skipParens(t, &t))
4139 goto Lfalse;
4140 continue;
4141 case TOKrparen:
4142 break;
4143 case TOKcomma:
4144 break;
4145 case TOKeof:
4146 case TOKsemicolon:
4147 goto Lfalse;
4148 default:
4149 continue;
4151 break;
4154 if (t->value != TOKcomma)
4155 break;
4157 if (t->value != TOKrparen)
4158 goto Lfalse;
4159 t = peek(t);
4160 if (pt)
4161 *pt = t;
4162 return 1;
4164 Lfalse:
4165 return 0;
4168 /*******************************************
4169 * Skip parens, brackets.
4170 * Input:
4171 * t is on opening (
4172 * Output:
4173 * *pt is set to closing token, which is ')' on success
4174 * Returns:
4175 * !=0 successful
4176 * 0 some parsing error
4179 int Parser::skipParens(Token *t, Token **pt)
4181 int parens = 0;
4183 while (1)
4185 switch (t->value)
4187 case TOKlparen:
4188 parens++;
4189 break;
4191 case TOKrparen:
4192 parens--;
4193 if (parens < 0)
4194 goto Lfalse;
4195 if (parens == 0)
4196 goto Ldone;
4197 break;
4199 case TOKeof:
4200 case TOKsemicolon:
4201 goto Lfalse;
4203 default:
4204 break;
4206 t = peek(t);
4209 Ldone:
4210 if (*pt)
4211 *pt = t;
4212 return 1;
4214 Lfalse:
4215 return 0;
4218 /********************************* Expression Parser ***************************/
4220 Expression *Parser::parsePrimaryExp()
4221 { Expression *e;
4222 Type *t;
4223 Identifier *id;
4224 enum TOK save;
4225 Loc loc = this->loc;
4227 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4228 switch (token.value)
4230 case TOKidentifier:
4231 id = token.ident;
4232 nextToken();
4233 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4234 { // identifier!(template-argument-list)
4235 TemplateInstance *tempinst;
4237 tempinst = new TemplateInstance(loc, id);
4238 nextToken();
4239 tempinst->tiargs = parseTemplateArgumentList();
4240 e = new ScopeExp(loc, tempinst);
4242 else
4243 e = new IdentifierExp(loc, id);
4244 break;
4246 case TOKdollar:
4247 if (!inBrackets)
4248 error("'$' is valid only inside [] of index or slice");
4249 e = new DollarExp(loc);
4250 nextToken();
4251 break;
4253 case TOKdot:
4254 // Signal global scope '.' operator with "" identifier
4255 e = new IdentifierExp(loc, Id::empty);
4256 break;
4258 case TOKthis:
4259 e = new ThisExp(loc);
4260 nextToken();
4261 break;
4263 case TOKsuper:
4264 e = new SuperExp(loc);
4265 nextToken();
4266 break;
4268 case TOKint32v:
4269 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
4270 nextToken();
4271 break;
4273 case TOKuns32v:
4274 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
4275 nextToken();
4276 break;
4278 case TOKint64v:
4279 e = new IntegerExp(loc, token.int64value, Type::tint64);
4280 nextToken();
4281 break;
4283 case TOKuns64v:
4284 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4285 nextToken();
4286 break;
4288 case TOKfloat32v:
4289 e = new RealExp(loc, token.float80value, Type::tfloat32);
4290 nextToken();
4291 break;
4293 case TOKfloat64v:
4294 e = new RealExp(loc, token.float80value, Type::tfloat64);
4295 nextToken();
4296 break;
4298 case TOKfloat80v:
4299 e = new RealExp(loc, token.float80value, Type::tfloat80);
4300 nextToken();
4301 break;
4303 case TOKimaginary32v:
4304 e = new RealExp(loc, token.float80value, Type::timaginary32);
4305 nextToken();
4306 break;
4308 case TOKimaginary64v:
4309 e = new RealExp(loc, token.float80value, Type::timaginary64);
4310 nextToken();
4311 break;
4313 case TOKimaginary80v:
4314 e = new RealExp(loc, token.float80value, Type::timaginary80);
4315 nextToken();
4316 break;
4318 case TOKnull:
4319 e = new NullExp(loc);
4320 nextToken();
4321 break;
4323 case TOKfile:
4324 { char *s = loc.filename ? loc.filename : mod->ident->toChars();
4325 e = new StringExp(loc, s, strlen(s), 0);
4326 nextToken();
4327 break;
4330 case TOKline:
4331 e = new IntegerExp(loc, loc.linnum, Type::tint32);
4332 nextToken();
4333 break;
4335 case TOKtrue:
4336 e = new IntegerExp(loc, 1, Type::tbool);
4337 nextToken();
4338 break;
4340 case TOKfalse:
4341 e = new IntegerExp(loc, 0, Type::tbool);
4342 nextToken();
4343 break;
4345 case TOKcharv:
4346 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tchar);
4347 nextToken();
4348 break;
4350 case TOKwcharv:
4351 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::twchar);
4352 nextToken();
4353 break;
4355 case TOKdcharv:
4356 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
4357 nextToken();
4358 break;
4360 case TOKstring:
4361 { unsigned char *s;
4362 unsigned len;
4363 unsigned char postfix;
4365 // cat adjacent strings
4366 s = token.ustring;
4367 len = token.len;
4368 postfix = token.postfix;
4369 while (1)
4371 nextToken();
4372 if (token.value == TOKstring)
4373 { unsigned len1;
4374 unsigned len2;
4375 unsigned char *s2;
4377 if (token.postfix)
4378 { if (token.postfix != postfix)
4379 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4380 postfix = token.postfix;
4383 len1 = len;
4384 len2 = token.len;
4385 len = len1 + len2;
4386 s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
4387 memcpy(s2, s, len1 * sizeof(unsigned char));
4388 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
4389 s = s2;
4391 else
4392 break;
4394 e = new StringExp(loc, s, len, postfix);
4395 break;
4398 CASE_BASIC_TYPES_X(t):
4399 nextToken();
4401 check(TOKdot, t->toChars());
4402 if (token.value != TOKidentifier)
4403 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
4404 goto Lerr;
4406 e = new TypeDotIdExp(loc, t, token.ident);
4407 nextToken();
4408 break;
4410 case TOKtypeof:
4412 t = parseTypeof();
4413 if (token.value == TOKdot)
4414 goto L1;
4415 e = new TypeExp(loc, t);
4416 break;
4419 case TOKtypeid:
4420 { Type *t;
4422 nextToken();
4423 check(TOKlparen, "typeid");
4424 t = parseType(); // ( type )
4425 check(TOKrparen);
4426 e = new TypeidExp(loc, t);
4427 break;
4430 case TOKtraits:
4431 { /* __traits(identifier, args...)
4433 Identifier *ident;
4434 Objects *args = NULL;
4436 nextToken();
4437 check(TOKlparen);
4438 if (token.value != TOKidentifier)
4439 { error("__traits(identifier, args...) expected");
4440 goto Lerr;
4442 ident = token.ident;
4443 nextToken();
4444 if (token.value == TOKcomma)
4445 args = parseTemplateArgumentList2(); // __traits(identifier, args...)
4446 else
4447 check(TOKrparen); // __traits(identifier)
4449 e = new TraitsExp(loc, ident, args);
4450 break;
4453 case TOKis:
4454 { Type *targ;
4455 Identifier *ident = NULL;
4456 Type *tspec = NULL;
4457 enum TOK tok = TOKreserved;
4458 enum TOK tok2 = TOKreserved;
4459 TemplateParameters *tpl = NULL;
4460 Loc loc = this->loc;
4462 nextToken();
4463 if (token.value == TOKlparen)
4465 nextToken();
4466 targ = parseType(&ident);
4467 if (token.value == TOKcolon || token.value == TOKequal)
4469 tok = token.value;
4470 nextToken();
4471 if (tok == TOKequal &&
4472 (token.value == TOKtypedef ||
4473 token.value == TOKstruct ||
4474 token.value == TOKunion ||
4475 token.value == TOKclass ||
4476 token.value == TOKsuper ||
4477 token.value == TOKenum ||
4478 token.value == TOKinterface ||
4479 token.value == TOKconst && peek(&token)->value == TOKrparen ||
4480 token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
4481 token.value == TOKfunction ||
4482 token.value == TOKdelegate ||
4483 token.value == TOKreturn))
4485 tok2 = token.value;
4486 nextToken();
4488 else
4490 tspec = parseType();
4493 if (ident && tspec)
4495 if (token.value == TOKcomma)
4496 tpl = parseTemplateParameterList(1);
4497 else
4498 { tpl = new TemplateParameters();
4499 check(TOKrparen);
4501 TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
4502 tpl->insert(0, tp);
4504 else
4505 check(TOKrparen);
4507 else
4508 { error("(type identifier : specialization) expected following is");
4509 goto Lerr;
4511 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
4512 break;
4515 case TOKassert:
4516 { Expression *msg = NULL;
4518 nextToken();
4519 check(TOKlparen, "assert");
4520 e = parseAssignExp();
4521 if (token.value == TOKcomma)
4522 { nextToken();
4523 msg = parseAssignExp();
4525 check(TOKrparen);
4526 e = new AssertExp(loc, e, msg);
4527 break;
4530 case TOKmixin:
4532 nextToken();
4533 check(TOKlparen, "mixin");
4534 e = parseAssignExp();
4535 check(TOKrparen);
4536 e = new CompileExp(loc, e);
4537 break;
4540 case TOKimport:
4542 nextToken();
4543 check(TOKlparen, "import");
4544 e = parseAssignExp();
4545 check(TOKrparen);
4546 e = new FileExp(loc, e);
4547 break;
4550 case TOKlparen:
4551 if (peekPastParen(&token)->value == TOKlcurly)
4552 { // (arguments) { statements... }
4553 save = TOKdelegate;
4554 goto case_delegate;
4556 // ( expression )
4557 nextToken();
4558 e = parseExpression();
4559 check(loc, TOKrparen);
4560 break;
4562 case TOKlbracket:
4563 { /* Parse array literals and associative array literals:
4564 * [ value, value, value ... ]
4565 * [ key:value, key:value, key:value ... ]
4567 Expressions *values = new Expressions();
4568 Expressions *keys = NULL;
4570 nextToken();
4571 if (token.value != TOKrbracket)
4573 while (1)
4575 Expression *e = parseAssignExp();
4576 if (token.value == TOKcolon && (keys || values->dim == 0))
4577 { nextToken();
4578 if (!keys)
4579 keys = new Expressions();
4580 keys->push(e);
4581 e = parseAssignExp();
4583 else if (keys)
4584 { error("'key:value' expected for associative array literal");
4585 delete keys;
4586 keys = NULL;
4588 values->push(e);
4589 if (token.value == TOKrbracket)
4590 break;
4591 check(TOKcomma);
4594 check(TOKrbracket);
4596 if (keys)
4597 e = new AssocArrayLiteralExp(loc, keys, values);
4598 else
4599 e = new ArrayLiteralExp(loc, values);
4600 break;
4603 case TOKlcurly:
4604 // { statements... }
4605 save = TOKdelegate;
4606 goto case_delegate;
4608 case TOKfunction:
4609 case TOKdelegate:
4610 save = token.value;
4611 nextToken();
4612 case_delegate:
4614 /* function type(parameters) { body }
4615 * delegate type(parameters) { body }
4616 * (parameters) { body }
4617 * { body }
4619 Arguments *arguments;
4620 int varargs;
4621 FuncLiteralDeclaration *fd;
4622 Type *t;
4623 bool isnothrow = false;
4624 bool ispure = false;
4626 if (token.value == TOKlcurly)
4628 t = NULL;
4629 varargs = 0;
4630 arguments = new Arguments();
4632 else
4634 if (token.value == TOKlparen)
4635 t = NULL;
4636 else
4638 t = parseBasicType();
4639 t = parseBasicType2(t); // function return type
4641 arguments = parseParameters(&varargs);
4642 while (1)
4644 if (token.value == TOKpure)
4645 ispure = true;
4646 else if (token.value == TOKnothrow)
4647 isnothrow = true;
4648 else
4649 break;
4650 nextToken();
4653 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
4654 tf->ispure = ispure;
4655 tf->isnothrow = isnothrow;
4656 fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
4657 parseContracts(fd);
4658 e = new FuncExp(loc, fd);
4659 break;
4662 default:
4663 error("expression expected, not '%s'", token.toChars());
4664 Lerr:
4665 // Anything for e, as long as it's not NULL
4666 e = new IntegerExp(loc, 0, Type::tint32);
4667 nextToken();
4668 break;
4670 return parsePostExp(e);
4673 Expression *Parser::parsePostExp(Expression *e)
4675 Loc loc;
4677 while (1)
4679 loc = this->loc;
4680 switch (token.value)
4682 case TOKdot:
4683 nextToken();
4684 if (token.value == TOKidentifier)
4685 { Identifier *id = token.ident;
4687 nextToken();
4688 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4689 { // identifier!(template-argument-list)
4690 TemplateInstance *tempinst;
4692 tempinst = new TemplateInstance(loc, id);
4693 nextToken();
4694 tempinst->tiargs = parseTemplateArgumentList();
4695 e = new DotTemplateInstanceExp(loc, e, tempinst);
4697 else
4698 e = new DotIdExp(loc, e, id);
4699 continue;
4701 else if (token.value == TOKnew)
4703 e = parseNewExp(e);
4704 continue;
4706 else
4707 error("identifier expected following '.', not '%s'", token.toChars());
4708 break;
4710 case TOKplusplus:
4711 e = new PostExp(TOKplusplus, loc, e);
4712 break;
4714 case TOKminusminus:
4715 e = new PostExp(TOKminusminus, loc, e);
4716 break;
4718 case TOKlparen:
4719 e = new CallExp(loc, e, parseArguments());
4720 continue;
4722 case TOKlbracket:
4723 { // array dereferences:
4724 // array[index]
4725 // array[]
4726 // array[lwr .. upr]
4727 Expression *index;
4728 Expression *upr;
4730 inBrackets++;
4731 nextToken();
4732 if (token.value == TOKrbracket)
4733 { // array[]
4734 e = new SliceExp(loc, e, NULL, NULL);
4735 nextToken();
4737 else
4739 index = parseAssignExp();
4740 if (token.value == TOKslice)
4741 { // array[lwr .. upr]
4742 nextToken();
4743 upr = parseAssignExp();
4744 e = new SliceExp(loc, e, index, upr);
4746 else
4747 { // array[index, i2, i3, i4, ...]
4748 Expressions *arguments = new Expressions();
4749 arguments->push(index);
4750 if (token.value == TOKcomma)
4752 nextToken();
4753 while (1)
4754 { Expression *arg;
4756 arg = parseAssignExp();
4757 arguments->push(arg);
4758 if (token.value == TOKrbracket)
4759 break;
4760 check(TOKcomma);
4763 e = new ArrayExp(loc, e, arguments);
4765 check(TOKrbracket);
4766 inBrackets--;
4768 continue;
4771 default:
4772 return e;
4774 nextToken();
4778 Expression *Parser::parseUnaryExp()
4779 { Expression *e;
4780 Loc loc = this->loc;
4782 switch (token.value)
4784 case TOKand:
4785 nextToken();
4786 e = parseUnaryExp();
4787 e = new AddrExp(loc, e);
4788 break;
4790 case TOKplusplus:
4791 nextToken();
4792 e = parseUnaryExp();
4793 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
4794 break;
4796 case TOKminusminus:
4797 nextToken();
4798 e = parseUnaryExp();
4799 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
4800 break;
4802 case TOKmul:
4803 nextToken();
4804 e = parseUnaryExp();
4805 e = new PtrExp(loc, e);
4806 break;
4808 case TOKmin:
4809 nextToken();
4810 e = parseUnaryExp();
4811 e = new NegExp(loc, e);
4812 break;
4814 case TOKadd:
4815 nextToken();
4816 e = parseUnaryExp();
4817 e = new UAddExp(loc, e);
4818 break;
4820 case TOKnot:
4821 nextToken();
4822 e = parseUnaryExp();
4823 e = new NotExp(loc, e);
4824 break;
4826 case TOKtilde:
4827 nextToken();
4828 e = parseUnaryExp();
4829 e = new ComExp(loc, e);
4830 break;
4832 case TOKdelete:
4833 nextToken();
4834 e = parseUnaryExp();
4835 e = new DeleteExp(loc, e);
4836 break;
4838 case TOKnew:
4839 e = parseNewExp(NULL);
4840 break;
4842 case TOKcast: // cast(type) expression
4843 { Type *t;
4845 nextToken();
4846 check(TOKlparen);
4847 /* Look for cast(const) and cast(invariant)
4849 if ((token.value == TOKconst || token.value == TOKinvariant) &&
4850 peek(&token)->value == TOKrparen)
4851 { enum TOK tok = token.value;
4852 nextToken();
4853 nextToken();
4854 e = parseUnaryExp();
4855 e = new CastExp(loc, e, tok);
4857 else
4859 t = parseType(); // ( type )
4860 check(TOKrparen);
4861 e = parseUnaryExp();
4862 e = new CastExp(loc, e, t);
4864 break;
4867 case TOKlparen:
4868 { Token *tk;
4870 tk = peek(&token);
4871 #if CCASTSYNTAX
4872 // If cast
4873 if (isDeclaration(tk, 0, TOKrparen, &tk))
4875 tk = peek(tk); // skip over right parenthesis
4876 switch (tk->value)
4878 case TOKdot:
4879 case TOKplusplus:
4880 case TOKminusminus:
4881 case TOKnot:
4882 case TOKdelete:
4883 case TOKnew:
4884 case TOKlparen:
4885 case TOKidentifier:
4886 case TOKthis:
4887 case TOKsuper:
4888 case TOKint32v:
4889 case TOKuns32v:
4890 case TOKint64v:
4891 case TOKuns64v:
4892 case TOKfloat32v:
4893 case TOKfloat64v:
4894 case TOKfloat80v:
4895 case TOKimaginary32v:
4896 case TOKimaginary64v:
4897 case TOKimaginary80v:
4898 case TOKnull:
4899 case TOKtrue:
4900 case TOKfalse:
4901 case TOKcharv:
4902 case TOKwcharv:
4903 case TOKdcharv:
4904 case TOKstring:
4905 #if 0
4906 case TOKtilde:
4907 case TOKand:
4908 case TOKmul:
4909 case TOKmin:
4910 case TOKadd:
4911 #endif
4912 case TOKfunction:
4913 case TOKdelegate:
4914 case TOKtypeof:
4915 case TOKfile:
4916 case TOKline:
4917 CASE_BASIC_TYPES: // (type)int.size
4918 { // (type) una_exp
4919 Type *t;
4921 nextToken();
4922 t = parseType();
4923 check(TOKrparen);
4925 // if .identifier
4926 if (token.value == TOKdot)
4928 nextToken();
4929 if (token.value != TOKidentifier)
4930 { error("Identifier expected following (type).");
4931 return NULL;
4933 e = new TypeDotIdExp(loc, t, token.ident);
4934 nextToken();
4935 e = parsePostExp(e);
4937 else
4939 e = parseUnaryExp();
4940 e = new CastExp(loc, e, t);
4941 error("C style cast illegal, use %s", e->toChars());
4943 return e;
4947 #endif
4948 e = parsePrimaryExp();
4949 break;
4951 default:
4952 e = parsePrimaryExp();
4953 break;
4955 assert(e);
4956 return e;
4959 Expression *Parser::parseMulExp()
4960 { Expression *e;
4961 Expression *e2;
4962 Loc loc = this->loc;
4964 e = parseUnaryExp();
4965 while (1)
4967 switch (token.value)
4969 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
4970 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
4971 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
4973 default:
4974 break;
4976 break;
4978 return e;
4981 Expression *Parser::parseAddExp()
4982 { Expression *e;
4983 Expression *e2;
4984 Loc loc = this->loc;
4986 e = parseMulExp();
4987 while (1)
4989 switch (token.value)
4991 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
4992 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
4993 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
4995 default:
4996 break;
4998 break;
5000 return e;
5003 Expression *Parser::parseShiftExp()
5004 { Expression *e;
5005 Expression *e2;
5006 Loc loc = this->loc;
5008 e = parseAddExp();
5009 while (1)
5011 switch (token.value)
5013 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5014 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5015 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5017 default:
5018 break;
5020 break;
5022 return e;
5025 Expression *Parser::parseRelExp()
5026 { Expression *e;
5027 Expression *e2;
5028 enum TOK op;
5029 Loc loc = this->loc;
5031 e = parseShiftExp();
5032 while (1)
5034 switch (token.value)
5036 case TOKlt:
5037 case TOKle:
5038 case TOKgt:
5039 case TOKge:
5040 case TOKunord:
5041 case TOKlg:
5042 case TOKleg:
5043 case TOKule:
5044 case TOKul:
5045 case TOKuge:
5046 case TOKug:
5047 case TOKue:
5048 op = token.value;
5049 nextToken();
5050 e2 = parseShiftExp();
5051 e = new CmpExp(op, loc, e, e2);
5052 continue;
5054 case TOKin:
5055 nextToken();
5056 e2 = parseShiftExp();
5057 e = new InExp(loc, e, e2);
5058 continue;
5060 default:
5061 break;
5063 break;
5065 return e;
5068 Expression *Parser::parseEqualExp()
5069 { Expression *e;
5070 Expression *e2;
5071 Token *t;
5072 Loc loc = this->loc;
5074 e = parseRelExp();
5075 while (1)
5076 { enum TOK value = token.value;
5078 switch (value)
5080 case TOKequal:
5081 case TOKnotequal:
5082 nextToken();
5083 e2 = parseRelExp();
5084 e = new EqualExp(value, loc, e, e2);
5085 continue;
5087 case TOKidentity:
5088 error("'===' is no longer legal, use 'is' instead");
5089 goto L1;
5091 case TOKnotidentity:
5092 error("'!==' is no longer legal, use '!is' instead");
5093 goto L1;
5095 case TOKis:
5096 value = TOKidentity;
5097 goto L1;
5099 case TOKnot:
5100 // Attempt to identify '!is'
5101 t = peek(&token);
5102 if (t->value != TOKis)
5103 break;
5104 nextToken();
5105 value = TOKnotidentity;
5106 goto L1;
5109 nextToken();
5110 e2 = parseRelExp();
5111 e = new IdentityExp(value, loc, e, e2);
5112 continue;
5114 default:
5115 break;
5117 break;
5119 return e;
5122 Expression *Parser::parseCmpExp()
5123 { Expression *e;
5124 Expression *e2;
5125 Token *t;
5126 Loc loc = this->loc;
5128 e = parseShiftExp();
5129 enum TOK op = token.value;
5131 switch (op)
5133 case TOKequal:
5134 case TOKnotequal:
5135 nextToken();
5136 e2 = parseShiftExp();
5137 e = new EqualExp(op, loc, e, e2);
5138 break;
5140 case TOKis:
5141 op = TOKidentity;
5142 goto L1;
5144 case TOKnot:
5145 // Attempt to identify '!is'
5146 t = peek(&token);
5147 if (t->value != TOKis)
5148 break;
5149 nextToken();
5150 op = TOKnotidentity;
5151 goto L1;
5154 nextToken();
5155 e2 = parseShiftExp();
5156 e = new IdentityExp(op, loc, e, e2);
5157 break;
5159 case TOKlt:
5160 case TOKle:
5161 case TOKgt:
5162 case TOKge:
5163 case TOKunord:
5164 case TOKlg:
5165 case TOKleg:
5166 case TOKule:
5167 case TOKul:
5168 case TOKuge:
5169 case TOKug:
5170 case TOKue:
5171 nextToken();
5172 e2 = parseShiftExp();
5173 e = new CmpExp(op, loc, e, e2);
5174 break;
5176 case TOKin:
5177 nextToken();
5178 e2 = parseShiftExp();
5179 e = new InExp(loc, e, e2);
5180 break;
5182 default:
5183 break;
5185 return e;
5188 Expression *Parser::parseAndExp()
5189 { Expression *e;
5190 Expression *e2;
5191 Loc loc = this->loc;
5193 if (global.params.Dversion == 1)
5195 e = parseEqualExp();
5196 while (token.value == TOKand)
5198 nextToken();
5199 e2 = parseEqualExp();
5200 e = new AndExp(loc,e,e2);
5201 loc = this->loc;
5204 else
5206 e = parseCmpExp();
5207 while (token.value == TOKand)
5209 nextToken();
5210 e2 = parseCmpExp();
5211 e = new AndExp(loc,e,e2);
5212 loc = this->loc;
5215 return e;
5218 Expression *Parser::parseXorExp()
5219 { Expression *e;
5220 Expression *e2;
5221 Loc loc = this->loc;
5223 e = parseAndExp();
5224 while (token.value == TOKxor)
5226 nextToken();
5227 e2 = parseAndExp();
5228 e = new XorExp(loc, e, e2);
5230 return e;
5233 Expression *Parser::parseOrExp()
5234 { Expression *e;
5235 Expression *e2;
5236 Loc loc = this->loc;
5238 e = parseXorExp();
5239 while (token.value == TOKor)
5241 nextToken();
5242 e2 = parseXorExp();
5243 e = new OrExp(loc, e, e2);
5245 return e;
5248 Expression *Parser::parseAndAndExp()
5249 { Expression *e;
5250 Expression *e2;
5251 Loc loc = this->loc;
5253 e = parseOrExp();
5254 while (token.value == TOKandand)
5256 nextToken();
5257 e2 = parseOrExp();
5258 e = new AndAndExp(loc, e, e2);
5260 return e;
5263 Expression *Parser::parseOrOrExp()
5264 { Expression *e;
5265 Expression *e2;
5266 Loc loc = this->loc;
5268 e = parseAndAndExp();
5269 while (token.value == TOKoror)
5271 nextToken();
5272 e2 = parseAndAndExp();
5273 e = new OrOrExp(loc, e, e2);
5275 return e;
5278 Expression *Parser::parseCondExp()
5279 { Expression *e;
5280 Expression *e1;
5281 Expression *e2;
5282 Loc loc = this->loc;
5284 e = parseOrOrExp();
5285 if (token.value == TOKquestion)
5287 nextToken();
5288 e1 = parseExpression();
5289 check(TOKcolon);
5290 e2 = parseCondExp();
5291 e = new CondExp(loc, e, e1, e2);
5293 return e;
5296 Expression *Parser::parseAssignExp()
5297 { Expression *e;
5298 Expression *e2;
5299 Loc loc;
5301 e = parseCondExp();
5302 while (1)
5304 loc = this->loc;
5305 switch (token.value)
5307 #define X(tok,ector) \
5308 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5310 X(TOKassign, AssignExp);
5311 X(TOKaddass, AddAssignExp);
5312 X(TOKminass, MinAssignExp);
5313 X(TOKmulass, MulAssignExp);
5314 X(TOKdivass, DivAssignExp);
5315 X(TOKmodass, ModAssignExp);
5316 X(TOKandass, AndAssignExp);
5317 X(TOKorass, OrAssignExp);
5318 X(TOKxorass, XorAssignExp);
5319 X(TOKshlass, ShlAssignExp);
5320 X(TOKshrass, ShrAssignExp);
5321 X(TOKushrass, UshrAssignExp);
5322 X(TOKcatass, CatAssignExp);
5324 #undef X
5325 default:
5326 break;
5328 break;
5330 return e;
5333 Expression *Parser::parseExpression()
5334 { Expression *e;
5335 Expression *e2;
5336 Loc loc = this->loc;
5338 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5339 e = parseAssignExp();
5340 while (token.value == TOKcomma)
5342 nextToken();
5343 e2 = parseAssignExp();
5344 e = new CommaExp(loc, e, e2);
5345 loc = this->loc;
5347 return e;
5351 /*************************
5352 * Collect argument list.
5353 * Assume current token is '(' or '['.
5356 Expressions *Parser::parseArguments()
5357 { // function call
5358 Expressions *arguments;
5359 Expression *arg;
5360 enum TOK endtok;
5362 arguments = new Expressions();
5363 if (token.value == TOKlbracket)
5364 endtok = TOKrbracket;
5365 else
5366 endtok = TOKrparen;
5369 nextToken();
5370 if (token.value != endtok)
5372 while (1)
5374 arg = parseAssignExp();
5375 arguments->push(arg);
5376 if (token.value == endtok)
5377 break;
5378 check(TOKcomma);
5381 check(endtok);
5383 return arguments;
5386 /*******************************************
5389 Expression *Parser::parseNewExp(Expression *thisexp)
5390 { Type *t;
5391 Expressions *newargs;
5392 Expressions *arguments = NULL;
5393 Expression *e;
5394 Loc loc = this->loc;
5396 nextToken();
5397 newargs = NULL;
5398 if (token.value == TOKlparen)
5400 newargs = parseArguments();
5403 // An anonymous nested class starts with "class"
5404 if (token.value == TOKclass)
5406 nextToken();
5407 if (token.value == TOKlparen)
5408 arguments = parseArguments();
5410 BaseClasses *baseclasses = NULL;
5411 if (token.value != TOKlcurly)
5412 baseclasses = parseBaseClasses();
5414 Identifier *id = NULL;
5415 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
5417 if (token.value != TOKlcurly)
5418 { error("{ members } expected for anonymous class");
5419 cd->members = NULL;
5421 else
5423 nextToken();
5424 Array *decl = parseDeclDefs(0);
5425 if (token.value != TOKrcurly)
5426 error("class member expected");
5427 nextToken();
5428 cd->members = decl;
5431 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5433 return e;
5436 t = parseBasicType();
5437 t = parseBasicType2(t);
5438 if (t->ty == Taarray)
5439 { TypeAArray *taa = (TypeAArray *)t;
5440 Type *index = taa->index;
5442 Expression *e = index->toExpression();
5443 if (e)
5444 { arguments = new Expressions();
5445 arguments->push(e);
5446 t = new TypeDArray(taa->next);
5448 else
5450 error("need size of rightmost array, not type %s", index->toChars());
5451 return new NullExp(loc);
5454 else if (t->ty == Tsarray)
5456 TypeSArray *tsa = (TypeSArray *)t;
5457 Expression *e = tsa->dim;
5459 arguments = new Expressions();
5460 arguments->push(e);
5461 t = new TypeDArray(tsa->next);
5463 else if (token.value == TOKlparen)
5465 arguments = parseArguments();
5467 e = new NewExp(loc, thisexp, newargs, t, arguments);
5468 return e;
5471 /**********************************************
5474 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
5476 s->addComment(combineComments(blockComment, token.lineComment));
5480 /********************************* ***************************/