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