]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/dmd/parse.c
re PR target/88938 (ICE in extract_insn, at recog.c:2304)
[thirdparty/gcc.git] / gcc / d / dmd / parse.c
CommitLineData
b4c522fa
IB
1
2/* Compiler implementation of the D programming language
f3ed896c 3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
b4c522fa
IB
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
9 */
10
11// This is the D parser
12
f9ab59ff 13#include "root/dsystem.h" // strlen(),memcpy()
b4c522fa 14#include "root/rmem.h"
f9ab59ff 15
b4c522fa
IB
16#include "mars.h"
17#include "lexer.h"
18#include "parse.h"
19#include "init.h"
20#include "attrib.h"
21#include "cond.h"
22#include "mtype.h"
23#include "template.h"
24#include "staticassert.h"
25#include "expression.h"
26#include "statement.h"
27#include "module.h"
28#include "dsymbol.h"
29#include "import.h"
30#include "declaration.h"
31#include "aggregate.h"
32#include "enum.h"
33#include "id.h"
34#include "version.h"
35#include "aliasthis.h"
36#include "nspace.h"
37#include "hdrgen.h"
38
39Expression *typeToExpression(Type *t);
40
41// Support C cast syntax:
42// (type)(expression)
43#define CCASTSYNTAX 1
44
45// Support postfix C array declarations, such as
46// int a[3][4];
47#define CARRAYDECL 1
48
49Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment)
50 : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
51{
52 //printf("Parser::Parser()\n");
53 mod = module;
54 md = NULL;
55 linkage = LINKd;
56 endloc = Loc();
57 inBrackets = 0;
58 lookingForElse = Loc();
59 //nextToken(); // start up the scanner
60}
61
62/*********************
63 * Use this constructor for string mixins.
64 * Input:
65 * loc location in source file of mixin
66 */
67Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment)
68 : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
69{
70 //printf("Parser::Parser()\n");
71 scanloc = loc;
72
73#ifndef IN_GCC
74 if (loc.filename)
75 {
76 /* Create a pseudo-filename for the mixin string, as it may not even exist
77 * in the source file.
78 */
79 char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1);
80 sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
81 scanloc.filename = filename;
82 }
83#endif
84
85 mod = module;
86 md = NULL;
87 linkage = LINKd;
88 endloc = Loc();
89 inBrackets = 0;
90 lookingForElse = Loc();
91 //nextToken(); // start up the scanner
92}
93
94Dsymbols *Parser::parseModule()
95{
96 const utf8_t *comment = token.blockComment;
97 bool isdeprecated = false;
98 Expression *msg = NULL;
99 Expressions *udas = NULL;
100 Dsymbols *decldefs;
101
102 Token *tk;
103 if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
104 {
105 while (token.value != TOKmodule)
106 {
107 switch (token.value)
108 {
109 case TOKdeprecated:
110 {
111 // deprecated (...) module ...
112 if (isdeprecated)
113 {
114 error("there is only one deprecation attribute allowed for module declaration");
115 }
116 else
117 {
118 isdeprecated = true;
119 }
120 nextToken();
121 if (token.value == TOKlparen)
122 {
123 check(TOKlparen);
124 msg = parseAssignExp();
125 check(TOKrparen);
126 }
127 break;
128 }
129 case TOKat:
130 {
131 Expressions *exps = NULL;
132 StorageClass stc = parseAttribute(&exps);
133
134 if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
135 stc == STCsafe || stc == STCtrusted || stc == STCsystem)
136 {
137 error("@%s attribute for module declaration is not supported", token.toChars());
138 }
139 else
140 {
141 udas = UserAttributeDeclaration::concat(udas, exps);
142 }
143 if (stc)
144 nextToken();
145 break;
146 }
147 default:
148 {
149 error("'module' expected instead of %s", token.toChars());
150 nextToken();
151 break;
152 }
153 }
154 }
155 }
156
157 if (udas)
158 {
159 Dsymbols *a = new Dsymbols();
160 UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
161 mod->userAttribDecl = udad;
162 }
163
164 // ModuleDeclation leads off
165 if (token.value == TOKmodule)
166 {
167 Loc loc = token.loc;
168
169 nextToken();
170 if (token.value != TOKidentifier)
171 {
172 error("identifier expected following module");
173 goto Lerr;
174 }
175 else
176 {
177 Identifiers *a = NULL;
178 Identifier *id;
179
180 id = token.ident;
181 while (nextToken() == TOKdot)
182 {
183 if (!a)
184 a = new Identifiers();
185 a->push(id);
186 nextToken();
187 if (token.value != TOKidentifier)
188 {
189 error("identifier expected following package");
190 goto Lerr;
191 }
192 id = token.ident;
193 }
194
195 md = new ModuleDeclaration(loc, a, id);
196 md->isdeprecated = isdeprecated;
197 md->msg = msg;
198
199 if (token.value != TOKsemicolon)
200 error("';' expected following module declaration instead of %s", token.toChars());
201 nextToken();
202 addComment(mod, comment);
203 }
204 }
205
206 decldefs = parseDeclDefs(0);
207 if (token.value != TOKeof)
208 {
209 error(token.loc, "unrecognized declaration");
210 goto Lerr;
211 }
212 return decldefs;
213
214Lerr:
215 while (token.value != TOKsemicolon && token.value != TOKeof)
216 nextToken();
217 nextToken();
218 return new Dsymbols();
219}
220
221struct PrefixAttributes
222{
223 StorageClass storageClass;
224 Expression *depmsg;
225 LINK link;
226 Prot protection;
227 bool setAlignment;
228 Expression *ealign;
229 Expressions *udas;
230 const utf8_t *comment;
231
232 PrefixAttributes()
233 : storageClass(STCundefined),
234 depmsg(NULL),
235 link(LINKdefault),
236 protection(PROTundefined),
237 setAlignment(false),
238 ealign(NULL),
239 udas(NULL),
240 comment(NULL)
241 {
242 }
243};
244
245Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
246{
247 Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration
248 if (!pLastDecl)
249 pLastDecl = &lastDecl;
250
251 LINK linksave = linkage; // save global state
252
253 //printf("Parser::parseDeclDefs()\n");
254 Dsymbols *decldefs = new Dsymbols();
255 do
256 {
257 // parse result
258 Dsymbol *s = NULL;
259 Dsymbols *a = NULL;
260
261 PrefixAttributes attrs;
262 if (!once || !pAttrs)
263 {
264 pAttrs = &attrs;
265 pAttrs->comment = token.blockComment;
266 }
267 PROTKIND prot;
268 StorageClass stc;
269 Condition *condition;
270
271 linkage = linksave;
272
273 switch (token.value)
274 {
275 case TOKenum:
276 {
277 /* Determine if this is a manifest constant declaration,
278 * or a conventional enum.
279 */
280 Token *t = peek(&token);
281 if (t->value == TOKlcurly || t->value == TOKcolon)
282 s = parseEnum();
283 else if (t->value != TOKidentifier)
284 goto Ldeclaration;
285 else
286 {
287 t = peek(t);
288 if (t->value == TOKlcurly || t->value == TOKcolon ||
289 t->value == TOKsemicolon)
290 s = parseEnum();
291 else
292 goto Ldeclaration;
293 }
294 break;
295 }
296
297 case TOKimport:
298 a = parseImport();
299 // keep pLastDecl
300 break;
301
302 case TOKtemplate:
303 s = (Dsymbol *)parseTemplateDeclaration();
304 break;
305
306 case TOKmixin:
307 {
308 Loc loc = token.loc;
309 switch (peekNext())
310 {
311 case TOKlparen:
312 {
313 // mixin(string)
314 nextToken();
315 check(TOKlparen, "mixin");
316 Expression *e = parseAssignExp();
317 check(TOKrparen);
318 check(TOKsemicolon);
319 s = new CompileDeclaration(loc, e);
320 break;
321 }
322 case TOKtemplate:
323 // mixin template
324 nextToken();
325 s = (Dsymbol *)parseTemplateDeclaration(true);
326 break;
327
328 default:
329 s = parseMixin();
330 break;
331 }
332 break;
333 }
334
335 case TOKwchar: case TOKdchar:
336 case TOKbool: case TOKchar:
337 case TOKint8: case TOKuns8:
338 case TOKint16: case TOKuns16:
339 case TOKint32: case TOKuns32:
340 case TOKint64: case TOKuns64:
341 case TOKint128: case TOKuns128:
342 case TOKfloat32: case TOKfloat64: case TOKfloat80:
343 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
344 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
345 case TOKvoid:
346 case TOKalias:
347 case TOKidentifier:
348 case TOKsuper:
349 case TOKtypeof:
350 case TOKdot:
351 case TOKvector:
352 case TOKstruct:
353 case TOKunion:
354 case TOKclass:
355 case TOKinterface:
356 Ldeclaration:
357 a = parseDeclarations(false, pAttrs, pAttrs->comment);
358 if (a && a->dim)
359 *pLastDecl = (*a)[a->dim-1];
360 break;
361
362 case TOKthis:
363 if (peekNext() == TOKdot)
364 goto Ldeclaration;
365 else
366 s = parseCtor(pAttrs);
367 break;
368
369 case TOKtilde:
370 s = parseDtor(pAttrs);
371 break;
372
373 case TOKinvariant:
374 {
375 Token *t = peek(&token);
376 if ((t->value == TOKlparen && peek(t)->value == TOKrparen) ||
377 t->value == TOKlcurly)
378 {
379 // invariant {}
380 // invariant() {}
381 s = parseInvariant(pAttrs);
382 }
383 else
384 {
385 error("invariant body expected, not '%s'", token.toChars());
386 goto Lerror;
387 }
388 break;
389 }
390
391 case TOKunittest:
392 if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
393 {
394 s = parseUnitTest(pAttrs);
395 if (*pLastDecl)
396 (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s;
397 }
398 else
399 {
400 // Skip over unittest block by counting { }
401 Loc loc = token.loc;
402 int braces = 0;
403 while (1)
404 {
405 nextToken();
406 switch (token.value)
407 {
408 case TOKlcurly:
409 ++braces;
410 continue;
411
412 case TOKrcurly:
413 if (--braces)
414 continue;
415 nextToken();
416 break;
417
418 case TOKeof:
419 /* { */
420 error(loc, "closing } of unittest not found before end of file");
421 goto Lerror;
422
423 default:
424 continue;
425 }
426 break;
427 }
428 // Workaround 14894. Add an empty unittest declaration to keep
429 // the number of symbols in this scope independent of -unittest.
430 s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL);
431 }
432 break;
433
434 case TOKnew:
435 s = parseNew(pAttrs);
436 break;
437
438 case TOKdelete:
439 s = parseDelete(pAttrs);
440 break;
441
442 case TOKcolon:
443 case TOKlcurly:
444 error("declaration expected, not '%s'",token.toChars());
445 goto Lerror;
446
447 case TOKrcurly:
448 case TOKeof:
449 if (once)
450 error("declaration expected, not '%s'", token.toChars());
451 return decldefs;
452
453 case TOKstatic:
454 {
455 TOK next = peekNext();
456 if (next == TOKthis)
457 s = parseStaticCtor(pAttrs);
458 else if (next == TOKtilde)
459 s = parseStaticDtor(pAttrs);
460 else if (next == TOKassert)
461 s = parseStaticAssert();
462 else if (next == TOKif)
463 {
464 condition = parseStaticIfCondition();
465 Dsymbols *athen;
466 if (token.value == TOKcolon)
467 athen = parseBlock(pLastDecl);
468 else
469 {
470 Loc lookingForElseSave = lookingForElse;
471 lookingForElse = token.loc;
472 athen = parseBlock(pLastDecl);
473 lookingForElse = lookingForElseSave;
474 }
475 Dsymbols *aelse = NULL;
476 if (token.value == TOKelse)
477 {
478 Loc elseloc = token.loc;
479 nextToken();
480 aelse = parseBlock(pLastDecl);
481 checkDanglingElse(elseloc);
482 }
483 s = new StaticIfDeclaration(condition, athen, aelse);
484 }
485 else if (next == TOKimport)
486 {
487 a = parseImport();
488 // keep pLastDecl
489 }
490 else
491 {
492 stc = STCstatic;
493 goto Lstc;
494 }
495 break;
496 }
497
498 case TOKconst:
499 if (peekNext() == TOKlparen)
500 goto Ldeclaration;
501 stc = STCconst;
502 goto Lstc;
503
504 case TOKimmutable:
505 if (peekNext() == TOKlparen)
506 goto Ldeclaration;
507 stc = STCimmutable;
508 goto Lstc;
509
510 case TOKshared:
511 {
512 TOK next = peekNext();
513 if (next == TOKlparen)
514 goto Ldeclaration;
515 if (next == TOKstatic)
516 {
517 TOK next2 = peekNext2();
518 if (next2 == TOKthis)
519 {
520 s = parseSharedStaticCtor(pAttrs);
521 break;
522 }
523 if (next2 == TOKtilde)
524 {
525 s = parseSharedStaticDtor(pAttrs);
526 break;
527 }
528 }
529 stc = STCshared;
530 goto Lstc;
531 }
532
533 case TOKwild:
534 if (peekNext() == TOKlparen)
535 goto Ldeclaration;
536 stc = STCwild;
537 goto Lstc;
538
539 case TOKfinal: stc = STCfinal; goto Lstc;
540 case TOKauto: stc = STCauto; goto Lstc;
541 case TOKscope: stc = STCscope; goto Lstc;
542 case TOKoverride: stc = STCoverride; goto Lstc;
543 case TOKabstract: stc = STCabstract; goto Lstc;
544 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
545 case TOKnothrow: stc = STCnothrow; goto Lstc;
546 case TOKpure: stc = STCpure; goto Lstc;
547 case TOKref: stc = STCref; goto Lstc;
548 case TOKgshared: stc = STCgshared; goto Lstc;
549 //case TOKmanifest: stc = STCmanifest; goto Lstc;
550 case TOKat:
551 {
552 Expressions *exps = NULL;
553 stc = parseAttribute(&exps);
554 if (stc)
555 goto Lstc; // it's a predefined attribute
556 // no redundant/conflicting check for UDAs
557 pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
558 goto Lautodecl;
559 }
560 Lstc:
561 pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc);
562 nextToken();
563
564 Lautodecl:
565 Token *tk;
566
567 /* Look for auto initializers:
568 * storage_class identifier = initializer;
569 * storage_class identifier(...) = initializer;
570 */
571 if (token.value == TOKidentifier &&
572 skipParensIf(peek(&token), &tk) &&
573 tk->value == TOKassign)
574 {
575 a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment);
576 pAttrs->storageClass = STCundefined;
577 if (a && a->dim)
578 *pLastDecl = (*a)[a->dim-1];
579 if (pAttrs->udas)
580 {
581 s = new UserAttributeDeclaration(pAttrs->udas, a);
582 pAttrs->udas = NULL;
583 }
584 break;
585 }
586
587 /* Look for return type inference for template functions.
588 */
589 if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
590 (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin ||
591 tk->value == TOKout || tk->value == TOKdo ||
592 (tk->value == TOKidentifier && tk->ident == Id::_body))
593 )
594 {
595 a = parseDeclarations(true, pAttrs, pAttrs->comment);
596 if (a && a->dim)
597 *pLastDecl = (*a)[a->dim-1];
598 if (pAttrs->udas)
599 {
600 s = new UserAttributeDeclaration(pAttrs->udas, a);
601 pAttrs->udas = NULL;
602 }
603 break;
604 }
605
606 a = parseBlock(pLastDecl, pAttrs);
607 if (pAttrs->storageClass != STCundefined)
608 {
609 s = new StorageClassDeclaration(pAttrs->storageClass, a);
610 pAttrs->storageClass = STCundefined;
611 }
612 if (pAttrs->udas)
613 {
614 if (s)
615 {
616 a = new Dsymbols();
617 a->push(s);
618 }
619 s = new UserAttributeDeclaration(pAttrs->udas, a);
620 pAttrs->udas = NULL;
621 }
622 break;
623
624 case TOKdeprecated:
625 {
626 if (peek(&token)->value != TOKlparen)
627 {
628 stc = STCdeprecated;
629 goto Lstc;
630 }
631 nextToken();
632 check(TOKlparen);
633 Expression *e = parseAssignExp();
634 check(TOKrparen);
635 if (pAttrs->depmsg)
636 {
637 error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'",
638 pAttrs->depmsg->toChars(), e->toChars());
639 }
640 pAttrs->depmsg = e;
641 a = parseBlock(pLastDecl, pAttrs);
642 if (pAttrs->depmsg)
643 {
644 s = new DeprecatedDeclaration(pAttrs->depmsg, a);
645 pAttrs->depmsg = NULL;
646 }
647 break;
648 }
649
650 case TOKlbracket:
651 {
652 if (peekNext() == TOKrbracket)
653 error("empty attribute list is not allowed");
654 error("use @(attributes) instead of [attributes]");
655 Expressions *exps = parseArguments();
656 // no redundant/conflicting check for UDAs
657
658 pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
659 a = parseBlock(pLastDecl, pAttrs);
660 if (pAttrs->udas)
661 {
662 s = new UserAttributeDeclaration(pAttrs->udas, a);
663 pAttrs->udas = NULL;
664 }
665 break;
666 }
667
668 case TOKextern:
669 {
670 if (peek(&token)->value != TOKlparen)
671 {
672 stc = STCextern;
673 goto Lstc;
674 }
675
676 Loc linkLoc = token.loc;
677 Identifiers *idents = NULL;
678 CPPMANGLE cppmangle = CPPMANGLEdefault;
679 LINK link = parseLinkage(&idents, &cppmangle);
680 if (pAttrs->link != LINKdefault)
681 {
682 if (pAttrs->link != link)
683 {
684 error("conflicting linkage extern (%s) and extern (%s)",
685 linkageToChars(pAttrs->link), linkageToChars(link));
686 }
687 else if (idents)
688 {
689 // Allow:
690 // extern(C++, foo) extern(C++, bar) void foo();
691 // to be equivalent with:
692 // extern(C++, foo.bar) void foo();
693 }
694 else
695 error("redundant linkage extern (%s)", linkageToChars(pAttrs->link));
696 }
697 pAttrs->link = link;
698 this->linkage = link;
699 a = parseBlock(pLastDecl, pAttrs);
700 if (idents)
701 {
702 assert(link == LINKcpp);
703 assert(idents->dim);
704 for (size_t i = idents->dim; i;)
705 {
706 Identifier *id = (*idents)[--i];
707 if (s)
708 {
709 a = new Dsymbols();
710 a->push(s);
711 }
712 s = new Nspace(linkLoc, id, a);
713 }
714 delete idents;
715 pAttrs->link = LINKdefault;
716 }
717 else if (pAttrs->link != LINKdefault)
718 {
719 s = new LinkDeclaration(pAttrs->link, a);
720 pAttrs->link = LINKdefault;
721 }
722 else if (cppmangle != CPPMANGLEdefault)
723 {
724 assert(link == LINKcpp);
725 s = new CPPMangleDeclaration(cppmangle, a);
726 }
727 break;
728 }
729
730 case TOKprivate: prot = PROTprivate; goto Lprot;
731 case TOKpackage: prot = PROTpackage; goto Lprot;
732 case TOKprotected: prot = PROTprotected; goto Lprot;
733 case TOKpublic: prot = PROTpublic; goto Lprot;
734 case TOKexport: prot = PROTexport; goto Lprot;
735 Lprot:
736 {
737 if (pAttrs->protection.kind != PROTundefined)
738 {
739 if (pAttrs->protection.kind != prot)
740 error("conflicting protection attribute '%s' and '%s'",
741 protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
742 else
743 error("redundant protection attribute '%s'", protectionToChars(prot));
744 }
745 pAttrs->protection.kind = prot;
746
747 nextToken();
748
749 // optional qualified package identifier to bind
750 // protection to
751 Identifiers *pkg_prot_idents = NULL;
752 if (pAttrs->protection.kind == PROTpackage && token.value == TOKlparen)
753 {
754 pkg_prot_idents = parseQualifiedIdentifier("protection package");
755
756 if (pkg_prot_idents)
757 check(TOKrparen);
758 else
759 {
760 while (token.value != TOKsemicolon && token.value != TOKeof)
761 nextToken();
762 nextToken();
763 break;
764 }
765 }
766
767 Loc attrloc = token.loc;
768 a = parseBlock(pLastDecl, pAttrs);
769 if (pAttrs->protection.kind != PROTundefined)
770 {
771 if (pAttrs->protection.kind == PROTpackage && pkg_prot_idents)
772 s = new ProtDeclaration(attrloc, pkg_prot_idents, a);
773 else
774 s = new ProtDeclaration(attrloc, pAttrs->protection, a);
775
776 pAttrs->protection = Prot(PROTundefined);
777 }
778 break;
779 }
780
781 case TOKalign:
782 {
783 const Loc attrLoc = token.loc;
784
785 nextToken();
786
787 Expression *e = NULL; // default
788 if (token.value == TOKlparen)
789 {
790 nextToken();
791 e = parseAssignExp();
792 check(TOKrparen);
793 }
794
795 if (pAttrs->setAlignment)
796 {
797 const char *s1 = "";
798 OutBuffer buf1;
799 if (e)
800 {
801 buf1.printf("(%s)", e->toChars());
802 s1 = buf1.peekString();
803 }
804 error("redundant alignment attribute align%s", s1);
805 }
806
807 pAttrs->setAlignment = true;
808 pAttrs->ealign = e;
809 a = parseBlock(pLastDecl, pAttrs);
810 if (pAttrs->setAlignment)
811 {
812 s = new AlignDeclaration(attrLoc, pAttrs->ealign, a);
813 pAttrs->setAlignment = false;
814 pAttrs->ealign = NULL;
815 }
816 break;
817 }
818
819 case TOKpragma:
820 {
821 Expressions *args = NULL;
822 Loc loc = token.loc;
823
824 nextToken();
825 check(TOKlparen);
826 if (token.value != TOKidentifier)
827 {
828 error("pragma(identifier) expected");
829 goto Lerror;
830 }
831 Identifier *ident = token.ident;
832 nextToken();
833 if (token.value == TOKcomma && peekNext() != TOKrparen)
834 args = parseArguments(); // pragma(identifier, args...)
835 else
836 check(TOKrparen); // pragma(identifier)
837
838 Dsymbols *a2 = NULL;
839 if (token.value == TOKsemicolon)
840 {
841 /* Bugzilla 2354: Accept single semicolon as an empty
842 * DeclarationBlock following attribute.
843 *
844 * Attribute DeclarationBlock
845 * Pragma DeclDef
846 * ;
847 */
848 nextToken();
849 }
850 else
851 a2 = parseBlock(pLastDecl);
852 s = new PragmaDeclaration(loc, ident, args, a2);
853 break;
854 }
855
856 case TOKdebug:
857 nextToken();
858 if (token.value == TOKassign)
859 {
860 nextToken();
861 if (token.value == TOKidentifier)
862 s = new DebugSymbol(token.loc, token.ident);
863 else if (token.value == TOKint32v || token.value == TOKint64v)
864 s = new DebugSymbol(token.loc, (unsigned)token.uns64value);
865 else
866 {
867 error("identifier or integer expected, not %s", token.toChars());
868 s = NULL;
869 }
870 nextToken();
871 if (token.value != TOKsemicolon)
872 error("semicolon expected");
873 nextToken();
874 break;
875 }
876
877 condition = parseDebugCondition();
878 goto Lcondition;
879
880 case TOKversion:
881 nextToken();
882 if (token.value == TOKassign)
883 {
884 nextToken();
885 if (token.value == TOKidentifier)
886 s = new VersionSymbol(token.loc, token.ident);
887 else if (token.value == TOKint32v || token.value == TOKint64v)
888 s = new VersionSymbol(token.loc, (unsigned)token.uns64value);
889 else
890 {
891 error("identifier or integer expected, not %s", token.toChars());
892 s = NULL;
893 }
894 nextToken();
895 if (token.value != TOKsemicolon)
896 error("semicolon expected");
897 nextToken();
898 break;
899 }
900 condition = parseVersionCondition();
901 goto Lcondition;
902
903 Lcondition:
904 {
905 Dsymbols *athen;
906 if (token.value == TOKcolon)
907 athen = parseBlock(pLastDecl);
908 else
909 {
910 Loc lookingForElseSave = lookingForElse;
911 lookingForElse = token.loc;
912 athen = parseBlock(pLastDecl);
913 lookingForElse = lookingForElseSave;
914 }
915 Dsymbols *aelse = NULL;
916 if (token.value == TOKelse)
917 {
918 Loc elseloc = token.loc;
919 nextToken();
920 aelse = parseBlock(pLastDecl);
921 checkDanglingElse(elseloc);
922 }
923 s = new ConditionalDeclaration(condition, athen, aelse);
924 break;
925 }
926
927 case TOKsemicolon: // empty declaration
928 //error("empty declaration");
929 nextToken();
930 continue;
931
932 default:
933 error("declaration expected, not '%s'",token.toChars());
934 Lerror:
935 while (token.value != TOKsemicolon && token.value != TOKeof)
936 nextToken();
937 nextToken();
938 s = NULL;
939 continue;
940 }
941
942 if (s)
943 {
944 if (!s->isAttribDeclaration())
945 *pLastDecl = s;
946 decldefs->push(s);
947 addComment(s, pAttrs->comment);
948 }
949 else if (a && a->dim)
950 {
951 decldefs->append(a);
952 }
953 } while (!once);
954
955 linkage = linksave;
956
957 return decldefs;
958}
959
960/*********************************************
961 * Give error on redundant/conflicting storage class.
962 *
963 * TODO: remove deprecation in 2.068 and keep only error
964 */
965
966StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc,
967 bool deprec)
968{
969 if ((storageClass & stc) ||
970 (storageClass & STCin && stc & (STCconst | STCscope)) ||
971 (stc & STCin && storageClass & (STCconst | STCscope)))
972 {
973 OutBuffer buf;
974 stcToBuffer(&buf, stc);
975 if (deprec)
976 deprecation("redundant attribute '%s'", buf.peekString());
977 else
978 error("redundant attribute '%s'", buf.peekString());
979 return storageClass | stc;
980 }
981
982 storageClass |= stc;
983
984 if (stc & (STCconst | STCimmutable | STCmanifest))
985 {
986 StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
987 if (u & (u - 1))
988 error("conflicting attribute '%s'", Token::toChars(token.value));
989 }
990 if (stc & (STCgshared | STCshared | STCtls))
991 {
992 StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
993 if (u & (u - 1))
994 error("conflicting attribute '%s'", Token::toChars(token.value));
995 }
996 if (stc & (STCsafe | STCsystem | STCtrusted))
997 {
998 StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
999 if (u & (u - 1))
1000 error("conflicting attribute '@%s'", token.toChars());
1001 }
1002
1003 return storageClass;
1004}
1005
1006/***********************************************
1007 * Parse attribute, lexer is on '@'.
1008 * Input:
1009 * pudas array of UDAs to append to
1010 * Returns:
1011 * storage class if a predefined attribute; also scanner remains on identifier.
1012 * 0 if not a predefined attribute
1013 * *pudas set if user defined attribute, scanner is past UDA
1014 * *pudas NULL if not a user defined attribute
1015 */
1016
1017StorageClass Parser::parseAttribute(Expressions **pudas)
1018{
1019 nextToken();
1020 Expressions *udas = NULL;
1021 StorageClass stc = 0;
1022 if (token.value == TOKidentifier)
1023 {
1024 if (token.ident == Id::property)
1025 stc = STCproperty;
1026 else if (token.ident == Id::nogc)
1027 stc = STCnogc;
1028 else if (token.ident == Id::safe)
1029 stc = STCsafe;
1030 else if (token.ident == Id::trusted)
1031 stc = STCtrusted;
1032 else if (token.ident == Id::system)
1033 stc = STCsystem;
1034 else if (token.ident == Id::disable)
1035 stc = STCdisable;
1036 else if (token.ident == Id::future)
1037 stc = STCfuture;
1038 else
1039 {
1040 // Allow identifier, template instantiation, or function call
1041 Expression *exp = parsePrimaryExp();
1042 if (token.value == TOKlparen)
1043 {
1044 Loc loc = token.loc;
1045 exp = new CallExp(loc, exp, parseArguments());
1046 }
1047
1048 udas = new Expressions();
1049 udas->push(exp);
1050 }
1051 }
1052 else if (token.value == TOKlparen)
1053 {
1054 // @( ArgumentList )
1055 // Concatenate with existing
1056 if (peekNext() == TOKrparen)
1057 error("empty attribute list is not allowed");
1058 udas = parseArguments();
1059 }
1060 else
1061 {
1062 error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
1063 }
1064
1065 if (stc)
1066 {
1067 }
1068 else if (udas)
1069 {
1070 *pudas = UserAttributeDeclaration::concat(*pudas, udas);
1071 }
1072 else
1073 error("valid attributes are @property, @safe, @trusted, @system, @disable");
1074 return stc;
1075}
1076
1077/***********************************************
1078 * Parse const/immutable/shared/inout/nothrow/pure postfix
1079 */
1080
1081StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas)
1082{
1083 while (1)
1084 {
1085 StorageClass stc;
1086 switch (token.value)
1087 {
1088 case TOKconst: stc = STCconst; break;
1089 case TOKimmutable: stc = STCimmutable; break;
1090 case TOKshared: stc = STCshared; break;
1091 case TOKwild: stc = STCwild; break;
1092 case TOKnothrow: stc = STCnothrow; break;
1093 case TOKpure: stc = STCpure; break;
1094 case TOKreturn: stc = STCreturn; break;
1095 case TOKscope: stc = STCscope; break;
1096 case TOKat:
1097 {
1098 Expressions *udas = NULL;
1099 stc = parseAttribute(&udas);
1100 if (udas)
1101 {
1102 if (pudas)
1103 *pudas = UserAttributeDeclaration::concat(*pudas, udas);
1104 else
1105 {
1106 // Disallow:
1107 // void function() @uda fp;
1108 // () @uda { return 1; }
1109 error("user defined attributes cannot appear as postfixes");
1110 }
1111 continue;
1112 }
1113 break;
1114 }
1115
1116 default:
1117 return storageClass;
1118 }
1119 storageClass = appendStorageClass(storageClass, stc, true);
1120 nextToken();
1121 }
1122}
1123
1124StorageClass Parser::parseTypeCtor()
1125{
1126 StorageClass storageClass = STCundefined;
1127
1128 while (1)
1129 {
1130 if (peek(&token)->value == TOKlparen)
1131 return storageClass;
1132
1133 StorageClass stc;
1134 switch (token.value)
1135 {
1136 case TOKconst: stc = STCconst; break;
1137 case TOKimmutable: stc = STCimmutable; break;
1138 case TOKshared: stc = STCshared; break;
1139 case TOKwild: stc = STCwild; break;
1140
1141 default:
1142 return storageClass;
1143 }
1144 storageClass = appendStorageClass(storageClass, stc);
1145 nextToken();
1146 }
1147}
1148
1149/********************************************
1150 * Parse declarations after an align, protection, or extern decl.
1151 */
1152
1153Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
1154{
1155 Dsymbols *a = NULL;
1156
1157 //printf("parseBlock()\n");
1158 switch (token.value)
1159 {
1160 case TOKsemicolon:
1161 error("declaration expected following attribute, not ';'");
1162 nextToken();
1163 break;
1164
1165 case TOKeof:
1166 error("declaration expected following attribute, not EOF");
1167 break;
1168
1169 case TOKlcurly:
1170 {
1171 Loc lookingForElseSave = lookingForElse;
1172 lookingForElse = Loc();
1173
1174 nextToken();
1175 a = parseDeclDefs(0, pLastDecl);
1176 if (token.value != TOKrcurly)
1177 {
1178 /* { */
1179 error("matching '}' expected, not %s", token.toChars());
1180 }
1181 else
1182 nextToken();
1183 lookingForElse = lookingForElseSave;
1184 break;
1185 }
1186
1187 case TOKcolon:
1188 nextToken();
1189 a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
1190 break;
1191
1192 default:
1193 a = parseDeclDefs(1, pLastDecl, pAttrs);
1194 break;
1195 }
1196 return a;
1197}
1198
1199/**********************************
1200 * Parse a static assertion.
1201 * Current token is 'static'.
1202 */
1203
1204StaticAssert *Parser::parseStaticAssert()
1205{
1206 Loc loc = token.loc;
1207 Expression *exp;
1208 Expression *msg = NULL;
1209
1210 //printf("parseStaticAssert()\n");
1211 nextToken();
1212 nextToken();
1213 check(TOKlparen);
1214 exp = parseAssignExp();
1215 if (token.value == TOKcomma)
1216 {
1217 nextToken();
1218 if (token.value != TOKrparen)
1219 {
1220 msg = parseAssignExp();
1221 if (token.value == TOKcomma)
1222 nextToken();
1223 }
1224 }
1225 check(TOKrparen);
1226 check(TOKsemicolon);
1227 return new StaticAssert(loc, exp, msg);
1228}
1229
1230/***********************************
1231 * Parse typeof(expression).
1232 * Current token is on the 'typeof'.
1233 */
1234
1235TypeQualified *Parser::parseTypeof()
1236{
1237 TypeQualified *t;
1238 Loc loc = token.loc;
1239
1240 nextToken();
1241 check(TOKlparen);
1242 if (token.value == TOKreturn) // typeof(return)
1243 {
1244 nextToken();
1245 t = new TypeReturn(loc);
1246 }
1247 else
1248 {
1249 Expression *exp = parseExpression(); // typeof(expression)
1250 t = new TypeTypeof(loc, exp);
1251 }
1252 check(TOKrparen);
1253 return t;
1254}
1255
1256/***********************************
1257 * Parse __vector(type).
1258 * Current token is on the '__vector'.
1259 */
1260
1261Type *Parser::parseVector()
1262{
1263 nextToken();
1264 check(TOKlparen);
1265 Type *tb = parseType();
1266 check(TOKrparen);
1267 return new TypeVector(tb);
1268}
1269
1270/***********************************
1271 * Parse:
1272 * extern (linkage)
1273 * extern (C++, namespaces)
1274 * The parser is on the 'extern' token.
1275 */
1276
1277LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle)
1278{
1279 Identifiers *idents = NULL;
1280 CPPMANGLE cppmangle = CPPMANGLEdefault;
1281 LINK link = LINKdefault;
1282 nextToken();
1283 assert(token.value == TOKlparen);
1284 nextToken();
1285 if (token.value == TOKidentifier)
1286 { Identifier *id = token.ident;
1287
1288 nextToken();
1289 if (id == Id::Windows)
1290 link = LINKwindows;
1291 else if (id == Id::Pascal)
1292 link = LINKpascal;
1293 else if (id == Id::D)
1294 link = LINKd;
1295 else if (id == Id::C)
1296 {
1297 link = LINKc;
1298 if (token.value == TOKplusplus)
1299 {
1300 link = LINKcpp;
1301 nextToken();
1302 if (token.value == TOKcomma) // , namespaces or class or struct
1303 {
1304 nextToken();
1305 if (token.value == TOKclass || token.value == TOKstruct)
1306 {
1307 cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
1308 nextToken();
1309 }
1310 else
1311 {
1312 idents = new Identifiers();
1313 while (1)
1314 {
1315 if (token.value == TOKidentifier)
1316 {
1317 Identifier *idn = token.ident;
1318 idents->push(idn);
1319 nextToken();
1320 if (token.value == TOKdot)
1321 {
1322 nextToken();
1323 continue;
1324 }
1325 }
1326 else
1327 {
1328 error("identifier expected for C++ namespace");
1329 idents = NULL; // error occurred, invalidate list of elements.
1330 }
1331 break;
1332 }
1333 }
1334 }
1335 }
1336 }
1337 else if (id == Id::Objective) // Looking for tokens "Objective-C"
1338 {
1339 if (token.value == TOKmin)
1340 {
1341 nextToken();
1342 if (token.ident == Id::C)
1343 {
1344 link = LINKobjc;
1345 nextToken();
1346 }
1347 else
1348 goto LinvalidLinkage;
1349 }
1350 else
1351 goto LinvalidLinkage;
1352 }
1353 else if (id == Id::System)
1354 {
1355 link = LINKsystem;
1356 }
1357 else
1358 {
1359 LinvalidLinkage:
1360 error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
1361 link = LINKd;
1362 }
1363 }
1364 else
1365 {
1366 link = LINKd; // default
1367 }
1368 check(TOKrparen);
1369 *pidents = idents;
1370 *pcppmangle = cppmangle;
1371 return link;
1372}
1373
1374/***********************************
1375 * Parse ident1.ident2.ident3
1376 *
1377 * Params:
1378 * entity = what qualified identifier is expected to resolve into.
1379 * Used only for better error message
1380 *
1381 * Returns:
1382 * array of identifiers with actual qualified one stored last
1383 */
1384Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
1385{
1386 Identifiers *qualified = NULL;
1387
1388 do
1389 {
1390 nextToken();
1391 if (token.value != TOKidentifier)
1392 {
1393 error("%s expected as dot-separated identifiers, got '%s'",
1394 entity, token.toChars());
1395 return NULL;
1396 }
1397
1398 Identifier *id = token.ident;
1399 if (!qualified)
1400 qualified = new Identifiers();
1401 qualified->push(id);
1402
1403 nextToken();
1404 } while (token.value == TOKdot);
1405
1406 return qualified;
1407}
1408
1409/**************************************
1410 * Parse a debug conditional
1411 */
1412
1413Condition *Parser::parseDebugCondition()
1414{
1415 Condition *c;
1416
1417 if (token.value == TOKlparen)
1418 {
1419 nextToken();
1420 unsigned level = 1;
1421 Identifier *id = NULL;
1422
1423 if (token.value == TOKidentifier)
1424 id = token.ident;
1425 else if (token.value == TOKint32v || token.value == TOKint64v)
1426 level = (unsigned)token.uns64value;
1427 else
1428 error("identifier or integer expected, not %s", token.toChars());
1429 nextToken();
1430 check(TOKrparen);
1431 c = new DebugCondition(mod, level, id);
1432 }
1433 else
1434 c = new DebugCondition(mod, 1, NULL);
1435 return c;
1436
1437}
1438
1439/**************************************
1440 * Parse a version conditional
1441 */
1442
1443Condition *Parser::parseVersionCondition()
1444{
1445 Condition *c;
1446 unsigned level = 1;
1447 Identifier *id = NULL;
1448
1449 if (token.value == TOKlparen)
1450 {
1451 nextToken();
1452 /* Allow:
1453 * version (unittest)
1454 * version (assert)
1455 * even though they are keywords
1456 */
1457 if (token.value == TOKidentifier)
1458 id = token.ident;
1459 else if (token.value == TOKint32v || token.value == TOKint64v)
1460 level = (unsigned)token.uns64value;
1461 else if (token.value == TOKunittest)
1462 id = Identifier::idPool(Token::toChars(TOKunittest));
1463 else if (token.value == TOKassert)
1464 id = Identifier::idPool(Token::toChars(TOKassert));
1465 else
1466 error("identifier or integer expected, not %s", token.toChars());
1467 nextToken();
1468 check(TOKrparen);
1469
1470 }
1471 else
1472 error("(condition) expected following version");
1473 c = new VersionCondition(mod, level, id);
1474 return c;
1475
1476}
1477
1478/***********************************************
1479 * static if (expression)
1480 * body
1481 * else
1482 * body
1483 * Current token is 'static'.
1484 */
1485
1486Condition *Parser::parseStaticIfCondition()
1487{
1488 Expression *exp;
1489 Condition *condition;
1490 Loc loc = token.loc;
1491
1492 nextToken();
1493 nextToken();
1494 if (token.value == TOKlparen)
1495 {
1496 nextToken();
1497 exp = parseAssignExp();
1498 check(TOKrparen);
1499 }
1500 else
1501 {
1502 error("(expression) expected following static if");
1503 exp = NULL;
1504 }
1505 condition = new StaticIfCondition(loc, exp);
1506 return condition;
1507}
1508
1509
1510/*****************************************
1511 * Parse a constructor definition:
1512 * this(parameters) { body }
1513 * or postblit:
1514 * this(this) { body }
1515 * or constructor template:
1516 * this(templateparameters)(parameters) { body }
1517 * Current token is 'this'.
1518 */
1519
1520Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
1521{
1522 Expressions *udas = NULL;
1523 Loc loc = token.loc;
1524 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1525
1526 nextToken();
1527 if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
1528 {
1529 // this(this) { ... }
1530 nextToken();
1531 nextToken();
1532 check(TOKrparen);
1533
1534 stc = parsePostfix(stc, &udas);
1535 if (stc & STCstatic)
1536 error(loc, "postblit cannot be static");
1537
1538 PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
1539 if (pAttrs)
1540 pAttrs->storageClass = STCundefined;
1541 Dsymbol *s = parseContracts(f);
1542 if (udas)
1543 {
1544 Dsymbols *a = new Dsymbols();
1545 a->push(f);
1546 s = new UserAttributeDeclaration(udas, a);
1547 }
1548 return s;
1549 }
1550
1551 /* Look ahead to see if:
1552 * this(...)(...)
1553 * which is a constructor template
1554 */
1555 TemplateParameters *tpl = NULL;
1556 if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
1557 {
1558 tpl = parseTemplateParameterList();
1559 }
1560
1561 /* Just a regular constructor
1562 */
1563 int varargs;
1564 Parameters *parameters = parseParameters(&varargs);
1565 stc = parsePostfix(stc, &udas);
1566 if (varargs != 0 || Parameter::dim(parameters) != 0)
1567 {
1568 if (stc & STCstatic)
1569 error(loc, "constructor cannot be static");
1570 }
1571 else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
1572 {
1573 if (ss == STCstatic)
1574 error(loc, "use 'static this()' to declare a static constructor");
1575 else if (ss == (STCshared | STCstatic))
1576 error(loc, "use 'shared static this()' to declare a shared static constructor");
1577 }
1578
1579 Expression *constraint = tpl ? parseConstraint() : NULL;
1580
1581 Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
1582 tf = tf->addSTC(stc);
1583
1584 CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
1585 if (pAttrs)
1586 pAttrs->storageClass = STCundefined;
1587 Dsymbol *s = parseContracts(f);
1588 if (udas)
1589 {
1590 Dsymbols *a = new Dsymbols();
1591 a->push(f);
1592 s = new UserAttributeDeclaration(udas, a);
1593 }
1594
1595 if (tpl)
1596 {
1597 // Wrap a template around it
1598 Dsymbols *decldefs = new Dsymbols();
1599 decldefs->push(s);
1600 s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
1601 }
1602
1603 return s;
1604}
1605
1606/*****************************************
1607 * Parse a destructor definition:
1608 * ~this() { body }
1609 * Current token is '~'.
1610 */
1611
1612Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
1613{
1614 Expressions *udas = NULL;
1615 Loc loc = token.loc;
1616 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1617
1618 nextToken();
1619 check(TOKthis);
1620 check(TOKlparen);
1621 check(TOKrparen);
1622
1623 stc = parsePostfix(stc, &udas);
1624 if (StorageClass ss = stc & (STCshared | STCstatic))
1625 {
1626 if (ss == STCstatic)
1627 error(loc, "use 'static ~this()' to declare a static destructor");
1628 else if (ss == (STCshared | STCstatic))
1629 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1630 }
1631
1632 DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
1633 if (pAttrs)
1634 pAttrs->storageClass = STCundefined;
1635 Dsymbol *s = parseContracts(f);
1636 if (udas)
1637 {
1638 Dsymbols *a = new Dsymbols();
1639 a->push(f);
1640 s = new UserAttributeDeclaration(udas, a);
1641 }
1642 return s;
1643}
1644
1645/*****************************************
1646 * Parse a static constructor definition:
1647 * static this() { body }
1648 * Current token is 'static'.
1649 */
1650
1651Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
1652{
1653 //Expressions *udas = NULL;
1654 Loc loc = token.loc;
1655 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1656
1657 nextToken();
1658 nextToken();
1659 check(TOKlparen);
1660 check(TOKrparen);
1661
1662 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1663 if (stc & STCshared)
1664 error(loc, "use 'shared static this()' to declare a shared static constructor");
1665 else if (stc & STCstatic)
1666 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1667 else if (StorageClass modStc = stc & STC_TYPECTOR)
1668 {
1669 OutBuffer buf;
1670 stcToBuffer(&buf, modStc);
1671 error(loc, "static constructor cannot be %s", buf.peekString());
1672 }
1673 stc &= ~(STCstatic | STC_TYPECTOR);
1674
1675 StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
1676 if (pAttrs)
1677 pAttrs->storageClass = STCundefined;
1678 Dsymbol *s = parseContracts(f);
1679 return s;
1680}
1681
1682/*****************************************
1683 * Parse a static destructor definition:
1684 * static ~this() { body }
1685 * Current token is 'static'.
1686 */
1687
1688Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
1689{
1690 Expressions *udas = NULL;
1691 Loc loc = token.loc;
1692 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1693
1694 nextToken();
1695 nextToken();
1696 check(TOKthis);
1697 check(TOKlparen);
1698 check(TOKrparen);
1699
1700 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1701 if (stc & STCshared)
1702 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1703 else if (stc & STCstatic)
1704 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1705 else if (StorageClass modStc = stc & STC_TYPECTOR)
1706 {
1707 OutBuffer buf;
1708 stcToBuffer(&buf, modStc);
1709 error(loc, "static destructor cannot be %s", buf.peekString());
1710 }
1711 stc &= ~(STCstatic | STC_TYPECTOR);
1712
1713 StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
1714 if (pAttrs)
1715 pAttrs->storageClass = STCundefined;
1716 Dsymbol *s = parseContracts(f);
1717 if (udas)
1718 {
1719 Dsymbols *a = new Dsymbols();
1720 a->push(f);
1721 s = new UserAttributeDeclaration(udas, a);
1722 }
1723 return s;
1724}
1725
1726/*****************************************
1727 * Parse a shared static constructor definition:
1728 * shared static this() { body }
1729 * Current token is 'shared'.
1730 */
1731
1732Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
1733{
1734 //Expressions *udas = NULL;
1735 Loc loc = token.loc;
1736 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1737
1738 nextToken();
1739 nextToken();
1740 nextToken();
1741 check(TOKlparen);
1742 check(TOKrparen);
1743
1744 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1745 if (StorageClass ss = stc & (STCshared | STCstatic))
1746 appendStorageClass(stc, ss); // complaint for the redundancy
1747 else if (StorageClass modStc = stc & STC_TYPECTOR)
1748 {
1749 OutBuffer buf;
1750 stcToBuffer(&buf, modStc);
1751 error(loc, "shared static constructor cannot be %s", buf.peekString());
1752 }
1753 stc &= ~(STCstatic | STC_TYPECTOR);
1754
1755 SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
1756 if (pAttrs)
1757 pAttrs->storageClass = STCundefined;
1758 Dsymbol *s = parseContracts(f);
1759 return s;
1760}
1761
1762/*****************************************
1763 * Parse a shared static destructor definition:
1764 * shared static ~this() { body }
1765 * Current token is 'shared'.
1766 */
1767
1768Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
1769{
1770 Expressions *udas = NULL;
1771 Loc loc = token.loc;
1772 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1773
1774 nextToken();
1775 nextToken();
1776 nextToken();
1777 check(TOKthis);
1778 check(TOKlparen);
1779 check(TOKrparen);
1780
1781 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1782 if (StorageClass ss = stc & (STCshared | STCstatic))
1783 appendStorageClass(stc, ss); // complaint for the redundancy
1784 else if (StorageClass modStc = stc & STC_TYPECTOR)
1785 {
1786 OutBuffer buf;
1787 stcToBuffer(&buf, modStc);
1788 error(loc, "shared static destructor cannot be %s", buf.peekString());
1789 }
1790 stc &= ~(STCstatic | STC_TYPECTOR);
1791
1792 SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
1793 if (pAttrs)
1794 pAttrs->storageClass = STCundefined;
1795 Dsymbol *s = parseContracts(f);
1796 if (udas)
1797 {
1798 Dsymbols *a = new Dsymbols();
1799 a->push(f);
1800 s = new UserAttributeDeclaration(udas, a);
1801 }
1802 return s;
1803}
1804
1805/*****************************************
1806 * Parse an invariant definition:
1807 * invariant() { body }
1808 * Current token is 'invariant'.
1809 */
1810
1811Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
1812{
1813 Loc loc = token.loc;
1814 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1815
1816 nextToken();
1817 if (token.value == TOKlparen) // optional ()
1818 {
1819 nextToken();
1820 check(TOKrparen);
1821 }
1822
1823 InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
1824 if (pAttrs)
1825 pAttrs->storageClass = STCundefined;
1826 f->fbody = parseStatement(PScurly);
1827 return f;
1828}
1829
1830/*****************************************
1831 * Parse a unittest definition:
1832 * unittest { body }
1833 * Current token is 'unittest'.
1834 */
1835
1836Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
1837{
1838 Loc loc = token.loc;
1839 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1840
1841 nextToken();
1842
1843 const utf8_t *begPtr = token.ptr + 1; // skip '{'
1844 const utf8_t *endPtr = NULL;
1845 Statement *sbody = parseStatement(PScurly, &endPtr);
1846
1847 /** Extract unittest body as a string. Must be done eagerly since memory
1848 will be released by the lexer before doc gen. */
1849 char *docline = NULL;
1850 if (global.params.doDocComments && endPtr > begPtr)
1851 {
1852 /* Remove trailing whitespaces */
1853 for (const utf8_t *p = endPtr - 1;
1854 begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
1855 {
1856 endPtr = p;
1857 }
1858
1859 size_t len = endPtr - begPtr;
1860 if (len > 0)
1861 {
1862 docline = (char *)mem.xmalloc(len + 2);
1863 memcpy(docline, begPtr, len);
1864 docline[len ] = '\n'; // Terminate all lines by LF
1865 docline[len+1] = '\0';
1866 }
1867 }
1868
1869 UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
1870 if (pAttrs)
1871 pAttrs->storageClass = STCundefined;
1872 f->fbody = sbody;
1873 return f;
1874}
1875
1876/*****************************************
1877 * Parse a new definition:
1878 * new(parameters) { body }
1879 * Current token is 'new'.
1880 */
1881
1882Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
1883{
1884 Loc loc = token.loc;
1885 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1886
1887 nextToken();
1888
1889 int varargs;
1890 Parameters *parameters = parseParameters(&varargs);
1891 NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
1892 if (pAttrs)
1893 pAttrs->storageClass = STCundefined;
1894 Dsymbol *s = parseContracts(f);
1895 return s;
1896}
1897
1898/*****************************************
1899 * Parse a delete definition:
1900 * delete(parameters) { body }
1901 * Current token is 'delete'.
1902 */
1903
1904Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
1905{
1906 Loc loc = token.loc;
1907 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1908
1909 nextToken();
1910
1911 int varargs;
1912 Parameters *parameters = parseParameters(&varargs);
1913 if (varargs)
1914 error("... not allowed in delete function parameter list");
1915 DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
1916 if (pAttrs)
1917 pAttrs->storageClass = STCundefined;
1918 Dsymbol *s = parseContracts(f);
1919 return s;
1920}
1921
1922/**********************************************
1923 * Parse parameter list.
1924 */
1925
1926Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl)
1927{
1928 Parameters *parameters = new Parameters();
1929 int varargs = 0;
1930 int hasdefault = 0;
1931
1932 check(TOKlparen);
1933 while (1)
1934 {
1935 Identifier *ai = NULL;
1936 Type *at;
1937 StorageClass storageClass = 0;
1938 StorageClass stc;
1939 Expression *ae;
1940
1941 for (;1; nextToken())
1942 {
1943 switch (token.value)
1944 {
1945 case TOKrparen:
1946 break;
1947
1948 case TOKdotdotdot:
1949 varargs = 1;
1950 nextToken();
1951 break;
1952
1953 case TOKconst:
1954 if (peek(&token)->value == TOKlparen)
1955 goto Ldefault;
1956 stc = STCconst;
1957 goto L2;
1958
1959 case TOKimmutable:
1960 if (peek(&token)->value == TOKlparen)
1961 goto Ldefault;
1962 stc = STCimmutable;
1963 goto L2;
1964
1965 case TOKshared:
1966 if (peek(&token)->value == TOKlparen)
1967 goto Ldefault;
1968 stc = STCshared;
1969 goto L2;
1970
1971 case TOKwild:
1972 if (peek(&token)->value == TOKlparen)
1973 goto Ldefault;
1974 stc = STCwild;
1975 goto L2;
1976
1977 case TOKin: stc = STCin; goto L2;
1978 case TOKout: stc = STCout; goto L2;
1979 case TOKref: stc = STCref; goto L2;
1980 case TOKlazy: stc = STClazy; goto L2;
1981 case TOKscope: stc = STCscope; goto L2;
1982 case TOKfinal: stc = STCfinal; goto L2;
1983 case TOKauto: stc = STCauto; goto L2;
1984 case TOKreturn: stc = STCreturn; goto L2;
1985 L2:
1986 storageClass = appendStorageClass(storageClass, stc);
1987 continue;
1988
1989 default:
1990 Ldefault:
1991 { stc = storageClass & (STCin | STCout | STCref | STClazy);
1992 // if stc is not a power of 2
1993 if (stc & (stc - 1) &&
1994 !(stc == (STCin | STCref)))
1995 error("incompatible parameter storage classes");
1996 //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
1997 //error("scope cannot be ref or out");
1998
1999 Token *t;
2000 if (tpl && token.value == TOKidentifier &&
2001 (t = peek(&token), (t->value == TOKcomma ||
2002 t->value == TOKrparen ||
2003 t->value == TOKdotdotdot)))
2004 {
2005 Identifier *id = Identifier::generateId("__T");
2006 Loc loc = token.loc;
2007 at = new TypeIdentifier(loc, id);
2008 if (!*tpl)
2009 *tpl = new TemplateParameters();
2010 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
2011 (*tpl)->push(tp);
2012
2013 ai = token.ident;
2014 nextToken();
2015 }
2016 else
2017 at = parseType(&ai);
2018 ae = NULL;
2019 if (token.value == TOKassign) // = defaultArg
2020 { nextToken();
2021 ae = parseDefaultInitExp();
2022 hasdefault = 1;
2023 }
2024 else
2025 { if (hasdefault)
2026 error("default argument expected for %s",
2027 ai ? ai->toChars() : at->toChars());
2028 }
2029 if (token.value == TOKdotdotdot)
2030 { /* This is:
2031 * at ai ...
2032 */
2033
2034 if (storageClass & (STCout | STCref))
2035 error("variadic argument cannot be out or ref");
2036 varargs = 2;
2037 parameters->push(new Parameter(storageClass, at, ai, ae));
2038 nextToken();
2039 break;
2040 }
2041 parameters->push(new Parameter(storageClass, at, ai, ae));
2042 if (token.value == TOKcomma)
2043 { nextToken();
2044 goto L1;
2045 }
2046 break;
2047 }
2048 }
2049 break;
2050 }
2051 break;
2052
2053 L1: ;
2054 }
2055 check(TOKrparen);
2056 *pvarargs = varargs;
2057 return parameters;
2058}
2059
2060
2061/*************************************
2062 */
2063
2064EnumDeclaration *Parser::parseEnum()
2065{
2066 EnumDeclaration *e;
2067 Identifier *id;
2068 Type *memtype;
2069 Loc loc = token.loc;
2070
2071 //printf("Parser::parseEnum()\n");
2072 nextToken();
2073 if (token.value == TOKidentifier)
2074 {
2075 id = token.ident;
2076 nextToken();
2077 }
2078 else
2079 id = NULL;
2080
2081 if (token.value == TOKcolon)
2082 {
2083 nextToken();
2084
2085 int alt = 0;
2086 Loc typeLoc = token.loc;
2087 memtype = parseBasicType();
2088 memtype = parseDeclarator(memtype, &alt, NULL);
2089 checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
2090 }
2091 else
2092 memtype = NULL;
2093
2094 e = new EnumDeclaration(loc, id, memtype);
2095 if (token.value == TOKsemicolon && id)
2096 nextToken();
2097 else if (token.value == TOKlcurly)
2098 {
2099 //printf("enum definition\n");
2100 e->members = new Dsymbols();
2101 nextToken();
2102 const utf8_t *comment = token.blockComment;
2103 while (token.value != TOKrcurly)
2104 {
2105 /* Can take the following forms:
2106 * 1. ident
2107 * 2. ident = value
2108 * 3. type ident = value
2109 */
2110
2111 loc = token.loc;
2112
2113 Type *type = NULL;
2114 Identifier *ident = NULL;
2115 Token *tp = peek(&token);
2116 if (token.value == TOKidentifier &&
2117 (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
2118 {
2119 ident = token.ident;
2120 type = NULL;
2121 nextToken();
2122 }
2123 else
2124 {
2125 type = parseType(&ident, NULL);
2126 if (!ident)
2127 error("no identifier for declarator %s", type->toChars());
2128 if (id || memtype)
2129 error("type only allowed if anonymous enum and no enum type");
2130 }
2131
2132 Expression *value;
2133 if (token.value == TOKassign)
2134 {
2135 nextToken();
2136 value = parseAssignExp();
2137 }
2138 else
2139 {
2140 value = NULL;
2141 if (type)
2142 error("if type, there must be an initializer");
2143 }
2144
2145 EnumMember *em = new EnumMember(loc, ident, value, type);
2146 e->members->push(em);
2147
2148 if (token.value == TOKrcurly)
2149 ;
2150 else
2151 {
2152 addComment(em, comment);
2153 comment = NULL;
2154 check(TOKcomma);
2155 }
2156 addComment(em, comment);
2157 comment = token.blockComment;
2158
2159 if (token.value == TOKeof)
2160 {
2161 error("premature end of file");
2162 break;
2163 }
2164 }
2165 nextToken();
2166 }
2167 else
2168 error("enum declaration is invalid");
2169
2170 //printf("-parseEnum() %s\n", e->toChars());
2171 return e;
2172}
2173
2174/********************************
2175 * Parse struct, union, interface, class.
2176 */
2177
2178Dsymbol *Parser::parseAggregate()
2179{
2180 AggregateDeclaration *a = NULL;
2181 int anon = 0;
2182 Identifier *id;
2183 TemplateParameters *tpl = NULL;
2184 Expression *constraint = NULL;
2185 Loc loc = token.loc;
2186 TOK tok = token.value;
2187
2188 //printf("Parser::parseAggregate()\n");
2189 nextToken();
2190 if (token.value != TOKidentifier)
2191 {
2192 id = NULL;
2193 }
2194 else
2195 {
2196 id = token.ident;
2197 nextToken();
2198
2199 if (token.value == TOKlparen)
2200 {
2201 // Class template declaration.
2202 // Gather template parameter list
2203 tpl = parseTemplateParameterList();
2204 constraint = parseConstraint();
2205 }
2206 }
2207
2208 switch (tok)
2209 {
2210 case TOKclass:
2211 case TOKinterface:
2212 {
2213 if (!id)
2214 error(loc, "anonymous classes not allowed");
2215
2216 // Collect base class(es)
2217 BaseClasses *baseclasses = NULL;
2218 if (token.value == TOKcolon)
2219 {
2220 nextToken();
2221 baseclasses = parseBaseClasses();
2222
2223 if (tpl)
2224 {
2225 Expression *tempCons = parseConstraint();
2226 if (tempCons)
2227 {
2228 if (constraint)
2229 error("members expected");
2230 else
2231 constraint = tempCons;
2232 }
2233 }
2234
2235 if (token.value != TOKlcurly)
2236 error("members expected");
2237 }
2238
2239 if (tok == TOKclass)
2240 {
2241 bool inObject = md && !md->packages && md->id == Id::object;
2242 a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
2243 }
2244 else
2245 a = new InterfaceDeclaration(loc, id, baseclasses);
2246 break;
2247 }
2248
2249 case TOKstruct:
2250 if (id)
2251 {
2252 bool inObject = md && !md->packages && md->id == Id::object;
2253 a = new StructDeclaration(loc, id, inObject);
2254 }
2255 else
2256 anon = 1;
2257 break;
2258
2259 case TOKunion:
2260 if (id)
2261 a = new UnionDeclaration(loc, id);
2262 else
2263 anon = 2;
2264 break;
2265
2266 default:
2267 assert(0);
2268 break;
2269 }
2270 if (a && token.value == TOKsemicolon)
2271 {
2272 nextToken();
2273 }
2274 else if (token.value == TOKlcurly)
2275 {
2276 const Loc lookingForElseSave = lookingForElse;
2277 lookingForElse = Loc();
2278 //printf("aggregate definition\n");
2279 nextToken();
2280 Dsymbols *decl = parseDeclDefs(0);
2281 lookingForElse = lookingForElseSave;
2282 if (token.value != TOKrcurly)
2283 error("} expected following members in %s declaration at %s",
2284 Token::toChars(tok), loc.toChars());
2285 nextToken();
2286 if (anon)
2287 {
2288 /* Anonymous structs/unions are more like attributes.
2289 */
2290 return new AnonDeclaration(loc, anon == 2, decl);
2291 }
2292 else
2293 a->members = decl;
2294 }
2295 else
2296 {
2297 error("{ } expected following %s declaration", Token::toChars(tok));
2298 a = new StructDeclaration(loc, NULL, false);
2299 }
2300
2301 if (tpl)
2302 {
2303 // Wrap a template around the aggregate declaration
2304 Dsymbols *decldefs = new Dsymbols();
2305 decldefs->push(a);
2306 TemplateDeclaration *tempdecl =
2307 new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
2308 return tempdecl;
2309 }
2310
2311 return a;
2312}
2313
2314/*******************************************
2315 */
2316
2317BaseClasses *Parser::parseBaseClasses()
2318{
2319 BaseClasses *baseclasses = new BaseClasses();
2320
2321 for (; 1; nextToken())
2322 {
2323 bool prot = false;
2324 Prot protection = Prot(PROTpublic);
2325 switch (token.value)
2326 {
2327 case TOKprivate:
2328 prot = true;
2329 protection = Prot(PROTprivate);
2330 nextToken();
2331 break;
2332 case TOKpackage:
2333 prot = true;
2334 protection = Prot(PROTpackage);
2335 nextToken();
2336 break;
2337 case TOKprotected:
2338 prot = true;
2339 protection = Prot(PROTprotected);
2340 nextToken();
2341 break;
2342 case TOKpublic:
2343 prot = true;
2344 protection = Prot(PROTpublic);
2345 nextToken();
2346 break;
2347 default: break;
2348 }
2349 if (prot)
2350 error("use of base class protection is no longer supported");
2351 BaseClass *b = new BaseClass(parseBasicType());
2352 baseclasses->push(b);
2353 if (token.value != TOKcomma)
2354 break;
2355 }
2356 return baseclasses;
2357}
2358
2359/**************************************
2360 * Parse constraint.
2361 * Constraint is of the form:
2362 * if ( ConstraintExpression )
2363 */
2364
2365Expression *Parser::parseConstraint()
2366{ Expression *e = NULL;
2367
2368 if (token.value == TOKif)
2369 {
2370 nextToken(); // skip over 'if'
2371 check(TOKlparen);
2372 e = parseExpression();
2373 check(TOKrparen);
2374 }
2375 return e;
2376}
2377
2378/**************************************
2379 * Parse a TemplateDeclaration.
2380 */
2381
2382TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
2383{
2384 TemplateDeclaration *tempdecl;
2385 Identifier *id;
2386 TemplateParameters *tpl;
2387 Dsymbols *decldefs;
2388 Expression *constraint = NULL;
2389 Loc loc = token.loc;
2390
2391 nextToken();
2392 if (token.value != TOKidentifier)
2393 {
2394 error("identifier expected following template");
2395 goto Lerr;
2396 }
2397 id = token.ident;
2398 nextToken();
2399 tpl = parseTemplateParameterList();
2400 if (!tpl)
2401 goto Lerr;
2402
2403 constraint = parseConstraint();
2404
2405 if (token.value != TOKlcurly)
2406 {
2407 error("members of template declaration expected");
2408 goto Lerr;
2409 }
2410 else
2411 decldefs = parseBlock(NULL);
2412
2413 tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
2414 return tempdecl;
2415
2416Lerr:
2417 return NULL;
2418}
2419
2420/******************************************
2421 * Parse template parameter list.
2422 * Input:
2423 * flag 0: parsing "( list )"
2424 * 1: parsing non-empty "list )"
2425 */
2426
2427TemplateParameters *Parser::parseTemplateParameterList(int flag)
2428{
2429 TemplateParameters *tpl = new TemplateParameters();
2430
2431 if (!flag && token.value != TOKlparen)
2432 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
2433 goto Lerr;
2434 }
2435 nextToken();
2436
2437 // Get array of TemplateParameters
2438 if (flag || token.value != TOKrparen)
2439 {
2440 int isvariadic = 0;
2441 while (token.value != TOKrparen)
2442 {
2443 TemplateParameter *tp;
2444 Loc loc;
2445 Identifier *tp_ident = NULL;
2446 Type *tp_spectype = NULL;
2447 Type *tp_valtype = NULL;
2448 Type *tp_defaulttype = NULL;
2449 Expression *tp_specvalue = NULL;
2450 Expression *tp_defaultvalue = NULL;
2451 Token *t;
2452
2453 // Get TemplateParameter
2454
2455 // First, look ahead to see if it is a TypeParameter or a ValueParameter
2456 t = peek(&token);
2457 if (token.value == TOKalias)
2458 { // AliasParameter
2459 nextToken();
2460 loc = token.loc; // todo
2461 Type *spectype = NULL;
2462 if (isDeclaration(&token, 2, TOKreserved, NULL))
2463 {
2464 spectype = parseType(&tp_ident);
2465 }
2466 else
2467 {
2468 if (token.value != TOKidentifier)
2469 {
2470 error("identifier expected for template alias parameter");
2471 goto Lerr;
2472 }
2473 tp_ident = token.ident;
2474 nextToken();
2475 }
2476 RootObject *spec = NULL;
2477 if (token.value == TOKcolon) // : Type
2478 {
2479 nextToken();
2480 if (isDeclaration(&token, 0, TOKreserved, NULL))
2481 spec = parseType();
2482 else
2483 spec = parseCondExp();
2484 }
2485 RootObject *def = NULL;
2486 if (token.value == TOKassign) // = Type
2487 {
2488 nextToken();
2489 if (isDeclaration(&token, 0, TOKreserved, NULL))
2490 def = parseType();
2491 else
2492 def = parseCondExp();
2493 }
2494 tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
2495 }
2496 else if (t->value == TOKcolon || t->value == TOKassign ||
2497 t->value == TOKcomma || t->value == TOKrparen)
2498 {
2499 // TypeParameter
2500 if (token.value != TOKidentifier)
2501 {
2502 error("identifier expected for template type parameter");
2503 goto Lerr;
2504 }
2505 loc = token.loc;
2506 tp_ident = token.ident;
2507 nextToken();
2508 if (token.value == TOKcolon) // : Type
2509 {
2510 nextToken();
2511 tp_spectype = parseType();
2512 }
2513 if (token.value == TOKassign) // = Type
2514 {
2515 nextToken();
2516 tp_defaulttype = parseType();
2517 }
2518 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2519 }
2520 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
2521 {
2522 // ident...
2523 if (isvariadic)
2524 error("variadic template parameter must be last");
2525 isvariadic = 1;
2526 loc = token.loc;
2527 tp_ident = token.ident;
2528 nextToken();
2529 nextToken();
2530 tp = new TemplateTupleParameter(loc, tp_ident);
2531 }
2532 else if (token.value == TOKthis)
2533 {
2534 // ThisParameter
2535 nextToken();
2536 if (token.value != TOKidentifier)
2537 {
2538 error("identifier expected for template this parameter");
2539 goto Lerr;
2540 }
2541 loc = token.loc;
2542 tp_ident = token.ident;
2543 nextToken();
2544 if (token.value == TOKcolon) // : Type
2545 {
2546 nextToken();
2547 tp_spectype = parseType();
2548 }
2549 if (token.value == TOKassign) // = Type
2550 {
2551 nextToken();
2552 tp_defaulttype = parseType();
2553 }
2554 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2555 }
2556 else
2557 {
2558 // ValueParameter
2559 loc = token.loc; // todo
2560 tp_valtype = parseType(&tp_ident);
2561 if (!tp_ident)
2562 {
2563 error("identifier expected for template value parameter");
2564 tp_ident = Identifier::idPool("error");
2565 }
2566 if (token.value == TOKcolon) // : CondExpression
2567 {
2568 nextToken();
2569 tp_specvalue = parseCondExp();
2570 }
2571 if (token.value == TOKassign) // = CondExpression
2572 {
2573 nextToken();
2574 tp_defaultvalue = parseDefaultInitExp();
2575 }
2576 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
2577 }
2578 tpl->push(tp);
2579 if (token.value != TOKcomma)
2580 break;
2581 nextToken();
2582 }
2583 }
2584 check(TOKrparen);
2585Lerr:
2586 return tpl;
2587}
2588
2589/******************************************
2590 * Parse template mixin.
2591 * mixin Foo;
2592 * mixin Foo!(args);
2593 * mixin a.b.c!(args).Foo!(args);
2594 * mixin Foo!(args) identifier;
2595 * mixin typeof(expr).identifier!(args);
2596 */
2597
2598Dsymbol *Parser::parseMixin()
2599{
2600 TemplateMixin *tm;
2601 Identifier *id;
2602 Objects *tiargs;
2603
2604 //printf("parseMixin()\n");
2605 Loc locMixin = token.loc;
2606 nextToken(); // skip 'mixin'
2607
2608 Loc loc = token.loc;
2609 TypeQualified *tqual = NULL;
2610 if (token.value == TOKdot)
2611 {
2612 id = Id::empty;
2613 }
2614 else
2615 {
2616 if (token.value == TOKtypeof)
2617 {
2618 tqual = parseTypeof();
2619 check(TOKdot);
2620 }
2621 if (token.value != TOKidentifier)
2622 {
2623 error("identifier expected, not %s", token.toChars());
2624 id = Id::empty;
2625 }
2626 else
2627 id = token.ident;
2628 nextToken();
2629 }
2630
2631 while (1)
2632 {
2633 tiargs = NULL;
2634 if (token.value == TOKnot)
2635 {
2636 tiargs = parseTemplateArguments();
2637 }
2638
2639 if (tiargs && token.value == TOKdot)
2640 {
2641 TemplateInstance *tempinst = new TemplateInstance(loc, id);
2642 tempinst->tiargs = tiargs;
2643 if (!tqual)
2644 tqual = new TypeInstance(loc, tempinst);
2645 else
2646 tqual->addInst(tempinst);
2647 tiargs = NULL;
2648 }
2649 else
2650 {
2651 if (!tqual)
2652 tqual = new TypeIdentifier(loc, id);
2653 else
2654 tqual->addIdent(id);
2655 }
2656
2657 if (token.value != TOKdot)
2658 break;
2659
2660 nextToken();
2661 if (token.value != TOKidentifier)
2662 {
2663 error("identifier expected following '.' instead of '%s'", token.toChars());
2664 break;
2665 }
2666 loc = token.loc;
2667 id = token.ident;
2668 nextToken();
2669 }
2670
2671 if (token.value == TOKidentifier)
2672 {
2673 id = token.ident;
2674 nextToken();
2675 }
2676 else
2677 id = NULL;
2678
2679 tm = new TemplateMixin(locMixin, id, tqual, tiargs);
2680 if (token.value != TOKsemicolon)
2681 error("';' expected after mixin");
2682 nextToken();
2683
2684 return tm;
2685}
2686
2687/******************************************
2688 * Parse template arguments.
2689 * Input:
2690 * current token is opening '!'
2691 * Output:
2692 * current token is one after closing ')'
2693 */
2694
2695Objects *Parser::parseTemplateArguments()
2696{
2697 Objects *tiargs;
2698
2699 nextToken();
2700 if (token.value == TOKlparen)
2701 {
2702 // ident!(template_arguments)
2703 tiargs = parseTemplateArgumentList();
2704 }
2705 else
2706 {
2707 // ident!template_argument
2708 tiargs = parseTemplateSingleArgument();
2709 }
2710 if (token.value == TOKnot)
2711 {
2712 TOK tok = peekNext();
2713 if (tok != TOKis && tok != TOKin)
2714 {
2715 error("multiple ! arguments are not allowed");
2716 Lagain:
2717 nextToken();
2718 if (token.value == TOKlparen)
2719 parseTemplateArgumentList();
2720 else
2721 parseTemplateSingleArgument();
2722 if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
2723 goto Lagain;
2724 }
2725 }
2726 return tiargs;
2727}
2728
2729/******************************************
2730 * Parse template argument list.
2731 * Input:
2732 * current token is opening '(',
2733 * or ',' for __traits
2734 * Output:
2735 * current token is one after closing ')'
2736 */
2737
2738Objects *Parser::parseTemplateArgumentList()
2739{
2740 //printf("Parser::parseTemplateArgumentList()\n");
2741 Objects *tiargs = new Objects();
2742 TOK endtok = TOKrparen;
2743 assert(token.value == TOKlparen || token.value == TOKcomma);
2744 nextToken();
2745
2746 // Get TemplateArgumentList
2747 while (token.value != endtok)
2748 {
2749 // See if it is an Expression or a Type
2750 if (isDeclaration(&token, 0, TOKreserved, NULL))
2751 { // Template argument is a type
2752 Type *ta = parseType();
2753 tiargs->push(ta);
2754 }
2755 else
2756 { // Template argument is an expression
2757 Expression *ea = parseAssignExp();
2758 tiargs->push(ea);
2759 }
2760 if (token.value != TOKcomma)
2761 break;
2762 nextToken();
2763 }
2764 check(endtok, "template argument list");
2765 return tiargs;
2766}
2767
2768/*****************************
2769 * Parse single template argument, to support the syntax:
2770 * foo!arg
2771 * Input:
2772 * current token is the arg
2773 */
2774
2775Objects *Parser::parseTemplateSingleArgument()
2776{
2777 //printf("parseTemplateSingleArgument()\n");
2778 Objects *tiargs = new Objects();
2779 Type *ta;
2780 switch (token.value)
2781 {
2782 case TOKidentifier:
2783 ta = new TypeIdentifier(token.loc, token.ident);
2784 goto LabelX;
2785
2786 case TOKvector:
2787 ta = parseVector();
2788 goto LabelX;
2789
2790 case TOKvoid: ta = Type::tvoid; goto LabelX;
2791 case TOKint8: ta = Type::tint8; goto LabelX;
2792 case TOKuns8: ta = Type::tuns8; goto LabelX;
2793 case TOKint16: ta = Type::tint16; goto LabelX;
2794 case TOKuns16: ta = Type::tuns16; goto LabelX;
2795 case TOKint32: ta = Type::tint32; goto LabelX;
2796 case TOKuns32: ta = Type::tuns32; goto LabelX;
2797 case TOKint64: ta = Type::tint64; goto LabelX;
2798 case TOKuns64: ta = Type::tuns64; goto LabelX;
2799 case TOKint128: ta = Type::tint128; goto LabelX;
2800 case TOKuns128: ta = Type::tuns128; goto LabelX;
2801 case TOKfloat32: ta = Type::tfloat32; goto LabelX;
2802 case TOKfloat64: ta = Type::tfloat64; goto LabelX;
2803 case TOKfloat80: ta = Type::tfloat80; goto LabelX;
2804 case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
2805 case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
2806 case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
2807 case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
2808 case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
2809 case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
2810 case TOKbool: ta = Type::tbool; goto LabelX;
2811 case TOKchar: ta = Type::tchar; goto LabelX;
2812 case TOKwchar: ta = Type::twchar; goto LabelX;
2813 case TOKdchar: ta = Type::tdchar; goto LabelX;
2814 LabelX:
2815 tiargs->push(ta);
2816 nextToken();
2817 break;
2818
2819 case TOKint32v:
2820 case TOKuns32v:
2821 case TOKint64v:
2822 case TOKuns64v:
2823 case TOKint128v:
2824 case TOKuns128v:
2825 case TOKfloat32v:
2826 case TOKfloat64v:
2827 case TOKfloat80v:
2828 case TOKimaginary32v:
2829 case TOKimaginary64v:
2830 case TOKimaginary80v:
2831 case TOKnull:
2832 case TOKtrue:
2833 case TOKfalse:
2834 case TOKcharv:
2835 case TOKwcharv:
2836 case TOKdcharv:
2837 case TOKstring:
2838 case TOKxstring:
2839 case TOKfile:
2840 case TOKfilefullpath:
2841 case TOKline:
2842 case TOKmodulestring:
2843 case TOKfuncstring:
2844 case TOKprettyfunc:
2845 case TOKthis:
2846 { // Template argument is an expression
2847 Expression *ea = parsePrimaryExp();
2848 tiargs->push(ea);
2849 break;
2850 }
2851
2852 default:
2853 error("template argument expected following !");
2854 break;
2855 }
2856 return tiargs;
2857}
2858
2859Dsymbols *Parser::parseImport()
2860{
2861 Dsymbols *decldefs = new Dsymbols();
2862 Identifier *aliasid = NULL;
2863
2864 int isstatic = token.value == TOKstatic;
2865 if (isstatic)
2866 nextToken();
2867
2868 //printf("Parser::parseImport()\n");
2869 do
2870 {
2871 L1:
2872 nextToken();
2873 if (token.value != TOKidentifier)
2874 {
2875 error("identifier expected following import");
2876 break;
2877 }
2878
2879 Loc loc = token.loc;
2880 Identifier *id = token.ident;
2881 Identifiers *a = NULL;
2882 nextToken();
2883 if (!aliasid && token.value == TOKassign)
2884 {
2885 aliasid = id;
2886 goto L1;
2887 }
2888 while (token.value == TOKdot)
2889 {
2890 if (!a)
2891 a = new Identifiers();
2892 a->push(id);
2893 nextToken();
2894 if (token.value != TOKidentifier)
2895 {
2896 error("identifier expected following package");
2897 break;
2898 }
2899 id = token.ident;
2900 nextToken();
2901 }
2902
2903 Import *s = new Import(loc, a, id, aliasid, isstatic);
2904 decldefs->push(s);
2905
2906 /* Look for
2907 * : alias=name, alias=name;
2908 * syntax.
2909 */
2910 if (token.value == TOKcolon)
2911 {
2912 do
2913 {
2914 nextToken();
2915 if (token.value != TOKidentifier)
2916 {
2917 error("identifier expected following :");
2918 break;
2919 }
2920 Identifier *alias = token.ident;
2921 Identifier *name;
2922 nextToken();
2923 if (token.value == TOKassign)
2924 {
2925 nextToken();
2926 if (token.value != TOKidentifier)
2927 {
2928 error("identifier expected following %s=", alias->toChars());
2929 break;
2930 }
2931 name = token.ident;
2932 nextToken();
2933 }
2934 else
2935 {
2936 name = alias;
2937 alias = NULL;
2938 }
2939 s->addAlias(name, alias);
2940 } while (token.value == TOKcomma);
2941 break; // no comma-separated imports of this form
2942 }
2943
2944 aliasid = NULL;
2945 } while (token.value == TOKcomma);
2946
2947 if (token.value == TOKsemicolon)
2948 nextToken();
2949 else
2950 {
2951 error("';' expected");
2952 nextToken();
2953 }
2954
2955 return decldefs;
2956}
2957
2958Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
2959{
2960 /* Take care of the storage class prefixes that
2961 * serve as type attributes:
2962 * const type
2963 * immutable type
2964 * shared type
2965 * inout type
2966 * inout const type
2967 * shared const type
2968 * shared inout type
2969 * shared inout const type
2970 */
2971 StorageClass stc = 0;
2972 while (1)
2973 {
2974 switch (token.value)
2975 {
2976 case TOKconst:
2977 if (peekNext() == TOKlparen)
2978 break; // const as type constructor
2979 stc |= STCconst; // const as storage class
2980 nextToken();
2981 continue;
2982
2983 case TOKimmutable:
2984 if (peekNext() == TOKlparen)
2985 break;
2986 stc |= STCimmutable;
2987 nextToken();
2988 continue;
2989
2990 case TOKshared:
2991 if (peekNext() == TOKlparen)
2992 break;
2993 stc |= STCshared;
2994 nextToken();
2995 continue;
2996
2997 case TOKwild:
2998 if (peekNext() == TOKlparen)
2999 break;
3000 stc |= STCwild;
3001 nextToken();
3002 continue;
3003
3004 default:
3005 break;
3006 }
3007 break;
3008 }
3009
3010 Loc typeLoc = token.loc;
3011
3012 Type *t;
3013 t = parseBasicType();
3014
3015 int alt = 0;
3016 t = parseDeclarator(t, &alt, pident, ptpl);
3017 checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
3018
3019 t = t->addSTC(stc);
3020 return t;
3021}
3022
3023Type *Parser::parseBasicType(bool dontLookDotIdents)
3024{
3025 Type *t;
3026 Loc loc;
3027 Identifier *id;
3028
3029 //printf("parseBasicType()\n");
3030 switch (token.value)
3031 {
3032 case TOKvoid: t = Type::tvoid; goto LabelX;
3033 case TOKint8: t = Type::tint8; goto LabelX;
3034 case TOKuns8: t = Type::tuns8; goto LabelX;
3035 case TOKint16: t = Type::tint16; goto LabelX;
3036 case TOKuns16: t = Type::tuns16; goto LabelX;
3037 case TOKint32: t = Type::tint32; goto LabelX;
3038 case TOKuns32: t = Type::tuns32; goto LabelX;
3039 case TOKint64: t = Type::tint64; goto LabelX;
3040 case TOKuns64: t = Type::tuns64; goto LabelX;
3041 case TOKint128: t = Type::tint128; goto LabelX;
3042 case TOKuns128: t = Type::tuns128; goto LabelX;
3043 case TOKfloat32: t = Type::tfloat32; goto LabelX;
3044 case TOKfloat64: t = Type::tfloat64; goto LabelX;
3045 case TOKfloat80: t = Type::tfloat80; goto LabelX;
3046 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
3047 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
3048 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
3049 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
3050 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
3051 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
3052 case TOKbool: t = Type::tbool; goto LabelX;
3053 case TOKchar: t = Type::tchar; goto LabelX;
3054 case TOKwchar: t = Type::twchar; goto LabelX;
3055 case TOKdchar: t = Type::tdchar; goto LabelX;
3056 LabelX:
3057 nextToken();
3058 break;
3059
3060 case TOKthis:
3061 case TOKsuper:
3062 case TOKidentifier:
3063 loc = token.loc;
3064 id = token.ident;
3065 nextToken();
3066 if (token.value == TOKnot)
3067 {
3068 // ident!(template_arguments)
3069 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3070 tempinst->tiargs = parseTemplateArguments();
3071 t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
3072 }
3073 else
3074 {
3075 t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
3076 }
3077 break;
3078
3079 case TOKdot:
3080 // Leading . as in .foo
3081 t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
3082 break;
3083
3084 case TOKtypeof:
3085 // typeof(expression)
3086 t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3087 break;
3088
3089 case TOKvector:
3090 t = parseVector();
3091 break;
3092
3093 case TOKconst:
3094 // const(type)
3095 nextToken();
3096 check(TOKlparen);
3097 t = parseType()->addSTC(STCconst);
3098 check(TOKrparen);
3099 break;
3100
3101 case TOKimmutable:
3102 // immutable(type)
3103 nextToken();
3104 check(TOKlparen);
3105 t = parseType()->addSTC(STCimmutable);
3106 check(TOKrparen);
3107 break;
3108
3109 case TOKshared:
3110 // shared(type)
3111 nextToken();
3112 check(TOKlparen);
3113 t = parseType()->addSTC(STCshared);
3114 check(TOKrparen);
3115 break;
3116
3117 case TOKwild:
3118 // wild(type)
3119 nextToken();
3120 check(TOKlparen);
3121 t = parseType()->addSTC(STCwild);
3122 check(TOKrparen);
3123 break;
3124
3125 default:
3126 error("basic type expected, not %s", token.toChars());
3127 t = Type::terror;
3128 break;
3129 }
3130 return t;
3131}
3132
3133Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
3134{
3135 Type *maybeArray = NULL;
3136 // See https://issues.dlang.org/show_bug.cgi?id=1215
3137 // A basic type can look like MyType (typical case), but also:
3138 // MyType.T -> A type
3139 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3140 // MyType[expr].T -> A type.
3141 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3142 // (iif MyType[expr].T is a Ttuple)
3143 while (1)
3144 {
3145 switch (token.value)
3146 {
3147 case TOKdot:
3148 {
3149 nextToken();
3150 if (token.value != TOKidentifier)
3151 {
3152 error("identifier expected following '.' instead of '%s'", token.toChars());
3153 break;
3154 }
3155 if (maybeArray)
3156 {
3157 // This is actually a TypeTuple index, not an {a/s}array.
3158 // We need to have a while loop to unwind all index taking:
3159 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3160 Objects dimStack;
3161 Type *t = maybeArray;
3162 while (true)
3163 {
3164 if (t->ty == Tsarray)
3165 {
3166 // The index expression is an Expression.
3167 TypeSArray *a = (TypeSArray *)t;
3168 dimStack.push(a->dim->syntaxCopy());
3169 t = a->next->syntaxCopy();
3170 }
3171 else if (t->ty == Taarray)
3172 {
3173 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3174 TypeAArray *a = (TypeAArray *)t;
3175 dimStack.push(a->index->syntaxCopy());
3176 t = a->next->syntaxCopy();
3177 }
3178 else
3179 {
3180 break;
3181 }
3182 }
3183 assert(dimStack.dim > 0);
3184 // We're good. Replay indices in the reverse order.
3185 tid = (TypeQualified *)t;
3186 while (dimStack.dim)
3187 {
3188 tid->addIndex(dimStack.pop());
3189 }
3190 maybeArray = NULL;
3191 }
3192 Loc loc = token.loc;
3193 Identifier *id = token.ident;
3194 nextToken();
3195 if (token.value == TOKnot)
3196 {
3197 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3198 tempinst->tiargs = parseTemplateArguments();
3199 tid->addInst(tempinst);
3200 }
3201 else
3202 tid->addIdent(id);
3203 continue;
3204 }
3205 case TOKlbracket:
3206 {
3207 if (dontLookDotIdents) // workaround for Bugzilla 14911
3208 goto Lend;
3209
3210 nextToken();
3211 Type *t = maybeArray ? maybeArray : (Type *)tid;
3212 if (token.value == TOKrbracket)
3213 {
3214 // It's a dynamic array, and we're done:
3215 // T[].U does not make sense.
3216 t = new TypeDArray(t);
3217 nextToken();
3218 return t;
3219 }
3220 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3221 {
3222 // This can be one of two things:
3223 // 1 - an associative array declaration, T[type]
3224 // 2 - an associative array declaration, T[expr]
3225 // These can only be disambiguated later.
3226 Type *index = parseType(); // [ type ]
3227 maybeArray = new TypeAArray(t, index);
3228 check(TOKrbracket);
3229 }
3230 else
3231 {
3232 // This can be one of three things:
3233 // 1 - an static array declaration, T[expr]
3234 // 2 - a slice, T[expr .. expr]
3235 // 3 - a template parameter pack index expression, T[expr].U
3236 // 1 and 3 can only be disambiguated later.
3237 //printf("it's type[expression]\n");
3238 inBrackets++;
3239 Expression *e = parseAssignExp(); // [ expression ]
3240 if (token.value == TOKslice)
3241 {
3242 // It's a slice, and we're done.
3243 nextToken();
3244 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3245 t = new TypeSlice(t, e, e2);
3246 inBrackets--;
3247 check(TOKrbracket);
3248 return t;
3249 }
3250 else
3251 {
3252 maybeArray = new TypeSArray(t, e);
3253 inBrackets--;
3254 check(TOKrbracket);
3255 continue;
3256 }
3257 }
3258 break;
3259 }
3260 default:
3261 goto Lend;
3262 }
3263 }
3264Lend:
3265 return maybeArray ? maybeArray : (Type *)tid;
3266}
3267
3268/******************************************
3269 * Parse things that follow the initial type t.
3270 * t *
3271 * t []
3272 * t [type]
3273 * t [expression]
3274 * t [expression .. expression]
3275 * t function
3276 * t delegate
3277 */
3278
3279Type *Parser::parseBasicType2(Type *t)
3280{
3281 //printf("parseBasicType2()\n");
3282 while (1)
3283 {
3284 switch (token.value)
3285 {
3286 case TOKmul:
3287 t = new TypePointer(t);
3288 nextToken();
3289 continue;
3290
3291 case TOKlbracket:
3292 // Handle []. Make sure things like
3293 // int[3][1] a;
3294 // is (array[1] of array[3] of int)
3295 nextToken();
3296 if (token.value == TOKrbracket)
3297 {
3298 t = new TypeDArray(t); // []
3299 nextToken();
3300 }
3301 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3302 {
3303 // It's an associative array declaration
3304 //printf("it's an associative array\n");
3305 Type *index = parseType(); // [ type ]
3306 t = new TypeAArray(t, index);
3307 check(TOKrbracket);
3308 }
3309 else
3310 {
3311 //printf("it's type[expression]\n");
3312 inBrackets++;
3313 Expression *e = parseAssignExp(); // [ expression ]
3314 if (token.value == TOKslice)
3315 {
3316 nextToken();
3317 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3318 t = new TypeSlice(t, e, e2);
3319 }
3320 else
3321 {
3322 t = new TypeSArray(t,e);
3323 }
3324 inBrackets--;
3325 check(TOKrbracket);
3326 }
3327 continue;
3328
3329 case TOKdelegate:
3330 case TOKfunction:
3331 {
3332 // Handle delegate declaration:
3333 // t delegate(parameter list) nothrow pure
3334 // t function(parameter list) nothrow pure
3335 TOK save = token.value;
3336 nextToken();
3337
3338 int varargs;
3339 Parameters *parameters = parseParameters(&varargs);
3340
3341 StorageClass stc = parsePostfix(STCundefined, NULL);
3342 TypeFunction *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3343 if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
3344 {
3345 if (save == TOKfunction)
3346 error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3347 else
3348 tf = (TypeFunction *)tf->addSTC(stc);
3349 }
3350
3351 if (save == TOKdelegate)
3352 t = new TypeDelegate(tf);
3353 else
3354 t = new TypePointer(tf); // pointer to function
3355 continue;
3356 }
3357
3358 default:
3359 return t;
3360 }
3361 assert(0);
3362 }
3363 assert(0);
3364 return NULL;
3365}
3366
3367Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
3368 TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
3369{
3370 //printf("parseDeclarator(tpl = %p)\n", tpl);
3371 t = parseBasicType2(t);
3372
3373 Type *ts;
3374 switch (token.value)
3375 {
3376 case TOKidentifier:
3377 if (pident)
3378 *pident = token.ident;
3379 else
3380 error("unexpected identifer '%s' in declarator", token.ident->toChars());
3381 ts = t;
3382 nextToken();
3383 break;
3384
3385 case TOKlparen:
3386 {
3387 // like: T (*fp)();
3388 // like: T ((*fp))();
3389 if (peekNext() == TOKmul ||
3390 peekNext() == TOKlparen)
3391 {
3392 /* Parse things with parentheses around the identifier, like:
3393 * int (*ident[3])[]
3394 * although the D style would be:
3395 * int[]*[3] ident
3396 */
3397 *palt |= 1;
3398 nextToken();
3399 ts = parseDeclarator(t, palt, pident);
3400 check(TOKrparen);
3401 break;
3402 }
3403 ts = t;
3404
3405 Token *peekt = &token;
3406 /* Completely disallow C-style things like:
3407 * T (a);
3408 * Improve error messages for the common bug of a missing return type
3409 * by looking to see if (a) looks like a parameter list.
3410 */
3411 if (isParameters(&peekt))
3412 {
3413 error("function declaration without return type. (Note that constructors are always named 'this')");
3414 }
3415 else
3416 error("unexpected ( in declarator");
3417 break;
3418 }
3419
3420 default:
3421 ts = t;
3422 break;
3423 }
3424
3425 // parse DeclaratorSuffixes
3426 while (1)
3427 {
3428 switch (token.value)
3429 {
3430#if CARRAYDECL
3431 /* Support C style array syntax:
3432 * int ident[]
3433 * as opposed to D-style:
3434 * int[] ident
3435 */
3436 case TOKlbracket:
3437 {
3438 // This is the old C-style post [] syntax.
3439 TypeNext *ta;
3440 nextToken();
3441 if (token.value == TOKrbracket)
3442 {
3443 // It's a dynamic array
3444 ta = new TypeDArray(t); // []
3445 nextToken();
3446 *palt |= 2;
3447 }
3448 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3449 {
3450 // It's an associative array
3451 //printf("it's an associative array\n");
3452 Type *index = parseType(); // [ type ]
3453 check(TOKrbracket);
3454 ta = new TypeAArray(t, index);
3455 *palt |= 2;
3456 }
3457 else
3458 {
3459 //printf("It's a static array\n");
3460 Expression *e = parseAssignExp(); // [ expression ]
3461 ta = new TypeSArray(t, e);
3462 check(TOKrbracket);
3463 *palt |= 2;
3464 }
3465
3466 /* Insert ta into
3467 * ts -> ... -> t
3468 * so that
3469 * ts -> ... -> ta -> t
3470 */
3471 Type **pt;
3472 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3473 ;
3474 *pt = ta;
3475 continue;
3476 }
3477#endif
3478 case TOKlparen:
3479 {
3480 if (tpl)
3481 {
3482 Token *tk = peekPastParen(&token);
3483 if (tk->value == TOKlparen)
3484 {
3485 /* Look ahead to see if this is (...)(...),
3486 * i.e. a function template declaration
3487 */
3488 //printf("function template declaration\n");
3489
3490 // Gather template parameter list
3491 *tpl = parseTemplateParameterList();
3492 }
3493 else if (tk->value == TOKassign)
3494 {
3495 /* or (...) =,
3496 * i.e. a variable template declaration
3497 */
3498 //printf("variable template declaration\n");
3499 *tpl = parseTemplateParameterList();
3500 break;
3501 }
3502 }
3503
3504 int varargs;
3505 Parameters *parameters = parseParameters(&varargs);
3506
3507 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3508 */
3509 StorageClass stc = parsePostfix(storageClass, pudas);
3510 // merge prefix storage classes
3511 Type *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3512 tf = tf->addSTC(stc);
3513 if (pdisable)
3514 *pdisable = stc & STCdisable ? 1 : 0;
3515
3516 /* Insert tf into
3517 * ts -> ... -> t
3518 * so that
3519 * ts -> ... -> tf -> t
3520 */
3521 Type **pt;
3522 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3523 ;
3524 *pt = tf;
3525 break;
3526 }
3527 default: break;
3528 }
3529 break;
3530 }
3531
3532 return ts;
3533}
3534
3535void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
3536 bool &setAlignment, Expression *&ealign, Expressions *&udas)
3537{
3538 StorageClass stc;
3539 bool sawLinkage = false; // seen a linkage declaration
3540
3541 while (1)
3542 {
3543 switch (token.value)
3544 {
3545 case TOKconst:
3546 if (peek(&token)->value == TOKlparen)
3547 break; // const as type constructor
3548 stc = STCconst; // const as storage class
3549 goto L1;
3550
3551 case TOKimmutable:
3552 if (peek(&token)->value == TOKlparen)
3553 break;
3554 stc = STCimmutable;
3555 goto L1;
3556
3557 case TOKshared:
3558 if (peek(&token)->value == TOKlparen)
3559 break;
3560 stc = STCshared;
3561 goto L1;
3562
3563 case TOKwild:
3564 if (peek(&token)->value == TOKlparen)
3565 break;
3566 stc = STCwild;
3567 goto L1;
3568
3569 case TOKstatic: stc = STCstatic; goto L1;
3570 case TOKfinal: stc = STCfinal; goto L1;
3571 case TOKauto: stc = STCauto; goto L1;
3572 case TOKscope: stc = STCscope; goto L1;
3573 case TOKoverride: stc = STCoverride; goto L1;
3574 case TOKabstract: stc = STCabstract; goto L1;
3575 case TOKsynchronized: stc = STCsynchronized; goto L1;
3576 case TOKdeprecated: stc = STCdeprecated; goto L1;
3577 case TOKnothrow: stc = STCnothrow; goto L1;
3578 case TOKpure: stc = STCpure; goto L1;
3579 case TOKref: stc = STCref; goto L1;
3580 case TOKgshared: stc = STCgshared; goto L1;
3581 case TOKenum: stc = STCmanifest; goto L1;
3582 case TOKat:
3583 {
3584 stc = parseAttribute(&udas);
3585 if (stc)
3586 goto L1;
3587 continue;
3588 }
3589 L1:
3590 storage_class = appendStorageClass(storage_class, stc);
3591 nextToken();
3592 continue;
3593
3594 case TOKextern:
3595 {
3596 if (peek(&token)->value != TOKlparen)
3597 {
3598 stc = STCextern;
3599 goto L1;
3600 }
3601
3602 if (sawLinkage)
3603 error("redundant linkage declaration");
3604 sawLinkage = true;
3605 Identifiers *idents = NULL;
3606 CPPMANGLE cppmangle = CPPMANGLEdefault;
3607 link = parseLinkage(&idents, &cppmangle);
3608 if (idents)
3609 {
3610 error("C++ name spaces not allowed here");
3611 delete idents;
3612 }
3613 if (cppmangle != CPPMANGLEdefault)
3614 {
3615 error("C++ mangle declaration not allowed here");
3616 }
3617 continue;
3618 }
3619
3620 case TOKalign:
3621 {
3622 nextToken();
3623 setAlignment = true;
3624 if (token.value == TOKlparen)
3625 {
3626 nextToken();
3627 ealign = parseExpression();
3628 check(TOKrparen);
3629 }
3630 continue;
3631 }
3632 default:
3633 break;
3634 }
3635 break;
3636 }
3637}
3638
3639/**********************************
3640 * Parse Declarations.
3641 * These can be:
3642 * 1. declarations at global/class level
3643 * 2. declarations at statement level
3644 * Return array of Declaration *'s.
3645 */
3646
3647Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
3648{
3649 StorageClass storage_class = STCundefined;
3650 Type *ts;
3651 Type *t;
3652 Type *tfirst;
3653 Identifier *ident;
3654 TOK tok = TOKreserved;
3655 LINK link = linkage;
3656 bool setAlignment = false;
3657 Expression *ealign = NULL;
3658 Loc loc = token.loc;
3659 Expressions *udas = NULL;
3660 Token *tk;
3661
3662 //printf("parseDeclarations() %s\n", token.toChars());
3663 if (!comment)
3664 comment = token.blockComment;
3665
3666 if (autodecl)
3667 {
3668 ts = NULL; // infer type
3669 goto L2;
3670 }
3671
3672 if (token.value == TOKalias)
3673 {
3674 tok = token.value;
3675 nextToken();
3676
3677 /* Look for:
3678 * alias identifier this;
3679 */
3680 if (token.value == TOKidentifier && peekNext() == TOKthis)
3681 {
3682 AliasThis *s = new AliasThis(loc, token.ident);
3683 nextToken();
3684 check(TOKthis);
3685 check(TOKsemicolon);
3686 Dsymbols *a = new Dsymbols();
3687 a->push(s);
3688 addComment(s, comment);
3689 return a;
3690 }
3691 /* Look for:
3692 * alias identifier = type;
3693 * alias identifier(...) = type;
3694 */
3695 if (token.value == TOKidentifier &&
3696 skipParensIf(peek(&token), &tk) &&
3697 tk->value == TOKassign)
3698 {
3699 Dsymbols *a = new Dsymbols();
3700 while (1)
3701 {
3702 ident = token.ident;
3703 nextToken();
3704 TemplateParameters *tpl = NULL;
3705 if (token.value == TOKlparen)
3706 tpl = parseTemplateParameterList();
3707 check(TOKassign);
3708
3709 Declaration *v;
3710 if (token.value == TOKfunction ||
3711 token.value == TOKdelegate ||
3712 (token.value == TOKlparen &&
3713 skipAttributes(peekPastParen(&token), &tk) &&
3714 (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
3715 token.value == TOKlcurly ||
3716 (token.value == TOKidentifier && peekNext() == TOKgoesto))
3717 {
3718 // function (parameters) { statements... }
3719 // delegate (parameters) { statements... }
3720 // (parameters) { statements... }
3721 // (parameters) => expression
3722 // { statements... }
3723 // identifier => expression
3724
3725 Dsymbol *s = parseFunctionLiteral();
3726 v = new AliasDeclaration(loc, ident, s);
3727 }
3728 else
3729 {
3730 // StorageClasses type
3731
3732 storage_class = STCundefined;
3733 link = linkage;
3734 setAlignment = false;
3735 ealign = NULL;
3736 udas = NULL;
3737 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3738
3739 if (udas)
3740 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3741
3742 t = parseType();
3743 v = new AliasDeclaration(loc, ident, t);
3744 }
3745 v->storage_class = storage_class;
3746
3747 Dsymbol *s = v;
3748 if (tpl)
3749 {
3750 Dsymbols *a2 = new Dsymbols();
3751 a2->push(s);
3752 TemplateDeclaration *tempdecl =
3753 new TemplateDeclaration(loc, ident, tpl, NULL, a2);
3754 s = tempdecl;
3755 }
3756 if (setAlignment)
3757 {
3758 Dsymbols *ax = new Dsymbols();
3759 ax->push(s);
3760 s = new AlignDeclaration(v->loc, ealign, ax);
3761 }
3762 if (link != linkage)
3763 {
3764 Dsymbols *a2 = new Dsymbols();
3765 a2->push(s);
3766 s = new LinkDeclaration(link, a2);
3767 }
3768 a->push(s);
3769
3770 switch (token.value)
3771 {
3772 case TOKsemicolon:
3773 nextToken();
3774 addComment(s, comment);
3775 break;
3776 case TOKcomma:
3777 nextToken();
3778 addComment(s, comment);
3779 if (token.value != TOKidentifier)
3780 {
3781 error("identifier expected following comma, not %s", token.toChars());
3782 break;
3783 }
3784 if (peekNext() != TOKassign && peekNext() != TOKlparen)
3785 {
3786 error("= expected following identifier");
3787 nextToken();
3788 break;
3789 }
3790 continue;
3791 default:
3792 error("semicolon expected to close %s declaration", Token::toChars(tok));
3793 break;
3794 }
3795 break;
3796 }
3797 return a;
3798 }
3799
3800 // alias StorageClasses type ident;
3801 }
3802
3803 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3804
3805 if (token.value == TOKstruct ||
3806 token.value == TOKunion ||
3807 token.value == TOKclass ||
3808 token.value == TOKinterface)
3809 {
3810 Dsymbol *s = parseAggregate();
3811 Dsymbols *a = new Dsymbols();
3812 a->push(s);
3813
3814 if (storage_class)
3815 {
3816 s = new StorageClassDeclaration(storage_class, a);
3817 a = new Dsymbols();
3818 a->push(s);
3819 }
3820 if (setAlignment)
3821 {
3822 s = new AlignDeclaration(s->loc, ealign, a);
3823 a = new Dsymbols();
3824 a->push(s);
3825 }
3826 if (link != linkage)
3827 {
3828 s = new LinkDeclaration(link, a);
3829 a = new Dsymbols();
3830 a->push(s);
3831 }
3832 if (udas)
3833 {
3834 s = new UserAttributeDeclaration(udas, a);
3835 a = new Dsymbols();
3836 a->push(s);
3837 }
3838
3839 addComment(s, comment);
3840 return a;
3841 }
3842
3843 /* Look for auto initializers:
3844 * storage_class identifier = initializer;
3845 * storage_class identifier(...) = initializer;
3846 */
3847 if ((storage_class || udas) &&
3848 token.value == TOKidentifier &&
3849 skipParensIf(peek(&token), &tk) &&
3850 tk->value == TOKassign)
3851 {
3852 Dsymbols *a = parseAutoDeclarations(storage_class, comment);
3853 if (udas)
3854 {
3855 Dsymbol *s = new UserAttributeDeclaration(udas, a);
3856 a = new Dsymbols();
3857 a->push(s);
3858 }
3859 return a;
3860 }
3861
3862 /* Look for return type inference for template functions.
3863 */
3864 if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) &&
3865 skipAttributes(tk, &tk) &&
3866 (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout ||
3867 tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body)))
3868 {
3869 ts = NULL;
3870 }
3871 else
3872 {
3873 ts = parseBasicType();
3874 ts = parseBasicType2(ts);
3875 }
3876
3877L2:
3878 tfirst = NULL;
3879 Dsymbols *a = new Dsymbols();
3880
3881 if (pAttrs)
3882 {
3883 storage_class |= pAttrs->storageClass;
3884 //pAttrs->storageClass = STCundefined;
3885 }
3886
3887 while (1)
3888 {
3889 TemplateParameters *tpl = NULL;
3890 int disable;
3891 int alt = 0;
3892
3893 loc = token.loc;
3894 ident = NULL;
3895 t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
3896 assert(t);
3897 if (!tfirst)
3898 tfirst = t;
3899 else if (t != tfirst)
3900 error("multiple declarations must have the same type, not %s and %s",
3901 tfirst->toChars(), t->toChars());
3902 bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
3903 if (ident)
3904 checkCstyleTypeSyntax(loc, t, alt, ident);
3905 else if (!isThis)
3906 error("no identifier for declarator %s", t->toChars());
3907
3908 if (tok == TOKalias)
3909 {
3910 Declaration *v;
3911 Initializer *init = NULL;
3912
3913 /* Aliases can no longer have multiple declarators, storage classes,
3914 * linkages, or auto declarations.
3915 * These never made any sense, anyway.
3916 * The code below needs to be fixed to reject them.
3917 * The grammar has already been fixed to preclude them.
3918 */
3919
3920 if (udas)
3921 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3922
3923 if (token.value == TOKassign)
3924 {
3925 nextToken();
3926 init = parseInitializer();
3927 }
3928 if (init)
3929 {
3930 if (isThis)
3931 error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
3932 init->toChars(), init->toChars());
3933 else
3934 error("alias cannot have initializer");
3935 }
3936 v = new AliasDeclaration(loc, ident, t);
3937
3938 v->storage_class = storage_class;
3939 if (pAttrs)
3940 {
3941 /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
3942 * on prefix and postfix.
3943 * @safe alias void function() FP1;
3944 * alias @safe void function() FP2; // FP2 is not @safe
3945 * alias void function() @safe FP3;
3946 */
3947 pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
3948 }
3949 Dsymbol *s = v;
3950
3951 if (link != linkage)
3952 {
3953 Dsymbols *ax = new Dsymbols();
3954 ax->push(v);
3955 s = new LinkDeclaration(link, ax);
3956 }
3957 a->push(s);
3958 switch (token.value)
3959 {
3960 case TOKsemicolon:
3961 nextToken();
3962 addComment(s, comment);
3963 break;
3964
3965 case TOKcomma:
3966 nextToken();
3967 addComment(s, comment);
3968 continue;
3969
3970 default:
3971 error("semicolon expected to close %s declaration", Token::toChars(tok));
3972 break;
3973 }
3974 }
3975 else if (t->ty == Tfunction)
3976 {
3977 Expression *constraint = NULL;
3978
3979 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
3980 FuncDeclaration *f =
3981 new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
3982 if (pAttrs)
3983 pAttrs->storageClass = STCundefined;
3984 if (tpl)
3985 constraint = parseConstraint();
3986 Dsymbol *s = parseContracts(f);
3987 Identifier *tplIdent = s->ident;
3988 if (link != linkage)
3989 {
3990 Dsymbols *ax = new Dsymbols();
3991 ax->push(s);
3992 s = new LinkDeclaration(link, ax);
3993 }
3994 if (udas)
3995 {
3996 Dsymbols *ax = new Dsymbols();
3997 ax->push(s);
3998 s = new UserAttributeDeclaration(udas, ax);
3999 }
4000
4001 /* A template parameter list means it's a function template
4002 */
4003 if (tpl)
4004 {
4005 // Wrap a template around the function declaration
4006 Dsymbols *decldefs = new Dsymbols();
4007 decldefs->push(s);
4008 TemplateDeclaration *tempdecl =
4009 new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4010 s = tempdecl;
4011
4012 if (storage_class & STCstatic)
4013 {
4014 assert(f->storage_class & STCstatic);
4015 f->storage_class &= ~STCstatic;
4016
4017 Dsymbols *ax = new Dsymbols();
4018 ax->push(s);
4019 s = new StorageClassDeclaration(STCstatic, ax);
4020 }
4021 }
4022 a->push(s);
4023 addComment(s, comment);
4024 }
4025 else if (ident)
4026 {
4027 Initializer *init = NULL;
4028 if (token.value == TOKassign)
4029 {
4030 nextToken();
4031 init = parseInitializer();
4032 }
4033
4034 VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
4035 v->storage_class = storage_class;
4036 if (pAttrs)
4037 pAttrs->storageClass = STCundefined;
4038
4039 Dsymbol *s = v;
4040
4041 if (tpl && init)
4042 {
4043 Dsymbols *a2 = new Dsymbols();
4044 a2->push(s);
4045 TemplateDeclaration *tempdecl =
4046 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4047 s = tempdecl;
4048 }
4049 if (link != linkage)
4050 {
4051 Dsymbols *ax = new Dsymbols();
4052 ax->push(s);
4053 s = new LinkDeclaration(link, ax);
4054 }
4055 if (udas)
4056 {
4057 Dsymbols *ax = new Dsymbols();
4058 ax->push(s);
4059 s = new UserAttributeDeclaration(udas, ax);
4060 }
4061 a->push(s);
4062 switch (token.value)
4063 {
4064 case TOKsemicolon:
4065 nextToken();
4066 addComment(s, comment);
4067 break;
4068
4069 case TOKcomma:
4070 nextToken();
4071 addComment(s, comment);
4072 continue;
4073
4074 default:
4075 error("semicolon expected, not '%s'", token.toChars());
4076 break;
4077 }
4078 }
4079 break;
4080 }
4081 return a;
4082}
4083
4084Dsymbol *Parser::parseFunctionLiteral()
4085{
4086 Loc loc = token.loc;
4087
4088 TemplateParameters *tpl = NULL;
4089 Parameters *parameters = NULL;
4090 int varargs = 0;
4091 Type *tret = NULL;
4092 StorageClass stc = 0;
4093 TOK save = TOKreserved;
4094
4095 switch (token.value)
4096 {
4097 case TOKfunction:
4098 case TOKdelegate:
4099 save = token.value;
4100 nextToken();
4101 if (token.value != TOKlparen && token.value != TOKlcurly)
4102 {
4103 // function type (parameters) { statements... }
4104 // delegate type (parameters) { statements... }
4105 tret = parseBasicType();
4106 tret = parseBasicType2(tret); // function return type
4107 }
4108
4109 if (token.value == TOKlparen)
4110 {
4111 // function (parameters) { statements... }
4112 // delegate (parameters) { statements... }
4113 }
4114 else
4115 {
4116 // function { statements... }
4117 // delegate { statements... }
4118 break;
4119 }
4120 /* fall through */
4121
4122 case TOKlparen:
4123 {
4124 // (parameters) => expression
4125 // (parameters) { statements... }
4126 parameters = parseParameters(&varargs, &tpl);
4127 stc = parsePostfix(STCundefined, NULL);
4128 if (StorageClass modStc = stc & STC_TYPECTOR)
4129 {
4130 if (save == TOKfunction)
4131 {
4132 OutBuffer buf;
4133 stcToBuffer(&buf, modStc);
4134 error("function literal cannot be %s", buf.peekString());
4135 }
4136 else
4137 save = TOKdelegate;
4138 }
4139 break;
4140 }
4141 case TOKlcurly:
4142 // { statements... }
4143 break;
4144
4145 case TOKidentifier:
4146 {
4147 // identifier => expression
4148 parameters = new Parameters();
4149 Identifier *id = Identifier::generateId("__T");
4150 Type *t = new TypeIdentifier(loc, id);
4151 parameters->push(new Parameter(0, t, token.ident, NULL));
4152
4153 tpl = new TemplateParameters();
4154 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
4155 tpl->push(tp);
4156
4157 nextToken();
4158 break;
4159 }
4160 default:
4161 assert(0);
4162 }
4163
4164 if (!parameters)
4165 parameters = new Parameters();
4166 TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc);
4167 tf = (TypeFunction *)tf->addSTC(stc);
4168 FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
4169
4170 if (token.value == TOKgoesto)
4171 {
4172 check(TOKgoesto);
4173 Loc returnloc = token.loc;
4174 Expression *ae = parseAssignExp();
4175 fd->fbody = new ReturnStatement(returnloc, ae);
4176 fd->endloc = token.loc;
4177 }
4178 else
4179 {
4180 parseContracts(fd);
4181 }
4182
4183 if (tpl)
4184 {
4185 // Wrap a template around function fd
4186 Dsymbols *decldefs = new Dsymbols();
4187 decldefs->push(fd);
4188 return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
4189 }
4190 else
4191 return fd;
4192}
4193
4194/*****************************************
4195 * Parse auto declarations of the form:
4196 * storageClass ident = init, ident = init, ... ;
4197 * and return the array of them.
4198 * Starts with token on the first ident.
4199 * Ends with scanner past closing ';'
4200 */
4201
4202Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
4203{
4204 //printf("parseAutoDeclarations\n");
4205 Token *tk;
4206 Dsymbols *a = new Dsymbols;
4207
4208 while (1)
4209 {
4210 Loc loc = token.loc;
4211 Identifier *ident = token.ident;
4212 nextToken(); // skip over ident
4213
4214 TemplateParameters *tpl = NULL;
4215 if (token.value == TOKlparen)
4216 tpl = parseTemplateParameterList();
4217
4218 check(TOKassign); // skip over '='
4219 Initializer *init = parseInitializer();
4220 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
4221 v->storage_class = storageClass;
4222
4223 Dsymbol *s = v;
4224 if (tpl)
4225 {
4226 Dsymbols *a2 = new Dsymbols();
4227 a2->push(v);
4228 TemplateDeclaration *tempdecl =
4229 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4230 s = tempdecl;
4231 }
4232 a->push(s);
4233 switch (token.value)
4234 {
4235 case TOKsemicolon:
4236 nextToken();
4237 addComment(s, comment);
4238 break;
4239
4240 case TOKcomma:
4241 nextToken();
4242 if (!(token.value == TOKidentifier &&
4243 skipParensIf(peek(&token), &tk) &&
4244 tk->value == TOKassign))
4245 {
4246 error("identifier expected following comma");
4247 break;
4248 }
4249 addComment(s, comment);
4250 continue;
4251
4252 default:
4253 error("semicolon expected following auto declaration, not '%s'", token.toChars());
4254 break;
4255 }
4256 break;
4257 }
4258 return a;
4259}
4260
4261/*****************************************
4262 * Parse contracts following function declaration.
4263 */
4264
4265FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
4266{
4267 LINK linksave = linkage;
4268
4269 bool literal = f->isFuncLiteralDeclaration() != NULL;
4270
4271 // The following is irrelevant, as it is overridden by sc->linkage in
4272 // TypeFunction::semantic
4273 linkage = LINKd; // nested functions have D linkage
4274L1:
4275 switch (token.value)
4276 {
4277 case TOKlcurly:
4278 if (f->frequire || f->fensure)
4279 error("missing body { ... } after in or out");
4280 f->fbody = parseStatement(PSsemi);
4281 f->endloc = endloc;
4282 break;
4283
4284 case TOKidentifier:
4285 if (token.ident != Id::_body)
4286 goto Ldefault;
4287 /* fall through */
4288
4289 case TOKdo:
4290 nextToken();
4291 f->fbody = parseStatement(PScurly);
4292 f->endloc = endloc;
4293 break;
4294
4295 case TOKin:
4296 nextToken();
4297 if (f->frequire)
4298 error("redundant 'in' statement");
4299 f->frequire = parseStatement(PScurly | PSscope);
4300 goto L1;
4301
4302 case TOKout:
4303 // parse: out (identifier) { statement }
4304 nextToken();
4305 if (token.value != TOKlcurly)
4306 {
4307 check(TOKlparen);
4308 if (token.value != TOKidentifier)
4309 error("(identifier) following 'out' expected, not %s", token.toChars());
4310 f->outId = token.ident;
4311 nextToken();
4312 check(TOKrparen);
4313 }
4314 if (f->fensure)
4315 error("redundant 'out' statement");
4316 f->fensure = parseStatement(PScurly | PSscope);
4317 goto L1;
4318
4319 case TOKsemicolon:
4320 if (!literal)
4321 {
4322 // Bugzilla 15799: Semicolon becomes a part of function declaration
4323 // only when neither of contracts exists.
4324 if (!f->frequire && !f->fensure)
4325 nextToken();
4326 break;
4327 }
4328 /* fall through */
4329
4330 default:
4331 Ldefault:
4332 if (literal)
4333 {
4334 const char *sbody = (f->frequire || f->fensure) ? "body " : "";
4335 error("missing %s{ ... } for function literal", sbody);
4336 }
4337 else if (!f->frequire && !f->fensure) // allow these even with no body
4338 {
4339 error("semicolon expected following function declaration");
4340 }
4341 break;
4342 }
4343 if (literal && !f->fbody)
4344 {
4345 // Set empty function body for error recovery
4346 f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
4347 }
4348
4349 linkage = linksave;
4350
4351 return f;
4352}
4353
4354/*****************************************
4355 * Parse initializer for variable declaration.
4356 */
4357
4358Initializer *Parser::parseInitializer()
4359{
4360 StructInitializer *is;
4361 ArrayInitializer *ia;
4362 ExpInitializer *ie;
4363 Expression *e;
4364 Identifier *id;
4365 Initializer *value;
4366 int comma;
4367 Loc loc = token.loc;
4368 Token *t;
4369 int braces;
4370 int brackets;
4371
4372 switch (token.value)
4373 {
4374 case TOKlcurly:
4375 /* Scan ahead to see if it is a struct initializer or
4376 * a function literal.
4377 * If it contains a ';', it is a function literal.
4378 * Treat { } as a struct initializer.
4379 */
4380 braces = 1;
4381 for (t = peek(&token); 1; t = peek(t))
4382 {
4383 switch (t->value)
4384 {
4385 case TOKsemicolon:
4386 case TOKreturn:
4387 goto Lexpression;
4388
4389 case TOKlcurly:
4390 braces++;
4391 continue;
4392
4393 case TOKrcurly:
4394 if (--braces == 0)
4395 break;
4396 continue;
4397
4398 case TOKeof:
4399 break;
4400
4401 default:
4402 continue;
4403 }
4404 break;
4405 }
4406
4407 is = new StructInitializer(loc);
4408 nextToken();
4409 comma = 2;
4410 while (1)
4411 {
4412 switch (token.value)
4413 {
4414 case TOKidentifier:
4415 if (comma == 1)
4416 error("comma expected separating field initializers");
4417 t = peek(&token);
4418 if (t->value == TOKcolon)
4419 {
4420 id = token.ident;
4421 nextToken();
4422 nextToken(); // skip over ':'
4423 }
4424 else
4425 { id = NULL;
4426 }
4427 value = parseInitializer();
4428 is->addInit(id, value);
4429 comma = 1;
4430 continue;
4431
4432 case TOKcomma:
4433 if (comma == 2)
4434 error("expression expected, not ','");
4435 nextToken();
4436 comma = 2;
4437 continue;
4438
4439 case TOKrcurly: // allow trailing comma's
4440 nextToken();
4441 break;
4442
4443 case TOKeof:
4444 error("found EOF instead of initializer");
4445 break;
4446
4447 default:
4448 if (comma == 1)
4449 error("comma expected separating field initializers");
4450 value = parseInitializer();
4451 is->addInit(NULL, value);
4452 comma = 1;
4453 continue;
4454 //error("found '%s' instead of field initializer", token.toChars());
4455 //break;
4456 }
4457 break;
4458 }
4459 return is;
4460
4461 case TOKlbracket:
4462 /* Scan ahead to see if it is an array initializer or
4463 * an expression.
4464 * If it ends with a ';' ',' or '}', it is an array initializer.
4465 */
4466 brackets = 1;
4467 for (t = peek(&token); 1; t = peek(t))
4468 {
4469 switch (t->value)
4470 {
4471 case TOKlbracket:
4472 brackets++;
4473 continue;
4474
4475 case TOKrbracket:
4476 if (--brackets == 0)
4477 { t = peek(t);
4478 if (t->value != TOKsemicolon &&
4479 t->value != TOKcomma &&
4480 t->value != TOKrbracket &&
4481 t->value != TOKrcurly)
4482 goto Lexpression;
4483 break;
4484 }
4485 continue;
4486
4487 case TOKeof:
4488 break;
4489
4490 default:
4491 continue;
4492 }
4493 break;
4494 }
4495
4496 ia = new ArrayInitializer(loc);
4497 nextToken();
4498 comma = 2;
4499 while (1)
4500 {
4501 switch (token.value)
4502 {
4503 default:
4504 if (comma == 1)
4505 { error("comma expected separating array initializers, not %s", token.toChars());
4506 nextToken();
4507 break;
4508 }
4509 e = parseAssignExp();
4510 if (!e)
4511 break;
4512 if (token.value == TOKcolon)
4513 {
4514 nextToken();
4515 value = parseInitializer();
4516 }
4517 else
4518 { value = new ExpInitializer(e->loc, e);
4519 e = NULL;
4520 }
4521 ia->addInit(e, value);
4522 comma = 1;
4523 continue;
4524
4525 case TOKlcurly:
4526 case TOKlbracket:
4527 if (comma == 1)
4528 error("comma expected separating array initializers, not %s", token.toChars());
4529 value = parseInitializer();
4530 if (token.value == TOKcolon)
4531 {
4532 nextToken();
4533 e = initializerToExpression(value);
4534 value = parseInitializer();
4535 }
4536 else
4537 e = NULL;
4538 ia->addInit(e, value);
4539 comma = 1;
4540 continue;
4541
4542 case TOKcomma:
4543 if (comma == 2)
4544 error("expression expected, not ','");
4545 nextToken();
4546 comma = 2;
4547 continue;
4548
4549 case TOKrbracket: // allow trailing comma's
4550 nextToken();
4551 break;
4552
4553 case TOKeof:
4554 error("found '%s' instead of array initializer", token.toChars());
4555 break;
4556 }
4557 break;
4558 }
4559 return ia;
4560
4561 case TOKvoid:
4562 t = peek(&token);
4563 if (t->value == TOKsemicolon || t->value == TOKcomma)
4564 {
4565 nextToken();
4566 return new VoidInitializer(loc);
4567 }
4568 goto Lexpression;
4569
4570 default:
4571 Lexpression:
4572 e = parseAssignExp();
4573 ie = new ExpInitializer(loc, e);
4574 return ie;
4575 }
4576}
4577
4578/*****************************************
4579 * Parses default argument initializer expression that is an assign expression,
4580 * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
4581 */
4582
4583Expression *Parser::parseDefaultInitExp()
4584{
4585 if (token.value == TOKfile ||
4586 token.value == TOKfilefullpath ||
4587 token.value == TOKline ||
4588 token.value == TOKmodulestring ||
4589 token.value == TOKfuncstring ||
4590 token.value == TOKprettyfunc)
4591 {
4592 Token *t = peek(&token);
4593 if (t->value == TOKcomma || t->value == TOKrparen)
4594 {
4595 Expression *e = NULL;
4596 if (token.value == TOKfile)
4597 e = new FileInitExp(token.loc, TOKfile);
4598 else if (token.value == TOKfilefullpath)
4599 e = new FileInitExp(token.loc, TOKfilefullpath);
4600 else if (token.value == TOKline)
4601 e = new LineInitExp(token.loc);
4602 else if (token.value == TOKmodulestring)
4603 e = new ModuleInitExp(token.loc);
4604 else if (token.value == TOKfuncstring)
4605 e = new FuncInitExp(token.loc);
4606 else if (token.value == TOKprettyfunc)
4607 e = new PrettyFuncInitExp(token.loc);
4608 else
4609 assert(0);
4610 nextToken();
4611 return e;
4612 }
4613 }
4614
4615 Expression *e = parseAssignExp();
4616 return e;
4617}
4618
4619/*****************************************
4620 */
4621
4622void Parser::checkDanglingElse(Loc elseloc)
4623{
4624 if (token.value != TOKelse &&
4625 token.value != TOKcatch &&
4626 token.value != TOKfinally &&
4627 lookingForElse.linnum != 0)
4628 {
4629 warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
4630 }
4631}
4632
4633void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
4634{
4635 if (!alt)
4636 return;
4637
4638 const char *sp = !ident ? "" : " ";
4639 const char *s = !ident ? "" : ident->toChars();
4640 if (alt & 1) // contains C-style function pointer syntax
4641 error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
4642 else
4643 ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
4644
4645}
4646
4647/*****************************************
4648 * Input:
4649 * flags PSxxxx
4650 * Output:
4651 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
4652 */
4653
4654Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
4655{
4656 Statement *s = NULL;
4657 Condition *cond;
4658 Statement *ifbody;
4659 Statement *elsebody;
4660 bool isfinal;
4661 Loc loc = token.loc;
4662
4663 //printf("parseStatement()\n");
4664
4665 if (flags & PScurly && token.value != TOKlcurly)
4666 error("statement expected to be { }, not %s", token.toChars());
4667
4668 switch (token.value)
4669 {
4670 case TOKidentifier:
4671 { /* A leading identifier can be a declaration, label, or expression.
4672 * The easiest case to check first is label:
4673 */
4674 Token *t = peek(&token);
4675 if (t->value == TOKcolon)
4676 {
4677 Token *nt = peek(t);
4678 if (nt->value == TOKcolon)
4679 {
4680 // skip ident::
4681 nextToken();
4682 nextToken();
4683 nextToken();
4684 error("use `.` for member lookup, not `::`");
4685 break;
4686 }
4687 // It's a label
4688 Identifier *ident = token.ident;
4689 nextToken();
4690 nextToken();
4691 if (token.value == TOKrcurly)
4692 s = NULL;
4693 else if (token.value == TOKlcurly)
4694 s = parseStatement(PScurly | PSscope);
4695 else
4696 s = parseStatement(PSsemi_ok);
4697 s = new LabelStatement(loc, ident, s);
4698 break;
4699 }
4700 }
4701 /* fall through */
4702 case TOKdot:
4703 case TOKtypeof:
4704 case TOKvector:
4705 /* Bugzilla 15163: If tokens can be handled as
4706 * old C-style declaration or D expression, prefer the latter.
4707 */
4708 if (isDeclaration(&token, 3, TOKreserved, NULL))
4709 goto Ldeclaration;
4710 else
4711 goto Lexp;
4712 break;
4713
4714 case TOKassert:
4715 case TOKthis:
4716 case TOKsuper:
4717 case TOKint32v:
4718 case TOKuns32v:
4719 case TOKint64v:
4720 case TOKuns64v:
4721 case TOKint128v:
4722 case TOKuns128v:
4723 case TOKfloat32v:
4724 case TOKfloat64v:
4725 case TOKfloat80v:
4726 case TOKimaginary32v:
4727 case TOKimaginary64v:
4728 case TOKimaginary80v:
4729 case TOKcharv:
4730 case TOKwcharv:
4731 case TOKdcharv:
4732 case TOKnull:
4733 case TOKtrue:
4734 case TOKfalse:
4735 case TOKstring:
4736 case TOKxstring:
4737 case TOKlparen:
4738 case TOKcast:
4739 case TOKmul:
4740 case TOKmin:
4741 case TOKadd:
4742 case TOKtilde:
4743 case TOKnot:
4744 case TOKplusplus:
4745 case TOKminusminus:
4746 case TOKnew:
4747 case TOKdelete:
4748 case TOKdelegate:
4749 case TOKfunction:
4750 case TOKtypeid:
4751 case TOKis:
4752 case TOKlbracket:
4753 case TOKtraits:
4754 case TOKfile:
4755 case TOKfilefullpath:
4756 case TOKline:
4757 case TOKmodulestring:
4758 case TOKfuncstring:
4759 case TOKprettyfunc:
4760 Lexp:
4761 {
4762 Expression *exp = parseExpression();
4763 check(TOKsemicolon, "statement");
4764 s = new ExpStatement(loc, exp);
4765 break;
4766 }
4767
4768 case TOKstatic:
4769 { // Look ahead to see if it's static assert() or static if()
4770
4771 Token *t = peek(&token);
4772 if (t->value == TOKassert)
4773 {
4774 s = new StaticAssertStatement(parseStaticAssert());
4775 break;
4776 }
4777 if (t->value == TOKif)
4778 {
4779 cond = parseStaticIfCondition();
4780 goto Lcondition;
4781 }
4782 if (t->value == TOKimport)
4783 {
4784 Dsymbols *imports = parseImport();
4785 s = new ImportStatement(loc, imports);
4786 if (flags & PSscope)
4787 s = new ScopeStatement(loc, s, token.loc);
4788 break;
4789 }
4790 goto Ldeclaration;
4791 }
4792
4793 case TOKfinal:
4794 if (peekNext() == TOKswitch)
4795 {
4796 nextToken();
4797 isfinal = true;
4798 goto Lswitch;
4799 }
4800 goto Ldeclaration;
4801
4802 case TOKwchar: case TOKdchar:
4803 case TOKbool: case TOKchar:
4804 case TOKint8: case TOKuns8:
4805 case TOKint16: case TOKuns16:
4806 case TOKint32: case TOKuns32:
4807 case TOKint64: case TOKuns64:
4808 case TOKint128: case TOKuns128:
4809 case TOKfloat32: case TOKfloat64: case TOKfloat80:
4810 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
4811 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
4812 case TOKvoid:
4813 // bug 7773: int.max is always a part of expression
4814 if (peekNext() == TOKdot)
4815 goto Lexp;
4816 if (peekNext() == TOKlparen)
4817 goto Lexp;
4818 /* fall through */
4819
4820 case TOKalias:
4821 case TOKconst:
4822 case TOKauto:
4823 case TOKabstract:
4824 case TOKextern:
4825 case TOKalign:
4826 case TOKimmutable:
4827 case TOKshared:
4828 case TOKwild:
4829 case TOKdeprecated:
4830 case TOKnothrow:
4831 case TOKpure:
4832 case TOKref:
4833 case TOKgshared:
4834 case TOKat:
4835 case TOKstruct:
4836 case TOKunion:
4837 case TOKclass:
4838 case TOKinterface:
4839 Ldeclaration:
4840 {
4841 Dsymbols *a = parseDeclarations(false, NULL, NULL);
4842 if (a->dim > 1)
4843 {
4844 Statements *as = new Statements();
4845 as->reserve(a->dim);
4846 for (size_t i = 0; i < a->dim; i++)
4847 {
4848 Dsymbol *d = (*a)[i];
4849 s = new ExpStatement(loc, d);
4850 as->push(s);
4851 }
4852 s = new CompoundDeclarationStatement(loc, as);
4853 }
4854 else if (a->dim == 1)
4855 {
4856 Dsymbol *d = (*a)[0];
4857 s = new ExpStatement(loc, d);
4858 }
4859 else
4860 s = new ExpStatement(loc, (Expression *)NULL);
4861 if (flags & PSscope)
4862 s = new ScopeStatement(loc, s, token.loc);
4863 break;
4864 }
4865
4866 case TOKenum:
4867 { /* Determine if this is a manifest constant declaration,
4868 * or a conventional enum.
4869 */
4870 Dsymbol *d;
4871 Token *t = peek(&token);
4872 if (t->value == TOKlcurly || t->value == TOKcolon)
4873 d = parseEnum();
4874 else if (t->value != TOKidentifier)
4875 goto Ldeclaration;
4876 else
4877 {
4878 t = peek(t);
4879 if (t->value == TOKlcurly || t->value == TOKcolon ||
4880 t->value == TOKsemicolon)
4881 d = parseEnum();
4882 else
4883 goto Ldeclaration;
4884 }
4885 s = new ExpStatement(loc, d);
4886 if (flags & PSscope)
4887 s = new ScopeStatement(loc, s, token.loc);
4888 break;
4889 }
4890
4891 case TOKmixin:
4892 { Token *t = peek(&token);
4893 if (t->value == TOKlparen)
4894 { // mixin(string)
4895 Expression *e = parseAssignExp();
4896 check(TOKsemicolon);
4897 if (e->op == TOKmixin)
4898 {
4899 CompileExp *cpe = (CompileExp *)e;
4900 s = new CompileStatement(loc, cpe->e1);
4901 }
4902 else
4903 {
4904 s = new ExpStatement(loc, e);
4905 }
4906 break;
4907 }
4908 Dsymbol *d = parseMixin();
4909 s = new ExpStatement(loc, d);
4910 if (flags & PSscope)
4911 s = new ScopeStatement(loc, s, token.loc);
4912 break;
4913 }
4914
4915 case TOKlcurly:
4916 {
4917 Loc lookingForElseSave = lookingForElse;
4918 lookingForElse = Loc();
4919
4920 nextToken();
4921 //if (token.value == TOKsemicolon)
4922 //error("use '{ }' for an empty statement, not a ';'");
4923 Statements *statements = new Statements();
4924 while (token.value != TOKrcurly && token.value != TOKeof)
4925 {
4926 statements->push(parseStatement(PSsemi | PScurlyscope));
4927 }
4928 if (endPtr) *endPtr = token.ptr;
4929 endloc = token.loc;
4930 if (pEndloc)
4931 {
4932 *pEndloc = token.loc;
4933 pEndloc = NULL; // don't set it again
4934 }
4935 s = new CompoundStatement(loc, statements);
4936 if (flags & (PSscope | PScurlyscope))
4937 s = new ScopeStatement(loc, s, token.loc);
4938 check(TOKrcurly, "compound statement");
4939 lookingForElse = lookingForElseSave;
4940 break;
4941 }
4942
4943 case TOKwhile:
4944 {
4945 nextToken();
4946 check(TOKlparen);
4947 Expression *condition = parseExpression();
4948 check(TOKrparen);
4949 Loc endloc;
4950 Statement *body = parseStatement(PSscope, NULL, &endloc);
4951 s = new WhileStatement(loc, condition, body, endloc);
4952 break;
4953 }
4954
4955 case TOKsemicolon:
4956 if (!(flags & PSsemi_ok))
4957 {
4958 if (flags & PSsemi)
4959 deprecation("use '{ }' for an empty statement, not a ';'");
4960 else
4961 error("use '{ }' for an empty statement, not a ';'");
4962 }
4963 nextToken();
4964 s = new ExpStatement(loc, (Expression *)NULL);
4965 break;
4966
4967 case TOKdo:
4968 { Statement *body;
4969 Expression *condition;
4970
4971 nextToken();
4972 Loc lookingForElseSave = lookingForElse;
4973 lookingForElse = Loc();
4974 body = parseStatement(PSscope);
4975 lookingForElse = lookingForElseSave;
4976 check(TOKwhile);
4977 check(TOKlparen);
4978 condition = parseExpression();
4979 check(TOKrparen);
4980 if (token.value == TOKsemicolon)
4981 nextToken();
4982 else
4983 error("terminating ';' required after do-while statement");
4984 s = new DoStatement(loc, body, condition, token.loc);
4985 break;
4986 }
4987
4988 case TOKfor:
4989 {
4990 Statement *init;
4991 Expression *condition;
4992 Expression *increment;
4993
4994 nextToken();
4995 check(TOKlparen);
4996 if (token.value == TOKsemicolon)
4997 { init = NULL;
4998 nextToken();
4999 }
5000 else
5001 {
5002 Loc lookingForElseSave = lookingForElse;
5003 lookingForElse = Loc();
5004 init = parseStatement(0);
5005 lookingForElse = lookingForElseSave;
5006 }
5007 if (token.value == TOKsemicolon)
5008 {
5009 condition = NULL;
5010 nextToken();
5011 }
5012 else
5013 {
5014 condition = parseExpression();
5015 check(TOKsemicolon, "for condition");
5016 }
5017 if (token.value == TOKrparen)
5018 { increment = NULL;
5019 nextToken();
5020 }
5021 else
5022 { increment = parseExpression();
5023 check(TOKrparen);
5024 }
5025 Loc endloc;
5026 Statement *body = parseStatement(PSscope, NULL, &endloc);
5027 s = new ForStatement(loc, init, condition, increment, body, endloc);
5028 break;
5029 }
5030
5031 case TOKforeach:
5032 case TOKforeach_reverse:
5033 {
5034 TOK op = token.value;
5035
5036 nextToken();
5037 check(TOKlparen);
5038
5039 Parameters *parameters = new Parameters();
5040
5041 while (1)
5042 {
5043 Identifier *ai = NULL;
5044 Type *at;
5045
5046 StorageClass storageClass = 0;
5047 StorageClass stc = 0;
5048 Lagain:
5049 if (stc)
5050 {
5051 storageClass = appendStorageClass(storageClass, stc);
5052 nextToken();
5053 }
5054 switch (token.value)
5055 {
5056 case TOKref:
5057 stc = STCref;
5058 goto Lagain;
5059
5060 case TOKconst:
5061 if (peekNext() != TOKlparen)
5062 {
5063 stc = STCconst;
5064 goto Lagain;
5065 }
5066 break;
5067 case TOKimmutable:
5068 if (peekNext() != TOKlparen)
5069 {
5070 stc = STCimmutable;
5071 goto Lagain;
5072 }
5073 break;
5074 case TOKshared:
5075 if (peekNext() != TOKlparen)
5076 {
5077 stc = STCshared;
5078 goto Lagain;
5079 }
5080 break;
5081 case TOKwild:
5082 if (peekNext() != TOKlparen)
5083 {
5084 stc = STCwild;
5085 goto Lagain;
5086 }
5087 break;
5088 default:
5089 break;
5090 }
5091 if (token.value == TOKidentifier)
5092 {
5093 Token *t = peek(&token);
5094 if (t->value == TOKcomma || t->value == TOKsemicolon)
5095 { ai = token.ident;
5096 at = NULL; // infer argument type
5097 nextToken();
5098 goto Larg;
5099 }
5100 }
5101 at = parseType(&ai);
5102 if (!ai)
5103 error("no identifier for declarator %s", at->toChars());
5104 Larg:
5105 Parameter *p = new Parameter(storageClass, at, ai, NULL);
5106 parameters->push(p);
5107 if (token.value == TOKcomma)
5108 { nextToken();
5109 continue;
5110 }
5111 break;
5112 }
5113 check(TOKsemicolon);
5114
5115 Expression *aggr = parseExpression();
5116 if (token.value == TOKslice && parameters->dim == 1)
5117 {
5118 Parameter *p = (*parameters)[0];
5119 delete parameters;
5120 nextToken();
5121 Expression *upr = parseExpression();
5122 check(TOKrparen);
5123 Loc endloc;
5124 Statement *body = parseStatement(0, NULL, &endloc);
5125 s = new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
5126 }
5127 else
5128 {
5129 check(TOKrparen);
5130 Loc endloc;
5131 Statement *body = parseStatement(0, NULL, &endloc);
5132 s = new ForeachStatement(loc, op, parameters, aggr, body, endloc);
5133 }
5134 break;
5135 }
5136
5137 case TOKif:
5138 {
5139 Parameter *param = NULL;
5140 Expression *condition;
5141
5142 nextToken();
5143 check(TOKlparen);
5144
5145 StorageClass storageClass = 0;
5146 StorageClass stc = 0;
5147 LagainStc:
5148 if (stc)
5149 {
5150 storageClass = appendStorageClass(storageClass, stc);
5151 nextToken();
5152 }
5153 switch (token.value)
5154 {
5155 case TOKref:
5156 stc = STCref;
5157 goto LagainStc;
5158 case TOKauto:
5159 stc = STCauto;
5160 goto LagainStc;
5161 case TOKconst:
5162 if (peekNext() != TOKlparen)
5163 {
5164 stc = STCconst;
5165 goto LagainStc;
5166 }
5167 break;
5168 case TOKimmutable:
5169 if (peekNext() != TOKlparen)
5170 {
5171 stc = STCimmutable;
5172 goto LagainStc;
5173 }
5174 break;
5175 case TOKshared:
5176 if (peekNext() != TOKlparen)
5177 {
5178 stc = STCshared;
5179 goto LagainStc;
5180 }
5181 break;
5182 case TOKwild:
5183 if (peekNext() != TOKlparen)
5184 {
5185 stc = STCwild;
5186 goto LagainStc;
5187 }
5188 break;
5189 default:
5190 break;
5191 }
5192
5193 if (storageClass != 0 &&
5194 token.value == TOKidentifier &&
5195 peek(&token)->value == TOKassign)
5196 {
5197 Identifier *ai = token.ident;
5198 Type *at = NULL; // infer parameter type
5199 nextToken();
5200 check(TOKassign);
5201 param = new Parameter(storageClass, at, ai, NULL);
5202 }
5203 else if (isDeclaration(&token, 2, TOKassign, NULL))
5204 {
5205 Identifier *ai;
5206 Type *at = parseType(&ai);
5207 check(TOKassign);
5208 param = new Parameter(storageClass, at, ai, NULL);
5209 }
5210
5211 condition = parseExpression();
5212 check(TOKrparen);
5213 {
5214 Loc lookingForElseSave = lookingForElse;
5215 lookingForElse = loc;
5216 ifbody = parseStatement(PSscope);
5217 lookingForElse = lookingForElseSave;
5218 }
5219 if (token.value == TOKelse)
5220 {
5221 Loc elseloc = token.loc;
5222 nextToken();
5223 elsebody = parseStatement(PSscope);
5224 checkDanglingElse(elseloc);
5225 }
5226 else
5227 elsebody = NULL;
5228 if (condition && ifbody)
5229 s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
5230 else
5231 s = NULL; // don't propagate parsing errors
5232 break;
5233 }
5234
5235 case TOKscope:
5236 if (peek(&token)->value != TOKlparen)
5237 goto Ldeclaration; // scope used as storage class
5238 nextToken();
5239 check(TOKlparen);
5240 if (token.value != TOKidentifier)
5241 { error("scope identifier expected");
5242 goto Lerror;
5243 }
5244 else
5245 { TOK t = TOKon_scope_exit;
5246 Identifier *id = token.ident;
5247
5248 if (id == Id::exit)
5249 t = TOKon_scope_exit;
5250 else if (id == Id::failure)
5251 t = TOKon_scope_failure;
5252 else if (id == Id::success)
5253 t = TOKon_scope_success;
5254 else
5255 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
5256 nextToken();
5257 check(TOKrparen);
5258 Statement *st = parseStatement(PSscope);
5259 s = new OnScopeStatement(loc, t, st);
5260 break;
5261 }
5262
5263 case TOKdebug:
5264 nextToken();
5265 if (token.value == TOKassign)
5266 {
5267 error("debug conditions can only be declared at module scope");
5268 nextToken();
5269 nextToken();
5270 goto Lerror;
5271 }
5272 cond = parseDebugCondition();
5273 goto Lcondition;
5274
5275 case TOKversion:
5276 nextToken();
5277 if (token.value == TOKassign)
5278 {
5279 error("version conditions can only be declared at module scope");
5280 nextToken();
5281 nextToken();
5282 goto Lerror;
5283 }
5284 cond = parseVersionCondition();
5285 goto Lcondition;
5286
5287 Lcondition:
5288 {
5289 Loc lookingForElseSave = lookingForElse;
5290 lookingForElse = loc;
5291 ifbody = parseStatement(0);
5292 lookingForElse = lookingForElseSave;
5293 }
5294 elsebody = NULL;
5295 if (token.value == TOKelse)
5296 {
5297 Loc elseloc = token.loc;
5298 nextToken();
5299 elsebody = parseStatement(0);
5300 checkDanglingElse(elseloc);
5301 }
5302 s = new ConditionalStatement(loc, cond, ifbody, elsebody);
5303 if (flags & PSscope)
5304 s = new ScopeStatement(loc, s, token.loc);
5305 break;
5306
5307 case TOKpragma:
5308 { Identifier *ident;
5309 Expressions *args = NULL;
5310 Statement *body;
5311
5312 nextToken();
5313 check(TOKlparen);
5314 if (token.value != TOKidentifier)
5315 { error("pragma(identifier expected");
5316 goto Lerror;
5317 }
5318 ident = token.ident;
5319 nextToken();
5320 if (token.value == TOKcomma && peekNext() != TOKrparen)
5321 args = parseArguments(); // pragma(identifier, args...);
5322 else
5323 check(TOKrparen); // pragma(identifier);
5324 if (token.value == TOKsemicolon)
5325 { nextToken();
5326 body = NULL;
5327 }
5328 else
5329 body = parseStatement(PSsemi);
5330 s = new PragmaStatement(loc, ident, args, body);
5331 break;
5332 }
5333
5334 case TOKswitch:
5335 isfinal = false;
5336 goto Lswitch;
5337
5338 Lswitch:
5339 {
5340 nextToken();
5341 check(TOKlparen);
5342 Expression *condition = parseExpression();
5343 check(TOKrparen);
5344 Statement *body = parseStatement(PSscope);
5345 s = new SwitchStatement(loc, condition, body, isfinal);
5346 break;
5347 }
5348
5349 case TOKcase:
5350 { Expression *exp;
5351 Expressions cases; // array of Expression's
5352 Expression *last = NULL;
5353
5354 while (1)
5355 {
5356 nextToken();
5357 exp = parseAssignExp();
5358 cases.push(exp);
5359 if (token.value != TOKcomma)
5360 break;
5361 }
5362 check(TOKcolon);
5363
5364 /* case exp: .. case last:
5365 */
5366 if (token.value == TOKslice)
5367 {
5368 if (cases.dim > 1)
5369 error("only one case allowed for start of case range");
5370 nextToken();
5371 check(TOKcase);
5372 last = parseAssignExp();
5373 check(TOKcolon);
5374 }
5375
5376 if (flags & PScurlyscope)
5377 {
5378 Statements *statements = new Statements();
5379 while (token.value != TOKcase &&
5380 token.value != TOKdefault &&
5381 token.value != TOKeof &&
5382 token.value != TOKrcurly)
5383 {
5384 statements->push(parseStatement(PSsemi | PScurlyscope));
5385 }
5386 s = new CompoundStatement(loc, statements);
5387 }
5388 else
5389 s = parseStatement(PSsemi | PScurlyscope);
5390 s = new ScopeStatement(loc, s, token.loc);
5391
5392 if (last)
5393 {
5394 s = new CaseRangeStatement(loc, exp, last, s);
5395 }
5396 else
5397 {
5398 // Keep cases in order by building the case statements backwards
5399 for (size_t i = cases.dim; i; i--)
5400 {
5401 exp = cases[i - 1];
5402 s = new CaseStatement(loc, exp, s);
5403 }
5404 }
5405 break;
5406 }
5407
5408 case TOKdefault:
5409 {
5410 nextToken();
5411 check(TOKcolon);
5412
5413 if (flags & PScurlyscope)
5414 {
5415 Statements *statements = new Statements();
5416 while (token.value != TOKcase &&
5417 token.value != TOKdefault &&
5418 token.value != TOKeof &&
5419 token.value != TOKrcurly)
5420 {
5421 statements->push(parseStatement(PSsemi | PScurlyscope));
5422 }
5423 s = new CompoundStatement(loc, statements);
5424 }
5425 else
5426 s = parseStatement(PSsemi | PScurlyscope);
5427 s = new ScopeStatement(loc, s, token.loc);
5428 s = new DefaultStatement(loc, s);
5429 break;
5430 }
5431
5432 case TOKreturn:
5433 { Expression *exp;
5434
5435 nextToken();
5436 if (token.value == TOKsemicolon)
5437 exp = NULL;
5438 else
5439 exp = parseExpression();
5440 check(TOKsemicolon, "return statement");
5441 s = new ReturnStatement(loc, exp);
5442 break;
5443 }
5444
5445 case TOKbreak:
5446 { Identifier *ident;
5447
5448 nextToken();
5449 if (token.value == TOKidentifier)
5450 { ident = token.ident;
5451 nextToken();
5452 }
5453 else
5454 ident = NULL;
5455 check(TOKsemicolon, "break statement");
5456 s = new BreakStatement(loc, ident);
5457 break;
5458 }
5459
5460 case TOKcontinue:
5461 { Identifier *ident;
5462
5463 nextToken();
5464 if (token.value == TOKidentifier)
5465 { ident = token.ident;
5466 nextToken();
5467 }
5468 else
5469 ident = NULL;
5470 check(TOKsemicolon, "continue statement");
5471 s = new ContinueStatement(loc, ident);
5472 break;
5473 }
5474
5475 case TOKgoto:
5476 { Identifier *ident;
5477
5478 nextToken();
5479 if (token.value == TOKdefault)
5480 {
5481 nextToken();
5482 s = new GotoDefaultStatement(loc);
5483 }
5484 else if (token.value == TOKcase)
5485 {
5486 Expression *exp = NULL;
5487
5488 nextToken();
5489 if (token.value != TOKsemicolon)
5490 exp = parseExpression();
5491 s = new GotoCaseStatement(loc, exp);
5492 }
5493 else
5494 {
5495 if (token.value != TOKidentifier)
5496 {
5497 error("identifier expected following goto");
5498 ident = NULL;
5499 }
5500 else
5501 {
5502 ident = token.ident;
5503 nextToken();
5504 }
5505 s = new GotoStatement(loc, ident);
5506 }
5507 check(TOKsemicolon, "goto statement");
5508 break;
5509 }
5510
5511 case TOKsynchronized:
5512 { Expression *exp;
5513 Statement *body;
5514
5515 Token *t = peek(&token);
5516 if (skipAttributes(t, &t) && t->value == TOKclass)
5517 goto Ldeclaration;
5518
5519 nextToken();
5520 if (token.value == TOKlparen)
5521 {
5522 nextToken();
5523 exp = parseExpression();
5524 check(TOKrparen);
5525 }
5526 else
5527 exp = NULL;
5528 body = parseStatement(PSscope);
5529 s = new SynchronizedStatement(loc, exp, body);
5530 break;
5531 }
5532
5533 case TOKwith:
5534 { Expression *exp;
5535 Statement *body;
5536
5537 nextToken();
5538 check(TOKlparen);
5539 exp = parseExpression();
5540 check(TOKrparen);
5541 body = parseStatement(PSscope);
5542 s = new WithStatement(loc, exp, body, token.loc);
5543 break;
5544 }
5545
5546 case TOKtry:
5547 { Statement *body;
5548 Catches *catches = NULL;
5549 Statement *finalbody = NULL;
5550
5551 nextToken();
5552 Loc lookingForElseSave = lookingForElse;
5553 lookingForElse = Loc();
5554 body = parseStatement(PSscope);
5555 lookingForElse = lookingForElseSave;
5556 while (token.value == TOKcatch)
5557 {
5558 Statement *handler;
5559 Catch *c;
5560 Type *t;
5561 Identifier *id;
5562 Loc catchloc = token.loc;
5563
5564 nextToken();
5565 if (token.value == TOKlcurly || token.value != TOKlparen)
5566 {
5567 t = NULL;
5568 id = NULL;
5569 }
5570 else
5571 {
5572 check(TOKlparen);
5573 id = NULL;
5574 t = parseType(&id);
5575 check(TOKrparen);
5576 }
5577 handler = parseStatement(0);
5578 c = new Catch(catchloc, t, id, handler);
5579 if (!catches)
5580 catches = new Catches();
5581 catches->push(c);
5582 }
5583
5584 if (token.value == TOKfinally)
5585 {
5586 nextToken();
5587 finalbody = parseStatement(PSscope);
5588 }
5589
5590 s = body;
5591 if (!catches && !finalbody)
5592 error("catch or finally expected following try");
5593 else
5594 { if (catches)
5595 s = new TryCatchStatement(loc, body, catches);
5596 if (finalbody)
5597 s = new TryFinallyStatement(loc, s, finalbody);
5598 }
5599 break;
5600 }
5601
5602 case TOKthrow:
5603 { Expression *exp;
5604
5605 nextToken();
5606 exp = parseExpression();
5607 check(TOKsemicolon, "throw statement");
5608 s = new ThrowStatement(loc, exp);
5609 break;
5610 }
5611
5612 case TOKasm:
5613 {
5614 // Parse the asm block into a sequence of AsmStatements,
5615 // each AsmStatement is one instruction.
5616 // Separate out labels.
5617 // Defer parsing of AsmStatements until semantic processing.
5618
5619 Loc labelloc;
5620
5621 nextToken();
5622 StorageClass stc = parsePostfix(STCundefined, NULL);
5623 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5624 error("const/immutable/shared/inout attributes are not allowed on asm blocks");
5625
5626 check(TOKlcurly);
5627 Token *toklist = NULL;
5628 Token **ptoklist = &toklist;
5629 Identifier *label = NULL;
5630 Statements *statements = new Statements();
5631 size_t nestlevel = 0;
5632 while (1)
5633 {
5634 switch (token.value)
5635 {
5636 case TOKidentifier:
5637 if (!toklist)
5638 {
5639 // Look ahead to see if it is a label
5640 Token *t = peek(&token);
5641 if (t->value == TOKcolon)
5642 { // It's a label
5643 label = token.ident;
5644 labelloc = token.loc;
5645 nextToken();
5646 nextToken();
5647 continue;
5648 }
5649 }
5650 goto Ldefault;
5651
5652 case TOKlcurly:
5653 ++nestlevel;
5654 goto Ldefault;
5655
5656 case TOKrcurly:
5657 if (nestlevel > 0)
5658 {
5659 --nestlevel;
5660 goto Ldefault;
5661 }
5662
5663 if (toklist || label)
5664 {
5665 error("asm statements must end in ';'");
5666 }
5667 break;
5668
5669 case TOKsemicolon:
5670 if (nestlevel != 0)
5671 error("mismatched number of curly brackets");
5672
5673 s = NULL;
5674 if (toklist || label)
5675 {
5676 // Create AsmStatement from list of tokens we've saved
5677 s = new AsmStatement(token.loc, toklist);
5678 toklist = NULL;
5679 ptoklist = &toklist;
5680 if (label)
5681 { s = new LabelStatement(labelloc, label, s);
5682 label = NULL;
5683 }
5684 statements->push(s);
5685 }
5686 nextToken();
5687 continue;
5688
5689 case TOKeof:
5690 /* { */
5691 error("matching '}' expected, not end of file");
5692 goto Lerror;
5693 /* fall through */
5694
5695 default:
5696 Ldefault:
5697 *ptoklist = Token::alloc();
5698 memcpy(*ptoklist, &token, sizeof(Token));
5699 ptoklist = &(*ptoklist)->next;
5700 *ptoklist = NULL;
5701
5702 nextToken();
5703 continue;
5704 }
5705 break;
5706 }
5707 s = new CompoundAsmStatement(loc, statements, stc);
5708 nextToken();
5709 break;
5710 }
5711
5712 case TOKimport:
5713 {
5714 Dsymbols *imports = parseImport();
5715 s = new ImportStatement(loc, imports);
5716 if (flags & PSscope)
5717 s = new ScopeStatement(loc, s, token.loc);
5718 break;
5719 }
5720
5721 case TOKtemplate:
5722 {
5723 Dsymbol *d = parseTemplateDeclaration();
5724 s = new ExpStatement(loc, d);
5725 break;
5726 }
5727
5728 default:
5729 error("found '%s' instead of statement", token.toChars());
5730 goto Lerror;
5731
5732 Lerror:
5733 while (token.value != TOKrcurly &&
5734 token.value != TOKsemicolon &&
5735 token.value != TOKeof)
5736 nextToken();
5737 if (token.value == TOKsemicolon)
5738 nextToken();
5739 s = NULL;
5740 break;
5741 }
5742 if (pEndloc)
5743 *pEndloc = token.loc;
5744 return s;
5745}
5746
5747void Parser::check(TOK value)
5748{
5749 check(token.loc, value);
5750}
5751
5752void Parser::check(Loc loc, TOK value)
5753{
5754 if (token.value != value)
5755 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
5756 nextToken();
5757}
5758
5759void Parser::check(TOK value, const char *string)
5760{
5761 if (token.value != value)
5762 error("found '%s' when expecting '%s' following %s",
5763 token.toChars(), Token::toChars(value), string);
5764 nextToken();
5765}
5766
5767void Parser::checkParens(TOK value, Expression *e)
5768{
5769 if (precedence[e->op] == PREC_rel && !e->parens)
5770 error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
5771}
5772
5773/************************************
5774 * Determine if the scanner is sitting on the start of a declaration.
5775 * Input:
5776 * needId 0 no identifier
5777 * 1 identifier optional
5778 * 2 must have identifier
5779 * 3 must have identifier, but don't recognize old C-style syntax.
5780 * Output:
5781 * if *pt is not NULL, it is set to the ending token, which would be endtok
5782 */
5783
5784bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
5785{
5786 //printf("isDeclaration(needId = %d)\n", needId);
5787 int haveId = 0;
5788 int haveTpl = 0;
5789
5790 while (1)
5791 {
5792 if ((t->value == TOKconst ||
5793 t->value == TOKimmutable ||
5794 t->value == TOKwild ||
5795 t->value == TOKshared) &&
5796 peek(t)->value != TOKlparen)
5797 {
5798 /* const type
5799 * immutable type
5800 * shared type
5801 * wild type
5802 */
5803 t = peek(t);
5804 continue;
5805 }
5806 break;
5807 }
5808
5809 if (!isBasicType(&t))
5810 {
5811 goto Lisnot;
5812 }
5813 if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3))
5814 goto Lisnot;
5815 if (needId == 1 || (needId == 0 && !haveId) || ((needId == 2 || needId == 3) && haveId))
5816 {
5817 if (pt)
5818 *pt = t;
5819 goto Lis;
5820 }
5821 else
5822 goto Lisnot;
5823
5824Lis:
5825 //printf("\tis declaration, t = %s\n", t->toChars());
5826 return true;
5827
5828Lisnot:
5829 //printf("\tis not declaration\n");
5830 return false;
5831}
5832
5833bool Parser::isBasicType(Token **pt)
5834{
5835 // This code parallels parseBasicType()
5836 Token *t = *pt;
5837
5838 switch (t->value)
5839 {
5840 case TOKwchar: case TOKdchar:
5841 case TOKbool: case TOKchar:
5842 case TOKint8: case TOKuns8:
5843 case TOKint16: case TOKuns16:
5844 case TOKint32: case TOKuns32:
5845 case TOKint64: case TOKuns64:
5846 case TOKint128: case TOKuns128:
5847 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5848 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5849 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5850 case TOKvoid:
5851 t = peek(t);
5852 break;
5853
5854 case TOKidentifier:
5855 L5:
5856 t = peek(t);
5857 if (t->value == TOKnot)
5858 {
5859 goto L4;
5860 }
5861 goto L3;
5862 while (1)
5863 {
5864 L2:
5865 t = peek(t);
5866 L3:
5867 if (t->value == TOKdot)
5868 {
5869 Ldot:
5870 t = peek(t);
5871 if (t->value != TOKidentifier)
5872 goto Lfalse;
5873 t = peek(t);
5874 if (t->value != TOKnot)
5875 goto L3;
5876 L4:
5877 /* Seen a !
5878 * Look for:
5879 * !( args ), !identifier, etc.
5880 */
5881 t = peek(t);
5882 switch (t->value)
5883 {
5884 case TOKidentifier:
5885 goto L5;
5886 case TOKlparen:
5887 if (!skipParens(t, &t))
5888 goto Lfalse;
5889 goto L3;
5890 case TOKwchar: case TOKdchar:
5891 case TOKbool: case TOKchar:
5892 case TOKint8: case TOKuns8:
5893 case TOKint16: case TOKuns16:
5894 case TOKint32: case TOKuns32:
5895 case TOKint64: case TOKuns64:
5896 case TOKint128: case TOKuns128:
5897 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5898 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5899 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5900 case TOKvoid:
5901 case TOKint32v:
5902 case TOKuns32v:
5903 case TOKint64v:
5904 case TOKuns64v:
5905 case TOKint128v:
5906 case TOKuns128v:
5907 case TOKfloat32v:
5908 case TOKfloat64v:
5909 case TOKfloat80v:
5910 case TOKimaginary32v:
5911 case TOKimaginary64v:
5912 case TOKimaginary80v:
5913 case TOKnull:
5914 case TOKtrue:
5915 case TOKfalse:
5916 case TOKcharv:
5917 case TOKwcharv:
5918 case TOKdcharv:
5919 case TOKstring:
5920 case TOKxstring:
5921 case TOKfile:
5922 case TOKfilefullpath:
5923 case TOKline:
5924 case TOKmodulestring:
5925 case TOKfuncstring:
5926 case TOKprettyfunc:
5927 goto L2;
5928 default:
5929 goto Lfalse;
5930 }
5931 }
5932 else
5933 break;
5934 }
5935 break;
5936
5937 case TOKdot:
5938 goto Ldot;
5939
5940 case TOKtypeof:
5941 case TOKvector:
5942 /* typeof(exp).identifier...
5943 */
5944 t = peek(t);
5945 if (!skipParens(t, &t))
5946 goto Lfalse;
5947 goto L3;
5948
5949 case TOKconst:
5950 case TOKimmutable:
5951 case TOKshared:
5952 case TOKwild:
5953 // const(type) or immutable(type) or shared(type) or wild(type)
5954 t = peek(t);
5955 if (t->value != TOKlparen)
5956 goto Lfalse;
5957 t = peek(t);
5958 if (!isDeclaration(t, 0, TOKrparen, &t))
5959 {
5960 goto Lfalse;
5961 }
5962 t = peek(t);
5963 break;
5964
5965 default:
5966 goto Lfalse;
5967 }
5968 *pt = t;
5969 //printf("is\n");
5970 return true;
5971
5972Lfalse:
5973 //printf("is not\n");
5974 return false;
5975}
5976
5977bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax)
5978{ // This code parallels parseDeclarator()
5979 Token *t = *pt;
5980 int parens;
5981
5982 //printf("Parser::isDeclarator() %s\n", t->toChars());
5983 if (t->value == TOKassign)
5984 return false;
5985
5986 while (1)
5987 {
5988 parens = false;
5989 switch (t->value)
5990 {
5991 case TOKmul:
5992 //case TOKand:
5993 t = peek(t);
5994 continue;
5995
5996 case TOKlbracket:
5997 t = peek(t);
5998 if (t->value == TOKrbracket)
5999 {
6000 t = peek(t);
6001 }
6002 else if (isDeclaration(t, 0, TOKrbracket, &t))
6003 {
6004 // It's an associative array declaration
6005 t = peek(t);
6006
6007 // ...[type].ident
6008 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6009 {
6010 t = peek(t);
6011 t = peek(t);
6012 }
6013 }
6014 else
6015 {
6016 // [ expression ]
6017 // [ expression .. expression ]
6018 if (!isExpression(&t))
6019 return false;
6020 if (t->value == TOKslice)
6021 {
6022 t = peek(t);
6023 if (!isExpression(&t))
6024 return false;
6025 if (t->value != TOKrbracket)
6026 return false;
6027 t = peek(t);
6028 }
6029 else
6030 {
6031 if (t->value != TOKrbracket)
6032 return false;
6033 t = peek(t);
6034
6035 // ...[index].ident
6036 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6037 {
6038 t = peek(t);
6039 t = peek(t);
6040 }
6041 }
6042 }
6043 continue;
6044
6045 case TOKidentifier:
6046 if (*haveId)
6047 return false;
6048 *haveId = true;
6049 t = peek(t);
6050 break;
6051
6052 case TOKlparen:
6053 if (!allowAltSyntax)
6054 return false; // Do not recognize C-style declarations.
6055
6056 t = peek(t);
6057
6058 if (t->value == TOKrparen)
6059 return false; // () is not a declarator
6060
6061 /* Regard ( identifier ) as not a declarator
6062 * BUG: what about ( *identifier ) in
6063 * f(*p)(x);
6064 * where f is a class instance with overloaded () ?
6065 * Should we just disallow C-style function pointer declarations?
6066 */
6067 if (t->value == TOKidentifier)
6068 { Token *t2 = peek(t);
6069 if (t2->value == TOKrparen)
6070 return false;
6071 }
6072
6073
6074 if (!isDeclarator(&t, haveId, NULL, TOKrparen))
6075 return false;
6076 t = peek(t);
6077 parens = true;
6078 break;
6079
6080 case TOKdelegate:
6081 case TOKfunction:
6082 t = peek(t);
6083 if (!isParameters(&t))
6084 return false;
6085 skipAttributes(t, &t);
6086 continue;
6087 default: break;
6088 }
6089 break;
6090 }
6091
6092 while (1)
6093 {
6094 switch (t->value)
6095 {
6096#if CARRAYDECL
6097 case TOKlbracket:
6098 parens = false;
6099 t = peek(t);
6100 if (t->value == TOKrbracket)
6101 {
6102 t = peek(t);
6103 }
6104 else if (isDeclaration(t, 0, TOKrbracket, &t))
6105 { // It's an associative array declaration
6106 t = peek(t);
6107 }
6108 else
6109 {
6110 // [ expression ]
6111 if (!isExpression(&t))
6112 return false;
6113 if (t->value != TOKrbracket)
6114 return false;
6115 t = peek(t);
6116 }
6117 continue;
6118#endif
6119
6120 case TOKlparen:
6121 parens = false;
6122 if (Token *tk = peekPastParen(t))
6123 {
6124 if (tk->value == TOKlparen)
6125 {
6126 if (!haveTpl) return false;
6127 *haveTpl = 1;
6128 t = tk;
6129 }
6130 else if (tk->value == TOKassign)
6131 {
6132 if (!haveTpl) return false;
6133 *haveTpl = 1;
6134 *pt = tk;
6135 return true;
6136 }
6137 }
6138 if (!isParameters(&t))
6139 return false;
6140 while (1)
6141 {
6142 switch (t->value)
6143 {
6144 case TOKconst:
6145 case TOKimmutable:
6146 case TOKshared:
6147 case TOKwild:
6148 case TOKpure:
6149 case TOKnothrow:
6150 case TOKreturn:
6151 case TOKscope:
6152 t = peek(t);
6153 continue;
6154 case TOKat:
6155 t = peek(t); // skip '@'
6156 t = peek(t); // skip identifier
6157 continue;
6158 default:
6159 break;
6160 }
6161 break;
6162 }
6163 continue;
6164
6165 case TOKidentifier:
6166 if (t->ident != Id::_body)
6167 goto Ldefault;
6168 /* fall through */
6169
6170 // Valid tokens that follow a declaration
6171 case TOKrparen:
6172 case TOKrbracket:
6173 case TOKassign:
6174 case TOKcomma:
6175 case TOKdotdotdot:
6176 case TOKsemicolon:
6177 case TOKlcurly:
6178 case TOKin:
6179 case TOKout:
6180 case TOKdo:
6181 // The !parens is to disallow unnecessary parentheses
6182 if (!parens && (endtok == TOKreserved || endtok == t->value))
6183 { *pt = t;
6184 return true;
6185 }
6186 return false;
6187
6188 case TOKif:
6189 return haveTpl ? true : false;
6190
6191 default:
6192 Ldefault:
6193 return false;
6194 }
6195 }
6196 assert(0);
6197}
6198
6199
6200bool Parser::isParameters(Token **pt)
6201{ // This code parallels parseParameters()
6202 Token *t = *pt;
6203
6204 //printf("isParameters()\n");
6205 if (t->value != TOKlparen)
6206 return false;
6207
6208 t = peek(t);
6209 for (;1; t = peek(t))
6210 {
6211 L1:
6212 switch (t->value)
6213 {
6214 case TOKrparen:
6215 break;
6216
6217 case TOKdotdotdot:
6218 t = peek(t);
6219 break;
6220
6221 case TOKin:
6222 case TOKout:
6223 case TOKref:
6224 case TOKlazy:
6225 case TOKscope:
6226 case TOKfinal:
6227 case TOKauto:
6228 case TOKreturn:
6229 continue;
6230
6231 case TOKconst:
6232 case TOKimmutable:
6233 case TOKshared:
6234 case TOKwild:
6235 t = peek(t);
6236 if (t->value == TOKlparen)
6237 {
6238 t = peek(t);
6239 if (!isDeclaration(t, 0, TOKrparen, &t))
6240 return false;
6241 t = peek(t); // skip past closing ')'
6242 goto L2;
6243 }
6244 goto L1;
6245
6246 default:
6247 { if (!isBasicType(&t))
6248 return false;
6249 L2:
6250 int tmp = false;
6251 if (t->value != TOKdotdotdot &&
6252 !isDeclarator(&t, &tmp, NULL, TOKreserved))
6253 return false;
6254 if (t->value == TOKassign)
6255 { t = peek(t);
6256 if (!isExpression(&t))
6257 return false;
6258 }
6259 if (t->value == TOKdotdotdot)
6260 {
6261 t = peek(t);
6262 break;
6263 }
6264 }
6265 if (t->value == TOKcomma)
6266 {
6267 continue;
6268 }
6269 break;
6270 }
6271 break;
6272 }
6273 if (t->value != TOKrparen)
6274 return false;
6275 t = peek(t);
6276 *pt = t;
6277 return true;
6278}
6279
6280bool Parser::isExpression(Token **pt)
6281{
6282 // This is supposed to determine if something is an expression.
6283 // What it actually does is scan until a closing right bracket
6284 // is found.
6285
6286 Token *t = *pt;
6287 int brnest = 0;
6288 int panest = 0;
6289 int curlynest = 0;
6290
6291 for (;; t = peek(t))
6292 {
6293 switch (t->value)
6294 {
6295 case TOKlbracket:
6296 brnest++;
6297 continue;
6298
6299 case TOKrbracket:
6300 if (--brnest >= 0)
6301 continue;
6302 break;
6303
6304 case TOKlparen:
6305 panest++;
6306 continue;
6307
6308 case TOKcomma:
6309 if (brnest || panest)
6310 continue;
6311 break;
6312
6313 case TOKrparen:
6314 if (--panest >= 0)
6315 continue;
6316 break;
6317
6318 case TOKlcurly:
6319 curlynest++;
6320 continue;
6321
6322 case TOKrcurly:
6323 if (--curlynest >= 0)
6324 continue;
6325 return false;
6326
6327 case TOKslice:
6328 if (brnest)
6329 continue;
6330 break;
6331
6332 case TOKsemicolon:
6333 if (curlynest)
6334 continue;
6335 return false;
6336
6337 case TOKeof:
6338 return false;
6339
6340 default:
6341 continue;
6342 }
6343 break;
6344 }
6345
6346 *pt = t;
6347 return true;
6348}
6349
6350/*******************************************
6351 * Skip parens, brackets.
6352 * Input:
6353 * t is on opening (
6354 * Output:
6355 * *pt is set to closing token, which is ')' on success
6356 * Returns:
6357 * true successful
6358 * false some parsing error
6359 */
6360
6361bool Parser::skipParens(Token *t, Token **pt)
6362{
6363 if (t->value != TOKlparen)
6364 return false;
6365
6366 int parens = 0;
6367
6368 while (1)
6369 {
6370 switch (t->value)
6371 {
6372 case TOKlparen:
6373 parens++;
6374 break;
6375
6376 case TOKrparen:
6377 parens--;
6378 if (parens < 0)
6379 goto Lfalse;
6380 if (parens == 0)
6381 goto Ldone;
6382 break;
6383
6384 case TOKeof:
6385 goto Lfalse;
6386
6387 default:
6388 break;
6389 }
6390 t = peek(t);
6391 }
6392
6393 Ldone:
6394 if (pt)
6395 *pt = peek(t); // skip found rparen
6396 return true;
6397
6398 Lfalse:
6399 return false;
6400}
6401
6402bool Parser::skipParensIf(Token *t, Token **pt)
6403{
6404 if (t->value != TOKlparen)
6405 {
6406 if (pt)
6407 *pt = t;
6408 return true;
6409 }
6410 return skipParens(t, pt);
6411}
6412
6413/*******************************************
6414 * Skip attributes.
6415 * Input:
6416 * t is on a candidate attribute
6417 * Output:
6418 * *pt is set to first non-attribute token on success
6419 * Returns:
6420 * true successful
6421 * false some parsing error
6422 */
6423
6424bool Parser::skipAttributes(Token *t, Token **pt)
6425{
6426 while (1)
6427 {
6428 switch (t->value)
6429 {
6430 case TOKconst:
6431 case TOKimmutable:
6432 case TOKshared:
6433 case TOKwild:
6434 case TOKfinal:
6435 case TOKauto:
6436 case TOKscope:
6437 case TOKoverride:
6438 case TOKabstract:
6439 case TOKsynchronized:
6440 break;
6441 case TOKdeprecated:
6442 if (peek(t)->value == TOKlparen)
6443 {
6444 t = peek(t);
6445 if (!skipParens(t, &t))
6446 goto Lerror;
6447 // t is on the next of closing parenthesis
6448 continue;
6449 }
6450 break;
6451 case TOKnothrow:
6452 case TOKpure:
6453 case TOKref:
6454 case TOKgshared:
6455 case TOKreturn:
6456 //case TOKmanifest:
6457 break;
6458 case TOKat:
6459 t = peek(t);
6460 if (t->value == TOKidentifier)
6461 {
6462 /* @identifier
6463 * @identifier!arg
6464 * @identifier!(arglist)
6465 * any of the above followed by (arglist)
6466 * @predefined_attribute
6467 */
6468 if (t->ident == Id::property ||
6469 t->ident == Id::nogc ||
6470 t->ident == Id::safe ||
6471 t->ident == Id::trusted ||
6472 t->ident == Id::system ||
6473 t->ident == Id::disable)
6474 break;
6475 t = peek(t);
6476 if (t->value == TOKnot)
6477 {
6478 t = peek(t);
6479 if (t->value == TOKlparen)
6480 {
6481 // @identifier!(arglist)
6482 if (!skipParens(t, &t))
6483 goto Lerror;
6484 // t is on the next of closing parenthesis
6485 }
6486 else
6487 {
6488 // @identifier!arg
6489 // Do low rent skipTemplateArgument
6490 if (t->value == TOKvector)
6491 {
6492 // identifier!__vector(type)
6493 t = peek(t);
6494 if (!skipParens(t, &t))
6495 goto Lerror;
6496 }
6497 else
6498 t = peek(t);
6499 }
6500 }
6501 if (t->value == TOKlparen)
6502 {
6503 if (!skipParens(t, &t))
6504 goto Lerror;
6505 // t is on the next of closing parenthesis
6506 continue;
6507 }
6508 continue;
6509 }
6510 if (t->value == TOKlparen)
6511 {
6512 // @( ArgumentList )
6513 if (!skipParens(t, &t))
6514 goto Lerror;
6515 // t is on the next of closing parenthesis
6516 continue;
6517 }
6518 goto Lerror;
6519 default:
6520 goto Ldone;
6521 }
6522 t = peek(t);
6523 }
6524
6525 Ldone:
6526 if (pt)
6527 *pt = t;
6528 return true;
6529
6530 Lerror:
6531 return false;
6532}
6533
6534/********************************* Expression Parser ***************************/
6535
6536Expression *Parser::parsePrimaryExp()
6537{
6538 Expression *e;
6539 Type *t;
6540 Identifier *id;
6541 Loc loc = token.loc;
6542
6543 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
6544 switch (token.value)
6545 {
6546 case TOKidentifier:
6547 {
6548 Token *t1 = peek(&token);
6549 Token *t2 = peek(t1);
6550 if (t1->value == TOKmin && t2->value == TOKgt)
6551 {
6552 // skip ident.
6553 nextToken();
6554 nextToken();
6555 nextToken();
6556 error("use `.` for member lookup, not `->`");
6557 goto Lerr;
6558 }
6559
6560 if (peekNext() == TOKgoesto)
6561 goto case_delegate;
6562
6563 id = token.ident;
6564 nextToken();
6565 TOK save;
6566 if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
6567 {
6568 // identifier!(template-argument-list)
6569 TemplateInstance *tempinst;
6570 tempinst = new TemplateInstance(loc, id);
6571 tempinst->tiargs = parseTemplateArguments();
6572 e = new ScopeExp(loc, tempinst);
6573 }
6574 else
6575 e = new IdentifierExp(loc, id);
6576 break;
6577 }
6578
6579 case TOKdollar:
6580 if (!inBrackets)
6581 error("'$' is valid only inside [] of index or slice");
6582 e = new DollarExp(loc);
6583 nextToken();
6584 break;
6585
6586 case TOKdot:
6587 // Signal global scope '.' operator with "" identifier
6588 e = new IdentifierExp(loc, Id::empty);
6589 break;
6590
6591 case TOKthis:
6592 e = new ThisExp(loc);
6593 nextToken();
6594 break;
6595
6596 case TOKsuper:
6597 e = new SuperExp(loc);
6598 nextToken();
6599 break;
6600
6601 case TOKint32v:
6602 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
6603 nextToken();
6604 break;
6605
6606 case TOKuns32v:
6607 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
6608 nextToken();
6609 break;
6610
6611 case TOKint64v:
6612 e = new IntegerExp(loc, token.int64value, Type::tint64);
6613 nextToken();
6614 break;
6615
6616 case TOKuns64v:
6617 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
6618 nextToken();
6619 break;
6620
6621 case TOKfloat32v:
6622 e = new RealExp(loc, token.floatvalue, Type::tfloat32);
6623 nextToken();
6624 break;
6625
6626 case TOKfloat64v:
6627 e = new RealExp(loc, token.floatvalue, Type::tfloat64);
6628 nextToken();
6629 break;
6630
6631 case TOKfloat80v:
6632 e = new RealExp(loc, token.floatvalue, Type::tfloat80);
6633 nextToken();
6634 break;
6635
6636 case TOKimaginary32v:
6637 e = new RealExp(loc, token.floatvalue, Type::timaginary32);
6638 nextToken();
6639 break;
6640
6641 case TOKimaginary64v:
6642 e = new RealExp(loc, token.floatvalue, Type::timaginary64);
6643 nextToken();
6644 break;
6645
6646 case TOKimaginary80v:
6647 e = new RealExp(loc, token.floatvalue, Type::timaginary80);
6648 nextToken();
6649 break;
6650
6651 case TOKnull:
6652 e = new NullExp(loc);
6653 nextToken();
6654 break;
6655
6656 case TOKfile:
6657 {
6658 const char *s = loc.filename ? loc.filename : mod->ident->toChars();
6659 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6660 nextToken();
6661 break;
6662 }
6663
6664 case TOKfilefullpath:
6665 {
6666 const char *srcfile = mod->srcfile->name->toChars();
6667 const char *s;
6668 if (loc.filename && !FileName::equals(loc.filename, srcfile))
6669 s = loc.filename;
6670 else
6671 s = FileName::combine(mod->srcfilePath, srcfile);
6672 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6673 nextToken();
6674 break;
6675 }
6676
6677 case TOKline:
6678 e = new IntegerExp(loc, loc.linnum, Type::tint32);
6679 nextToken();
6680 break;
6681
6682 case TOKmodulestring:
6683 {
6684 const char *s = md ? md->toChars() : mod->toChars();
6685 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6686 nextToken();
6687 break;
6688 }
6689
6690 case TOKfuncstring:
6691 e = new FuncInitExp(loc);
6692 nextToken();
6693 break;
6694
6695 case TOKprettyfunc:
6696 e = new PrettyFuncInitExp(loc);
6697 nextToken();
6698 break;
6699
6700 case TOKtrue:
6701 e = new IntegerExp(loc, 1, Type::tbool);
6702 nextToken();
6703 break;
6704
6705 case TOKfalse:
6706 e = new IntegerExp(loc, 0, Type::tbool);
6707 nextToken();
6708 break;
6709
6710 case TOKcharv:
6711 e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
6712 nextToken();
6713 break;
6714
6715 case TOKwcharv:
6716 e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
6717 nextToken();
6718 break;
6719
6720 case TOKdcharv:
6721 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
6722 nextToken();
6723 break;
6724
6725 case TOKstring:
6726 case TOKxstring:
6727 {
6728 // cat adjacent strings
6729 utf8_t *s = token.ustring;
6730 size_t len = token.len;
6731 unsigned char postfix = token.postfix;
6732 while (1)
6733 {
6734 const Token prev = token;
6735 nextToken();
6736 if (token.value == TOKstring ||
6737 token.value == TOKxstring)
6738 {
6739 if (token.postfix)
6740 { if (token.postfix != postfix)
6741 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
6742 postfix = token.postfix;
6743 }
6744
6745 deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
6746 prev.toChars(), token.toChars());
6747
6748 size_t len1 = len;
6749 size_t len2 = token.len;
6750 len = len1 + len2;
6751 utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
6752 memcpy(s2, s, len1 * sizeof(utf8_t));
6753 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
6754 s = s2;
6755 }
6756 else
6757 break;
6758 }
6759 e = new StringExp(loc, s, len, postfix);
6760 break;
6761 }
6762
6763 case TOKvoid: t = Type::tvoid; goto LabelX;
6764 case TOKint8: t = Type::tint8; goto LabelX;
6765 case TOKuns8: t = Type::tuns8; goto LabelX;
6766 case TOKint16: t = Type::tint16; goto LabelX;
6767 case TOKuns16: t = Type::tuns16; goto LabelX;
6768 case TOKint32: t = Type::tint32; goto LabelX;
6769 case TOKuns32: t = Type::tuns32; goto LabelX;
6770 case TOKint64: t = Type::tint64; goto LabelX;
6771 case TOKuns64: t = Type::tuns64; goto LabelX;
6772 case TOKint128: t = Type::tint128; goto LabelX;
6773 case TOKuns128: t = Type::tuns128; goto LabelX;
6774 case TOKfloat32: t = Type::tfloat32; goto LabelX;
6775 case TOKfloat64: t = Type::tfloat64; goto LabelX;
6776 case TOKfloat80: t = Type::tfloat80; goto LabelX;
6777 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
6778 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
6779 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
6780 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
6781 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
6782 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
6783 case TOKbool: t = Type::tbool; goto LabelX;
6784 case TOKchar: t = Type::tchar; goto LabelX;
6785 case TOKwchar: t = Type::twchar; goto LabelX;
6786 case TOKdchar: t = Type::tdchar; goto LabelX;
6787 LabelX:
6788 nextToken();
6789 if (token.value == TOKlparen)
6790 {
6791 e = new TypeExp(loc, t);
6792 e = new CallExp(loc, e, parseArguments());
6793 break;
6794 }
6795 check(TOKdot, t->toChars());
6796 if (token.value != TOKidentifier)
6797 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
6798 goto Lerr;
6799 }
6800 e = typeDotIdExp(loc, t, token.ident);
6801 nextToken();
6802 break;
6803
6804 case TOKtypeof:
6805 {
6806 t = parseTypeof();
6807 e = new TypeExp(loc, t);
6808 break;
6809 }
6810
6811 case TOKvector:
6812 {
6813 t = parseVector();
6814 e = new TypeExp(loc, t);
6815 break;
6816 }
6817
6818 case TOKtypeid:
6819 {
6820 nextToken();
6821 check(TOKlparen, "typeid");
6822 RootObject *o;
6823 if (isDeclaration(&token, 0, TOKreserved, NULL))
6824 { // argument is a type
6825 o = parseType();
6826 }
6827 else
6828 { // argument is an expression
6829 o = parseAssignExp();
6830 }
6831 check(TOKrparen);
6832 e = new TypeidExp(loc, o);
6833 break;
6834 }
6835
6836 case TOKtraits:
6837 { /* __traits(identifier, args...)
6838 */
6839 Identifier *ident;
6840 Objects *args = NULL;
6841
6842 nextToken();
6843 check(TOKlparen);
6844 if (token.value != TOKidentifier)
6845 { error("__traits(identifier, args...) expected");
6846 goto Lerr;
6847 }
6848 ident = token.ident;
6849 nextToken();
6850 if (token.value == TOKcomma)
6851 args = parseTemplateArgumentList(); // __traits(identifier, args...)
6852 else
6853 check(TOKrparen); // __traits(identifier)
6854
6855 e = new TraitsExp(loc, ident, args);
6856 break;
6857 }
6858
6859 case TOKis:
6860 {
6861 Type *targ;
6862 Identifier *ident = NULL;
6863 Type *tspec = NULL;
6864 TOK tok = TOKreserved;
6865 TOK tok2 = TOKreserved;
6866 TemplateParameters *tpl = NULL;
6867
6868 nextToken();
6869 if (token.value == TOKlparen)
6870 {
6871 nextToken();
6872 targ = parseType(&ident);
6873 if (token.value == TOKcolon || token.value == TOKequal)
6874 {
6875 tok = token.value;
6876 nextToken();
6877 if (tok == TOKequal &&
6878 (token.value == TOKstruct ||
6879 token.value == TOKunion ||
6880 token.value == TOKclass ||
6881 token.value == TOKsuper ||
6882 token.value == TOKenum ||
6883 token.value == TOKinterface ||
6884 token.value == TOKargTypes ||
6885 token.value == TOKparameters ||
6886 (token.value == TOKconst && peek(&token)->value == TOKrparen) ||
6887 (token.value == TOKimmutable && peek(&token)->value == TOKrparen) ||
6888 (token.value == TOKshared && peek(&token)->value == TOKrparen) ||
6889 (token.value == TOKwild && peek(&token)->value == TOKrparen) ||
6890 token.value == TOKfunction ||
6891 token.value == TOKdelegate ||
6892 token.value == TOKreturn ||
6893 (token.value == TOKvector && peek(&token)->value == TOKrparen)))
6894 {
6895 tok2 = token.value;
6896 nextToken();
6897 }
6898 else
6899 {
6900 tspec = parseType();
6901 }
6902 }
6903 if (tspec)
6904 {
6905 if (token.value == TOKcomma)
6906 tpl = parseTemplateParameterList(1);
6907 else
6908 {
6909 tpl = new TemplateParameters();
6910 check(TOKrparen);
6911 }
6912 }
6913 else
6914 check(TOKrparen);
6915 }
6916 else
6917 {
6918 error("(type identifier : specialization) expected following is");
6919 goto Lerr;
6920 }
6921 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
6922 break;
6923 }
6924
6925 case TOKassert:
6926 { Expression *msg = NULL;
6927
6928 nextToken();
6929 check(TOKlparen, "assert");
6930 e = parseAssignExp();
6931 if (token.value == TOKcomma)
6932 {
6933 nextToken();
6934 if (token.value != TOKrparen)
6935 {
6936 msg = parseAssignExp();
6937 if (token.value == TOKcomma)
6938 nextToken();
6939 }
6940 }
6941 check(TOKrparen);
6942 e = new AssertExp(loc, e, msg);
6943 break;
6944 }
6945
6946 case TOKmixin:
6947 {
6948 nextToken();
6949 check(TOKlparen, "mixin");
6950 e = parseAssignExp();
6951 check(TOKrparen);
6952 e = new CompileExp(loc, e);
6953 break;
6954 }
6955
6956 case TOKimport:
6957 {
6958 nextToken();
6959 check(TOKlparen, "import");
6960 e = parseAssignExp();
6961 check(TOKrparen);
6962 e = new ImportExp(loc, e);
6963 break;
6964 }
6965
6966 case TOKnew:
6967 e = parseNewExp(NULL);
6968 break;
6969
6970 case TOKlparen:
6971 {
6972 Token *tk = peekPastParen(&token);
6973 if (skipAttributes(tk, &tk) &&
6974 (tk->value == TOKgoesto || tk->value == TOKlcurly))
6975 {
6976 // (arguments) => expression
6977 // (arguments) { statements... }
6978 goto case_delegate;
6979 }
6980
6981 // ( expression )
6982 nextToken();
6983 e = parseExpression();
6984 e->parens = 1;
6985 check(loc, TOKrparen);
6986 break;
6987 }
6988
6989 case TOKlbracket:
6990 { /* Parse array literals and associative array literals:
6991 * [ value, value, value ... ]
6992 * [ key:value, key:value, key:value ... ]
6993 */
6994 Expressions *values = new Expressions();
6995 Expressions *keys = NULL;
6996
6997 nextToken();
6998 while (token.value != TOKrbracket && token.value != TOKeof)
6999 {
7000 e = parseAssignExp();
7001 if (token.value == TOKcolon && (keys || values->dim == 0))
7002 { nextToken();
7003 if (!keys)
7004 keys = new Expressions();
7005 keys->push(e);
7006 e = parseAssignExp();
7007 }
7008 else if (keys)
7009 { error("'key:value' expected for associative array literal");
7010 delete keys;
7011 keys = NULL;
7012 }
7013 values->push(e);
7014 if (token.value == TOKrbracket)
7015 break;
7016 check(TOKcomma);
7017 }
7018 check(loc, TOKrbracket);
7019
7020 if (keys)
7021 e = new AssocArrayLiteralExp(loc, keys, values);
7022 else
7023 e = new ArrayLiteralExp(loc, values);
7024 break;
7025 }
7026
7027 case TOKlcurly:
7028 case TOKfunction:
7029 case TOKdelegate:
7030 case_delegate:
7031 {
7032 Dsymbol *s = parseFunctionLiteral();
7033 e = new FuncExp(loc, s);
7034 break;
7035 }
7036
7037 default:
7038 error("expression expected, not '%s'", token.toChars());
7039 Lerr:
7040 // Anything for e, as long as it's not NULL
7041 e = new IntegerExp(loc, 0, Type::tint32);
7042 nextToken();
7043 break;
7044 }
7045 return e;
7046}
7047
7048Expression *Parser::parsePostExp(Expression *e)
7049{
7050 Loc loc;
7051
7052 while (1)
7053 {
7054 loc = token.loc;
7055 switch (token.value)
7056 {
7057 case TOKdot:
7058 nextToken();
7059 if (token.value == TOKidentifier)
7060 { Identifier *id = token.ident;
7061
7062 nextToken();
7063 if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
7064 {
7065 Objects *tiargs = parseTemplateArguments();
7066 e = new DotTemplateInstanceExp(loc, e, id, tiargs);
7067 }
7068 else
7069 e = new DotIdExp(loc, e, id);
7070 continue;
7071 }
7072 else if (token.value == TOKnew)
7073 {
7074 e = parseNewExp(e);
7075 continue;
7076 }
7077 else
7078 error("identifier expected following '.', not '%s'", token.toChars());
7079 break;
7080
7081 case TOKplusplus:
7082 e = new PostExp(TOKplusplus, loc, e);
7083 break;
7084
7085 case TOKminusminus:
7086 e = new PostExp(TOKminusminus, loc, e);
7087 break;
7088
7089 case TOKlparen:
7090 e = new CallExp(loc, e, parseArguments());
7091 continue;
7092
7093 case TOKlbracket:
7094 { // array dereferences:
7095 // array[index]
7096 // array[]
7097 // array[lwr .. upr]
7098 Expression *index;
7099 Expression *upr;
7100 Expressions *arguments = new Expressions();
7101
7102 inBrackets++;
7103 nextToken();
7104 while (token.value != TOKrbracket && token.value != TOKeof)
7105 {
7106 index = parseAssignExp();
7107 if (token.value == TOKslice)
7108 {
7109 // array[..., lwr..upr, ...]
7110 nextToken();
7111 upr = parseAssignExp();
7112 arguments->push(new IntervalExp(loc, index, upr));
7113 }
7114 else
7115 arguments->push(index);
7116 if (token.value == TOKrbracket)
7117 break;
7118 check(TOKcomma);
7119 }
7120 check(TOKrbracket);
7121 inBrackets--;
7122 e = new ArrayExp(loc, e, arguments);
7123 continue;
7124 }
7125
7126 default:
7127 return e;
7128 }
7129 nextToken();
7130 }
7131}
7132
7133Expression *Parser::parseUnaryExp()
7134{
7135 Expression *e;
7136 Loc loc = token.loc;
7137
7138 switch (token.value)
7139 {
7140 case TOKand:
7141 nextToken();
7142 e = parseUnaryExp();
7143 e = new AddrExp(loc, e);
7144 break;
7145
7146 case TOKplusplus:
7147 nextToken();
7148 e = parseUnaryExp();
7149 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7150 e = new PreExp(TOKpreplusplus, loc, e);
7151 break;
7152
7153 case TOKminusminus:
7154 nextToken();
7155 e = parseUnaryExp();
7156 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7157 e = new PreExp(TOKpreminusminus, loc, e);
7158 break;
7159
7160 case TOKmul:
7161 nextToken();
7162 e = parseUnaryExp();
7163 e = new PtrExp(loc, e);
7164 break;
7165
7166 case TOKmin:
7167 nextToken();
7168 e = parseUnaryExp();
7169 e = new NegExp(loc, e);
7170 break;
7171
7172 case TOKadd:
7173 nextToken();
7174 e = parseUnaryExp();
7175 e = new UAddExp(loc, e);
7176 break;
7177
7178 case TOKnot:
7179 nextToken();
7180 e = parseUnaryExp();
7181 e = new NotExp(loc, e);
7182 break;
7183
7184 case TOKtilde:
7185 nextToken();
7186 e = parseUnaryExp();
7187 e = new ComExp(loc, e);
7188 break;
7189
7190 case TOKdelete:
7191 nextToken();
7192 e = parseUnaryExp();
7193 e = new DeleteExp(loc, e, false);
7194 break;
7195
7196 case TOKcast: // cast(type) expression
7197 {
7198 nextToken();
7199 check(TOKlparen);
7200 /* Look for cast(), cast(const), cast(immutable),
7201 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7202 */
7203 unsigned char m = 0;
7204 while (1)
7205 {
7206 switch (token.value)
7207 {
7208 case TOKconst:
7209 if (peekNext() == TOKlparen)
7210 break; // const as type constructor
7211 m |= MODconst; // const as storage class
7212 nextToken();
7213 continue;
7214
7215 case TOKimmutable:
7216 if (peekNext() == TOKlparen)
7217 break;
7218 m |= MODimmutable;
7219 nextToken();
7220 continue;
7221
7222 case TOKshared:
7223 if (peekNext() == TOKlparen)
7224 break;
7225 m |= MODshared;
7226 nextToken();
7227 continue;
7228
7229 case TOKwild:
7230 if (peekNext() == TOKlparen)
7231 break;
7232 m |= MODwild;
7233 nextToken();
7234 continue;
7235
7236 default:
7237 break;
7238 }
7239 break;
7240 }
7241 if (token.value == TOKrparen)
7242 {
7243 nextToken();
7244 e = parseUnaryExp();
7245 e = new CastExp(loc, e, m);
7246 }
7247 else
7248 {
7249 Type *t = parseType(); // cast( type )
7250 t = t->addMod(m); // cast( const type )
7251 check(TOKrparen);
7252 e = parseUnaryExp();
7253 e = new CastExp(loc, e, t);
7254 }
7255 break;
7256 }
7257
7258 case TOKwild:
7259 case TOKshared:
7260 case TOKconst:
7261 case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
7262 {
7263 StorageClass stc = parseTypeCtor();
7264 Type *t = parseBasicType();
7265 t = t->addSTC(stc);
7266 e = new TypeExp(loc, t);
7267 if (stc == 0 && token.value == TOKdot)
7268 {
7269 nextToken();
7270 if (token.value != TOKidentifier)
7271 {
7272 error("identifier expected following (type).");
7273 return NULL;
7274 }
7275 e = typeDotIdExp(loc, t, token.ident);
7276 nextToken();
7277 e = parsePostExp(e);
7278 break;
7279 }
7280 else if (token.value != TOKlparen)
7281 {
7282 error("(arguments) expected following %s", t->toChars());
7283 return e;
7284 }
7285 e = new CallExp(loc, e, parseArguments());
7286 break;
7287 }
7288
7289
7290 case TOKlparen:
7291 { Token *tk;
7292
7293 tk = peek(&token);
7294#if CCASTSYNTAX
7295 // If cast
7296 if (isDeclaration(tk, 0, TOKrparen, &tk))
7297 {
7298 tk = peek(tk); // skip over right parenthesis
7299 switch (tk->value)
7300 {
7301 case TOKnot:
7302 tk = peek(tk);
7303 if (tk->value == TOKis || tk->value == TOKin) // !is or !in
7304 break;
7305 /* fall through */
7306
7307 case TOKdot:
7308 case TOKplusplus:
7309 case TOKminusminus:
7310 case TOKdelete:
7311 case TOKnew:
7312 case TOKlparen:
7313 case TOKidentifier:
7314 case TOKthis:
7315 case TOKsuper:
7316 case TOKint32v:
7317 case TOKuns32v:
7318 case TOKint64v:
7319 case TOKuns64v:
7320 case TOKint128v:
7321 case TOKuns128v:
7322 case TOKfloat32v:
7323 case TOKfloat64v:
7324 case TOKfloat80v:
7325 case TOKimaginary32v:
7326 case TOKimaginary64v:
7327 case TOKimaginary80v:
7328 case TOKnull:
7329 case TOKtrue:
7330 case TOKfalse:
7331 case TOKcharv:
7332 case TOKwcharv:
7333 case TOKdcharv:
7334 case TOKstring:
7335 case TOKfunction:
7336 case TOKdelegate:
7337 case TOKtypeof:
7338 case TOKvector:
7339 case TOKfile:
7340 case TOKfilefullpath:
7341 case TOKline:
7342 case TOKmodulestring:
7343 case TOKfuncstring:
7344 case TOKprettyfunc:
7345 case TOKwchar: case TOKdchar:
7346 case TOKbool: case TOKchar:
7347 case TOKint8: case TOKuns8:
7348 case TOKint16: case TOKuns16:
7349 case TOKint32: case TOKuns32:
7350 case TOKint64: case TOKuns64:
7351 case TOKint128: case TOKuns128:
7352 case TOKfloat32: case TOKfloat64: case TOKfloat80:
7353 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
7354 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
7355 case TOKvoid:
7356 { // (type) una_exp
7357 Type *t;
7358
7359 nextToken();
7360 t = parseType();
7361 check(TOKrparen);
7362
7363 // if .identifier
7364 // or .identifier!( ... )
7365 if (token.value == TOKdot)
7366 {
7367 if (peekNext() != TOKidentifier && peekNext() != TOKnew)
7368 {
7369 error("identifier or new keyword expected following (...).");
7370 return NULL;
7371 }
7372 e = new TypeExp(loc, t);
7373 e = parsePostExp(e);
7374 }
7375 else
7376 {
7377 e = parseUnaryExp();
7378 e = new CastExp(loc, e, t);
7379 error("C style cast illegal, use %s", e->toChars());
7380 }
7381 return e;
7382 }
7383 default:
7384 break;
7385 }
7386 }
7387#endif
7388 e = parsePrimaryExp();
7389 e = parsePostExp(e);
7390 break;
7391 }
7392 default:
7393 e = parsePrimaryExp();
7394 e = parsePostExp(e);
7395 break;
7396 }
7397 assert(e);
7398
7399 // ^^ is right associative and has higher precedence than the unary operators
7400 while (token.value == TOKpow)
7401 {
7402 nextToken();
7403 Expression *e2 = parseUnaryExp();
7404 e = new PowExp(loc, e, e2);
7405 }
7406
7407 return e;
7408}
7409
7410Expression *Parser::parseMulExp()
7411{
7412 Expression *e;
7413 Expression *e2;
7414 Loc loc = token.loc;
7415
7416 e = parseUnaryExp();
7417 while (1)
7418 {
7419 switch (token.value)
7420 {
7421 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
7422 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
7423 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
7424
7425 default:
7426 break;
7427 }
7428 break;
7429 }
7430 return e;
7431}
7432
7433Expression *Parser::parseAddExp()
7434{
7435 Expression *e;
7436 Expression *e2;
7437 Loc loc = token.loc;
7438
7439 e = parseMulExp();
7440 while (1)
7441 {
7442 switch (token.value)
7443 {
7444 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
7445 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
7446 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
7447
7448 default:
7449 break;
7450 }
7451 break;
7452 }
7453 return e;
7454}
7455
7456Expression *Parser::parseShiftExp()
7457{
7458 Expression *e;
7459 Expression *e2;
7460 Loc loc = token.loc;
7461
7462 e = parseAddExp();
7463 while (1)
7464 {
7465 switch (token.value)
7466 {
7467 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
7468 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
7469 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
7470
7471 default:
7472 break;
7473 }
7474 break;
7475 }
7476 return e;
7477}
7478
7479Expression *Parser::parseCmpExp()
7480{
7481 Expression *e;
7482 Expression *e2;
7483 Token *t;
7484 Loc loc = token.loc;
7485
7486 e = parseShiftExp();
7487 TOK op = token.value;
7488
7489 switch (op)
7490 {
7491 case TOKequal:
7492 case TOKnotequal:
7493 nextToken();
7494 e2 = parseShiftExp();
7495 e = new EqualExp(op, loc, e, e2);
7496 break;
7497
7498 case TOKis:
7499 op = TOKidentity;
7500 goto L1;
7501
7502 case TOKnot:
7503 // Attempt to identify '!is'
7504 t = peek(&token);
7505 if (t->value == TOKin)
7506 {
7507 nextToken();
7508 nextToken();
7509 e2 = parseShiftExp();
7510 e = new InExp(loc, e, e2);
7511 e = new NotExp(loc, e);
7512 break;
7513 }
7514 if (t->value != TOKis)
7515 break;
7516 nextToken();
7517 op = TOKnotidentity;
7518 goto L1;
7519
7520 L1:
7521 nextToken();
7522 e2 = parseShiftExp();
7523 e = new IdentityExp(op, loc, e, e2);
7524 break;
7525
7526 case TOKlt:
7527 case TOKle:
7528 case TOKgt:
7529 case TOKge:
7530 case TOKunord:
7531 case TOKlg:
7532 case TOKleg:
7533 case TOKule:
7534 case TOKul:
7535 case TOKuge:
7536 case TOKug:
7537 case TOKue:
7538 nextToken();
7539 e2 = parseShiftExp();
7540 e = new CmpExp(op, loc, e, e2);
7541 break;
7542
7543 case TOKin:
7544 nextToken();
7545 e2 = parseShiftExp();
7546 e = new InExp(loc, e, e2);
7547 break;
7548
7549 default:
7550 break;
7551 }
7552 return e;
7553}
7554
7555Expression *Parser::parseAndExp()
7556{
7557 Loc loc = token.loc;
7558
7559 Expression *e = parseCmpExp();
7560 while (token.value == TOKand)
7561 {
7562 checkParens(TOKand, e);
7563 nextToken();
7564 Expression *e2 = parseCmpExp();
7565 checkParens(TOKand, e2);
7566 e = new AndExp(loc,e,e2);
7567 loc = token.loc;
7568 }
7569 return e;
7570}
7571
7572Expression *Parser::parseXorExp()
7573{
7574 Loc loc = token.loc;
7575
7576 Expression *e = parseAndExp();
7577 while (token.value == TOKxor)
7578 {
7579 checkParens(TOKxor, e);
7580 nextToken();
7581 Expression *e2 = parseAndExp();
7582 checkParens(TOKxor, e2);
7583 e = new XorExp(loc, e, e2);
7584 }
7585 return e;
7586}
7587
7588Expression *Parser::parseOrExp()
7589{
7590 Loc loc = token.loc;
7591
7592 Expression *e = parseXorExp();
7593 while (token.value == TOKor)
7594 {
7595 checkParens(TOKor, e);
7596 nextToken();
7597 Expression *e2 = parseXorExp();
7598 checkParens(TOKor, e2);
7599 e = new OrExp(loc, e, e2);
7600 }
7601 return e;
7602}
7603
7604Expression *Parser::parseAndAndExp()
7605{
7606 Expression *e;
7607 Expression *e2;
7608 Loc loc = token.loc;
7609
7610 e = parseOrExp();
7611 while (token.value == TOKandand)
7612 {
7613 nextToken();
7614 e2 = parseOrExp();
7615 e = new AndAndExp(loc, e, e2);
7616 }
7617 return e;
7618}
7619
7620Expression *Parser::parseOrOrExp()
7621{
7622 Expression *e;
7623 Expression *e2;
7624 Loc loc = token.loc;
7625
7626 e = parseAndAndExp();
7627 while (token.value == TOKoror)
7628 {
7629 nextToken();
7630 e2 = parseAndAndExp();
7631 e = new OrOrExp(loc, e, e2);
7632 }
7633 return e;
7634}
7635
7636Expression *Parser::parseCondExp()
7637{
7638 Expression *e;
7639 Expression *e1;
7640 Expression *e2;
7641 Loc loc = token.loc;
7642
7643 e = parseOrOrExp();
7644 if (token.value == TOKquestion)
7645 {
7646 nextToken();
7647 e1 = parseExpression();
7648 check(TOKcolon);
7649 e2 = parseCondExp();
7650 e = new CondExp(loc, e, e1, e2);
7651 }
7652 return e;
7653}
7654
7655Expression *Parser::parseAssignExp()
7656{
7657 Expression *e;
7658 Expression *e2;
7659 Loc loc;
7660
7661 e = parseCondExp();
7662 while (1)
7663 {
7664 loc = token.loc;
7665 switch (token.value)
7666 {
7667 case TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
7668 case TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
7669 case TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
7670 case TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
7671 case TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
7672 case TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
7673 case TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue;
7674 case TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
7675 case TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
7676 case TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
7677 case TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
7678 case TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
7679 case TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
7680 case TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
7681 default:
7682 break;
7683 }
7684 break;
7685 }
7686 return e;
7687}
7688
7689Expression *Parser::parseExpression()
7690{
7691 Expression *e;
7692 Expression *e2;
7693 Loc loc = token.loc;
7694
7695 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
7696 e = parseAssignExp();
7697 while (token.value == TOKcomma)
7698 {
7699 nextToken();
7700 e2 = parseAssignExp();
7701 e = new CommaExp(loc, e, e2, false);
7702 loc = token.loc;
7703 }
7704 return e;
7705}
7706
7707
7708/*************************
7709 * Collect argument list.
7710 * Assume current token is ',', '(' or '['.
7711 */
7712
7713Expressions *Parser::parseArguments()
7714{ // function call
7715 Expressions *arguments;
7716 Expression *arg;
7717 TOK endtok;
7718
7719 arguments = new Expressions();
7720 if (token.value == TOKlbracket)
7721 endtok = TOKrbracket;
7722 else
7723 endtok = TOKrparen;
7724
7725 {
7726 nextToken();
7727 while (token.value != endtok && token.value != TOKeof)
7728 {
7729 arg = parseAssignExp();
7730 arguments->push(arg);
7731 if (token.value == endtok)
7732 break;
7733 check(TOKcomma);
7734 }
7735 check(endtok);
7736 }
7737 return arguments;
7738}
7739
7740/*******************************************
7741 */
7742
7743Expression *Parser::parseNewExp(Expression *thisexp)
7744{
7745 Type *t;
7746 Expressions *newargs;
7747 Expressions *arguments = NULL;
7748 Loc loc = token.loc;
7749
7750 nextToken();
7751 newargs = NULL;
7752 if (token.value == TOKlparen)
7753 {
7754 newargs = parseArguments();
7755 }
7756
7757 // An anonymous nested class starts with "class"
7758 if (token.value == TOKclass)
7759 {
7760 nextToken();
7761 if (token.value == TOKlparen)
7762 arguments = parseArguments();
7763
7764 BaseClasses *baseclasses = NULL;
7765 if (token.value != TOKlcurly)
7766 baseclasses = parseBaseClasses();
7767
7768 Identifier *id = NULL;
7769 Dsymbols *members = NULL;
7770
7771 if (token.value != TOKlcurly)
7772 {
7773 error("{ members } expected for anonymous class");
7774 }
7775 else
7776 {
7777 nextToken();
7778 members = parseDeclDefs(0);
7779 if (token.value != TOKrcurly)
7780 error("class member expected");
7781 nextToken();
7782 }
7783
7784 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false);
7785 Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
7786
7787 return e;
7788 }
7789
7790 StorageClass stc = parseTypeCtor();
7791 t = parseBasicType(true);
7792 t = parseBasicType2(t);
7793 t = t->addSTC(stc);
7794 if (t->ty == Taarray)
7795 {
7796 TypeAArray *taa = (TypeAArray *)t;
7797 Type *index = taa->index;
7798
7799 Expression *edim = typeToExpression(index);
7800 if (!edim)
7801 {
7802 error("need size of rightmost array, not type %s", index->toChars());
7803 return new NullExp(loc);
7804 }
7805 t = new TypeSArray(taa->next, edim);
7806 }
7807 else if (t->ty == Tsarray)
7808 {
7809 }
7810 else if (token.value == TOKlparen)
7811 {
7812 arguments = parseArguments();
7813 }
7814 Expression *e = new NewExp(loc, thisexp, newargs, t, arguments);
7815 return e;
7816}
7817
7818/**********************************************
7819 */
7820
7821void Parser::addComment(Dsymbol *s, const utf8_t *blockComment)
7822{
7823 s->addComment(combineComments(blockComment, token.lineComment));
7824 token.lineComment = NULL;
7825}
7826
7827
7828/**********************************
7829 * Set operator precedence for each operator.
7830 */
7831
7832PREC precedence[TOKMAX];
7833
7834struct PrecedenceInitializer
7835{
7836 PrecedenceInitializer();
7837};
7838
7839static PrecedenceInitializer precedenceinitializer;
7840
7841PrecedenceInitializer::PrecedenceInitializer()
7842{
7843 for (size_t i = 0; i < TOKMAX; i++)
7844 precedence[i] = PREC_zero;
7845
7846 precedence[TOKtype] = PREC_expr;
7847 precedence[TOKerror] = PREC_expr;
7848
7849 precedence[TOKtypeof] = PREC_primary;
7850 precedence[TOKmixin] = PREC_primary;
7851 precedence[TOKimport] = PREC_primary;
7852
7853 precedence[TOKdotvar] = PREC_primary;
7854 precedence[TOKscope] = PREC_primary;
7855 precedence[TOKidentifier] = PREC_primary;
7856 precedence[TOKthis] = PREC_primary;
7857 precedence[TOKsuper] = PREC_primary;
7858 precedence[TOKint64] = PREC_primary;
7859 precedence[TOKfloat64] = PREC_primary;
7860 precedence[TOKcomplex80] = PREC_primary;
7861 precedence[TOKnull] = PREC_primary;
7862 precedence[TOKstring] = PREC_primary;
7863 precedence[TOKarrayliteral] = PREC_primary;
7864 precedence[TOKassocarrayliteral] = PREC_primary;
7865 precedence[TOKclassreference] = PREC_primary;
7866 precedence[TOKfile] = PREC_primary;
7867 precedence[TOKfilefullpath] = PREC_primary;
7868 precedence[TOKline] = PREC_primary;
7869 precedence[TOKmodulestring] = PREC_primary;
7870 precedence[TOKfuncstring] = PREC_primary;
7871 precedence[TOKprettyfunc] = PREC_primary;
7872 precedence[TOKtypeid] = PREC_primary;
7873 precedence[TOKis] = PREC_primary;
7874 precedence[TOKassert] = PREC_primary;
7875 precedence[TOKhalt] = PREC_primary;
7876 precedence[TOKtemplate] = PREC_primary;
7877 precedence[TOKdsymbol] = PREC_primary;
7878 precedence[TOKfunction] = PREC_primary;
7879 precedence[TOKvar] = PREC_primary;
7880 precedence[TOKsymoff] = PREC_primary;
7881 precedence[TOKstructliteral] = PREC_primary;
7882 precedence[TOKarraylength] = PREC_primary;
7883 precedence[TOKdelegateptr] = PREC_primary;
7884 precedence[TOKdelegatefuncptr] = PREC_primary;
7885 precedence[TOKremove] = PREC_primary;
7886 precedence[TOKtuple] = PREC_primary;
7887 precedence[TOKtraits] = PREC_primary;
7888 precedence[TOKdefault] = PREC_primary;
7889 precedence[TOKoverloadset] = PREC_primary;
7890 precedence[TOKvoid] = PREC_primary;
7891
7892 // post
7893 precedence[TOKdotti] = PREC_primary;
7894 precedence[TOKdotid] = PREC_primary;
7895 precedence[TOKdottd] = PREC_primary;
7896 precedence[TOKdot] = PREC_primary;
7897 precedence[TOKdottype] = PREC_primary;
7898// precedence[TOKarrow] = PREC_primary;
7899 precedence[TOKplusplus] = PREC_primary;
7900 precedence[TOKminusminus] = PREC_primary;
7901 precedence[TOKpreplusplus] = PREC_primary;
7902 precedence[TOKpreminusminus] = PREC_primary;
7903 precedence[TOKcall] = PREC_primary;
7904 precedence[TOKslice] = PREC_primary;
7905 precedence[TOKarray] = PREC_primary;
7906 precedence[TOKindex] = PREC_primary;
7907
7908 precedence[TOKdelegate] = PREC_unary;
7909 precedence[TOKaddress] = PREC_unary;
7910 precedence[TOKstar] = PREC_unary;
7911 precedence[TOKneg] = PREC_unary;
7912 precedence[TOKuadd] = PREC_unary;
7913 precedence[TOKnot] = PREC_unary;
7914 precedence[TOKtilde] = PREC_unary;
7915 precedence[TOKdelete] = PREC_unary;
7916 precedence[TOKnew] = PREC_unary;
7917 precedence[TOKnewanonclass] = PREC_unary;
7918 precedence[TOKcast] = PREC_unary;
7919
7920 precedence[TOKvector] = PREC_unary;
7921 precedence[TOKpow] = PREC_pow;
7922
7923 precedence[TOKmul] = PREC_mul;
7924 precedence[TOKdiv] = PREC_mul;
7925 precedence[TOKmod] = PREC_mul;
7926
7927 precedence[TOKadd] = PREC_add;
7928 precedence[TOKmin] = PREC_add;
7929 precedence[TOKcat] = PREC_add;
7930
7931 precedence[TOKshl] = PREC_shift;
7932 precedence[TOKshr] = PREC_shift;
7933 precedence[TOKushr] = PREC_shift;
7934
7935 precedence[TOKlt] = PREC_rel;
7936 precedence[TOKle] = PREC_rel;
7937 precedence[TOKgt] = PREC_rel;
7938 precedence[TOKge] = PREC_rel;
7939 precedence[TOKunord] = PREC_rel;
7940 precedence[TOKlg] = PREC_rel;
7941 precedence[TOKleg] = PREC_rel;
7942 precedence[TOKule] = PREC_rel;
7943 precedence[TOKul] = PREC_rel;
7944 precedence[TOKuge] = PREC_rel;
7945 precedence[TOKug] = PREC_rel;
7946 precedence[TOKue] = PREC_rel;
7947 precedence[TOKin] = PREC_rel;
7948
7949 /* Note that we changed precedence, so that < and != have the same
7950 * precedence. This change is in the parser, too.
7951 */
7952 precedence[TOKequal] = PREC_rel;
7953 precedence[TOKnotequal] = PREC_rel;
7954 precedence[TOKidentity] = PREC_rel;
7955 precedence[TOKnotidentity] = PREC_rel;
7956
7957 precedence[TOKand] = PREC_and;
7958
7959 precedence[TOKxor] = PREC_xor;
7960
7961 precedence[TOKor] = PREC_or;
7962
7963 precedence[TOKandand] = PREC_andand;
7964
7965 precedence[TOKoror] = PREC_oror;
7966
7967 precedence[TOKquestion] = PREC_cond;
7968
7969 precedence[TOKassign] = PREC_assign;
7970 precedence[TOKconstruct] = PREC_assign;
7971 precedence[TOKblit] = PREC_assign;
7972 precedence[TOKaddass] = PREC_assign;
7973 precedence[TOKminass] = PREC_assign;
7974 precedence[TOKcatass] = PREC_assign;
7975 precedence[TOKmulass] = PREC_assign;
7976 precedence[TOKdivass] = PREC_assign;
7977 precedence[TOKmodass] = PREC_assign;
7978 precedence[TOKpowass] = PREC_assign;
7979 precedence[TOKshlass] = PREC_assign;
7980 precedence[TOKshrass] = PREC_assign;
7981 precedence[TOKushrass] = PREC_assign;
7982 precedence[TOKandass] = PREC_assign;
7983 precedence[TOKorass] = PREC_assign;
7984 precedence[TOKxorass] = PREC_assign;
7985
7986 precedence[TOKcomma] = PREC_expr;
7987 precedence[TOKdeclaration] = PREC_expr;
7988
7989 precedence[TOKinterval] = PREC_assign;
7990}