Modular handling of externals
[delight/core.git] / dmd2 / parse.c
blob5abaa52ae30c6a9f503340e6733c18aaf680ab38
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("no global variables (%s) allowed in Delight; "
145 "try const, or put it in a class", d->toChars());
150 return decldefs;
152 Lerr:
153 while (token.value != TOKsemicolon && token.value != TOKeof)
154 nextToken();
155 nextToken();
156 return new Array();
159 Array *Parser::parseDeclDefs(int once)
160 { Dsymbol *s;
161 Array *decldefs;
162 Array *a;
163 Array *aelse;
164 enum PROT prot;
165 unsigned stc;
166 unsigned storageClass;
167 Condition *condition;
168 unsigned char *comment;
170 //printf("Parser::parseDeclDefs()\n");
171 decldefs = new Array();
174 comment = token.blockComment;
175 storageClass = 0;
176 switch (token.value)
178 case TOKendline:
179 nextToken();
180 continue;
181 case TOKenum:
182 { /* Determine if this is a manifest constant declaration,
183 * or a conventional enum.
185 Token *t = peek(&token);
186 if (t->value == TOKlcurly || t->value == TOKcolon)
187 s = parseEnum();
188 else if (t->value != TOKidentifier)
189 goto Ldeclaration;
190 else
192 t = peek(t);
193 if (t->value == TOKlcurly || t->value == TOKcolon ||
194 t->value == TOKsemicolon)
195 s = parseEnum();
196 else
197 goto Ldeclaration;
199 break;
202 case TOKstruct:
203 case TOKunion:
204 case TOKclass:
205 case TOKinterface:
206 s = parseAggregate();
207 break;
209 case TOKimport:
210 s = parseImport(decldefs, 0);
211 break;
213 case TOKtemplate:
214 s = (Dsymbol *)parseTemplateDeclaration();
215 break;
217 case TOKmixin:
218 { Loc loc = this->loc;
219 if (peek(&token)->value == TOKlparen)
220 { // mixin(string)
221 nextToken();
222 check(TOKlparen, "mixin");
223 Expression *e = parseAssignExp();
224 check(TOKrparen);
225 check(TOKsemicolon);
226 s = new CompileDeclaration(loc, e);
227 break;
229 s = parseMixin();
230 break;
233 CASE_BASIC_TYPES:
234 case TOKalias:
235 case TOKtypedef:
236 case TOKidentifier:
237 case TOKtypeof:
238 case TOKdot:
239 Ldeclaration:
240 a = parseDeclarations();
241 decldefs->append(a);
242 continue;
244 case TOKthis:
245 s = parseCtor();
246 break;
248 case TOKassign:
249 s = parsePostBlit();
250 break;
252 case TOKtilde:
253 s = parseDtor();
254 break;
256 case TOKinvariant:
257 { Token *t;
258 t = peek(&token);
259 if (t->value == TOKlparen)
261 if (peek(t)->value == TOKrparen)
262 // invariant() forms start of class invariant
263 s = parseInvariant();
264 else
265 // invariant(type)
266 goto Ldeclaration;
268 else
270 stc = STCinvariant;
271 goto Lstc;
273 break;
276 case TOKunittest:
277 s = parseUnitTest();
278 break;
280 case TOKnew:
281 s = parseNew();
282 break;
284 case TOKdelete:
285 s = parseDelete();
286 break;
288 case TOKeof:
289 case TOKrcurly:
290 return decldefs;
292 case TOKstatic:
293 nextToken();
294 if (token.value == TOKthis)
296 s = parseStaticCtor();
297 if (dltNormalMode)
298 error("no static constructors in Delight");
300 else if (token.value == TOKtilde)
302 s = parseStaticDtor();
303 if (dltNormalMode)
304 error("no static destructors in Delight");
306 else if (token.value == TOKassert)
307 s = parseStaticAssert();
308 else if (token.value == TOKif)
309 { condition = parseStaticIfCondition();
310 a = parseBlock();
311 aelse = NULL;
312 if (token.value == TOKelse)
313 { nextToken();
314 aelse = parseBlock();
316 s = new StaticIfDeclaration(condition, a, aelse);
317 break;
319 else if (token.value == TOKimport)
321 s = parseImport(decldefs, 1);
323 else
324 { stc = STCstatic;
325 goto Lstc2;
327 break;
329 case TOKin:
330 nextToken();
331 stc = STCinject;
332 goto Lstc2;
334 case TOKconst:
335 if (peek(&token)->value == TOKlparen)
336 goto Ldeclaration;
337 stc = STCconst;
338 goto Lstc;
340 case TOKfinal: stc = STCfinal; goto Lstc;
341 case TOKauto: stc = STCauto; goto Lstc;
342 case TOKscope: stc = STCscope; goto Lstc;
343 case TOKoverride: stc = STCoverride; goto Lstc;
344 case TOKabstract: stc = STCabstract; goto Lstc;
345 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
346 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
347 case TOKnothrow: stc = STCnothrow; goto Lstc;
348 case TOKpure: stc = STCpure; goto Lstc;
349 case TOKtls: stc = STCtls; goto Lstc;
350 //case TOKmanifest: stc = STCmanifest; goto Lstc;
352 Lstc:
353 if (storageClass & stc)
354 error("redundant storage class %s", Token::toChars(token.value));
356 unsigned u = storageClass | stc;
357 u &= STCconst | STCinvariant | STCmanifest;
358 if (u & (u - 1))
359 error("conflicting storage class %s", Token::toChars(token.value));
361 nextToken();
362 Lstc2:
363 storageClass |= stc;
364 switch (token.value)
366 case TOKconst:
367 case TOKinvariant:
368 // If followed by a (, it is not a storage class
369 if (peek(&token)->value == TOKlparen)
370 break;
371 if (token.value == TOKconst)
372 stc = STCconst;
373 else
374 stc = STCinvariant;
375 goto Lstc;
376 case TOKfinal: stc = STCfinal; goto Lstc;
377 case TOKauto: stc = STCauto; goto Lstc;
378 case TOKscope: stc = STCscope; goto Lstc;
379 case TOKoverride: stc = STCoverride; goto Lstc;
380 case TOKabstract: stc = STCabstract; goto Lstc;
381 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
382 case TOKdeprecated: stc = STCdeprecated; goto Lstc;
383 case TOKnothrow: stc = STCnothrow; goto Lstc;
384 case TOKpure: stc = STCpure; goto Lstc;
385 case TOKtls: stc = STCtls; goto Lstc;
386 //case TOKmanifest: stc = STCmanifest; goto Lstc;
387 default:
388 break;
391 /* Look for auto initializers:
392 * storage_class identifier = initializer;
394 if (token.value == TOKidentifier &&
395 peek(&token)->value == TOKassign)
397 while (1)
399 Identifier *ident = token.ident;
400 nextToken();
401 nextToken();
402 Initializer *init = parseInitializer();
403 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
404 v->storage_class = storageClass;
405 v->dltNormalMode = dltNormalMode;
406 s = v;
407 if (token.value == TOKsemicolon || token.value == TOKendline)
409 nextToken();
411 else if (token.value == TOKcomma)
413 nextToken();
414 if (token.value == TOKidentifier &&
415 peek(&token)->value == TOKassign)
417 decldefs->push(s);
418 addComment(s, comment);
419 continue;
421 else
422 error("Identifier expected following comma");
424 else
425 error("%s expected following declaration, not '%s'", endToken(), token.toChars());
426 break;
429 else
430 { a = parseBlock();
431 s = new StorageClassDeclaration(storageClass, a);
433 break;
435 case TOKextern:
436 if (peek(&token)->value != TOKlparen)
437 { stc = STCextern;
438 goto Lstc;
441 enum LINK linksave = linkage;
442 linkage = parseLinkage();
443 a = parseBlock();
444 s = new LinkDeclaration(linkage, a);
445 linkage = linksave;
447 if (dltNormalMode)
448 error("access to external symbols can be done only by dlt.* modules");
449 break;
451 case TOKprivate: prot = PROTprivate; goto Lprot;
452 case TOKpackage: prot = PROTpackage; goto Lprot;
453 case TOKprotected: prot = PROTprotected; goto Lprot;
454 case TOKpublic: prot = PROTpublic; goto Lprot;
455 case TOKexport: prot = PROTexport; goto Lprot;
457 Lprot:
458 nextToken();
459 switch (token.value)
461 case TOKprivate:
462 case TOKpackage:
463 case TOKprotected:
464 case TOKpublic:
465 case TOKexport:
466 error("redundant protection attribute");
467 break;
469 a = parseBlock();
470 s = new ProtDeclaration(prot, a);
471 break;
473 case TOKalign:
474 { unsigned n;
476 s = NULL;
477 nextToken();
478 if (token.value == TOKlparen)
480 nextToken();
481 if (token.value == TOKint32v)
482 n = (unsigned)token.uns64value;
483 else
484 { error("integer expected, not %s", token.toChars());
485 n = 1;
487 nextToken();
488 check(TOKrparen);
490 else
491 n = global.structalign; // default
493 a = parseBlock();
494 s = new AlignDeclaration(n, a);
495 break;
498 case TOKpragma:
499 { Identifier *ident;
500 Expressions *args = NULL;
502 nextToken();
503 check(TOKlparen);
504 if (token.value != TOKidentifier)
505 { error("pragma(identifier expected");
506 goto Lerror;
508 ident = token.ident;
509 nextToken();
510 if (token.value == TOKcomma)
511 args = parseArguments(); // pragma(identifier, args...)
512 else
513 check(TOKrparen); // pragma(identifier)
515 if (token.value == TOKsemicolon || token.value == TOKendline)
516 a = NULL;
517 else if (dltSyntax)
519 check(TOKcolon);
520 a = parseDeclDefs(0);
521 check(TOKrcurly);
523 else
524 a = parseBlock();
525 s = new PragmaDeclaration(loc, ident, args, a);
526 break;
529 case TOKdebug:
530 nextToken();
531 if (token.value == TOKassign)
533 nextToken();
534 if (token.value == TOKidentifier)
535 s = new DebugSymbol(loc, token.ident);
536 else if (token.value == TOKint32v)
537 s = new DebugSymbol(loc, (unsigned)token.uns64value);
538 else
539 { error("identifier or integer expected, not %s", token.toChars());
540 s = NULL;
542 nextToken();
543 if (token.value != TOKsemicolon)
544 error("semicolon expected");
545 nextToken();
546 break;
549 condition = parseDebugCondition();
550 goto Lcondition;
552 case TOKversion:
553 nextToken();
554 if (token.value == TOKassign)
556 nextToken();
557 if (token.value == TOKidentifier)
558 s = new VersionSymbol(loc, token.ident);
559 else if (token.value == TOKint32v)
560 s = new VersionSymbol(loc, (unsigned)token.uns64value);
561 else
562 { error("identifier or integer expected, not %s", token.toChars());
563 s = NULL;
565 nextToken();
566 if (token.value != TOKsemicolon && token.value != TOKendline)
567 error("%s expected after version assignment", endToken());
568 nextToken();
569 break;
571 condition = parseVersionCondition();
572 goto Lcondition;
574 Lcondition:
575 a = parseBlock();
576 aelse = NULL;
577 if (token.value == TOKelse)
578 { nextToken();
579 aelse = parseBlock();
581 s = new ConditionalDeclaration(condition, a, aelse);
582 break;
584 case TOKsemicolon: // empty declaration
585 nextToken();
586 continue;
588 default:
589 error("Declaration expected, not '%s'",token.toChars());
590 Lerror:
591 while (token.value != TOKsemicolon && token.value != TOKendline && token.value != TOKeof)
592 nextToken();
593 nextToken();
594 s = NULL;
595 continue;
597 if (s)
598 { decldefs->push(s);
599 addComment(s, comment);
601 } while (!once);
602 return decldefs;
606 /********************************************
607 * Parse declarations after an align, protection, or extern decl.
610 Array *Parser::parseBlock()
612 Array *a = NULL;
613 Dsymbol *s;
615 //printf("Parser::parseBlock()\n");
616 switch (token.value)
618 case TOKsemicolon:
619 error("declaration expected following attribute, not ';'");
620 nextToken();
621 break;
623 case TOKlcurly:
624 nextToken();
625 a = parseDeclDefs(0);
626 if (token.value != TOKrcurly)
627 { /* { */
628 error("matching '}' expected, not %s", token.toChars());
630 else
631 nextToken();
632 break;
634 case TOKcolon:
635 nextToken();
636 #if 0
637 a = NULL;
638 #else
639 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
640 #endif
641 break;
643 default:
644 a = parseDeclDefs(1);
645 break;
647 return a;
650 Array *DltParser::parseBlock()
652 Array *a = NULL;
653 Dsymbol *s;
655 optionalEndline();
656 switch (token.value)
658 case TOKendline:
659 case TOKsemicolon:
660 error("declaration expected following attribute, not %s", token.toChars());
661 nextToken();
662 break;
664 case TOKcolon:
665 nextToken();
666 a = parseDeclDefs(0);
667 if (token.value != TOKrcurly)
669 error("matching end-of-block expected, not %s", token.toChars());
671 else
672 nextToken();
673 break;
675 default:
676 a = parseDeclDefs(1);
677 break;
679 return a;
682 /**********************************
683 * Parse a static assertion.
686 StaticAssert *Parser::parseStaticAssert()
688 Loc loc = this->loc;
689 Expression *exp;
690 Expression *msg = NULL;
692 //printf("parseStaticAssert()\n");
693 nextToken();
694 checkLParen();
695 exp = parseAssignExp();
696 if (token.value == TOKcomma)
697 { nextToken();
698 msg = parseAssignExp();
700 checkRParen();
701 if (token.value == TOKsemicolon || token.value == TOKendline) {
702 nextToken();
703 return new StaticAssert(loc, exp, msg);
705 error("expected %s after static assert", endToken());
708 /***********************************
709 * Parse typeof(expression).
710 * Current token is on the 'typeof'.
713 TypeQualified *Parser::parseTypeof()
714 { TypeQualified *t;
715 Loc loc = this->loc;
717 nextToken();
718 check(TOKlparen);
719 if (token.value == TOKreturn) // typeof(return)
721 nextToken();
722 t = new TypeReturn(loc);
724 else
725 { Expression *exp = parseExpression(); // typeof(expression)
726 t = new TypeTypeof(loc, exp);
728 check(TOKrparen);
729 return t;
732 /***********************************
733 * Parse extern (linkage)
734 * The parser is on the 'extern' token.
737 enum LINK Parser::parseLinkage()
739 enum LINK link = LINKdefault;
740 nextToken();
741 assert(token.value == TOKlparen);
742 nextToken();
743 if (token.value == TOKidentifier)
744 { Identifier *id = token.ident;
746 nextToken();
747 if (id == Id::Windows)
748 link = LINKwindows;
749 else if (id == Id::Pascal)
750 link = LINKpascal;
751 else if (id == Id::D)
752 link = LINKd;
753 else if (id == Id::C)
755 link = LINKc;
756 if (token.value == TOKplusplus)
757 { link = LINKcpp;
758 nextToken();
761 else if (id == Id::System)
763 #ifdef IN_GCC
764 link = d_gcc_is_target_win32() ? LINKwindows : LINKc;
765 #else
766 #if _WIN32
767 link = LINKwindows;
768 #else
769 link = LINKc;
770 #endif
771 #endif
773 else
775 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
776 link = LINKd;
779 else
781 link = LINKd; // default
783 check(TOKrparen);
784 return link;
787 /**************************************
788 * Parse a debug conditional
791 Condition *Parser::parseDebugCondition()
793 Condition *c;
795 if (token.value == TOKlparen)
797 nextToken();
798 unsigned level = 1;
799 Identifier *id = NULL;
801 if (token.value == TOKidentifier)
802 id = token.ident;
803 else if (token.value == TOKint32v)
804 level = (unsigned)token.uns64value;
805 else
806 error("identifier or integer expected, not %s", token.toChars());
807 nextToken();
808 check(TOKrparen);
809 c = new DebugCondition(mod, level, id);
810 if (dltSyntax && token.value != TOKcolon)
811 error("expected colon after debug(), not '%s'", token.toChars());
812 } else {
813 if (dltSyntax && token.value != TOKcolon)
814 error("expected ':' or '(' after 'debug', not '%s'", token.toChars());
815 c = new DebugCondition(mod, 1, NULL);
817 return c;
821 /**************************************
822 * Parse a version conditional
825 Condition *Parser::parseVersionCondition()
827 Condition *c;
828 unsigned level = 1;
829 Identifier *id = NULL;
831 if (token.value == TOKlparen)
833 nextToken();
834 if (token.value == TOKidentifier)
835 id = token.ident;
836 else if (token.value == TOKint32v)
837 level = (unsigned)token.uns64value;
838 #if V2
839 /* Allow:
840 * version (unittest)
841 * even though unittest is a keyword
843 else if (token.value == TOKunittest)
844 id = Lexer::idPool(Token::toChars(TOKunittest));
845 #endif
846 else
847 error("identifier or integer expected, not %s", token.toChars());
848 nextToken();
849 check(TOKrparen);
852 else
853 error("(condition) expected following version");
854 c = new VersionCondition(mod, level, id);
855 return c;
859 /***********************************************
860 * static if (expression)
861 * body
862 * else
863 * body
866 Condition *Parser::parseStaticIfCondition()
867 { Expression *exp;
868 Condition *condition;
869 Array *aif;
870 Array *aelse;
871 Loc loc = this->loc;
873 nextToken();
874 checkLParen();
875 exp = parseAssignExp();
876 checkRParen();
878 condition = new StaticIfCondition(loc, exp);
879 return condition;
883 /*****************************************
884 * Parse a constructor definition:
885 * this(arguments) { body }
886 * or postblit:
887 * this(this) { body }
888 * Current token is 'this'.
891 FuncDeclaration *Parser::parseCtor()
893 Loc loc = this->loc;
895 nextToken();
896 if (token.value == TOKlparen && peek(&token)->value == TOKthis)
897 { // this(this) { ... }
898 nextToken();
899 nextToken();
900 check(TOKrparen);
901 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
902 parseContracts(f);
903 return f;
905 int varargs;
906 Arguments *arguments = parseParameters(&varargs);
907 CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs);
908 parseContracts(f);
909 return f;
912 /*****************************************
913 * Parse a postblit definition:
914 * =this() { body }
915 * Current token is '='.
918 PostBlitDeclaration *Parser::parsePostBlit()
920 Loc loc = this->loc;
922 nextToken();
923 check(TOKthis);
924 check(TOKlparen);
925 check(TOKrparen);
927 PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
928 parseContracts(f);
929 return f;
932 /*****************************************
933 * Parse a destructor definition:
934 * ~this() { body }
935 * Current token is '~'.
938 DtorDeclaration *Parser::parseDtor()
940 DtorDeclaration *f;
941 Loc loc = this->loc;
943 nextToken();
944 check(TOKthis);
945 check(TOKlparen);
946 check(TOKrparen);
948 f = new DtorDeclaration(loc, 0);
949 parseContracts(f);
950 return f;
953 /*****************************************
954 * Parse a static constructor definition:
955 * static this() { body }
956 * Current token is 'this'.
959 StaticCtorDeclaration *Parser::parseStaticCtor()
961 StaticCtorDeclaration *f;
962 Loc loc = this->loc;
964 nextToken();
965 check(TOKlparen);
966 check(TOKrparen);
968 f = new StaticCtorDeclaration(loc, 0);
969 parseContracts(f);
970 return f;
973 /*****************************************
974 * Parse a static destructor definition:
975 * static ~this() { body }
976 * Current token is '~'.
979 StaticDtorDeclaration *Parser::parseStaticDtor()
981 StaticDtorDeclaration *f;
982 Loc loc = this->loc;
984 nextToken();
985 check(TOKthis);
986 check(TOKlparen);
987 check(TOKrparen);
989 f = new StaticDtorDeclaration(loc, 0);
990 parseContracts(f);
991 return f;
994 /*****************************************
995 * Parse an invariant definition:
996 * invariant { body }
997 * Current token is 'invariant'.
1000 InvariantDeclaration *Parser::parseInvariant()
1002 InvariantDeclaration *f;
1003 Loc loc = this->loc;
1005 nextToken();
1007 // () are optional
1008 if (token.value == TOKlparen)
1009 { nextToken();
1010 check(TOKrparen);
1013 f = new InvariantDeclaration(loc, 0);
1014 f->fbody = parseStatement(PScurly);
1015 return f;
1018 /*****************************************
1019 * Parse a unittest definition:
1020 * unittest { body }
1021 * Current token is 'unittest'.
1024 UnitTestDeclaration *Parser::parseUnitTest()
1026 UnitTestDeclaration *f;
1027 Statement *body;
1028 Loc loc = this->loc;
1030 nextToken();
1032 body = parseStatement(PScurly);
1034 f = new UnitTestDeclaration(loc, this->loc);
1035 f->fbody = body;
1036 return f;
1039 /*****************************************
1040 * Parse a new definition:
1041 * new(arguments) { body }
1042 * Current token is 'new'.
1045 NewDeclaration *Parser::parseNew()
1047 NewDeclaration *f;
1048 Arguments *arguments;
1049 int varargs;
1050 Loc loc = this->loc;
1052 nextToken();
1053 arguments = parseParameters(&varargs);
1054 f = new NewDeclaration(loc, 0, arguments, varargs);
1055 parseContracts(f);
1056 return f;
1059 /*****************************************
1060 * Parse a delete definition:
1061 * delete(arguments) { body }
1062 * Current token is 'delete'.
1065 DeleteDeclaration *Parser::parseDelete()
1067 DeleteDeclaration *f;
1068 Arguments *arguments;
1069 int varargs;
1070 Loc loc = this->loc;
1072 nextToken();
1073 arguments = parseParameters(&varargs);
1074 if (varargs)
1075 error("... not allowed in delete function parameter list");
1076 f = new DeleteDeclaration(loc, 0, arguments);
1077 parseContracts(f);
1078 return f;
1081 /**********************************************
1082 * Parse parameter list.
1085 Arguments *Parser::parseParameters(int *pvarargs)
1087 Arguments *arguments = new Arguments();
1088 int varargs = 0;
1089 int hasdefault = 0;
1091 check(TOKlparen);
1092 while (1)
1093 { Type *tb;
1094 Identifier *ai;
1095 Type *at;
1096 Argument *a;
1097 unsigned storageClass;
1098 unsigned stc;
1099 Expression *ae;
1101 ai = NULL;
1102 storageClass = 0; // parameter is "in" by default
1103 for (;1; nextToken())
1105 switch (token.value)
1107 case TOKrparen:
1108 break;
1110 case TOKdotdotdot:
1111 varargs = 1;
1112 nextToken();
1113 break;
1115 case TOKconst:
1116 if (peek(&token)->value == TOKlparen)
1117 goto Ldefault;
1118 stc = STCconst;
1119 goto L2;
1121 case TOKinvariant:
1122 if (peek(&token)->value == TOKlparen)
1123 goto Ldefault;
1124 stc = STCinvariant;
1125 goto L2;
1127 case TOKin: stc = STCin; goto L2;
1128 case TOKout: stc = STCout; goto L2;
1129 case TOKinout:
1130 case TOKref: stc = STCref; goto L2;
1131 case TOKlazy: stc = STClazy; goto L2;
1132 case TOKscope: stc = STCscope; goto L2;
1133 case TOKfinal: stc = STCfinal; goto L2;
1134 case TOKstatic: stc = STCstatic; goto L2;
1136 if (storageClass & stc ||
1137 (storageClass & STCin && stc & (STCconst | STCscope)) ||
1138 (stc & STCin && storageClass & (STCconst | STCscope))
1140 error("redundant storage class %s", Token::toChars(token.value));
1141 storageClass |= stc;
1143 unsigned u = storageClass & (STCconst | STCinvariant);
1144 if (u & (u - 1))
1145 error("conflicting storage class %s", Token::toChars(token.value));
1147 continue;
1149 default:
1150 Ldefault:
1151 stc = storageClass & (STCin | STCout | STCref | STClazy);
1152 if (stc & (stc - 1)) // if stc is not a power of 2
1153 error("incompatible parameter storage classes");
1154 if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1155 error("out cannot be const");
1156 if ((storageClass & (STCinvariant | STCout)) == (STCinvariant | STCout))
1157 error("out cannot be invariant");
1158 if ((storageClass & STCscope) &&
1159 (storageClass & (STCref | STCout)))
1160 error("scope cannot be ref or out");
1161 at = parseType(&ai);
1162 ae = NULL;
1163 if (token.value == TOKassign) // = defaultArg
1164 { nextToken();
1165 ae = parseDefaultInitExp();
1166 hasdefault = 1;
1168 else
1169 { if (hasdefault)
1170 error("default argument expected for %s",
1171 ai ? ai->toChars() : at->toChars());
1173 if (token.value == TOKdotdotdot)
1174 { /* This is:
1175 * at ai ...
1178 if (storageClass & (STCout | STCref))
1179 error("variadic argument cannot be out or ref");
1180 varargs = 2;
1181 a = new Argument(storageClass, at, ai, ae);
1182 arguments->push(a);
1183 nextToken();
1184 break;
1186 a = new Argument(storageClass, at, ai, ae);
1187 arguments->push(a);
1188 if (token.value == TOKcomma)
1189 { nextToken();
1190 goto L1;
1192 break;
1194 break;
1196 break;
1198 L1: ;
1200 check(TOKrparen);
1201 *pvarargs = varargs;
1202 return arguments;
1206 /*************************************
1209 EnumDeclaration *Parser::parseEnum()
1210 { EnumDeclaration *e;
1211 Identifier *id;
1212 Type *memtype;
1213 Loc loc = this->loc;
1215 //printf("Parser::parseEnum()\n");
1216 nextToken();
1217 if (token.value == TOKidentifier)
1218 { id = token.ident;
1219 nextToken();
1221 else
1222 id = NULL;
1224 if (token.value == (dltSyntax ? TOKextends : TOKcolon))
1226 nextToken();
1227 memtype = parseBasicType();
1228 memtype = parseDeclarator(memtype, NULL, NULL);
1230 else
1231 memtype = NULL;
1233 e = new EnumDeclaration(loc, id, memtype);
1234 if ((token.value == TOKsemicolon || token.value == TOKendline) && id)
1235 nextToken();
1236 else if (token.value == startBlockTok)
1238 //printf("enum definition\n");
1239 e->members = new Array();
1240 nextToken();
1241 unsigned char *comment = token.blockComment;
1242 optionalEndline();
1243 while (token.value != TOKrcurly)
1245 /* Can take the following forms:
1246 * 1. ident
1247 * 2. ident = value
1248 * 3. type ident = value
1251 loc = this->loc;
1253 Type *type = NULL;
1254 Identifier *ident;
1255 Token *tp = peek(&token);
1256 if (token.value == TOKidentifier &&
1257 (tp->value == TOKassign || tp->value == TOKcomma ||
1258 tp->value == TOKendline || tp->value == TOKrcurly))
1260 ident = token.ident;
1261 type = NULL;
1262 nextToken();
1264 else
1266 type = parseType(&ident, NULL);
1267 if (id || memtype)
1268 error("type only allowed if anonymous enum and no enum type");
1271 Expression *value;
1272 if (token.value == TOKassign)
1274 nextToken();
1275 value = parseAssignExp();
1277 else
1278 { value = NULL;
1279 if (type)
1280 error("if type, there must be an initializer");
1283 EnumMember *em = new EnumMember(loc, ident, value, type);
1284 e->members->push(em);
1286 if (dltSyntax)
1288 if (token.value == TOKcomma)
1289 nextToken();
1290 else if (token.value != TOKendline)
1291 error("expected comma or newline after %s, not %s",
1292 em->toChars(), token.toChars());
1293 optionalEndline();
1296 if (token.value == TOKrcurly)
1298 else
1299 { addComment(em, comment);
1300 comment = NULL;
1301 if (!dltSyntax)
1302 check(TOKcomma);
1304 addComment(em, comment);
1305 comment = token.blockComment;
1307 nextToken();
1309 else
1310 error("enum declaration is invalid");
1311 //printf("-parseEnum() %s\n", e->toChars());
1312 return e;
1315 Dsymbol *Parser::parseAggregate()
1316 { AggregateDeclaration *a = NULL;
1317 int anon = 0;
1318 enum TOK tok;
1319 Identifier *id;
1320 TemplateParameters *tpl = NULL;
1322 //printf("Parser::parseAggregate()\n");
1323 tok = token.value;
1324 nextToken();
1325 if (token.value != TOKidentifier)
1326 { id = NULL;
1328 else
1329 { id = token.ident;
1330 nextToken();
1332 if (token.value == TOKlparen)
1333 { // Class template declaration.
1335 // Gather template parameter list
1336 tpl = parseTemplateParameterList();
1340 Loc loc = this->loc;
1341 switch (tok)
1342 { case TOKclass:
1343 case TOKinterface:
1345 if (!id)
1346 error("anonymous classes not allowed");
1348 // Collect base class(es)
1349 BaseClasses *baseclasses = parseBaseClasses();
1350 if (baseclasses && token.value != startBlockTok) {
1351 error("members expected");
1354 if (tok == TOKclass)
1355 a = new ClassDeclaration(loc, id, baseclasses);
1356 else
1357 a = new InterfaceDeclaration(loc, id, baseclasses);
1358 break;
1361 case TOKstruct:
1362 if (id)
1363 a = new StructDeclaration(loc, id);
1364 else
1365 anon = 1;
1366 break;
1368 case TOKunion:
1369 if (id)
1370 a = new UnionDeclaration(loc, id);
1371 else
1372 anon = 2;
1373 break;
1375 default:
1376 assert(0);
1377 break;
1379 if (a && token.value == (dltSyntax ? TOKendline : TOKsemicolon))
1380 { nextToken();
1382 else if (token.value == startBlockTok)
1384 //printf("aggregate definition\n");
1385 nextToken();
1386 optionalEndline();
1387 Array *decl = parseDeclDefs(0);
1388 if (token.value != TOKrcurly)
1389 error("end-of-block expected following member declarations in aggregate");
1390 nextToken();
1391 if (anon)
1393 /* Anonymous structs/unions are more like attributes.
1395 return new AnonDeclaration(loc, anon - 1, decl);
1397 else
1398 a->members = decl;
1400 else
1402 error("%s expected following aggregate declaration", Token::toChars(startBlockTok));
1403 a = new StructDeclaration(loc, NULL);
1406 if (tpl)
1407 { Array *decldefs;
1408 TemplateDeclaration *tempdecl;
1410 // Wrap a template around the aggregate declaration
1411 decldefs = new Array();
1412 decldefs->push(a);
1413 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1414 return tempdecl;
1417 return a;
1420 /*******************************************
1423 /* If current token is TOKcolon, TOKextends or TOKimplements, return
1424 * the bases. Otherwise, return null.
1426 BaseClasses *Parser::parseBaseClasses()
1428 enum PROT protection = PROTpublic;
1429 int type; // 1 = extends, 2 = implements, 3 = unknown
1431 if (dltSyntax) {
1432 if (token.value == TOKextends)
1433 type = 1;
1434 else if (token.value == TOKimplements)
1435 type = 2;
1436 else
1437 return NULL;
1438 } else {
1439 if (token.value == TOKcolon)
1440 type = 3;
1441 else
1442 return NULL;
1445 nextToken();
1447 BaseClasses *baseclasses = new BaseClasses();
1449 for (; 1; nextToken())
1451 enum PROT protection = PROTpublic;
1452 switch (token.value)
1454 case TOKprivate:
1455 protection = PROTprivate;
1456 nextToken();
1457 break;
1458 case TOKpackage:
1459 protection = PROTpackage;
1460 nextToken();
1461 break;
1462 case TOKprotected:
1463 protection = PROTprotected;
1464 nextToken();
1465 break;
1466 case TOKpublic:
1467 protection = PROTpublic;
1468 nextToken();
1469 break;
1471 if (token.value == TOKidentifier)
1473 BaseClass *b = new BaseClass(parseBasicType(), protection);
1474 baseclasses->push(b);
1476 switch (token.value) {
1477 case TOKcomma:
1478 continue;
1479 case TOKextends:
1480 if (type == 2)
1481 error("extends part must come before implements");
1482 else
1483 error("only one extends is permitted");
1484 continue;
1485 case TOKimplements:
1486 if (type == 1)
1487 type = 2;
1488 else
1489 error("separate implemented interfaces with commas");
1490 continue;
1492 break;
1494 else
1496 error("base classes expected instead of %s", token.toChars());
1497 return NULL;
1500 return baseclasses;
1503 /**************************************
1504 * Parse a TemplateDeclaration.
1507 TemplateDeclaration *Parser::parseTemplateDeclaration()
1509 TemplateDeclaration *tempdecl;
1510 Identifier *id;
1511 TemplateParameters *tpl;
1512 Array *decldefs;
1513 Loc loc = this->loc;
1515 nextToken();
1516 if (token.value != TOKidentifier)
1517 { error("TemplateIdentifier expected following template");
1518 goto Lerr;
1520 id = token.ident;
1521 nextToken();
1522 tpl = parseTemplateParameterList();
1523 if (!tpl)
1524 goto Lerr;
1526 if (token.value != startBlockTok)
1527 { error("members of template declaration expected");
1528 goto Lerr;
1530 else
1532 nextToken();
1533 decldefs = parseDeclDefs(0);
1534 if (token.value != TOKrcurly)
1535 { error("template member expected");
1536 goto Lerr;
1538 nextToken();
1541 tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs, dltSyntax);
1542 return tempdecl;
1544 Lerr:
1545 return NULL;
1548 /******************************************
1549 * Parse template parameter list.
1550 * Input:
1551 * flag 0: parsing "( list )"
1552 * 1: parsing non-empty "list )"
1555 TemplateParameters *Parser::parseTemplateParameterList(int flag)
1557 TemplateParameters *tpl = new TemplateParameters();
1559 if (!flag && token.value != TOKlparen)
1560 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1561 goto Lerr;
1563 nextToken();
1565 // Get array of TemplateParameters
1566 if (flag || token.value != TOKrparen)
1567 { int isvariadic = 0;
1569 while (1)
1570 { TemplateParameter *tp;
1571 Identifier *tp_ident = NULL;
1572 Type *tp_spectype = NULL;
1573 Type *tp_valtype = NULL;
1574 Type *tp_defaulttype = NULL;
1575 Expression *tp_specvalue = NULL;
1576 Expression *tp_defaultvalue = NULL;
1577 Token *t;
1579 // Get TemplateParameter
1581 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1582 t = peek(&token);
1583 if (token.value == TOKalias)
1584 { // AliasParameter
1585 nextToken();
1586 if (token.value != TOKidentifier)
1587 { error("Identifier expected for template parameter");
1588 goto Lerr;
1590 tp_ident = token.ident;
1591 nextToken();
1592 if (token.value == TOKcolon) // : Type
1594 nextToken();
1595 tp_spectype = parseType();
1597 if (token.value == TOKassign) // = Type
1599 nextToken();
1600 tp_defaulttype = parseType();
1602 tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1604 else if (t->value == TOKcolon || t->value == TOKassign ||
1605 t->value == TOKcomma || t->value == TOKrparen)
1606 { // TypeParameter
1607 if (token.value != TOKidentifier)
1608 { error("Identifier expected for template parameter");
1609 goto Lerr;
1611 tp_ident = token.ident;
1612 nextToken();
1613 if (token.value == TOKcolon) // : Type
1615 nextToken();
1616 tp_spectype = parseType();
1618 if (token.value == TOKassign) // = Type
1620 nextToken();
1621 tp_defaulttype = parseType();
1623 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1625 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1626 { // ident...
1627 if (isvariadic)
1628 error("variadic template parameter must be last");
1629 isvariadic = 1;
1630 tp_ident = token.ident;
1631 nextToken();
1632 nextToken();
1633 tp = new TemplateTupleParameter(loc, tp_ident);
1635 else if (token.value == TOKthis)
1636 { // ThisParameter
1637 nextToken();
1638 if (token.value != TOKidentifier)
1639 { error("Identifier expected for template parameter");
1640 goto Lerr;
1642 tp_ident = token.ident;
1643 nextToken();
1644 if (token.value == TOKcolon) // : Type
1646 nextToken();
1647 tp_spectype = parseType();
1649 if (token.value == TOKassign) // = Type
1651 nextToken();
1652 tp_defaulttype = parseType();
1654 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1656 else
1657 { // ValueParameter
1658 tp_valtype = parseType(&tp_ident);
1659 if (!tp_ident)
1661 error("no identifier for template value parameter");
1662 tp_ident = new Identifier("error", TOKidentifier);
1664 if (token.value == TOKcolon) // : CondExpression
1666 nextToken();
1667 tp_specvalue = parseCondExp();
1669 if (token.value == TOKassign) // = CondExpression
1671 nextToken();
1672 tp_defaultvalue = parseDefaultInitExp();
1674 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1676 tpl->push(tp);
1677 if (token.value != TOKcomma)
1678 break;
1679 nextToken();
1682 check(TOKrparen);
1683 Lerr:
1684 return tpl;
1687 /******************************************
1688 * Parse template mixin.
1689 * mixin Foo;
1690 * mixin Foo!(args);
1691 * mixin a.b.c!(args).Foo!(args);
1692 * mixin Foo!(args) identifier;
1693 * mixin typeof(expr).identifier!(args);
1696 Dsymbol *Parser::parseMixin()
1698 TemplateMixin *tm;
1699 Identifier *id;
1700 Type *tqual;
1701 Objects *tiargs;
1702 Array *idents;
1704 //printf("parseMixin()\n");
1705 nextToken();
1706 tqual = NULL;
1707 if (token.value == TOKdot)
1709 id = Id::empty;
1711 else
1713 if (token.value == TOKtypeof)
1715 tqual = parseTypeof();
1716 check(TOKdot);
1718 if (token.value != TOKidentifier)
1720 error("identifier expected, not %s", token.toChars());
1721 goto Lerr;
1723 id = token.ident;
1724 nextToken();
1727 idents = new Array();
1728 while (1)
1730 tiargs = NULL;
1731 if (token.value == TOKnot)
1733 nextToken();
1734 tiargs = parseTemplateArgumentList();
1737 if (token.value != TOKdot)
1738 break;
1740 if (tiargs)
1741 { TemplateInstance *tempinst = new TemplateInstance(loc, id);
1742 tempinst->tiargs = tiargs;
1743 id = (Identifier *)tempinst;
1744 tiargs = NULL;
1746 idents->push(id);
1748 nextToken();
1749 if (token.value != TOKidentifier)
1750 { error("identifier expected following '.' instead of '%s'", token.toChars());
1751 break;
1753 id = token.ident;
1754 nextToken();
1756 idents->push(id);
1758 if (token.value == TOKidentifier)
1760 id = token.ident;
1761 nextToken();
1763 else
1764 id = NULL;
1766 tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1768 if (dltSyntax) {
1769 if (token.value != TOKsemicolon && token.value != TOKendline)
1770 error("newline expected after mixin");
1771 } else {
1772 if (token.value != TOKsemicolon)
1773 error("';' expected after mixin");
1774 nextToken();
1777 return tm;
1779 Lerr:
1780 return NULL;
1783 /******************************************
1784 * Parse template argument list.
1785 * Input:
1786 * current token is opening '('
1787 * Output:
1788 * current token is one after closing ')'
1791 Objects *Parser::parseTemplateArgumentList()
1793 //printf("Parser::parseTemplateArgumentList()\n");
1794 if (token.value != TOKlparen)
1795 { error("!(TemplateArgumentList) expected following TemplateIdentifier");
1796 return new Objects();
1798 return parseTemplateArgumentList2();
1801 Objects *Parser::parseTemplateArgumentList2()
1803 Objects *tiargs = new Objects();
1804 nextToken();
1806 // Get TemplateArgumentList
1807 if (token.value != TOKrparen)
1809 while (1)
1811 // See if it is an Expression or a Type
1812 if (isDeclaration(&token, 0, TOKreserved, NULL))
1813 { // Type
1814 Type *ta;
1816 // Get TemplateArgument
1817 ta = parseType();
1818 tiargs->push(ta);
1820 else
1821 { // Expression
1822 Expression *ea;
1824 ea = parseAssignExp();
1825 tiargs->push(ea);
1827 if (token.value != TOKcomma)
1828 break;
1829 nextToken();
1832 check(TOKrparen, "template argument list");
1833 return tiargs;
1836 Import *Parser::parseImport(Array *decldefs, int isstatic)
1837 { Import *s;
1838 Identifier *id;
1839 Identifier *aliasid = NULL;
1840 Array *a;
1841 Loc loc;
1843 if (dltSyntax && isstatic)
1844 error("Delight imports are static by default");
1846 //printf("Parser::parseImport()\n");
1850 nextToken();
1851 if (token.value != TOKidentifier)
1852 { error("Identifier expected following import");
1853 break;
1856 loc = this->loc;
1857 a = NULL;
1858 id = token.ident;
1859 nextToken();
1860 if (!aliasid && token.value == TOKassign)
1862 aliasid = id;
1863 goto L1;
1865 while (token.value == TOKdot)
1867 if (!a)
1868 a = new Array();
1869 a->push(id);
1870 nextToken();
1871 if (token.value != TOKidentifier)
1872 { error("Identifier expected following package");
1873 break;
1875 id = token.ident;
1876 nextToken();
1879 s = new Import(loc, a, token.ident, aliasid, isstatic);
1880 decldefs->push(s);
1882 /* Look for
1883 * : alias=name, alias=name;
1884 * syntax.
1886 if (token.value == TOKcolon)
1888 nextToken();
1889 while (1)
1890 { Identifier *name;
1891 Identifier *alias;
1893 optionalEndline();
1895 if (dltSyntax && token.value == TOKrcurly)
1896 break;
1897 if (dltSyntax && token.value == TOKmul)
1899 // import module: *
1900 nextToken();
1901 optionalEndline();
1902 break;
1904 if (token.value != TOKidentifier)
1905 { error("Identifier expected following :");
1906 break;
1908 alias = token.ident;
1909 nextToken();
1910 if (token.value == TOKassign)
1912 nextToken();
1913 if (token.value != TOKidentifier)
1914 { error("Identifier expected following %s=", alias->toChars());
1915 break;
1917 name = token.ident;
1918 nextToken();
1920 else
1921 { name = alias;
1922 alias = NULL;
1924 s->addAlias(name, alias);
1925 if (token.value != TOKcomma && token.value != TOKendline)
1926 break;
1927 nextToken();
1929 if (dltSyntax)
1931 check(TOKrcurly);
1932 return NULL;
1934 else
1935 break;
1936 } else if (dltSyntax) {
1937 s->isstatic = true;
1940 aliasid = NULL;
1941 } while (token.value == TOKcomma);
1943 if (token.value == TOKsemicolon || token.value == TOKendline)
1944 nextToken();
1945 else
1947 error("%s expected", endToken());
1948 nextToken();
1951 return NULL;
1954 Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
1955 { Type *t;
1957 if (token.value == TOKconst && peek(&token)->value != TOKlparen)
1959 nextToken();
1960 /* const type
1962 t = parseType(pident, tpl);
1963 t = t->makeConst();
1964 return t;
1966 else if (token.value == TOKinvariant && peek(&token)->value != TOKlparen)
1968 nextToken();
1969 /* invariant type
1971 t = parseType(pident, tpl);
1972 t = t->makeInvariant();
1973 return t;
1975 else
1976 t = parseBasicType();
1977 t = parseDeclarator(t, pident, tpl);
1978 return t;
1981 Type *Parser::parseBasicType()
1982 { Type *t;
1983 Identifier *id;
1984 TypeQualified *tid;
1985 TemplateInstance *tempinst;
1987 //printf("parseBasicType()\n");
1988 switch (token.value)
1990 CASE_BASIC_TYPES_X(t):
1991 nextToken();
1992 break;
1994 case TOKidentifier:
1995 id = token.ident;
1996 nextToken();
1997 if (token.value == TOKnot)
1999 nextToken();
2000 tempinst = new TemplateInstance(loc, id);
2001 tempinst->tiargs = parseTemplateArgumentList();
2002 tid = new TypeInstance(loc, tempinst);
2003 goto Lident2;
2005 Lident:
2006 tid = new TypeIdentifier(loc, id);
2007 Lident2:
2008 while (token.value == TOKdot)
2009 { nextToken();
2010 if (token.value != TOKidentifier)
2011 { error("identifier expected following '.' instead of '%s'", token.toChars());
2012 break;
2014 id = token.ident;
2015 nextToken();
2016 if (token.value == TOKnot)
2018 nextToken();
2019 tempinst = new TemplateInstance(loc, id);
2020 tempinst->tiargs = parseTemplateArgumentList();
2021 tid->addIdent((Identifier *)tempinst);
2023 else
2024 tid->addIdent(id);
2026 t = tid;
2027 break;
2029 case TOKdot:
2030 id = Id::empty;
2031 goto Lident;
2033 case TOKtypeof:
2035 tid = parseTypeof();
2036 goto Lident2;
2039 case TOKconst:
2040 // const(type)
2041 nextToken();
2042 check(TOKlparen);
2043 t = parseType();
2044 check(TOKrparen);
2045 t = t->makeConst();
2046 break;
2048 case TOKinvariant:
2049 // invariant(type)
2050 nextToken();
2051 check(TOKlparen);
2052 t = parseType();
2053 check(TOKrparen);
2054 t = t->makeInvariant();
2055 break;
2057 default:
2058 error("basic type expected, not %s", token.toChars());
2059 t = Type::tint32;
2060 break;
2062 return t;
2065 Type *Parser::parseBasicType2(Type *t)
2067 Type *ts;
2068 Type *ta;
2070 //printf("parseBasicType2()\n");
2071 while (1)
2073 switch (token.value)
2075 case TOKmul:
2076 t = new TypePointer(t);
2077 nextToken();
2078 continue;
2080 case TOKlbracket:
2081 // Handle []. Make sure things like
2082 // int[3][1] a;
2083 // is (array[1] of array[3] of int)
2084 nextToken();
2085 if (token.value == TOKrbracket)
2087 t = new TypeDArray(t); // []
2088 nextToken();
2090 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2091 { // It's an associative array declaration
2092 Type *index;
2094 //printf("it's an associative array\n");
2095 index = parseType(); // [ type ]
2096 t = new TypeAArray(t, index);
2097 check(TOKrbracket);
2099 else
2101 //printf("it's [expression]\n");
2102 inBrackets++;
2103 Expression *e = parseExpression(); // [ expression ]
2104 if (token.value == TOKslice)
2105 { Expression *e2;
2107 nextToken();
2108 e2 = parseExpression(); // [ exp .. exp ]
2109 t = new TypeSlice(t, e, e2);
2111 else
2112 t = new TypeSArray(t,e);
2113 inBrackets--;
2114 check(TOKrbracket);
2116 continue;
2118 case TOKdelegate:
2119 case TOKfunction:
2120 { // Handle delegate declaration:
2121 // t delegate(parameter list)
2122 // t function(parameter list)
2123 Arguments *arguments;
2124 int varargs;
2125 bool ispure = false;
2126 bool isnothrow = false;
2127 enum TOK save = token.value;
2129 nextToken();
2130 arguments = parseParameters(&varargs);
2131 while (1)
2133 if (token.value == TOKpure)
2134 ispure = true;
2135 else if (token.value == TOKnothrow)
2136 isnothrow = true;
2137 else
2138 break;
2139 nextToken();
2141 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
2142 tf->ispure = ispure;
2143 tf->isnothrow = isnothrow;
2144 if (save == TOKdelegate)
2145 t = new TypeDelegate(tf);
2146 else
2147 t = new TypePointer(tf); // pointer to function
2148 continue;
2151 case TOKquestion:
2152 // Allow maybe annotations even for D code. Makes it easier to adapt
2153 // D interfaces for Delight
2154 if (1 || dltSyntax)
2156 Type *old = t;
2157 t = t->maybe(false);
2158 if (t == old)
2159 error("Type %s cannot be null; ? is pointless", old->toChars());
2160 nextToken();
2161 continue;
2163 // fall-through to default
2165 default:
2166 ts = t;
2167 break;
2169 break;
2172 return ts;
2175 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
2176 { Type *ts;
2178 //printf("parseDeclarator(tpl = %p)\n", tpl);
2179 t = parseBasicType2(t);
2181 switch (token.value)
2184 case TOKidentifier:
2185 if (pident)
2186 *pident = token.ident;
2187 else
2188 error("unexpected identifer '%s' in declarator", token.ident->toChars());
2189 ts = t;
2190 nextToken();
2191 break;
2193 case TOKlparen:
2194 /* Parse things with parentheses around the identifier, like:
2195 * int (*ident[3])[]
2196 * although the D style would be:
2197 * int[]*[3] ident
2199 nextToken();
2200 ts = parseDeclarator(t, pident);
2201 check(TOKrparen);
2202 break;
2204 default:
2205 ts = t;
2206 break;
2209 while (1)
2211 switch (token.value)
2213 #if CARRAYDECL
2214 /* Support C style array syntax:
2215 * int ident[]
2216 * as opposed to D-style:
2217 * int[] ident
2219 case TOKlbracket:
2220 { // This is the old C-style post [] syntax.
2221 TypeNext *ta;
2223 if (dltSyntax)
2224 error("use 'type[] var', not 'type var[]'");
2226 nextToken();
2227 if (token.value == TOKrbracket)
2228 { // It's a dynamic array
2229 ta = new TypeDArray(t); // []
2230 nextToken();
2232 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2233 { // It's an associative array
2235 //printf("it's an associative array\n");
2236 Type *index = parseType(); // [ type ]
2237 check(TOKrbracket);
2238 ta = new TypeAArray(t, index);
2240 else
2242 //printf("It's a static array\n");
2243 Expression *e = parseExpression(); // [ expression ]
2244 ta = new TypeSArray(t, e);
2245 check(TOKrbracket);
2248 /* Insert ta into
2249 * ts -> ... -> t
2250 * so that
2251 * ts -> ... -> ta -> t
2253 Type **pt;
2254 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2256 *pt = ta;
2257 continue;
2259 #endif
2260 case TOKlparen:
2262 if (tpl)
2264 /* Look ahead to see if this is (...)(...),
2265 * i.e. a function template declaration
2267 if (peekPastParen(&token)->value == TOKlparen)
2269 //printf("function template declaration\n");
2271 // Gather template parameter list
2272 *tpl = parseTemplateParameterList();
2276 int varargs;
2277 Arguments *arguments = parseParameters(&varargs);
2278 Type *tf = new TypeFunction(arguments, t, varargs, linkage);
2280 /* Parse const/invariant/nothrow postfix
2282 while (1)
2284 switch (token.value)
2286 case TOKconst:
2287 tf = tf->makeConst();
2288 nextToken();
2289 continue;
2291 case TOKinvariant:
2292 tf = tf->makeInvariant();
2293 nextToken();
2294 continue;
2296 case TOKnothrow:
2297 ((TypeFunction *)tf)->isnothrow = 1;
2298 nextToken();
2299 continue;
2301 case TOKpure:
2302 ((TypeFunction *)tf)->ispure = 1;
2303 nextToken();
2304 continue;
2306 break;
2309 /* Insert tf into
2310 * ts -> ... -> t
2311 * so that
2312 * ts -> ... -> tf -> t
2314 Type **pt;
2315 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2317 *pt = tf;
2318 break;
2321 break;
2324 return ts;
2327 /**********************************
2328 * Return array of Declaration *'s.
2331 Array *Parser::parseDeclarations()
2333 enum STC storage_class;
2334 enum STC stc;
2335 Type *ts;
2336 Type *t;
2337 Type *tfirst;
2338 Identifier *ident;
2339 Array *a;
2340 enum TOK tok;
2341 unsigned char *comment = token.blockComment;
2342 enum LINK link = linkage;
2344 //printf("parseDeclarations() %s\n", token.toChars());
2345 switch (token.value)
2347 case TOKtypedef:
2348 case TOKalias:
2349 tok = token.value;
2350 nextToken();
2351 break;
2353 default:
2354 tok = TOKreserved;
2355 break;
2358 storage_class = STCundefined;
2359 while (1)
2361 switch (token.value)
2363 case TOKconst:
2364 if (peek(&token)->value == TOKlparen)
2365 break;
2366 stc = STCconst;
2367 goto L1;
2369 case TOKinvariant:
2370 if (peek(&token)->value == TOKlparen)
2371 break;
2372 stc = STCinvariant;
2373 goto L1;
2375 case TOKstatic: stc = STCstatic; goto L1;
2376 case TOKfinal: stc = STCfinal; goto L1;
2377 case TOKauto: stc = STCauto; goto L1;
2378 case TOKscope: stc = STCscope; goto L1;
2379 case TOKoverride: stc = STCoverride; goto L1;
2380 case TOKabstract: stc = STCabstract; goto L1;
2381 case TOKsynchronized: stc = STCsynchronized; goto L1;
2382 case TOKdeprecated: stc = STCdeprecated; goto L1;
2383 case TOKnothrow: stc = STCnothrow; goto L1;
2384 case TOKpure: stc = STCpure; goto L1;
2385 case TOKtls: stc = STCtls; goto L1;
2386 case TOKenum: stc = STCmanifest; goto L1;
2388 if (storage_class & stc)
2389 error("redundant storage class '%s'", token.toChars());
2390 storage_class = (STC) (storage_class | stc);
2392 unsigned u = storage_class;
2393 u &= STCconst | STCinvariant | STCmanifest;
2394 if (u & (u - 1))
2395 error("conflicting storage class %s", Token::toChars(token.value));
2397 nextToken();
2398 continue;
2400 case TOKextern:
2401 if (peek(&token)->value != TOKlparen)
2402 { stc = STCextern;
2403 goto L1;
2406 link = parseLinkage();
2407 continue;
2409 default:
2410 break;
2412 break;
2415 a = new Array();
2417 /* Look for auto initializers:
2418 * storage_class identifier = initializer;
2420 while (storage_class &&
2421 token.value == TOKidentifier &&
2422 peek(&token)->value == TOKassign)
2424 ident = token.ident;
2425 nextToken();
2426 nextToken();
2427 Initializer *init = parseInitializer();
2428 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2429 v->storage_class = storage_class;
2430 v->dltNormalMode = dltNormalMode;
2431 a->push(v);
2432 if (token.value == TOKsemicolon || token.value == TOKendline)
2434 nextToken();
2435 addComment(v, comment);
2437 else if (token.value == TOKcomma)
2439 nextToken();
2440 if (!(token.value == TOKidentifier && peek(&token)->value == TOKassign))
2442 error("Identifier expected following comma");
2444 else
2445 continue;
2447 else
2448 error("%s expected following auto declaration, not '%s'", endToken(), token.toChars());
2449 return a;
2452 if (token.value == TOKclass)
2453 { AggregateDeclaration *s;
2455 s = (AggregateDeclaration *)parseAggregate();
2456 s->storage_class |= storage_class;
2457 a->push(s);
2458 addComment(s, comment);
2459 return a;
2462 ts = parseBasicType();
2463 ts = parseBasicType2(ts);
2464 tfirst = NULL;
2466 while (1)
2468 Loc loc = this->loc;
2469 TemplateParameters *tpl = NULL;
2471 ident = NULL;
2472 t = parseDeclarator(ts, &ident, &tpl);
2473 assert(t);
2474 if (!tfirst)
2475 tfirst = t;
2476 else if (t != tfirst)
2477 error("multiple declarations must have the same type, not %s and %s",
2478 tfirst->toChars(), t->toChars());
2479 if (!ident)
2480 error("no identifier for declarator %s", t->toChars());
2482 if (tok == TOKtypedef || tok == TOKalias)
2483 { Declaration *v;
2484 Initializer *init;
2486 init = NULL;
2487 if (token.value == TOKassign)
2489 nextToken();
2490 init = parseInitializer();
2492 if (tok == TOKtypedef)
2493 v = new TypedefDeclaration(loc, ident, t, init);
2494 else
2495 { if (init)
2496 error("alias cannot have initializer");
2497 v = new AliasDeclaration(loc, ident, t);
2499 v->storage_class = storage_class;
2500 if (link == linkage)
2501 a->push(v);
2502 else
2504 Array *ax = new Array();
2505 ax->push(v);
2506 Dsymbol *s = new LinkDeclaration(link, ax);
2507 a->push(s);
2509 switch (token.value)
2510 { case TOKsemicolon:
2511 case TOKendline:
2512 nextToken();
2513 addComment(v, comment);
2514 break;
2516 case TOKcomma:
2517 nextToken();
2518 addComment(v, comment);
2519 continue;
2521 default:
2522 error("%s expected to close %s declaration", endToken(), Token::toChars(tok));
2523 break;
2526 else if (t->ty == Tfunction)
2527 { FuncDeclaration *f;
2528 Dsymbol *s;
2530 f = new FuncDeclaration(loc, 0, ident, storage_class, t);
2531 addComment(f, comment);
2532 parseContracts(f);
2533 addComment(f, NULL);
2534 if (link == linkage)
2536 s = f;
2538 else
2540 Array *ax = new Array();
2541 ax->push(f);
2542 s = new LinkDeclaration(link, ax);
2544 if (tpl) // it's a function template
2545 { Array *decldefs;
2546 TemplateDeclaration *tempdecl;
2548 // Wrap a template around the aggregate declaration
2549 decldefs = new Array();
2550 decldefs->push(s);
2551 tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs, dltSyntax);
2552 s = tempdecl;
2554 addComment(s, comment);
2555 a->push(s);
2557 else
2558 { VarDeclaration *v;
2559 Initializer *init;
2561 init = NULL;
2562 if (token.value == TOKassign)
2564 nextToken();
2565 init = parseInitializer();
2567 v = new VarDeclaration(loc, t, ident, init);
2568 if (dltSyntax)
2569 v->requirePointerInit = true;
2570 v->storage_class = storage_class;
2571 v->dltNormalMode = dltNormalMode;
2572 if (link == linkage)
2573 a->push(v);
2574 else
2576 Array *ax = new Array();
2577 ax->push(v);
2578 Dsymbol *s = new LinkDeclaration(link, ax);
2579 a->push(s);
2581 switch (token.value)
2583 case TOKendline:
2584 nextToken();
2585 addComment(v, comment);
2586 break;
2587 case TOKsemicolon:
2588 if (!dltSyntax)
2589 nextToken();
2590 addComment(v, comment);
2591 break;
2592 case TOKcomma:
2593 nextToken();
2594 addComment(v, comment);
2595 continue;
2597 default:
2598 error("%s expected, not '%s'", endToken(), token.toChars());
2599 break;
2602 break;
2604 return a;
2607 /*****************************************
2608 * Parse contracts following function declaration.
2611 void Parser::parseContracts(FuncDeclaration *f)
2613 Type *tb;
2614 enum LINK linksave = linkage;
2616 // The following is irrelevant, as it is overridden by sc->linkage in
2617 // TypeFunction::semantic
2618 linkage = LINKd; // nested functions have D linkage
2620 switch (token.value)
2622 case TOKlcurly:
2623 case TOKcolon:
2624 if (token.value != startBlockTok)
2625 error("use %s to start a new block", Token::toChars(startBlockTok));
2626 if (f->frequire || f->fensure)
2627 error("missing body { ... } after in or out");
2628 f->fbody = parseStatement(PSsemi | PScolon);
2629 f->endloc = endloc;
2630 break;
2632 case TOKbody:
2633 nextToken();
2634 f->fbody = parseStatement(PScurly);
2635 f->endloc = endloc;
2636 break;
2638 case TOKsemicolon:
2639 if (dltSyntax)
2640 error("unexpected semi-colon after function declaration");
2641 // fall-through
2642 case TOKendline:
2643 if (f->frequire || f->fensure)
2644 error("missing body { ... } after in or out");
2645 nextToken();
2646 break;
2648 #if 0 // Do we want this for function declarations, so we can do:
2649 // int x, y, foo(), z;
2650 case TOKcomma:
2651 nextToken();
2652 continue;
2653 #endif
2655 #if 0 // Dumped feature
2656 case TOKthrow:
2657 if (!f->fthrows)
2658 f->fthrows = new Array();
2659 nextToken();
2660 check(TOKlparen);
2661 while (1)
2663 tb = parseBasicType();
2664 f->fthrows->push(tb);
2665 if (token.value == TOKcomma)
2666 { nextToken();
2667 continue;
2669 break;
2671 check(TOKrparen);
2672 goto L1;
2673 #endif
2675 case TOKin:
2676 nextToken();
2677 if (f->frequire)
2678 error("redundant 'in' statement");
2679 f->frequire = parseStatement(PScurly | PSscope);
2680 goto L1;
2682 case TOKout:
2683 // parse: out (identifier) { statement }
2684 nextToken();
2685 if (token.value != startBlockTok)
2687 check(TOKlparen);
2688 if (token.value != TOKidentifier)
2689 error("(identifier) following 'out' expected, not %s", token.toChars());
2690 f->outId = token.ident;
2691 nextToken();
2692 check(TOKrparen);
2694 if (f->fensure)
2695 error("redundant 'out' statement");
2696 f->fensure = parseStatement(PScurly | PSscope);
2697 goto L1;
2699 default:
2700 error("%s expected following function declaration", endToken());
2701 break;
2703 linkage = linksave;
2706 /*****************************************
2709 Initializer *Parser::parseInitializer()
2711 StructInitializer *is;
2712 ArrayInitializer *ia;
2713 ExpInitializer *ie;
2714 Expression *e;
2715 Identifier *id;
2716 Initializer *value;
2717 int comma;
2718 Loc loc = this->loc;
2719 Token *t;
2720 int braces;
2722 switch (token.value)
2724 case TOKlcurly:
2725 /* Scan ahead to see if it is a struct initializer or
2726 * a function literal.
2727 * If it contains a ';', it is a function literal.
2728 * Treat { } as a struct initializer.
2730 braces = 1;
2731 for (t = peek(&token); 1; t = peek(t))
2733 switch (t->value)
2735 case TOKsemicolon:
2736 case TOKreturn:
2737 goto Lexpression;
2739 case TOKlcurly:
2740 braces++;
2741 continue;
2743 case TOKrcurly:
2744 if (--braces == 0)
2745 break;
2746 continue;
2748 case TOKeof:
2749 break;
2751 default:
2752 continue;
2754 break;
2757 is = new StructInitializer(loc);
2758 nextToken();
2759 comma = 0;
2760 while (1)
2762 switch (token.value)
2764 case TOKidentifier:
2765 if (comma == 1)
2766 error("comma expected separating field initializers");
2767 t = peek(&token);
2768 if (t->value == TOKcolon)
2770 id = token.ident;
2771 nextToken();
2772 nextToken(); // skip over ':'
2774 else
2775 { id = NULL;
2777 value = parseInitializer();
2778 is->addInit(id, value);
2779 comma = 1;
2780 continue;
2782 case TOKcomma:
2783 nextToken();
2784 comma = 2;
2785 continue;
2787 case TOKrcurly: // allow trailing comma's
2788 nextToken();
2789 break;
2791 case TOKeof:
2792 error("found EOF instead of initializer");
2793 break;
2795 default:
2796 value = parseInitializer();
2797 is->addInit(NULL, value);
2798 comma = 1;
2799 continue;
2800 //error("found '%s' instead of field initializer", token.toChars());
2801 //break;
2803 break;
2805 return is;
2807 case TOKlbracket:
2808 ia = new ArrayInitializer(loc);
2809 nextToken();
2810 comma = 0;
2811 while (1)
2813 switch (token.value)
2815 default:
2816 if (comma == 1)
2817 { error("comma expected separating array initializers, not %s", token.toChars());
2818 nextToken();
2819 break;
2821 e = parseAssignExp();
2822 if (!e)
2823 break;
2824 if (token.value == TOKcolon)
2826 nextToken();
2827 value = parseInitializer();
2829 else
2830 { value = new ExpInitializer(e->loc, e);
2831 e = NULL;
2833 ia->addInit(e, value);
2834 comma = 1;
2835 continue;
2837 case TOKlcurly:
2838 case TOKlbracket:
2839 if (comma == 1)
2840 error("comma expected separating array initializers, not %s", token.toChars());
2841 value = parseInitializer();
2842 ia->addInit(NULL, value);
2843 comma = 1;
2844 continue;
2846 case TOKcomma:
2847 nextToken();
2848 comma = 2;
2849 continue;
2851 case TOKrbracket: // allow trailing comma's
2852 nextToken();
2853 break;
2855 case TOKeof:
2856 error("found '%s' instead of array initializer", token.toChars());
2857 break;
2859 break;
2861 return ia;
2863 case TOKvoid:
2864 t = peek(&token);
2865 if (t->value == TOKsemicolon || t->value == TOKcomma || t->value == TOKendline)
2867 nextToken();
2868 return new VoidInitializer(loc);
2870 goto Lexpression;
2872 default:
2873 Lexpression:
2874 e = parseAssignExp();
2875 ie = new ExpInitializer(loc, e);
2876 return ie;
2880 /*****************************************
2881 * Parses default argument initializer expression that is an assign expression,
2882 * with special handling for __FILE__ and __LINE__.
2885 Expression *Parser::parseDefaultInitExp()
2887 if (token.value == TOKfile ||
2888 token.value == TOKline)
2890 Token *t = peek(&token);
2891 if (t->value == TOKcomma || t->value == TOKrparen)
2892 { Expression *e;
2894 if (token.value == TOKfile)
2895 e = new FileInitExp(loc);
2896 else
2897 e = new LineInitExp(loc);
2898 nextToken();
2899 return e;
2903 Expression *e = parseAssignExp();
2904 return e;
2907 Statement *Parser::logStatement(int level) {
2908 nextToken();
2909 if (token.value != TOKlparen)
2910 error(loc, "found '%s' when expecting '('", token.toChars());
2911 return new LogStatement(loc, level, parseArguments());
2914 /*****************************************
2915 * Input:
2916 * flags PSxxxx
2919 Statement *DltParser::parseStatement(int flags)
2921 optionalEndline();
2922 if (flags & (PScolon | PSscope))
2923 flags |= PScurly;
2924 return Parser::parseStatement(flags);
2927 Statement *Parser::parseStatement(int flags)
2928 { Statement *s;
2929 Token *t;
2930 Condition *condition;
2931 Statement *ifbody;
2932 Statement *elsebody;
2933 Loc loc = this->loc;
2935 //printf("parseStatement()\n");
2937 if ((flags & PScurly) && token.value != startBlockTok)
2938 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
2940 int tok = token.value;
2942 switch (token.value)
2944 case TOKidentifier:
2945 if (!dltSyntax)
2947 // Need to look ahead to see if it is a declaration, label, or expression
2948 t = peek(&token);
2949 if (t->value == TOKcolon)
2950 { // It's a label
2951 Identifier *ident;
2953 ident = token.ident;
2954 nextToken();
2955 nextToken();
2956 s = parseStatement(PSsemi);
2957 s = new LabelStatement(loc, ident, s);
2958 break;
2961 // fallthrough to TOKdot
2962 case TOKdot:
2963 case TOKtypeof:
2964 if (isDeclaration(&token, 2, TOKreserved, NULL))
2965 goto Ldeclaration;
2966 else
2967 goto Lexp;
2968 break;
2970 case TOKassert:
2971 case TOKthis:
2972 case TOKsuper:
2973 case TOKint32v:
2974 case TOKuns32v:
2975 case TOKint64v:
2976 case TOKuns64v:
2977 case TOKfloat32v:
2978 case TOKfloat64v:
2979 case TOKfloat80v:
2980 case TOKimaginary32v:
2981 case TOKimaginary64v:
2982 case TOKimaginary80v:
2983 case TOKcharv:
2984 case TOKwcharv:
2985 case TOKdcharv:
2986 case TOKnull:
2987 case TOKtrue:
2988 case TOKfalse:
2989 case TOKstring:
2990 case TOKlparen:
2991 case TOKcast:
2992 case TOKmul:
2993 case TOKmin:
2994 case TOKadd:
2995 case TOKplusplus:
2996 case TOKminusminus:
2997 case TOKnew:
2998 case TOKdelete:
2999 case TOKdelegate:
3000 case TOKfunction:
3001 case TOKtypeid:
3002 case TOKis:
3003 case TOKlbracket:
3004 case TOKtraits:
3005 case TOKfile:
3006 case TOKline:
3007 Lexp:
3008 { Expression *exp;
3010 exp = parseExpression();
3011 if (!dltSyntax)
3012 check(TOKsemicolon, "statement");
3013 s = new ExpStatement(loc, exp);
3014 break;
3017 case TOKstatic:
3018 { // Look ahead to see if it's static assert() or static if()
3019 Token *t;
3021 t = peek(&token);
3022 if (t->value == TOKassert)
3024 nextToken();
3025 s = new StaticAssertStatement(parseStaticAssert());
3026 break;
3028 if (t->value == TOKif)
3030 nextToken();
3031 condition = parseStaticIfCondition();
3032 goto Lcondition;
3034 if (dltNormalMode)
3035 error("no static variables in Delight");
3036 goto Ldeclaration;
3039 CASE_BASIC_TYPES:
3040 case TOKtypedef:
3041 case TOKalias:
3042 case TOKconst:
3043 case TOKauto:
3044 case TOKextern:
3045 case TOKfinal:
3046 case TOKinvariant:
3047 // case TOKtypeof:
3048 Ldeclaration:
3049 { Array *a;
3051 a = parseDeclarations();
3052 if (a->dim > 1)
3054 Statements *as = new Statements();
3055 as->reserve(a->dim);
3056 for (int i = 0; i < a->dim; i++)
3058 Dsymbol *d = (Dsymbol *)a->data[i];
3059 s = new DeclarationStatement(loc, d);
3060 as->push(s);
3062 s = new CompoundStatement(loc, as);
3064 else if (a->dim == 1)
3066 Dsymbol *d = (Dsymbol *)a->data[0];
3067 s = new DeclarationStatement(loc, d);
3069 else
3070 assert(0);
3071 if (flags & PSscope)
3072 s = new ScopeStatement(loc, s);
3073 break;
3076 case TOKstruct:
3077 case TOKunion:
3078 case TOKclass:
3079 case TOKinterface:
3080 { Dsymbol *d;
3082 d = parseAggregate();
3083 s = new DeclarationStatement(loc, d);
3084 break;
3087 case TOKenum:
3088 { /* Determine if this is a manifest constant declaration,
3089 * or a conventional enum.
3091 Dsymbol *d;
3092 Token *t = peek(&token);
3093 if (t->value == TOKlcurly || t->value == TOKcolon)
3094 d = parseEnum();
3095 else if (t->value != TOKidentifier)
3096 goto Ldeclaration;
3097 else
3099 t = peek(t);
3100 if (t->value == TOKlcurly || t->value == TOKcolon ||
3101 t->value == TOKsemicolon)
3102 d = parseEnum();
3103 else
3104 goto Ldeclaration;
3106 s = new DeclarationStatement(loc, d);
3107 break;
3110 case TOKmixin:
3111 { t = peek(&token);
3112 if (t->value == TOKlparen)
3113 { // mixin(string)
3114 nextToken();
3115 check(TOKlparen, "mixin");
3116 Expression *e = parseAssignExp();
3117 check(TOKrparen);
3118 if (dltSyntax) {
3119 if (token.value != TOKsemicolon && token.value != TOKendline) {
3120 error("expected newline after mixin(), not '%s'", token.toChars());
3122 } else {
3123 check(TOKsemicolon);
3125 s = new CompileStatement(loc, e);
3126 break;
3128 Dsymbol *d = parseMixin();
3129 s = new DeclarationStatement(loc, d);
3130 break;
3133 case TOKcolon:
3134 case TOKlcurly:
3135 { Statements *statements;
3137 if (token.value != startBlockTok)
3138 error("statement expected to start with %s, not %s", Token::toChars(startBlockTok), token.toChars());
3140 nextToken();
3141 optionalEndline();
3142 statements = new Statements();
3143 while (token.value != TOKrcurly)
3145 statements->push(parseStatement(PSsemi | PScurlyscope));
3146 optionalEndline();
3148 endloc = this->loc;
3149 s = new CompoundStatement(loc, statements);
3150 if (flags & (PSscope | PScurlyscope))
3151 s = new ScopeStatement(loc, s);
3152 nextToken();
3153 break;
3156 case TOKlog_error: s = logStatement(LogStatement::Error); break;
3157 case TOKlog_warning: s = logStatement(LogStatement::Warn); break;
3158 case TOKlog_info: s = logStatement(LogStatement::Info); break;
3159 case TOKlog_trace: s = logStatement(LogStatement::Trace); break;
3161 case TOKwhile:
3162 { Expression *condition;
3163 Statement *body;
3165 nextToken();
3166 checkLParen();
3167 condition = parseExpression();
3168 checkRParen();
3169 body = parseStatement(PSscope);
3170 s = new WhileStatement(loc, condition, body);
3171 break;
3174 case TOKsemicolon:
3175 if (!(flags & PSsemi))
3176 error("use '{ }' for an empty statement, not a ';'");
3177 nextToken();
3178 s = new ExpStatement(loc, NULL);
3179 break;
3181 case TOKdo:
3182 { Statement *body;
3183 Expression *condition;
3185 nextToken();
3186 body = parseStatement(PSscope);
3187 check(TOKwhile);
3188 checkLParen();
3189 condition = parseExpression();
3190 checkRParen();
3191 s = new DoStatement(loc, body, condition);
3192 break;
3195 case TOKfor:
3197 Statement *init;
3198 Expression *condition;
3199 Expression *increment;
3200 Statement *body;
3202 nextToken();
3204 if (token.value == TOKlparen) {
3205 /* for (init; cond; incr): ... */
3206 nextToken();
3207 if (token.value == TOKsemicolon)
3208 { init = NULL;
3209 nextToken();
3211 else
3212 { init = parseStatement(0);
3213 if (dltSyntax)
3214 check(TOKsemicolon);
3216 if (token.value == TOKsemicolon)
3218 condition = NULL;
3219 nextToken();
3221 else
3223 condition = parseExpression();
3224 check(TOKsemicolon, "for condition");
3226 if (token.value == TOKrparen)
3227 { increment = NULL;
3228 nextToken();
3230 else
3231 { increment = parseExpression();
3232 check(TOKrparen);
3234 body = parseStatement(PSscope);
3235 s = new ForStatement(loc, init, condition, increment, body);
3236 if (init)
3237 s = new ScopeStatement(loc, s);
3238 } else if (dltSyntax)
3239 goto caseForeach;
3240 break;
3243 caseForeach:
3244 case TOKforeach:
3245 case TOKforeach_reverse:
3247 /* for var in seq: ... */
3248 /* for index, var in seq: ... */
3249 Arguments *arguments;
3251 Statement *d;
3252 Statement *body;
3253 Expression *aggr;
3254 enum TOK op = (TOK) tok;
3256 if (tok == TOKfor)
3257 op = TOKforeach; // Delight foreach syntax
3258 else
3259 nextToken();
3261 checkLParen();
3263 TOK inTok = dltSyntax ? TOKin : TOKsemicolon;
3265 arguments = new Arguments();
3267 while (1)
3269 Type *tb;
3270 Identifier *ai = NULL;
3271 Type *at;
3272 unsigned storageClass;
3273 Argument *a;
3275 storageClass = 0;
3276 if (token.value == TOKinout || token.value == TOKref)
3277 { storageClass = STCref;
3278 nextToken();
3280 if (token.value == TOKidentifier)
3282 Token *t = peek(&token);
3283 if (t->value == TOKcomma || t->value == inTok)
3284 { ai = token.ident;
3285 at = NULL; // infer argument type
3286 nextToken();
3287 goto Larg;
3290 at = parseType(&ai);
3291 if (!ai)
3292 error("no identifier for declarator %s", at->toChars());
3293 Larg:
3294 a = new Argument(storageClass, at, ai, NULL);
3295 arguments->push(a);
3296 if (token.value == TOKcomma)
3297 { nextToken();
3298 continue;
3300 break;
3303 check(inTok);
3305 aggr = parseExpression();
3306 if (token.value == TOKslice && arguments->dim == 1)
3308 Argument *a = (Argument *)arguments->data[0];
3309 delete arguments;
3310 nextToken();
3311 Expression *upr = parseExpression();
3312 checkRParen();
3313 if (token.value == TOKreserved)
3315 op = TOKforeach_reverse;
3316 nextToken();
3318 body = parseStatement(0);
3319 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3321 else
3323 checkRParen();
3324 if (token.value == TOKreserved)
3326 op = TOKforeach_reverse;
3327 nextToken();
3329 body = parseStatement(0);
3330 s = new ForeachStatement(loc, op, arguments, aggr, body);
3332 break;
3335 case TOKif:
3336 { Argument *arg = NULL;
3337 Expression *condition;
3338 Statement *ifbody;
3339 Statement *elsebody;
3341 nextToken();
3342 checkLParen();
3344 if (token.value == TOKauto)
3346 nextToken();
3347 if (token.value == TOKidentifier)
3349 Token *t = peek(&token);
3350 if (t->value == TOKassign)
3352 arg = new Argument(0, NULL, token.ident, NULL);
3353 nextToken();
3354 nextToken();
3356 else
3357 { error("= expected following auto identifier");
3358 goto Lerror;
3361 else
3362 { error("identifier expected following auto");
3363 goto Lerror;
3366 else if (isDeclaration(&token, 2, TOKassign, NULL))
3368 Type *at;
3369 Identifier *ai;
3371 at = parseType(&ai);
3372 check(TOKassign);
3373 arg = new Argument(0, at, ai, NULL);
3376 // Check for " ident;"
3377 else if (token.value == TOKidentifier && !dltSyntax)
3379 Token *t = peek(&token);
3380 if (t->value == TOKcomma || t->value == TOKsemicolon)
3382 arg = new Argument(0, NULL, token.ident, NULL);
3383 nextToken();
3384 nextToken();
3385 if (1 || !global.params.useDeprecated)
3386 error("if (v; e) is deprecated, use if (auto v = e)");
3390 condition = parseExpression();
3391 checkRParen();
3392 ifbody = parseStatement(PSscope);
3393 if (token.value == TOKelse)
3395 nextToken();
3396 if (dltSyntax)
3398 if (token.value == TOKcolon) {
3399 elsebody = parseStatement(PSscope);
3400 } else if (token.value == TOKif) {
3401 elsebody = parseStatement(0);
3402 } else {
3403 error("Expected 'else:' or 'else if', not 'else %s'", token.toChars());
3404 elsebody = NULL;
3407 else
3408 elsebody = parseStatement(PSscope);
3410 else
3411 elsebody = NULL;
3412 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3413 break;
3416 case TOKscope:
3417 if (peek(&token)->value != TOKlparen)
3418 goto Ldeclaration; // scope used as storage class
3419 nextToken();
3420 check(TOKlparen);
3421 if (token.value != TOKidentifier)
3422 { error("scope identifier expected");
3423 goto Lerror;
3425 else
3426 { TOK t = TOKon_scope_exit;
3427 Identifier *id = token.ident;
3429 if (id == Id::exit)
3430 t = TOKon_scope_exit;
3431 else if (id == Id::failure)
3432 t = TOKon_scope_failure;
3433 else if (id == Id::success)
3434 t = TOKon_scope_success;
3435 else
3436 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3437 nextToken();
3438 check(TOKrparen);
3439 Statement *st = parseStatement(PScolon | PScurlyscope);
3440 s = new OnScopeStatement(loc, t, st);
3441 break;
3444 case TOKdebug:
3445 nextToken();
3446 condition = parseDebugCondition();
3447 goto Lcondition;
3449 case TOKversion:
3450 nextToken();
3451 condition = parseVersionCondition();
3452 goto Lcondition;
3454 Lcondition:
3455 if (dltSyntax && token.value != TOKcolon)
3456 error("expected colon after condition, not '%s'", token.toChars());
3457 ifbody = parseStatement(PScolon /*PSsemi*/);
3458 elsebody = NULL;
3459 if (token.value == TOKelse)
3461 nextToken();
3462 elsebody = parseStatement(PScolon /*PSsemi*/);
3464 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3465 break;
3467 case TOKpragma:
3468 { Identifier *ident;
3469 Expressions *args = NULL;
3470 Statement *body;
3472 nextToken();
3473 check(TOKlparen);
3474 if (token.value != TOKidentifier)
3475 { error("pragma(identifier expected");
3476 goto Lerror;
3478 ident = token.ident;
3479 nextToken();
3480 if (token.value == TOKcomma)
3481 args = parseArguments(); // pragma(identifier, args...);
3482 else
3483 check(TOKrparen); // pragma(identifier);
3484 if (token.value == TOKsemicolon)
3485 { nextToken();
3486 body = NULL;
3488 else
3489 body = parseStatement(PSsemi | PScolon);
3490 s = new PragmaStatement(loc, ident, args, body);
3491 break;
3494 case TOKswitch:
3495 { Expression *condition;
3496 Statement *body;
3498 nextToken();
3499 checkLParen();
3500 condition = parseExpression();
3501 checkRParen();
3502 body = parseStatement(PSscope | PScolon);
3503 s = new SwitchStatement(loc, condition, body);
3504 break;
3507 case TOKcase:
3508 { Expression *exp;
3509 Statements *statements;
3510 Array cases; // array of Expression's
3512 while (1)
3514 nextToken();
3515 exp = parseAssignExp();
3516 cases.push(exp);
3517 if (token.value != TOKcomma)
3518 break;
3521 if (dltSyntax)
3523 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3525 else
3527 check(TOKcolon);
3529 statements = new Statements();
3530 while (token.value != TOKcase &&
3531 token.value != TOKdefault &&
3532 token.value != TOKrcurly)
3534 statements->push(parseStatement(PSsemi | PScurlyscope));
3536 s = new CompoundStatement(loc, statements);
3539 s = new ScopeStatement(loc, s);
3541 // Keep cases in order by building the case statements backwards
3542 for (int i = cases.dim; i; i--)
3544 exp = (Expression *)cases.data[i - 1];
3545 s = new CaseStatement(loc, exp, s);
3547 break;
3550 case TOKdefault:
3552 Statements *statements;
3554 nextToken();
3556 if (dltSyntax)
3558 s = parseStatement(PSsemi | PScurlyscope | PScolon);
3560 else
3562 check(TOKcolon);
3564 statements = new Statements();
3565 while (token.value != TOKcase &&
3566 token.value != TOKdefault &&
3567 token.value != TOKrcurly)
3569 statements->push(parseStatement(PSsemi | PScurlyscope));
3571 s = new CompoundStatement(loc, statements);
3574 s = new ScopeStatement(loc, s);
3575 s = new DefaultStatement(loc, s);
3576 break;
3579 case TOKreturn:
3580 { Expression *exp;
3582 nextToken();
3583 if (token.value == TOKsemicolon || token.value == TOKendline)
3584 exp = NULL;
3585 else
3586 exp = parseExpression();
3588 if (!dltSyntax)
3589 check(TOKsemicolon, "return statement");
3590 else if (token.value != TOKendline) {
3591 error("Expected end-of-line after return statement, but found '%s'", token.toChars());
3594 s = new ReturnStatement(loc, exp);
3595 break;
3598 case TOKbreak:
3599 { Identifier *ident;
3601 nextToken();
3602 if (token.value == TOKidentifier)
3603 { ident = token.ident;
3604 nextToken();
3606 else
3607 ident = NULL;
3608 if (token.value != TOKsemicolon && token.value != TOKendline) {
3609 error("expected %s after break, not '%s'", endToken(), token.toChars());
3611 if (!dltSyntax)
3612 nextToken();
3613 s = new BreakStatement(loc, ident);
3614 break;
3617 case TOKcontinue:
3618 { Identifier *ident;
3620 nextToken();
3621 if (token.value == TOKidentifier)
3622 { ident = token.ident;
3623 nextToken();
3625 else
3626 ident = NULL;
3627 check(TOKsemicolon, "continue statement");
3628 s = new ContinueStatement(loc, ident);
3629 break;
3632 case TOKgoto:
3633 { Identifier *ident;
3635 nextToken();
3636 if (token.value == TOKdefault)
3638 nextToken();
3639 s = new GotoDefaultStatement(loc);
3641 else if (token.value == TOKcase)
3643 Expression *exp = NULL;
3645 nextToken();
3646 if (token.value != TOKsemicolon)
3647 exp = parseExpression();
3648 s = new GotoCaseStatement(loc, exp);
3650 else
3652 if (token.value != TOKidentifier)
3653 { error("Identifier expected following goto");
3654 ident = NULL;
3656 else
3657 { ident = token.ident;
3658 nextToken();
3660 s = new GotoStatement(loc, ident);
3662 if (dltSyntax)
3664 if (token.value != TOKsemicolon && token.value != TOKendline) {
3665 error("expected %s after goto statement, not '%s'", endToken(), token.toChars());
3668 else
3669 check(TOKsemicolon);
3670 break;
3673 case TOKsynchronized:
3674 { Expression *exp;
3675 Statement *body;
3677 nextToken();
3678 if (token.value == TOKlparen)
3680 nextToken();
3681 exp = parseExpression();
3682 check(TOKrparen);
3684 else
3685 exp = NULL;
3686 body = parseStatement(PSscope);
3687 s = new SynchronizedStatement(loc, exp, body);
3688 break;
3691 case TOKwith:
3692 { Expression *exp;
3693 Statement *body;
3695 nextToken();
3696 check(TOKlparen);
3697 exp = parseExpression();
3698 check(TOKrparen);
3699 body = parseStatement(PSscope);
3700 s = new WithStatement(loc, exp, body);
3701 break;
3704 case TOKtry:
3705 { Statement *body;
3706 Array *catches = NULL;
3707 Statement *finalbody = NULL;
3709 nextToken();
3710 body = parseStatement(PSscope);
3711 while (token.value == TOKcatch)
3713 Statement *handler;
3714 Catch *c;
3715 Type *t;
3716 Identifier *id;
3717 Loc loc = this->loc;
3719 nextToken();
3720 if (token.value == startBlockTok)
3722 t = NULL;
3723 id = NULL;
3725 else
3727 checkLParen();
3728 id = NULL;
3729 t = parseType(&id);
3730 checkRParen();
3732 handler = parseStatement(PScolon);
3733 c = new Catch(loc, t, id, handler);
3734 if (!catches)
3735 catches = new Array();
3736 catches->push(c);
3739 if (token.value == TOKfinally)
3740 { nextToken();
3741 finalbody = parseStatement(PScolon);
3744 s = body;
3745 if (!catches && !finalbody)
3746 error("catch or finally expected following try");
3747 else
3748 { if (catches)
3749 s = new TryCatchStatement(loc, body, catches);
3750 if (finalbody)
3751 s = new TryFinallyStatement(loc, s, finalbody);
3753 break;
3756 case TOKthrow:
3757 { Expression *exp;
3759 nextToken();
3760 exp = parseExpression();
3761 if (token.value != TOKsemicolon && token.value != TOKendline) {
3762 error("%s expected after throw statement, not '%s'", endToken(), token.toChars());
3764 if (!dltSyntax)
3765 nextToken();
3766 s = new ThrowStatement(loc, exp);
3767 break;
3770 case TOKvolatile:
3771 nextToken();
3772 s = parseStatement(PSsemi | PScurlyscope);
3773 if (!global.params.useDeprecated)
3774 error("volatile statements deprecated; used synchronized statements instead");
3775 s = new VolatileStatement(loc, s);
3776 break;
3778 case TOKasm:
3779 { Statements *statements;
3780 Identifier *label;
3781 Loc labelloc;
3782 Token *toklist;
3783 Token **ptoklist;
3785 // Parse the asm block into a sequence of AsmStatements,
3786 // each AsmStatement is one instruction.
3787 // Separate out labels.
3788 // Defer parsing of AsmStatements until semantic processing.
3790 nextToken();
3791 #if GDC_EXTENDED_ASM_SYNTAX
3792 if (token.value == TOKlparen)
3794 nextToken();
3795 s = parseExtAsm(1);
3796 break;
3798 #endif
3799 check(startBlockTok);
3800 toklist = NULL;
3801 ptoklist = &toklist;
3802 label = NULL;
3803 statements = new Statements();
3804 while (1)
3806 switch (token.value)
3808 case TOKidentifier:
3809 if (!toklist)
3811 // Look ahead to see if it is a label
3812 t = peek(&token);
3813 if (t->value == TOKcolon)
3814 { // It's a label
3815 label = token.ident;
3816 labelloc = this->loc;
3817 nextToken();
3818 nextToken();
3819 continue;
3822 goto Ldefault;
3824 case TOKrcurly:
3825 if (toklist || label)
3827 error("asm statements must end in ';'");
3829 break;
3831 case TOKendline:
3832 case TOKsemicolon:
3833 s = NULL;
3834 if (toklist || label)
3835 { // Create AsmStatement from list of tokens we've saved
3836 s = new AsmStatement(this->loc, toklist);
3837 toklist = NULL;
3838 ptoklist = &toklist;
3839 if (label)
3840 { s = new LabelStatement(labelloc, label, s);
3841 label = NULL;
3843 statements->push(s);
3845 nextToken();
3846 continue;
3848 case TOKeof:
3849 /* { */
3850 error("matching '}' expected, not end of file");
3851 break;
3853 case TOKlparen:
3854 case TOKstring:
3855 // If the first token is a string or '(', parse as extended asm.
3856 if (! toklist)
3858 s = parseExtAsm(0);
3859 statements->push(s);
3860 continue;
3862 // ...else, drop through.
3864 default:
3865 Ldefault:
3866 *ptoklist = new Token();
3867 memcpy(*ptoklist, &token, sizeof(Token));
3868 ptoklist = &(*ptoklist)->next;
3869 *ptoklist = NULL;
3871 nextToken();
3872 continue;
3874 break;
3876 s = new CompoundStatement(loc, statements);
3877 nextToken();
3878 break;
3881 default:
3882 error("found '%s' instead of statement", token.toChars());
3883 goto Lerror;
3885 Lerror:
3886 while (token.value != TOKrcurly &&
3887 token.value != TOKsemicolon &&
3888 token.value != TOKeof)
3889 nextToken();
3890 if (token.value == TOKsemicolon)
3891 nextToken();
3892 s = NULL;
3893 break;
3896 return s;
3899 Statement *Parser::parseExtAsm(int expect_rparen)
3901 Expression * insnTemplate;
3902 Expressions * args = NULL;
3903 Array * argNames = NULL;
3904 Expressions * argConstraints = NULL;
3905 int nOutputArgs = 0;
3906 Expressions * clobbers = NULL;
3907 bool isInputPhase = false; // Output operands first, then input.
3909 insnTemplate = parseExpression();
3910 if (token.value == TOKrparen || token.value == TOKsemicolon)
3911 goto Ldone;
3912 check(TOKcolon);
3913 while (1) {
3914 Expression * arg = NULL;
3915 Identifier * name = NULL;
3916 Expression * constraint = NULL;
3918 switch (token.value)
3920 case TOKsemicolon:
3921 case TOKrparen:
3922 goto Ldone;
3924 case TOKcolon:
3925 nextToken();
3926 goto LnextPhase;
3928 case TOKeof:
3929 error("unterminated statement");
3931 case TOKlbracket:
3932 nextToken();
3933 if (token.value == TOKidentifier)
3935 name = token.ident;
3936 nextToken();
3938 else
3939 error("expected identifier after '['");
3940 check(TOKrbracket);
3941 // drop through
3942 default:
3943 constraint = parsePrimaryExp();
3944 if (constraint->op != TOKstring)
3945 error("expected constant string constraint for operand");
3946 arg = parseAssignExp();
3947 if (! args)
3949 args = new Expressions;
3950 argConstraints = new Expressions;
3951 argNames = new Array;
3953 args->push(arg);
3954 argNames->push(name);
3955 argConstraints->push(constraint);
3956 if (! isInputPhase)
3957 nOutputArgs++;
3959 if (token.value == TOKcomma)
3960 nextToken();
3961 break;
3963 continue;
3964 LnextPhase:
3965 if (! isInputPhase)
3966 isInputPhase = true;
3967 else
3968 break;
3971 while (1)
3973 Expression * clobber;
3975 switch (token.value)
3977 case TOKsemicolon:
3978 case TOKrparen:
3979 goto Ldone;
3981 case TOKeof:
3982 error("unterminated statement");
3984 default:
3985 clobber = parseAssignExp();
3986 if (clobber->op != TOKstring)
3987 error("expected constant string constraint for clobber name");
3988 if (! clobbers)
3989 clobbers = new Expressions;
3990 clobbers->push(clobber);
3992 if (token.value == TOKcomma)
3993 nextToken();
3994 break;
3997 Ldone:
3998 if (expect_rparen)
3999 check(TOKrparen);
4000 else
4001 check(TOKsemicolon);
4003 return new ExtAsmStatement(loc, insnTemplate, args, argNames,
4004 argConstraints, nOutputArgs, clobbers);
4007 void Parser::optionalEndline() {
4008 while (token.value == TOKendline) {
4009 nextToken();
4013 void Parser::check(enum TOK value)
4015 check(loc, value);
4018 void Parser::check(Loc loc, enum TOK value)
4020 if (token.value != value)
4021 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
4022 nextToken();
4025 void Parser::check(enum TOK value, char *string)
4027 if (token.value != value)
4028 error("found '%s' when expecting '%s' following '%s'",
4029 token.toChars(), Token::toChars(value), string);
4030 nextToken();
4033 char *Parser::endToken()
4035 return "semicolon";
4038 char *DltParser::endToken()
4040 return "newline";
4043 void Parser::checkLParen() { check(TOKlparen); }
4044 void Parser::checkRParen() { check(TOKrparen); }
4046 void DltParser::checkLParen() { }
4047 void DltParser::checkRParen() { }
4049 /************************************
4050 * Determine if the scanner is sitting on the start of a declaration.
4051 * Input:
4052 * needId 0 no identifier
4053 * 1 identifier optional
4054 * 2 must have identifier
4057 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
4059 int haveId = 0;
4061 if ((t->value == TOKconst || t->value == TOKinvariant) &&
4062 peek(t)->value != TOKlparen)
4063 { /* const type
4064 * invariant type
4066 t = peek(t);
4069 if (!isBasicType(&t))
4070 return FALSE;
4071 if (!isDeclarator(&t, &haveId, endtok))
4072 return FALSE;
4073 if ( needId == 1 ||
4074 (needId == 0 && !haveId) ||
4075 (needId == 2 && haveId))
4076 { if (pt)
4077 *pt = t;
4078 return TRUE;
4080 else
4081 return FALSE;
4084 int Parser::isBasicType(Token **pt)
4086 // This code parallels parseBasicType()
4087 Token *t = *pt;
4088 Token *t2;
4089 int parens;
4090 int haveId = 0;
4092 switch (t->value)
4094 CASE_BASIC_TYPES:
4095 t = peek(t);
4096 break;
4098 case TOKidentifier:
4099 t = peek(t);
4100 if (t->value == TOKnot)
4102 goto L4;
4104 goto L3;
4105 while (1)
4108 t = peek(t);
4110 if (t->value == TOKdot)
4112 Ldot:
4113 t = peek(t);
4114 if (t->value != TOKidentifier)
4115 goto Lfalse;
4116 t = peek(t);
4117 if (t->value != TOKnot)
4118 goto L3;
4120 t = peek(t);
4121 if (t->value != TOKlparen)
4122 goto Lfalse;
4123 if (!skipParens(t, &t))
4124 goto Lfalse;
4126 else
4127 break;
4129 break;
4131 case TOKdot:
4132 goto Ldot;
4134 case TOKtypeof:
4135 /* typeof(exp).identifier...
4137 t = peek(t);
4138 if (t->value != TOKlparen)
4139 goto Lfalse;
4140 if (!skipParens(t, &t))
4141 goto Lfalse;
4142 goto L2;
4144 case TOKconst:
4145 case TOKinvariant:
4146 // const(type) or invariant(type)
4147 t = peek(t);
4148 if (t->value != TOKlparen)
4149 goto Lfalse;
4150 t = peek(t);
4151 if (!isDeclaration(t, 0, TOKrparen, &t))
4152 goto Lfalse;
4153 t = peek(t);
4154 break;
4156 default:
4157 goto Lfalse;
4159 *pt = t;
4160 return TRUE;
4162 Lfalse:
4163 return FALSE;
4166 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
4167 { // This code parallels parseDeclarator()
4168 Token *t = *pt;
4169 int parens;
4171 //printf("Parser::isDeclarator()\n");
4172 //t->print();
4173 if (t->value == TOKassign)
4174 return FALSE;
4176 while (1)
4178 parens = FALSE;
4179 switch (t->value)
4181 case TOKquestion:
4182 case TOKmul:
4183 case TOKand:
4184 t = peek(t);
4185 continue;
4187 case TOKlbracket:
4188 t = peek(t);
4189 if (t->value == TOKrbracket)
4191 t = peek(t);
4193 else if (isDeclaration(t, 0, TOKrbracket, &t))
4194 { // It's an associative array declaration
4195 t = peek(t);
4197 else
4199 // [ expression ]
4200 // [ expression .. expression ]
4201 if (!isExpression(&t))
4202 return FALSE;
4203 if (t->value == TOKslice)
4204 { t = peek(t);
4205 if (!isExpression(&t))
4206 return FALSE;
4208 if (t->value != TOKrbracket)
4209 return FALSE;
4210 t = peek(t);
4212 continue;
4214 case TOKidentifier:
4215 if (*haveId)
4216 return FALSE;
4217 *haveId = TRUE;
4218 t = peek(t);
4219 break;
4221 case TOKlparen:
4222 t = peek(t);
4224 if (t->value == TOKrparen)
4225 return FALSE; // () is not a declarator
4227 /* Regard ( identifier ) as not a declarator
4228 * BUG: what about ( *identifier ) in
4229 * f(*p)(x);
4230 * where f is a class instance with overloaded () ?
4231 * Should we just disallow C-style function pointer declarations?
4233 if (t->value == TOKidentifier)
4234 { Token *t2 = peek(t);
4235 if (t2->value == TOKrparen)
4236 return FALSE;
4240 if (!isDeclarator(&t, haveId, TOKrparen))
4241 return FALSE;
4242 t = peek(t);
4243 parens = TRUE;
4244 break;
4246 case TOKdelegate:
4247 case TOKfunction:
4248 t = peek(t);
4249 if (!isParameters(&t))
4250 return FALSE;
4251 continue;
4253 break;
4256 while (1)
4258 switch (t->value)
4260 #if CARRAYDECL
4261 case TOKlbracket:
4262 parens = FALSE;
4263 t = peek(t);
4264 if (t->value == TOKrbracket)
4266 t = peek(t);
4268 else if (isDeclaration(t, 0, TOKrbracket, &t))
4269 { // It's an associative array declaration
4270 t = peek(t);
4272 else
4274 // [ expression ]
4275 if (!isExpression(&t))
4276 return FALSE;
4277 if (t->value != TOKrbracket)
4278 return FALSE;
4279 t = peek(t);
4281 continue;
4282 #endif
4284 case TOKlparen:
4285 parens = FALSE;
4286 if (!isParameters(&t))
4287 return FALSE;
4288 if (t->value == TOKconst || t->value == TOKinvariant)
4289 t = peek(t);
4290 continue;
4292 // Valid tokens that follow a declaration
4293 case TOKrparen:
4294 case TOKrbracket:
4295 case TOKassign:
4296 case TOKcomma:
4297 case TOKendline:
4298 case TOKsemicolon:
4299 case TOKlcurly:
4300 case TOKcolon:
4301 case TOKin:
4302 if ((dltSyntax && t->value == TOKlcurly) ||
4303 (!dltSyntax && t->value == TOKcolon)) {
4304 return FALSE;
4307 // The !parens is to disallow unnecessary parentheses
4308 if (!parens && (endtok == TOKreserved || endtok == t->value))
4309 { *pt = t;
4310 return TRUE;
4312 return FALSE;
4314 default:
4315 return FALSE;
4321 int Parser::isParameters(Token **pt)
4322 { // This code parallels parseParameters()
4323 Token *t = *pt;
4324 int tmp;
4326 //printf("isParameters()\n");
4327 if (t->value != TOKlparen)
4328 return FALSE;
4330 t = peek(t);
4331 for (;1; t = peek(t))
4333 switch (t->value)
4335 case TOKrparen:
4336 break;
4338 case TOKdotdotdot:
4339 t = peek(t);
4340 break;
4342 case TOKin:
4343 case TOKout:
4344 case TOKinout:
4345 case TOKref:
4346 case TOKlazy:
4347 case TOKconst:
4348 case TOKinvariant:
4349 case TOKfinal:
4350 case TOKstatic:
4351 continue;
4353 default:
4354 if (!isBasicType(&t))
4355 return FALSE;
4356 tmp = FALSE;
4357 if (t->value != TOKdotdotdot &&
4358 !isDeclarator(&t, &tmp, TOKreserved))
4359 return FALSE;
4360 if (t->value == TOKassign)
4361 { t = peek(t);
4362 if (!isExpression(&t))
4363 return FALSE;
4365 if (t->value == TOKdotdotdot)
4367 t = peek(t);
4368 break;
4370 if (t->value == TOKcomma)
4372 continue;
4374 break;
4376 break;
4378 if (t->value != TOKrparen)
4379 return FALSE;
4380 t = peek(t);
4381 *pt = t;
4382 return TRUE;
4385 int Parser::isExpression(Token **pt)
4387 // This is supposed to determine if something is an expression.
4388 // What it actually does is scan until a closing right bracket
4389 // is found.
4391 Token *t = *pt;
4392 int brnest = 0;
4393 int panest = 0;
4394 int curlynest = 0;
4396 for (;; t = peek(t))
4398 switch (t->value)
4400 case TOKlbracket:
4401 brnest++;
4402 continue;
4404 case TOKrbracket:
4405 if (--brnest >= 0)
4406 continue;
4407 break;
4409 case TOKlparen:
4410 panest++;
4411 continue;
4413 case TOKcomma:
4414 if (brnest || panest)
4415 continue;
4416 break;
4418 case TOKrparen:
4419 if (--panest >= 0)
4420 continue;
4421 break;
4423 case TOKlcurly:
4424 curlynest++;
4425 continue;
4427 case TOKrcurly:
4428 if (--curlynest >= 0)
4429 continue;
4430 return FALSE;
4432 case TOKslice:
4433 if (brnest)
4434 continue;
4435 break;
4437 case TOKsemicolon:
4438 if (curlynest)
4439 continue;
4440 return FALSE;
4442 case TOKeof:
4443 return FALSE;
4445 default:
4446 continue;
4448 break;
4451 *pt = t;
4452 return TRUE;
4455 /**********************************************
4456 * Skip over
4457 * instance foo.bar(parameters...)
4458 * Output:
4459 * if (pt), *pt is set to the token following the closing )
4460 * Returns:
4461 * 1 it's valid instance syntax
4462 * 0 invalid instance syntax
4465 int Parser::isTemplateInstance(Token *t, Token **pt)
4467 t = peek(t);
4468 if (t->value != TOKdot)
4470 if (t->value != TOKidentifier)
4471 goto Lfalse;
4472 t = peek(t);
4474 while (t->value == TOKdot)
4476 t = peek(t);
4477 if (t->value != TOKidentifier)
4478 goto Lfalse;
4479 t = peek(t);
4481 if (t->value != TOKlparen)
4482 goto Lfalse;
4484 // Skip over the template arguments
4485 while (1)
4487 while (1)
4489 t = peek(t);
4490 switch (t->value)
4492 case TOKlparen:
4493 if (!skipParens(t, &t))
4494 goto Lfalse;
4495 continue;
4496 case TOKrparen:
4497 break;
4498 case TOKcomma:
4499 break;
4500 case TOKeof:
4501 case TOKsemicolon:
4502 goto Lfalse;
4503 default:
4504 continue;
4506 break;
4509 if (t->value != TOKcomma)
4510 break;
4512 if (t->value != TOKrparen)
4513 goto Lfalse;
4514 t = peek(t);
4515 if (pt)
4516 *pt = t;
4517 return 1;
4519 Lfalse:
4520 return 0;
4523 /*******************************************
4524 * Skip parens, brackets.
4525 * Input:
4526 * t is on opening (
4527 * Output:
4528 * *pt is set to closing token, which is ')' on success
4529 * Returns:
4530 * !=0 successful
4531 * 0 some parsing error
4534 int Parser::skipParens(Token *t, Token **pt)
4536 int parens = 0;
4538 while (1)
4540 switch (t->value)
4542 case TOKlparen:
4543 parens++;
4544 break;
4546 case TOKrparen:
4547 parens--;
4548 if (parens < 0)
4549 goto Lfalse;
4550 if (parens == 0)
4551 goto Ldone;
4552 break;
4554 case TOKeof:
4555 case TOKsemicolon:
4556 goto Lfalse;
4558 default:
4559 break;
4561 t = peek(t);
4564 Ldone:
4565 if (*pt)
4566 *pt = t;
4567 return 1;
4569 Lfalse:
4570 return 0;
4573 /********************************* Expression Parser ***************************/
4575 Expression *Parser::parsePrimaryExp()
4576 { Expression *e;
4577 Type *t;
4578 Identifier *id;
4579 enum TOK save;
4580 Loc loc = this->loc;
4582 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4583 switch (token.value)
4585 case TOKidentifier:
4586 id = token.ident;
4587 nextToken();
4588 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
4589 { // identifier!(template-argument-list)
4590 TemplateInstance *tempinst;
4592 tempinst = new TemplateInstance(loc, id);
4593 nextToken();
4594 tempinst->tiargs = parseTemplateArgumentList();
4595 e = new ScopeExp(loc, tempinst);
4597 else
4598 e = new IdentifierExp(loc, id);
4599 break;
4601 case TOKdollar:
4602 if (!inBrackets)
4603 error("'$' is valid only inside [] of index or slice");
4604 e = new DollarExp(loc);
4605 nextToken();
4606 break;
4608 case TOKdot:
4609 // Signal global scope '.' operator with "" identifier
4610 e = new IdentifierExp(loc, Id::empty);
4611 break;
4613 case TOKthis:
4614 e = new ThisExp(loc);
4615 nextToken();
4616 break;
4618 case TOKsuper:
4619 e = new SuperExp(loc);
4620 nextToken();
4621 break;
4623 case TOKint32v:
4624 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
4625 nextToken();
4626 break;
4628 case TOKuns32v:
4629 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
4630 nextToken();
4631 break;
4633 case TOKint64v:
4634 e = new IntegerExp(loc, token.int64value, Type::tint64);
4635 nextToken();
4636 break;
4638 case TOKuns64v:
4639 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4640 nextToken();
4641 break;
4643 case TOKfloat32v:
4644 e = new RealExp(loc, token.float80value, Type::tfloat32);
4645 nextToken();
4646 break;
4648 case TOKfloat64v:
4649 e = new RealExp(loc, token.float80value, Type::tfloat64);
4650 nextToken();
4651 break;
4653 case TOKfloat80v:
4654 e = new RealExp(loc, token.float80value, Type::tfloat80);
4655 nextToken();
4656 break;
4658 case TOKimaginary32v:
4659 e = new RealExp(loc, token.float80value, Type::timaginary32);
4660 nextToken();
4661 break;
4663 case TOKimaginary64v:
4664 e = new RealExp(loc, token.float80value, Type::timaginary64);
4665 nextToken();
4666 break;
4668 case TOKimaginary80v:
4669 e = new RealExp(loc, token.float80value, Type::timaginary80);
4670 nextToken();
4671 break;
4673 case TOKnull:
4674 e = new NullExp(loc);
4675 ((NullExp *) e)->dUnchecked = !dltSyntax;
4676 nextToken();
4677 break;
4679 case TOKfile:
4680 { char *s = loc.filename ? loc.filename : mod->ident->toChars();
4681 e = new StringExp(loc, s, strlen(s), 0);
4682 nextToken();
4683 break;
4686 case TOKline:
4687 e = new IntegerExp(loc, loc.linnum, Type::tint32);
4688 nextToken();
4689 break;
4691 case TOKtrue:
4692 e = new IntegerExp(loc, 1, Type::tbool);
4693 nextToken();
4694 break;
4696 case TOKfalse:
4697 e = new IntegerExp(loc, 0, Type::tbool);
4698 nextToken();
4699 break;
4701 case TOKcharv:
4702 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tchar);
4703 nextToken();
4704 break;
4706 case TOKwcharv:
4707 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::twchar);
4708 nextToken();
4709 break;
4711 case TOKdcharv:
4712 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
4713 nextToken();
4714 break;
4716 case TOKstring:
4717 { unsigned char *s;
4718 unsigned len;
4719 unsigned char postfix;
4721 // cat adjacent strings
4722 s = token.ustring;
4723 len = token.len;
4724 postfix = token.postfix;
4725 while (1)
4727 nextToken();
4728 if (token.value == TOKstring)
4729 { unsigned len1;
4730 unsigned len2;
4731 unsigned char *s2;
4733 if (token.postfix)
4734 { if (token.postfix != postfix)
4735 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4736 postfix = token.postfix;
4739 len1 = len;
4740 len2 = token.len;
4741 len = len1 + len2;
4742 s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
4743 memcpy(s2, s, len1 * sizeof(unsigned char));
4744 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
4745 s = s2;
4747 else
4748 break;
4750 e = new StringExp(loc, s, len, postfix);
4751 break;
4754 CASE_BASIC_TYPES_X(t):
4755 nextToken();
4757 check(TOKdot, t->toChars());
4758 if (token.value != TOKidentifier)
4759 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
4760 goto Lerr;
4762 e = new TypeDotIdExp(loc, t, token.ident);
4763 nextToken();
4764 break;
4766 case TOKtypeof:
4768 t = parseTypeof();
4769 if (token.value == TOKdot)
4770 goto L1;
4771 e = new TypeExp(loc, t);
4772 break;
4775 case TOKtypeid:
4776 { Type *t;
4778 nextToken();
4779 check(TOKlparen, "typeid");
4780 t = parseType(); // ( type )
4781 check(TOKrparen);
4782 e = new TypeidExp(loc, t);
4783 break;
4786 case TOKtraits:
4787 { /* __traits(identifier, args...)
4789 Identifier *ident;
4790 Objects *args = NULL;
4792 nextToken();
4793 check(TOKlparen);
4794 if (token.value != TOKidentifier)
4795 { error("__traits(identifier, args...) expected");
4796 goto Lerr;
4798 ident = token.ident;
4799 nextToken();
4800 if (token.value == TOKcomma)
4801 args = parseTemplateArgumentList2(); // __traits(identifier, args...)
4802 else
4803 check(TOKrparen); // __traits(identifier)
4805 e = new TraitsExp(loc, ident, args);
4806 break;
4809 case TOKis:
4810 { Type *targ;
4811 Identifier *ident = NULL;
4812 Type *tspec = NULL;
4813 enum TOK tok = TOKreserved;
4814 enum TOK tok2 = TOKreserved;
4815 TemplateParameters *tpl = NULL;
4816 Loc loc = this->loc;
4818 nextToken();
4819 if (token.value == TOKlparen)
4821 nextToken();
4822 targ = parseType(&ident);
4823 if (token.value == TOKcolon || token.value == TOKequal)
4825 tok = token.value;
4826 nextToken();
4827 if (tok == TOKequal &&
4828 (token.value == TOKtypedef ||
4829 token.value == TOKstruct ||
4830 token.value == TOKunion ||
4831 token.value == TOKclass ||
4832 token.value == TOKsuper ||
4833 token.value == TOKenum ||
4834 token.value == TOKinterface ||
4835 token.value == TOKconst && peek(&token)->value == TOKrparen ||
4836 token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
4837 token.value == TOKfunction ||
4838 token.value == TOKdelegate ||
4839 token.value == TOKreturn))
4841 tok2 = token.value;
4842 nextToken();
4844 else
4846 tspec = parseType();
4849 if (ident && tspec)
4851 if (token.value == TOKcomma)
4852 tpl = parseTemplateParameterList(1);
4853 else
4854 { tpl = new TemplateParameters();
4855 check(TOKrparen);
4857 TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
4858 tpl->insert(0, tp);
4860 else
4861 check(TOKrparen);
4863 else
4864 { error("(type identifier : specialization) expected following is");
4865 goto Lerr;
4867 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
4868 break;
4871 case TOKassert:
4872 { Expression *msg = NULL;
4874 nextToken();
4876 checkLParen();
4877 e = parseAssignExp();
4878 if (token.value == (dltSyntax ? TOKelse : TOKcomma))
4879 { nextToken();
4880 msg = parseAssignExp();
4881 } else if (token.value == TOKcomma)
4882 error("Suspicious comma after assert; try 'else' instead");
4883 checkRParen();
4885 e = new AssertExp(loc, e, msg);
4886 break;
4889 case TOKmixin:
4891 nextToken();
4892 check(TOKlparen, "mixin");
4893 e = parseAssignExp();
4894 check(TOKrparen);
4895 e = new CompileExp(loc, e);
4896 break;
4899 case TOKimport:
4901 nextToken();
4902 check(TOKlparen, "import");
4903 e = parseAssignExp();
4904 check(TOKrparen);
4905 e = new FileExp(loc, e);
4906 break;
4909 case TOKlparen:
4910 if (peekPastParen(&token)->value == startBlockTok)
4911 { // (arguments) { statements... }
4912 save = TOKdelegate;
4913 goto case_delegate;
4915 // ( expression )
4916 nextToken();
4917 e = parseExpression();
4918 check(loc, TOKrparen);
4919 break;
4921 case TOKlbracket:
4922 { /* Parse array literals and associative array literals:
4923 * [ value, value, value ... ]
4924 * [ key:value, key:value, key:value ... ]
4926 Expressions *values = new Expressions();
4927 Expressions *keys = NULL;
4929 nextToken();
4930 if (token.value != TOKrbracket)
4932 while (1)
4934 Expression *e = parseAssignExp();
4935 if (token.value == TOKcolon && (keys || values->dim == 0))
4936 { nextToken();
4937 if (!keys)
4938 keys = new Expressions();
4939 keys->push(e);
4940 e = parseAssignExp();
4942 else if (keys)
4943 { error("'key:value' expected for associative array literal");
4944 delete keys;
4945 keys = NULL;
4947 values->push(e);
4948 if (token.value == TOKrbracket)
4949 break;
4950 check(TOKcomma);
4953 check(TOKrbracket);
4955 if (keys)
4956 e = new AssocArrayLiteralExp(loc, keys, values);
4957 else
4958 e = new ArrayLiteralExp(loc, values);
4959 break;
4962 case TOKlcurly:
4963 // { statements... }
4964 save = TOKdelegate;
4965 goto case_delegate;
4967 case TOKfunction:
4968 case TOKdelegate:
4969 save = token.value;
4970 nextToken();
4971 case_delegate:
4973 /* function type(parameters) { body }
4974 * delegate type(parameters) { body }
4975 * (parameters) { body }
4976 * { body }
4978 Arguments *arguments;
4979 int varargs;
4980 FuncLiteralDeclaration *fd;
4981 Type *t;
4982 bool isnothrow = false;
4983 bool ispure = false;
4985 if (token.value == startBlockTok)
4987 t = NULL;
4988 varargs = 0;
4989 arguments = new Arguments();
4991 else
4993 if (token.value == TOKlparen)
4994 t = NULL;
4995 else
4997 t = parseBasicType();
4998 t = parseBasicType2(t); // function return type
5000 arguments = parseParameters(&varargs);
5001 while (1)
5003 if (token.value == TOKpure)
5004 ispure = true;
5005 else if (token.value == TOKnothrow)
5006 isnothrow = true;
5007 else
5008 break;
5009 nextToken();
5012 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage);
5013 tf->ispure = ispure;
5014 tf->isnothrow = isnothrow;
5015 fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
5016 if (dltSyntax)
5018 check(TOKcolon);
5019 if (!nesting)
5020 indent--; // This colon doesn't start a new indent level
5021 fd->fbody = new ReturnStatement(loc, parseAssignExp());
5022 fd->endloc = loc;
5024 else
5026 parseContracts(fd);
5028 e = new FuncExp(loc, fd);
5029 break;
5032 default:
5033 error("expression expected, not '%s'", token.toChars());
5034 Lerr:
5035 // Anything for e, as long as it's not NULL
5036 e = new IntegerExp(loc, 0, Type::tint32);
5037 nextToken();
5038 break;
5040 return parsePostExp(e);
5043 Expression *Parser::parsePostExp(Expression *e)
5045 Loc loc;
5047 while (1)
5049 loc = this->loc;
5050 switch (token.value)
5052 case TOKdot:
5053 nextToken();
5054 if (token.value == TOKidentifier)
5055 { Identifier *id = token.ident;
5057 nextToken();
5058 if (token.value == TOKnot && peek(&token)->value == TOKlparen)
5059 { // identifier!(template-argument-list)
5060 TemplateInstance *tempinst;
5062 tempinst = new TemplateInstance(loc, id);
5063 nextToken();
5064 tempinst->tiargs = parseTemplateArgumentList();
5065 e = new DotTemplateInstanceExp(loc, e, tempinst);
5067 else
5068 e = new DotIdExp(loc, e, id);
5069 continue;
5071 else if (token.value == TOKnew)
5073 e = parseNewExp(e);
5074 continue;
5076 else
5077 error("identifier expected following '.', not '%s'", token.toChars());
5078 break;
5080 case TOKplusplus:
5081 e = new PostExp(TOKplusplus, loc, e);
5082 break;
5084 case TOKminusminus:
5085 e = new PostExp(TOKminusminus, loc, e);
5086 break;
5088 case TOKlparen:
5089 e = new CallExp(loc, e, parseArguments());
5090 continue;
5092 case TOKlbracket:
5093 { // array dereferences:
5094 // array[index]
5095 // array[]
5096 // array[lwr .. upr]
5097 Expression *index;
5098 Expression *upr;
5100 inBrackets++;
5101 nextToken();
5102 if (token.value == TOKrbracket)
5103 { // array[]
5104 e = new SliceExp(loc, e, NULL, NULL);
5105 nextToken();
5107 else
5109 index = parseAssignExp();
5110 if (token.value == TOKslice)
5111 { // array[lwr .. upr]
5112 nextToken();
5113 upr = parseAssignExp();
5114 e = new SliceExp(loc, e, index, upr);
5116 else
5117 { // array[index, i2, i3, i4, ...]
5118 Expressions *arguments = new Expressions();
5119 arguments->push(index);
5120 if (token.value == TOKcomma)
5122 nextToken();
5123 while (1)
5124 { Expression *arg;
5126 arg = parseAssignExp();
5127 arguments->push(arg);
5128 if (token.value == TOKrbracket)
5129 break;
5130 check(TOKcomma);
5133 e = new ArrayExp(loc, e, arguments);
5135 check(TOKrbracket);
5136 inBrackets--;
5138 continue;
5141 default:
5142 return e;
5144 nextToken();
5148 Expression *Parser::parseUnaryExp()
5149 { Expression *e;
5150 Loc loc = this->loc;
5152 switch (token.value)
5154 case TOKand:
5155 nextToken();
5156 e = parseUnaryExp();
5157 e = new AddrExp(loc, e);
5158 break;
5160 case TOKplusplus:
5161 nextToken();
5162 e = parseUnaryExp();
5163 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5164 break;
5166 case TOKminusminus:
5167 nextToken();
5168 e = parseUnaryExp();
5169 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5170 break;
5172 case TOKmul:
5173 nextToken();
5174 e = parseUnaryExp();
5175 e = new PtrExp(loc, e);
5176 break;
5178 case TOKmin:
5179 nextToken();
5180 e = parseUnaryExp();
5181 e = new NegExp(loc, e);
5182 break;
5184 case TOKadd:
5185 nextToken();
5186 e = parseUnaryExp();
5187 e = new UAddExp(loc, e);
5188 break;
5190 case TOKnot:
5191 nextToken();
5192 e = parseUnaryExp();
5193 e = new NotExp(loc, e);
5194 break;
5196 case TOKtilde:
5197 nextToken();
5198 e = parseUnaryExp();
5199 e = new ComExp(loc, e);
5200 break;
5202 case TOKdelete:
5203 nextToken();
5204 e = parseUnaryExp();
5205 e = new DeleteExp(loc, e);
5206 break;
5208 case TOKnew:
5209 e = parseNewExp(NULL);
5210 break;
5212 case TOKcast: // cast(type) expression
5213 { Type *t;
5215 nextToken();
5216 check(TOKlparen);
5217 /* Look for cast(const) and cast(invariant)
5219 if ((token.value == TOKconst || token.value == TOKinvariant) &&
5220 peek(&token)->value == TOKrparen)
5221 { enum TOK tok = token.value;
5222 nextToken();
5223 nextToken();
5224 e = parseUnaryExp();
5225 e = new CastExp(loc, e, tok);
5227 else
5229 t = parseType(); // ( type )
5230 check(TOKrparen);
5231 e = parseUnaryExp();
5232 e = new CastExp(loc, e, t);
5234 break;
5237 case TOKlparen:
5238 { Token *tk;
5240 tk = peek(&token);
5241 #if CCASTSYNTAX
5242 // If cast
5243 if (isDeclaration(tk, 0, TOKrparen, &tk))
5245 tk = peek(tk); // skip over right parenthesis
5246 switch (tk->value)
5248 case TOKdot:
5249 case TOKplusplus:
5250 case TOKminusminus:
5251 case TOKnot:
5252 case TOKdelete:
5253 case TOKnew:
5254 case TOKlparen:
5255 case TOKidentifier:
5256 case TOKthis:
5257 case TOKsuper:
5258 case TOKint32v:
5259 case TOKuns32v:
5260 case TOKint64v:
5261 case TOKuns64v:
5262 case TOKfloat32v:
5263 case TOKfloat64v:
5264 case TOKfloat80v:
5265 case TOKimaginary32v:
5266 case TOKimaginary64v:
5267 case TOKimaginary80v:
5268 case TOKnull:
5269 case TOKtrue:
5270 case TOKfalse:
5271 case TOKcharv:
5272 case TOKwcharv:
5273 case TOKdcharv:
5274 case TOKstring:
5275 #if 0
5276 case TOKtilde:
5277 case TOKand:
5278 case TOKmul:
5279 case TOKmin:
5280 case TOKadd:
5281 #endif
5282 case TOKfunction:
5283 case TOKdelegate:
5284 case TOKtypeof:
5285 case TOKfile:
5286 case TOKline:
5287 CASE_BASIC_TYPES: // (type)int.size
5288 { // (type) una_exp
5289 Type *t;
5291 nextToken();
5292 t = parseType();
5293 check(TOKrparen);
5295 // if .identifier
5296 if (token.value == TOKdot)
5298 nextToken();
5299 if (token.value != TOKidentifier)
5300 { error("Identifier expected following (type).");
5301 return NULL;
5303 e = new TypeDotIdExp(loc, t, token.ident);
5304 nextToken();
5305 e = parsePostExp(e);
5307 else
5309 e = parseUnaryExp();
5310 e = new CastExp(loc, e, t);
5311 error("C style cast illegal, use %s", e->toChars());
5313 return e;
5317 #endif
5318 e = parsePrimaryExp();
5319 break;
5321 default:
5322 e = parsePrimaryExp();
5323 break;
5325 assert(e);
5326 return e;
5329 Expression *Parser::parseMulExp()
5330 { Expression *e;
5331 Expression *e2;
5332 Loc loc = this->loc;
5334 e = parseUnaryExp();
5335 while (1)
5337 switch (token.value)
5339 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5340 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5341 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5343 default:
5344 break;
5346 break;
5348 return e;
5351 Expression *Parser::parseAddExp()
5352 { Expression *e;
5353 Expression *e2;
5354 Loc loc = this->loc;
5356 e = parseMulExp();
5357 while (1)
5359 switch (token.value)
5361 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5362 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5363 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5365 default:
5366 break;
5368 break;
5370 return e;
5373 Expression *Parser::parseShiftExp()
5374 { Expression *e;
5375 Expression *e2;
5376 Loc loc = this->loc;
5378 e = parseAddExp();
5379 while (1)
5381 switch (token.value)
5383 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5384 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5385 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5387 default:
5388 break;
5390 break;
5392 return e;
5395 Expression *Parser::parseRelExp()
5396 { Expression *e;
5397 Expression *e2;
5398 enum TOK op;
5399 Loc loc = this->loc;
5401 e = parseShiftExp();
5402 while (1)
5404 switch (token.value)
5406 case TOKlt:
5407 case TOKle:
5408 case TOKgt:
5409 case TOKge:
5410 case TOKunord:
5411 case TOKlg:
5412 case TOKleg:
5413 case TOKule:
5414 case TOKul:
5415 case TOKuge:
5416 case TOKug:
5417 case TOKue:
5418 op = token.value;
5419 nextToken();
5420 e2 = parseShiftExp();
5421 e = new CmpExp(op, loc, e, e2);
5422 continue;
5424 case TOKin:
5425 nextToken();
5426 e2 = parseShiftExp();
5427 e = new InExp(loc, e, e2);
5428 continue;
5430 default:
5431 break;
5433 break;
5435 return e;
5438 Expression *Parser::parseEqualExp()
5439 { Expression *e;
5440 Expression *e2;
5441 Token *t;
5442 Loc loc = this->loc;
5444 e = parseRelExp();
5445 while (1)
5446 { enum TOK value = token.value;
5448 switch (value)
5450 case TOKequal:
5451 case TOKnotequal:
5452 nextToken();
5453 e2 = parseRelExp();
5454 e = new EqualExp(value, loc, e, e2);
5455 continue;
5457 case TOKidentity:
5458 error("'===' is no longer legal, use 'is' instead");
5459 goto L1;
5461 case TOKnotidentity:
5462 error("'!==' is no longer legal, use '!is' instead");
5463 goto L1;
5465 case TOKis:
5466 value = TOKidentity;
5467 error("TOKis");
5468 if (dltSyntax)
5470 t = peek(&token);
5471 error("next: %s", t->toChars());
5472 if (t->value == TOKnot)
5474 // X is not Y
5475 value = TOKnotidentity;
5476 nextToken();
5479 goto L1;
5481 case TOKnot:
5482 // Attempt to identify '!is'
5483 t = peek(&token);
5484 if (t->value != TOKis)
5485 break;
5486 nextToken();
5487 value = TOKnotidentity;
5488 goto L1;
5491 nextToken();
5492 e2 = parseRelExp();
5493 e = new IdentityExp(value, loc, e, e2);
5494 continue;
5496 default:
5497 break;
5499 break;
5501 return e;
5504 Expression *Parser::parseCmpExp()
5505 { Expression *e;
5506 Expression *e2;
5507 Token *t;
5508 Loc loc = this->loc;
5510 e = parseShiftExp();
5511 enum TOK op = token.value;
5513 switch (op)
5515 case TOKequal:
5516 case TOKnotequal:
5517 nextToken();
5518 e2 = parseShiftExp();
5519 e = new EqualExp(op, loc, e, e2);
5520 break;
5522 case TOKis:
5523 op = TOKidentity;
5524 if (dltSyntax)
5526 t = peek(&token);
5527 if (t->value == TOKnot)
5529 // X is not Y
5530 op = TOKnotidentity;
5531 nextToken();
5534 goto L1;
5536 case TOKnot:
5537 // Attempt to identify '!is'
5538 t = peek(&token);
5539 if (t->value != TOKis)
5540 break;
5541 nextToken();
5542 op = TOKnotidentity;
5543 goto L1;
5546 nextToken();
5547 e2 = parseShiftExp();
5548 e = new IdentityExp(op, loc, e, e2);
5549 break;
5551 case TOKlt:
5552 case TOKle:
5553 case TOKgt:
5554 case TOKge:
5555 case TOKunord:
5556 case TOKlg:
5557 case TOKleg:
5558 case TOKule:
5559 case TOKul:
5560 case TOKuge:
5561 case TOKug:
5562 case TOKue:
5563 nextToken();
5564 e2 = parseShiftExp();
5565 e = new CmpExp(op, loc, e, e2);
5566 break;
5568 case TOKin:
5569 nextToken();
5570 e2 = parseShiftExp();
5571 e = new InExp(loc, e, e2);
5572 break;
5574 default:
5575 break;
5577 return e;
5580 Expression *Parser::parseAndExp()
5581 { Expression *e;
5582 Expression *e2;
5583 Loc loc = this->loc;
5585 if (global.params.Dversion == 1)
5587 e = parseEqualExp();
5588 while (token.value == TOKand)
5590 nextToken();
5591 e2 = parseEqualExp();
5592 e = new AndExp(loc,e,e2);
5593 loc = this->loc;
5596 else
5598 e = parseCmpExp();
5599 while (token.value == TOKand)
5601 nextToken();
5602 e2 = parseCmpExp();
5603 e = new AndExp(loc,e,e2);
5604 loc = this->loc;
5607 return e;
5610 Expression *Parser::parseXorExp()
5611 { Expression *e;
5612 Expression *e2;
5613 Loc loc = this->loc;
5615 e = parseAndExp();
5616 while (token.value == TOKxor)
5618 nextToken();
5619 e2 = parseAndExp();
5620 e = new XorExp(loc, e, e2);
5622 return e;
5625 Expression *Parser::parseOrExp()
5626 { Expression *e;
5627 Expression *e2;
5628 Loc loc = this->loc;
5630 e = parseXorExp();
5631 while (token.value == TOKor)
5633 nextToken();
5634 e2 = parseXorExp();
5635 e = new OrExp(loc, e, e2);
5637 return e;
5640 Expression *Parser::parseAndAndExp()
5641 { Expression *e;
5642 Expression *e2;
5643 Loc loc = this->loc;
5645 e = parseOrExp();
5646 while (token.value == TOKandand)
5648 nextToken();
5649 e2 = parseOrExp();
5650 e = new AndAndExp(loc, e, e2);
5652 return e;
5655 Expression *Parser::parseOrOrExp()
5656 { Expression *e;
5657 Expression *e2;
5658 Loc loc = this->loc;
5660 e = parseAndAndExp();
5661 while (token.value == TOKoror)
5663 nextToken();
5664 e2 = parseAndAndExp();
5665 e = new OrOrExp(loc, e, e2);
5667 return e;
5670 Expression *Parser::parseCondExp()
5671 { Expression *e;
5672 Expression *e1;
5673 Expression *e2;
5674 Loc loc = this->loc;
5676 e = parseOrOrExp();
5677 if (token.value == TOKquestion)
5679 nextToken();
5680 e1 = parseExpression();
5681 check(TOKcolon);
5682 e2 = parseCondExp();
5683 e = new CondExp(loc, e, e1, e2);
5685 return e;
5688 Expression *DltParser::parseCondExp()
5689 { Expression *e;
5690 Expression *e1;
5691 Expression *e2;
5692 Loc loc = this->loc;
5694 e = parseOrOrExp();
5695 if (token.value == TOKif)
5697 nextToken();
5698 e1 = parseExpression();
5699 check(TOKelse);
5700 e2 = parseCondExp();
5701 e = new CondExp(loc, e1, e, e2);
5703 return e;
5706 Expression *Parser::parseAssignExp()
5707 { Expression *e;
5708 Expression *e2;
5709 Loc loc;
5711 e = parseCondExp();
5712 while (1)
5714 loc = this->loc;
5715 switch (token.value)
5717 #define X(tok,ector) \
5718 case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
5720 X(TOKassign, AssignExp);
5721 X(TOKaddass, AddAssignExp);
5722 X(TOKminass, MinAssignExp);
5723 X(TOKmulass, MulAssignExp);
5724 X(TOKdivass, DivAssignExp);
5725 X(TOKmodass, ModAssignExp);
5726 X(TOKandass, AndAssignExp);
5727 X(TOKorass, OrAssignExp);
5728 X(TOKxorass, XorAssignExp);
5729 X(TOKshlass, ShlAssignExp);
5730 X(TOKshrass, ShrAssignExp);
5731 X(TOKushrass, UshrAssignExp);
5732 X(TOKcatass, CatAssignExp);
5734 #undef X
5735 default:
5736 break;
5738 break;
5740 return e;
5743 Expression *Parser::parseExpression()
5744 { Expression *e;
5745 Expression *e2;
5746 Loc loc = this->loc;
5748 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
5749 e = parseAssignExp();
5750 while (token.value == TOKcomma)
5752 nextToken();
5753 e2 = parseAssignExp();
5754 e = new CommaExp(loc, e, e2);
5755 loc = this->loc;
5757 return e;
5761 /*************************
5762 * Collect argument list.
5763 * Assume current token is '(' or '['.
5766 Expressions *Parser::parseArguments()
5767 { // function call
5768 Expressions *arguments;
5769 Expression *arg;
5770 enum TOK endtok;
5772 arguments = new Expressions();
5773 if (token.value == TOKlbracket)
5774 endtok = TOKrbracket;
5775 else
5776 endtok = TOKrparen;
5779 nextToken();
5780 if (token.value != endtok)
5782 while (1)
5784 arg = parseAssignExp();
5785 arguments->push(arg);
5786 if (token.value == endtok)
5787 break;
5788 check(TOKcomma);
5791 check(endtok);
5793 return arguments;
5796 /*******************************************
5799 Expression *Parser::parseNewExp(Expression *thisexp)
5800 { Type *t;
5801 Expressions *newargs;
5802 Expressions *arguments = NULL;
5803 Expression *e;
5804 Loc loc = this->loc;
5806 nextToken();
5807 newargs = NULL;
5808 if (token.value == TOKlparen)
5810 newargs = parseArguments();
5813 // An anonymous nested class starts with "class"
5814 if (token.value == TOKclass)
5816 nextToken();
5818 if (dltSyntax)
5819 error("no anonymous classes in Delight");
5821 if (token.value == TOKlparen)
5822 arguments = parseArguments();
5824 BaseClasses *baseclasses = NULL;
5825 if (token.value != TOKlcurly)
5826 baseclasses = parseBaseClasses();
5828 Identifier *id = NULL;
5829 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
5831 if (token.value != startBlockTok)
5832 { error("{ members } expected for anonymous class");
5833 cd->members = NULL;
5835 else
5837 nextToken();
5838 Array *decl = parseDeclDefs(0);
5839 if (token.value != TOKrcurly)
5840 error("class member expected");
5841 nextToken();
5842 cd->members = decl;
5845 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5847 return e;
5850 t = parseBasicType();
5851 t = parseBasicType2(t);
5852 if (t->ty == Taarray)
5853 { TypeAArray *taa = (TypeAArray *)t;
5854 Type *index = taa->index;
5856 Expression *e = index->toExpression();
5857 if (e)
5858 { arguments = new Expressions();
5859 arguments->push(e);
5860 t = new TypeDArray(taa->next);
5862 else
5864 error("need size of rightmost array, not type %s", index->toChars());
5865 return new NullExp(loc);
5868 else if (t->ty == Tsarray)
5870 TypeSArray *tsa = (TypeSArray *)t;
5871 Expression *e = tsa->dim;
5873 arguments = new Expressions();
5874 arguments->push(e);
5875 t = new TypeDArray(tsa->next);
5877 else if (token.value == TOKlparen)
5879 arguments = parseArguments();
5881 e = new NewExp(loc, thisexp, newargs, t, arguments);
5882 return e;
5885 /**********************************************
5888 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
5890 s->addComment(combineComments(blockComment, token.lineComment));
5894 /********************************* ***************************/