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