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