Don't require a ; after a continue statement
[delight/core.git] / dmd2 / parse.c
blobb0a7757f7af2328544c0c9db953d30ad11d4fd8f
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.*" or _externals
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 || id == Id::_externals))
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(d->loc, "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 == startBlockTok ||
187 t->value == (dltSyntax ? TOKextends : TOKcolon))
189 s = parseEnum();
191 else if (t->value != TOKidentifier)
192 goto Ldeclaration;
193 else
195 t = peek(t);
196 if (t->value == startBlockTok ||
197 t->value == (dltSyntax ? TOKextends : TOKcolon) ||
198 t->value == TOKsemicolon)
199 s = parseEnum();
200 else
201 goto Ldeclaration;
203 break;
206 case TOKstruct:
207 case TOKunion:
208 case TOKclass:
209 case TOKinterface:
210 s = parseAggregate();
211 break;
213 case TOKimport:
214 s = parseImport(decldefs, 0);
215 break;
217 case TOKtemplate:
218 s = (Dsymbol *)parseTemplateDeclaration();
219 break;
221 case TOKmixin:
222 { Loc loc = this->loc;
223 if (peek(&token)->value == TOKlparen)
224 { // mixin(string)
225 nextToken();
226 check(TOKlparen, "mixin");
227 Expression *e = parseAssignExp();
228 check(TOKrparen);
229 check(TOKsemicolon);
230 s = new CompileDeclaration(loc, e);
231 break;
233 s = parseMixin();
234 break;
237 CASE_BASIC_TYPES:
238 case TOKalias:
239 case TOKtypedef:
240 case TOKidentifier:
241 case TOKtypeof:
242 case TOKdot:
243 Ldeclaration:
244 a = parseDeclarations();
245 decldefs->append(a);
246 continue;
248 case TOKthis:
249 s = parseCtor();
250 break;
252 case TOKassign:
253 s = parsePostBlit();
254 break;
256 case TOKtilde:
257 s = parseDtor();
258 break;
260 case TOKinvariant:
261 { Token *t;
262 t = peek(&token);
263 if (t->value == TOKlparen)
265 if (peek(t)->value == TOKrparen)
266 // invariant() forms start of class invariant
267 s = parseInvariant();
268 else
269 // invariant(type)
270 goto Ldeclaration;
272 else
274 stc = STCinvariant;
275 goto Lstc;
277 break;
280 case TOKunittest:
281 s = parseUnitTest();
282 break;
284 case TOKnew:
285 s = parseNew();
286 break;
288 case TOKdelete:
289 s = parseDelete();
290 break;
292 case TOKeof:
293 case TOKrcurly:
294 return decldefs;
296 case TOKstatic:
297 nextToken();
298 if (token.value == TOKthis)
300 s = parseStaticCtor();
301 if (dltNormalMode)
302 error("no static constructors in Delight");
304 else if (token.value == TOKtilde)
306 s = parseStaticDtor();
307 if (dltNormalMode)
308 error("no static destructors in Delight");
310 else if (token.value == TOKassert)
311 s = parseStaticAssert();
312 else if (token.value == TOKif)
313 { condition = parseStaticIfCondition();
314 a = parseBlock();
315 aelse = NULL;
316 if (token.value == TOKelse)
317 { nextToken();
318 aelse = parseBlock();
320 s = new StaticIfDeclaration(condition, a, aelse);
321 break;
323 else if (token.value == TOKimport)
325 s = parseImport(decldefs, 1);
327 else
328 { stc = STCstatic;
329 goto Lstc2;
331 break;
333 case TOKin:
334 nextToken();
335 stc = STCinject;
336 goto Lstc2;
338 case TOKconst:
339 if (peek(&token)->value == TOKlparen)
340 goto Ldeclaration;
341 stc = STCconst;
342 goto Lstc;
344 case TOKfinal: stc = STCfinal; goto Lstc;
345 case TOKauto: stc = STCauto; goto Lstc;
346 case TOKscope: stc = STCscope; goto Lstc;
347 case TOKoverride: stc = STCoverride; goto Lstc;
348 case TOKabstract: stc = STCabstract; goto Lstc;
349 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
350 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
351 case TOKnothrow: stc = STCnothrow; goto Lstc;
352 case TOKpure: stc = STCpure; goto Lstc;
353 case TOKtls: stc = STCtls; goto Lstc;
354 //case TOKmanifest: stc = STCmanifest; goto Lstc;
356 Lstc:
357 if (storageClass & stc)
358 error("redundant storage class %s", Token::toChars(token.value));
360 unsigned u = storageClass | stc;
361 u &= STCconst | STCinvariant | STCmanifest;
362 if (u & (u - 1))
363 error("conflicting storage class %s", Token::toChars(token.value));
365 nextToken();
366 Lstc2:
367 storageClass |= stc;
368 switch (token.value)
370 case TOKconst:
371 case TOKinvariant:
372 // If followed by a (, it is not a storage class
373 if (peek(&token)->value == TOKlparen)
374 break;
375 if (token.value == TOKconst)
376 stc = STCconst;
377 else
378 stc = STCinvariant;
379 goto Lstc;
380 case TOKfinal: stc = STCfinal; goto Lstc;
381 case TOKauto: stc = STCauto; goto Lstc;
382 case TOKscope: stc = STCscope; goto Lstc;
383 case TOKoverride: stc = STCoverride; goto Lstc;
384 case TOKabstract: stc = STCabstract; goto Lstc;
385 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
386 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
387 case TOKnothrow: stc = STCnothrow; goto Lstc;
388 case TOKpure: stc = STCpure; goto Lstc;
389 case TOKtls: stc = STCtls; goto Lstc;
390 //case TOKmanifest: stc = STCmanifest; goto Lstc;
391 default:
392 break;
395 /* Look for auto initializers:
396 * storage_class identifier = initializer;
398 if (token.value == TOKidentifier &&
399 peek(&token)->value == TOKassign)
401 while (1)
403 Identifier *ident = token.ident;
404 nextToken();
405 nextToken();
406 Initializer *init = parseInitializer();
407 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
408 v->storage_class = storageClass;
409 v->dltNormalMode = dltNormalMode;
410 s = v;
411 if (token.value == TOKsemicolon || token.value == TOKendline)
413 nextToken();
415 else if (token.value == TOKcomma)
417 nextToken();
418 if (token.value == TOKidentifier &&
419 peek(&token)->value == TOKassign)
421 decldefs->push(s);
422 addComment(s, comment);
423 continue;
425 else
426 error("Identifier expected following comma");
428 else
429 error("%s expected following declaration, not '%s'", endToken(), token.toChars());
430 break;
433 else
434 { a = parseBlock();
435 s = new StorageClassDeclaration(storageClass, a);
437 break;
439 case TOKextern:
440 if (peek(&token)->value != TOKlparen)
441 { stc = STCextern;
442 goto Lstc;
445 enum LINK linksave = linkage;
446 linkage = parseLinkage();
447 a = parseBlock();
448 s = new LinkDeclaration(linkage, a);
449 linkage = linksave;
451 if (dltNormalMode)
452 error("access to external symbols can be done only by dlt.* modules");
453 break;
455 case TOKprivate: prot = PROTprivate; goto Lprot;
456 case TOKpackage: prot = PROTpackage; goto Lprot;
457 case TOKprotected: prot = PROTprotected; goto Lprot;
458 case TOKpublic: prot = PROTpublic; goto Lprot;
459 case TOKexport: prot = PROTexport; goto Lprot;
461 Lprot:
462 nextToken();
463 switch (token.value)
465 case TOKprivate:
466 case TOKpackage:
467 case TOKprotected:
468 case TOKpublic:
469 case TOKexport:
470 error("redundant protection attribute");
471 break;
473 a = parseBlock();
474 s = new ProtDeclaration(prot, a);
475 break;
477 case TOKalign:
478 { unsigned n;
480 s = NULL;
481 nextToken();
482 if (token.value == TOKlparen)
484 nextToken();
485 if (token.value == TOKint32v)
486 n = (unsigned)token.uns64value;
487 else
488 { error("integer expected, not %s", token.toChars());
489 n = 1;
491 nextToken();
492 check(TOKrparen);
494 else
495 n = global.structalign; // default
497 a = parseBlock();
498 s = new AlignDeclaration(n, a);
499 break;
502 case TOKpragma:
503 { Identifier *ident;
504 Expressions *args = NULL;
506 nextToken();
507 check(TOKlparen);
508 if (token.value != TOKidentifier)
509 { error("pragma(identifier expected");
510 goto Lerror;
512 ident = token.ident;
513 nextToken();
514 if (token.value == TOKcomma)
515 args = parseArguments(); // pragma(identifier, args...)
516 else
517 check(TOKrparen); // pragma(identifier)
519 if (token.value == TOKsemicolon || token.value == TOKendline)
520 a = NULL;
521 else if (dltSyntax)
523 check(TOKcolon);
524 a = parseDeclDefs(0);
525 check(TOKrcurly);
527 else
528 a = parseBlock();
529 s = new PragmaDeclaration(loc, ident, args, a);
530 break;
533 case TOKdebug:
534 nextToken();
535 if (token.value == TOKassign)
537 nextToken();
538 if (token.value == TOKidentifier)
539 s = new DebugSymbol(loc, token.ident);
540 else if (token.value == TOKint32v)
541 s = new DebugSymbol(loc, (unsigned)token.uns64value);
542 else
543 { error("identifier or integer expected, not %s", token.toChars());
544 s = NULL;
546 nextToken();
547 if (token.value != TOKsemicolon)
548 error("semicolon expected");
549 nextToken();
550 break;
553 condition = parseDebugCondition();
554 goto Lcondition;
556 case TOKversion:
557 nextToken();
558 if (token.value == TOKassign)
560 nextToken();
561 if (token.value == TOKidentifier)
562 s = new VersionSymbol(loc, token.ident);
563 else if (token.value == TOKint32v)
564 s = new VersionSymbol(loc, (unsigned)token.uns64value);
565 else
566 { error("identifier or integer expected, not %s", token.toChars());
567 s = NULL;
569 nextToken();
570 if (token.value != TOKsemicolon && token.value != TOKendline)
571 error("%s expected after version assignment", endToken());
572 nextToken();
573 break;
575 condition = parseVersionCondition();
576 goto Lcondition;
578 Lcondition:
579 a = parseBlock();
580 aelse = NULL;
581 if (token.value == TOKelse)
582 { nextToken();
583 aelse = parseBlock();
585 s = new ConditionalDeclaration(condition, a, aelse);
586 break;
588 case TOKsemicolon: // empty declaration
589 nextToken();
590 continue;
592 default:
593 error("Declaration expected, not '%s'",token.toChars());
594 Lerror:
595 while (token.value != TOKsemicolon && token.value != TOKendline && token.value != TOKeof)
596 nextToken();
597 nextToken();
598 s = NULL;
599 continue;
601 if (s)
602 { decldefs->push(s);
603 addComment(s, comment);
605 } while (!once);
606 return decldefs;
610 /********************************************
611 * Parse declarations after an align, protection, or extern decl.
614 Array *Parser::parseBlock()
616 Array *a = NULL;
617 Dsymbol *s;
619 //printf("Parser::parseBlock()\n");
620 switch (token.value)
622 case TOKsemicolon:
623 error("declaration expected following attribute, not ';'");
624 nextToken();
625 break;
627 case TOKlcurly:
628 nextToken();
629 a = parseDeclDefs(0);
630 if (token.value != TOKrcurly)
631 { /* { */
632 error("matching '}' expected, not %s", token.toChars());
634 else
635 nextToken();
636 break;
638 case TOKcolon:
639 nextToken();
640 #if 0
641 a = NULL;
642 #else
643 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
644 #endif
645 break;
647 default:
648 a = parseDeclDefs(1);
649 break;
651 return a;
654 Array *DltParser::parseBlock()
656 Array *a = NULL;
657 Dsymbol *s;
659 optionalEndline();
660 switch (token.value)
662 case TOKendline:
663 case TOKsemicolon:
664 error("declaration expected following attribute, not %s", token.toChars());
665 nextToken();
666 break;
668 case TOKcolon:
669 nextToken();
670 a = parseDeclDefs(0);
671 if (token.value != TOKrcurly)
673 error("matching end-of-block expected, not %s", token.toChars());
675 else
676 nextToken();
677 break;
679 default:
680 a = parseDeclDefs(1);
681 break;
683 return a;
686 /**********************************
687 * Parse a static assertion.
690 StaticAssert *Parser::parseStaticAssert()
692 Loc loc = this->loc;
693 Expression *exp;
694 Expression *msg = NULL;
696 //printf("parseStaticAssert()\n");
697 nextToken();
698 checkLParen();
699 exp = parseAssignExp();
700 if (token.value == TOKcomma)
701 { nextToken();
702 msg = parseAssignExp();
704 checkRParen();
705 if (token.value == TOKsemicolon || token.value == TOKendline) {
706 nextToken();
707 return new StaticAssert(loc, exp, msg);
709 error("expected %s after static assert", endToken());
712 /***********************************
713 * Parse typeof(expression).
714 * Current token is on the 'typeof'.
717 TypeQualified *Parser::parseTypeof()
718 { TypeQualified *t;
719 Loc loc = this->loc;
721 nextToken();
722 check(TOKlparen);
723 if (token.value == TOKreturn) // typeof(return)
725 nextToken();
726 t = new TypeReturn(loc);
728 else
729 { Expression *exp = parseExpression(); // typeof(expression)
730 t = new TypeTypeof(loc, exp);
732 check(TOKrparen);
733 return t;
736 /***********************************
737 * Parse extern (linkage)
738 * The parser is on the 'extern' token.
741 enum LINK Parser::parseLinkage()
743 enum LINK link = LINKdefault;
744 nextToken();
745 assert(token.value == TOKlparen);
746 nextToken();
747 if (token.value == TOKidentifier)
748 { Identifier *id = token.ident;
750 nextToken();
751 if (id == Id::Windows)
752 link = LINKwindows;
753 else if (id == Id::Pascal)
754 link = LINKpascal;
755 else if (id == Id::D)
756 link = LINKd;
757 else if (id == Id::GObject)
758 link = LINKgobject;
759 else if (id == Id::C)
761 link = LINKc;
762 if (token.value == TOKplusplus)
763 { link = LINKcpp;
764 nextToken();
767 else if (id == Id::System)
769 #ifdef IN_GCC
770 link = d_gcc_is_target_win32() ? LINKwindows : LINKc;
771 #else
772 #if _WIN32
773 link = LINKwindows;
774 #else
775 link = LINKc;
776 #endif
777 #endif
779 else
781 error("valid linkage identifiers are D, C, C++, GObject, Pascal, Windows, System");
782 link = LINKd;
785 else
787 link = LINKd; // default
789 check(TOKrparen);
790 return link;
793 /**************************************
794 * Parse a debug conditional
797 Condition *Parser::parseDebugCondition()
799 Condition *c;
801 if (token.value == TOKlparen)
803 nextToken();
804 unsigned level = 1;
805 Identifier *id = NULL;
807 if (token.value == TOKidentifier)
808 id = token.ident;
809 else if (token.value == TOKint32v)
810 level = (unsigned)token.uns64value;
811 else
812 error("identifier or integer expected, not %s", token.toChars());
813 nextToken();
814 check(TOKrparen);
815 c = new DebugCondition(mod, level, id);
816 if (dltSyntax && token.value != TOKcolon)
817 error("expected colon after debug(), not '%s'", token.toChars());
818 } else {
819 if (dltSyntax && token.value != TOKcolon)
820 error("expected ':' or '(' after 'debug', not '%s'", token.toChars());
821 c = new DebugCondition(mod, 1, NULL);
823 return c;
827 /**************************************
828 * Parse a version conditional
831 Condition *Parser::parseVersionCondition()
833 Condition *c;
834 unsigned level = 1;
835 Identifier *id = NULL;
837 if (token.value == TOKlparen)
839 nextToken();
840 if (token.value == TOKidentifier)
841 id = token.ident;
842 else if (token.value == TOKint32v)
843 level = (unsigned)token.uns64value;
844 #if V2
845 /* Allow:
846 * version (unittest)
847 * even though unittest is a keyword
849 else if (token.value == TOKunittest)
850 id = Lexer::idPool(Token::toChars(TOKunittest));
851 #endif
852 else
853 error("identifier or integer expected, not %s", token.toChars());
854 nextToken();
855 check(TOKrparen);
858 else
859 error("(condition) expected following version");
860 c = new VersionCondition(mod, level, id);
861 return c;
865 /***********************************************
866 * static if (expression)
867 * body
868 * else
869 * body
872 Condition *Parser::parseStaticIfCondition()
873 { Expression *exp;
874 Condition *condition;
875 Array *aif;
876 Array *aelse;
877 Loc loc = this->loc;
879 nextToken();
880 checkLParen();
881 exp = parseAssignExp();
882 checkRParen();
884 condition = new StaticIfCondition(loc, exp);
885 return condition;
889 /*****************************************
890 * Parse a constructor definition:
891 * this(arguments) { body }
892 * or postblit:
893 * this(this) { body }
894 * Current token is 'this'.
897 FuncDeclaration *Parser::parseCtor()
899 Loc loc = this->loc;
901 nextToken();
902 if (token.value == TOKlparen && peek(&token)->value == TOKthis)
903 { // this(this) { ... }
904 nextToken();
905 nextToken();
906 check(TOKrparen);
907 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
908 parseContracts(f);
909 return f;
911 int varargs;
912 Arguments *arguments = parseParameters(&varargs);
913 CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs);
914 parseContracts(f);
915 return f;
918 /*****************************************
919 * Parse a postblit definition:
920 * =this() { body }
921 * Current token is '='.
924 PostBlitDeclaration *Parser::parsePostBlit()
926 Loc loc = this->loc;
928 nextToken();
929 check(TOKthis);
930 check(TOKlparen);
931 check(TOKrparen);
933 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
934 parseContracts(f);
935 return f;
938 /*****************************************
939 * Parse a destructor definition:
940 * ~this() { body }
941 * Current token is '~'.
944 DtorDeclaration *Parser::parseDtor()
946 DtorDeclaration *f;
947 Loc loc = this->loc;
949 nextToken();
950 check(TOKthis);
951 check(TOKlparen);
952 check(TOKrparen);
954 f = new DtorDeclaration(loc, 0);
955 parseContracts(f);
956 return f;
959 /*****************************************
960 * Parse a static constructor definition:
961 * static this() { body }
962 * Current token is 'this'.
965 StaticCtorDeclaration *Parser::parseStaticCtor()
967 StaticCtorDeclaration *f;
968 Loc loc = this->loc;
970 nextToken();
971 check(TOKlparen);
972 check(TOKrparen);
974 f = new StaticCtorDeclaration(loc, 0);
975 parseContracts(f);
976 return f;
979 /*****************************************
980 * Parse a static destructor definition:
981 * static ~this() { body }
982 * Current token is '~'.
985 StaticDtorDeclaration *Parser::parseStaticDtor()
987 StaticDtorDeclaration *f;
988 Loc loc = this->loc;
990 nextToken();
991 check(TOKthis);
992 check(TOKlparen);
993 check(TOKrparen);
995 f = new StaticDtorDeclaration(loc, 0);
996 parseContracts(f);
997 return f;
1000 /*****************************************
1001 * Parse an invariant definition:
1002 * invariant { body }
1003 * Current token is 'invariant'.
1006 InvariantDeclaration *Parser::parseInvariant()
1008 InvariantDeclaration *f;
1009 Loc loc = this->loc;
1011 nextToken();
1013 // () are optional
1014 if (token.value == TOKlparen)
1015 { nextToken();
1016 check(TOKrparen);
1019 f = new InvariantDeclaration(loc, 0);
1020 f->fbody = parseStatement(PScurly);
1021 return f;
1024 /*****************************************
1025 * Parse a unittest definition:
1026 * unittest { body }
1027 * Current token is 'unittest'.
1030 UnitTestDeclaration *Parser::parseUnitTest()
1032 UnitTestDeclaration *f;
1033 Statement *body;
1034 Loc loc = this->loc;
1036 nextToken();
1038 body = parseStatement(PScurly);
1040 f = new UnitTestDeclaration(loc, this->loc);
1041 f->fbody = body;
1042 return f;
1045 /*****************************************
1046 * Parse a new definition:
1047 * new(arguments) { body }
1048 * Current token is 'new'.
1051 NewDeclaration *Parser::parseNew()
1053 NewDeclaration *f;
1054 Arguments *arguments;
1055 int varargs;
1056 Loc loc = this->loc;
1058 nextToken();
1059 arguments = parseParameters(&varargs);
1060 f = new NewDeclaration(loc, 0, arguments, varargs);
1061 parseContracts(f);
1062 return f;
1065 /*****************************************
1066 * Parse a delete definition:
1067 * delete(arguments) { body }
1068 * Current token is 'delete'.
1071 DeleteDeclaration *Parser::parseDelete()
1073 DeleteDeclaration *f;
1074 Arguments *arguments;
1075 int varargs;
1076 Loc loc = this->loc;
1078 nextToken();
1079 arguments = parseParameters(&varargs);
1080 if (varargs)
1081 error("... not allowed in delete function parameter list");
1082 f = new DeleteDeclaration(loc, 0, arguments);
1083 parseContracts(f);
1084 return f;
1087 /**********************************************
1088 * Parse parameter list.
1091 Arguments *Parser::parseParameters(int *pvarargs)
1093 Arguments *arguments = new Arguments();
1094 int varargs = 0;
1095 int hasdefault = 0;
1097 check(TOKlparen);
1098 while (1)
1099 { Type *tb;
1100 Identifier *ai;
1101 Type *at;
1102 Argument *a;
1103 unsigned storageClass;
1104 unsigned stc;
1105 Expression *ae;
1107 ai = NULL;
1108 storageClass = 0; // parameter is "in" by default
1109 for (;1; nextToken())
1111 switch (token.value)
1113 case TOKrparen:
1114 break;
1116 case TOKdotdotdot:
1117 varargs = 1;
1118 nextToken();
1119 break;
1121 case TOKconst:
1122 if (peek(&token)->value == TOKlparen)
1123 goto Ldefault;
1124 stc = STCconst;
1125 goto L2;
1127 case TOKinvariant:
1128 if (peek(&token)->value == TOKlparen)
1129 goto Ldefault;
1130 stc = STCinvariant;
1131 goto L2;
1133 case TOKin: stc = STCin; goto L2;
1134 case TOKout: stc = STCout; goto L2;
1135 case TOKinout:
1136 case TOKref: stc = STCref; goto L2;
1137 case TOKlazy: stc = STClazy; goto L2;
1138 case TOKscope: stc = STCscope; goto L2;
1139 case TOKfinal: stc = STCfinal; goto L2;
1140 case TOKstatic: stc = STCstatic; goto L2;
1142 if (storageClass & stc ||
1143 (storageClass & STCin && stc & (STCconst | STCscope)) ||
1144 (stc & STCin && storageClass & (STCconst | STCscope))
1146 error("redundant storage class %s", Token::toChars(token.value));
1147 storageClass |= stc;
1149 unsigned u = storageClass & (STCconst | STCinvariant);
1150 if (u & (u - 1))
1151 error("conflicting storage class %s", Token::toChars(token.value));
1153 continue;
1155 default:
1156 Ldefault:
1157 stc = storageClass & (STCin | STCout | STCref | STClazy);
1158 if (stc & (stc - 1)) // if stc is not a power of 2
1159 error("incompatible parameter storage classes");
1160 if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1161 error("out cannot be const");
1162 if ((storageClass & (STCinvariant | STCout)) == (STCinvariant | STCout))
1163 error("out cannot be invariant");
1164 if ((storageClass & STCscope) &&
1165 (storageClass & (STCref | STCout)))
1166 error("scope cannot be ref or out");
1167 at = parseType(&ai);
1168 ae = NULL;
1169 if (token.value == TOKassign) // = defaultArg
1170 { nextToken();
1171 ae = parseDefaultInitExp();
1172 hasdefault = 1;
1174 else
1175 { if (hasdefault)
1176 error("default argument expected for %s",
1177 ai ? ai->toChars() : at->toChars());
1179 if (token.value == TOKdotdotdot)
1180 { /* This is:
1181 * at ai ...
1184 if (storageClass & (STCout | STCref))
1185 error("variadic argument cannot be out or ref");
1186 varargs = 2;
1187 a = new Argument(storageClass, at, ai, ae);
1188 arguments->push(a);
1189 nextToken();
1190 break;
1192 a = new Argument(storageClass, at, ai, ae);
1193 arguments->push(a);
1194 if (token.value == TOKcomma)
1195 { nextToken();
1196 goto L1;
1198 break;
1200 break;
1202 break;
1204 L1: ;
1206 check(TOKrparen);
1207 *pvarargs = varargs;
1208 return arguments;
1212 /*************************************
1215 EnumDeclaration *Parser::parseEnum()
1216 { EnumDeclaration *e;
1217 Identifier *id;
1218 Type *memtype;
1219 Loc loc = this->loc;
1221 //printf("Parser::parseEnum()\n");
1222 nextToken();
1223 if (token.value == TOKidentifier)
1224 { id = token.ident;
1225 nextToken();
1227 else
1228 id = NULL;
1230 if (token.value == (dltSyntax ? TOKextends : TOKcolon))
1232 nextToken();
1233 memtype = parseBasicType();
1234 memtype = parseDeclarator(memtype, NULL, NULL);
1236 else
1237 memtype = NULL;
1239 e = new EnumDeclaration(loc, id, memtype);
1240 if ((token.value == TOKsemicolon || token.value == TOKendline) && id)
1241 nextToken();
1242 else if (token.value == startBlockTok)
1244 //printf("enum definition\n");
1245 e->members = new Array();
1246 nextToken();
1247 unsigned char *comment = token.blockComment;
1248 optionalEndline();
1249 while (token.value != TOKrcurly)
1251 /* Can take the following forms:
1252 * 1. ident
1253 * 2. ident = value
1254 * 3. type ident = value
1257 loc = this->loc;
1259 Type *type = NULL;
1260 Identifier *ident;
1261 Token *tp = peek(&token);
1262 if (token.value == TOKidentifier &&
1263 (tp->value == TOKassign || tp->value == TOKcomma ||
1264 tp->value == TOKendline || tp->value == TOKrcurly))
1266 ident = token.ident;
1267 type = NULL;
1268 nextToken();
1270 else
1272 type = parseType(&ident, NULL);
1273 if (id || memtype)
1274 error("type only allowed if anonymous enum and no enum type");
1277 Expression *value;
1278 if (token.value == TOKassign)
1280 nextToken();
1281 value = parseAssignExp();
1283 else
1284 { value = NULL;
1285 if (type)
1286 error("if type, there must be an initializer");
1289 EnumMember *em = new EnumMember(loc, ident, value, type);
1290 e->members->push(em);
1292 if (dltSyntax)
1294 if (token.value == TOKcomma)
1295 nextToken();
1296 else if (token.value != TOKendline)
1297 error("expected comma or newline after %s, not %s",
1298 em->toChars(), token.toChars());
1299 optionalEndline();
1302 if (token.value == TOKrcurly)
1304 else
1305 { addComment(em, comment);
1306 comment = NULL;
1307 if (!dltSyntax)
1308 check(TOKcomma);
1310 addComment(em, comment);
1311 comment = token.blockComment;
1313 nextToken();
1315 else
1316 error("enum declaration is invalid");
1317 //printf("-parseEnum() %s\n", e->toChars());
1318 return e;
1321 Dsymbol *Parser::parseAggregate()
1322 { AggregateDeclaration *a = NULL;
1323 int anon = 0;
1324 enum TOK tok;
1325 Identifier *id;
1326 TemplateParameters *tpl = NULL;
1328 //printf("Parser::parseAggregate()\n");
1329 tok = token.value;
1330 nextToken();
1331 if (token.value != TOKidentifier)
1332 { id = NULL;
1334 else
1335 { id = token.ident;
1336 nextToken();
1338 if (token.value == TOKlparen)
1339 { // Class template declaration.
1341 // Gather template parameter list
1342 tpl = parseTemplateParameterList();
1346 Loc loc = this->loc;
1347 switch (tok)
1348 { case TOKclass:
1349 case TOKinterface:
1351 if (!id)
1352 error("anonymous classes not allowed");
1354 // Collect base class(es)
1355 BaseClasses *baseclasses = parseBaseClasses();
1356 if (baseclasses && token.value != startBlockTok) {
1357 error("members expected");
1360 if (tok == TOKclass)
1361 a = new ClassDeclaration(loc, id, baseclasses, linkage);
1362 else
1363 a = new InterfaceDeclaration(loc, id, baseclasses, linkage);
1364 break;
1367 case TOKstruct:
1368 if (id)
1369 a = new StructDeclaration(loc, id);
1370 else
1371 anon = 1;
1372 break;
1374 case TOKunion:
1375 if (id)
1376 a = new UnionDeclaration(loc, id);
1377 else
1378 anon = 2;
1379 break;
1381 default:
1382 assert(0);
1383 break;
1385 if (a && token.value == (dltSyntax ? TOKendline : TOKsemicolon))
1386 { nextToken();
1388 else if (token.value == startBlockTok)
1390 //printf("aggregate definition\n");
1391 nextToken();
1392 optionalEndline();
1393 Array *decl = parseDeclDefs(0);
1394 if (token.value != TOKrcurly)
1395 error("end-of-block expected following member declarations in aggregate");
1396 nextToken();
1397 if (anon)
1399 /* Anonymous structs/unions are more like attributes.
1401 return new AnonDeclaration(loc, anon - 1, decl);
1403 else
1404 a->members = decl;
1406 else
1408 error("%s expected following aggregate declaration", Token::toChars(startBlockTok));
1409 a = new StructDeclaration(loc, NULL);
1412 if (tpl)
1413 { Array *decldefs;
1414 TemplateDeclaration *tempdecl;
1416 // Wrap a template around the aggregate declaration
1417 decldefs = new Array();
1418 decldefs->push(a);
1419 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1420 return tempdecl;
1423 return a;
1426 /*******************************************
1429 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1430 * the bases. Otherwise, return null.
1432 BaseClasses *Parser::parseBaseClasses()
1434 enum PROT protection = PROTpublic;
1435 int type; // 1 = extends, 2 = implements, 3 = unknown
1437 if (dltSyntax) {
1438 if (token.value == TOKextends)
1439 type = 1;
1440 else if (token.value == TOKimplements)
1441 type = 2;
1442 else
1443 return NULL;
1444 } else {
1445 if (token.value == TOKcolon)
1446 type = 3;
1447 else
1448 return NULL;
1451 nextToken();
1453 BaseClasses *baseclasses = new BaseClasses();
1455 for (; 1; nextToken())
1457 enum PROT protection = PROTpublic;
1458 switch (token.value)
1460 case TOKprivate:
1461 protection = PROTprivate;
1462 nextToken();
1463 break;
1464 case TOKpackage:
1465 protection = PROTpackage;
1466 nextToken();
1467 break;
1468 case TOKprotected:
1469 protection = PROTprotected;
1470 nextToken();
1471 break;
1472 case TOKpublic:
1473 protection = PROTpublic;
1474 nextToken();
1475 break;
1477 if (token.value == TOKidentifier)
1479 BaseClass *b = new BaseClass(parseBasicType(), protection);
1480 baseclasses->push(b);
1482 switch (token.value) {
1483 case TOKcomma:
1484 continue;
1485 case TOKextends:
1486 if (type == 2)
1487 error("extends part must come before implements");
1488 else
1489 error("only one extends is permitted");
1490 continue;
1491 case TOKimplements:
1492 if (type == 1)
1493 type = 2;
1494 else
1495 error("separate implemented interfaces with commas");
1496 continue;
1498 break;
1500 else
1502 error("base classes expected instead of %s", token.toChars());
1503 return NULL;
1506 return baseclasses;
1509 /**************************************
1510 * Parse a TemplateDeclaration.
1513 TemplateDeclaration *Parser::parseTemplateDeclaration()
1515 TemplateDeclaration *tempdecl;
1516 Identifier *id;
1517 TemplateParameters *tpl;
1518 Array *decldefs;
1519 Loc loc = this->loc;
1521 nextToken();
1522 if (token.value != TOKidentifier)
1523 { error("TemplateIdentifier expected following template");
1524 goto Lerr;
1526 id = token.ident;
1527 nextToken();
1528 tpl = parseTemplateParameterList();
1529 if (!tpl)
1530 goto Lerr;
1532 if (token.value != startBlockTok)
1533 { error("members of template declaration expected");
1534 goto Lerr;
1536 else
1538 nextToken();
1539 decldefs = parseDeclDefs(0);
1540 if (token.value != TOKrcurly)
1541 { error("template member expected");
1542 goto Lerr;
1544 nextToken();
1547 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1548 return tempdecl;
1550 Lerr:
1551 return NULL;
1554 /******************************************
1555 * Parse template parameter list.
1556 * Input:
1557 * flag 0: parsing "( list )"
1558 * 1: parsing non-empty "list )"
1561 TemplateParameters *Parser::parseTemplateParameterList(int flag)
1563 TemplateParameters *tpl = new TemplateParameters();
1565 if (!flag && token.value != TOKlparen)
1566 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1567 goto Lerr;
1569 nextToken();
1571 // Get array of TemplateParameters
1572 if (flag || token.value != TOKrparen)
1573 { int isvariadic = 0;
1575 while (1)
1576 { TemplateParameter *tp;
1577 Identifier *tp_ident = NULL;
1578 Type *tp_spectype = NULL;
1579 Type *tp_valtype = NULL;
1580 Type *tp_defaulttype = NULL;
1581 Expression *tp_specvalue = NULL;
1582 Expression *tp_defaultvalue = NULL;
1583 Token *t;
1585 // Get TemplateParameter
1587 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1588 t = peek(&token);
1589 if (token.value == TOKalias)
1590 { // AliasParameter
1591 nextToken();
1592 if (token.value != TOKidentifier)
1593 { error("Identifier expected for template parameter");
1594 goto Lerr;
1596 tp_ident = token.ident;
1597 nextToken();
1598 if (token.value == TOKcolon) // : Type
1600 nextToken();
1601 tp_spectype = parseType();
1603 if (token.value == TOKassign) // = Type
1605 nextToken();
1606 tp_defaulttype = parseType();
1608 tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1610 else if (t->value == TOKcolon || t->value == TOKassign ||
1611 t->value == TOKcomma || t->value == TOKrparen)
1612 { // TypeParameter
1613 if (token.value != TOKidentifier)
1614 { error("Identifier expected for template parameter");
1615 goto Lerr;
1617 tp_ident = token.ident;
1618 nextToken();
1619 if (token.value == TOKcolon) // : Type
1621 nextToken();
1622 tp_spectype = parseType();
1624 if (token.value == TOKassign) // = Type
1626 nextToken();
1627 tp_defaulttype = parseType();
1629 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1631 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1632 { // ident...
1633 if (isvariadic)
1634 error("variadic template parameter must be last");
1635 isvariadic = 1;
1636 tp_ident = token.ident;
1637 nextToken();
1638 nextToken();
1639 tp = new TemplateTupleParameter(loc, tp_ident);
1641 else if (token.value == TOKthis)
1642 { // ThisParameter
1643 nextToken();
1644 if (token.value != TOKidentifier)
1645 { error("Identifier expected for template parameter");
1646 goto Lerr;
1648 tp_ident = token.ident;
1649 nextToken();
1650 if (token.value == TOKcolon) // : Type
1652 nextToken();
1653 tp_spectype = parseType();
1655 if (token.value == TOKassign) // = Type
1657 nextToken();
1658 tp_defaulttype = parseType();
1660 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1662 else
1663 { // ValueParameter
1664 tp_valtype = parseType(&tp_ident);
1665 if (!tp_ident)
1667 error("no identifier for template value parameter");
1668 tp_ident = new Identifier("error", TOKidentifier);
1670 if (token.value == TOKcolon) // : CondExpression
1672 nextToken();
1673 tp_specvalue = parseCondExp();
1675 if (token.value == TOKassign) // = CondExpression
1677 nextToken();
1678 tp_defaultvalue = parseDefaultInitExp();
1680 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1682 tpl->push(tp);
1683 if (token.value != TOKcomma)
1684 break;
1685 nextToken();
1688 check(TOKrparen);
1689 Lerr:
1690 return tpl;
1693 /******************************************
1694 * Parse template mixin.
1695 * mixin Foo;
1696 * mixin Foo!(args);
1697 * mixin a.b.c!(args).Foo!(args);
1698 * mixin Foo!(args) identifier;
1699 * mixin typeof(expr).identifier!(args);
1702 Dsymbol *Parser::parseMixin()
1704 TemplateMixin *tm;
1705 Identifier *id;
1706 Type *tqual;
1707 Objects *tiargs;
1708 Array *idents;
1710 //printf("parseMixin()\n");
1711 nextToken();
1712 tqual = NULL;
1713 if (token.value == TOKdot)
1715 id = Id::empty;
1717 else
1719 if (token.value == TOKtypeof)
1721 tqual = parseTypeof();
1722 check(TOKdot);
1724 if (token.value != TOKidentifier)
1726 error("identifier expected, not %s", token.toChars());
1727 goto Lerr;
1729 id = token.ident;
1730 nextToken();
1733 idents = new Array();
1734 while (1)
1736 tiargs = NULL;
1737 if (token.value == TOKnot)
1739 nextToken();
1740 tiargs = parseTemplateArgumentList();
1743 if (token.value != TOKdot)
1744 break;
1746 if (tiargs)
1747 { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1748 tempinst->tiargs = tiargs;
1749 id = (Identifier *)tempinst;
1750 tiargs = NULL;
1752 idents->push(id);
1754 nextToken();
1755 if (token.value != TOKidentifier)
1756 { error("identifier expected following '.' instead of '%s'", token.toChars());
1757 break;
1759 id = token.ident;
1760 nextToken();
1762 idents->push(id);
1764 if (token.value == TOKidentifier)
1766 id = token.ident;
1767 nextToken();
1769 else
1770 id = NULL;
1772 tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1774 if (dltSyntax) {
1775 if (token.value != TOKsemicolon && token.value != TOKendline)
1776 error("newline expected after mixin");
1777 } else {
1778 if (token.value != TOKsemicolon)
1779 error("';' expected after mixin");
1780 nextToken();
1783 return tm;
1785 Lerr:
1786 return NULL;
1789 /******************************************
1790 * Parse template argument list.
1791 * Input:
1792 * current token is opening '('
1793 * Output:
1794 * current token is one after closing ')'
1797 Objects *Parser::parseTemplateArgumentList()
1799 //printf("Parser::parseTemplateArgumentList()\n");
1800 if (token.value != TOKlparen)
1801 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1802 return new Objects();
1804 return parseTemplateArgumentList2();
1807 Objects *Parser::parseTemplateArgumentList2()
1809 Objects *tiargs = new Objects();
1810 nextToken();
1812 // Get TemplateArgumentList
1813 if (token.value != TOKrparen)
1815 while (1)
1817 // See if it is an Expression or a Type
1818 if (isDeclaration(&token, 0, TOKreserved, NULL))
1819 { // Type
1820 Type *ta;
1822 // Get TemplateArgument
1823 ta = parseType();
1824 tiargs->push(ta);
1826 else
1827 { // Expression
1828 Expression *ea;
1830 ea = parseAssignExp();
1831 tiargs->push(ea);
1833 if (token.value != TOKcomma)
1834 break;
1835 nextToken();
1838 check(TOKrparen, "template argument list");
1839 return tiargs;
1842 Import *Parser::parseImport(Array *decldefs, int isstatic)
1843 { Import *s;
1844 Identifier *id;
1845 Identifier *aliasid = NULL;
1846 Array *a;
1847 Loc loc;
1849 if (dltSyntax && isstatic)
1850 error("Delight imports are static by default");
1852 //printf("Parser::parseImport()\n");
1856 nextToken();
1857 if (token.value != TOKidentifier)
1858 { error("Identifier expected following import");
1859 break;
1862 loc = this->loc;
1863 a = NULL;
1864 id = token.ident;
1865 nextToken();
1866 if (!aliasid && token.value == TOKassign)
1868 aliasid = id;
1869 goto L1;
1871 while (token.value == TOKdot)
1873 if (!a)
1874 a = new Array();
1875 a->push(id);
1876 nextToken();
1877 if (token.value != TOKidentifier)
1878 { error("Identifier expected following package");
1879 break;
1881 id = token.ident;
1882 nextToken();
1885 s = new Import(loc, a, token.ident, aliasid, isstatic);
1886 decldefs->push(s);
1888 /* Look for
1889 * : alias=name, alias=name;
1890 * syntax.
1892 if (token.value == TOKcolon)
1894 nextToken();
1895 while (1)
1896 { Identifier *name;
1897 Identifier *alias;
1899 optionalEndline();
1901 if (dltSyntax && token.value == TOKrcurly)
1902 break;
1903 if (dltSyntax && token.value == TOKmul)
1905 // import module: *
1906 nextToken();
1907 optionalEndline();
1908 break;
1910 if (token.value != TOKidentifier)
1911 { error("Identifier expected following :");
1912 break;
1914 alias = token.ident;
1915 nextToken();
1916 if (token.value == TOKassign)
1918 nextToken();
1919 if (token.value != TOKidentifier)
1920 { error("Identifier expected following %s=", alias->toChars());
1921 break;
1923 name = token.ident;
1924 nextToken();
1926 else
1927 { name = alias;
1928 alias = NULL;
1930 s->addAlias(name, alias);
1931 if (token.value != TOKcomma && token.value != TOKendline)
1932 break;
1933 nextToken();
1935 if (dltSyntax)
1937 check(TOKrcurly);
1938 return NULL;
1940 else
1941 break;
1942 } else if (dltSyntax) {
1943 s->isstatic = true;
1946 aliasid = NULL;
1947 } while (token.value == TOKcomma);
1949 if (token.value == TOKsemicolon || token.value == TOKendline)
1950 nextToken();
1951 else
1953 error("%s expected", endToken());
1954 nextToken();
1957 return NULL;
1960 Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
1961 { Type *t;
1963 if (token.value == TOKconst && peek(&token)->value != TOKlparen)
1965 nextToken();
1966 /* const type
1968 t = parseType(pident, tpl);
1969 t = t->makeConst();
1970 return t;
1972 else if (token.value == TOKinvariant && peek(&token)->value != TOKlparen)
1974 nextToken();
1975 /* invariant type
1977 t = parseType(pident, tpl);
1978 t = t->makeInvariant();
1979 return t;
1981 else
1982 t = parseBasicType();
1983 t = parseDeclarator(t, pident, tpl);
1984 return t;
1987 Type *Parser::parseBasicType()
1988 { Type *t;
1989 Identifier *id;
1990 TypeQualified *tid;
1991 TemplateInstance *tempinst;
1993 //printf("parseBasicType()\n");
1994 switch (token.value)
1996 CASE_BASIC_TYPES_X(t):
1997 nextToken();
1998 break;
2000 case TOKidentifier:
2001 id = token.ident;
2002 nextToken();
2003 if (token.value == TOKnot)
2005 nextToken();
2006 tempinst = new TemplateInstance(loc, id);
2007 tempinst->tiargs = parseTemplateArgumentList();
2008 tid = new TypeInstance(loc, tempinst);
2009 goto Lident2;
2011 Lident:
2012 tid = new TypeIdentifier(loc, id);
2013 Lident2:
2014 while (token.value == TOKdot)
2015 { nextToken();
2016 if (token.value != TOKidentifier)
2017 { error("identifier expected following '.' instead of '%s'", token.toChars());
2018 break;
2020 id = token.ident;
2021 nextToken();
2022 if (token.value == TOKnot)
2024 nextToken();
2025 tempinst = new TemplateInstance(loc, id);
2026 tempinst->tiargs = parseTemplateArgumentList();
2027 tid->addIdent((Identifier *)tempinst);
2029 else
2030 tid->addIdent(id);
2032 t = tid;
2033 break;
2035 case TOKdot:
2036 id = Id::empty;
2037 goto Lident;
2039 case TOKtypeof:
2041 tid = parseTypeof();
2042 goto Lident2;
2045 case TOKconst:
2046 // const(type)
2047 nextToken();
2048 check(TOKlparen);
2049 t = parseType();
2050 check(TOKrparen);
2051 t = t->makeConst();
2052 break;
2054 case TOKinvariant:
2055 // invariant(type)
2056 nextToken();
2057 check(TOKlparen);
2058 t = parseType();
2059 check(TOKrparen);
2060 t = t->makeInvariant();
2061 break;
2063 default:
2064 error("basic type expected, not %s", token.toChars());
2065 t = Type::tint32;
2066 break;
2068 return t;
2071 Type *Parser::parseBasicType2(Type *t)
2073 Type *ts;
2074 Type *ta;
2076 //printf("parseBasicType2()\n");
2077 while (1)
2079 switch (token.value)
2081 case TOKmul:
2082 t = new TypePointer(t);
2083 nextToken();
2084 continue;
2086 case TOKlbracket:
2087 // Handle []. Make sure things like
2088 // int[3][1] a;
2089 // is (array[1] of array[3] of int)
2090 nextToken();
2091 if (token.value == TOKrbracket)
2093 t = new TypeDArray(t); // []
2094 nextToken();
2096 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2097 { // It's an associative array declaration
2098 Type *index;
2100 //printf("it's an associative array\n");
2101 index = parseType(); // [ type ]
2102 t = new TypeAArray(t, index);
2103 check(TOKrbracket);
2105 else
2107 //printf("it's [expression]\n");
2108 inBrackets++;
2109 Expression *e = parseExpression(); // [ expression ]
2110 if (token.value == TOKslice)
2111 { Expression *e2;
2113 nextToken();
2114 e2 = parseExpression(); // [ exp .. exp ]
2115 t = new TypeSlice(t, e, e2);
2117 else
2118 t = new TypeSArray(t,e);
2119 inBrackets--;
2120 check(TOKrbracket);
2122 continue;
2124 case TOKdelegate:
2125 case TOKfunction:
2126 { // Handle delegate declaration:
2127 // t delegate(parameter list)
2128 // t function(parameter list)
2129 Arguments *arguments;
2130 int varargs;
2131 bool ispure = false;
2132 bool isnothrow = false;
2133 enum TOK save = token.value;
2135 nextToken();
2136 arguments = parseParameters(&varargs);
2137 while (1)
2139 if (token.value == TOKpure)
2140 ispure = true;
2141 else if (token.value == TOKnothrow)
2142 isnothrow = true;
2143 else
2144 break;
2145 nextToken();
2147 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
2148 tf->ispure = ispure;
2149 tf->isnothrow = isnothrow;
2150 if (save == TOKdelegate)
2151 t = new TypeDelegate(tf);
2152 else
2153 t = new TypePointer(tf); // pointer to function
2154 continue;
2157 case TOKquestion:
2158 // Allow maybe annotations even for D code. Makes it easier to adapt
2159 // D interfaces for Delight
2160 if (1 || dltSyntax)
2162 Type *old = t;
2163 t = t->maybe(false);
2164 if (t == old)
2165 error("Type %s cannot be null; ? is pointless", old->toChars());
2166 nextToken();
2167 continue;
2169 // fall-through to default
2171 default:
2172 ts = t;
2173 break;
2175 break;
2178 return ts;
2181 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
2182 { Type *ts;
2184 //printf("parseDeclarator(tpl = %p)\n", tpl);
2185 t = parseBasicType2(t);
2187 switch (token.value)
2190 case TOKidentifier:
2191 if (pident)
2192 *pident = token.ident;
2193 else
2194 error("unexpected identifer '%s' in declarator", token.ident->toChars());
2195 ts = t;
2196 nextToken();
2197 break;
2199 case TOKlparen:
2200 /* Parse things with parentheses around the identifier, like:
2201 * int (*ident[3])[]
2202 * although the D style would be:
2203 * int[]*[3] ident
2205 nextToken();
2206 ts = parseDeclarator(t, pident);
2207 check(TOKrparen);
2208 break;
2210 default:
2211 ts = t;
2212 break;
2215 while (1)
2217 switch (token.value)
2219 #if CARRAYDECL
2220 /* Support C style array syntax:
2221 * int ident[]
2222 * as opposed to D-style:
2223 * int[] ident
2225 case TOKlbracket:
2226 { // This is the old C-style post [] syntax.
2227 TypeNext *ta;
2229 if (dltSyntax)
2230 error("use 'type[] var', not 'type var[]'");
2232 nextToken();
2233 if (token.value == TOKrbracket)
2234 { // It's a dynamic array
2235 ta = new TypeDArray(t); // []
2236 nextToken();
2238 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2239 { // It's an associative array
2241 //printf("it's an associative array\n");
2242 Type *index = parseType(); // [ type ]
2243 check(TOKrbracket);
2244 ta = new TypeAArray(t, index);
2246 else
2248 //printf("It's a static array\n");
2249 Expression *e = parseExpression(); // [ expression ]
2250 ta = new TypeSArray(t, e);
2251 check(TOKrbracket);
2254 /* Insert ta into
2255 * ts -> ... -> t
2256 * so that
2257 * ts -> ... -> ta -> t
2259 Type **pt;
2260 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2262 *pt = ta;
2263 continue;
2265 #endif
2266 case TOKlparen:
2268 if (tpl)
2270 /* Look ahead to see if this is (...)(...),
2271 * i.e. a function template declaration
2273 if (peekPastParen(&token)->value == TOKlparen)
2275 //printf("function template declaration\n");
2277 // Gather template parameter list
2278 *tpl = parseTemplateParameterList();
2282 int varargs;
2283 Arguments *arguments = parseParameters(&varargs);
2284 Type *tf = new TypeFunction(arguments, t, varargs, linkage);
2286 /* Parse const/invariant/nothrow postfix
2288 while (1)
2290 switch (token.value)
2292 case TOKconst:
2293 tf = tf->makeConst();
2294 nextToken();
2295 continue;
2297 case TOKinvariant:
2298 tf = tf->makeInvariant();
2299 nextToken();
2300 continue;
2302 case TOKnothrow:
2303 ((TypeFunction *)tf)->isnothrow = 1;
2304 nextToken();
2305 continue;
2307 case TOKpure:
2308 ((TypeFunction *)tf)->ispure = 1;
2309 nextToken();
2310 continue;
2312 break;
2315 /* Insert tf into
2316 * ts -> ... -> t
2317 * so that
2318 * ts -> ... -> tf -> t
2320 Type **pt;
2321 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2323 *pt = tf;
2324 break;
2327 break;
2330 return ts;
2333 /**********************************
2334 * Return array of Declaration *'s.
2337 Array *Parser::parseDeclarations()
2339 enum STC storage_class;
2340 enum STC stc;
2341 Type *ts;
2342 Type *t;
2343 Type *tfirst;
2344 Identifier *ident;
2345 Array *a;
2346 enum TOK tok;
2347 unsigned char *comment = token.blockComment;
2348 enum LINK link = linkage;
2350 //printf("parseDeclarations() %s\n", token.toChars());
2351 switch (token.value)
2353 case TOKtypedef:
2354 case TOKalias:
2355 tok = token.value;
2356 nextToken();
2357 break;
2359 default:
2360 tok = TOKreserved;
2361 break;
2364 storage_class = STCundefined;
2365 while (1)
2367 switch (token.value)
2369 case TOKconst:
2370 if (peek(&token)->value == TOKlparen)
2371 break;
2372 stc = STCconst;
2373 goto L1;
2375 case TOKinvariant:
2376 if (peek(&token)->value == TOKlparen)
2377 break;
2378 stc = STCinvariant;
2379 goto L1;
2381 case TOKstatic: stc = STCstatic; goto L1;
2382 case TOKfinal: stc = STCfinal; goto L1;
2383 case TOKauto: stc = STCauto; goto L1;
2384 case TOKscope: stc = STCscope; goto L1;
2385 case TOKoverride: stc = STCoverride; goto L1;
2386 case TOKabstract: stc = STCabstract; goto L1;
2387 case TOKsynchronized: stc = STCsynchronized; goto L1;
2388 case TOKdeprecated: stc = STCdeprecated; goto L1;
2389 case TOKnothrow: stc = STCnothrow; goto L1;
2390 case TOKpure: stc = STCpure; goto L1;
2391 case TOKtls: stc = STCtls; goto L1;
2392 case TOKenum: stc = STCmanifest; goto L1;
2394 if (storage_class & stc)
2395 error("redundant storage class '%s'", token.toChars());
2396 storage_class = (STC) (storage_class | stc);
2398 unsigned u = storage_class;
2399 u &= STCconst | STCinvariant | STCmanifest;
2400 if (u & (u - 1))
2401 error("conflicting storage class %s", Token::toChars(token.value));
2403 nextToken();
2404 continue;
2406 case TOKextern:
2407 if (peek(&token)->value != TOKlparen)
2408 { stc = STCextern;
2409 goto L1;
2412 link = parseLinkage();
2413 continue;
2415 default:
2416 break;
2418 break;
2421 a = new Array();
2423 /* Look for auto initializers:
2424 * storage_class identifier = initializer;
2426 while (storage_class &&
2427 token.value == TOKidentifier &&
2428 peek(&token)->value == TOKassign)
2430 ident = token.ident;
2431 nextToken();
2432 nextToken();
2433 Initializer *init = parseInitializer();
2434 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2435 v->storage_class = storage_class;
2436 v->dltNormalMode = dltNormalMode;
2437 a->push(v);
2438 if (token.value == TOKsemicolon || token.value == TOKendline)
2440 nextToken();
2441 addComment(v, comment);
2443 else if (token.value == TOKcomma)
2445 nextToken();
2446 if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
2448 error("Identifier expected following comma");
2450 else
2451 continue;
2453 else
2454 error("%s expected following auto declaration, not '%s'", endToken(), token.toChars());
2455 return a;
2458 if (token.value == TOKclass)
2459 { AggregateDeclaration *s;
2461 s = (AggregateDeclaration *)parseAggregate();
2462 s->storage_class |= storage_class;
2463 a->push(s);
2464 addComment(s, comment);
2465 return a;
2468 ts = parseBasicType();
2469 ts = parseBasicType2(ts);
2470 tfirst = NULL;
2472 while (1)
2474 Loc loc = this->loc;
2475 TemplateParameters *tpl = NULL;
2477 ident = NULL;
2478 t = parseDeclarator(ts, &ident, &tpl);
2479 assert(t);
2480 if (!tfirst)
2481 tfirst = t;
2482 else if (t != tfirst)
2483 error("multiple declarations must have the same type, not %s and %s",
2484 tfirst->toChars(), t->toChars());
2485 if (!ident)
2486 error("no identifier for declarator %s", t->toChars());
2488 if (tok == TOKtypedef || tok == TOKalias)
2489 { Declaration *v;
2490 Initializer *init;
2492 init = NULL;
2493 if (token.value == TOKassign)
2495 nextToken();
2496 init = parseInitializer();
2498 if (tok == TOKtypedef)
2499 v = new TypedefDeclaration(loc, ident, t, init);
2500 else
2501 { if (init)
2502 error("alias cannot have initializer");
2503 v = new AliasDeclaration(loc, ident, t);
2505 v->storage_class = storage_class;
2506 if (link == linkage)
2507 a->push(v);
2508 else
2510 Array *ax = new Array();
2511 ax->push(v);
2512 Dsymbol *s = new LinkDeclaration(link, ax);
2513 a->push(s);
2515 switch (token.value)
2516 { case TOKsemicolon:
2517 case TOKendline:
2518 nextToken();
2519 addComment(v, comment);
2520 break;
2522 case TOKcomma:
2523 nextToken();
2524 addComment(v, comment);
2525 continue;
2527 default:
2528 error("%s expected to close %s declaration", endToken(), Token::toChars(tok));
2529 break;
2532 else if (t->ty == Tfunction)
2533 { FuncDeclaration *f;
2534 Dsymbol *s;
2536 f = new FuncDeclaration(loc, 0, ident, storage_class, t);
2537 addComment(f, comment);
2538 parseContracts(f);
2539 addComment(f, NULL);
2540 if (link == linkage)
2542 s = f;
2544 else
2546 Array *ax = new Array();
2547 ax->push(f);
2548 s = new LinkDeclaration(link, ax);
2550 if (tpl) // it's a function template
2551 { Array *decldefs;
2552 TemplateDeclaration *tempdecl;
2554 // Wrap a template around the aggregate declaration
2555 decldefs = new Array();
2556 decldefs->push(s);
2557 tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs, dltSyntax);
2558 s = tempdecl;
2560 addComment(s, comment);
2561 a->push(s);
2563 else
2564 { VarDeclaration *v;
2565 Initializer *init;
2567 init = NULL;
2568 if (token.value == TOKassign)
2570 nextToken();
2571 init = parseInitializer();
2573 v = new VarDeclaration(loc, t, ident, init);
2574 if (dltSyntax)
2575 v->requirePointerInit = true;
2576 v->storage_class = storage_class;
2577 v->dltNormalMode = dltNormalMode;
2578 if (link == linkage)
2579 a->push(v);
2580 else
2582 Array *ax = new Array();
2583 ax->push(v);
2584 Dsymbol *s = new LinkDeclaration(link, ax);
2585 a->push(s);
2587 switch (token.value)
2589 case TOKendline:
2590 nextToken();
2591 addComment(v, comment);
2592 break;
2593 case TOKsemicolon:
2594 if (!dltSyntax)
2595 nextToken();
2596 addComment(v, comment);
2597 break;
2598 case TOKcomma:
2599 nextToken();
2600 addComment(v, comment);
2601 continue;
2603 default:
2604 error("%s expected, not '%s'", endToken(), token.toChars());
2605 break;
2608 break;
2610 return a;
2613 /*****************************************
2614 * Parse contracts following function declaration.
2617 void Parser::parseContracts(FuncDeclaration *f)
2619 Type *tb;
2620 enum LINK linksave = linkage;
2622 // The following is irrelevant, as it is overridden by sc->linkage in
2623 // TypeFunction::semantic
2624 linkage = LINKd; // nested functions have D linkage
2626 switch (token.value)
2628 case TOKlcurly:
2629 case TOKcolon:
2630 if (token.value != startBlockTok)
2631 error("use %s to start a new block", Token::toChars(startBlockTok));
2632 if (f->frequire || f->fensure)
2633 error("missing body { ... } after in or out");
2634 f->fbody = parseStatement(PSsemi | PScolon);
2635 f->endloc = endloc;
2636 break;
2638 case TOKbody:
2639 nextToken();
2640 f->fbody = parseStatement(PScurly);
2641 f->endloc = endloc;
2642 break;
2644 case TOKsemicolon:
2645 if (dltSyntax)
2646 error("unexpected semi-colon after function declaration");
2647 // fall-through
2648 case TOKendline:
2649 if (f->frequire || f->fensure)
2650 error("missing body { ... } after in or out");
2651 nextToken();
2652 break;
2654 #if 0 // Do we want this for function declarations, so we can do:
2655 // int x, y, foo(), z;
2656 case TOKcomma:
2657 nextToken();
2658 continue;
2659 #endif
2661 #if 0 // Dumped feature
2662 case TOKthrow:
2663 if (!f->fthrows)
2664 f->fthrows = new Array();
2665 nextToken();
2666 check(TOKlparen);
2667 while (1)
2669 tb = parseBasicType();
2670 f->fthrows->push(tb);
2671 if (token.value == TOKcomma)
2672 { nextToken();
2673 continue;
2675 break;
2677 check(TOKrparen);
2678 goto L1;
2679 #endif
2681 case TOKin:
2682 nextToken();
2683 if (f->frequire)
2684 error("redundant 'in' statement");
2685 f->frequire = parseStatement(PScurly | PSscope);
2686 goto L1;
2688 case TOKout:
2689 // parse: out (identifier) { statement }
2690 nextToken();
2691 if (token.value != startBlockTok)
2693 check(TOKlparen);
2694 if (token.value != TOKidentifier)
2695 error("(identifier) following 'out' expected, not %s", token.toChars());
2696 f->outId = token.ident;
2697 nextToken();
2698 check(TOKrparen);
2700 if (f->fensure)
2701 error("redundant 'out' statement");
2702 f->fensure = parseStatement(PScurly | PSscope);
2703 goto L1;
2705 default:
2706 error("%s expected following function declaration", endToken());
2707 break;
2709 linkage = linksave;
2712 /*****************************************
2715 Initializer *Parser::parseInitializer()
2717 StructInitializer *is;
2718 ArrayInitializer *ia;
2719 ExpInitializer *ie;
2720 Expression *e;
2721 Identifier *id;
2722 Initializer *value;
2723 int comma;
2724 Loc loc = this->loc;
2725 Token *t;
2726 int braces;
2728 switch (token.value)
2730 case TOKlcurly:
2731 /* Scan ahead to see if it is a struct initializer or
2732 * a function literal.
2733 * If it contains a ';', it is a function literal.
2734 * Treat { } as a struct initializer.
2736 braces = 1;
2737 for (t = peek(&token); 1; t = peek(t))
2739 switch (t->value)
2741 case TOKsemicolon:
2742 case TOKreturn:
2743 goto Lexpression;
2745 case TOKlcurly:
2746 braces++;
2747 continue;
2749 case TOKrcurly:
2750 if (--braces == 0)
2751 break;
2752 continue;
2754 case TOKeof:
2755 break;
2757 default:
2758 continue;
2760 break;
2763 is = new StructInitializer(loc);
2764 nextToken();
2765 comma = 0;
2766 while (1)
2768 switch (token.value)
2770 case TOKidentifier:
2771 if (comma == 1)
2772 error("comma expected separating field initializers");
2773 t = peek(&token);
2774 if (t->value == TOKcolon)
2776 id = token.ident;
2777 nextToken();
2778 nextToken(); // skip over ':'
2780 else
2781 { id = NULL;
2783 value = parseInitializer();
2784 is->addInit(id, value);
2785 comma = 1;
2786 continue;
2788 case TOKcomma:
2789 nextToken();
2790 comma = 2;
2791 continue;
2793 case TOKrcurly: // allow trailing comma's
2794 nextToken();
2795 break;
2797 case TOKeof:
2798 error("found EOF instead of initializer");
2799 break;
2801 default:
2802 value = parseInitializer();
2803 is->addInit(NULL, value);
2804 comma = 1;
2805 continue;
2806 //error("found '%s' instead of field initializer", token.toChars());
2807 //break;
2809 break;
2811 return is;
2813 case TOKlbracket:
2814 ia = new ArrayInitializer(loc);
2815 nextToken();
2816 comma = 0;
2817 while (1)
2819 switch (token.value)
2821 default:
2822 if (comma == 1)
2823 { error("comma expected separating array initializers, not %s", token.toChars());
2824 nextToken();
2825 break;
2827 e = parseAssignExp();
2828 if (!e)
2829 break;
2830 if (token.value == TOKcolon)
2832 nextToken();
2833 value = parseInitializer();
2835 else
2836 { value = new ExpInitializer(e->loc, e);
2837 e = NULL;
2839 ia->addInit(e, value);
2840 comma = 1;
2841 continue;
2843 case TOKlcurly:
2844 case TOKlbracket:
2845 if (comma == 1)
2846 error("comma expected separating array initializers, not %s", token.toChars());
2847 value = parseInitializer();
2848 ia->addInit(NULL, value);
2849 comma = 1;
2850 continue;
2852 case TOKcomma:
2853 nextToken();
2854 comma = 2;
2855 continue;
2857 case TOKrbracket: // allow trailing comma's
2858 nextToken();
2859 break;
2861 case TOKeof:
2862 error("found '%s' instead of array initializer", token.toChars());
2863 break;
2865 break;
2867 return ia;
2869 case TOKvoid:
2870 t = peek(&token);
2871 if (t->value == TOKsemicolon || t->value == TOKcomma || t->value == TOKendline)
2873 nextToken();
2874 return new VoidInitializer(loc);
2876 goto Lexpression;
2878 default:
2879 Lexpression:
2880 e = parseAssignExp();
2881 ie = new ExpInitializer(loc, e);
2882 return ie;
2886 /*****************************************
2887 * Parses default argument initializer expression that is an assign expression,
2888 * with special handling for __FILE__ and __LINE__.
2891 Expression *Parser::parseDefaultInitExp()
2893 if (token.value == TOKfile ||
2894 token.value == TOKline)
2896 Token *t = peek(&token);
2897 if (t->value == TOKcomma || t->value == TOKrparen)
2898 { Expression *e;
2900 if (token.value == TOKfile)
2901 e = new FileInitExp(loc);
2902 else
2903 e = new LineInitExp(loc);
2904 nextToken();
2905 return e;
2909 Expression *e = parseAssignExp();
2910 return e;
2913 Statement *Parser::logStatement(int level) {
2914 nextToken();
2915 if (token.value != TOKlparen)
2916 error(loc, "found '%s' when expecting '('", token.toChars());
2917 return new LogStatement(loc, level, parseArguments());
2920 /*****************************************
2921 * Input:
2922 * flags PSxxxx
2925 Statement *DltParser::parseStatement(int flags)
2927 optionalEndline();
2928 if (flags & (PScolon | PSscope))
2929 flags |= PScurly;
2930 return Parser::parseStatement(flags);
2933 Statement *Parser::parseStatement(int flags)
2934 { Statement *s;
2935 Token *t;
2936 Condition *condition;
2937 Statement *ifbody;
2938 Statement *elsebody;
2939 Loc loc = this->loc;
2941 //printf("parseStatement()\n");
2943 if ((flags & PScurly) && token.value != startBlockTok)
2944 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
2946 int tok = token.value;
2948 switch (token.value)
2950 case TOKidentifier:
2951 if (!dltSyntax)
2953 // Need to look ahead to see if it is a declaration, label, or expression
2954 t = peek(&token);
2955 if (t->value == TOKcolon)
2956 { // It's a label
2957 Identifier *ident;
2959 ident = token.ident;
2960 nextToken();
2961 nextToken();
2962 s = parseStatement(PSsemi);
2963 s = new LabelStatement(loc, ident, s);
2964 break;
2967 // fallthrough to TOKdot
2968 case TOKdot:
2969 case TOKtypeof:
2970 if (isDeclaration(&token, 2, TOKreserved, NULL))
2971 goto Ldeclaration;
2972 else
2973 goto Lexp;
2974 break;
2976 case TOKassert:
2977 case TOKthis:
2978 case TOKsuper:
2979 case TOKint32v:
2980 case TOKuns32v:
2981 case TOKint64v:
2982 case TOKuns64v:
2983 case TOKfloat32v:
2984 case TOKfloat64v:
2985 case TOKfloat80v:
2986 case TOKimaginary32v:
2987 case TOKimaginary64v:
2988 case TOKimaginary80v:
2989 case TOKcharv:
2990 case TOKwcharv:
2991 case TOKdcharv:
2992 case TOKnull:
2993 case TOKtrue:
2994 case TOKfalse:
2995 case TOKstring:
2996 case TOKlparen:
2997 case TOKcast:
2998 case TOKmul:
2999 case TOKmin:
3000 case TOKadd:
3001 case TOKplusplus:
3002 case TOKminusminus:
3003 case TOKnew:
3004 case TOKdelete:
3005 case TOKdelegate:
3006 case TOKfunction:
3007 case TOKtypeid:
3008 case TOKis:
3009 case TOKlbracket:
3010 case TOKtraits:
3011 case TOKfile:
3012 case TOKline:
3013 Lexp:
3014 { Expression *exp;
3016 exp = parseExpression();
3017 if (!dltSyntax)
3018 check(TOKsemicolon, "statement");
3019 s = new ExpStatement(loc, exp);
3020 break;
3023 case TOKstatic:
3024 { // Look ahead to see if it's static assert() or static if()
3025 Token *t;
3027 t = peek(&token);
3028 if (t->value == TOKassert)
3030 nextToken();
3031 s = new StaticAssertStatement(parseStaticAssert());
3032 break;
3034 if (t->value == TOKif)
3036 nextToken();
3037 condition = parseStaticIfCondition();
3038 goto Lcondition;
3040 if (dltNormalMode)
3041 error("no static variables in Delight");
3042 goto Ldeclaration;
3045 CASE_BASIC_TYPES:
3046 case TOKtypedef:
3047 case TOKalias:
3048 case TOKconst:
3049 case TOKauto:
3050 case TOKextern:
3051 case TOKfinal:
3052 case TOKinvariant:
3053 // case TOKtypeof:
3054 Ldeclaration:
3055 { Array *a;
3057 a = parseDeclarations();
3058 if (a->dim > 1)
3060 Statements *as = new Statements();
3061 as->reserve(a->dim);
3062 for (int i = 0; i < a->dim; i++)
3064 Dsymbol *d = (Dsymbol *)a->data[i];
3065 s = new DeclarationStatement(loc, d);
3066 as->push(s);
3068 s = new CompoundStatement(loc, as);
3070 else if (a->dim == 1)
3072 Dsymbol *d = (Dsymbol *)a->data[0];
3073 s = new DeclarationStatement(loc, d);
3075 else
3076 assert(0);
3077 if (flags & PSscope)
3078 s = new ScopeStatement(loc, s);
3079 break;
3082 case TOKstruct:
3083 case TOKunion:
3084 case TOKclass:
3085 case TOKinterface:
3086 { Dsymbol *d;
3088 d = parseAggregate();
3089 s = new DeclarationStatement(loc, d);
3090 break;
3093 case TOKenum:
3094 { /* Determine if this is a manifest constant declaration,
3095 * or a conventional enum.
3097 Dsymbol *d;
3098 Token *t = peek(&token);
3099 if (t->value == startBlockTok ||
3100 t->value == (dltSyntax ? TOKextends : TOKcolon))
3102 d = parseEnum();
3104 else if (t->value != TOKidentifier)
3105 goto Ldeclaration;
3106 else
3108 t = peek(t);
3109 if (t->value == startBlockTok ||
3110 t->value == (dltSyntax ? TOKextends : TOKcolon) ||
3111 t->value == TOKsemicolon)
3112 d = parseEnum();
3113 else
3114 goto Ldeclaration;
3116 s = new DeclarationStatement(loc, d);
3117 break;
3120 case TOKmixin:
3121 { t = peek(&token);
3122 if (t->value == TOKlparen)
3123 { // mixin(string)
3124 nextToken();
3125 check(TOKlparen, "mixin");
3126 Expression *e = parseAssignExp();
3127 check(TOKrparen);
3128 if (dltSyntax) {
3129 if (token.value != TOKsemicolon && token.value != TOKendline) {
3130 error("expected newline after mixin(), not '%s'", token.toChars());
3132 } else {
3133 check(TOKsemicolon);
3135 s = new CompileStatement(loc, e);
3136 break;
3138 Dsymbol *d = parseMixin();
3139 s = new DeclarationStatement(loc, d);
3140 break;
3143 case TOKcolon:
3144 case TOKlcurly:
3145 { Statements *statements;
3147 if (token.value != startBlockTok)
3148 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
3150 nextToken();
3151 optionalEndline();
3152 statements = new Statements();
3153 while (token.value != TOKrcurly)
3155 statements->push(parseStatement(PSsemi | PScurlyscope));
3156 optionalEndline();
3158 endloc = this->loc;
3159 s = new CompoundStatement(loc, statements);
3160 if (flags & (PSscope | PScurlyscope))
3161 s = new ScopeStatement(loc, s);
3162 nextToken();
3163 break;
3166 case TOKlog_error: s = logStatement(LogStatement::Error); break;
3167 case TOKlog_warning: s = logStatement(LogStatement::Warn); break;
3168 case TOKlog_info: s = logStatement(LogStatement::Info); break;
3169 case TOKlog_trace: s = logStatement(LogStatement::Trace); break;
3171 case TOKwhile:
3172 { Expression *condition;
3173 Statement *body;
3175 nextToken();
3176 checkLParen();
3177 condition = parseExpression();
3178 checkRParen();
3179 body = parseStatement(PSscope);
3180 s = new WhileStatement(loc, condition, body);
3181 break;
3184 case TOKsemicolon:
3185 if (!(flags & PSsemi))
3186 error("use '{ }' for an empty statement, not a ';'");
3187 nextToken();
3188 s = new ExpStatement(loc, NULL);
3189 break;
3191 case TOKdo:
3192 { Statement *body;
3193 Expression *condition;
3195 nextToken();
3196 body = parseStatement(PSscope);
3197 check(TOKwhile);
3198 checkLParen();
3199 condition = parseExpression();
3200 checkRParen();
3201 s = new DoStatement(loc, body, condition);
3202 break;
3205 case TOKfor:
3207 Statement *init;
3208 Expression *condition;
3209 Expression *increment;
3210 Statement *body;
3212 nextToken();
3214 if (token.value == TOKlparen) {
3215 /* for (init; cond; incr): ... */
3216 nextToken();
3217 if (token.value == TOKsemicolon)
3218 { init = NULL;
3219 nextToken();
3221 else
3222 { init = parseStatement(0);
3223 if (dltSyntax)
3224 check(TOKsemicolon);
3226 if (token.value == TOKsemicolon)
3228 condition = NULL;
3229 nextToken();
3231 else
3233 condition = parseExpression();
3234 check(TOKsemicolon, "for condition");
3236 if (token.value == TOKrparen)
3237 { increment = NULL;
3238 nextToken();
3240 else
3241 { increment = parseExpression();
3242 check(TOKrparen);
3244 body = parseStatement(PSscope);
3245 s = new ForStatement(loc, init, condition, increment, body);
3246 if (init)
3247 s = new ScopeStatement(loc, s);
3248 } else if (dltSyntax)
3249 goto caseForeach;
3250 break;
3253 caseForeach:
3254 case TOKforeach:
3255 case TOKforeach_reverse:
3257 /* for var in seq: ... */
3258 /* for index, var in seq: ... */
3259 Arguments *arguments;
3261 Statement *d;
3262 Statement *body;
3263 Expression *aggr;
3264 enum TOK op = (TOK) tok;
3266 if (tok == TOKfor)
3267 op = TOKforeach; // Delight foreach syntax
3268 else
3269 nextToken();
3271 checkLParen();
3273 TOK inTok = dltSyntax ? TOKin : TOKsemicolon;
3275 arguments = new Arguments();
3277 while (1)
3279 Type *tb;
3280 Identifier *ai = NULL;
3281 Type *at;
3282 unsigned storageClass;
3283 Argument *a;
3285 storageClass = 0;
3286 if (token.value == TOKinout || token.value == TOKref)
3287 { storageClass = STCref;
3288 nextToken();
3290 if (token.value == TOKidentifier)
3292 Token *t = peek(&token);
3293 if (t->value == TOKcomma || t->value == inTok)
3294 { ai = token.ident;
3295 at = NULL; // infer argument type
3296 nextToken();
3297 goto Larg;
3300 at = parseType(&ai);
3301 if (!ai)
3302 error("no identifier for declarator %s", at->toChars());
3303 Larg:
3304 a = new Argument(storageClass, at, ai, NULL);
3305 arguments->push(a);
3306 if (token.value == TOKcomma)
3307 { nextToken();
3308 continue;
3310 break;
3313 check(inTok);
3315 aggr = parseExpression();
3316 if (token.value == TOKslice && arguments->dim == 1)
3318 Argument *a = (Argument *)arguments->data[0];
3319 delete arguments;
3320 nextToken();
3321 Expression *upr = parseExpression();
3322 checkRParen();
3323 if (token.value == TOKreserved)
3325 op = TOKforeach_reverse;
3326 nextToken();
3328 body = parseStatement(0);
3329 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3331 else
3333 checkRParen();
3334 if (token.value == TOKreversed)
3336 op = TOKforeach_reverse;
3337 nextToken();
3339 body = parseStatement(0);
3340 s = new ForeachStatement(loc, op, arguments, aggr, body);
3342 break;
3345 case TOKif:
3346 { Argument *arg = NULL;
3347 Expression *condition;
3348 Statement *ifbody;
3349 Statement *elsebody;
3351 nextToken();
3352 checkLParen();
3354 if (token.value == TOKauto)
3356 nextToken();
3357 if (token.value == TOKidentifier)
3359 Token *t = peek(&token);
3360 if (t->value == TOKassign)
3362 arg = new Argument(0, NULL, token.ident, NULL);
3363 nextToken();
3364 nextToken();
3366 else
3367 { error("= expected following auto identifier");
3368 goto Lerror;
3371 else
3372 { error("identifier expected following auto");
3373 goto Lerror;
3376 else if (isDeclaration(&token, 2, TOKassign, NULL))
3378 Type *at;
3379 Identifier *ai;
3381 at = parseType(&ai);
3382 check(TOKassign);
3383 arg = new Argument(0, at, ai, NULL);
3386 // Check for " ident;"
3387 else if (token.value == TOKidentifier && !dltSyntax)
3389 Token *t = peek(&token);
3390 if (t->value == TOKcomma || t->value == TOKsemicolon)
3392 arg = new Argument(0, NULL, token.ident, NULL);
3393 nextToken();
3394 nextToken();
3395 if (1 || !global.params.useDeprecated)
3396 error("if (v; e) is deprecated, use if (auto v = e)");
3400 condition = parseExpression();
3401 checkRParen();
3402 ifbody = parseStatement(PSscope);
3403 if (token.value == TOKelse)
3405 nextToken();
3406 if (dltSyntax)
3408 if (token.value == TOKcolon) {
3409 elsebody = parseStatement(PSscope);
3410 } else if (token.value == TOKif) {
3411 elsebody = parseStatement(0);
3412 } else {
3413 error("Expected 'else:' or 'else if', not 'else %s'", token.toChars());
3414 elsebody = NULL;
3417 else
3418 elsebody = parseStatement(PSscope);
3420 else
3421 elsebody = NULL;
3422 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3423 break;
3426 case TOKscope:
3427 if (peek(&token)->value != TOKlparen)
3428 goto Ldeclaration; // scope used as storage class
3429 nextToken();
3430 check(TOKlparen);
3431 if (token.value != TOKidentifier)
3432 { error("scope identifier expected");
3433 goto Lerror;
3435 else
3436 { TOK t = TOKon_scope_exit;
3437 Identifier *id = token.ident;
3439 if (id == Id::exit)
3440 t = TOKon_scope_exit;
3441 else if (id == Id::failure)
3442 t = TOKon_scope_failure;
3443 else if (id == Id::success)
3444 t = TOKon_scope_success;
3445 else
3446 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3447 nextToken();
3448 check(TOKrparen);
3449 Statement *st = parseStatement(PScolon | PScurlyscope);
3450 s = new OnScopeStatement(loc, t, st);
3451 break;
3454 case TOKdebug:
3455 nextToken();
3456 condition = parseDebugCondition();
3457 goto Lcondition;
3459 case TOKversion:
3460 nextToken();
3461 condition = parseVersionCondition();
3462 goto Lcondition;
3464 Lcondition:
3465 if (dltSyntax && token.value != TOKcolon)
3466 error("expected colon after condition, not '%s'", token.toChars());
3467 ifbody = parseStatement(PScolon /*PSsemi*/);
3468 elsebody = NULL;
3469 if (token.value == TOKelse)
3471 nextToken();
3472 elsebody = parseStatement(PScolon /*PSsemi*/);
3474 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3475 break;
3477 case TOKpragma:
3478 { Identifier *ident;
3479 Expressions *args = NULL;
3480 Statement *body;
3482 nextToken();
3483 check(TOKlparen);
3484 if (token.value != TOKidentifier)
3485 { error("pragma(identifier expected");
3486 goto Lerror;
3488 ident = token.ident;
3489 nextToken();
3490 if (token.value == TOKcomma)
3491 args = parseArguments(); // pragma(identifier, args...);
3492 else
3493 check(TOKrparen); // pragma(identifier);
3494 if (token.value == TOKsemicolon)
3495 { nextToken();
3496 body = NULL;
3498 else
3499 body = parseStatement(PSsemi | PScolon);
3500 s = new PragmaStatement(loc, ident, args, body);
3501 break;
3504 case TOKswitch:
3505 { Expression *condition;
3506 Statement *body;
3508 nextToken();
3509 checkLParen();
3510 condition = parseExpression();
3511 checkRParen();
3512 body = parseStatement(PSscope | PScolon);
3513 s = new SwitchStatement(loc, condition, body);
3514 break;
3517 case TOKcase:
3518 { Expression *exp;
3519 Statements *statements;
3520 Array cases; // array of Expression's
3522 while (1)
3524 nextToken();
3525 exp = parseAssignExp();
3526 cases.push(exp);
3527 if (token.value != TOKcomma)
3528 break;
3531 if (dltSyntax)
3533 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3535 else
3537 check(TOKcolon);
3539 statements = new Statements();
3540 while (token.value != TOKcase &&
3541 token.value != TOKdefault &&
3542 token.value != TOKrcurly)
3544 statements->push(parseStatement(PSsemi | PScurlyscope));
3546 s = new CompoundStatement(loc, statements);
3549 s = new ScopeStatement(loc, s);
3551 // Keep cases in order by building the case statements backwards
3552 for (int i = cases.dim; i; i--)
3554 exp = (Expression *)cases.data[i - 1];
3555 s = new CaseStatement(loc, exp, s);
3557 break;
3560 case TOKdefault:
3562 Statements *statements;
3564 nextToken();
3566 if (dltSyntax)
3568 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3570 else
3572 check(TOKcolon);
3574 statements = new Statements();
3575 while (token.value != TOKcase &&
3576 token.value != TOKdefault &&
3577 token.value != TOKrcurly)
3579 statements->push(parseStatement(PSsemi | PScurlyscope));
3581 s = new CompoundStatement(loc, statements);
3584 s = new ScopeStatement(loc, s);
3585 s = new DefaultStatement(loc, s);
3586 break;
3589 case TOKreturn:
3590 { Expression *exp;
3592 nextToken();
3593 if (token.value == TOKsemicolon || token.value == TOKendline)
3594 exp = NULL;
3595 else
3596 exp = parseExpression();
3598 if (!dltSyntax)
3599 check(TOKsemicolon, "return statement");
3600 else if (token.value != TOKendline) {
3601 error("Expected end-of-line after return statement, but found '%s'", token.toChars());
3604 s = new ReturnStatement(loc, exp);
3605 break;
3608 case TOKbreak:
3609 { Identifier *ident;
3611 nextToken();
3612 if (token.value == TOKidentifier)
3613 { ident = token.ident;
3614 nextToken();
3616 else
3617 ident = NULL;
3618 if (token.value != TOKsemicolon && token.value != TOKendline) {
3619 error("expected %s after break, not '%s'", endToken(), token.toChars());
3621 if (!dltSyntax)
3622 nextToken();
3623 s = new BreakStatement(loc, ident);
3624 break;
3627 case TOKcontinue:
3628 { Identifier *ident;
3630 nextToken();
3631 if (token.value == TOKidentifier)
3632 { ident = token.ident;
3633 nextToken();
3635 else
3636 ident = NULL;
3637 if (!dltSyntax)
3638 check(TOKsemicolon, "continue statement");
3639 else if (token.value != TOKendline && token.value != TOKsemicolon) {
3640 error("Expected end-of-line after continue statement, but found '%s'", token.toChars());
3642 s = new ContinueStatement(loc, ident);
3643 break;
3646 case TOKgoto:
3647 { Identifier *ident;
3649 nextToken();
3650 if (token.value == TOKdefault)
3652 nextToken();
3653 s = new GotoDefaultStatement(loc);
3655 else if (token.value == TOKcase)
3657 Expression *exp = NULL;
3659 nextToken();
3660 if (token.value != TOKsemicolon)
3661 exp = parseExpression();
3662 s = new GotoCaseStatement(loc, exp);
3664 else
3666 if (token.value != TOKidentifier)
3667 { error("Identifier expected following goto");
3668 ident = NULL;
3670 else
3671 { ident = token.ident;
3672 nextToken();
3674 s = new GotoStatement(loc, ident);
3676 if (dltSyntax)
3678 if (token.value != TOKsemicolon && token.value != TOKendline) {
3679 error("expected %s after goto statement, not '%s'", endToken(), token.toChars());
3682 else
3683 check(TOKsemicolon);
3684 break;
3687 case TOKsynchronized:
3688 { Expression *exp;
3689 Statement *body;
3691 nextToken();
3692 if (token.value == TOKlparen)
3694 nextToken();
3695 exp = parseExpression();
3696 check(TOKrparen);
3698 else
3699 exp = NULL;
3700 body = parseStatement(PSscope);
3701 s = new SynchronizedStatement(loc, exp, body);
3702 break;
3705 case TOKwith:
3706 { Expression *exp;
3707 Statement *body;
3709 nextToken();
3710 check(TOKlparen);
3711 exp = parseExpression();
3712 check(TOKrparen);
3713 body = parseStatement(PSscope);
3714 s = new WithStatement(loc, exp, body);
3715 break;
3718 case TOKtry:
3719 { Statement *body;
3720 Array *catches = NULL;
3721 Statement *finalbody = NULL;
3723 nextToken();
3724 body = parseStatement(PSscope);
3725 while (token.value == TOKcatch)
3727 Statement *handler;
3728 Catch *c;
3729 Type *t;
3730 Identifier *id;
3731 Loc loc = this->loc;
3733 nextToken();
3734 if (token.value == startBlockTok)
3736 t = NULL;
3737 id = NULL;
3739 else
3741 checkLParen();
3742 id = NULL;
3743 t = parseType(&id);
3744 checkRParen();
3746 handler = parseStatement(PScolon);
3747 c = new Catch(loc, t, id, handler);
3748 if (!catches)
3749 catches = new Array();
3750 catches->push(c);
3753 if (token.value == TOKfinally)
3754 { nextToken();
3755 finalbody = parseStatement(PScolon);
3758 s = body;
3759 if (!catches && !finalbody)
3760 error("catch or finally expected following try");
3761 else
3762 { if (catches)
3763 s = new TryCatchStatement(loc, body, catches);
3764 if (finalbody)
3765 s = new TryFinallyStatement(loc, s, finalbody);
3767 break;
3770 case TOKthrow:
3771 { Expression *exp;
3773 nextToken();
3774 exp = parseExpression();
3775 if (token.value != TOKsemicolon && token.value != TOKendline) {
3776 error("%s expected after throw statement, not '%s'", endToken(), token.toChars());
3778 if (!dltSyntax)
3779 nextToken();
3780 s = new ThrowStatement(loc, exp);
3781 break;
3784 case TOKvolatile:
3785 nextToken();
3786 s = parseStatement(PSsemi | PScurlyscope);
3787 if (!global.params.useDeprecated)
3788 error("volatile statements deprecated; used synchronized statements instead");
3789 s = new VolatileStatement(loc, s);
3790 break;
3792 case TOKasm:
3793 { Statements *statements;
3794 Identifier *label;
3795 Loc labelloc;
3796 Token *toklist;
3797 Token **ptoklist;
3799 // Parse the asm block into a sequence of AsmStatements,
3800 // each AsmStatement is one instruction.
3801 // Separate out labels.
3802 // Defer parsing of AsmStatements until semantic processing.
3804 nextToken();
3805 #if GDC_EXTENDED_ASM_SYNTAX
3806 if (token.value == TOKlparen)
3808 nextToken();
3809 s = parseExtAsm(1);
3810 break;
3812 #endif
3813 check(startBlockTok);
3814 toklist = NULL;
3815 ptoklist = &toklist;
3816 label = NULL;
3817 statements = new Statements();
3818 while (1)
3820 switch (token.value)
3822 case TOKidentifier:
3823 if (!toklist)
3825 // Look ahead to see if it is a label
3826 t = peek(&token);
3827 if (t->value == TOKcolon)
3828 { // It's a label
3829 label = token.ident;
3830 labelloc = this->loc;
3831 nextToken();
3832 nextToken();
3833 continue;
3836 goto Ldefault;
3838 case TOKrcurly:
3839 if (toklist || label)
3841 error("asm statements must end in ';'");
3843 break;
3845 case TOKendline:
3846 case TOKsemicolon:
3847 s = NULL;
3848 if (toklist || label)
3849 { // Create AsmStatement from list of tokens we've saved
3850 s = new AsmStatement(this->loc, toklist);
3851 toklist = NULL;
3852 ptoklist = &toklist;
3853 if (label)
3854 { s = new LabelStatement(labelloc, label, s);
3855 label = NULL;
3857 statements->push(s);
3859 nextToken();
3860 continue;
3862 case TOKeof:
3863 /* { */
3864 error("matching '}' expected, not end of file");
3865 break;
3867 case TOKlparen:
3868 case TOKstring:
3869 // If the first token is a string or '(', parse as extended asm.
3870 if (! toklist)
3872 s = parseExtAsm(0);
3873 statements->push(s);
3874 continue;
3876 // ...else, drop through.
3878 default:
3879 Ldefault:
3880 *ptoklist = new Token();
3881 memcpy(*ptoklist, &token, sizeof(Token));
3882 ptoklist = &(*ptoklist)->next;
3883 *ptoklist = NULL;
3885 nextToken();
3886 continue;
3888 break;
3890 s = new CompoundStatement(loc, statements);
3891 nextToken();
3892 break;
3895 default:
3896 error("found '%s' instead of statement", token.toChars());
3897 goto Lerror;
3899 Lerror:
3900 while (token.value != TOKrcurly &&
3901 token.value != TOKsemicolon &&
3902 token.value != TOKeof)
3903 nextToken();
3904 if (token.value == TOKsemicolon)
3905 nextToken();
3906 s = NULL;
3907 break;
3910 return s;
3913 Statement *Parser::parseExtAsm(int expect_rparen)
3915 Expression * insnTemplate;
3916 Expressions * args = NULL;
3917 Array * argNames = NULL;
3918 Expressions * argConstraints = NULL;
3919 int nOutputArgs = 0;
3920 Expressions * clobbers = NULL;
3921 bool isInputPhase = false; // Output operands first, then input.
3923 insnTemplate = parseExpression();
3924 if (token.value == TOKrparen || token.value == TOKsemicolon)
3925 goto Ldone;
3926 check(TOKcolon);
3927 while (1) {
3928 Expression * arg = NULL;
3929 Identifier * name = NULL;
3930 Expression * constraint = NULL;
3932 switch (token.value)
3934 case TOKsemicolon:
3935 case TOKrparen:
3936 goto Ldone;
3938 case TOKcolon:
3939 nextToken();
3940 goto LnextPhase;
3942 case TOKeof:
3943 error("unterminated statement");
3945 case TOKlbracket:
3946 nextToken();
3947 if (token.value == TOKidentifier)
3949 name = token.ident;
3950 nextToken();
3952 else
3953 error("expected identifier after '['");
3954 check(TOKrbracket);
3955 // drop through
3956 default:
3957 constraint = parsePrimaryExp();
3958 if (constraint->op != TOKstring)
3959 error("expected constant string constraint for operand");
3960 arg = parseAssignExp();
3961 if (! args)
3963 args = new Expressions;
3964 argConstraints = new Expressions;
3965 argNames = new Array;
3967 args->push(arg);
3968 argNames->push(name);
3969 argConstraints->push(constraint);
3970 if (! isInputPhase)
3971 nOutputArgs++;
3973 if (token.value == TOKcomma)
3974 nextToken();
3975 break;
3977 continue;
3978 LnextPhase:
3979 if (! isInputPhase)
3980 isInputPhase = true;
3981 else
3982 break;
3985 while (1)
3987 Expression * clobber;
3989 switch (token.value)
3991 case TOKsemicolon:
3992 case TOKrparen:
3993 goto Ldone;
3995 case TOKeof:
3996 error("unterminated statement");
3998 default:
3999 clobber = parseAssignExp();
4000 if (clobber->op != TOKstring)
4001 error("expected constant string constraint for clobber name");
4002 if (! clobbers)
4003 clobbers = new Expressions;
4004 clobbers->push(clobber);
4006 if (token.value == TOKcomma)
4007 nextToken();
4008 break;
4011 Ldone:
4012 if (expect_rparen)
4013 check(TOKrparen);
4014 else
4015 check(TOKsemicolon);
4017 return new ExtAsmStatement(loc, insnTemplate, args, argNames,
4018 argConstraints, nOutputArgs, clobbers);
4021 void Parser::optionalEndline() {
4022 while (token.value == TOKendline) {
4023 nextToken();
4027 void Parser::check(enum TOK value)
4029 check(loc, value);
4032 void Parser::check(Loc loc, enum TOK value)
4034 if (token.value != value)
4035 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
4036 nextToken();
4039 void Parser::check(enum TOK value, char *string)
4041 if (token.value != value)
4042 error("found '%s' when expecting '%s' following '%s'",
4043 token.toChars(), Token::toChars(value), string);
4044 nextToken();
4047 char *Parser::endToken()
4049 return "semicolon";
4052 char *DltParser::endToken()
4054 return "newline";
4057 void Parser::checkLParen() { check(TOKlparen); }
4058 void Parser::checkRParen() { check(TOKrparen); }
4060 void DltParser::checkLParen() { }
4061 void DltParser::checkRParen() { }
4063 /************************************
4064 * Determine if the scanner is sitting on the start of a declaration.
4065 * Input:
4066 * needId 0 no identifier
4067 * 1 identifier optional
4068 * 2 must have identifier
4071 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
4073 int haveId = 0;
4075 if ((t->value == TOKconst || t->value == TOKinvariant) &&
4076 peek(t)->value != TOKlparen)
4077 { /* const type
4078 * invariant type
4080 t = peek(t);
4083 if (!isBasicType(&t))
4084 return FALSE;
4085 if (!isDeclarator(&t, &haveId, endtok))
4086 return FALSE;
4087 if ( needId == 1 ||
4088 (needId == 0 && !haveId) ||
4089 (needId == 2 && haveId))
4090 { if (pt)
4091 *pt = t;
4092 return TRUE;
4094 else
4095 return FALSE;
4098 int Parser::isBasicType(Token **pt)
4100 // This code parallels parseBasicType()
4101 Token *t = *pt;
4102 Token *t2;
4103 int parens;
4104 int haveId = 0;
4106 switch (t->value)
4108 CASE_BASIC_TYPES:
4109 t = peek(t);
4110 break;
4112 case TOKidentifier:
4113 t = peek(t);
4114 if (t->value == TOKnot)
4116 goto L4;
4118 goto L3;
4119 while (1)
4122 t = peek(t);
4124 if (t->value == TOKdot)
4126 Ldot:
4127 t = peek(t);
4128 if (t->value != TOKidentifier)
4129 goto Lfalse;
4130 t = peek(t);
4131 if (t->value != TOKnot)
4132 goto L3;
4134 t = peek(t);
4135 if (t->value != TOKlparen)
4136 goto Lfalse;
4137 if (!skipParens(t, &t))
4138 goto Lfalse;
4140 else
4141 break;
4143 break;
4145 case TOKdot:
4146 goto Ldot;
4148 case TOKtypeof:
4149 /* typeof(exp).identifier...
4151 t = peek(t);
4152 if (t->value != TOKlparen)
4153 goto Lfalse;
4154 if (!skipParens(t, &t))
4155 goto Lfalse;
4156 goto L2;
4158 case TOKconst:
4159 case TOKinvariant:
4160 // const(type) or invariant(type)
4161 t = peek(t);
4162 if (t->value != TOKlparen)
4163 goto Lfalse;
4164 t = peek(t);
4165 if (!isDeclaration(t, 0, TOKrparen, &t))
4166 goto Lfalse;
4167 t = peek(t);
4168 break;
4170 default:
4171 goto Lfalse;
4173 *pt = t;
4174 return TRUE;
4176 Lfalse:
4177 return FALSE;
4180 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
4181 { // This code parallels parseDeclarator()
4182 Token *t = *pt;
4183 int parens;
4185 //printf("Parser::isDeclarator()\n");
4186 //t->print();
4187 if (t->value == TOKassign)
4188 return FALSE;
4190 while (1)
4192 parens = FALSE;
4193 switch (t->value)
4195 case TOKquestion:
4196 case TOKmul:
4197 case TOKand:
4198 t = peek(t);
4199 continue;
4201 case TOKlbracket:
4202 t = peek(t);
4203 if (t->value == TOKrbracket)
4205 t = peek(t);
4207 else if (isDeclaration(t, 0, TOKrbracket, &t))
4208 { // It's an associative array declaration
4209 t = peek(t);
4211 else
4213 // [ expression ]
4214 // [ expression .. expression ]
4215 if (!isExpression(&t))
4216 return FALSE;
4217 if (t->value == TOKslice)
4218 { t = peek(t);
4219 if (!isExpression(&t))
4220 return FALSE;
4222 if (t->value != TOKrbracket)
4223 return FALSE;
4224 t = peek(t);
4226 continue;
4228 case TOKidentifier:
4229 if (*haveId)
4230 return FALSE;
4231 *haveId = TRUE;
4232 t = peek(t);
4233 break;
4235 case TOKlparen:
4236 t = peek(t);
4238 if (t->value == TOKrparen)
4239 return FALSE; // () is not a declarator
4241 /* Regard ( identifier ) as not a declarator
4242 * BUG: what about ( *identifier ) in
4243 * f(*p)(x);
4244 * where f is a class instance with overloaded () ?
4245 * Should we just disallow C-style function pointer declarations?
4247 if (t->value == TOKidentifier)
4248 { Token *t2 = peek(t);
4249 if (t2->value == TOKrparen)
4250 return FALSE;
4254 if (!isDeclarator(&t, haveId, TOKrparen))
4255 return FALSE;
4256 t = peek(t);
4257 parens = TRUE;
4258 break;
4260 case TOKdelegate:
4261 case TOKfunction:
4262 t = peek(t);
4263 if (!isParameters(&t))
4264 return FALSE;
4265 continue;
4267 break;
4270 while (1)
4272 switch (t->value)
4274 #if CARRAYDECL
4275 case TOKlbracket:
4276 parens = FALSE;
4277 t = peek(t);
4278 if (t->value == TOKrbracket)
4280 t = peek(t);
4282 else if (isDeclaration(t, 0, TOKrbracket, &t))
4283 { // It's an associative array declaration
4284 t = peek(t);
4286 else
4288 // [ expression ]
4289 if (!isExpression(&t))
4290 return FALSE;
4291 if (t->value != TOKrbracket)
4292 return FALSE;
4293 t = peek(t);
4295 continue;
4296 #endif
4298 case TOKlparen:
4299 parens = FALSE;
4300 if (!isParameters(&t))
4301 return FALSE;
4302 if (t->value == TOKconst || t->value == TOKinvariant)
4303 t = peek(t);
4304 continue;
4306 // Valid tokens that follow a declaration
4307 case TOKrparen:
4308 case TOKrbracket:
4309 case TOKassign:
4310 case TOKcomma:
4311 case TOKendline:
4312 case TOKsemicolon:
4313 case TOKlcurly:
4314 case TOKcolon:
4315 case TOKin:
4316 if ((dltSyntax && t->value == TOKlcurly) ||
4317 (!dltSyntax && t->value == TOKcolon)) {
4318 return FALSE;
4321 // The !parens is to disallow unnecessary parentheses
4322 if (!parens && (endtok == TOKreserved || endtok == t->value))
4323 { *pt = t;
4324 return TRUE;
4326 return FALSE;
4328 default:
4329 return FALSE;
4335 int Parser::isParameters(Token **pt)
4336 { // This code parallels parseParameters()
4337 Token *t = *pt;
4338 int tmp;
4340 //printf("isParameters()\n");
4341 if (t->value != TOKlparen)
4342 return FALSE;
4344 t = peek(t);
4345 for (;1; t = peek(t))
4347 switch (t->value)
4349 case TOKrparen:
4350 break;
4352 case TOKdotdotdot:
4353 t = peek(t);
4354 break;
4356 case TOKin:
4357 case TOKout:
4358 case TOKinout:
4359 case TOKref:
4360 case TOKlazy:
4361 case TOKconst:
4362 case TOKinvariant:
4363 case TOKfinal:
4364 case TOKstatic:
4365 continue;
4367 default:
4368 if (!isBasicType(&t))
4369 return FALSE;
4370 tmp = FALSE;
4371 if (t->value != TOKdotdotdot &&
4372 !isDeclarator(&t, &tmp, TOKreserved))
4373 return FALSE;
4374 if (t->value == TOKassign)
4375 { t = peek(t);
4376 if (!isExpression(&t))
4377 return FALSE;
4379 if (t->value == TOKdotdotdot)
4381 t = peek(t);
4382 break;
4384 if (t->value == TOKcomma)
4386 continue;
4388 break;
4390 break;
4392 if (t->value != TOKrparen)
4393 return FALSE;
4394 t = peek(t);
4395 *pt = t;
4396 return TRUE;
4399 int Parser::isExpression(Token **pt)
4401 // This is supposed to determine if something is an expression.
4402 // What it actually does is scan until a closing right bracket
4403 // is found.
4405 Token *t = *pt;
4406 int brnest = 0;
4407 int panest = 0;
4408 int curlynest = 0;
4410 for (;; t = peek(t))
4412 switch (t->value)
4414 case TOKlbracket:
4415 brnest++;
4416 continue;
4418 case TOKrbracket:
4419 if (--brnest >= 0)
4420 continue;
4421 break;
4423 case TOKlparen:
4424 panest++;
4425 continue;
4427 case TOKcomma:
4428 if (brnest || panest)
4429 continue;
4430 break;
4432 case TOKrparen:
4433 if (--panest >= 0)
4434 continue;
4435 break;
4437 case TOKlcurly:
4438 curlynest++;
4439 continue;
4441 case TOKrcurly:
4442 if (--curlynest >= 0)
4443 continue;
4444 return FALSE;
4446 case TOKslice:
4447 if (brnest)
4448 continue;
4449 break;
4451 case TOKsemicolon:
4452 if (curlynest)
4453 continue;
4454 return FALSE;
4456 case TOKeof:
4457 return FALSE;
4459 default:
4460 continue;
4462 break;
4465 *pt = t;
4466 return TRUE;
4469 /**********************************************
4470 * Skip over
4471 * instance foo.bar(parameters...)
4472 * Output:
4473 * if (pt), *pt is set to the token following the closing )
4474 * Returns:
4475 * 1 it's valid instance syntax
4476 * 0 invalid instance syntax
4479 int Parser::isTemplateInstance(Token *t, Token **pt)
4481 t = peek(t);
4482 if (t->value != TOKdot)
4484 if (t->value != TOKidentifier)
4485 goto Lfalse;
4486 t = peek(t);
4488 while (t->value == TOKdot)
4490 t = peek(t);
4491 if (t->value != TOKidentifier)
4492 goto Lfalse;
4493 t = peek(t);
4495 if (t->value != TOKlparen)
4496 goto Lfalse;
4498 // Skip over the template arguments
4499 while (1)
4501 while (1)
4503 t = peek(t);
4504 switch (t->value)
4506 case TOKlparen:
4507 if (!skipParens(t, &t))
4508 goto Lfalse;
4509 continue;
4510 case TOKrparen:
4511 break;
4512 case TOKcomma:
4513 break;
4514 case TOKeof:
4515 case TOKsemicolon:
4516 goto Lfalse;
4517 default:
4518 continue;
4520 break;
4523 if (t->value != TOKcomma)
4524 break;
4526 if (t->value != TOKrparen)
4527 goto Lfalse;
4528 t = peek(t);
4529 if (pt)
4530 *pt = t;
4531 return 1;
4533 Lfalse:
4534 return 0;
4537 /*******************************************
4538 * Skip parens, brackets.
4539 * Input:
4540 * t is on opening (
4541 * Output:
4542 * *pt is set to closing token, which is ')' on success
4543 * Returns:
4544 * !=0 successful
4545 * 0 some parsing error
4548 int Parser::skipParens(Token *t, Token **pt)
4550 int parens = 0;
4552 while (1)
4554 switch (t->value)
4556 case TOKlparen:
4557 parens++;
4558 break;
4560 case TOKrparen:
4561 parens--;
4562 if (parens < 0)
4563 goto Lfalse;
4564 if (parens == 0)
4565 goto Ldone;
4566 break;
4568 case TOKeof:
4569 case TOKsemicolon:
4570 goto Lfalse;
4572 default:
4573 break;
4575 t = peek(t);
4578 Ldone:
4579 if (*pt)
4580 *pt = t;
4581 return 1;
4583 Lfalse:
4584 return 0;
4587 /********************************* Expression Parser ***************************/
4589 Expression *Parser::parsePrimaryExp()
4590 { Expression *e;
4591 Type *t;
4592 Identifier *id;
4593 enum TOK save;
4594 Loc loc = this->loc;
4596 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4597 switch (token.value)
4599 case TOKidentifier:
4600 id = token.ident;
4601 nextToken();
4602 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4603 { // identifier!(template-argument-list)
4604 TemplateInstance *tempinst;
4606 tempinst = new TemplateInstance(loc, id);
4607 nextToken();
4608 tempinst->tiargs = parseTemplateArgumentList();
4609 e = new ScopeExp(loc, tempinst);
4611 else
4612 e = new IdentifierExp(loc, id);
4613 break;
4615 case TOKdollar:
4616 if (!inBrackets)
4617 error("'$' is valid only inside [] of index or slice");
4618 e = new DollarExp(loc);
4619 nextToken();
4620 break;
4622 case TOKdot:
4623 // Signal global scope '.' operator with "" identifier
4624 e = new IdentifierExp(loc, Id::empty);
4625 break;
4627 case TOKthis:
4628 e = new ThisExp(loc);
4629 nextToken();
4630 break;
4632 case TOKsuper:
4633 e = new SuperExp(loc);
4634 nextToken();
4635 break;
4637 case TOKint32v:
4638 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
4639 nextToken();
4640 break;
4642 case TOKuns32v:
4643 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
4644 nextToken();
4645 break;
4647 case TOKint64v:
4648 e = new IntegerExp(loc, token.int64value, Type::tint64);
4649 nextToken();
4650 break;
4652 case TOKuns64v:
4653 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4654 nextToken();
4655 break;
4657 case TOKfloat32v:
4658 e = new RealExp(loc, token.float80value, Type::tfloat32);
4659 nextToken();
4660 break;
4662 case TOKfloat64v:
4663 e = new RealExp(loc, token.float80value, Type::tfloat64);
4664 nextToken();
4665 break;
4667 case TOKfloat80v:
4668 e = new RealExp(loc, token.float80value, Type::tfloat80);
4669 nextToken();
4670 break;
4672 case TOKimaginary32v:
4673 e = new RealExp(loc, token.float80value, Type::timaginary32);
4674 nextToken();
4675 break;
4677 case TOKimaginary64v:
4678 e = new RealExp(loc, token.float80value, Type::timaginary64);
4679 nextToken();
4680 break;
4682 case TOKimaginary80v:
4683 e = new RealExp(loc, token.float80value, Type::timaginary80);
4684 nextToken();
4685 break;
4687 case TOKnull:
4688 e = new NullExp(loc);
4689 ((NullExp *) e)->dUnchecked = !dltSyntax;
4690 nextToken();
4691 break;
4693 case TOKfile:
4694 { char *s = loc.filename ? loc.filename : mod->ident->toChars();
4695 e = new StringExp(loc, s, strlen(s), 0);
4696 nextToken();
4697 break;
4700 case TOKline:
4701 e = new IntegerExp(loc, loc.linnum, Type::tint32);
4702 nextToken();
4703 break;
4705 case TOKtrue:
4706 e = new IntegerExp(loc, 1, Type::tbool);
4707 nextToken();
4708 break;
4710 case TOKfalse:
4711 e = new IntegerExp(loc, 0, Type::tbool);
4712 nextToken();
4713 break;
4715 case TOKcharv:
4716 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tchar);
4717 nextToken();
4718 break;
4720 case TOKwcharv:
4721 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::twchar);
4722 nextToken();
4723 break;
4725 case TOKdcharv:
4726 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
4727 nextToken();
4728 break;
4730 case TOKstring:
4731 { unsigned char *s;
4732 unsigned len;
4733 unsigned char postfix;
4735 // cat adjacent strings
4736 s = token.ustring;
4737 len = token.len;
4738 postfix = token.postfix;
4739 while (1)
4741 nextToken();
4742 if (token.value == TOKstring)
4743 { unsigned len1;
4744 unsigned len2;
4745 unsigned char *s2;
4747 if (token.postfix)
4748 { if (token.postfix != postfix)
4749 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4750 postfix = token.postfix;
4753 len1 = len;
4754 len2 = token.len;
4755 len = len1 + len2;
4756 s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
4757 memcpy(s2, s, len1 * sizeof(unsigned char));
4758 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
4759 s = s2;
4761 else
4762 break;
4764 e = new StringExp(loc, s, len, postfix);
4765 break;
4768 CASE_BASIC_TYPES_X(t):
4769 nextToken();
4771 check(TOKdot, t->toChars());
4772 if (token.value != TOKidentifier)
4773 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
4774 goto Lerr;
4776 e = new TypeDotIdExp(loc, t, token.ident);
4777 nextToken();
4778 break;
4780 case TOKtypeof:
4782 t = parseTypeof();
4783 if (token.value == TOKdot)
4784 goto L1;
4785 e = new TypeExp(loc, t);
4786 break;
4789 case TOKtypeid:
4790 { Type *t;
4792 nextToken();
4793 check(TOKlparen, "typeid");
4794 t = parseType(); // ( type )
4795 check(TOKrparen);
4796 e = new TypeidExp(loc, t);
4797 break;
4800 case TOKtraits:
4801 { /* __traits(identifier, args...)
4803 Identifier *ident;
4804 Objects *args = NULL;
4806 nextToken();
4807 check(TOKlparen);
4808 if (token.value != TOKidentifier)
4809 { error("__traits(identifier, args...) expected");
4810 goto Lerr;
4812 ident = token.ident;
4813 nextToken();
4814 if (token.value == TOKcomma)
4815 args = parseTemplateArgumentList2(); // __traits(identifier, args...)
4816 else
4817 check(TOKrparen); // __traits(identifier)
4819 e = new TraitsExp(loc, ident, args);
4820 break;
4823 case TOKis:
4824 { Type *targ;
4825 Identifier *ident = NULL;
4826 Type *tspec = NULL;
4827 enum TOK tok = TOKreserved;
4828 enum TOK tok2 = TOKreserved;
4829 TemplateParameters *tpl = NULL;
4830 Loc loc = this->loc;
4832 nextToken();
4833 if (token.value == TOKlparen)
4835 nextToken();
4836 targ = parseType(&ident);
4837 if (token.value == TOKcolon || token.value == TOKequal)
4839 tok = token.value;
4840 nextToken();
4841 if (tok == TOKequal &&
4842 (token.value == TOKtypedef ||
4843 token.value == TOKstruct ||
4844 token.value == TOKunion ||
4845 token.value == TOKclass ||
4846 token.value == TOKsuper ||
4847 token.value == TOKenum ||
4848 token.value == TOKinterface ||
4849 token.value == TOKconst && peek(&token)->value == TOKrparen ||
4850 token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
4851 token.value == TOKfunction ||
4852 token.value == TOKdelegate ||
4853 token.value == TOKreturn))
4855 tok2 = token.value;
4856 nextToken();
4858 else
4860 tspec = parseType();
4863 if (ident && tspec)
4865 if (token.value == TOKcomma)
4866 tpl = parseTemplateParameterList(1);
4867 else
4868 { tpl = new TemplateParameters();
4869 check(TOKrparen);
4871 TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
4872 tpl->insert(0, tp);
4874 else
4875 check(TOKrparen);
4877 else
4878 { error("(type identifier : specialization) expected following is");
4879 goto Lerr;
4881 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
4882 break;
4885 case TOKassert:
4886 { Expression *msg = NULL;
4888 nextToken();
4890 checkLParen();
4891 e = parseAssignExp();
4892 if (token.value == (dltSyntax ? TOKelse : TOKcomma))
4893 { nextToken();
4894 msg = parseAssignExp();
4895 } else if (token.value == TOKcomma)
4896 error("Suspicious comma after assert; try 'else' instead");
4897 checkRParen();
4899 e = new AssertExp(loc, e, msg);
4900 break;
4903 case TOKmixin:
4905 nextToken();
4906 check(TOKlparen, "mixin");
4907 e = parseAssignExp();
4908 check(TOKrparen);
4909 e = new CompileExp(loc, e);
4910 break;
4913 case TOKimport:
4915 nextToken();
4916 check(TOKlparen, "import");
4917 e = parseAssignExp();
4918 check(TOKrparen);
4919 e = new FileExp(loc, e);
4920 break;
4923 case TOKlparen:
4924 if (peekPastParen(&token)->value == startBlockTok)
4925 { // (arguments) { statements... }
4926 save = TOKdelegate;
4927 goto case_delegate;
4929 // ( expression )
4930 nextToken();
4931 e = parseExpression();
4932 check(loc, TOKrparen);
4933 break;
4935 case TOKlbracket:
4936 { /* Parse array literals and associative array literals:
4937 * [ value, value, value ... ]
4938 * [ key:value, key:value, key:value ... ]
4940 Expressions *values = new Expressions();
4941 Expressions *keys = NULL;
4943 nextToken();
4944 if (token.value != TOKrbracket)
4946 while (1)
4948 Expression *e = parseAssignExp();
4949 if (token.value == TOKcolon && (keys || values->dim == 0))
4950 { nextToken();
4951 if (!keys)
4952 keys = new Expressions();
4953 keys->push(e);
4954 e = parseAssignExp();
4956 else if (keys)
4957 { error("'key:value' expected for associative array literal");
4958 delete keys;
4959 keys = NULL;
4961 values->push(e);
4962 if (token.value == TOKrbracket)
4963 break;
4964 check(TOKcomma);
4967 check(TOKrbracket);
4969 if (keys)
4970 e = new AssocArrayLiteralExp(loc, keys, values);
4971 else
4972 e = new ArrayLiteralExp(loc, values);
4973 break;
4976 case TOKlcurly:
4977 // { statements... }
4978 save = TOKdelegate;
4979 goto case_delegate;
4981 case TOKfunction:
4982 case TOKdelegate:
4983 save = token.value;
4984 nextToken();
4985 case_delegate:
4987 /* function type(parameters) { body }
4988 * delegate type(parameters) { body }
4989 * (parameters) { body }
4990 * { body }
4992 Arguments *arguments;
4993 int varargs;
4994 FuncLiteralDeclaration *fd;
4995 Type *t;
4996 bool isnothrow = false;
4997 bool ispure = false;
4999 if (token.value == startBlockTok)
5001 t = NULL;
5002 varargs = 0;
5003 arguments = new Arguments();
5005 else
5007 if (token.value == TOKlparen)
5008 t = NULL;
5009 else
5011 t = parseBasicType();
5012 t = parseBasicType2(t); // function return type
5014 arguments = parseParameters(&varargs);
5015 while (1)
5017 if (token.value == TOKpure)
5018 ispure = true;
5019 else if (token.value == TOKnothrow)
5020 isnothrow = true;
5021 else
5022 break;
5023 nextToken();
5026 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
5027 tf->ispure = ispure;
5028 tf->isnothrow = isnothrow;
5029 fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
5030 if (dltSyntax)
5032 check(TOKcolon);
5033 if (!nesting)
5034 indent--; // This colon doesn't start a new indent level
5035 fd->fbody = new ReturnStatement(loc, parseAssignExp());
5036 fd->endloc = loc;
5038 else
5040 parseContracts(fd);
5042 e = new FuncExp(loc, fd);
5043 break;
5046 default:
5047 error("expression expected, not '%s'", token.toChars());
5048 Lerr:
5049 // Anything for e, as long as it's not NULL
5050 e = new IntegerExp(loc, 0, Type::tint32);
5051 nextToken();
5052 break;
5054 return parsePostExp(e);
5057 Expression *Parser::parsePostExp(Expression *e)
5059 Loc loc;
5061 while (1)
5063 loc = this->loc;
5064 switch (token.value)
5066 case TOKdot:
5067 nextToken();
5068 if (token.value == TOKidentifier)
5069 { Identifier *id = token.ident;
5071 nextToken();
5072 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
5073 { // identifier!(template-argument-list)
5074 TemplateInstance *tempinst;
5076 tempinst = new TemplateInstance(loc, id);
5077 nextToken();
5078 tempinst->tiargs = parseTemplateArgumentList();
5079 e = new DotTemplateInstanceExp(loc, e, tempinst);
5081 else
5082 e = new DotIdExp(loc, e, id);
5083 continue;
5085 else if (token.value == TOKnew)
5087 e = parseNewExp(e);
5088 continue;
5090 else
5091 error("identifier expected following '.', not '%s'", token.toChars());
5092 break;
5094 case TOKplusplus:
5095 e = new PostExp(TOKplusplus, loc, e);
5096 break;
5098 case TOKminusminus:
5099 e = new PostExp(TOKminusminus, loc, e);
5100 break;
5102 case TOKlparen:
5103 e = new CallExp(loc, e, parseArguments());
5104 continue;
5106 case TOKlbracket:
5107 { // array dereferences:
5108 // array[index]
5109 // array[]
5110 // array[lwr .. upr]
5111 Expression *index;
5112 Expression *upr;
5114 inBrackets++;
5115 nextToken();
5116 if (token.value == TOKrbracket)
5117 { // array[]
5118 e = new SliceExp(loc, e, NULL, NULL);
5119 nextToken();
5121 else
5123 index = parseAssignExp();
5124 if (token.value == TOKslice)
5125 { // array[lwr .. upr]
5126 nextToken();
5127 upr = parseAssignExp();
5128 e = new SliceExp(loc, e, index, upr);
5130 else
5131 { // array[index, i2, i3, i4, ...]
5132 Expressions *arguments = new Expressions();
5133 arguments->push(index);
5134 if (token.value == TOKcomma)
5136 nextToken();
5137 while (1)
5138 { Expression *arg;
5140 arg = parseAssignExp();
5141 arguments->push(arg);
5142 if (token.value == TOKrbracket)
5143 break;
5144 check(TOKcomma);
5147 e = new ArrayExp(loc, e, arguments);
5149 check(TOKrbracket);
5150 inBrackets--;
5152 continue;
5155 default:
5156 return e;
5158 nextToken();
5162 Expression *Parser::parseUnaryExp()
5163 { Expression *e;
5164 Loc loc = this->loc;
5166 switch (token.value)
5168 case TOKand:
5169 nextToken();
5170 e = parseUnaryExp();
5171 e = new AddrExp(loc, e);
5172 break;
5174 case TOKplusplus:
5175 nextToken();
5176 e = parseUnaryExp();
5177 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5178 break;
5180 case TOKminusminus:
5181 nextToken();
5182 e = parseUnaryExp();
5183 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5184 break;
5186 case TOKmul:
5187 nextToken();
5188 e = parseUnaryExp();
5189 e = new PtrExp(loc, e);
5190 break;
5192 case TOKmin:
5193 nextToken();
5194 e = parseUnaryExp();
5195 e = new NegExp(loc, e);
5196 break;
5198 case TOKadd:
5199 nextToken();
5200 e = parseUnaryExp();
5201 e = new UAddExp(loc, e);
5202 break;
5204 case TOKnot:
5205 nextToken();
5206 e = parseUnaryExp();
5207 e = new NotExp(loc, e);
5208 break;
5210 case TOKtilde:
5211 nextToken();
5212 e = parseUnaryExp();
5213 e = new ComExp(loc, e);
5214 break;
5216 case TOKdelete:
5217 nextToken();
5218 e = parseUnaryExp();
5219 e = new DeleteExp(loc, e);
5220 break;
5222 case TOKnew:
5223 e = parseNewExp(NULL);
5224 break;
5226 case TOKcast: // cast(type) expression
5227 { Type *t;
5229 nextToken();
5230 check(TOKlparen);
5231 /* Look for cast(const) and cast(invariant)
5233 if ((token.value == TOKconst || token.value == TOKinvariant) &&
5234 peek(&token)->value == TOKrparen)
5235 { enum TOK tok = token.value;
5236 nextToken();
5237 nextToken();
5238 e = parseUnaryExp();
5239 e = new CastExp(loc, e, tok);
5241 else
5243 t = parseType(); // ( type )
5244 check(TOKrparen);
5245 e = parseUnaryExp();
5246 e = new CastExp(loc, e, t);
5248 break;
5251 case TOKlparen:
5252 { Token *tk;
5254 tk = peek(&token);
5255 #if CCASTSYNTAX
5256 // If cast
5257 if (isDeclaration(tk, 0, TOKrparen, &tk))
5259 tk = peek(tk); // skip over right parenthesis
5260 switch (tk->value)
5262 case TOKdot:
5263 case TOKplusplus:
5264 case TOKminusminus:
5265 case TOKnot:
5266 case TOKdelete:
5267 case TOKnew:
5268 case TOKlparen:
5269 case TOKidentifier:
5270 case TOKthis:
5271 case TOKsuper:
5272 case TOKint32v:
5273 case TOKuns32v:
5274 case TOKint64v:
5275 case TOKuns64v:
5276 case TOKfloat32v:
5277 case TOKfloat64v:
5278 case TOKfloat80v:
5279 case TOKimaginary32v:
5280 case TOKimaginary64v:
5281 case TOKimaginary80v:
5282 case TOKnull:
5283 case TOKtrue:
5284 case TOKfalse:
5285 case TOKcharv:
5286 case TOKwcharv:
5287 case TOKdcharv:
5288 case TOKstring:
5289 #if 0
5290 case TOKtilde:
5291 case TOKand:
5292 case TOKmul:
5293 case TOKmin:
5294 case TOKadd:
5295 #endif
5296 case TOKfunction:
5297 case TOKdelegate:
5298 case TOKtypeof:
5299 case TOKfile:
5300 case TOKline:
5301 CASE_BASIC_TYPES: // (type)int.size
5302 { // (type) una_exp
5303 Type *t;
5305 nextToken();
5306 t = parseType();
5307 check(TOKrparen);
5309 // if .identifier
5310 if (token.value == TOKdot)
5312 nextToken();
5313 if (token.value != TOKidentifier)
5314 { error("Identifier expected following (type).");
5315 return NULL;
5317 e = new TypeDotIdExp(loc, t, token.ident);
5318 nextToken();
5319 e = parsePostExp(e);
5321 else
5323 e = parseUnaryExp();
5324 e = new CastExp(loc, e, t);
5325 error("C style cast illegal, use %s", e->toChars());
5327 return e;
5331 #endif
5332 e = parsePrimaryExp();
5333 break;
5335 default:
5336 e = parsePrimaryExp();
5337 break;
5339 assert(e);
5340 return e;
5343 Expression *Parser::parseMulExp()
5344 { Expression *e;
5345 Expression *e2;
5346 Loc loc = this->loc;
5348 e = parseUnaryExp();
5349 while (1)
5351 switch (token.value)
5353 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5354 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5355 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5357 default:
5358 break;
5360 break;
5362 return e;
5365 Expression *Parser::parseAddExp()
5366 { Expression *e;
5367 Expression *e2;
5368 Loc loc = this->loc;
5370 e = parseMulExp();
5371 while (1)
5373 switch (token.value)
5375 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5376 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5377 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5379 default:
5380 break;
5382 break;
5384 return e;
5387 Expression *Parser::parseShiftExp()
5388 { Expression *e;
5389 Expression *e2;
5390 Loc loc = this->loc;
5392 e = parseAddExp();
5393 while (1)
5395 switch (token.value)
5397 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5398 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5399 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5401 default:
5402 break;
5404 break;
5406 return e;
5409 Expression *Parser::parseRelExp()
5410 { Expression *e;
5411 Expression *e2;
5412 enum TOK op;
5413 Loc loc = this->loc;
5415 e = parseShiftExp();
5416 while (1)
5418 switch (token.value)
5420 case TOKlt:
5421 case TOKle:
5422 case TOKgt:
5423 case TOKge:
5424 case TOKunord:
5425 case TOKlg:
5426 case TOKleg:
5427 case TOKule:
5428 case TOKul:
5429 case TOKuge:
5430 case TOKug:
5431 case TOKue:
5432 op = token.value;
5433 nextToken();
5434 e2 = parseShiftExp();
5435 e = new CmpExp(op, loc, e, e2);
5436 continue;
5438 case TOKin:
5439 nextToken();
5440 e2 = parseShiftExp();
5441 e = new InExp(loc, e, e2);
5442 continue;
5444 default:
5445 break;
5447 break;
5449 return e;
5452 Expression *Parser::parseEqualExp()
5453 { Expression *e;
5454 Expression *e2;
5455 Token *t;
5456 Loc loc = this->loc;
5458 e = parseRelExp();
5459 while (1)
5460 { enum TOK value = token.value;
5462 switch (value)
5464 case TOKequal:
5465 case TOKnotequal:
5466 nextToken();
5467 e2 = parseRelExp();
5468 e = new EqualExp(value, loc, e, e2);
5469 continue;
5471 case TOKidentity:
5472 error("'===' is no longer legal, use 'is' instead");
5473 goto L1;
5475 case TOKnotidentity:
5476 error("'!==' is no longer legal, use '!is' instead");
5477 goto L1;
5479 case TOKis:
5480 value = TOKidentity;
5481 error("TOKis");
5482 if (dltSyntax)
5484 t = peek(&token);
5485 error("next: %s", t->toChars());
5486 if (t->value == TOKnot)
5488 // X is not Y
5489 value = TOKnotidentity;
5490 nextToken();
5493 goto L1;
5495 case TOKnot:
5496 // Attempt to identify '!is'
5497 t = peek(&token);
5498 if (t->value != TOKis)
5499 break;
5500 nextToken();
5501 value = TOKnotidentity;
5502 goto L1;
5505 nextToken();
5506 e2 = parseRelExp();
5507 e = new IdentityExp(value, loc, e, e2);
5508 continue;
5510 default:
5511 break;
5513 break;
5515 return e;
5518 Expression *Parser::parseCmpExp()
5519 { Expression *e;
5520 Expression *e2;
5521 Token *t;
5522 Loc loc = this->loc;
5524 e = parseShiftExp();
5525 enum TOK op = token.value;
5527 switch (op)
5529 case TOKequal:
5530 case TOKnotequal:
5531 nextToken();
5532 e2 = parseShiftExp();
5533 e = new EqualExp(op, loc, e, e2);
5534 break;
5536 case TOKis:
5537 op = TOKidentity;
5538 if (dltSyntax)
5540 t = peek(&token);
5541 if (t->value == TOKnot)
5543 // X is not Y
5544 op = TOKnotidentity;
5545 nextToken();
5548 goto L1;
5550 case TOKnot:
5551 // Attempt to identify '!is'
5552 t = peek(&token);
5553 if (t->value != TOKis)
5554 break;
5555 nextToken();
5556 op = TOKnotidentity;
5557 goto L1;
5560 nextToken();
5561 e2 = parseShiftExp();
5562 e = new IdentityExp(op, loc, e, e2);
5563 break;
5565 case TOKlt:
5566 case TOKle:
5567 case TOKgt:
5568 case TOKge:
5569 case TOKunord:
5570 case TOKlg:
5571 case TOKleg:
5572 case TOKule:
5573 case TOKul:
5574 case TOKuge:
5575 case TOKug:
5576 case TOKue:
5577 nextToken();
5578 e2 = parseShiftExp();
5579 e = new CmpExp(op, loc, e, e2);
5580 break;
5582 case TOKin:
5583 nextToken();
5584 e2 = parseShiftExp();
5585 e = new InExp(loc, e, e2);
5586 break;
5588 default:
5589 break;
5591 return e;
5594 Expression *Parser::parseAndExp()
5595 { Expression *e;
5596 Expression *e2;
5597 Loc loc = this->loc;
5599 if (global.params.Dversion == 1)
5601 e = parseEqualExp();
5602 while (token.value == TOKand)
5604 nextToken();
5605 e2 = parseEqualExp();
5606 e = new AndExp(loc,e,e2);
5607 loc = this->loc;
5610 else
5612 e = parseCmpExp();
5613 while (token.value == TOKand)
5615 nextToken();
5616 e2 = parseCmpExp();
5617 e = new AndExp(loc,e,e2);
5618 loc = this->loc;
5621 return e;
5624 Expression *Parser::parseXorExp()
5625 { Expression *e;
5626 Expression *e2;
5627 Loc loc = this->loc;
5629 e = parseAndExp();
5630 while (token.value == TOKxor)
5632 nextToken();
5633 e2 = parseAndExp();
5634 e = new XorExp(loc, e, e2);
5636 return e;
5639 Expression *Parser::parseOrExp()
5640 { Expression *e;
5641 Expression *e2;
5642 Loc loc = this->loc;
5644 e = parseXorExp();
5645 while (token.value == TOKor)
5647 nextToken();
5648 e2 = parseXorExp();
5649 e = new OrExp(loc, e, e2);
5651 return e;
5654 Expression *Parser::parseAndAndExp()
5655 { Expression *e;
5656 Expression *e2;
5657 Loc loc = this->loc;
5659 e = parseOrExp();
5660 while (token.value == TOKandand)
5662 nextToken();
5663 e2 = parseOrExp();
5664 e = new AndAndExp(loc, e, e2);
5666 return e;
5669 Expression *Parser::parseOrOrExp()
5670 { Expression *e;
5671 Expression *e2;
5672 Loc loc = this->loc;
5674 e = parseAndAndExp();
5675 while (token.value == TOKoror)
5677 nextToken();
5678 e2 = parseAndAndExp();
5679 e = new OrOrExp(loc, e, e2);
5681 return e;
5684 Expression *Parser::parseCondExp()
5685 { Expression *e;
5686 Expression *e1;
5687 Expression *e2;
5688 Loc loc = this->loc;
5690 e = parseOrOrExp();
5691 if (token.value == TOKquestion)
5693 nextToken();
5694 e1 = parseExpression();
5695 check(TOKcolon);
5696 e2 = parseCondExp();
5697 e = new CondExp(loc, e, e1, e2);
5699 return e;
5702 Expression *DltParser::parseCondExp()
5703 { Expression *e;
5704 Expression *e1;
5705 Expression *e2;
5706 Loc loc = this->loc;
5708 e = parseOrOrExp();
5709 if (token.value == TOKif)
5711 nextToken();
5712 e1 = parseExpression();
5713 check(TOKelse);
5714 e2 = parseCondExp();
5715 e = new CondExp(loc, e1, e, e2);
5717 return e;
5720 Expression *Parser::parseAssignExp()
5721 { Expression *e;
5722 Expression *e2;
5723 Loc loc;
5725 e = parseCondExp();
5726 while (1)
5728 loc = this->loc;
5729 switch (token.value)
5731 #define X(tok,ector) \
5732 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5734 X(TOKassign, AssignExp);
5735 X(TOKaddass, AddAssignExp);
5736 X(TOKminass, MinAssignExp);
5737 X(TOKmulass, MulAssignExp);
5738 X(TOKdivass, DivAssignExp);
5739 X(TOKmodass, ModAssignExp);
5740 X(TOKandass, AndAssignExp);
5741 X(TOKorass, OrAssignExp);
5742 X(TOKxorass, XorAssignExp);
5743 X(TOKshlass, ShlAssignExp);
5744 X(TOKshrass, ShrAssignExp);
5745 X(TOKushrass, UshrAssignExp);
5746 X(TOKcatass, CatAssignExp);
5748 #undef X
5749 default:
5750 break;
5752 break;
5754 return e;
5757 Expression *Parser::parseExpression()
5758 { Expression *e;
5759 Expression *e2;
5760 Loc loc = this->loc;
5762 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5763 e = parseAssignExp();
5764 while (token.value == TOKcomma)
5766 nextToken();
5767 e2 = parseAssignExp();
5768 e = new CommaExp(loc, e, e2);
5769 loc = this->loc;
5771 return e;
5775 /*************************
5776 * Collect argument list.
5777 * Assume current token is '(' or '['.
5780 Expressions *Parser::parseArguments()
5781 { // function call
5782 Expressions *arguments;
5783 Expression *arg;
5784 enum TOK endtok;
5786 arguments = new Expressions();
5787 if (token.value == TOKlbracket)
5788 endtok = TOKrbracket;
5789 else
5790 endtok = TOKrparen;
5793 nextToken();
5794 if (token.value != endtok)
5796 while (1)
5798 arg = parseAssignExp();
5799 arguments->push(arg);
5800 if (token.value == endtok)
5801 break;
5802 check(TOKcomma);
5805 check(endtok);
5807 return arguments;
5810 /*******************************************
5813 Expression *Parser::parseNewExp(Expression *thisexp)
5814 { Type *t;
5815 Expressions *newargs;
5816 Expressions *arguments = NULL;
5817 Expression *e;
5818 Loc loc = this->loc;
5820 nextToken();
5821 newargs = NULL;
5822 if (token.value == TOKlparen)
5824 newargs = parseArguments();
5827 // An anonymous nested class starts with "class"
5828 if (token.value == TOKclass)
5830 nextToken();
5832 if (dltSyntax)
5833 error("no anonymous classes in Delight");
5835 if (token.value == TOKlparen)
5836 arguments = parseArguments();
5838 BaseClasses *baseclasses = NULL;
5839 if (token.value != TOKlcurly)
5840 baseclasses = parseBaseClasses();
5842 Identifier *id = NULL;
5843 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, linkage);
5845 if (token.value != startBlockTok)
5846 { error("{ members } expected for anonymous class");
5847 cd->members = NULL;
5849 else
5851 nextToken();
5852 Array *decl = parseDeclDefs(0);
5853 if (token.value != TOKrcurly)
5854 error("class member expected");
5855 nextToken();
5856 cd->members = decl;
5859 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5861 return e;
5864 t = parseBasicType();
5865 t = parseBasicType2(t);
5866 if (t->ty == Taarray)
5867 { TypeAArray *taa = (TypeAArray *)t;
5868 Type *index = taa->index;
5870 Expression *e = index->toExpression();
5871 if (e)
5872 { arguments = new Expressions();
5873 arguments->push(e);
5874 t = new TypeDArray(taa->next);
5876 else
5878 error("need size of rightmost array, not type %s", index->toChars());
5879 return new NullExp(loc);
5882 else if (t->ty == Tsarray)
5884 TypeSArray *tsa = (TypeSArray *)t;
5885 Expression *e = tsa->dim;
5887 arguments = new Expressions();
5888 arguments->push(e);
5889 t = new TypeDArray(tsa->next);
5891 else if (token.value == TOKlparen)
5893 arguments = parseArguments();
5895 e = new NewExp(loc, thisexp, newargs, t, arguments);
5896 return e;
5899 /**********************************************
5902 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
5904 s->addComment(combineComments(blockComment, token.lineComment));
5908 /********************************* ***************************/