Special unchecked nulls for d
[delight/core.git] / dmd2 / parse.c
blobe63a597a7b045a8a6d47e1866b3e9b29efc49fec
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, module->isDltFile)
64 //printf("Parser::Parser()\n");
65 md = NULL;
66 linkage = LINKd;
67 dltNormalMode = FALSE;
68 endloc = 0;
69 inBrackets = 0;
70 startBlockTok = TOKlcurly;
71 //nextToken(); // start up the scanner
74 DltParser::DltParser(Module *module, unsigned char *base, unsigned length, int doDocComment)
75 : Parser(module, base, length, doDocComment)
77 //printf("DltParser::DltParser(%s)\n", module->ident->string);
78 startBlockTok = TOKcolon;
79 dltNormalMode = TRUE; // becomes false if we find a "module dlt.*"
82 Array *Parser::parseModule()
84 Array *decldefs;
86 // ModuleDeclation leads off
87 optionalEndline();
88 if (token.value == TOKmodule)
90 unsigned char *comment = token.blockComment;
92 nextToken();
93 if (token.value != TOKidentifier)
94 { error("Identifier expected following module");
95 goto Lerr;
97 else
99 Array *a = NULL;
100 Identifier *id;
102 id = token.ident;
104 if (dltSyntax && id == Id::dlt)
105 dltNormalMode = FALSE;
107 while (nextToken() == TOKdot)
109 if (!a)
110 a = new Array();
111 a->push(id);
112 nextToken();
113 if (token.value != TOKidentifier)
114 { error("Identifier expected following package");
115 goto Lerr;
117 id = token.ident;
120 md = new ModuleDeclaration(a, id);
122 TOK end = dltSyntax ? TOKendline : TOKsemicolon;
123 if (token.value != end)
124 error("%s expected following module declaration instead of %s", Token::toChars(end), token.toChars());
126 nextToken();
127 addComment(mod, comment);
131 decldefs = parseDeclDefs(0);
132 if (token.value != TOKeof)
133 { error("unrecognized declaration '%s'", token.toChars());
134 goto Lerr;
137 if (dltNormalMode)
139 // Check for global variables
140 for (int i = 0; i < decldefs->dim; i++)
142 Dsymbol *d = (Dsymbol *) decldefs->data[i];
143 if (d->isVarDeclaration()) {
144 error("no global variables (%s) allowed in Delight; "
145 "try const, or put it in a class", d->toChars());
150 return decldefs;
152 Lerr:
153 while (token.value != TOKsemicolon && token.value != TOKeof)
154 nextToken();
155 nextToken();
156 return new Array();
159 Array *Parser::parseDeclDefs(int once)
160 { Dsymbol *s;
161 Array *decldefs;
162 Array *a;
163 Array *aelse;
164 enum PROT prot;
165 unsigned stc;
166 unsigned storageClass;
167 Condition *condition;
168 unsigned char *comment;
170 //printf("Parser::parseDeclDefs()\n");
171 decldefs = new Array();
174 comment = token.blockComment;
175 storageClass = 0;
176 switch (token.value)
178 case TOKendline:
179 nextToken();
180 continue;
181 case TOKenum:
182 { /* Determine if this is a manifest constant declaration,
183 * or a conventional enum.
185 Token *t = peek(&token);
186 if (t->value == TOKlcurly || t->value == TOKcolon)
187 s = parseEnum();
188 else if (t->value != TOKidentifier)
189 goto Ldeclaration;
190 else
192 t = peek(t);
193 if (t->value == TOKlcurly || t->value == TOKcolon ||
194 t->value == TOKsemicolon)
195 s = parseEnum();
196 else
197 goto Ldeclaration;
199 break;
202 case TOKstruct:
203 case TOKunion:
204 case TOKclass:
205 case TOKinterface:
206 s = parseAggregate();
207 break;
209 case TOKimport:
210 s = parseImport(decldefs, 0);
211 break;
213 case TOKtemplate:
214 s = (Dsymbol *)parseTemplateDeclaration();
215 break;
217 case TOKmixin:
218 { Loc loc = this->loc;
219 if (peek(&token)->value == TOKlparen)
220 { // mixin(string)
221 nextToken();
222 check(TOKlparen, "mixin");
223 Expression *e = parseAssignExp();
224 check(TOKrparen);
225 check(TOKsemicolon);
226 s = new CompileDeclaration(loc, e);
227 break;
229 s = parseMixin();
230 break;
233 CASE_BASIC_TYPES:
234 case TOKalias:
235 case TOKtypedef:
236 case TOKidentifier:
237 case TOKtypeof:
238 case TOKdot:
239 Ldeclaration:
240 a = parseDeclarations();
241 decldefs->append(a);
242 continue;
244 case TOKthis:
245 s = parseCtor();
246 break;
248 case TOKassign:
249 s = parsePostBlit();
250 break;
252 case TOKtilde:
253 s = parseDtor();
254 break;
256 case TOKinvariant:
257 { Token *t;
258 t = peek(&token);
259 if (t->value == TOKlparen)
261 if (peek(t)->value == TOKrparen)
262 // invariant() forms start of class invariant
263 s = parseInvariant();
264 else
265 // invariant(type)
266 goto Ldeclaration;
268 else
270 stc = STCinvariant;
271 goto Lstc;
273 break;
276 case TOKunittest:
277 s = parseUnitTest();
278 break;
280 case TOKnew:
281 s = parseNew();
282 break;
284 case TOKdelete:
285 s = parseDelete();
286 break;
288 case TOKeof:
289 case TOKrcurly:
290 return decldefs;
292 case TOKstatic:
293 nextToken();
294 if (token.value == TOKthis)
296 s = parseStaticCtor();
297 if (dltNormalMode)
298 error("no static constructors in Delight");
300 else if (token.value == TOKtilde)
302 s = parseStaticDtor();
303 if (dltNormalMode)
304 error("no static destructors in Delight");
306 else if (token.value == TOKassert)
307 s = parseStaticAssert();
308 else if (token.value == TOKif)
309 { condition = parseStaticIfCondition();
310 a = parseBlock();
311 aelse = NULL;
312 if (token.value == TOKelse)
313 { nextToken();
314 aelse = parseBlock();
316 s = new StaticIfDeclaration(condition, a, aelse);
317 break;
319 else if (token.value == TOKimport)
321 s = parseImport(decldefs, 1);
323 else
324 { stc = STCstatic;
325 goto Lstc2;
327 break;
329 case TOKin:
330 nextToken();
331 stc = STCin;
332 goto Lstc2;
334 case TOKconst:
335 if (peek(&token)->value == TOKlparen)
336 goto Ldeclaration;
337 stc = STCconst;
338 goto Lstc;
340 case TOKfinal: stc = STCfinal; goto Lstc;
341 case TOKauto: stc = STCauto; goto Lstc;
342 case TOKscope: stc = STCscope; goto Lstc;
343 case TOKoverride: stc = STCoverride; goto Lstc;
344 case TOKabstract: stc = STCabstract; goto Lstc;
345 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
346 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
347 case TOKnothrow: stc = STCnothrow; goto Lstc;
348 case TOKpure: stc = STCpure; goto Lstc;
349 case TOKtls: stc = STCtls; goto Lstc;
350 //case TOKmanifest: stc = STCmanifest; goto Lstc;
352 Lstc:
353 if (storageClass & stc)
354 error("redundant storage class %s", Token::toChars(token.value));
356 unsigned u = storageClass | stc;
357 u &= STCconst | STCinvariant | STCmanifest;
358 if (u & (u - 1))
359 error("conflicting storage class %s", Token::toChars(token.value));
361 nextToken();
362 Lstc2:
363 storageClass |= stc;
364 switch (token.value)
366 case TOKconst:
367 case TOKinvariant:
368 // If followed by a (, it is not a storage class
369 if (peek(&token)->value == TOKlparen)
370 break;
371 if (token.value == TOKconst)
372 stc = STCconst;
373 else
374 stc = STCinvariant;
375 goto Lstc;
376 case TOKfinal: stc = STCfinal; goto Lstc;
377 case TOKauto: stc = STCauto; goto Lstc;
378 case TOKscope: stc = STCscope; goto Lstc;
379 case TOKoverride: stc = STCoverride; goto Lstc;
380 case TOKabstract: stc = STCabstract; goto Lstc;
381 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
382 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
383 case TOKnothrow: stc = STCnothrow; goto Lstc;
384 case TOKpure: stc = STCpure; goto Lstc;
385 case TOKtls: stc = STCtls; goto Lstc;
386 //case TOKmanifest: stc = STCmanifest; goto Lstc;
387 default:
388 break;
391 /* Look for auto initializers:
392 * storage_class identifier = initializer;
394 if (token.value == TOKidentifier &&
395 peek(&token)->value == TOKassign)
397 while (1)
399 Identifier *ident = token.ident;
400 nextToken();
401 nextToken();
402 Initializer *init = parseInitializer();
403 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
404 v->storage_class = storageClass;
405 v->dltNormalMode = dltNormalMode;
406 s = v;
407 if (token.value == TOKsemicolon || token.value == TOKendline)
409 nextToken();
411 else if (token.value == TOKcomma)
413 nextToken();
414 if (token.value == TOKidentifier &&
415 peek(&token)->value == TOKassign)
417 decldefs->push(s);
418 addComment(s, comment);
419 continue;
421 else
422 error("Identifier expected following comma");
424 else
425 error("%s expected following declaration, not '%s'", endToken(), token.toChars());
426 break;
429 else
430 { a = parseBlock();
431 s = new StorageClassDeclaration(storageClass, a);
433 break;
435 case TOKextern:
436 if (peek(&token)->value != TOKlparen)
437 { stc = STCextern;
438 goto Lstc;
441 enum LINK linksave = linkage;
442 linkage = parseLinkage();
443 a = parseBlock();
444 s = new LinkDeclaration(linkage, a);
445 linkage = linksave;
447 if (dltNormalMode)
448 error("access to external symbols can be done only by dlt.* modules");
449 break;
451 case TOKprivate: prot = PROTprivate; goto Lprot;
452 case TOKpackage: prot = PROTpackage; goto Lprot;
453 case TOKprotected: prot = PROTprotected; goto Lprot;
454 case TOKpublic: prot = PROTpublic; goto Lprot;
455 case TOKexport: prot = PROTexport; goto Lprot;
457 Lprot:
458 nextToken();
459 switch (token.value)
461 case TOKprivate:
462 case TOKpackage:
463 case TOKprotected:
464 case TOKpublic:
465 case TOKexport:
466 error("redundant protection attribute");
467 break;
469 a = parseBlock();
470 s = new ProtDeclaration(prot, a);
471 break;
473 case TOKalign:
474 { unsigned n;
476 s = NULL;
477 nextToken();
478 if (token.value == TOKlparen)
480 nextToken();
481 if (token.value == TOKint32v)
482 n = (unsigned)token.uns64value;
483 else
484 { error("integer expected, not %s", token.toChars());
485 n = 1;
487 nextToken();
488 check(TOKrparen);
490 else
491 n = global.structalign; // default
493 a = parseBlock();
494 s = new AlignDeclaration(n, a);
495 break;
498 case TOKpragma:
499 { Identifier *ident;
500 Expressions *args = NULL;
502 nextToken();
503 check(TOKlparen);
504 if (token.value != TOKidentifier)
505 { error("pragma(identifier expected");
506 goto Lerror;
508 ident = token.ident;
509 nextToken();
510 if (token.value == TOKcomma)
511 args = parseArguments(); // pragma(identifier, args...)
512 else
513 check(TOKrparen); // pragma(identifier)
515 if (token.value == TOKsemicolon || token.value == TOKendline)
516 a = NULL;
517 else if (dltSyntax)
519 check(TOKcolon);
520 a = parseDeclDefs(0);
521 check(TOKrcurly);
523 else
524 a = parseBlock();
525 s = new PragmaDeclaration(loc, ident, args, a);
526 break;
529 case TOKdebug:
530 nextToken();
531 if (token.value == TOKassign)
533 nextToken();
534 if (token.value == TOKidentifier)
535 s = new DebugSymbol(loc, token.ident);
536 else if (token.value == TOKint32v)
537 s = new DebugSymbol(loc, (unsigned)token.uns64value);
538 else
539 { error("identifier or integer expected, not %s", token.toChars());
540 s = NULL;
542 nextToken();
543 if (token.value != TOKsemicolon)
544 error("semicolon expected");
545 nextToken();
546 break;
549 condition = parseDebugCondition();
550 goto Lcondition;
552 case TOKversion:
553 nextToken();
554 if (token.value == TOKassign)
556 nextToken();
557 if (token.value == TOKidentifier)
558 s = new VersionSymbol(loc, token.ident);
559 else if (token.value == TOKint32v)
560 s = new VersionSymbol(loc, (unsigned)token.uns64value);
561 else
562 { error("identifier or integer expected, not %s", token.toChars());
563 s = NULL;
565 nextToken();
566 if (token.value != TOKsemicolon && token.value != TOKendline)
567 error("%s expected after version assignment", endToken());
568 nextToken();
569 break;
571 condition = parseVersionCondition();
572 goto Lcondition;
574 Lcondition:
575 a = parseBlock();
576 aelse = NULL;
577 if (token.value == TOKelse)
578 { nextToken();
579 aelse = parseBlock();
581 s = new ConditionalDeclaration(condition, a, aelse);
582 break;
584 case TOKsemicolon: // empty declaration
585 nextToken();
586 continue;
588 default:
589 error("Declaration expected, not '%s'",token.toChars());
590 Lerror:
591 while (token.value != TOKsemicolon && token.value != TOKendline && token.value != TOKeof)
592 nextToken();
593 nextToken();
594 s = NULL;
595 continue;
597 if (s)
598 { decldefs->push(s);
599 addComment(s, comment);
601 } while (!once);
602 return decldefs;
606 /********************************************
607 * Parse declarations after an align, protection, or extern decl.
610 Array *Parser::parseBlock()
612 Array *a = NULL;
613 Dsymbol *s;
615 //printf("Parser::parseBlock()\n");
616 switch (token.value)
618 case TOKsemicolon:
619 error("declaration expected following attribute, not ';'");
620 nextToken();
621 break;
623 case TOKlcurly:
624 nextToken();
625 a = parseDeclDefs(0);
626 if (token.value != TOKrcurly)
627 { /* { */
628 error("matching '}' expected, not %s", token.toChars());
630 else
631 nextToken();
632 break;
634 case TOKcolon:
635 nextToken();
636 #if 0
637 a = NULL;
638 #else
639 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
640 #endif
641 break;
643 default:
644 a = parseDeclDefs(1);
645 break;
647 return a;
650 Array *DltParser::parseBlock()
652 Array *a = NULL;
653 Dsymbol *s;
655 optionalEndline();
656 switch (token.value)
658 case TOKendline:
659 case TOKsemicolon:
660 error("declaration expected following attribute, not %s", token.toChars());
661 nextToken();
662 break;
664 case TOKcolon:
665 nextToken();
666 a = parseDeclDefs(0);
667 if (token.value != TOKrcurly)
669 error("matching end-of-block expected, not %s", token.toChars());
671 else
672 nextToken();
673 break;
675 default:
676 a = parseDeclDefs(1);
677 break;
679 return a;
682 /**********************************
683 * Parse a static assertion.
686 StaticAssert *Parser::parseStaticAssert()
688 Loc loc = this->loc;
689 Expression *exp;
690 Expression *msg = NULL;
692 //printf("parseStaticAssert()\n");
693 nextToken();
694 checkLParen();
695 exp = parseAssignExp();
696 if (token.value == TOKcomma)
697 { nextToken();
698 msg = parseAssignExp();
700 checkRParen();
701 if (token.value == TOKsemicolon || token.value == TOKendline) {
702 nextToken();
703 return new StaticAssert(loc, exp, msg);
705 error("expected %s after static assert", endToken());
708 /***********************************
709 * Parse typeof(expression).
710 * Current token is on the 'typeof'.
713 TypeQualified *Parser::parseTypeof()
714 { TypeQualified *t;
715 Loc loc = this->loc;
717 nextToken();
718 check(TOKlparen);
719 if (token.value == TOKreturn) // typeof(return)
721 nextToken();
722 t = new TypeReturn(loc);
724 else
725 { Expression *exp = parseExpression(); // typeof(expression)
726 t = new TypeTypeof(loc, exp);
728 check(TOKrparen);
729 return t;
732 /***********************************
733 * Parse extern (linkage)
734 * The parser is on the 'extern' token.
737 enum LINK Parser::parseLinkage()
739 enum LINK link = LINKdefault;
740 nextToken();
741 assert(token.value == TOKlparen);
742 nextToken();
743 if (token.value == TOKidentifier)
744 { Identifier *id = token.ident;
746 nextToken();
747 if (id == Id::Windows)
748 link = LINKwindows;
749 else if (id == Id::Pascal)
750 link = LINKpascal;
751 else if (id == Id::D)
752 link = LINKd;
753 else if (id == Id::C)
755 link = LINKc;
756 if (token.value == TOKplusplus)
757 { link = LINKcpp;
758 nextToken();
761 else if (id == Id::System)
763 #ifdef IN_GCC
764 link = d_gcc_is_target_win32() ? LINKwindows : LINKc;
765 #else
766 #if _WIN32
767 link = LINKwindows;
768 #else
769 link = LINKc;
770 #endif
771 #endif
773 else
775 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
776 link = LINKd;
779 else
781 link = LINKd; // default
783 check(TOKrparen);
784 return link;
787 /**************************************
788 * Parse a debug conditional
791 Condition *Parser::parseDebugCondition()
793 Condition *c;
795 if (token.value == TOKlparen)
797 nextToken();
798 unsigned level = 1;
799 Identifier *id = NULL;
801 if (token.value == TOKidentifier)
802 id = token.ident;
803 else if (token.value == TOKint32v)
804 level = (unsigned)token.uns64value;
805 else
806 error("identifier or integer expected, not %s", token.toChars());
807 nextToken();
808 check(TOKrparen);
809 c = new DebugCondition(mod, level, id);
810 if (dltSyntax && token.value != TOKcolon)
811 error("expected colon after debug(), not '%s'", token.toChars());
812 } else {
813 if (dltSyntax && token.value != TOKcolon)
814 error("expected ':' or '(' after 'debug', not '%s'", token.toChars());
815 c = new DebugCondition(mod, 1, NULL);
817 return c;
821 /**************************************
822 * Parse a version conditional
825 Condition *Parser::parseVersionCondition()
827 Condition *c;
828 unsigned level = 1;
829 Identifier *id = NULL;
831 if (token.value == TOKlparen)
833 nextToken();
834 if (token.value == TOKidentifier)
835 id = token.ident;
836 else if (token.value == TOKint32v)
837 level = (unsigned)token.uns64value;
838 #if V2
839 /* Allow:
840 * version (unittest)
841 * even though unittest is a keyword
843 else if (token.value == TOKunittest)
844 id = Lexer::idPool(Token::toChars(TOKunittest));
845 #endif
846 else
847 error("identifier or integer expected, not %s", token.toChars());
848 nextToken();
849 check(TOKrparen);
852 else
853 error("(condition) expected following version");
854 c = new VersionCondition(mod, level, id);
855 return c;
859 /***********************************************
860 * static if (expression)
861 * body
862 * else
863 * body
866 Condition *Parser::parseStaticIfCondition()
867 { Expression *exp;
868 Condition *condition;
869 Array *aif;
870 Array *aelse;
871 Loc loc = this->loc;
873 nextToken();
874 checkLParen();
875 exp = parseAssignExp();
876 checkRParen();
878 condition = new StaticIfCondition(loc, exp);
879 return condition;
883 /*****************************************
884 * Parse a constructor definition:
885 * this(arguments) { body }
886 * or postblit:
887 * this(this) { body }
888 * Current token is 'this'.
891 FuncDeclaration *Parser::parseCtor()
893 Loc loc = this->loc;
895 nextToken();
896 if (token.value == TOKlparen && peek(&token)->value == TOKthis)
897 { // this(this) { ... }
898 nextToken();
899 nextToken();
900 check(TOKrparen);
901 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
902 parseContracts(f);
903 return f;
905 int varargs;
906 Arguments *arguments = parseParameters(&varargs);
907 CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs);
908 parseContracts(f);
909 return f;
912 /*****************************************
913 * Parse a postblit definition:
914 * =this() { body }
915 * Current token is '='.
918 PostBlitDeclaration *Parser::parsePostBlit()
920 Loc loc = this->loc;
922 nextToken();
923 check(TOKthis);
924 check(TOKlparen);
925 check(TOKrparen);
927 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
928 parseContracts(f);
929 return f;
932 /*****************************************
933 * Parse a destructor definition:
934 * ~this() { body }
935 * Current token is '~'.
938 DtorDeclaration *Parser::parseDtor()
940 DtorDeclaration *f;
941 Loc loc = this->loc;
943 nextToken();
944 check(TOKthis);
945 check(TOKlparen);
946 check(TOKrparen);
948 f = new DtorDeclaration(loc, 0);
949 parseContracts(f);
950 return f;
953 /*****************************************
954 * Parse a static constructor definition:
955 * static this() { body }
956 * Current token is 'this'.
959 StaticCtorDeclaration *Parser::parseStaticCtor()
961 StaticCtorDeclaration *f;
962 Loc loc = this->loc;
964 nextToken();
965 check(TOKlparen);
966 check(TOKrparen);
968 f = new StaticCtorDeclaration(loc, 0);
969 parseContracts(f);
970 return f;
973 /*****************************************
974 * Parse a static destructor definition:
975 * static ~this() { body }
976 * Current token is '~'.
979 StaticDtorDeclaration *Parser::parseStaticDtor()
981 StaticDtorDeclaration *f;
982 Loc loc = this->loc;
984 nextToken();
985 check(TOKthis);
986 check(TOKlparen);
987 check(TOKrparen);
989 f = new StaticDtorDeclaration(loc, 0);
990 parseContracts(f);
991 return f;
994 /*****************************************
995 * Parse an invariant definition:
996 * invariant { body }
997 * Current token is 'invariant'.
1000 InvariantDeclaration *Parser::parseInvariant()
1002 InvariantDeclaration *f;
1003 Loc loc = this->loc;
1005 nextToken();
1007 // () are optional
1008 if (token.value == TOKlparen)
1009 { nextToken();
1010 check(TOKrparen);
1013 f = new InvariantDeclaration(loc, 0);
1014 f->fbody = parseStatement(PScurly);
1015 return f;
1018 /*****************************************
1019 * Parse a unittest definition:
1020 * unittest { body }
1021 * Current token is 'unittest'.
1024 UnitTestDeclaration *Parser::parseUnitTest()
1026 UnitTestDeclaration *f;
1027 Statement *body;
1028 Loc loc = this->loc;
1030 nextToken();
1032 body = parseStatement(PScurly);
1034 f = new UnitTestDeclaration(loc, this->loc);
1035 f->fbody = body;
1036 return f;
1039 /*****************************************
1040 * Parse a new definition:
1041 * new(arguments) { body }
1042 * Current token is 'new'.
1045 NewDeclaration *Parser::parseNew()
1047 NewDeclaration *f;
1048 Arguments *arguments;
1049 int varargs;
1050 Loc loc = this->loc;
1052 nextToken();
1053 arguments = parseParameters(&varargs);
1054 f = new NewDeclaration(loc, 0, arguments, varargs);
1055 parseContracts(f);
1056 return f;
1059 /*****************************************
1060 * Parse a delete definition:
1061 * delete(arguments) { body }
1062 * Current token is 'delete'.
1065 DeleteDeclaration *Parser::parseDelete()
1067 DeleteDeclaration *f;
1068 Arguments *arguments;
1069 int varargs;
1070 Loc loc = this->loc;
1072 nextToken();
1073 arguments = parseParameters(&varargs);
1074 if (varargs)
1075 error("... not allowed in delete function parameter list");
1076 f = new DeleteDeclaration(loc, 0, arguments);
1077 parseContracts(f);
1078 return f;
1081 /**********************************************
1082 * Parse parameter list.
1085 Arguments *Parser::parseParameters(int *pvarargs)
1087 Arguments *arguments = new Arguments();
1088 int varargs = 0;
1089 int hasdefault = 0;
1091 check(TOKlparen);
1092 while (1)
1093 { Type *tb;
1094 Identifier *ai;
1095 Type *at;
1096 Argument *a;
1097 unsigned storageClass;
1098 unsigned stc;
1099 Expression *ae;
1101 ai = NULL;
1102 storageClass = 0; // parameter is "in" by default
1103 for (;1; nextToken())
1105 switch (token.value)
1107 case TOKrparen:
1108 break;
1110 case TOKdotdotdot:
1111 varargs = 1;
1112 nextToken();
1113 break;
1115 case TOKconst:
1116 if (peek(&token)->value == TOKlparen)
1117 goto Ldefault;
1118 stc = STCconst;
1119 goto L2;
1121 case TOKinvariant:
1122 if (peek(&token)->value == TOKlparen)
1123 goto Ldefault;
1124 stc = STCinvariant;
1125 goto L2;
1127 case TOKin: stc = STCin; goto L2;
1128 case TOKout: stc = STCout; goto L2;
1129 case TOKinout:
1130 case TOKref: stc = STCref; goto L2;
1131 case TOKlazy: stc = STClazy; goto L2;
1132 case TOKscope: stc = STCscope; goto L2;
1133 case TOKfinal: stc = STCfinal; goto L2;
1134 case TOKstatic: stc = STCstatic; goto L2;
1136 if (storageClass & stc ||
1137 (storageClass & STCin && stc & (STCconst | STCscope)) ||
1138 (stc & STCin && storageClass & (STCconst | STCscope))
1140 error("redundant storage class %s", Token::toChars(token.value));
1141 storageClass |= stc;
1143 unsigned u = storageClass & (STCconst | STCinvariant);
1144 if (u & (u - 1))
1145 error("conflicting storage class %s", Token::toChars(token.value));
1147 continue;
1149 default:
1150 Ldefault:
1151 stc = storageClass & (STCin | STCout | STCref | STClazy);
1152 if (stc & (stc - 1)) // if stc is not a power of 2
1153 error("incompatible parameter storage classes");
1154 if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1155 error("out cannot be const");
1156 if ((storageClass & (STCinvariant | STCout)) == (STCinvariant | STCout))
1157 error("out cannot be invariant");
1158 if ((storageClass & STCscope) &&
1159 (storageClass & (STCref | STCout)))
1160 error("scope cannot be ref or out");
1161 at = parseType(&ai);
1162 ae = NULL;
1163 if (token.value == TOKassign) // = defaultArg
1164 { nextToken();
1165 ae = parseDefaultInitExp();
1166 hasdefault = 1;
1168 else
1169 { if (hasdefault)
1170 error("default argument expected for %s",
1171 ai ? ai->toChars() : at->toChars());
1173 if (token.value == TOKdotdotdot)
1174 { /* This is:
1175 * at ai ...
1178 if (storageClass & (STCout | STCref))
1179 error("variadic argument cannot be out or ref");
1180 varargs = 2;
1181 a = new Argument(storageClass, at, ai, ae);
1182 arguments->push(a);
1183 nextToken();
1184 break;
1186 a = new Argument(storageClass, at, ai, ae);
1187 arguments->push(a);
1188 if (token.value == TOKcomma)
1189 { nextToken();
1190 goto L1;
1192 break;
1194 break;
1196 break;
1198 L1: ;
1200 check(TOKrparen);
1201 *pvarargs = varargs;
1202 return arguments;
1206 /*************************************
1209 EnumDeclaration *Parser::parseEnum()
1210 { EnumDeclaration *e;
1211 Identifier *id;
1212 Type *memtype;
1213 Loc loc = this->loc;
1215 //printf("Parser::parseEnum()\n");
1216 nextToken();
1217 if (token.value == TOKidentifier)
1218 { id = token.ident;
1219 nextToken();
1221 else
1222 id = NULL;
1224 if (token.value == (dltSyntax ? TOKextends : TOKcolon))
1226 nextToken();
1227 memtype = parseBasicType();
1228 memtype = parseDeclarator(memtype, NULL, NULL);
1230 else
1231 memtype = NULL;
1233 e = new EnumDeclaration(loc, id, memtype);
1234 if ((token.value == TOKsemicolon || token.value == TOKendline) && id)
1235 nextToken();
1236 else if (token.value == startBlockTok)
1238 //printf("enum definition\n");
1239 e->members = new Array();
1240 nextToken();
1241 unsigned char *comment = token.blockComment;
1242 optionalEndline();
1243 while (token.value != TOKrcurly)
1245 /* Can take the following forms:
1246 * 1. ident
1247 * 2. ident = value
1248 * 3. type ident = value
1251 loc = this->loc;
1253 Type *type = NULL;
1254 Identifier *ident;
1255 Token *tp = peek(&token);
1256 if (token.value == TOKidentifier &&
1257 (tp->value == TOKassign || tp->value == TOKcomma ||
1258 tp->value == TOKendline || tp->value == TOKrcurly))
1260 ident = token.ident;
1261 type = NULL;
1262 nextToken();
1264 else
1266 type = parseType(&ident, NULL);
1267 if (id || memtype)
1268 error("type only allowed if anonymous enum and no enum type");
1271 Expression *value;
1272 if (token.value == TOKassign)
1274 nextToken();
1275 value = parseAssignExp();
1277 else
1278 { value = NULL;
1279 if (type)
1280 error("if type, there must be an initializer");
1283 EnumMember *em = new EnumMember(loc, ident, value, type);
1284 e->members->push(em);
1286 if (dltSyntax)
1288 if (token.value == TOKcomma)
1289 nextToken();
1290 else if (token.value != TOKendline)
1291 error("expected comma or newline after %s, not %s",
1292 em->toChars(), token.toChars());
1293 optionalEndline();
1296 if (token.value == TOKrcurly)
1298 else
1299 { addComment(em, comment);
1300 comment = NULL;
1301 if (!dltSyntax)
1302 check(TOKcomma);
1304 addComment(em, comment);
1305 comment = token.blockComment;
1307 nextToken();
1309 else
1310 error("enum declaration is invalid");
1311 //printf("-parseEnum() %s\n", e->toChars());
1312 return e;
1315 Dsymbol *Parser::parseAggregate()
1316 { AggregateDeclaration *a = NULL;
1317 int anon = 0;
1318 enum TOK tok;
1319 Identifier *id;
1320 TemplateParameters *tpl = NULL;
1322 //printf("Parser::parseAggregate()\n");
1323 tok = token.value;
1324 nextToken();
1325 if (token.value != TOKidentifier)
1326 { id = NULL;
1328 else
1329 { id = token.ident;
1330 nextToken();
1332 if (token.value == TOKlparen)
1333 { // Class template declaration.
1335 // Gather template parameter list
1336 tpl = parseTemplateParameterList();
1340 Loc loc = this->loc;
1341 switch (tok)
1342 { case TOKclass:
1343 case TOKinterface:
1345 if (!id)
1346 error("anonymous classes not allowed");
1348 // Collect base class(es)
1349 BaseClasses *baseclasses = parseBaseClasses();
1350 if (baseclasses && token.value != startBlockTok) {
1351 error("members expected");
1354 if (tok == TOKclass)
1355 a = new ClassDeclaration(loc, id, baseclasses);
1356 else
1357 a = new InterfaceDeclaration(loc, id, baseclasses);
1358 break;
1361 case TOKstruct:
1362 if (id)
1363 a = new StructDeclaration(loc, id);
1364 else
1365 anon = 1;
1366 break;
1368 case TOKunion:
1369 if (id)
1370 a = new UnionDeclaration(loc, id);
1371 else
1372 anon = 2;
1373 break;
1375 default:
1376 assert(0);
1377 break;
1379 if (a && token.value == (dltSyntax ? TOKendline : TOKsemicolon))
1380 { nextToken();
1382 else if (token.value == startBlockTok)
1384 //printf("aggregate definition\n");
1385 nextToken();
1386 optionalEndline();
1387 Array *decl = parseDeclDefs(0);
1388 if (token.value != TOKrcurly)
1389 error("end-of-block expected following member declarations in aggregate");
1390 nextToken();
1391 if (anon)
1393 /* Anonymous structs/unions are more like attributes.
1395 return new AnonDeclaration(loc, anon - 1, decl);
1397 else
1398 a->members = decl;
1400 else
1402 error("%s expected following aggregate declaration", Token::toChars(startBlockTok));
1403 a = new StructDeclaration(loc, NULL);
1406 if (tpl)
1407 { Array *decldefs;
1408 TemplateDeclaration *tempdecl;
1410 // Wrap a template around the aggregate declaration
1411 decldefs = new Array();
1412 decldefs->push(a);
1413 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1414 return tempdecl;
1417 return a;
1420 /*******************************************
1423 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1424 * the bases. Otherwise, return null.
1426 BaseClasses *Parser::parseBaseClasses()
1428 enum PROT protection = PROTpublic;
1429 int type; // 1 = extends, 2 = implements, 3 = unknown
1431 if (dltSyntax) {
1432 if (token.value == TOKextends)
1433 type = 1;
1434 else if (token.value == TOKimplements)
1435 type = 2;
1436 else
1437 return NULL;
1438 } else {
1439 if (token.value == TOKcolon)
1440 type = 3;
1441 else
1442 return NULL;
1445 nextToken();
1447 BaseClasses *baseclasses = new BaseClasses();
1449 for (; 1; nextToken())
1451 enum PROT protection = PROTpublic;
1452 switch (token.value)
1454 case TOKprivate:
1455 protection = PROTprivate;
1456 nextToken();
1457 break;
1458 case TOKpackage:
1459 protection = PROTpackage;
1460 nextToken();
1461 break;
1462 case TOKprotected:
1463 protection = PROTprotected;
1464 nextToken();
1465 break;
1466 case TOKpublic:
1467 protection = PROTpublic;
1468 nextToken();
1469 break;
1471 if (token.value == TOKidentifier)
1473 BaseClass *b = new BaseClass(parseBasicType(), protection);
1474 baseclasses->push(b);
1476 switch (token.value) {
1477 case TOKcomma:
1478 continue;
1479 case TOKextends:
1480 if (type == 2)
1481 error("extends part must come before implements");
1482 else
1483 error("only one extends is permitted");
1484 continue;
1485 case TOKimplements:
1486 if (type == 1)
1487 type = 2;
1488 else
1489 error("separate implemented interfaces with commas");
1490 continue;
1492 break;
1494 else
1496 error("base classes expected instead of %s", token.toChars());
1497 return NULL;
1500 return baseclasses;
1503 /**************************************
1504 * Parse a TemplateDeclaration.
1507 TemplateDeclaration *Parser::parseTemplateDeclaration()
1509 TemplateDeclaration *tempdecl;
1510 Identifier *id;
1511 TemplateParameters *tpl;
1512 Array *decldefs;
1513 Loc loc = this->loc;
1515 nextToken();
1516 if (token.value != TOKidentifier)
1517 { error("TemplateIdentifier expected following template");
1518 goto Lerr;
1520 id = token.ident;
1521 nextToken();
1522 tpl = parseTemplateParameterList();
1523 if (!tpl)
1524 goto Lerr;
1526 if (token.value != startBlockTok)
1527 { error("members of template declaration expected");
1528 goto Lerr;
1530 else
1532 nextToken();
1533 decldefs = parseDeclDefs(0);
1534 if (token.value != TOKrcurly)
1535 { error("template member expected");
1536 goto Lerr;
1538 nextToken();
1541 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1542 return tempdecl;
1544 Lerr:
1545 return NULL;
1548 /******************************************
1549 * Parse template parameter list.
1550 * Input:
1551 * flag 0: parsing "( list )"
1552 * 1: parsing non-empty "list )"
1555 TemplateParameters *Parser::parseTemplateParameterList(int flag)
1557 TemplateParameters *tpl = new TemplateParameters();
1559 if (!flag && token.value != TOKlparen)
1560 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1561 goto Lerr;
1563 nextToken();
1565 // Get array of TemplateParameters
1566 if (flag || token.value != TOKrparen)
1567 { int isvariadic = 0;
1569 while (1)
1570 { TemplateParameter *tp;
1571 Identifier *tp_ident = NULL;
1572 Type *tp_spectype = NULL;
1573 Type *tp_valtype = NULL;
1574 Type *tp_defaulttype = NULL;
1575 Expression *tp_specvalue = NULL;
1576 Expression *tp_defaultvalue = NULL;
1577 Token *t;
1579 // Get TemplateParameter
1581 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1582 t = peek(&token);
1583 if (token.value == TOKalias)
1584 { // AliasParameter
1585 nextToken();
1586 if (token.value != TOKidentifier)
1587 { error("Identifier expected for template parameter");
1588 goto Lerr;
1590 tp_ident = token.ident;
1591 nextToken();
1592 if (token.value == TOKcolon) // : Type
1594 nextToken();
1595 tp_spectype = parseType();
1597 if (token.value == TOKassign) // = Type
1599 nextToken();
1600 tp_defaulttype = parseType();
1602 tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1604 else if (t->value == TOKcolon || t->value == TOKassign ||
1605 t->value == TOKcomma || t->value == TOKrparen)
1606 { // TypeParameter
1607 if (token.value != TOKidentifier)
1608 { error("Identifier expected for template parameter");
1609 goto Lerr;
1611 tp_ident = token.ident;
1612 nextToken();
1613 if (token.value == TOKcolon) // : Type
1615 nextToken();
1616 tp_spectype = parseType();
1618 if (token.value == TOKassign) // = Type
1620 nextToken();
1621 tp_defaulttype = parseType();
1623 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1625 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1626 { // ident...
1627 if (isvariadic)
1628 error("variadic template parameter must be last");
1629 isvariadic = 1;
1630 tp_ident = token.ident;
1631 nextToken();
1632 nextToken();
1633 tp = new TemplateTupleParameter(loc, tp_ident);
1635 else if (token.value == TOKthis)
1636 { // ThisParameter
1637 nextToken();
1638 if (token.value != TOKidentifier)
1639 { error("Identifier expected for template parameter");
1640 goto Lerr;
1642 tp_ident = token.ident;
1643 nextToken();
1644 if (token.value == TOKcolon) // : Type
1646 nextToken();
1647 tp_spectype = parseType();
1649 if (token.value == TOKassign) // = Type
1651 nextToken();
1652 tp_defaulttype = parseType();
1654 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1656 else
1657 { // ValueParameter
1658 tp_valtype = parseType(&tp_ident);
1659 if (!tp_ident)
1661 error("no identifier for template value parameter");
1662 tp_ident = new Identifier("error", TOKidentifier);
1664 if (token.value == TOKcolon) // : CondExpression
1666 nextToken();
1667 tp_specvalue = parseCondExp();
1669 if (token.value == TOKassign) // = CondExpression
1671 nextToken();
1672 tp_defaultvalue = parseDefaultInitExp();
1674 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1676 tpl->push(tp);
1677 if (token.value != TOKcomma)
1678 break;
1679 nextToken();
1682 check(TOKrparen);
1683 Lerr:
1684 return tpl;
1687 /******************************************
1688 * Parse template mixin.
1689 * mixin Foo;
1690 * mixin Foo!(args);
1691 * mixin a.b.c!(args).Foo!(args);
1692 * mixin Foo!(args) identifier;
1693 * mixin typeof(expr).identifier!(args);
1696 Dsymbol *Parser::parseMixin()
1698 TemplateMixin *tm;
1699 Identifier *id;
1700 Type *tqual;
1701 Objects *tiargs;
1702 Array *idents;
1704 //printf("parseMixin()\n");
1705 nextToken();
1706 tqual = NULL;
1707 if (token.value == TOKdot)
1709 id = Id::empty;
1711 else
1713 if (token.value == TOKtypeof)
1715 tqual = parseTypeof();
1716 check(TOKdot);
1718 if (token.value != TOKidentifier)
1720 error("identifier expected, not %s", token.toChars());
1721 goto Lerr;
1723 id = token.ident;
1724 nextToken();
1727 idents = new Array();
1728 while (1)
1730 tiargs = NULL;
1731 if (token.value == TOKnot)
1733 nextToken();
1734 tiargs = parseTemplateArgumentList();
1737 if (token.value != TOKdot)
1738 break;
1740 if (tiargs)
1741 { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1742 tempinst->tiargs = tiargs;
1743 id = (Identifier *)tempinst;
1744 tiargs = NULL;
1746 idents->push(id);
1748 nextToken();
1749 if (token.value != TOKidentifier)
1750 { error("identifier expected following '.' instead of '%s'", token.toChars());
1751 break;
1753 id = token.ident;
1754 nextToken();
1756 idents->push(id);
1758 if (token.value == TOKidentifier)
1760 id = token.ident;
1761 nextToken();
1763 else
1764 id = NULL;
1766 tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1767 if (token.value != TOKsemicolon)
1768 error("';' expected after mixin");
1769 nextToken();
1771 return tm;
1773 Lerr:
1774 return NULL;
1777 /******************************************
1778 * Parse template argument list.
1779 * Input:
1780 * current token is opening '('
1781 * Output:
1782 * current token is one after closing ')'
1785 Objects *Parser::parseTemplateArgumentList()
1787 //printf("Parser::parseTemplateArgumentList()\n");
1788 if (token.value != TOKlparen)
1789 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1790 return new Objects();
1792 return parseTemplateArgumentList2();
1795 Objects *Parser::parseTemplateArgumentList2()
1797 Objects *tiargs = new Objects();
1798 nextToken();
1800 // Get TemplateArgumentList
1801 if (token.value != TOKrparen)
1803 while (1)
1805 // See if it is an Expression or a Type
1806 if (isDeclaration(&token, 0, TOKreserved, NULL))
1807 { // Type
1808 Type *ta;
1810 // Get TemplateArgument
1811 ta = parseType();
1812 tiargs->push(ta);
1814 else
1815 { // Expression
1816 Expression *ea;
1818 ea = parseAssignExp();
1819 tiargs->push(ea);
1821 if (token.value != TOKcomma)
1822 break;
1823 nextToken();
1826 check(TOKrparen, "template argument list");
1827 return tiargs;
1830 Import *Parser::parseImport(Array *decldefs, int isstatic)
1831 { Import *s;
1832 Identifier *id;
1833 Identifier *aliasid = NULL;
1834 Array *a;
1835 Loc loc;
1837 //printf("Parser::parseImport()\n");
1841 nextToken();
1842 if (token.value != TOKidentifier)
1843 { error("Identifier expected following import");
1844 break;
1847 loc = this->loc;
1848 a = NULL;
1849 id = token.ident;
1850 nextToken();
1851 if (!aliasid && token.value == TOKassign)
1853 aliasid = id;
1854 goto L1;
1856 while (token.value == TOKdot)
1858 if (!a)
1859 a = new Array();
1860 a->push(id);
1861 nextToken();
1862 if (token.value != TOKidentifier)
1863 { error("Identifier expected following package");
1864 break;
1866 id = token.ident;
1867 nextToken();
1870 s = new Import(loc, a, token.ident, aliasid, isstatic);
1871 decldefs->push(s);
1873 /* Look for
1874 * : alias=name, alias=name;
1875 * syntax.
1877 if (token.value == TOKcolon)
1879 nextToken();
1880 while (1)
1881 { Identifier *name;
1882 Identifier *alias;
1884 optionalEndline();
1886 if (dltSyntax && token.value == TOKrcurly)
1887 break;
1888 if (token.value != TOKidentifier)
1889 { error("Identifier expected following :");
1890 break;
1892 alias = token.ident;
1893 nextToken();
1894 if (token.value == TOKassign)
1896 nextToken();
1897 if (token.value != TOKidentifier)
1898 { error("Identifier expected following %s=", alias->toChars());
1899 break;
1901 name = token.ident;
1902 nextToken();
1904 else
1905 { name = alias;
1906 alias = NULL;
1908 s->addAlias(name, alias);
1909 if (token.value != TOKcomma && token.value != TOKendline)
1910 break;
1911 nextToken();
1913 if (dltSyntax)
1915 check(TOKrcurly);
1916 return NULL;
1918 else
1919 break;
1922 aliasid = NULL;
1923 } while (token.value == TOKcomma);
1925 if (token.value == TOKsemicolon || token.value == TOKendline)
1926 nextToken();
1927 else
1929 error("%s expected", endToken());
1930 nextToken();
1933 return NULL;
1936 Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
1937 { Type *t;
1939 if (token.value == TOKconst && peek(&token)->value != TOKlparen)
1941 nextToken();
1942 /* const type
1944 t = parseType(pident, tpl);
1945 t = t->makeConst();
1946 return t;
1948 else if (token.value == TOKinvariant && peek(&token)->value != TOKlparen)
1950 nextToken();
1951 /* invariant type
1953 t = parseType(pident, tpl);
1954 t = t->makeInvariant();
1955 return t;
1957 else
1958 t = parseBasicType();
1959 t = parseDeclarator(t, pident, tpl);
1960 return t;
1963 Type *Parser::parseBasicType()
1964 { Type *t;
1965 Identifier *id;
1966 TypeQualified *tid;
1967 TemplateInstance *tempinst;
1969 //printf("parseBasicType()\n");
1970 switch (token.value)
1972 CASE_BASIC_TYPES_X(t):
1973 nextToken();
1974 break;
1976 case TOKidentifier:
1977 id = token.ident;
1978 nextToken();
1979 if (token.value == TOKnot)
1981 nextToken();
1982 tempinst = new TemplateInstance(loc, id);
1983 tempinst->tiargs = parseTemplateArgumentList();
1984 tid = new TypeInstance(loc, tempinst);
1985 goto Lident2;
1987 Lident:
1988 tid = new TypeIdentifier(loc, id);
1989 Lident2:
1990 while (token.value == TOKdot)
1991 { nextToken();
1992 if (token.value != TOKidentifier)
1993 { error("identifier expected following '.' instead of '%s'", token.toChars());
1994 break;
1996 id = token.ident;
1997 nextToken();
1998 if (token.value == TOKnot)
2000 nextToken();
2001 tempinst = new TemplateInstance(loc, id);
2002 tempinst->tiargs = parseTemplateArgumentList();
2003 tid->addIdent((Identifier *)tempinst);
2005 else
2006 tid->addIdent(id);
2008 t = tid;
2009 break;
2011 case TOKdot:
2012 id = Id::empty;
2013 goto Lident;
2015 case TOKtypeof:
2017 tid = parseTypeof();
2018 goto Lident2;
2021 case TOKconst:
2022 // const(type)
2023 nextToken();
2024 check(TOKlparen);
2025 t = parseType();
2026 check(TOKrparen);
2027 t = t->makeConst();
2028 break;
2030 case TOKinvariant:
2031 // invariant(type)
2032 nextToken();
2033 check(TOKlparen);
2034 t = parseType();
2035 check(TOKrparen);
2036 t = t->makeInvariant();
2037 break;
2039 default:
2040 error("basic type expected, not %s", token.toChars());
2041 t = Type::tint32;
2042 break;
2044 return t;
2047 Type *Parser::parseBasicType2(Type *t)
2049 Type *ts;
2050 Type *ta;
2052 //printf("parseBasicType2()\n");
2053 while (1)
2055 switch (token.value)
2057 case TOKmul:
2058 t = new TypePointer(t);
2059 nextToken();
2060 continue;
2062 case TOKlbracket:
2063 // Handle []. Make sure things like
2064 // int[3][1] a;
2065 // is (array[1] of array[3] of int)
2066 nextToken();
2067 if (token.value == TOKrbracket)
2069 t = new TypeDArray(t); // []
2070 nextToken();
2072 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2073 { // It's an associative array declaration
2074 Type *index;
2076 //printf("it's an associative array\n");
2077 index = parseType(); // [ type ]
2078 t = new TypeAArray(t, index);
2079 check(TOKrbracket);
2081 else
2083 //printf("it's [expression]\n");
2084 inBrackets++;
2085 Expression *e = parseExpression(); // [ expression ]
2086 if (token.value == TOKslice)
2087 { Expression *e2;
2089 nextToken();
2090 e2 = parseExpression(); // [ exp .. exp ]
2091 t = new TypeSlice(t, e, e2);
2093 else
2094 t = new TypeSArray(t,e);
2095 inBrackets--;
2096 check(TOKrbracket);
2098 continue;
2100 case TOKdelegate:
2101 case TOKfunction:
2102 { // Handle delegate declaration:
2103 // t delegate(parameter list)
2104 // t function(parameter list)
2105 Arguments *arguments;
2106 int varargs;
2107 bool ispure = false;
2108 bool isnothrow = false;
2109 enum TOK save = token.value;
2111 nextToken();
2112 arguments = parseParameters(&varargs);
2113 while (1)
2115 if (token.value == TOKpure)
2116 ispure = true;
2117 else if (token.value == TOKnothrow)
2118 isnothrow = true;
2119 else
2120 break;
2121 nextToken();
2123 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
2124 tf->ispure = ispure;
2125 tf->isnothrow = isnothrow;
2126 if (save == TOKdelegate)
2127 t = new TypeDelegate(tf);
2128 else
2129 t = new TypePointer(tf); // pointer to function
2130 continue;
2133 case TOKquestion:
2134 if (dltSyntax)
2136 Type *old = t;
2137 t = t->maybe(false);
2138 if (t == old)
2139 error("Type %s cannot be null; ? is pointless", old->toChars());
2140 nextToken();
2141 continue;
2143 // fall-through to default
2145 default:
2146 ts = t;
2147 break;
2149 break;
2152 if (!dltSyntax)
2154 switch (ts->ty) {
2155 case Tident:
2156 // Don't wrap it yet, because that confuses resolve()
2157 ((TypeIdentifier *) ts)->maybe = 1;
2158 break;
2159 case Tpointer:
2160 ts = ts->maybe(false);
2161 break;
2165 return ts;
2168 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
2169 { Type *ts;
2171 //printf("parseDeclarator(tpl = %p)\n", tpl);
2172 t = parseBasicType2(t);
2174 switch (token.value)
2177 case TOKidentifier:
2178 if (pident)
2179 *pident = token.ident;
2180 else
2181 error("unexpected identifer '%s' in declarator", token.ident->toChars());
2182 ts = t;
2183 nextToken();
2184 break;
2186 case TOKlparen:
2187 /* Parse things with parentheses around the identifier, like:
2188 * int (*ident[3])[]
2189 * although the D style would be:
2190 * int[]*[3] ident
2192 nextToken();
2193 ts = parseDeclarator(t, pident);
2194 check(TOKrparen);
2195 break;
2197 default:
2198 ts = t;
2199 break;
2202 while (1)
2204 switch (token.value)
2206 #if CARRAYDECL
2207 /* Support C style array syntax:
2208 * int ident[]
2209 * as opposed to D-style:
2210 * int[] ident
2212 case TOKlbracket:
2213 { // This is the old C-style post [] syntax.
2214 TypeNext *ta;
2216 if (dltSyntax)
2217 error("use 'type[] var', not 'type var[]'");
2219 nextToken();
2220 if (token.value == TOKrbracket)
2221 { // It's a dynamic array
2222 ta = new TypeDArray(t); // []
2223 nextToken();
2225 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2226 { // It's an associative array
2228 //printf("it's an associative array\n");
2229 Type *index = parseType(); // [ type ]
2230 check(TOKrbracket);
2231 ta = new TypeAArray(t, index);
2233 else
2235 //printf("It's a static array\n");
2236 Expression *e = parseExpression(); // [ expression ]
2237 ta = new TypeSArray(t, e);
2238 check(TOKrbracket);
2241 /* Insert ta into
2242 * ts -> ... -> t
2243 * so that
2244 * ts -> ... -> ta -> t
2246 Type **pt;
2247 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2249 *pt = ta;
2250 continue;
2252 #endif
2253 case TOKlparen:
2255 if (tpl)
2257 /* Look ahead to see if this is (...)(...),
2258 * i.e. a function template declaration
2260 if (peekPastParen(&token)->value == TOKlparen)
2262 //printf("function template declaration\n");
2264 // Gather template parameter list
2265 *tpl = parseTemplateParameterList();
2269 int varargs;
2270 Arguments *arguments = parseParameters(&varargs);
2271 Type *tf = new TypeFunction(arguments, t, varargs, linkage);
2273 /* Parse const/invariant/nothrow postfix
2275 while (1)
2277 switch (token.value)
2279 case TOKconst:
2280 tf = tf->makeConst();
2281 nextToken();
2282 continue;
2284 case TOKinvariant:
2285 tf = tf->makeInvariant();
2286 nextToken();
2287 continue;
2289 case TOKnothrow:
2290 ((TypeFunction *)tf)->isnothrow = 1;
2291 nextToken();
2292 continue;
2294 case TOKpure:
2295 ((TypeFunction *)tf)->ispure = 1;
2296 nextToken();
2297 continue;
2299 break;
2302 /* Insert tf into
2303 * ts -> ... -> t
2304 * so that
2305 * ts -> ... -> tf -> t
2307 Type **pt;
2308 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2310 *pt = tf;
2311 break;
2314 break;
2317 return ts;
2320 /**********************************
2321 * Return array of Declaration *'s.
2324 Array *Parser::parseDeclarations()
2326 enum STC storage_class;
2327 enum STC stc;
2328 Type *ts;
2329 Type *t;
2330 Type *tfirst;
2331 Identifier *ident;
2332 Array *a;
2333 enum TOK tok;
2334 unsigned char *comment = token.blockComment;
2335 enum LINK link = linkage;
2337 //printf("parseDeclarations() %s\n", token.toChars());
2338 switch (token.value)
2340 case TOKtypedef:
2341 case TOKalias:
2342 tok = token.value;
2343 nextToken();
2344 break;
2346 default:
2347 tok = TOKreserved;
2348 break;
2351 storage_class = STCundefined;
2352 while (1)
2354 switch (token.value)
2356 case TOKconst:
2357 if (peek(&token)->value == TOKlparen)
2358 break;
2359 stc = STCconst;
2360 goto L1;
2362 case TOKinvariant:
2363 if (peek(&token)->value == TOKlparen)
2364 break;
2365 stc = STCinvariant;
2366 goto L1;
2368 case TOKstatic: stc = STCstatic; goto L1;
2369 case TOKfinal: stc = STCfinal; goto L1;
2370 case TOKauto: stc = STCauto; goto L1;
2371 case TOKscope: stc = STCscope; goto L1;
2372 case TOKoverride: stc = STCoverride; goto L1;
2373 case TOKabstract: stc = STCabstract; goto L1;
2374 case TOKsynchronized: stc = STCsynchronized; goto L1;
2375 case TOKdeprecated: stc = STCdeprecated; goto L1;
2376 case TOKnothrow: stc = STCnothrow; goto L1;
2377 case TOKpure: stc = STCpure; goto L1;
2378 case TOKtls: stc = STCtls; goto L1;
2379 case TOKenum: stc = STCmanifest; goto L1;
2381 if (storage_class & stc)
2382 error("redundant storage class '%s'", token.toChars());
2383 storage_class = (STC) (storage_class | stc);
2385 unsigned u = storage_class;
2386 u &= STCconst | STCinvariant | STCmanifest;
2387 if (u & (u - 1))
2388 error("conflicting storage class %s", Token::toChars(token.value));
2390 nextToken();
2391 continue;
2393 case TOKextern:
2394 if (peek(&token)->value != TOKlparen)
2395 { stc = STCextern;
2396 goto L1;
2399 link = parseLinkage();
2400 continue;
2402 default:
2403 break;
2405 break;
2408 a = new Array();
2410 /* Look for auto initializers:
2411 * storage_class identifier = initializer;
2413 while (storage_class &&
2414 token.value == TOKidentifier &&
2415 peek(&token)->value == TOKassign)
2417 ident = token.ident;
2418 nextToken();
2419 nextToken();
2420 Initializer *init = parseInitializer();
2421 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2422 v->storage_class = storage_class;
2423 v->dltNormalMode = dltNormalMode;
2424 a->push(v);
2425 if (token.value == TOKsemicolon || token.value == TOKendline)
2427 nextToken();
2428 addComment(v, comment);
2430 else if (token.value == TOKcomma)
2432 nextToken();
2433 if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
2435 error("Identifier expected following comma");
2437 else
2438 continue;
2440 else
2441 error("%s expected following auto declaration, not '%s'", endToken(), token.toChars());
2442 return a;
2445 if (token.value == TOKclass)
2446 { AggregateDeclaration *s;
2448 s = (AggregateDeclaration *)parseAggregate();
2449 s->storage_class |= storage_class;
2450 a->push(s);
2451 addComment(s, comment);
2452 return a;
2455 ts = parseBasicType();
2456 ts = parseBasicType2(ts);
2457 tfirst = NULL;
2459 while (1)
2461 Loc loc = this->loc;
2462 TemplateParameters *tpl = NULL;
2464 ident = NULL;
2465 t = parseDeclarator(ts, &ident, &tpl);
2466 assert(t);
2467 if (!tfirst)
2468 tfirst = t;
2469 else if (t != tfirst)
2470 error("multiple declarations must have the same type, not %s and %s",
2471 tfirst->toChars(), t->toChars());
2472 if (!ident)
2473 error("no identifier for declarator %s", t->toChars());
2475 if (tok == TOKtypedef || tok == TOKalias)
2476 { Declaration *v;
2477 Initializer *init;
2479 init = NULL;
2480 if (token.value == TOKassign)
2482 nextToken();
2483 init = parseInitializer();
2485 if (tok == TOKtypedef)
2486 v = new TypedefDeclaration(loc, ident, t, init);
2487 else
2488 { if (init)
2489 error("alias cannot have initializer");
2490 v = new AliasDeclaration(loc, ident, t);
2492 v->storage_class = storage_class;
2493 if (link == linkage)
2494 a->push(v);
2495 else
2497 Array *ax = new Array();
2498 ax->push(v);
2499 Dsymbol *s = new LinkDeclaration(link, ax);
2500 a->push(s);
2502 switch (token.value)
2503 { case TOKsemicolon:
2504 case TOKendline:
2505 nextToken();
2506 addComment(v, comment);
2507 break;
2509 case TOKcomma:
2510 nextToken();
2511 addComment(v, comment);
2512 continue;
2514 default:
2515 error("%s expected to close %s declaration", endToken(), Token::toChars(tok));
2516 break;
2519 else if (t->ty == Tfunction)
2520 { FuncDeclaration *f;
2521 Dsymbol *s;
2523 f = new FuncDeclaration(loc, 0, ident, storage_class, t);
2524 addComment(f, comment);
2525 parseContracts(f);
2526 addComment(f, NULL);
2527 if (link == linkage)
2529 s = f;
2531 else
2533 Array *ax = new Array();
2534 ax->push(f);
2535 s = new LinkDeclaration(link, ax);
2537 if (tpl) // it's a function template
2538 { Array *decldefs;
2539 TemplateDeclaration *tempdecl;
2541 // Wrap a template around the aggregate declaration
2542 decldefs = new Array();
2543 decldefs->push(s);
2544 tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs, dltSyntax);
2545 s = tempdecl;
2547 addComment(s, comment);
2548 a->push(s);
2550 else
2551 { VarDeclaration *v;
2552 Initializer *init;
2554 init = NULL;
2555 if (token.value == TOKassign)
2557 nextToken();
2558 init = parseInitializer();
2560 v = new VarDeclaration(loc, t, ident, init);
2561 if (dltSyntax)
2562 v->requirePointerInit = true;
2563 v->storage_class = storage_class;
2564 v->dltNormalMode = dltNormalMode;
2565 if (link == linkage)
2566 a->push(v);
2567 else
2569 Array *ax = new Array();
2570 ax->push(v);
2571 Dsymbol *s = new LinkDeclaration(link, ax);
2572 a->push(s);
2574 switch (token.value)
2576 case TOKendline:
2577 nextToken();
2578 addComment(v, comment);
2579 break;
2580 case TOKsemicolon:
2581 if (!dltSyntax)
2582 nextToken();
2583 addComment(v, comment);
2584 break;
2585 case TOKcomma:
2586 nextToken();
2587 addComment(v, comment);
2588 continue;
2590 default:
2591 error("%s expected, not '%s'", endToken(), token.toChars());
2592 break;
2595 break;
2597 return a;
2600 /*****************************************
2601 * Parse contracts following function declaration.
2604 void Parser::parseContracts(FuncDeclaration *f)
2606 Type *tb;
2607 enum LINK linksave = linkage;
2609 // The following is irrelevant, as it is overridden by sc->linkage in
2610 // TypeFunction::semantic
2611 linkage = LINKd; // nested functions have D linkage
2613 switch (token.value)
2615 case TOKlcurly:
2616 case TOKcolon:
2617 if (token.value != startBlockTok)
2618 error("use %s to start a new block", Token::toChars(startBlockTok));
2619 if (f->frequire || f->fensure)
2620 error("missing body { ... } after in or out");
2621 f->fbody = parseStatement(PSsemi | PScolon);
2622 f->endloc = endloc;
2623 break;
2625 case TOKbody:
2626 nextToken();
2627 f->fbody = parseStatement(PScurly);
2628 f->endloc = endloc;
2629 break;
2631 case TOKsemicolon:
2632 if (dltSyntax)
2633 error("unexpected semi-colon after function declaration");
2634 // fall-through
2635 case TOKendline:
2636 if (f->frequire || f->fensure)
2637 error("missing body { ... } after in or out");
2638 nextToken();
2639 break;
2641 #if 0 // Do we want this for function declarations, so we can do:
2642 // int x, y, foo(), z;
2643 case TOKcomma:
2644 nextToken();
2645 continue;
2646 #endif
2648 #if 0 // Dumped feature
2649 case TOKthrow:
2650 if (!f->fthrows)
2651 f->fthrows = new Array();
2652 nextToken();
2653 check(TOKlparen);
2654 while (1)
2656 tb = parseBasicType();
2657 f->fthrows->push(tb);
2658 if (token.value == TOKcomma)
2659 { nextToken();
2660 continue;
2662 break;
2664 check(TOKrparen);
2665 goto L1;
2666 #endif
2668 case TOKin:
2669 nextToken();
2670 if (f->frequire)
2671 error("redundant 'in' statement");
2672 f->frequire = parseStatement(PScurly | PSscope);
2673 goto L1;
2675 case TOKout:
2676 // parse: out (identifier) { statement }
2677 nextToken();
2678 if (token.value != startBlockTok)
2680 check(TOKlparen);
2681 if (token.value != TOKidentifier)
2682 error("(identifier) following 'out' expected, not %s", token.toChars());
2683 f->outId = token.ident;
2684 nextToken();
2685 check(TOKrparen);
2687 if (f->fensure)
2688 error("redundant 'out' statement");
2689 f->fensure = parseStatement(PScurly | PSscope);
2690 goto L1;
2692 default:
2693 error("%s expected following function declaration", endToken());
2694 break;
2696 linkage = linksave;
2699 /*****************************************
2702 Initializer *Parser::parseInitializer()
2704 StructInitializer *is;
2705 ArrayInitializer *ia;
2706 ExpInitializer *ie;
2707 Expression *e;
2708 Identifier *id;
2709 Initializer *value;
2710 int comma;
2711 Loc loc = this->loc;
2712 Token *t;
2713 int braces;
2715 switch (token.value)
2717 case TOKlcurly:
2718 /* Scan ahead to see if it is a struct initializer or
2719 * a function literal.
2720 * If it contains a ';', it is a function literal.
2721 * Treat { } as a struct initializer.
2723 braces = 1;
2724 for (t = peek(&token); 1; t = peek(t))
2726 switch (t->value)
2728 case TOKsemicolon:
2729 case TOKreturn:
2730 goto Lexpression;
2732 case TOKlcurly:
2733 braces++;
2734 continue;
2736 case TOKrcurly:
2737 if (--braces == 0)
2738 break;
2739 continue;
2741 case TOKeof:
2742 break;
2744 default:
2745 continue;
2747 break;
2750 is = new StructInitializer(loc);
2751 nextToken();
2752 comma = 0;
2753 while (1)
2755 switch (token.value)
2757 case TOKidentifier:
2758 if (comma == 1)
2759 error("comma expected separating field initializers");
2760 t = peek(&token);
2761 if (t->value == TOKcolon)
2763 id = token.ident;
2764 nextToken();
2765 nextToken(); // skip over ':'
2767 else
2768 { id = NULL;
2770 value = parseInitializer();
2771 is->addInit(id, value);
2772 comma = 1;
2773 continue;
2775 case TOKcomma:
2776 nextToken();
2777 comma = 2;
2778 continue;
2780 case TOKrcurly: // allow trailing comma's
2781 nextToken();
2782 break;
2784 case TOKeof:
2785 error("found EOF instead of initializer");
2786 break;
2788 default:
2789 value = parseInitializer();
2790 is->addInit(NULL, value);
2791 comma = 1;
2792 continue;
2793 //error("found '%s' instead of field initializer", token.toChars());
2794 //break;
2796 break;
2798 return is;
2800 case TOKlbracket:
2801 ia = new ArrayInitializer(loc);
2802 nextToken();
2803 comma = 0;
2804 while (1)
2806 switch (token.value)
2808 default:
2809 if (comma == 1)
2810 { error("comma expected separating array initializers, not %s", token.toChars());
2811 nextToken();
2812 break;
2814 e = parseAssignExp();
2815 if (!e)
2816 break;
2817 if (token.value == TOKcolon)
2819 nextToken();
2820 value = parseInitializer();
2822 else
2823 { value = new ExpInitializer(e->loc, e);
2824 e = NULL;
2826 ia->addInit(e, value);
2827 comma = 1;
2828 continue;
2830 case TOKlcurly:
2831 case TOKlbracket:
2832 if (comma == 1)
2833 error("comma expected separating array initializers, not %s", token.toChars());
2834 value = parseInitializer();
2835 ia->addInit(NULL, value);
2836 comma = 1;
2837 continue;
2839 case TOKcomma:
2840 nextToken();
2841 comma = 2;
2842 continue;
2844 case TOKrbracket: // allow trailing comma's
2845 nextToken();
2846 break;
2848 case TOKeof:
2849 error("found '%s' instead of array initializer", token.toChars());
2850 break;
2852 break;
2854 return ia;
2856 case TOKvoid:
2857 t = peek(&token);
2858 if (t->value == TOKsemicolon || t->value == TOKcomma || t->value == TOKendline)
2860 nextToken();
2861 return new VoidInitializer(loc);
2863 goto Lexpression;
2865 default:
2866 Lexpression:
2867 e = parseAssignExp();
2868 ie = new ExpInitializer(loc, e);
2869 return ie;
2873 /*****************************************
2874 * Parses default argument initializer expression that is an assign expression,
2875 * with special handling for __FILE__ and __LINE__.
2878 Expression *Parser::parseDefaultInitExp()
2880 if (token.value == TOKfile ||
2881 token.value == TOKline)
2883 Token *t = peek(&token);
2884 if (t->value == TOKcomma || t->value == TOKrparen)
2885 { Expression *e;
2887 if (token.value == TOKfile)
2888 e = new FileInitExp(loc);
2889 else
2890 e = new LineInitExp(loc);
2891 nextToken();
2892 return e;
2896 Expression *e = parseAssignExp();
2897 return e;
2900 Statement *Parser::logStatement(int level) {
2901 nextToken();
2902 if (token.value != TOKlparen)
2903 error(loc, "found '%s' when expecting '('", token.toChars());
2904 return new LogStatement(loc, level, parseArguments());
2907 /*****************************************
2908 * Input:
2909 * flags PSxxxx
2912 Statement *DltParser::parseStatement(int flags)
2914 optionalEndline();
2915 if (flags & (PScolon | PSscope))
2916 flags |= PScurly;
2917 return Parser::parseStatement(flags);
2920 Statement *Parser::parseStatement(int flags)
2921 { Statement *s;
2922 Token *t;
2923 Condition *condition;
2924 Statement *ifbody;
2925 Statement *elsebody;
2926 Loc loc = this->loc;
2928 //printf("parseStatement()\n");
2930 if ((flags & PScurly) && token.value != startBlockTok)
2931 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
2933 int tok = token.value;
2935 switch (token.value)
2937 case TOKidentifier:
2938 if (!dltSyntax)
2940 // Need to look ahead to see if it is a declaration, label, or expression
2941 t = peek(&token);
2942 if (t->value == TOKcolon)
2943 { // It's a label
2944 Identifier *ident;
2946 ident = token.ident;
2947 nextToken();
2948 nextToken();
2949 s = parseStatement(PSsemi);
2950 s = new LabelStatement(loc, ident, s);
2951 break;
2954 // fallthrough to TOKdot
2955 case TOKdot:
2956 case TOKtypeof:
2957 if (isDeclaration(&token, 2, TOKreserved, NULL))
2958 goto Ldeclaration;
2959 else
2960 goto Lexp;
2961 break;
2963 case TOKassert:
2964 case TOKthis:
2965 case TOKsuper:
2966 case TOKint32v:
2967 case TOKuns32v:
2968 case TOKint64v:
2969 case TOKuns64v:
2970 case TOKfloat32v:
2971 case TOKfloat64v:
2972 case TOKfloat80v:
2973 case TOKimaginary32v:
2974 case TOKimaginary64v:
2975 case TOKimaginary80v:
2976 case TOKcharv:
2977 case TOKwcharv:
2978 case TOKdcharv:
2979 case TOKnull:
2980 case TOKtrue:
2981 case TOKfalse:
2982 case TOKstring:
2983 case TOKlparen:
2984 case TOKcast:
2985 case TOKmul:
2986 case TOKmin:
2987 case TOKadd:
2988 case TOKplusplus:
2989 case TOKminusminus:
2990 case TOKnew:
2991 case TOKdelete:
2992 case TOKdelegate:
2993 case TOKfunction:
2994 case TOKtypeid:
2995 case TOKis:
2996 case TOKlbracket:
2997 case TOKtraits:
2998 case TOKfile:
2999 case TOKline:
3000 Lexp:
3001 { Expression *exp;
3003 exp = parseExpression();
3004 if (!dltSyntax)
3005 check(TOKsemicolon, "statement");
3006 s = new ExpStatement(loc, exp);
3007 break;
3010 case TOKstatic:
3011 { // Look ahead to see if it's static assert() or static if()
3012 Token *t;
3014 t = peek(&token);
3015 if (t->value == TOKassert)
3017 nextToken();
3018 s = new StaticAssertStatement(parseStaticAssert());
3019 break;
3021 if (t->value == TOKif)
3023 nextToken();
3024 condition = parseStaticIfCondition();
3025 goto Lcondition;
3027 if (dltNormalMode)
3028 error("no static variables in Delight");
3029 goto Ldeclaration;
3032 CASE_BASIC_TYPES:
3033 case TOKtypedef:
3034 case TOKalias:
3035 case TOKconst:
3036 case TOKauto:
3037 case TOKextern:
3038 case TOKfinal:
3039 case TOKinvariant:
3040 // case TOKtypeof:
3041 Ldeclaration:
3042 { Array *a;
3044 a = parseDeclarations();
3045 if (a->dim > 1)
3047 Statements *as = new Statements();
3048 as->reserve(a->dim);
3049 for (int i = 0; i < a->dim; i++)
3051 Dsymbol *d = (Dsymbol *)a->data[i];
3052 s = new DeclarationStatement(loc, d);
3053 as->push(s);
3055 s = new CompoundStatement(loc, as);
3057 else if (a->dim == 1)
3059 Dsymbol *d = (Dsymbol *)a->data[0];
3060 s = new DeclarationStatement(loc, d);
3062 else
3063 assert(0);
3064 if (flags & PSscope)
3065 s = new ScopeStatement(loc, s);
3066 break;
3069 case TOKstruct:
3070 case TOKunion:
3071 case TOKclass:
3072 case TOKinterface:
3073 { Dsymbol *d;
3075 d = parseAggregate();
3076 s = new DeclarationStatement(loc, d);
3077 break;
3080 case TOKenum:
3081 { /* Determine if this is a manifest constant declaration,
3082 * or a conventional enum.
3084 Dsymbol *d;
3085 Token *t = peek(&token);
3086 if (t->value == TOKlcurly || t->value == TOKcolon)
3087 d = parseEnum();
3088 else if (t->value != TOKidentifier)
3089 goto Ldeclaration;
3090 else
3092 t = peek(t);
3093 if (t->value == TOKlcurly || t->value == TOKcolon ||
3094 t->value == TOKsemicolon)
3095 d = parseEnum();
3096 else
3097 goto Ldeclaration;
3099 s = new DeclarationStatement(loc, d);
3100 break;
3103 case TOKmixin:
3104 { t = peek(&token);
3105 if (t->value == TOKlparen)
3106 { // mixin(string)
3107 nextToken();
3108 check(TOKlparen, "mixin");
3109 Expression *e = parseAssignExp();
3110 check(TOKrparen);
3111 if (dltSyntax) {
3112 if (token.value != TOKsemicolon && token.value != TOKendline) {
3113 error("expected newline after mixin(), not '%s'", token.toChars());
3115 } else {
3116 check(TOKsemicolon);
3118 s = new CompileStatement(loc, e);
3119 break;
3121 Dsymbol *d = parseMixin();
3122 s = new DeclarationStatement(loc, d);
3123 break;
3126 case TOKcolon:
3127 case TOKlcurly:
3128 { Statements *statements;
3130 if (token.value != startBlockTok)
3131 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
3133 nextToken();
3134 optionalEndline();
3135 statements = new Statements();
3136 while (token.value != TOKrcurly)
3138 statements->push(parseStatement(PSsemi | PScurlyscope));
3139 optionalEndline();
3141 endloc = this->loc;
3142 s = new CompoundStatement(loc, statements);
3143 if (flags & (PSscope | PScurlyscope))
3144 s = new ScopeStatement(loc, s);
3145 nextToken();
3146 break;
3149 case TOKlog_error: s = logStatement(LogStatement::Error); break;
3150 case TOKlog_warning: s = logStatement(LogStatement::Warn); break;
3151 case TOKlog_info: s = logStatement(LogStatement::Info); break;
3152 case TOKlog_trace: s = logStatement(LogStatement::Trace); break;
3154 case TOKwhile:
3155 { Expression *condition;
3156 Statement *body;
3158 nextToken();
3159 checkLParen();
3160 condition = parseExpression();
3161 checkRParen();
3162 body = parseStatement(PSscope);
3163 s = new WhileStatement(loc, condition, body);
3164 break;
3167 case TOKsemicolon:
3168 if (!(flags & PSsemi))
3169 error("use '{ }' for an empty statement, not a ';'");
3170 nextToken();
3171 s = new ExpStatement(loc, NULL);
3172 break;
3174 case TOKdo:
3175 { Statement *body;
3176 Expression *condition;
3178 nextToken();
3179 body = parseStatement(PSscope);
3180 check(TOKwhile);
3181 checkLParen();
3182 condition = parseExpression();
3183 checkRParen();
3184 s = new DoStatement(loc, body, condition);
3185 break;
3188 case TOKfor:
3190 Statement *init;
3191 Expression *condition;
3192 Expression *increment;
3193 Statement *body;
3195 nextToken();
3197 if (token.value == TOKlparen) {
3198 /* for (init; cond; incr): ... */
3199 nextToken();
3200 if (token.value == TOKsemicolon)
3201 { init = NULL;
3202 nextToken();
3204 else
3205 { init = parseStatement(0);
3206 if (dltSyntax)
3207 check(TOKsemicolon);
3209 if (token.value == TOKsemicolon)
3211 condition = NULL;
3212 nextToken();
3214 else
3216 condition = parseExpression();
3217 check(TOKsemicolon, "for condition");
3219 if (token.value == TOKrparen)
3220 { increment = NULL;
3221 nextToken();
3223 else
3224 { increment = parseExpression();
3225 check(TOKrparen);
3227 body = parseStatement(PSscope);
3228 s = new ForStatement(loc, init, condition, increment, body);
3229 if (init)
3230 s = new ScopeStatement(loc, s);
3231 } else if (dltSyntax)
3232 goto caseForeach;
3233 break;
3236 caseForeach:
3237 case TOKforeach:
3238 case TOKforeach_reverse:
3240 /* for var in seq: ... */
3241 /* for index, var in seq: ... */
3242 Arguments *arguments;
3244 Statement *d;
3245 Statement *body;
3246 Expression *aggr;
3247 enum TOK op = (TOK) tok;
3249 if (tok == TOKfor)
3250 op = TOKforeach; // Delight foreach syntax
3251 else
3252 nextToken();
3254 checkLParen();
3256 TOK inTok = dltSyntax ? TOKin : TOKsemicolon;
3258 arguments = new Arguments();
3260 while (1)
3262 Type *tb;
3263 Identifier *ai = NULL;
3264 Type *at;
3265 unsigned storageClass;
3266 Argument *a;
3268 storageClass = 0;
3269 if (token.value == TOKinout || token.value == TOKref)
3270 { storageClass = STCref;
3271 nextToken();
3273 if (token.value == TOKidentifier)
3275 Token *t = peek(&token);
3276 if (t->value == TOKcomma || t->value == inTok)
3277 { ai = token.ident;
3278 at = NULL; // infer argument type
3279 nextToken();
3280 goto Larg;
3283 at = parseType(&ai);
3284 if (!ai)
3285 error("no identifier for declarator %s", at->toChars());
3286 Larg:
3287 a = new Argument(storageClass, at, ai, NULL);
3288 arguments->push(a);
3289 if (token.value == TOKcomma)
3290 { nextToken();
3291 continue;
3293 break;
3296 check(inTok);
3298 aggr = parseExpression();
3299 if (token.value == TOKslice && arguments->dim == 1)
3301 Argument *a = (Argument *)arguments->data[0];
3302 delete arguments;
3303 nextToken();
3304 Expression *upr = parseExpression();
3305 checkRParen();
3306 if (token.value == TOKreserved)
3308 op = TOKforeach_reverse;
3309 nextToken();
3311 body = parseStatement(0);
3312 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3314 else
3316 checkRParen();
3317 if (token.value == TOKreserved)
3319 op = TOKforeach_reverse;
3320 nextToken();
3322 body = parseStatement(0);
3323 s = new ForeachStatement(loc, op, arguments, aggr, body);
3325 break;
3328 case TOKif:
3329 { Argument *arg = NULL;
3330 Expression *condition;
3331 Statement *ifbody;
3332 Statement *elsebody;
3334 nextToken();
3335 checkLParen();
3337 if (token.value == TOKauto)
3339 nextToken();
3340 if (token.value == TOKidentifier)
3342 Token *t = peek(&token);
3343 if (t->value == TOKassign)
3345 arg = new Argument(0, NULL, token.ident, NULL);
3346 nextToken();
3347 nextToken();
3349 else
3350 { error("= expected following auto identifier");
3351 goto Lerror;
3354 else
3355 { error("identifier expected following auto");
3356 goto Lerror;
3359 else if (isDeclaration(&token, 2, TOKassign, NULL))
3361 Type *at;
3362 Identifier *ai;
3364 at = parseType(&ai);
3365 check(TOKassign);
3366 arg = new Argument(0, at, ai, NULL);
3369 // Check for " ident;"
3370 else if (token.value == TOKidentifier && !dltSyntax)
3372 Token *t = peek(&token);
3373 if (t->value == TOKcomma || t->value == TOKsemicolon)
3375 arg = new Argument(0, NULL, token.ident, NULL);
3376 nextToken();
3377 nextToken();
3378 if (1 || !global.params.useDeprecated)
3379 error("if (v; e) is deprecated, use if (auto v = e)");
3383 condition = parseExpression();
3384 checkRParen();
3385 ifbody = parseStatement(PSscope);
3386 if (token.value == TOKelse)
3388 nextToken();
3389 if (dltSyntax)
3391 if (token.value == TOKcolon) {
3392 elsebody = parseStatement(PSscope);
3393 } else if (token.value == TOKif) {
3394 elsebody = parseStatement(0);
3395 } else {
3396 error("Expected 'else:' or 'else if', not 'else %s'", token.toChars());
3397 elsebody = NULL;
3400 else
3401 elsebody = parseStatement(PSscope);
3403 else
3404 elsebody = NULL;
3405 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3406 break;
3409 case TOKscope:
3410 if (peek(&token)->value != TOKlparen)
3411 goto Ldeclaration; // scope used as storage class
3412 nextToken();
3413 check(TOKlparen);
3414 if (token.value != TOKidentifier)
3415 { error("scope identifier expected");
3416 goto Lerror;
3418 else
3419 { TOK t = TOKon_scope_exit;
3420 Identifier *id = token.ident;
3422 if (id == Id::exit)
3423 t = TOKon_scope_exit;
3424 else if (id == Id::failure)
3425 t = TOKon_scope_failure;
3426 else if (id == Id::success)
3427 t = TOKon_scope_success;
3428 else
3429 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3430 nextToken();
3431 check(TOKrparen);
3432 Statement *st = parseStatement(PScolon | PScurlyscope);
3433 s = new OnScopeStatement(loc, t, st);
3434 break;
3437 case TOKdebug:
3438 nextToken();
3439 condition = parseDebugCondition();
3440 goto Lcondition;
3442 case TOKversion:
3443 nextToken();
3444 condition = parseVersionCondition();
3445 goto Lcondition;
3447 Lcondition:
3448 if (dltSyntax && token.value != TOKcolon)
3449 error("expected colon after condition, not '%s'", token.toChars());
3450 ifbody = parseStatement(PScolon /*PSsemi*/);
3451 elsebody = NULL;
3452 if (token.value == TOKelse)
3454 nextToken();
3455 elsebody = parseStatement(PScolon /*PSsemi*/);
3457 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3458 break;
3460 case TOKpragma:
3461 { Identifier *ident;
3462 Expressions *args = NULL;
3463 Statement *body;
3465 nextToken();
3466 check(TOKlparen);
3467 if (token.value != TOKidentifier)
3468 { error("pragma(identifier expected");
3469 goto Lerror;
3471 ident = token.ident;
3472 nextToken();
3473 if (token.value == TOKcomma)
3474 args = parseArguments(); // pragma(identifier, args...);
3475 else
3476 check(TOKrparen); // pragma(identifier);
3477 if (token.value == TOKsemicolon)
3478 { nextToken();
3479 body = NULL;
3481 else
3482 body = parseStatement(PSsemi | PScolon);
3483 s = new PragmaStatement(loc, ident, args, body);
3484 break;
3487 case TOKswitch:
3488 { Expression *condition;
3489 Statement *body;
3491 nextToken();
3492 checkLParen();
3493 condition = parseExpression();
3494 checkRParen();
3495 body = parseStatement(PSscope | PScolon);
3496 s = new SwitchStatement(loc, condition, body);
3497 break;
3500 case TOKcase:
3501 { Expression *exp;
3502 Statements *statements;
3503 Array cases; // array of Expression's
3505 while (1)
3507 nextToken();
3508 exp = parseAssignExp();
3509 cases.push(exp);
3510 if (token.value != TOKcomma)
3511 break;
3514 if (dltSyntax)
3516 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3518 else
3520 check(TOKcolon);
3522 statements = new Statements();
3523 while (token.value != TOKcase &&
3524 token.value != TOKdefault &&
3525 token.value != TOKrcurly)
3527 statements->push(parseStatement(PSsemi | PScurlyscope));
3529 s = new CompoundStatement(loc, statements);
3532 s = new ScopeStatement(loc, s);
3534 // Keep cases in order by building the case statements backwards
3535 for (int i = cases.dim; i; i--)
3537 exp = (Expression *)cases.data[i - 1];
3538 s = new CaseStatement(loc, exp, s);
3540 break;
3543 case TOKdefault:
3545 Statements *statements;
3547 nextToken();
3549 if (dltSyntax)
3551 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3553 else
3555 check(TOKcolon);
3557 statements = new Statements();
3558 while (token.value != TOKcase &&
3559 token.value != TOKdefault &&
3560 token.value != TOKrcurly)
3562 statements->push(parseStatement(PSsemi | PScurlyscope));
3564 s = new CompoundStatement(loc, statements);
3567 s = new ScopeStatement(loc, s);
3568 s = new DefaultStatement(loc, s);
3569 break;
3572 case TOKreturn:
3573 { Expression *exp;
3575 nextToken();
3576 if (token.value == TOKsemicolon || token.value == TOKendline)
3577 exp = NULL;
3578 else
3579 exp = parseExpression();
3581 if (!dltSyntax)
3582 check(TOKsemicolon, "return statement");
3583 else if (token.value != TOKendline) {
3584 error("Expected end-of-line after return statement, but found '%s'", token.toChars());
3587 s = new ReturnStatement(loc, exp);
3588 break;
3591 case TOKbreak:
3592 { Identifier *ident;
3594 nextToken();
3595 if (token.value == TOKidentifier)
3596 { ident = token.ident;
3597 nextToken();
3599 else
3600 ident = NULL;
3601 if (token.value != TOKsemicolon && token.value != TOKendline) {
3602 error("expected %s after break, not '%s'", endToken(), token.toChars());
3604 if (!dltSyntax)
3605 nextToken();
3606 s = new BreakStatement(loc, ident);
3607 break;
3610 case TOKcontinue:
3611 { Identifier *ident;
3613 nextToken();
3614 if (token.value == TOKidentifier)
3615 { ident = token.ident;
3616 nextToken();
3618 else
3619 ident = NULL;
3620 check(TOKsemicolon, "continue statement");
3621 s = new ContinueStatement(loc, ident);
3622 break;
3625 case TOKgoto:
3626 { Identifier *ident;
3628 nextToken();
3629 if (token.value == TOKdefault)
3631 nextToken();
3632 s = new GotoDefaultStatement(loc);
3634 else if (token.value == TOKcase)
3636 Expression *exp = NULL;
3638 nextToken();
3639 if (token.value != TOKsemicolon)
3640 exp = parseExpression();
3641 s = new GotoCaseStatement(loc, exp);
3643 else
3645 if (token.value != TOKidentifier)
3646 { error("Identifier expected following goto");
3647 ident = NULL;
3649 else
3650 { ident = token.ident;
3651 nextToken();
3653 s = new GotoStatement(loc, ident);
3655 if (dltSyntax)
3657 if (token.value != TOKsemicolon && token.value != TOKendline) {
3658 error("expected %s after goto statement, not '%s'", endToken(), token.toChars());
3661 else
3662 check(TOKsemicolon);
3663 break;
3666 case TOKsynchronized:
3667 { Expression *exp;
3668 Statement *body;
3670 nextToken();
3671 if (token.value == TOKlparen)
3673 nextToken();
3674 exp = parseExpression();
3675 check(TOKrparen);
3677 else
3678 exp = NULL;
3679 body = parseStatement(PSscope);
3680 s = new SynchronizedStatement(loc, exp, body);
3681 break;
3684 case TOKwith:
3685 { Expression *exp;
3686 Statement *body;
3688 nextToken();
3689 check(TOKlparen);
3690 exp = parseExpression();
3691 check(TOKrparen);
3692 body = parseStatement(PSscope);
3693 s = new WithStatement(loc, exp, body);
3694 break;
3697 case TOKtry:
3698 { Statement *body;
3699 Array *catches = NULL;
3700 Statement *finalbody = NULL;
3702 nextToken();
3703 body = parseStatement(PSscope);
3704 while (token.value == TOKcatch)
3706 Statement *handler;
3707 Catch *c;
3708 Type *t;
3709 Identifier *id;
3710 Loc loc = this->loc;
3712 nextToken();
3713 if (token.value == startBlockTok)
3715 t = NULL;
3716 id = NULL;
3718 else
3720 check(TOKlparen);
3721 id = NULL;
3722 t = parseType(&id);
3723 check(TOKrparen);
3725 handler = parseStatement(PScolon);
3726 c = new Catch(loc, t, id, handler);
3727 if (!catches)
3728 catches = new Array();
3729 catches->push(c);
3732 if (token.value == TOKfinally)
3733 { nextToken();
3734 finalbody = parseStatement(PScolon);
3737 s = body;
3738 if (!catches && !finalbody)
3739 error("catch or finally expected following try");
3740 else
3741 { if (catches)
3742 s = new TryCatchStatement(loc, body, catches);
3743 if (finalbody)
3744 s = new TryFinallyStatement(loc, s, finalbody);
3746 break;
3749 case TOKthrow:
3750 { Expression *exp;
3752 nextToken();
3753 exp = parseExpression();
3754 if (token.value != TOKsemicolon && token.value != TOKendline) {
3755 error("%s expected after throw statement, not '%s'", endToken(), token.toChars());
3757 if (!dltSyntax)
3758 nextToken();
3759 s = new ThrowStatement(loc, exp);
3760 break;
3763 case TOKvolatile:
3764 nextToken();
3765 s = parseStatement(PSsemi | PScurlyscope);
3766 if (!global.params.useDeprecated)
3767 error("volatile statements deprecated; used synchronized statements instead");
3768 s = new VolatileStatement(loc, s);
3769 break;
3771 case TOKasm:
3772 { Statements *statements;
3773 Identifier *label;
3774 Loc labelloc;
3775 Token *toklist;
3776 Token **ptoklist;
3778 // Parse the asm block into a sequence of AsmStatements,
3779 // each AsmStatement is one instruction.
3780 // Separate out labels.
3781 // Defer parsing of AsmStatements until semantic processing.
3783 nextToken();
3784 #if GDC_EXTENDED_ASM_SYNTAX
3785 if (token.value == TOKlparen)
3787 nextToken();
3788 s = parseExtAsm(1);
3789 break;
3791 #endif
3792 check(startBlockTok);
3793 toklist = NULL;
3794 ptoklist = &toklist;
3795 label = NULL;
3796 statements = new Statements();
3797 while (1)
3799 switch (token.value)
3801 case TOKidentifier:
3802 if (!toklist)
3804 // Look ahead to see if it is a label
3805 t = peek(&token);
3806 if (t->value == TOKcolon)
3807 { // It's a label
3808 label = token.ident;
3809 labelloc = this->loc;
3810 nextToken();
3811 nextToken();
3812 continue;
3815 goto Ldefault;
3817 case TOKrcurly:
3818 if (toklist || label)
3820 error("asm statements must end in ';'");
3822 break;
3824 case TOKendline:
3825 case TOKsemicolon:
3826 s = NULL;
3827 if (toklist || label)
3828 { // Create AsmStatement from list of tokens we've saved
3829 s = new AsmStatement(this->loc, toklist);
3830 toklist = NULL;
3831 ptoklist = &toklist;
3832 if (label)
3833 { s = new LabelStatement(labelloc, label, s);
3834 label = NULL;
3836 statements->push(s);
3838 nextToken();
3839 continue;
3841 case TOKeof:
3842 /* { */
3843 error("matching '}' expected, not end of file");
3844 break;
3846 case TOKlparen:
3847 case TOKstring:
3848 // If the first token is a string or '(', parse as extended asm.
3849 if (! toklist)
3851 s = parseExtAsm(0);
3852 statements->push(s);
3853 continue;
3855 // ...else, drop through.
3857 default:
3858 Ldefault:
3859 *ptoklist = new Token();
3860 memcpy(*ptoklist, &token, sizeof(Token));
3861 ptoklist = &(*ptoklist)->next;
3862 *ptoklist = NULL;
3864 nextToken();
3865 continue;
3867 break;
3869 s = new CompoundStatement(loc, statements);
3870 nextToken();
3871 break;
3874 default:
3875 error("found '%s' instead of statement", token.toChars());
3876 goto Lerror;
3878 Lerror:
3879 while (token.value != TOKrcurly &&
3880 token.value != TOKsemicolon &&
3881 token.value != TOKeof)
3882 nextToken();
3883 if (token.value == TOKsemicolon)
3884 nextToken();
3885 s = NULL;
3886 break;
3889 return s;
3892 Statement *Parser::parseExtAsm(int expect_rparen)
3894 Expression * insnTemplate;
3895 Expressions * args = NULL;
3896 Array * argNames = NULL;
3897 Expressions * argConstraints = NULL;
3898 int nOutputArgs = 0;
3899 Expressions * clobbers = NULL;
3900 bool isInputPhase = false; // Output operands first, then input.
3902 insnTemplate = parseExpression();
3903 if (token.value == TOKrparen || token.value == TOKsemicolon)
3904 goto Ldone;
3905 check(TOKcolon);
3906 while (1) {
3907 Expression * arg = NULL;
3908 Identifier * name = NULL;
3909 Expression * constraint = NULL;
3911 switch (token.value)
3913 case TOKsemicolon:
3914 case TOKrparen:
3915 goto Ldone;
3917 case TOKcolon:
3918 nextToken();
3919 goto LnextPhase;
3921 case TOKeof:
3922 error("unterminated statement");
3924 case TOKlbracket:
3925 nextToken();
3926 if (token.value == TOKidentifier)
3928 name = token.ident;
3929 nextToken();
3931 else
3932 error("expected identifier after '['");
3933 check(TOKrbracket);
3934 // drop through
3935 default:
3936 constraint = parsePrimaryExp();
3937 if (constraint->op != TOKstring)
3938 error("expected constant string constraint for operand");
3939 arg = parseAssignExp();
3940 if (! args)
3942 args = new Expressions;
3943 argConstraints = new Expressions;
3944 argNames = new Array;
3946 args->push(arg);
3947 argNames->push(name);
3948 argConstraints->push(constraint);
3949 if (! isInputPhase)
3950 nOutputArgs++;
3952 if (token.value == TOKcomma)
3953 nextToken();
3954 break;
3956 continue;
3957 LnextPhase:
3958 if (! isInputPhase)
3959 isInputPhase = true;
3960 else
3961 break;
3964 while (1)
3966 Expression * clobber;
3968 switch (token.value)
3970 case TOKsemicolon:
3971 case TOKrparen:
3972 goto Ldone;
3974 case TOKeof:
3975 error("unterminated statement");
3977 default:
3978 clobber = parseAssignExp();
3979 if (clobber->op != TOKstring)
3980 error("expected constant string constraint for clobber name");
3981 if (! clobbers)
3982 clobbers = new Expressions;
3983 clobbers->push(clobber);
3985 if (token.value == TOKcomma)
3986 nextToken();
3987 break;
3990 Ldone:
3991 if (expect_rparen)
3992 check(TOKrparen);
3993 else
3994 check(TOKsemicolon);
3996 return new ExtAsmStatement(loc, insnTemplate, args, argNames,
3997 argConstraints, nOutputArgs, clobbers);
4000 void Parser::optionalEndline() {
4001 while (token.value == TOKendline) {
4002 nextToken();
4006 void Parser::check(enum TOK value)
4008 check(loc, value);
4011 void Parser::check(Loc loc, enum TOK value)
4013 if (token.value != value)
4014 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
4015 nextToken();
4018 void Parser::check(enum TOK value, char *string)
4020 if (token.value != value)
4021 error("found '%s' when expecting '%s' following '%s'",
4022 token.toChars(), Token::toChars(value), string);
4023 nextToken();
4026 char *Parser::endToken()
4028 return "semicolon";
4031 char *DltParser::endToken()
4033 return "newline";
4036 void Parser::checkLParen() { check(TOKlparen); }
4037 void Parser::checkRParen() { check(TOKrparen); }
4039 void DltParser::checkLParen() { }
4040 void DltParser::checkRParen() { }
4042 /************************************
4043 * Determine if the scanner is sitting on the start of a declaration.
4044 * Input:
4045 * needId 0 no identifier
4046 * 1 identifier optional
4047 * 2 must have identifier
4050 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
4052 int haveId = 0;
4054 if ((t->value == TOKconst || t->value == TOKinvariant) &&
4055 peek(t)->value != TOKlparen)
4056 { /* const type
4057 * invariant type
4059 t = peek(t);
4062 if (!isBasicType(&t))
4063 return FALSE;
4064 if (!isDeclarator(&t, &haveId, endtok))
4065 return FALSE;
4066 if ( needId == 1 ||
4067 (needId == 0 && !haveId) ||
4068 (needId == 2 && haveId))
4069 { if (pt)
4070 *pt = t;
4071 return TRUE;
4073 else
4074 return FALSE;
4077 int Parser::isBasicType(Token **pt)
4079 // This code parallels parseBasicType()
4080 Token *t = *pt;
4081 Token *t2;
4082 int parens;
4083 int haveId = 0;
4085 switch (t->value)
4087 CASE_BASIC_TYPES:
4088 t = peek(t);
4089 break;
4091 case TOKidentifier:
4092 t = peek(t);
4093 if (t->value == TOKnot)
4095 goto L4;
4097 goto L3;
4098 while (1)
4101 t = peek(t);
4103 if (t->value == TOKdot)
4105 Ldot:
4106 t = peek(t);
4107 if (t->value != TOKidentifier)
4108 goto Lfalse;
4109 t = peek(t);
4110 if (t->value != TOKnot)
4111 goto L3;
4113 t = peek(t);
4114 if (t->value != TOKlparen)
4115 goto Lfalse;
4116 if (!skipParens(t, &t))
4117 goto Lfalse;
4119 else
4120 break;
4122 break;
4124 case TOKdot:
4125 goto Ldot;
4127 case TOKtypeof:
4128 /* typeof(exp).identifier...
4130 t = peek(t);
4131 if (t->value != TOKlparen)
4132 goto Lfalse;
4133 if (!skipParens(t, &t))
4134 goto Lfalse;
4135 goto L2;
4137 case TOKconst:
4138 case TOKinvariant:
4139 // const(type) or invariant(type)
4140 t = peek(t);
4141 if (t->value != TOKlparen)
4142 goto Lfalse;
4143 t = peek(t);
4144 if (!isDeclaration(t, 0, TOKrparen, &t))
4145 goto Lfalse;
4146 t = peek(t);
4147 break;
4149 default:
4150 goto Lfalse;
4152 *pt = t;
4153 return TRUE;
4155 Lfalse:
4156 return FALSE;
4159 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
4160 { // This code parallels parseDeclarator()
4161 Token *t = *pt;
4162 int parens;
4164 //printf("Parser::isDeclarator()\n");
4165 //t->print();
4166 if (t->value == TOKassign)
4167 return FALSE;
4169 while (1)
4171 parens = FALSE;
4172 switch (t->value)
4174 case TOKquestion:
4175 case TOKmul:
4176 case TOKand:
4177 t = peek(t);
4178 continue;
4180 case TOKlbracket:
4181 t = peek(t);
4182 if (t->value == TOKrbracket)
4184 t = peek(t);
4186 else if (isDeclaration(t, 0, TOKrbracket, &t))
4187 { // It's an associative array declaration
4188 t = peek(t);
4190 else
4192 // [ expression ]
4193 // [ expression .. expression ]
4194 if (!isExpression(&t))
4195 return FALSE;
4196 if (t->value == TOKslice)
4197 { t = peek(t);
4198 if (!isExpression(&t))
4199 return FALSE;
4201 if (t->value != TOKrbracket)
4202 return FALSE;
4203 t = peek(t);
4205 continue;
4207 case TOKidentifier:
4208 if (*haveId)
4209 return FALSE;
4210 *haveId = TRUE;
4211 t = peek(t);
4212 break;
4214 case TOKlparen:
4215 t = peek(t);
4217 if (t->value == TOKrparen)
4218 return FALSE; // () is not a declarator
4220 /* Regard ( identifier ) as not a declarator
4221 * BUG: what about ( *identifier ) in
4222 * f(*p)(x);
4223 * where f is a class instance with overloaded () ?
4224 * Should we just disallow C-style function pointer declarations?
4226 if (t->value == TOKidentifier)
4227 { Token *t2 = peek(t);
4228 if (t2->value == TOKrparen)
4229 return FALSE;
4233 if (!isDeclarator(&t, haveId, TOKrparen))
4234 return FALSE;
4235 t = peek(t);
4236 parens = TRUE;
4237 break;
4239 case TOKdelegate:
4240 case TOKfunction:
4241 t = peek(t);
4242 if (!isParameters(&t))
4243 return FALSE;
4244 continue;
4246 break;
4249 while (1)
4251 switch (t->value)
4253 #if CARRAYDECL
4254 case TOKlbracket:
4255 parens = FALSE;
4256 t = peek(t);
4257 if (t->value == TOKrbracket)
4259 t = peek(t);
4261 else if (isDeclaration(t, 0, TOKrbracket, &t))
4262 { // It's an associative array declaration
4263 t = peek(t);
4265 else
4267 // [ expression ]
4268 if (!isExpression(&t))
4269 return FALSE;
4270 if (t->value != TOKrbracket)
4271 return FALSE;
4272 t = peek(t);
4274 continue;
4275 #endif
4277 case TOKlparen:
4278 parens = FALSE;
4279 if (!isParameters(&t))
4280 return FALSE;
4281 if (t->value == TOKconst || t->value == TOKinvariant)
4282 t = peek(t);
4283 continue;
4285 // Valid tokens that follow a declaration
4286 case TOKrparen:
4287 case TOKrbracket:
4288 case TOKassign:
4289 case TOKcomma:
4290 case TOKendline:
4291 case TOKsemicolon:
4292 case TOKlcurly:
4293 case TOKin:
4294 // The !parens is to disallow unnecessary parentheses
4295 if (!parens && (endtok == TOKreserved || endtok == t->value))
4296 { *pt = t;
4297 return TRUE;
4299 return FALSE;
4301 default:
4302 return FALSE;
4308 int Parser::isParameters(Token **pt)
4309 { // This code parallels parseParameters()
4310 Token *t = *pt;
4311 int tmp;
4313 //printf("isParameters()\n");
4314 if (t->value != TOKlparen)
4315 return FALSE;
4317 t = peek(t);
4318 for (;1; t = peek(t))
4320 switch (t->value)
4322 case TOKrparen:
4323 break;
4325 case TOKdotdotdot:
4326 t = peek(t);
4327 break;
4329 case TOKin:
4330 case TOKout:
4331 case TOKinout:
4332 case TOKref:
4333 case TOKlazy:
4334 case TOKconst:
4335 case TOKinvariant:
4336 case TOKfinal:
4337 case TOKstatic:
4338 continue;
4340 default:
4341 if (!isBasicType(&t))
4342 return FALSE;
4343 tmp = FALSE;
4344 if (t->value != TOKdotdotdot &&
4345 !isDeclarator(&t, &tmp, TOKreserved))
4346 return FALSE;
4347 if (t->value == TOKassign)
4348 { t = peek(t);
4349 if (!isExpression(&t))
4350 return FALSE;
4352 if (t->value == TOKdotdotdot)
4354 t = peek(t);
4355 break;
4357 if (t->value == TOKcomma)
4359 continue;
4361 break;
4363 break;
4365 if (t->value != TOKrparen)
4366 return FALSE;
4367 t = peek(t);
4368 *pt = t;
4369 return TRUE;
4372 int Parser::isExpression(Token **pt)
4374 // This is supposed to determine if something is an expression.
4375 // What it actually does is scan until a closing right bracket
4376 // is found.
4378 Token *t = *pt;
4379 int brnest = 0;
4380 int panest = 0;
4381 int curlynest = 0;
4383 for (;; t = peek(t))
4385 switch (t->value)
4387 case TOKlbracket:
4388 brnest++;
4389 continue;
4391 case TOKrbracket:
4392 if (--brnest >= 0)
4393 continue;
4394 break;
4396 case TOKlparen:
4397 panest++;
4398 continue;
4400 case TOKcomma:
4401 if (brnest || panest)
4402 continue;
4403 break;
4405 case TOKrparen:
4406 if (--panest >= 0)
4407 continue;
4408 break;
4410 case TOKlcurly:
4411 curlynest++;
4412 continue;
4414 case TOKrcurly:
4415 if (--curlynest >= 0)
4416 continue;
4417 return FALSE;
4419 case TOKslice:
4420 if (brnest)
4421 continue;
4422 break;
4424 case TOKsemicolon:
4425 if (curlynest)
4426 continue;
4427 return FALSE;
4429 case TOKeof:
4430 return FALSE;
4432 default:
4433 continue;
4435 break;
4438 *pt = t;
4439 return TRUE;
4442 /**********************************************
4443 * Skip over
4444 * instance foo.bar(parameters...)
4445 * Output:
4446 * if (pt), *pt is set to the token following the closing )
4447 * Returns:
4448 * 1 it's valid instance syntax
4449 * 0 invalid instance syntax
4452 int Parser::isTemplateInstance(Token *t, Token **pt)
4454 t = peek(t);
4455 if (t->value != TOKdot)
4457 if (t->value != TOKidentifier)
4458 goto Lfalse;
4459 t = peek(t);
4461 while (t->value == TOKdot)
4463 t = peek(t);
4464 if (t->value != TOKidentifier)
4465 goto Lfalse;
4466 t = peek(t);
4468 if (t->value != TOKlparen)
4469 goto Lfalse;
4471 // Skip over the template arguments
4472 while (1)
4474 while (1)
4476 t = peek(t);
4477 switch (t->value)
4479 case TOKlparen:
4480 if (!skipParens(t, &t))
4481 goto Lfalse;
4482 continue;
4483 case TOKrparen:
4484 break;
4485 case TOKcomma:
4486 break;
4487 case TOKeof:
4488 case TOKsemicolon:
4489 goto Lfalse;
4490 default:
4491 continue;
4493 break;
4496 if (t->value != TOKcomma)
4497 break;
4499 if (t->value != TOKrparen)
4500 goto Lfalse;
4501 t = peek(t);
4502 if (pt)
4503 *pt = t;
4504 return 1;
4506 Lfalse:
4507 return 0;
4510 /*******************************************
4511 * Skip parens, brackets.
4512 * Input:
4513 * t is on opening (
4514 * Output:
4515 * *pt is set to closing token, which is ')' on success
4516 * Returns:
4517 * !=0 successful
4518 * 0 some parsing error
4521 int Parser::skipParens(Token *t, Token **pt)
4523 int parens = 0;
4525 while (1)
4527 switch (t->value)
4529 case TOKlparen:
4530 parens++;
4531 break;
4533 case TOKrparen:
4534 parens--;
4535 if (parens < 0)
4536 goto Lfalse;
4537 if (parens == 0)
4538 goto Ldone;
4539 break;
4541 case TOKeof:
4542 case TOKsemicolon:
4543 goto Lfalse;
4545 default:
4546 break;
4548 t = peek(t);
4551 Ldone:
4552 if (*pt)
4553 *pt = t;
4554 return 1;
4556 Lfalse:
4557 return 0;
4560 /********************************* Expression Parser ***************************/
4562 Expression *Parser::parsePrimaryExp()
4563 { Expression *e;
4564 Type *t;
4565 Identifier *id;
4566 enum TOK save;
4567 Loc loc = this->loc;
4569 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4570 switch (token.value)
4572 case TOKidentifier:
4573 id = token.ident;
4574 nextToken();
4575 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4576 { // identifier!(template-argument-list)
4577 TemplateInstance *tempinst;
4579 tempinst = new TemplateInstance(loc, id);
4580 nextToken();
4581 tempinst->tiargs = parseTemplateArgumentList();
4582 e = new ScopeExp(loc, tempinst);
4584 else
4585 e = new IdentifierExp(loc, id);
4586 break;
4588 case TOKdollar:
4589 if (!inBrackets)
4590 error("'$' is valid only inside [] of index or slice");
4591 e = new DollarExp(loc);
4592 nextToken();
4593 break;
4595 case TOKdot:
4596 // Signal global scope '.' operator with "" identifier
4597 e = new IdentifierExp(loc, Id::empty);
4598 break;
4600 case TOKthis:
4601 e = new ThisExp(loc);
4602 nextToken();
4603 break;
4605 case TOKsuper:
4606 e = new SuperExp(loc);
4607 nextToken();
4608 break;
4610 case TOKint32v:
4611 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
4612 nextToken();
4613 break;
4615 case TOKuns32v:
4616 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
4617 nextToken();
4618 break;
4620 case TOKint64v:
4621 e = new IntegerExp(loc, token.int64value, Type::tint64);
4622 nextToken();
4623 break;
4625 case TOKuns64v:
4626 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4627 nextToken();
4628 break;
4630 case TOKfloat32v:
4631 e = new RealExp(loc, token.float80value, Type::tfloat32);
4632 nextToken();
4633 break;
4635 case TOKfloat64v:
4636 e = new RealExp(loc, token.float80value, Type::tfloat64);
4637 nextToken();
4638 break;
4640 case TOKfloat80v:
4641 e = new RealExp(loc, token.float80value, Type::tfloat80);
4642 nextToken();
4643 break;
4645 case TOKimaginary32v:
4646 e = new RealExp(loc, token.float80value, Type::timaginary32);
4647 nextToken();
4648 break;
4650 case TOKimaginary64v:
4651 e = new RealExp(loc, token.float80value, Type::timaginary64);
4652 nextToken();
4653 break;
4655 case TOKimaginary80v:
4656 e = new RealExp(loc, token.float80value, Type::timaginary80);
4657 nextToken();
4658 break;
4660 case TOKnull:
4661 e = new NullExp(loc);
4662 ((NullExp *) e)->dUnchecked = !dltSyntax;
4663 nextToken();
4664 break;
4666 case TOKfile:
4667 { char *s = loc.filename ? loc.filename : mod->ident->toChars();
4668 e = new StringExp(loc, s, strlen(s), 0);
4669 nextToken();
4670 break;
4673 case TOKline:
4674 e = new IntegerExp(loc, loc.linnum, Type::tint32);
4675 nextToken();
4676 break;
4678 case TOKtrue:
4679 e = new IntegerExp(loc, 1, Type::tbool);
4680 nextToken();
4681 break;
4683 case TOKfalse:
4684 e = new IntegerExp(loc, 0, Type::tbool);
4685 nextToken();
4686 break;
4688 case TOKcharv:
4689 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tchar);
4690 nextToken();
4691 break;
4693 case TOKwcharv:
4694 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::twchar);
4695 nextToken();
4696 break;
4698 case TOKdcharv:
4699 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
4700 nextToken();
4701 break;
4703 case TOKstring:
4704 { unsigned char *s;
4705 unsigned len;
4706 unsigned char postfix;
4708 // cat adjacent strings
4709 s = token.ustring;
4710 len = token.len;
4711 postfix = token.postfix;
4712 while (1)
4714 nextToken();
4715 if (token.value == TOKstring)
4716 { unsigned len1;
4717 unsigned len2;
4718 unsigned char *s2;
4720 if (token.postfix)
4721 { if (token.postfix != postfix)
4722 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4723 postfix = token.postfix;
4726 len1 = len;
4727 len2 = token.len;
4728 len = len1 + len2;
4729 s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
4730 memcpy(s2, s, len1 * sizeof(unsigned char));
4731 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
4732 s = s2;
4734 else
4735 break;
4737 e = new StringExp(loc, s, len, postfix);
4738 break;
4741 CASE_BASIC_TYPES_X(t):
4742 nextToken();
4744 check(TOKdot, t->toChars());
4745 if (token.value != TOKidentifier)
4746 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
4747 goto Lerr;
4749 e = new TypeDotIdExp(loc, t, token.ident);
4750 nextToken();
4751 break;
4753 case TOKtypeof:
4755 t = parseTypeof();
4756 if (token.value == TOKdot)
4757 goto L1;
4758 e = new TypeExp(loc, t);
4759 break;
4762 case TOKtypeid:
4763 { Type *t;
4765 nextToken();
4766 check(TOKlparen, "typeid");
4767 t = parseType(); // ( type )
4768 check(TOKrparen);
4769 e = new TypeidExp(loc, t);
4770 break;
4773 case TOKtraits:
4774 { /* __traits(identifier, args...)
4776 Identifier *ident;
4777 Objects *args = NULL;
4779 nextToken();
4780 check(TOKlparen);
4781 if (token.value != TOKidentifier)
4782 { error("__traits(identifier, args...) expected");
4783 goto Lerr;
4785 ident = token.ident;
4786 nextToken();
4787 if (token.value == TOKcomma)
4788 args = parseTemplateArgumentList2(); // __traits(identifier, args...)
4789 else
4790 check(TOKrparen); // __traits(identifier)
4792 e = new TraitsExp(loc, ident, args);
4793 break;
4796 case TOKis:
4797 { Type *targ;
4798 Identifier *ident = NULL;
4799 Type *tspec = NULL;
4800 enum TOK tok = TOKreserved;
4801 enum TOK tok2 = TOKreserved;
4802 TemplateParameters *tpl = NULL;
4803 Loc loc = this->loc;
4805 nextToken();
4806 if (token.value == TOKlparen)
4808 nextToken();
4809 targ = parseType(&ident);
4810 if (token.value == TOKcolon || token.value == TOKequal)
4812 tok = token.value;
4813 nextToken();
4814 if (tok == TOKequal &&
4815 (token.value == TOKtypedef ||
4816 token.value == TOKstruct ||
4817 token.value == TOKunion ||
4818 token.value == TOKclass ||
4819 token.value == TOKsuper ||
4820 token.value == TOKenum ||
4821 token.value == TOKinterface ||
4822 token.value == TOKconst && peek(&token)->value == TOKrparen ||
4823 token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
4824 token.value == TOKfunction ||
4825 token.value == TOKdelegate ||
4826 token.value == TOKreturn))
4828 tok2 = token.value;
4829 nextToken();
4831 else
4833 tspec = parseType();
4836 if (ident && tspec)
4838 if (token.value == TOKcomma)
4839 tpl = parseTemplateParameterList(1);
4840 else
4841 { tpl = new TemplateParameters();
4842 check(TOKrparen);
4844 TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
4845 tpl->insert(0, tp);
4847 else
4848 check(TOKrparen);
4850 else
4851 { error("(type identifier : specialization) expected following is");
4852 goto Lerr;
4854 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
4855 break;
4858 case TOKassert:
4859 { Expression *msg = NULL;
4861 nextToken();
4863 checkLParen();
4864 e = parseAssignExp();
4865 if (token.value == (dltSyntax ? TOKelse : TOKcomma))
4866 { nextToken();
4867 msg = parseAssignExp();
4868 } else if (token.value == TOKcomma)
4869 error("Suspicious comma after assert; try 'else' instead");
4870 checkRParen();
4872 e = new AssertExp(loc, e, msg);
4873 break;
4876 case TOKmixin:
4878 nextToken();
4879 check(TOKlparen, "mixin");
4880 e = parseAssignExp();
4881 check(TOKrparen);
4882 e = new CompileExp(loc, e);
4883 break;
4886 case TOKimport:
4888 nextToken();
4889 check(TOKlparen, "import");
4890 e = parseAssignExp();
4891 check(TOKrparen);
4892 e = new FileExp(loc, e);
4893 break;
4896 case TOKlparen:
4897 if (peekPastParen(&token)->value == TOKlcurly)
4898 { // (arguments) { statements... }
4899 save = TOKdelegate;
4900 goto case_delegate;
4902 // ( expression )
4903 nextToken();
4904 e = parseExpression();
4905 check(loc, TOKrparen);
4906 break;
4908 case TOKlbracket:
4909 { /* Parse array literals and associative array literals:
4910 * [ value, value, value ... ]
4911 * [ key:value, key:value, key:value ... ]
4913 Expressions *values = new Expressions();
4914 Expressions *keys = NULL;
4916 nextToken();
4917 if (token.value != TOKrbracket)
4919 while (1)
4921 Expression *e = parseAssignExp();
4922 if (token.value == TOKcolon && (keys || values->dim == 0))
4923 { nextToken();
4924 if (!keys)
4925 keys = new Expressions();
4926 keys->push(e);
4927 e = parseAssignExp();
4929 else if (keys)
4930 { error("'key:value' expected for associative array literal");
4931 delete keys;
4932 keys = NULL;
4934 values->push(e);
4935 if (token.value == TOKrbracket)
4936 break;
4937 check(TOKcomma);
4940 check(TOKrbracket);
4942 if (keys)
4943 e = new AssocArrayLiteralExp(loc, keys, values);
4944 else
4945 e = new ArrayLiteralExp(loc, values);
4946 break;
4949 case TOKlcurly:
4950 // { statements... }
4951 save = TOKdelegate;
4952 goto case_delegate;
4954 case TOKfunction:
4955 case TOKdelegate:
4956 save = token.value;
4957 nextToken();
4958 case_delegate:
4960 /* function type(parameters) { body }
4961 * delegate type(parameters) { body }
4962 * (parameters) { body }
4963 * { body }
4965 Arguments *arguments;
4966 int varargs;
4967 FuncLiteralDeclaration *fd;
4968 Type *t;
4969 bool isnothrow = false;
4970 bool ispure = false;
4972 if (token.value == startBlockTok)
4974 t = NULL;
4975 varargs = 0;
4976 arguments = new Arguments();
4978 else
4980 if (token.value == TOKlparen)
4981 t = NULL;
4982 else
4984 t = parseBasicType();
4985 t = parseBasicType2(t); // function return type
4987 arguments = parseParameters(&varargs);
4988 while (1)
4990 if (token.value == TOKpure)
4991 ispure = true;
4992 else if (token.value == TOKnothrow)
4993 isnothrow = true;
4994 else
4995 break;
4996 nextToken();
4999 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
5000 tf->ispure = ispure;
5001 tf->isnothrow = isnothrow;
5002 fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
5003 if (dltSyntax)
5005 check(TOKcolon);
5006 if (!nesting)
5007 indent--; // This colon doesn't start a new indent level
5008 fd->fbody = new ReturnStatement(loc, parseAssignExp());
5009 fd->endloc = loc;
5011 else
5013 parseContracts(fd);
5015 e = new FuncExp(loc, fd);
5016 break;
5019 default:
5020 error("expression expected, not '%s'", token.toChars());
5021 Lerr:
5022 // Anything for e, as long as it's not NULL
5023 e = new IntegerExp(loc, 0, Type::tint32);
5024 nextToken();
5025 break;
5027 return parsePostExp(e);
5030 Expression *Parser::parsePostExp(Expression *e)
5032 Loc loc;
5034 while (1)
5036 loc = this->loc;
5037 switch (token.value)
5039 case TOKdot:
5040 nextToken();
5041 if (token.value == TOKidentifier)
5042 { Identifier *id = token.ident;
5044 nextToken();
5045 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
5046 { // identifier!(template-argument-list)
5047 TemplateInstance *tempinst;
5049 tempinst = new TemplateInstance(loc, id);
5050 nextToken();
5051 tempinst->tiargs = parseTemplateArgumentList();
5052 e = new DotTemplateInstanceExp(loc, e, tempinst);
5054 else
5055 e = new DotIdExp(loc, e, id);
5056 continue;
5058 else if (token.value == TOKnew)
5060 e = parseNewExp(e);
5061 continue;
5063 else
5064 error("identifier expected following '.', not '%s'", token.toChars());
5065 break;
5067 case TOKplusplus:
5068 e = new PostExp(TOKplusplus, loc, e);
5069 break;
5071 case TOKminusminus:
5072 e = new PostExp(TOKminusminus, loc, e);
5073 break;
5075 case TOKlparen:
5076 e = new CallExp(loc, e, parseArguments());
5077 continue;
5079 case TOKlbracket:
5080 { // array dereferences:
5081 // array[index]
5082 // array[]
5083 // array[lwr .. upr]
5084 Expression *index;
5085 Expression *upr;
5087 inBrackets++;
5088 nextToken();
5089 if (token.value == TOKrbracket)
5090 { // array[]
5091 e = new SliceExp(loc, e, NULL, NULL);
5092 nextToken();
5094 else
5096 index = parseAssignExp();
5097 if (token.value == TOKslice)
5098 { // array[lwr .. upr]
5099 nextToken();
5100 upr = parseAssignExp();
5101 e = new SliceExp(loc, e, index, upr);
5103 else
5104 { // array[index, i2, i3, i4, ...]
5105 Expressions *arguments = new Expressions();
5106 arguments->push(index);
5107 if (token.value == TOKcomma)
5109 nextToken();
5110 while (1)
5111 { Expression *arg;
5113 arg = parseAssignExp();
5114 arguments->push(arg);
5115 if (token.value == TOKrbracket)
5116 break;
5117 check(TOKcomma);
5120 e = new ArrayExp(loc, e, arguments);
5122 check(TOKrbracket);
5123 inBrackets--;
5125 continue;
5128 default:
5129 return e;
5131 nextToken();
5135 Expression *Parser::parseUnaryExp()
5136 { Expression *e;
5137 Loc loc = this->loc;
5139 switch (token.value)
5141 case TOKand:
5142 nextToken();
5143 e = parseUnaryExp();
5144 e = new AddrExp(loc, e);
5145 break;
5147 case TOKplusplus:
5148 nextToken();
5149 e = parseUnaryExp();
5150 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5151 break;
5153 case TOKminusminus:
5154 nextToken();
5155 e = parseUnaryExp();
5156 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5157 break;
5159 case TOKmul:
5160 nextToken();
5161 e = parseUnaryExp();
5162 e = new PtrExp(loc, e);
5163 break;
5165 case TOKmin:
5166 nextToken();
5167 e = parseUnaryExp();
5168 e = new NegExp(loc, e);
5169 break;
5171 case TOKadd:
5172 nextToken();
5173 e = parseUnaryExp();
5174 e = new UAddExp(loc, e);
5175 break;
5177 case TOKnot:
5178 nextToken();
5179 e = parseUnaryExp();
5180 e = new NotExp(loc, e);
5181 break;
5183 case TOKtilde:
5184 nextToken();
5185 e = parseUnaryExp();
5186 e = new ComExp(loc, e);
5187 break;
5189 case TOKdelete:
5190 nextToken();
5191 e = parseUnaryExp();
5192 e = new DeleteExp(loc, e);
5193 break;
5195 case TOKnew:
5196 e = parseNewExp(NULL);
5197 break;
5199 case TOKcast: // cast(type) expression
5200 { Type *t;
5202 nextToken();
5203 check(TOKlparen);
5204 /* Look for cast(const) and cast(invariant)
5206 if ((token.value == TOKconst || token.value == TOKinvariant) &&
5207 peek(&token)->value == TOKrparen)
5208 { enum TOK tok = token.value;
5209 nextToken();
5210 nextToken();
5211 e = parseUnaryExp();
5212 e = new CastExp(loc, e, tok);
5214 else
5216 t = parseType(); // ( type )
5217 check(TOKrparen);
5218 e = parseUnaryExp();
5219 e = new CastExp(loc, e, t);
5221 break;
5224 case TOKlparen:
5225 { Token *tk;
5227 tk = peek(&token);
5228 #if CCASTSYNTAX
5229 // If cast
5230 if (isDeclaration(tk, 0, TOKrparen, &tk))
5232 tk = peek(tk); // skip over right parenthesis
5233 switch (tk->value)
5235 case TOKdot:
5236 case TOKplusplus:
5237 case TOKminusminus:
5238 case TOKnot:
5239 case TOKdelete:
5240 case TOKnew:
5241 case TOKlparen:
5242 case TOKidentifier:
5243 case TOKthis:
5244 case TOKsuper:
5245 case TOKint32v:
5246 case TOKuns32v:
5247 case TOKint64v:
5248 case TOKuns64v:
5249 case TOKfloat32v:
5250 case TOKfloat64v:
5251 case TOKfloat80v:
5252 case TOKimaginary32v:
5253 case TOKimaginary64v:
5254 case TOKimaginary80v:
5255 case TOKnull:
5256 case TOKtrue:
5257 case TOKfalse:
5258 case TOKcharv:
5259 case TOKwcharv:
5260 case TOKdcharv:
5261 case TOKstring:
5262 #if 0
5263 case TOKtilde:
5264 case TOKand:
5265 case TOKmul:
5266 case TOKmin:
5267 case TOKadd:
5268 #endif
5269 case TOKfunction:
5270 case TOKdelegate:
5271 case TOKtypeof:
5272 case TOKfile:
5273 case TOKline:
5274 CASE_BASIC_TYPES: // (type)int.size
5275 { // (type) una_exp
5276 Type *t;
5278 nextToken();
5279 t = parseType();
5280 check(TOKrparen);
5282 // if .identifier
5283 if (token.value == TOKdot)
5285 nextToken();
5286 if (token.value != TOKidentifier)
5287 { error("Identifier expected following (type).");
5288 return NULL;
5290 e = new TypeDotIdExp(loc, t, token.ident);
5291 nextToken();
5292 e = parsePostExp(e);
5294 else
5296 e = parseUnaryExp();
5297 e = new CastExp(loc, e, t);
5298 error("C style cast illegal, use %s", e->toChars());
5300 return e;
5304 #endif
5305 e = parsePrimaryExp();
5306 break;
5308 default:
5309 e = parsePrimaryExp();
5310 break;
5312 assert(e);
5313 return e;
5316 Expression *Parser::parseMulExp()
5317 { Expression *e;
5318 Expression *e2;
5319 Loc loc = this->loc;
5321 e = parseUnaryExp();
5322 while (1)
5324 switch (token.value)
5326 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5327 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5328 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5330 default:
5331 break;
5333 break;
5335 return e;
5338 Expression *Parser::parseAddExp()
5339 { Expression *e;
5340 Expression *e2;
5341 Loc loc = this->loc;
5343 e = parseMulExp();
5344 while (1)
5346 switch (token.value)
5348 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5349 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5350 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5352 default:
5353 break;
5355 break;
5357 return e;
5360 Expression *Parser::parseShiftExp()
5361 { Expression *e;
5362 Expression *e2;
5363 Loc loc = this->loc;
5365 e = parseAddExp();
5366 while (1)
5368 switch (token.value)
5370 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5371 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5372 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5374 default:
5375 break;
5377 break;
5379 return e;
5382 Expression *Parser::parseRelExp()
5383 { Expression *e;
5384 Expression *e2;
5385 enum TOK op;
5386 Loc loc = this->loc;
5388 e = parseShiftExp();
5389 while (1)
5391 switch (token.value)
5393 case TOKlt:
5394 case TOKle:
5395 case TOKgt:
5396 case TOKge:
5397 case TOKunord:
5398 case TOKlg:
5399 case TOKleg:
5400 case TOKule:
5401 case TOKul:
5402 case TOKuge:
5403 case TOKug:
5404 case TOKue:
5405 op = token.value;
5406 nextToken();
5407 e2 = parseShiftExp();
5408 e = new CmpExp(op, loc, e, e2);
5409 continue;
5411 case TOKin:
5412 nextToken();
5413 e2 = parseShiftExp();
5414 e = new InExp(loc, e, e2);
5415 continue;
5417 default:
5418 break;
5420 break;
5422 return e;
5425 Expression *Parser::parseEqualExp()
5426 { Expression *e;
5427 Expression *e2;
5428 Token *t;
5429 Loc loc = this->loc;
5431 e = parseRelExp();
5432 while (1)
5433 { enum TOK value = token.value;
5435 switch (value)
5437 case TOKequal:
5438 case TOKnotequal:
5439 nextToken();
5440 e2 = parseRelExp();
5441 e = new EqualExp(value, loc, e, e2);
5442 continue;
5444 case TOKidentity:
5445 error("'===' is no longer legal, use 'is' instead");
5446 goto L1;
5448 case TOKnotidentity:
5449 error("'!==' is no longer legal, use '!is' instead");
5450 goto L1;
5452 case TOKis:
5453 value = TOKidentity;
5454 error("TOKis");
5455 if (dltSyntax)
5457 t = peek(&token);
5458 error("next: %s", t->toChars());
5459 if (t->value == TOKnot)
5461 // X is not Y
5462 value = TOKnotidentity;
5463 nextToken();
5466 goto L1;
5468 case TOKnot:
5469 // Attempt to identify '!is'
5470 t = peek(&token);
5471 if (t->value != TOKis)
5472 break;
5473 nextToken();
5474 value = TOKnotidentity;
5475 goto L1;
5478 nextToken();
5479 e2 = parseRelExp();
5480 e = new IdentityExp(value, loc, e, e2);
5481 continue;
5483 default:
5484 break;
5486 break;
5488 return e;
5491 Expression *Parser::parseCmpExp()
5492 { Expression *e;
5493 Expression *e2;
5494 Token *t;
5495 Loc loc = this->loc;
5497 e = parseShiftExp();
5498 enum TOK op = token.value;
5500 switch (op)
5502 case TOKequal:
5503 case TOKnotequal:
5504 nextToken();
5505 e2 = parseShiftExp();
5506 e = new EqualExp(op, loc, e, e2);
5507 break;
5509 case TOKis:
5510 op = TOKidentity;
5511 if (dltSyntax)
5513 t = peek(&token);
5514 if (t->value == TOKnot)
5516 // X is not Y
5517 op = TOKnotidentity;
5518 nextToken();
5521 goto L1;
5523 case TOKnot:
5524 // Attempt to identify '!is'
5525 t = peek(&token);
5526 if (t->value != TOKis)
5527 break;
5528 nextToken();
5529 op = TOKnotidentity;
5530 goto L1;
5533 nextToken();
5534 e2 = parseShiftExp();
5535 e = new IdentityExp(op, loc, e, e2);
5536 break;
5538 case TOKlt:
5539 case TOKle:
5540 case TOKgt:
5541 case TOKge:
5542 case TOKunord:
5543 case TOKlg:
5544 case TOKleg:
5545 case TOKule:
5546 case TOKul:
5547 case TOKuge:
5548 case TOKug:
5549 case TOKue:
5550 nextToken();
5551 e2 = parseShiftExp();
5552 e = new CmpExp(op, loc, e, e2);
5553 break;
5555 case TOKin:
5556 nextToken();
5557 e2 = parseShiftExp();
5558 e = new InExp(loc, e, e2);
5559 break;
5561 default:
5562 break;
5564 return e;
5567 Expression *Parser::parseAndExp()
5568 { Expression *e;
5569 Expression *e2;
5570 Loc loc = this->loc;
5572 if (global.params.Dversion == 1)
5574 e = parseEqualExp();
5575 while (token.value == TOKand)
5577 nextToken();
5578 e2 = parseEqualExp();
5579 e = new AndExp(loc,e,e2);
5580 loc = this->loc;
5583 else
5585 e = parseCmpExp();
5586 while (token.value == TOKand)
5588 nextToken();
5589 e2 = parseCmpExp();
5590 e = new AndExp(loc,e,e2);
5591 loc = this->loc;
5594 return e;
5597 Expression *Parser::parseXorExp()
5598 { Expression *e;
5599 Expression *e2;
5600 Loc loc = this->loc;
5602 e = parseAndExp();
5603 while (token.value == TOKxor)
5605 nextToken();
5606 e2 = parseAndExp();
5607 e = new XorExp(loc, e, e2);
5609 return e;
5612 Expression *Parser::parseOrExp()
5613 { Expression *e;
5614 Expression *e2;
5615 Loc loc = this->loc;
5617 e = parseXorExp();
5618 while (token.value == TOKor)
5620 nextToken();
5621 e2 = parseXorExp();
5622 e = new OrExp(loc, e, e2);
5624 return e;
5627 Expression *Parser::parseAndAndExp()
5628 { Expression *e;
5629 Expression *e2;
5630 Loc loc = this->loc;
5632 e = parseOrExp();
5633 while (token.value == TOKandand)
5635 nextToken();
5636 e2 = parseOrExp();
5637 e = new AndAndExp(loc, e, e2);
5639 return e;
5642 Expression *Parser::parseOrOrExp()
5643 { Expression *e;
5644 Expression *e2;
5645 Loc loc = this->loc;
5647 e = parseAndAndExp();
5648 while (token.value == TOKoror)
5650 nextToken();
5651 e2 = parseAndAndExp();
5652 e = new OrOrExp(loc, e, e2);
5654 return e;
5657 Expression *Parser::parseCondExp()
5658 { Expression *e;
5659 Expression *e1;
5660 Expression *e2;
5661 Loc loc = this->loc;
5663 e = parseOrOrExp();
5664 if (token.value == TOKquestion)
5666 nextToken();
5667 e1 = parseExpression();
5668 check(TOKcolon);
5669 e2 = parseCondExp();
5670 e = new CondExp(loc, e, e1, e2);
5672 return e;
5675 Expression *DltParser::parseCondExp()
5676 { Expression *e;
5677 Expression *e1;
5678 Expression *e2;
5679 Loc loc = this->loc;
5681 e = parseOrOrExp();
5682 if (token.value == TOKif)
5684 nextToken();
5685 e1 = parseExpression();
5686 check(TOKelse);
5687 e2 = parseCondExp();
5688 e = new CondExp(loc, e1, e, e2);
5690 return e;
5693 Expression *Parser::parseAssignExp()
5694 { Expression *e;
5695 Expression *e2;
5696 Loc loc;
5698 e = parseCondExp();
5699 while (1)
5701 loc = this->loc;
5702 switch (token.value)
5704 #define X(tok,ector) \
5705 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5707 X(TOKassign, AssignExp);
5708 X(TOKaddass, AddAssignExp);
5709 X(TOKminass, MinAssignExp);
5710 X(TOKmulass, MulAssignExp);
5711 X(TOKdivass, DivAssignExp);
5712 X(TOKmodass, ModAssignExp);
5713 X(TOKandass, AndAssignExp);
5714 X(TOKorass, OrAssignExp);
5715 X(TOKxorass, XorAssignExp);
5716 X(TOKshlass, ShlAssignExp);
5717 X(TOKshrass, ShrAssignExp);
5718 X(TOKushrass, UshrAssignExp);
5719 X(TOKcatass, CatAssignExp);
5721 #undef X
5722 default:
5723 break;
5725 break;
5727 return e;
5730 Expression *Parser::parseExpression()
5731 { Expression *e;
5732 Expression *e2;
5733 Loc loc = this->loc;
5735 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5736 e = parseAssignExp();
5737 while (token.value == TOKcomma)
5739 nextToken();
5740 e2 = parseAssignExp();
5741 e = new CommaExp(loc, e, e2);
5742 loc = this->loc;
5744 return e;
5748 /*************************
5749 * Collect argument list.
5750 * Assume current token is '(' or '['.
5753 Expressions *Parser::parseArguments()
5754 { // function call
5755 Expressions *arguments;
5756 Expression *arg;
5757 enum TOK endtok;
5759 arguments = new Expressions();
5760 if (token.value == TOKlbracket)
5761 endtok = TOKrbracket;
5762 else
5763 endtok = TOKrparen;
5766 nextToken();
5767 if (token.value != endtok)
5769 while (1)
5771 arg = parseAssignExp();
5772 arguments->push(arg);
5773 if (token.value == endtok)
5774 break;
5775 check(TOKcomma);
5778 check(endtok);
5780 return arguments;
5783 /*******************************************
5786 Expression *Parser::parseNewExp(Expression *thisexp)
5787 { Type *t;
5788 Expressions *newargs;
5789 Expressions *arguments = NULL;
5790 Expression *e;
5791 Loc loc = this->loc;
5793 nextToken();
5794 newargs = NULL;
5795 if (token.value == TOKlparen)
5797 newargs = parseArguments();
5800 // An anonymous nested class starts with "class"
5801 if (token.value == TOKclass)
5803 nextToken();
5805 if (dltSyntax)
5806 error("no anonymous classes in Delight");
5808 if (token.value == TOKlparen)
5809 arguments = parseArguments();
5811 BaseClasses *baseclasses = NULL;
5812 if (token.value != TOKlcurly)
5813 baseclasses = parseBaseClasses();
5815 Identifier *id = NULL;
5816 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
5818 if (token.value != startBlockTok)
5819 { error("{ members } expected for anonymous class");
5820 cd->members = NULL;
5822 else
5824 nextToken();
5825 Array *decl = parseDeclDefs(0);
5826 if (token.value != TOKrcurly)
5827 error("class member expected");
5828 nextToken();
5829 cd->members = decl;
5832 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5834 return e;
5837 t = parseBasicType();
5838 t = parseBasicType2(t);
5839 if (t->ty == Taarray)
5840 { TypeAArray *taa = (TypeAArray *)t;
5841 Type *index = taa->index;
5843 Expression *e = index->toExpression();
5844 if (e)
5845 { arguments = new Expressions();
5846 arguments->push(e);
5847 t = new TypeDArray(taa->next);
5849 else
5851 error("need size of rightmost array, not type %s", index->toChars());
5852 return new NullExp(loc);
5855 else if (t->ty == Tsarray)
5857 TypeSArray *tsa = (TypeSArray *)t;
5858 Expression *e = tsa->dim;
5860 arguments = new Expressions();
5861 arguments->push(e);
5862 t = new TypeDArray(tsa->next);
5864 else if (token.value == TOKlparen)
5866 arguments = parseArguments();
5868 e = new NewExp(loc, thisexp, newargs, t, arguments);
5869 return e;
5872 /**********************************************
5875 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
5877 s->addComment(combineComments(blockComment, token.lineComment));
5881 /********************************* ***************************/