]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/d/dmd/parse.c
fix GIMPLE parser for loops
[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;
b4c522fa
IB
1297 else if (id == Id::D)
1298 link = LINKd;
1299 else if (id == Id::C)
1300 {
1301 link = LINKc;
1302 if (token.value == TOKplusplus)
1303 {
1304 link = LINKcpp;
1305 nextToken();
1306 if (token.value == TOKcomma) // , namespaces or class or struct
1307 {
1308 nextToken();
1309 if (token.value == TOKclass || token.value == TOKstruct)
1310 {
1311 cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
1312 nextToken();
1313 }
9503d7b1
IB
1314 else if (token.value == TOKstring) // extern(C++, "namespace", "namespaces")
1315 {
1316 cppMangleOnly = true;
1317 idents = new Identifiers();
1318
1319 while (1)
1320 {
1321 StringExp *stringExp = (StringExp *)parsePrimaryExp();
1322 const char *name = stringExp->toPtr();
1323 if (stringExp->len == 0)
1324 {
1325 error("invalid zero length C++ namespace");
1326 idents = NULL;
1327 break;
1328 }
1329 else if (!Identifier::isValidIdentifier(name))
1330 {
1331 error("expected valid identifer for C++ namespace but got `%s`", name);
1332 idents = NULL;
1333 break;
1334 }
1335 idents->push(Identifier::idPool(name));
1336 if (token.value == TOKcomma)
1337 {
1338 nextToken();
1339 if (token.value != TOKstring)
1340 {
1341 error("string expected following `,` for C++ namespace, not `%s`", token.toChars());
1342 idents = NULL;
1343 break;
1344 }
1345 }
1346 else
1347 break;
1348 }
1349 }
b4c522fa
IB
1350 else
1351 {
1352 idents = new Identifiers();
1353 while (1)
1354 {
1355 if (token.value == TOKidentifier)
1356 {
1357 Identifier *idn = token.ident;
1358 idents->push(idn);
1359 nextToken();
1360 if (token.value == TOKdot)
1361 {
1362 nextToken();
1363 continue;
1364 }
1365 }
1366 else
1367 {
1368 error("identifier expected for C++ namespace");
1369 idents = NULL; // error occurred, invalidate list of elements.
1370 }
1371 break;
1372 }
1373 }
1374 }
1375 }
1376 }
1377 else if (id == Id::Objective) // Looking for tokens "Objective-C"
1378 {
1379 if (token.value == TOKmin)
1380 {
1381 nextToken();
1382 if (token.ident == Id::C)
1383 {
1384 link = LINKobjc;
1385 nextToken();
1386 }
1387 else
1388 goto LinvalidLinkage;
1389 }
1390 else
1391 goto LinvalidLinkage;
1392 }
1393 else if (id == Id::System)
1394 {
1395 link = LINKsystem;
1396 }
1397 else
1398 {
1399 LinvalidLinkage:
6b2f370f 1400 error("valid linkage identifiers are D, C, C++, Objective-C, Windows, System");
b4c522fa
IB
1401 link = LINKd;
1402 }
1403 }
1404 else
1405 {
1406 link = LINKd; // default
1407 }
1408 check(TOKrparen);
1409 *pidents = idents;
1410 *pcppmangle = cppmangle;
9503d7b1 1411 *pcppMangleOnly = cppMangleOnly;
b4c522fa
IB
1412 return link;
1413}
1414
1415/***********************************
1416 * Parse ident1.ident2.ident3
1417 *
1418 * Params:
1419 * entity = what qualified identifier is expected to resolve into.
1420 * Used only for better error message
1421 *
1422 * Returns:
1423 * array of identifiers with actual qualified one stored last
1424 */
1425Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
1426{
1427 Identifiers *qualified = NULL;
1428
1429 do
1430 {
1431 nextToken();
1432 if (token.value != TOKidentifier)
1433 {
1434 error("%s expected as dot-separated identifiers, got '%s'",
1435 entity, token.toChars());
1436 return NULL;
1437 }
1438
1439 Identifier *id = token.ident;
1440 if (!qualified)
1441 qualified = new Identifiers();
1442 qualified->push(id);
1443
1444 nextToken();
1445 } while (token.value == TOKdot);
1446
1447 return qualified;
1448}
1449
1450/**************************************
1451 * Parse a debug conditional
1452 */
1453
1454Condition *Parser::parseDebugCondition()
1455{
1456 Condition *c;
1457
1458 if (token.value == TOKlparen)
1459 {
1460 nextToken();
1461 unsigned level = 1;
1462 Identifier *id = NULL;
1463
1464 if (token.value == TOKidentifier)
1465 id = token.ident;
1466 else if (token.value == TOKint32v || token.value == TOKint64v)
1467 level = (unsigned)token.uns64value;
1468 else
1469 error("identifier or integer expected, not %s", token.toChars());
1470 nextToken();
1471 check(TOKrparen);
1472 c = new DebugCondition(mod, level, id);
1473 }
1474 else
1475 c = new DebugCondition(mod, 1, NULL);
1476 return c;
1477
1478}
1479
1480/**************************************
1481 * Parse a version conditional
1482 */
1483
1484Condition *Parser::parseVersionCondition()
1485{
1486 Condition *c;
1487 unsigned level = 1;
1488 Identifier *id = NULL;
1489
1490 if (token.value == TOKlparen)
1491 {
1492 nextToken();
1493 /* Allow:
1494 * version (unittest)
1495 * version (assert)
1496 * even though they are keywords
1497 */
1498 if (token.value == TOKidentifier)
1499 id = token.ident;
1500 else if (token.value == TOKint32v || token.value == TOKint64v)
1501 level = (unsigned)token.uns64value;
1502 else if (token.value == TOKunittest)
1503 id = Identifier::idPool(Token::toChars(TOKunittest));
1504 else if (token.value == TOKassert)
1505 id = Identifier::idPool(Token::toChars(TOKassert));
1506 else
1507 error("identifier or integer expected, not %s", token.toChars());
1508 nextToken();
1509 check(TOKrparen);
1510
1511 }
1512 else
1513 error("(condition) expected following version");
1514 c = new VersionCondition(mod, level, id);
1515 return c;
1516
1517}
1518
1519/***********************************************
1520 * static if (expression)
1521 * body
1522 * else
1523 * body
1524 * Current token is 'static'.
1525 */
1526
1527Condition *Parser::parseStaticIfCondition()
1528{
1529 Expression *exp;
1530 Condition *condition;
1531 Loc loc = token.loc;
1532
1533 nextToken();
1534 nextToken();
1535 if (token.value == TOKlparen)
1536 {
1537 nextToken();
1538 exp = parseAssignExp();
1539 check(TOKrparen);
1540 }
1541 else
1542 {
1543 error("(expression) expected following static if");
1544 exp = NULL;
1545 }
1546 condition = new StaticIfCondition(loc, exp);
1547 return condition;
1548}
1549
1550
1551/*****************************************
1552 * Parse a constructor definition:
1553 * this(parameters) { body }
1554 * or postblit:
1555 * this(this) { body }
1556 * or constructor template:
1557 * this(templateparameters)(parameters) { body }
1558 * Current token is 'this'.
1559 */
1560
1561Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
1562{
1563 Expressions *udas = NULL;
1564 Loc loc = token.loc;
1565 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1566
1567 nextToken();
1568 if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
1569 {
1570 // this(this) { ... }
1571 nextToken();
1572 nextToken();
1573 check(TOKrparen);
1574
1575 stc = parsePostfix(stc, &udas);
1576 if (stc & STCstatic)
1577 error(loc, "postblit cannot be static");
1578
1579 PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
1580 if (pAttrs)
1581 pAttrs->storageClass = STCundefined;
1582 Dsymbol *s = parseContracts(f);
1583 if (udas)
1584 {
1585 Dsymbols *a = new Dsymbols();
1586 a->push(f);
1587 s = new UserAttributeDeclaration(udas, a);
1588 }
1589 return s;
1590 }
1591
1592 /* Look ahead to see if:
1593 * this(...)(...)
1594 * which is a constructor template
1595 */
1596 TemplateParameters *tpl = NULL;
1597 if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
1598 {
1599 tpl = parseTemplateParameterList();
1600 }
1601
1602 /* Just a regular constructor
1603 */
c3a2ba10 1604 VarArg varargs;
b4c522fa
IB
1605 Parameters *parameters = parseParameters(&varargs);
1606 stc = parsePostfix(stc, &udas);
c3a2ba10 1607 if (varargs != VARARGnone || Parameter::dim(parameters) != 0)
b4c522fa
IB
1608 {
1609 if (stc & STCstatic)
1610 error(loc, "constructor cannot be static");
1611 }
1612 else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
1613 {
1614 if (ss == STCstatic)
1615 error(loc, "use 'static this()' to declare a static constructor");
1616 else if (ss == (STCshared | STCstatic))
1617 error(loc, "use 'shared static this()' to declare a shared static constructor");
1618 }
1619
1620 Expression *constraint = tpl ? parseConstraint() : NULL;
1621
c3a2ba10
IB
1622 Type *tf = new TypeFunction(ParameterList(parameters, varargs),
1623 NULL, linkage, stc); // ReturnType -> auto
b4c522fa
IB
1624 tf = tf->addSTC(stc);
1625
1626 CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
1627 if (pAttrs)
1628 pAttrs->storageClass = STCundefined;
1629 Dsymbol *s = parseContracts(f);
1630 if (udas)
1631 {
1632 Dsymbols *a = new Dsymbols();
1633 a->push(f);
1634 s = new UserAttributeDeclaration(udas, a);
1635 }
1636
1637 if (tpl)
1638 {
1639 // Wrap a template around it
1640 Dsymbols *decldefs = new Dsymbols();
1641 decldefs->push(s);
1642 s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
1643 }
1644
1645 return s;
1646}
1647
1648/*****************************************
1649 * Parse a destructor definition:
1650 * ~this() { body }
1651 * Current token is '~'.
1652 */
1653
1654Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
1655{
1656 Expressions *udas = NULL;
1657 Loc loc = token.loc;
1658 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1659
1660 nextToken();
1661 check(TOKthis);
1662 check(TOKlparen);
1663 check(TOKrparen);
1664
1665 stc = parsePostfix(stc, &udas);
1666 if (StorageClass ss = stc & (STCshared | STCstatic))
1667 {
1668 if (ss == STCstatic)
1669 error(loc, "use 'static ~this()' to declare a static destructor");
1670 else if (ss == (STCshared | STCstatic))
1671 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1672 }
1673
1674 DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
1675 if (pAttrs)
1676 pAttrs->storageClass = STCundefined;
1677 Dsymbol *s = parseContracts(f);
1678 if (udas)
1679 {
1680 Dsymbols *a = new Dsymbols();
1681 a->push(f);
1682 s = new UserAttributeDeclaration(udas, a);
1683 }
1684 return s;
1685}
1686
1687/*****************************************
1688 * Parse a static constructor definition:
1689 * static this() { body }
1690 * Current token is 'static'.
1691 */
1692
1693Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
1694{
1695 //Expressions *udas = NULL;
1696 Loc loc = token.loc;
1697 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1698
1699 nextToken();
1700 nextToken();
1701 check(TOKlparen);
1702 check(TOKrparen);
1703
1704 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1705 if (stc & STCshared)
1706 error(loc, "use 'shared static this()' to declare a shared static constructor");
1707 else if (stc & STCstatic)
1708 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1709 else if (StorageClass modStc = stc & STC_TYPECTOR)
1710 {
1711 OutBuffer buf;
1712 stcToBuffer(&buf, modStc);
fced594b 1713 error(loc, "static constructor cannot be %s", buf.peekChars());
b4c522fa
IB
1714 }
1715 stc &= ~(STCstatic | STC_TYPECTOR);
1716
1717 StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
1718 if (pAttrs)
1719 pAttrs->storageClass = STCundefined;
1720 Dsymbol *s = parseContracts(f);
1721 return s;
1722}
1723
1724/*****************************************
1725 * Parse a static destructor definition:
1726 * static ~this() { body }
1727 * Current token is 'static'.
1728 */
1729
1730Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
1731{
1732 Expressions *udas = NULL;
1733 Loc loc = token.loc;
1734 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1735
1736 nextToken();
1737 nextToken();
1738 check(TOKthis);
1739 check(TOKlparen);
1740 check(TOKrparen);
1741
1742 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1743 if (stc & STCshared)
1744 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1745 else if (stc & STCstatic)
1746 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1747 else if (StorageClass modStc = stc & STC_TYPECTOR)
1748 {
1749 OutBuffer buf;
1750 stcToBuffer(&buf, modStc);
fced594b 1751 error(loc, "static destructor cannot be %s", buf.peekChars());
b4c522fa
IB
1752 }
1753 stc &= ~(STCstatic | STC_TYPECTOR);
1754
1755 StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
1756 if (pAttrs)
1757 pAttrs->storageClass = STCundefined;
1758 Dsymbol *s = parseContracts(f);
1759 if (udas)
1760 {
1761 Dsymbols *a = new Dsymbols();
1762 a->push(f);
1763 s = new UserAttributeDeclaration(udas, a);
1764 }
1765 return s;
1766}
1767
1768/*****************************************
1769 * Parse a shared static constructor definition:
1770 * shared static this() { body }
1771 * Current token is 'shared'.
1772 */
1773
1774Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
1775{
1776 //Expressions *udas = NULL;
1777 Loc loc = token.loc;
1778 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1779
1780 nextToken();
1781 nextToken();
1782 nextToken();
1783 check(TOKlparen);
1784 check(TOKrparen);
1785
1786 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1787 if (StorageClass ss = stc & (STCshared | STCstatic))
1788 appendStorageClass(stc, ss); // complaint for the redundancy
1789 else if (StorageClass modStc = stc & STC_TYPECTOR)
1790 {
1791 OutBuffer buf;
1792 stcToBuffer(&buf, modStc);
fced594b 1793 error(loc, "shared static constructor cannot be %s", buf.peekChars());
b4c522fa
IB
1794 }
1795 stc &= ~(STCstatic | STC_TYPECTOR);
1796
1797 SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
1798 if (pAttrs)
1799 pAttrs->storageClass = STCundefined;
1800 Dsymbol *s = parseContracts(f);
1801 return s;
1802}
1803
1804/*****************************************
1805 * Parse a shared static destructor definition:
1806 * shared static ~this() { body }
1807 * Current token is 'shared'.
1808 */
1809
1810Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
1811{
1812 Expressions *udas = NULL;
1813 Loc loc = token.loc;
1814 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1815
1816 nextToken();
1817 nextToken();
1818 nextToken();
1819 check(TOKthis);
1820 check(TOKlparen);
1821 check(TOKrparen);
1822
1823 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1824 if (StorageClass ss = stc & (STCshared | STCstatic))
1825 appendStorageClass(stc, ss); // complaint for the redundancy
1826 else if (StorageClass modStc = stc & STC_TYPECTOR)
1827 {
1828 OutBuffer buf;
1829 stcToBuffer(&buf, modStc);
fced594b 1830 error(loc, "shared static destructor cannot be %s", buf.peekChars());
b4c522fa
IB
1831 }
1832 stc &= ~(STCstatic | STC_TYPECTOR);
1833
1834 SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
1835 if (pAttrs)
1836 pAttrs->storageClass = STCundefined;
1837 Dsymbol *s = parseContracts(f);
1838 if (udas)
1839 {
1840 Dsymbols *a = new Dsymbols();
1841 a->push(f);
1842 s = new UserAttributeDeclaration(udas, a);
1843 }
1844 return s;
1845}
1846
1847/*****************************************
1848 * Parse an invariant definition:
1849 * invariant() { body }
1850 * Current token is 'invariant'.
1851 */
1852
1853Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
1854{
1855 Loc loc = token.loc;
1856 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1857
1858 nextToken();
1859 if (token.value == TOKlparen) // optional ()
1860 {
1861 nextToken();
1862 check(TOKrparen);
1863 }
1864
1865 InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
1866 if (pAttrs)
1867 pAttrs->storageClass = STCundefined;
1868 f->fbody = parseStatement(PScurly);
1869 return f;
1870}
1871
1872/*****************************************
1873 * Parse a unittest definition:
1874 * unittest { body }
1875 * Current token is 'unittest'.
1876 */
1877
1878Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
1879{
1880 Loc loc = token.loc;
1881 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1882
1883 nextToken();
1884
1885 const utf8_t *begPtr = token.ptr + 1; // skip '{'
1886 const utf8_t *endPtr = NULL;
1887 Statement *sbody = parseStatement(PScurly, &endPtr);
1888
1889 /** Extract unittest body as a string. Must be done eagerly since memory
1890 will be released by the lexer before doc gen. */
1891 char *docline = NULL;
1892 if (global.params.doDocComments && endPtr > begPtr)
1893 {
1894 /* Remove trailing whitespaces */
1895 for (const utf8_t *p = endPtr - 1;
1896 begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
1897 {
1898 endPtr = p;
1899 }
1900
1901 size_t len = endPtr - begPtr;
1902 if (len > 0)
1903 {
1904 docline = (char *)mem.xmalloc(len + 2);
1905 memcpy(docline, begPtr, len);
1906 docline[len ] = '\n'; // Terminate all lines by LF
1907 docline[len+1] = '\0';
1908 }
1909 }
1910
1911 UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
1912 if (pAttrs)
1913 pAttrs->storageClass = STCundefined;
1914 f->fbody = sbody;
1915 return f;
1916}
1917
1918/*****************************************
1919 * Parse a new definition:
1920 * new(parameters) { body }
1921 * Current token is 'new'.
1922 */
1923
1924Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
1925{
1926 Loc loc = token.loc;
1927 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1928
1929 nextToken();
1930
c3a2ba10 1931 VarArg varargs;
b4c522fa
IB
1932 Parameters *parameters = parseParameters(&varargs);
1933 NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
1934 if (pAttrs)
1935 pAttrs->storageClass = STCundefined;
1936 Dsymbol *s = parseContracts(f);
1937 return s;
1938}
1939
1940/*****************************************
1941 * Parse a delete definition:
1942 * delete(parameters) { body }
1943 * Current token is 'delete'.
1944 */
1945
1946Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
1947{
1948 Loc loc = token.loc;
1949 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1950
1951 nextToken();
1952
c3a2ba10 1953 VarArg varargs;
b4c522fa 1954 Parameters *parameters = parseParameters(&varargs);
c3a2ba10 1955 if (varargs != VARARGnone)
b4c522fa
IB
1956 error("... not allowed in delete function parameter list");
1957 DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
1958 if (pAttrs)
1959 pAttrs->storageClass = STCundefined;
1960 Dsymbol *s = parseContracts(f);
1961 return s;
1962}
1963
1964/**********************************************
1965 * Parse parameter list.
1966 */
1967
c3a2ba10 1968Parameters *Parser::parseParameters(VarArg *pvarargs, TemplateParameters **tpl)
b4c522fa
IB
1969{
1970 Parameters *parameters = new Parameters();
c3a2ba10 1971 VarArg varargs = VARARGnone;
b4c522fa
IB
1972 int hasdefault = 0;
1973
1974 check(TOKlparen);
1975 while (1)
1976 {
1977 Identifier *ai = NULL;
1978 Type *at;
1979 StorageClass storageClass = 0;
1980 StorageClass stc;
1981 Expression *ae;
1982
1983 for (;1; nextToken())
1984 {
1985 switch (token.value)
1986 {
1987 case TOKrparen:
1988 break;
1989
1990 case TOKdotdotdot:
c3a2ba10 1991 varargs = VARARGvariadic;
b4c522fa
IB
1992 nextToken();
1993 break;
1994
1995 case TOKconst:
1996 if (peek(&token)->value == TOKlparen)
1997 goto Ldefault;
1998 stc = STCconst;
1999 goto L2;
2000
2001 case TOKimmutable:
2002 if (peek(&token)->value == TOKlparen)
2003 goto Ldefault;
2004 stc = STCimmutable;
2005 goto L2;
2006
2007 case TOKshared:
2008 if (peek(&token)->value == TOKlparen)
2009 goto Ldefault;
2010 stc = STCshared;
2011 goto L2;
2012
2013 case TOKwild:
2014 if (peek(&token)->value == TOKlparen)
2015 goto Ldefault;
2016 stc = STCwild;
2017 goto L2;
2018
2019 case TOKin: stc = STCin; goto L2;
2020 case TOKout: stc = STCout; goto L2;
2021 case TOKref: stc = STCref; goto L2;
2022 case TOKlazy: stc = STClazy; goto L2;
2023 case TOKscope: stc = STCscope; goto L2;
2024 case TOKfinal: stc = STCfinal; goto L2;
2025 case TOKauto: stc = STCauto; goto L2;
2026 case TOKreturn: stc = STCreturn; goto L2;
2027 L2:
2028 storageClass = appendStorageClass(storageClass, stc);
2029 continue;
2030
2031 default:
2032 Ldefault:
2033 { stc = storageClass & (STCin | STCout | STCref | STClazy);
2034 // if stc is not a power of 2
2035 if (stc & (stc - 1) &&
2036 !(stc == (STCin | STCref)))
2037 error("incompatible parameter storage classes");
2038 //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
2039 //error("scope cannot be ref or out");
2040
2041 Token *t;
2042 if (tpl && token.value == TOKidentifier &&
2043 (t = peek(&token), (t->value == TOKcomma ||
2044 t->value == TOKrparen ||
2045 t->value == TOKdotdotdot)))
2046 {
2047 Identifier *id = Identifier::generateId("__T");
2048 Loc loc = token.loc;
2049 at = new TypeIdentifier(loc, id);
2050 if (!*tpl)
2051 *tpl = new TemplateParameters();
2052 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
2053 (*tpl)->push(tp);
2054
2055 ai = token.ident;
2056 nextToken();
2057 }
2058 else
2059 at = parseType(&ai);
2060 ae = NULL;
2061 if (token.value == TOKassign) // = defaultArg
2062 { nextToken();
2063 ae = parseDefaultInitExp();
2064 hasdefault = 1;
2065 }
2066 else
2067 { if (hasdefault)
2068 error("default argument expected for %s",
2069 ai ? ai->toChars() : at->toChars());
2070 }
2071 if (token.value == TOKdotdotdot)
2072 { /* This is:
2073 * at ai ...
2074 */
2075
2076 if (storageClass & (STCout | STCref))
2077 error("variadic argument cannot be out or ref");
c3a2ba10 2078 varargs = VARARGtypesafe;
b4c522fa
IB
2079 parameters->push(new Parameter(storageClass, at, ai, ae));
2080 nextToken();
2081 break;
2082 }
2083 parameters->push(new Parameter(storageClass, at, ai, ae));
2084 if (token.value == TOKcomma)
2085 { nextToken();
2086 goto L1;
2087 }
2088 break;
2089 }
2090 }
2091 break;
2092 }
2093 break;
2094
2095 L1: ;
2096 }
2097 check(TOKrparen);
2098 *pvarargs = varargs;
2099 return parameters;
2100}
2101
2102
2103/*************************************
2104 */
2105
2106EnumDeclaration *Parser::parseEnum()
2107{
2108 EnumDeclaration *e;
2109 Identifier *id;
2110 Type *memtype;
2111 Loc loc = token.loc;
2112
2113 //printf("Parser::parseEnum()\n");
2114 nextToken();
2115 if (token.value == TOKidentifier)
2116 {
2117 id = token.ident;
2118 nextToken();
2119 }
2120 else
2121 id = NULL;
2122
2123 if (token.value == TOKcolon)
2124 {
2125 nextToken();
2126
2127 int alt = 0;
2128 Loc typeLoc = token.loc;
2129 memtype = parseBasicType();
2130 memtype = parseDeclarator(memtype, &alt, NULL);
2131 checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
2132 }
2133 else
2134 memtype = NULL;
2135
2136 e = new EnumDeclaration(loc, id, memtype);
2137 if (token.value == TOKsemicolon && id)
2138 nextToken();
2139 else if (token.value == TOKlcurly)
2140 {
2141 //printf("enum definition\n");
2142 e->members = new Dsymbols();
2143 nextToken();
2144 const utf8_t *comment = token.blockComment;
2145 while (token.value != TOKrcurly)
2146 {
2147 /* Can take the following forms:
2148 * 1. ident
2149 * 2. ident = value
2150 * 3. type ident = value
2151 */
2152
2153 loc = token.loc;
2154
2155 Type *type = NULL;
2156 Identifier *ident = NULL;
2157 Token *tp = peek(&token);
2158 if (token.value == TOKidentifier &&
2159 (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
2160 {
2161 ident = token.ident;
2162 type = NULL;
2163 nextToken();
2164 }
2165 else
2166 {
2167 type = parseType(&ident, NULL);
2168 if (!ident)
2169 error("no identifier for declarator %s", type->toChars());
2170 if (id || memtype)
2171 error("type only allowed if anonymous enum and no enum type");
2172 }
2173
2174 Expression *value;
2175 if (token.value == TOKassign)
2176 {
2177 nextToken();
2178 value = parseAssignExp();
2179 }
2180 else
2181 {
2182 value = NULL;
2183 if (type)
2184 error("if type, there must be an initializer");
2185 }
2186
2187 EnumMember *em = new EnumMember(loc, ident, value, type);
2188 e->members->push(em);
2189
2190 if (token.value == TOKrcurly)
2191 ;
2192 else
2193 {
2194 addComment(em, comment);
2195 comment = NULL;
2196 check(TOKcomma);
2197 }
2198 addComment(em, comment);
2199 comment = token.blockComment;
2200
2201 if (token.value == TOKeof)
2202 {
2203 error("premature end of file");
2204 break;
2205 }
2206 }
2207 nextToken();
2208 }
2209 else
2210 error("enum declaration is invalid");
2211
2212 //printf("-parseEnum() %s\n", e->toChars());
2213 return e;
2214}
2215
2216/********************************
2217 * Parse struct, union, interface, class.
2218 */
2219
2220Dsymbol *Parser::parseAggregate()
2221{
2222 AggregateDeclaration *a = NULL;
2223 int anon = 0;
2224 Identifier *id;
2225 TemplateParameters *tpl = NULL;
2226 Expression *constraint = NULL;
2227 Loc loc = token.loc;
2228 TOK tok = token.value;
2229
2230 //printf("Parser::parseAggregate()\n");
2231 nextToken();
2232 if (token.value != TOKidentifier)
2233 {
2234 id = NULL;
2235 }
2236 else
2237 {
2238 id = token.ident;
2239 nextToken();
2240
2241 if (token.value == TOKlparen)
2242 {
2243 // Class template declaration.
2244 // Gather template parameter list
2245 tpl = parseTemplateParameterList();
2246 constraint = parseConstraint();
2247 }
2248 }
2249
2250 switch (tok)
2251 {
2252 case TOKclass:
2253 case TOKinterface:
2254 {
2255 if (!id)
2256 error(loc, "anonymous classes not allowed");
2257
2258 // Collect base class(es)
2259 BaseClasses *baseclasses = NULL;
2260 if (token.value == TOKcolon)
2261 {
2262 nextToken();
2263 baseclasses = parseBaseClasses();
2264
2265 if (tpl)
2266 {
2267 Expression *tempCons = parseConstraint();
2268 if (tempCons)
2269 {
2270 if (constraint)
2271 error("members expected");
2272 else
2273 constraint = tempCons;
2274 }
2275 }
2276
2277 if (token.value != TOKlcurly)
2278 error("members expected");
2279 }
2280
2281 if (tok == TOKclass)
2282 {
2283 bool inObject = md && !md->packages && md->id == Id::object;
2284 a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
2285 }
2286 else
2287 a = new InterfaceDeclaration(loc, id, baseclasses);
2288 break;
2289 }
2290
2291 case TOKstruct:
2292 if (id)
2293 {
2294 bool inObject = md && !md->packages && md->id == Id::object;
2295 a = new StructDeclaration(loc, id, inObject);
2296 }
2297 else
2298 anon = 1;
2299 break;
2300
2301 case TOKunion:
2302 if (id)
2303 a = new UnionDeclaration(loc, id);
2304 else
2305 anon = 2;
2306 break;
2307
2308 default:
2309 assert(0);
2310 break;
2311 }
2312 if (a && token.value == TOKsemicolon)
2313 {
2314 nextToken();
2315 }
2316 else if (token.value == TOKlcurly)
2317 {
2318 const Loc lookingForElseSave = lookingForElse;
2319 lookingForElse = Loc();
2320 //printf("aggregate definition\n");
2321 nextToken();
2322 Dsymbols *decl = parseDeclDefs(0);
2323 lookingForElse = lookingForElseSave;
2324 if (token.value != TOKrcurly)
2325 error("} expected following members in %s declaration at %s",
2326 Token::toChars(tok), loc.toChars());
2327 nextToken();
2328 if (anon)
2329 {
2330 /* Anonymous structs/unions are more like attributes.
2331 */
2332 return new AnonDeclaration(loc, anon == 2, decl);
2333 }
2334 else
2335 a->members = decl;
2336 }
2337 else
2338 {
2339 error("{ } expected following %s declaration", Token::toChars(tok));
2340 a = new StructDeclaration(loc, NULL, false);
2341 }
2342
2343 if (tpl)
2344 {
2345 // Wrap a template around the aggregate declaration
2346 Dsymbols *decldefs = new Dsymbols();
2347 decldefs->push(a);
2348 TemplateDeclaration *tempdecl =
2349 new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
2350 return tempdecl;
2351 }
2352
2353 return a;
2354}
2355
2356/*******************************************
2357 */
2358
2359BaseClasses *Parser::parseBaseClasses()
2360{
2361 BaseClasses *baseclasses = new BaseClasses();
2362
2363 for (; 1; nextToken())
2364 {
2365 bool prot = false;
0a2ee409 2366 Prot protection = Prot(Prot::public_);
b4c522fa
IB
2367 switch (token.value)
2368 {
2369 case TOKprivate:
2370 prot = true;
0a2ee409 2371 protection = Prot(Prot::private_);
b4c522fa
IB
2372 nextToken();
2373 break;
2374 case TOKpackage:
2375 prot = true;
0a2ee409 2376 protection = Prot(Prot::package_);
b4c522fa
IB
2377 nextToken();
2378 break;
2379 case TOKprotected:
2380 prot = true;
0a2ee409 2381 protection = Prot(Prot::protected_);
b4c522fa
IB
2382 nextToken();
2383 break;
2384 case TOKpublic:
2385 prot = true;
0a2ee409 2386 protection = Prot(Prot::public_);
b4c522fa
IB
2387 nextToken();
2388 break;
2389 default: break;
2390 }
2391 if (prot)
2392 error("use of base class protection is no longer supported");
2393 BaseClass *b = new BaseClass(parseBasicType());
2394 baseclasses->push(b);
2395 if (token.value != TOKcomma)
2396 break;
2397 }
2398 return baseclasses;
2399}
2400
2401/**************************************
2402 * Parse constraint.
2403 * Constraint is of the form:
2404 * if ( ConstraintExpression )
2405 */
2406
2407Expression *Parser::parseConstraint()
2408{ Expression *e = NULL;
2409
2410 if (token.value == TOKif)
2411 {
2412 nextToken(); // skip over 'if'
2413 check(TOKlparen);
2414 e = parseExpression();
2415 check(TOKrparen);
2416 }
2417 return e;
2418}
2419
2420/**************************************
2421 * Parse a TemplateDeclaration.
2422 */
2423
2424TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
2425{
2426 TemplateDeclaration *tempdecl;
2427 Identifier *id;
2428 TemplateParameters *tpl;
2429 Dsymbols *decldefs;
2430 Expression *constraint = NULL;
2431 Loc loc = token.loc;
2432
2433 nextToken();
2434 if (token.value != TOKidentifier)
2435 {
2436 error("identifier expected following template");
2437 goto Lerr;
2438 }
2439 id = token.ident;
2440 nextToken();
2441 tpl = parseTemplateParameterList();
2442 if (!tpl)
2443 goto Lerr;
2444
2445 constraint = parseConstraint();
2446
2447 if (token.value != TOKlcurly)
2448 {
2449 error("members of template declaration expected");
2450 goto Lerr;
2451 }
2452 else
2453 decldefs = parseBlock(NULL);
2454
2455 tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
2456 return tempdecl;
2457
2458Lerr:
2459 return NULL;
2460}
2461
2462/******************************************
2463 * Parse template parameter list.
2464 * Input:
2465 * flag 0: parsing "( list )"
2466 * 1: parsing non-empty "list )"
2467 */
2468
2469TemplateParameters *Parser::parseTemplateParameterList(int flag)
2470{
2471 TemplateParameters *tpl = new TemplateParameters();
2472
2473 if (!flag && token.value != TOKlparen)
2474 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
2475 goto Lerr;
2476 }
2477 nextToken();
2478
2479 // Get array of TemplateParameters
2480 if (flag || token.value != TOKrparen)
2481 {
2482 int isvariadic = 0;
2483 while (token.value != TOKrparen)
2484 {
2485 TemplateParameter *tp;
2486 Loc loc;
2487 Identifier *tp_ident = NULL;
2488 Type *tp_spectype = NULL;
2489 Type *tp_valtype = NULL;
2490 Type *tp_defaulttype = NULL;
2491 Expression *tp_specvalue = NULL;
2492 Expression *tp_defaultvalue = NULL;
2493 Token *t;
2494
2495 // Get TemplateParameter
2496
2497 // First, look ahead to see if it is a TypeParameter or a ValueParameter
2498 t = peek(&token);
2499 if (token.value == TOKalias)
2500 { // AliasParameter
2501 nextToken();
2502 loc = token.loc; // todo
2503 Type *spectype = NULL;
2504 if (isDeclaration(&token, 2, TOKreserved, NULL))
2505 {
2506 spectype = parseType(&tp_ident);
2507 }
2508 else
2509 {
2510 if (token.value != TOKidentifier)
2511 {
2512 error("identifier expected for template alias parameter");
2513 goto Lerr;
2514 }
2515 tp_ident = token.ident;
2516 nextToken();
2517 }
2518 RootObject *spec = NULL;
2519 if (token.value == TOKcolon) // : Type
2520 {
2521 nextToken();
2522 if (isDeclaration(&token, 0, TOKreserved, NULL))
2523 spec = parseType();
2524 else
2525 spec = parseCondExp();
2526 }
2527 RootObject *def = NULL;
2528 if (token.value == TOKassign) // = Type
2529 {
2530 nextToken();
2531 if (isDeclaration(&token, 0, TOKreserved, NULL))
2532 def = parseType();
2533 else
2534 def = parseCondExp();
2535 }
2536 tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
2537 }
2538 else if (t->value == TOKcolon || t->value == TOKassign ||
2539 t->value == TOKcomma || t->value == TOKrparen)
2540 {
2541 // TypeParameter
2542 if (token.value != TOKidentifier)
2543 {
2544 error("identifier expected for template type parameter");
2545 goto Lerr;
2546 }
2547 loc = token.loc;
2548 tp_ident = token.ident;
2549 nextToken();
2550 if (token.value == TOKcolon) // : Type
2551 {
2552 nextToken();
2553 tp_spectype = parseType();
2554 }
2555 if (token.value == TOKassign) // = Type
2556 {
2557 nextToken();
2558 tp_defaulttype = parseType();
2559 }
2560 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2561 }
2562 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
2563 {
2564 // ident...
2565 if (isvariadic)
2566 error("variadic template parameter must be last");
2567 isvariadic = 1;
2568 loc = token.loc;
2569 tp_ident = token.ident;
2570 nextToken();
2571 nextToken();
2572 tp = new TemplateTupleParameter(loc, tp_ident);
2573 }
2574 else if (token.value == TOKthis)
2575 {
2576 // ThisParameter
2577 nextToken();
2578 if (token.value != TOKidentifier)
2579 {
2580 error("identifier expected for template this parameter");
2581 goto Lerr;
2582 }
2583 loc = token.loc;
2584 tp_ident = token.ident;
2585 nextToken();
2586 if (token.value == TOKcolon) // : Type
2587 {
2588 nextToken();
2589 tp_spectype = parseType();
2590 }
2591 if (token.value == TOKassign) // = Type
2592 {
2593 nextToken();
2594 tp_defaulttype = parseType();
2595 }
2596 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2597 }
2598 else
2599 {
2600 // ValueParameter
2601 loc = token.loc; // todo
2602 tp_valtype = parseType(&tp_ident);
2603 if (!tp_ident)
2604 {
2605 error("identifier expected for template value parameter");
2606 tp_ident = Identifier::idPool("error");
2607 }
2608 if (token.value == TOKcolon) // : CondExpression
2609 {
2610 nextToken();
2611 tp_specvalue = parseCondExp();
2612 }
2613 if (token.value == TOKassign) // = CondExpression
2614 {
2615 nextToken();
2616 tp_defaultvalue = parseDefaultInitExp();
2617 }
2618 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
2619 }
2620 tpl->push(tp);
2621 if (token.value != TOKcomma)
2622 break;
2623 nextToken();
2624 }
2625 }
2626 check(TOKrparen);
2627Lerr:
2628 return tpl;
2629}
2630
2631/******************************************
2632 * Parse template mixin.
2633 * mixin Foo;
2634 * mixin Foo!(args);
2635 * mixin a.b.c!(args).Foo!(args);
2636 * mixin Foo!(args) identifier;
2637 * mixin typeof(expr).identifier!(args);
2638 */
2639
2640Dsymbol *Parser::parseMixin()
2641{
2642 TemplateMixin *tm;
2643 Identifier *id;
2644 Objects *tiargs;
2645
2646 //printf("parseMixin()\n");
2647 Loc locMixin = token.loc;
2648 nextToken(); // skip 'mixin'
2649
2650 Loc loc = token.loc;
2651 TypeQualified *tqual = NULL;
2652 if (token.value == TOKdot)
2653 {
2654 id = Id::empty;
2655 }
2656 else
2657 {
2658 if (token.value == TOKtypeof)
2659 {
2660 tqual = parseTypeof();
2661 check(TOKdot);
2662 }
2663 if (token.value != TOKidentifier)
2664 {
2665 error("identifier expected, not %s", token.toChars());
2666 id = Id::empty;
2667 }
2668 else
2669 id = token.ident;
2670 nextToken();
2671 }
2672
2673 while (1)
2674 {
2675 tiargs = NULL;
2676 if (token.value == TOKnot)
2677 {
2678 tiargs = parseTemplateArguments();
2679 }
2680
2681 if (tiargs && token.value == TOKdot)
2682 {
2683 TemplateInstance *tempinst = new TemplateInstance(loc, id);
2684 tempinst->tiargs = tiargs;
2685 if (!tqual)
2686 tqual = new TypeInstance(loc, tempinst);
2687 else
2688 tqual->addInst(tempinst);
2689 tiargs = NULL;
2690 }
2691 else
2692 {
2693 if (!tqual)
2694 tqual = new TypeIdentifier(loc, id);
2695 else
2696 tqual->addIdent(id);
2697 }
2698
2699 if (token.value != TOKdot)
2700 break;
2701
2702 nextToken();
2703 if (token.value != TOKidentifier)
2704 {
2705 error("identifier expected following '.' instead of '%s'", token.toChars());
2706 break;
2707 }
2708 loc = token.loc;
2709 id = token.ident;
2710 nextToken();
2711 }
2712
2713 if (token.value == TOKidentifier)
2714 {
2715 id = token.ident;
2716 nextToken();
2717 }
2718 else
2719 id = NULL;
2720
2721 tm = new TemplateMixin(locMixin, id, tqual, tiargs);
2722 if (token.value != TOKsemicolon)
2723 error("';' expected after mixin");
2724 nextToken();
2725
2726 return tm;
2727}
2728
2729/******************************************
2730 * Parse template arguments.
2731 * Input:
2732 * current token is opening '!'
2733 * Output:
2734 * current token is one after closing ')'
2735 */
2736
2737Objects *Parser::parseTemplateArguments()
2738{
2739 Objects *tiargs;
2740
2741 nextToken();
2742 if (token.value == TOKlparen)
2743 {
2744 // ident!(template_arguments)
2745 tiargs = parseTemplateArgumentList();
2746 }
2747 else
2748 {
2749 // ident!template_argument
2750 tiargs = parseTemplateSingleArgument();
2751 }
2752 if (token.value == TOKnot)
2753 {
2754 TOK tok = peekNext();
2755 if (tok != TOKis && tok != TOKin)
2756 {
2757 error("multiple ! arguments are not allowed");
2758 Lagain:
2759 nextToken();
2760 if (token.value == TOKlparen)
2761 parseTemplateArgumentList();
2762 else
2763 parseTemplateSingleArgument();
2764 if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
2765 goto Lagain;
2766 }
2767 }
2768 return tiargs;
2769}
2770
2771/******************************************
2772 * Parse template argument list.
2773 * Input:
2774 * current token is opening '(',
2775 * or ',' for __traits
2776 * Output:
2777 * current token is one after closing ')'
2778 */
2779
2780Objects *Parser::parseTemplateArgumentList()
2781{
2782 //printf("Parser::parseTemplateArgumentList()\n");
2783 Objects *tiargs = new Objects();
2784 TOK endtok = TOKrparen;
2785 assert(token.value == TOKlparen || token.value == TOKcomma);
2786 nextToken();
2787
2788 // Get TemplateArgumentList
2789 while (token.value != endtok)
2790 {
2791 // See if it is an Expression or a Type
2792 if (isDeclaration(&token, 0, TOKreserved, NULL))
2793 { // Template argument is a type
2794 Type *ta = parseType();
2795 tiargs->push(ta);
2796 }
2797 else
2798 { // Template argument is an expression
2799 Expression *ea = parseAssignExp();
2800 tiargs->push(ea);
2801 }
2802 if (token.value != TOKcomma)
2803 break;
2804 nextToken();
2805 }
2806 check(endtok, "template argument list");
2807 return tiargs;
2808}
2809
2810/*****************************
2811 * Parse single template argument, to support the syntax:
2812 * foo!arg
2813 * Input:
2814 * current token is the arg
2815 */
2816
2817Objects *Parser::parseTemplateSingleArgument()
2818{
2819 //printf("parseTemplateSingleArgument()\n");
2820 Objects *tiargs = new Objects();
2821 Type *ta;
2822 switch (token.value)
2823 {
2824 case TOKidentifier:
2825 ta = new TypeIdentifier(token.loc, token.ident);
2826 goto LabelX;
2827
2828 case TOKvector:
2829 ta = parseVector();
2830 goto LabelX;
2831
2832 case TOKvoid: ta = Type::tvoid; goto LabelX;
2833 case TOKint8: ta = Type::tint8; goto LabelX;
2834 case TOKuns8: ta = Type::tuns8; goto LabelX;
2835 case TOKint16: ta = Type::tint16; goto LabelX;
2836 case TOKuns16: ta = Type::tuns16; goto LabelX;
2837 case TOKint32: ta = Type::tint32; goto LabelX;
2838 case TOKuns32: ta = Type::tuns32; goto LabelX;
2839 case TOKint64: ta = Type::tint64; goto LabelX;
2840 case TOKuns64: ta = Type::tuns64; goto LabelX;
2841 case TOKint128: ta = Type::tint128; goto LabelX;
2842 case TOKuns128: ta = Type::tuns128; goto LabelX;
2843 case TOKfloat32: ta = Type::tfloat32; goto LabelX;
2844 case TOKfloat64: ta = Type::tfloat64; goto LabelX;
2845 case TOKfloat80: ta = Type::tfloat80; goto LabelX;
2846 case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
2847 case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
2848 case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
2849 case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
2850 case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
2851 case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
2852 case TOKbool: ta = Type::tbool; goto LabelX;
2853 case TOKchar: ta = Type::tchar; goto LabelX;
2854 case TOKwchar: ta = Type::twchar; goto LabelX;
2855 case TOKdchar: ta = Type::tdchar; goto LabelX;
2856 LabelX:
2857 tiargs->push(ta);
2858 nextToken();
2859 break;
2860
2861 case TOKint32v:
2862 case TOKuns32v:
2863 case TOKint64v:
2864 case TOKuns64v:
2865 case TOKint128v:
2866 case TOKuns128v:
2867 case TOKfloat32v:
2868 case TOKfloat64v:
2869 case TOKfloat80v:
2870 case TOKimaginary32v:
2871 case TOKimaginary64v:
2872 case TOKimaginary80v:
2873 case TOKnull:
2874 case TOKtrue:
2875 case TOKfalse:
2876 case TOKcharv:
2877 case TOKwcharv:
2878 case TOKdcharv:
2879 case TOKstring:
2880 case TOKxstring:
2881 case TOKfile:
2882 case TOKfilefullpath:
2883 case TOKline:
2884 case TOKmodulestring:
2885 case TOKfuncstring:
2886 case TOKprettyfunc:
2887 case TOKthis:
2888 { // Template argument is an expression
2889 Expression *ea = parsePrimaryExp();
2890 tiargs->push(ea);
2891 break;
2892 }
2893
2894 default:
2895 error("template argument expected following !");
2896 break;
2897 }
2898 return tiargs;
2899}
2900
2901Dsymbols *Parser::parseImport()
2902{
2903 Dsymbols *decldefs = new Dsymbols();
2904 Identifier *aliasid = NULL;
2905
2906 int isstatic = token.value == TOKstatic;
2907 if (isstatic)
2908 nextToken();
2909
2910 //printf("Parser::parseImport()\n");
2911 do
2912 {
2913 L1:
2914 nextToken();
2915 if (token.value != TOKidentifier)
2916 {
2917 error("identifier expected following import");
2918 break;
2919 }
2920
2921 Loc loc = token.loc;
2922 Identifier *id = token.ident;
2923 Identifiers *a = NULL;
2924 nextToken();
2925 if (!aliasid && token.value == TOKassign)
2926 {
2927 aliasid = id;
2928 goto L1;
2929 }
2930 while (token.value == TOKdot)
2931 {
2932 if (!a)
2933 a = new Identifiers();
2934 a->push(id);
2935 nextToken();
2936 if (token.value != TOKidentifier)
2937 {
2938 error("identifier expected following package");
2939 break;
2940 }
2941 id = token.ident;
2942 nextToken();
2943 }
2944
2945 Import *s = new Import(loc, a, id, aliasid, isstatic);
2946 decldefs->push(s);
2947
2948 /* Look for
2949 * : alias=name, alias=name;
2950 * syntax.
2951 */
2952 if (token.value == TOKcolon)
2953 {
2954 do
2955 {
2956 nextToken();
2957 if (token.value != TOKidentifier)
2958 {
2959 error("identifier expected following :");
2960 break;
2961 }
2962 Identifier *alias = token.ident;
2963 Identifier *name;
2964 nextToken();
2965 if (token.value == TOKassign)
2966 {
2967 nextToken();
2968 if (token.value != TOKidentifier)
2969 {
2970 error("identifier expected following %s=", alias->toChars());
2971 break;
2972 }
2973 name = token.ident;
2974 nextToken();
2975 }
2976 else
2977 {
2978 name = alias;
2979 alias = NULL;
2980 }
2981 s->addAlias(name, alias);
2982 } while (token.value == TOKcomma);
2983 break; // no comma-separated imports of this form
2984 }
2985
2986 aliasid = NULL;
2987 } while (token.value == TOKcomma);
2988
2989 if (token.value == TOKsemicolon)
2990 nextToken();
2991 else
2992 {
2993 error("';' expected");
2994 nextToken();
2995 }
2996
2997 return decldefs;
2998}
2999
3000Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
3001{
3002 /* Take care of the storage class prefixes that
3003 * serve as type attributes:
3004 * const type
3005 * immutable type
3006 * shared type
3007 * inout type
3008 * inout const type
3009 * shared const type
3010 * shared inout type
3011 * shared inout const type
3012 */
3013 StorageClass stc = 0;
3014 while (1)
3015 {
3016 switch (token.value)
3017 {
3018 case TOKconst:
3019 if (peekNext() == TOKlparen)
3020 break; // const as type constructor
3021 stc |= STCconst; // const as storage class
3022 nextToken();
3023 continue;
3024
3025 case TOKimmutable:
3026 if (peekNext() == TOKlparen)
3027 break;
3028 stc |= STCimmutable;
3029 nextToken();
3030 continue;
3031
3032 case TOKshared:
3033 if (peekNext() == TOKlparen)
3034 break;
3035 stc |= STCshared;
3036 nextToken();
3037 continue;
3038
3039 case TOKwild:
3040 if (peekNext() == TOKlparen)
3041 break;
3042 stc |= STCwild;
3043 nextToken();
3044 continue;
3045
3046 default:
3047 break;
3048 }
3049 break;
3050 }
3051
3052 Loc typeLoc = token.loc;
3053
3054 Type *t;
3055 t = parseBasicType();
3056
3057 int alt = 0;
3058 t = parseDeclarator(t, &alt, pident, ptpl);
3059 checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
3060
3061 t = t->addSTC(stc);
3062 return t;
3063}
3064
3065Type *Parser::parseBasicType(bool dontLookDotIdents)
3066{
3067 Type *t;
3068 Loc loc;
3069 Identifier *id;
3070
3071 //printf("parseBasicType()\n");
3072 switch (token.value)
3073 {
3074 case TOKvoid: t = Type::tvoid; goto LabelX;
3075 case TOKint8: t = Type::tint8; goto LabelX;
3076 case TOKuns8: t = Type::tuns8; goto LabelX;
3077 case TOKint16: t = Type::tint16; goto LabelX;
3078 case TOKuns16: t = Type::tuns16; goto LabelX;
3079 case TOKint32: t = Type::tint32; goto LabelX;
3080 case TOKuns32: t = Type::tuns32; goto LabelX;
ecbb1530
IB
3081 case TOKint64:
3082 t = Type::tint64;
3083 nextToken();
3084 if (token.value == TOKint64) // if `long long`
3085 {
3086 error("use `long` for a 64 bit integer instead of `long long`");
3087 nextToken();
3088 }
3089 else if (token.value == TOKfloat64) // if `long double`
3090 {
3091 error("use `real` instead of `long double`");
3092 t = Type::tfloat80;
3093 nextToken();
3094
3095 }
3096 break;
3097
b4c522fa
IB
3098 case TOKuns64: t = Type::tuns64; goto LabelX;
3099 case TOKint128: t = Type::tint128; goto LabelX;
3100 case TOKuns128: t = Type::tuns128; goto LabelX;
3101 case TOKfloat32: t = Type::tfloat32; goto LabelX;
3102 case TOKfloat64: t = Type::tfloat64; goto LabelX;
3103 case TOKfloat80: t = Type::tfloat80; goto LabelX;
3104 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
3105 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
3106 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
3107 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
3108 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
3109 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
3110 case TOKbool: t = Type::tbool; goto LabelX;
3111 case TOKchar: t = Type::tchar; goto LabelX;
3112 case TOKwchar: t = Type::twchar; goto LabelX;
3113 case TOKdchar: t = Type::tdchar; goto LabelX;
3114 LabelX:
3115 nextToken();
3116 break;
3117
3118 case TOKthis:
3119 case TOKsuper:
3120 case TOKidentifier:
3121 loc = token.loc;
3122 id = token.ident;
3123 nextToken();
3124 if (token.value == TOKnot)
3125 {
3126 // ident!(template_arguments)
3127 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3128 tempinst->tiargs = parseTemplateArguments();
3129 t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
3130 }
3131 else
3132 {
3133 t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
3134 }
3135 break;
3136
3137 case TOKdot:
3138 // Leading . as in .foo
3139 t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
3140 break;
3141
3142 case TOKtypeof:
3143 // typeof(expression)
3144 t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3145 break;
3146
3147 case TOKvector:
3148 t = parseVector();
3149 break;
3150
5b74dd0a
IB
3151 case TOKtraits:
3152 if (TraitsExp *te = (TraitsExp *) parsePrimaryExp())
3153 {
3154 if (te->ident && te->args)
3155 {
3156 t = new TypeTraits(token.loc, te);
3157 break;
3158 }
3159 }
3160 t = new TypeError();
3161 break;
3162
b4c522fa
IB
3163 case TOKconst:
3164 // const(type)
3165 nextToken();
3166 check(TOKlparen);
3167 t = parseType()->addSTC(STCconst);
3168 check(TOKrparen);
3169 break;
3170
3171 case TOKimmutable:
3172 // immutable(type)
3173 nextToken();
3174 check(TOKlparen);
3175 t = parseType()->addSTC(STCimmutable);
3176 check(TOKrparen);
3177 break;
3178
3179 case TOKshared:
3180 // shared(type)
3181 nextToken();
3182 check(TOKlparen);
3183 t = parseType()->addSTC(STCshared);
3184 check(TOKrparen);
3185 break;
3186
3187 case TOKwild:
3188 // wild(type)
3189 nextToken();
3190 check(TOKlparen);
3191 t = parseType()->addSTC(STCwild);
3192 check(TOKrparen);
3193 break;
3194
3195 default:
3196 error("basic type expected, not %s", token.toChars());
3197 t = Type::terror;
3198 break;
3199 }
3200 return t;
3201}
3202
3203Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
3204{
3205 Type *maybeArray = NULL;
3206 // See https://issues.dlang.org/show_bug.cgi?id=1215
3207 // A basic type can look like MyType (typical case), but also:
3208 // MyType.T -> A type
3209 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3210 // MyType[expr].T -> A type.
3211 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3212 // (iif MyType[expr].T is a Ttuple)
3213 while (1)
3214 {
3215 switch (token.value)
3216 {
3217 case TOKdot:
3218 {
3219 nextToken();
3220 if (token.value != TOKidentifier)
3221 {
3222 error("identifier expected following '.' instead of '%s'", token.toChars());
3223 break;
3224 }
3225 if (maybeArray)
3226 {
3227 // This is actually a TypeTuple index, not an {a/s}array.
3228 // We need to have a while loop to unwind all index taking:
3229 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3230 Objects dimStack;
3231 Type *t = maybeArray;
3232 while (true)
3233 {
3234 if (t->ty == Tsarray)
3235 {
3236 // The index expression is an Expression.
3237 TypeSArray *a = (TypeSArray *)t;
3238 dimStack.push(a->dim->syntaxCopy());
3239 t = a->next->syntaxCopy();
3240 }
3241 else if (t->ty == Taarray)
3242 {
3243 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3244 TypeAArray *a = (TypeAArray *)t;
3245 dimStack.push(a->index->syntaxCopy());
3246 t = a->next->syntaxCopy();
3247 }
3248 else
3249 {
3250 break;
3251 }
3252 }
2cbc99d1 3253 assert(dimStack.length > 0);
b4c522fa
IB
3254 // We're good. Replay indices in the reverse order.
3255 tid = (TypeQualified *)t;
2cbc99d1 3256 while (dimStack.length)
b4c522fa
IB
3257 {
3258 tid->addIndex(dimStack.pop());
3259 }
3260 maybeArray = NULL;
3261 }
3262 Loc loc = token.loc;
3263 Identifier *id = token.ident;
3264 nextToken();
3265 if (token.value == TOKnot)
3266 {
3267 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3268 tempinst->tiargs = parseTemplateArguments();
3269 tid->addInst(tempinst);
3270 }
3271 else
3272 tid->addIdent(id);
3273 continue;
3274 }
3275 case TOKlbracket:
3276 {
3277 if (dontLookDotIdents) // workaround for Bugzilla 14911
3278 goto Lend;
3279
3280 nextToken();
3281 Type *t = maybeArray ? maybeArray : (Type *)tid;
3282 if (token.value == TOKrbracket)
3283 {
3284 // It's a dynamic array, and we're done:
3285 // T[].U does not make sense.
3286 t = new TypeDArray(t);
3287 nextToken();
3288 return t;
3289 }
3290 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3291 {
3292 // This can be one of two things:
3293 // 1 - an associative array declaration, T[type]
3294 // 2 - an associative array declaration, T[expr]
3295 // These can only be disambiguated later.
3296 Type *index = parseType(); // [ type ]
3297 maybeArray = new TypeAArray(t, index);
3298 check(TOKrbracket);
3299 }
3300 else
3301 {
3302 // This can be one of three things:
3303 // 1 - an static array declaration, T[expr]
3304 // 2 - a slice, T[expr .. expr]
3305 // 3 - a template parameter pack index expression, T[expr].U
3306 // 1 and 3 can only be disambiguated later.
3307 //printf("it's type[expression]\n");
3308 inBrackets++;
3309 Expression *e = parseAssignExp(); // [ expression ]
3310 if (token.value == TOKslice)
3311 {
3312 // It's a slice, and we're done.
3313 nextToken();
3314 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3315 t = new TypeSlice(t, e, e2);
3316 inBrackets--;
3317 check(TOKrbracket);
3318 return t;
3319 }
3320 else
3321 {
3322 maybeArray = new TypeSArray(t, e);
3323 inBrackets--;
3324 check(TOKrbracket);
3325 continue;
3326 }
3327 }
3328 break;
3329 }
3330 default:
3331 goto Lend;
3332 }
3333 }
3334Lend:
3335 return maybeArray ? maybeArray : (Type *)tid;
3336}
3337
3338/******************************************
3339 * Parse things that follow the initial type t.
3340 * t *
3341 * t []
3342 * t [type]
3343 * t [expression]
3344 * t [expression .. expression]
3345 * t function
3346 * t delegate
3347 */
3348
3349Type *Parser::parseBasicType2(Type *t)
3350{
3351 //printf("parseBasicType2()\n");
3352 while (1)
3353 {
3354 switch (token.value)
3355 {
3356 case TOKmul:
3357 t = new TypePointer(t);
3358 nextToken();
3359 continue;
3360
3361 case TOKlbracket:
3362 // Handle []. Make sure things like
3363 // int[3][1] a;
3364 // is (array[1] of array[3] of int)
3365 nextToken();
3366 if (token.value == TOKrbracket)
3367 {
3368 t = new TypeDArray(t); // []
3369 nextToken();
3370 }
3371 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3372 {
3373 // It's an associative array declaration
3374 //printf("it's an associative array\n");
3375 Type *index = parseType(); // [ type ]
3376 t = new TypeAArray(t, index);
3377 check(TOKrbracket);
3378 }
3379 else
3380 {
3381 //printf("it's type[expression]\n");
3382 inBrackets++;
3383 Expression *e = parseAssignExp(); // [ expression ]
3384 if (token.value == TOKslice)
3385 {
3386 nextToken();
3387 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3388 t = new TypeSlice(t, e, e2);
3389 }
3390 else
3391 {
3392 t = new TypeSArray(t,e);
3393 }
3394 inBrackets--;
3395 check(TOKrbracket);
3396 }
3397 continue;
3398
3399 case TOKdelegate:
3400 case TOKfunction:
3401 {
3402 // Handle delegate declaration:
3403 // t delegate(parameter list) nothrow pure
3404 // t function(parameter list) nothrow pure
3405 TOK save = token.value;
3406 nextToken();
3407
c3a2ba10 3408 VarArg varargs;
b4c522fa
IB
3409 Parameters *parameters = parseParameters(&varargs);
3410
3411 StorageClass stc = parsePostfix(STCundefined, NULL);
c3a2ba10
IB
3412 TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs),
3413 t, linkage, stc);
b4c522fa
IB
3414 if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
3415 {
3416 if (save == TOKfunction)
3417 error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3418 else
3419 tf = (TypeFunction *)tf->addSTC(stc);
3420 }
3421
3422 if (save == TOKdelegate)
3423 t = new TypeDelegate(tf);
3424 else
3425 t = new TypePointer(tf); // pointer to function
3426 continue;
3427 }
3428
3429 default:
3430 return t;
3431 }
3432 assert(0);
3433 }
3434 assert(0);
3435 return NULL;
3436}
3437
3438Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
3439 TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
3440{
3441 //printf("parseDeclarator(tpl = %p)\n", tpl);
3442 t = parseBasicType2(t);
3443
3444 Type *ts;
3445 switch (token.value)
3446 {
3447 case TOKidentifier:
3448 if (pident)
3449 *pident = token.ident;
3450 else
3451 error("unexpected identifer '%s' in declarator", token.ident->toChars());
3452 ts = t;
3453 nextToken();
3454 break;
3455
3456 case TOKlparen:
3457 {
3458 // like: T (*fp)();
3459 // like: T ((*fp))();
3460 if (peekNext() == TOKmul ||
3461 peekNext() == TOKlparen)
3462 {
3463 /* Parse things with parentheses around the identifier, like:
3464 * int (*ident[3])[]
3465 * although the D style would be:
3466 * int[]*[3] ident
3467 */
3468 *palt |= 1;
3469 nextToken();
3470 ts = parseDeclarator(t, palt, pident);
3471 check(TOKrparen);
3472 break;
3473 }
3474 ts = t;
3475
3476 Token *peekt = &token;
3477 /* Completely disallow C-style things like:
3478 * T (a);
3479 * Improve error messages for the common bug of a missing return type
3480 * by looking to see if (a) looks like a parameter list.
3481 */
3482 if (isParameters(&peekt))
3483 {
3484 error("function declaration without return type. (Note that constructors are always named 'this')");
3485 }
3486 else
3487 error("unexpected ( in declarator");
3488 break;
3489 }
3490
3491 default:
3492 ts = t;
3493 break;
3494 }
3495
3496 // parse DeclaratorSuffixes
3497 while (1)
3498 {
3499 switch (token.value)
3500 {
3501#if CARRAYDECL
3502 /* Support C style array syntax:
3503 * int ident[]
3504 * as opposed to D-style:
3505 * int[] ident
3506 */
3507 case TOKlbracket:
3508 {
3509 // This is the old C-style post [] syntax.
3510 TypeNext *ta;
3511 nextToken();
3512 if (token.value == TOKrbracket)
3513 {
3514 // It's a dynamic array
3515 ta = new TypeDArray(t); // []
3516 nextToken();
3517 *palt |= 2;
3518 }
3519 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3520 {
3521 // It's an associative array
3522 //printf("it's an associative array\n");
3523 Type *index = parseType(); // [ type ]
3524 check(TOKrbracket);
3525 ta = new TypeAArray(t, index);
3526 *palt |= 2;
3527 }
3528 else
3529 {
3530 //printf("It's a static array\n");
3531 Expression *e = parseAssignExp(); // [ expression ]
3532 ta = new TypeSArray(t, e);
3533 check(TOKrbracket);
3534 *palt |= 2;
3535 }
3536
3537 /* Insert ta into
3538 * ts -> ... -> t
3539 * so that
3540 * ts -> ... -> ta -> t
3541 */
3542 Type **pt;
3543 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3544 ;
3545 *pt = ta;
3546 continue;
3547 }
3548#endif
3549 case TOKlparen:
3550 {
3551 if (tpl)
3552 {
3553 Token *tk = peekPastParen(&token);
3554 if (tk->value == TOKlparen)
3555 {
3556 /* Look ahead to see if this is (...)(...),
3557 * i.e. a function template declaration
3558 */
3559 //printf("function template declaration\n");
3560
3561 // Gather template parameter list
3562 *tpl = parseTemplateParameterList();
3563 }
3564 else if (tk->value == TOKassign)
3565 {
3566 /* or (...) =,
3567 * i.e. a variable template declaration
3568 */
3569 //printf("variable template declaration\n");
3570 *tpl = parseTemplateParameterList();
3571 break;
3572 }
3573 }
3574
c3a2ba10 3575 VarArg varargs;
b4c522fa
IB
3576 Parameters *parameters = parseParameters(&varargs);
3577
3578 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3579 */
3580 StorageClass stc = parsePostfix(storageClass, pudas);
3581 // merge prefix storage classes
c3a2ba10
IB
3582 Type *tf = new TypeFunction(ParameterList(parameters, varargs),
3583 t, linkage, stc);
b4c522fa
IB
3584 tf = tf->addSTC(stc);
3585 if (pdisable)
3586 *pdisable = stc & STCdisable ? 1 : 0;
3587
3588 /* Insert tf into
3589 * ts -> ... -> t
3590 * so that
3591 * ts -> ... -> tf -> t
3592 */
3593 Type **pt;
3594 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3595 ;
3596 *pt = tf;
3597 break;
3598 }
3599 default: break;
3600 }
3601 break;
3602 }
3603
3604 return ts;
3605}
3606
3607void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
3608 bool &setAlignment, Expression *&ealign, Expressions *&udas)
3609{
3610 StorageClass stc;
3611 bool sawLinkage = false; // seen a linkage declaration
3612
3613 while (1)
3614 {
3615 switch (token.value)
3616 {
3617 case TOKconst:
3618 if (peek(&token)->value == TOKlparen)
3619 break; // const as type constructor
3620 stc = STCconst; // const as storage class
3621 goto L1;
3622
3623 case TOKimmutable:
3624 if (peek(&token)->value == TOKlparen)
3625 break;
3626 stc = STCimmutable;
3627 goto L1;
3628
3629 case TOKshared:
3630 if (peek(&token)->value == TOKlparen)
3631 break;
3632 stc = STCshared;
3633 goto L1;
3634
3635 case TOKwild:
3636 if (peek(&token)->value == TOKlparen)
3637 break;
3638 stc = STCwild;
3639 goto L1;
3640
3641 case TOKstatic: stc = STCstatic; goto L1;
3642 case TOKfinal: stc = STCfinal; goto L1;
3643 case TOKauto: stc = STCauto; goto L1;
3644 case TOKscope: stc = STCscope; goto L1;
3645 case TOKoverride: stc = STCoverride; goto L1;
3646 case TOKabstract: stc = STCabstract; goto L1;
3647 case TOKsynchronized: stc = STCsynchronized; goto L1;
3648 case TOKdeprecated: stc = STCdeprecated; goto L1;
3649 case TOKnothrow: stc = STCnothrow; goto L1;
3650 case TOKpure: stc = STCpure; goto L1;
3651 case TOKref: stc = STCref; goto L1;
3652 case TOKgshared: stc = STCgshared; goto L1;
3653 case TOKenum: stc = STCmanifest; goto L1;
3654 case TOKat:
3655 {
3656 stc = parseAttribute(&udas);
3657 if (stc)
3658 goto L1;
3659 continue;
3660 }
3661 L1:
3662 storage_class = appendStorageClass(storage_class, stc);
3663 nextToken();
3664 continue;
3665
3666 case TOKextern:
3667 {
3668 if (peek(&token)->value != TOKlparen)
3669 {
3670 stc = STCextern;
3671 goto L1;
3672 }
3673
3674 if (sawLinkage)
3675 error("redundant linkage declaration");
3676 sawLinkage = true;
3677 Identifiers *idents = NULL;
3678 CPPMANGLE cppmangle = CPPMANGLEdefault;
9503d7b1
IB
3679 bool cppMangleOnly = false;
3680 link = parseLinkage(&idents, &cppmangle, &cppMangleOnly);
b4c522fa
IB
3681 if (idents)
3682 {
3683 error("C++ name spaces not allowed here");
3684 delete idents;
3685 }
3686 if (cppmangle != CPPMANGLEdefault)
3687 {
3688 error("C++ mangle declaration not allowed here");
3689 }
3690 continue;
3691 }
3692
3693 case TOKalign:
3694 {
3695 nextToken();
3696 setAlignment = true;
3697 if (token.value == TOKlparen)
3698 {
3699 nextToken();
3700 ealign = parseExpression();
3701 check(TOKrparen);
3702 }
3703 continue;
3704 }
3705 default:
3706 break;
3707 }
3708 break;
3709 }
3710}
3711
3712/**********************************
3713 * Parse Declarations.
3714 * These can be:
3715 * 1. declarations at global/class level
3716 * 2. declarations at statement level
3717 * Return array of Declaration *'s.
3718 */
3719
3720Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
3721{
3722 StorageClass storage_class = STCundefined;
3723 Type *ts;
3724 Type *t;
3725 Type *tfirst;
3726 Identifier *ident;
3727 TOK tok = TOKreserved;
3728 LINK link = linkage;
3729 bool setAlignment = false;
3730 Expression *ealign = NULL;
3731 Loc loc = token.loc;
3732 Expressions *udas = NULL;
3733 Token *tk;
3734
3735 //printf("parseDeclarations() %s\n", token.toChars());
3736 if (!comment)
3737 comment = token.blockComment;
3738
3739 if (autodecl)
3740 {
3741 ts = NULL; // infer type
3742 goto L2;
3743 }
3744
3745 if (token.value == TOKalias)
3746 {
3747 tok = token.value;
3748 nextToken();
3749
3750 /* Look for:
3751 * alias identifier this;
3752 */
3753 if (token.value == TOKidentifier && peekNext() == TOKthis)
3754 {
3755 AliasThis *s = new AliasThis(loc, token.ident);
3756 nextToken();
3757 check(TOKthis);
3758 check(TOKsemicolon);
3759 Dsymbols *a = new Dsymbols();
3760 a->push(s);
3761 addComment(s, comment);
3762 return a;
3763 }
3764 /* Look for:
3765 * alias identifier = type;
3766 * alias identifier(...) = type;
3767 */
3768 if (token.value == TOKidentifier &&
3769 skipParensIf(peek(&token), &tk) &&
3770 tk->value == TOKassign)
3771 {
3772 Dsymbols *a = new Dsymbols();
3773 while (1)
3774 {
3775 ident = token.ident;
3776 nextToken();
3777 TemplateParameters *tpl = NULL;
3778 if (token.value == TOKlparen)
3779 tpl = parseTemplateParameterList();
3780 check(TOKassign);
3781
3782 Declaration *v;
3783 if (token.value == TOKfunction ||
3784 token.value == TOKdelegate ||
3785 (token.value == TOKlparen &&
3786 skipAttributes(peekPastParen(&token), &tk) &&
3787 (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
3788 token.value == TOKlcurly ||
3789 (token.value == TOKidentifier && peekNext() == TOKgoesto))
3790 {
3791 // function (parameters) { statements... }
3792 // delegate (parameters) { statements... }
3793 // (parameters) { statements... }
3794 // (parameters) => expression
3795 // { statements... }
3796 // identifier => expression
3797
3798 Dsymbol *s = parseFunctionLiteral();
3799 v = new AliasDeclaration(loc, ident, s);
3800 }
3801 else
3802 {
3803 // StorageClasses type
3804
3805 storage_class = STCundefined;
3806 link = linkage;
3807 setAlignment = false;
3808 ealign = NULL;
3809 udas = NULL;
3810 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3811
3812 if (udas)
3813 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3814
3815 t = parseType();
3816 v = new AliasDeclaration(loc, ident, t);
3817 }
3818 v->storage_class = storage_class;
3819
3820 Dsymbol *s = v;
3821 if (tpl)
3822 {
3823 Dsymbols *a2 = new Dsymbols();
3824 a2->push(s);
3825 TemplateDeclaration *tempdecl =
3826 new TemplateDeclaration(loc, ident, tpl, NULL, a2);
3827 s = tempdecl;
3828 }
3829 if (setAlignment)
3830 {
3831 Dsymbols *ax = new Dsymbols();
3832 ax->push(s);
3833 s = new AlignDeclaration(v->loc, ealign, ax);
3834 }
3835 if (link != linkage)
3836 {
3837 Dsymbols *a2 = new Dsymbols();
3838 a2->push(s);
3839 s = new LinkDeclaration(link, a2);
3840 }
3841 a->push(s);
3842
3843 switch (token.value)
3844 {
3845 case TOKsemicolon:
3846 nextToken();
3847 addComment(s, comment);
3848 break;
3849 case TOKcomma:
3850 nextToken();
3851 addComment(s, comment);
3852 if (token.value != TOKidentifier)
3853 {
3854 error("identifier expected following comma, not %s", token.toChars());
3855 break;
3856 }
3857 if (peekNext() != TOKassign && peekNext() != TOKlparen)
3858 {
3859 error("= expected following identifier");
3860 nextToken();
3861 break;
3862 }
3863 continue;
3864 default:
3865 error("semicolon expected to close %s declaration", Token::toChars(tok));
3866 break;
3867 }
3868 break;
3869 }
3870 return a;
3871 }
3872
3873 // alias StorageClasses type ident;
3874 }
3875
3876 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3877
3878 if (token.value == TOKstruct ||
3879 token.value == TOKunion ||
3880 token.value == TOKclass ||
3881 token.value == TOKinterface)
3882 {
3883 Dsymbol *s = parseAggregate();
3884 Dsymbols *a = new Dsymbols();
3885 a->push(s);
3886
3887 if (storage_class)
3888 {
3889 s = new StorageClassDeclaration(storage_class, a);
3890 a = new Dsymbols();
3891 a->push(s);
3892 }
3893 if (setAlignment)
3894 {
3895 s = new AlignDeclaration(s->loc, ealign, a);
3896 a = new Dsymbols();
3897 a->push(s);
3898 }
3899 if (link != linkage)
3900 {
3901 s = new LinkDeclaration(link, a);
3902 a = new Dsymbols();
3903 a->push(s);
3904 }
3905 if (udas)
3906 {
3907 s = new UserAttributeDeclaration(udas, a);
3908 a = new Dsymbols();
3909 a->push(s);
3910 }
3911
3912 addComment(s, comment);
3913 return a;
3914 }
3915
3916 /* Look for auto initializers:
3917 * storage_class identifier = initializer;
3918 * storage_class identifier(...) = initializer;
3919 */
3920 if ((storage_class || udas) &&
3921 token.value == TOKidentifier &&
3922 skipParensIf(peek(&token), &tk) &&
3923 tk->value == TOKassign)
3924 {
3925 Dsymbols *a = parseAutoDeclarations(storage_class, comment);
3926 if (udas)
3927 {
3928 Dsymbol *s = new UserAttributeDeclaration(udas, a);
3929 a = new Dsymbols();
3930 a->push(s);
3931 }
3932 return a;
3933 }
3934
3935 /* Look for return type inference for template functions.
3936 */
3937 if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) &&
3938 skipAttributes(tk, &tk) &&
3939 (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout ||
3940 tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body)))
3941 {
3942 ts = NULL;
3943 }
3944 else
3945 {
3946 ts = parseBasicType();
3947 ts = parseBasicType2(ts);
3948 }
3949
3950L2:
3951 tfirst = NULL;
3952 Dsymbols *a = new Dsymbols();
3953
3954 if (pAttrs)
3955 {
3956 storage_class |= pAttrs->storageClass;
3957 //pAttrs->storageClass = STCundefined;
3958 }
3959
3960 while (1)
3961 {
3962 TemplateParameters *tpl = NULL;
3963 int disable;
3964 int alt = 0;
3965
3966 loc = token.loc;
3967 ident = NULL;
3968 t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
3969 assert(t);
3970 if (!tfirst)
3971 tfirst = t;
3972 else if (t != tfirst)
3973 error("multiple declarations must have the same type, not %s and %s",
3974 tfirst->toChars(), t->toChars());
3975 bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
3976 if (ident)
3977 checkCstyleTypeSyntax(loc, t, alt, ident);
3978 else if (!isThis)
3979 error("no identifier for declarator %s", t->toChars());
3980
3981 if (tok == TOKalias)
3982 {
3983 Declaration *v;
3984 Initializer *init = NULL;
3985
3986 /* Aliases can no longer have multiple declarators, storage classes,
3987 * linkages, or auto declarations.
3988 * These never made any sense, anyway.
3989 * The code below needs to be fixed to reject them.
3990 * The grammar has already been fixed to preclude them.
3991 */
3992
3993 if (udas)
3994 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3995
3996 if (token.value == TOKassign)
3997 {
3998 nextToken();
3999 init = parseInitializer();
4000 }
4001 if (init)
4002 {
4003 if (isThis)
4004 error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
4005 init->toChars(), init->toChars());
4006 else
4007 error("alias cannot have initializer");
4008 }
4009 v = new AliasDeclaration(loc, ident, t);
4010
4011 v->storage_class = storage_class;
4012 if (pAttrs)
4013 {
4014 /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
4015 * on prefix and postfix.
4016 * @safe alias void function() FP1;
4017 * alias @safe void function() FP2; // FP2 is not @safe
4018 * alias void function() @safe FP3;
4019 */
4020 pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
4021 }
4022 Dsymbol *s = v;
4023
4024 if (link != linkage)
4025 {
4026 Dsymbols *ax = new Dsymbols();
4027 ax->push(v);
4028 s = new LinkDeclaration(link, ax);
4029 }
4030 a->push(s);
4031 switch (token.value)
4032 {
4033 case TOKsemicolon:
4034 nextToken();
4035 addComment(s, comment);
4036 break;
4037
4038 case TOKcomma:
4039 nextToken();
4040 addComment(s, comment);
4041 continue;
4042
4043 default:
4044 error("semicolon expected to close %s declaration", Token::toChars(tok));
4045 break;
4046 }
4047 }
4048 else if (t->ty == Tfunction)
4049 {
4050 Expression *constraint = NULL;
4051
4052 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
4053 FuncDeclaration *f =
4054 new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
4055 if (pAttrs)
4056 pAttrs->storageClass = STCundefined;
4057 if (tpl)
4058 constraint = parseConstraint();
4059 Dsymbol *s = parseContracts(f);
4060 Identifier *tplIdent = s->ident;
4061 if (link != linkage)
4062 {
4063 Dsymbols *ax = new Dsymbols();
4064 ax->push(s);
4065 s = new LinkDeclaration(link, ax);
4066 }
4067 if (udas)
4068 {
4069 Dsymbols *ax = new Dsymbols();
4070 ax->push(s);
4071 s = new UserAttributeDeclaration(udas, ax);
4072 }
4073
4074 /* A template parameter list means it's a function template
4075 */
4076 if (tpl)
4077 {
4078 // Wrap a template around the function declaration
4079 Dsymbols *decldefs = new Dsymbols();
4080 decldefs->push(s);
4081 TemplateDeclaration *tempdecl =
4082 new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4083 s = tempdecl;
4084
4085 if (storage_class & STCstatic)
4086 {
4087 assert(f->storage_class & STCstatic);
4088 f->storage_class &= ~STCstatic;
4089
4090 Dsymbols *ax = new Dsymbols();
4091 ax->push(s);
4092 s = new StorageClassDeclaration(STCstatic, ax);
4093 }
4094 }
4095 a->push(s);
4096 addComment(s, comment);
4097 }
4098 else if (ident)
4099 {
4100 Initializer *init = NULL;
4101 if (token.value == TOKassign)
4102 {
4103 nextToken();
4104 init = parseInitializer();
4105 }
4106
4107 VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
4108 v->storage_class = storage_class;
4109 if (pAttrs)
4110 pAttrs->storageClass = STCundefined;
4111
4112 Dsymbol *s = v;
4113
4114 if (tpl && init)
4115 {
4116 Dsymbols *a2 = new Dsymbols();
4117 a2->push(s);
4118 TemplateDeclaration *tempdecl =
4119 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4120 s = tempdecl;
4121 }
4122 if (link != linkage)
4123 {
4124 Dsymbols *ax = new Dsymbols();
4125 ax->push(s);
4126 s = new LinkDeclaration(link, ax);
4127 }
4128 if (udas)
4129 {
4130 Dsymbols *ax = new Dsymbols();
4131 ax->push(s);
4132 s = new UserAttributeDeclaration(udas, ax);
4133 }
4134 a->push(s);
4135 switch (token.value)
4136 {
4137 case TOKsemicolon:
4138 nextToken();
4139 addComment(s, comment);
4140 break;
4141
4142 case TOKcomma:
4143 nextToken();
4144 addComment(s, comment);
4145 continue;
4146
4147 default:
4148 error("semicolon expected, not '%s'", token.toChars());
4149 break;
4150 }
4151 }
4152 break;
4153 }
4154 return a;
4155}
4156
4157Dsymbol *Parser::parseFunctionLiteral()
4158{
4159 Loc loc = token.loc;
4160
4161 TemplateParameters *tpl = NULL;
4162 Parameters *parameters = NULL;
c3a2ba10 4163 VarArg varargs = VARARGnone;
b4c522fa
IB
4164 Type *tret = NULL;
4165 StorageClass stc = 0;
4166 TOK save = TOKreserved;
4167
4168 switch (token.value)
4169 {
4170 case TOKfunction:
4171 case TOKdelegate:
4172 save = token.value;
4173 nextToken();
4174 if (token.value != TOKlparen && token.value != TOKlcurly)
4175 {
4176 // function type (parameters) { statements... }
4177 // delegate type (parameters) { statements... }
4178 tret = parseBasicType();
4179 tret = parseBasicType2(tret); // function return type
4180 }
4181
4182 if (token.value == TOKlparen)
4183 {
4184 // function (parameters) { statements... }
4185 // delegate (parameters) { statements... }
4186 }
4187 else
4188 {
4189 // function { statements... }
4190 // delegate { statements... }
4191 break;
4192 }
4193 /* fall through */
4194
4195 case TOKlparen:
4196 {
4197 // (parameters) => expression
4198 // (parameters) { statements... }
4199 parameters = parseParameters(&varargs, &tpl);
4200 stc = parsePostfix(STCundefined, NULL);
4201 if (StorageClass modStc = stc & STC_TYPECTOR)
4202 {
4203 if (save == TOKfunction)
4204 {
4205 OutBuffer buf;
4206 stcToBuffer(&buf, modStc);
fced594b 4207 error("function literal cannot be %s", buf.peekChars());
b4c522fa
IB
4208 }
4209 else
4210 save = TOKdelegate;
4211 }
4212 break;
4213 }
4214 case TOKlcurly:
4215 // { statements... }
4216 break;
4217
4218 case TOKidentifier:
4219 {
4220 // identifier => expression
4221 parameters = new Parameters();
4222 Identifier *id = Identifier::generateId("__T");
4223 Type *t = new TypeIdentifier(loc, id);
4224 parameters->push(new Parameter(0, t, token.ident, NULL));
4225
4226 tpl = new TemplateParameters();
4227 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
4228 tpl->push(tp);
4229
4230 nextToken();
4231 break;
4232 }
4233 default:
4234 assert(0);
4235 }
4236
4237 if (!parameters)
4238 parameters = new Parameters();
c3a2ba10
IB
4239 TypeFunction *tf = new TypeFunction(ParameterList(parameters, varargs),
4240 tret, linkage, stc);
b4c522fa
IB
4241 tf = (TypeFunction *)tf->addSTC(stc);
4242 FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
4243
4244 if (token.value == TOKgoesto)
4245 {
4246 check(TOKgoesto);
4247 Loc returnloc = token.loc;
4248 Expression *ae = parseAssignExp();
4249 fd->fbody = new ReturnStatement(returnloc, ae);
4250 fd->endloc = token.loc;
4251 }
4252 else
4253 {
4254 parseContracts(fd);
4255 }
4256
4257 if (tpl)
4258 {
4259 // Wrap a template around function fd
4260 Dsymbols *decldefs = new Dsymbols();
4261 decldefs->push(fd);
4262 return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
4263 }
4264 else
4265 return fd;
4266}
4267
4268/*****************************************
4269 * Parse auto declarations of the form:
4270 * storageClass ident = init, ident = init, ... ;
4271 * and return the array of them.
4272 * Starts with token on the first ident.
4273 * Ends with scanner past closing ';'
4274 */
4275
4276Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
4277{
4278 //printf("parseAutoDeclarations\n");
4279 Token *tk;
4280 Dsymbols *a = new Dsymbols;
4281
4282 while (1)
4283 {
4284 Loc loc = token.loc;
4285 Identifier *ident = token.ident;
4286 nextToken(); // skip over ident
4287
4288 TemplateParameters *tpl = NULL;
4289 if (token.value == TOKlparen)
4290 tpl = parseTemplateParameterList();
4291
4292 check(TOKassign); // skip over '='
4293 Initializer *init = parseInitializer();
4294 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
4295 v->storage_class = storageClass;
4296
4297 Dsymbol *s = v;
4298 if (tpl)
4299 {
4300 Dsymbols *a2 = new Dsymbols();
4301 a2->push(v);
4302 TemplateDeclaration *tempdecl =
4303 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4304 s = tempdecl;
4305 }
4306 a->push(s);
4307 switch (token.value)
4308 {
4309 case TOKsemicolon:
4310 nextToken();
4311 addComment(s, comment);
4312 break;
4313
4314 case TOKcomma:
4315 nextToken();
4316 if (!(token.value == TOKidentifier &&
4317 skipParensIf(peek(&token), &tk) &&
4318 tk->value == TOKassign))
4319 {
4320 error("identifier expected following comma");
4321 break;
4322 }
4323 addComment(s, comment);
4324 continue;
4325
4326 default:
4327 error("semicolon expected following auto declaration, not '%s'", token.toChars());
4328 break;
4329 }
4330 break;
4331 }
4332 return a;
4333}
4334
4335/*****************************************
4336 * Parse contracts following function declaration.
4337 */
4338
4339FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
4340{
4341 LINK linksave = linkage;
4342
4343 bool literal = f->isFuncLiteralDeclaration() != NULL;
4344
4345 // The following is irrelevant, as it is overridden by sc->linkage in
4346 // TypeFunction::semantic
4347 linkage = LINKd; // nested functions have D linkage
4348L1:
4349 switch (token.value)
4350 {
4351 case TOKlcurly:
4352 if (f->frequire || f->fensure)
4353 error("missing body { ... } after in or out");
4354 f->fbody = parseStatement(PSsemi);
4355 f->endloc = endloc;
4356 break;
4357
4358 case TOKidentifier:
4359 if (token.ident != Id::_body)
4360 goto Ldefault;
4361 /* fall through */
4362
4363 case TOKdo:
4364 nextToken();
4365 f->fbody = parseStatement(PScurly);
4366 f->endloc = endloc;
4367 break;
4368
4369 case TOKin:
4370 nextToken();
4371 if (f->frequire)
4372 error("redundant 'in' statement");
4373 f->frequire = parseStatement(PScurly | PSscope);
4374 goto L1;
4375
4376 case TOKout:
4377 // parse: out (identifier) { statement }
4378 nextToken();
4379 if (token.value != TOKlcurly)
4380 {
4381 check(TOKlparen);
4382 if (token.value != TOKidentifier)
4383 error("(identifier) following 'out' expected, not %s", token.toChars());
4384 f->outId = token.ident;
4385 nextToken();
4386 check(TOKrparen);
4387 }
4388 if (f->fensure)
4389 error("redundant 'out' statement");
4390 f->fensure = parseStatement(PScurly | PSscope);
4391 goto L1;
4392
4393 case TOKsemicolon:
4394 if (!literal)
4395 {
4396 // Bugzilla 15799: Semicolon becomes a part of function declaration
4397 // only when neither of contracts exists.
4398 if (!f->frequire && !f->fensure)
4399 nextToken();
4400 break;
4401 }
4402 /* fall through */
4403
4404 default:
4405 Ldefault:
4406 if (literal)
4407 {
4408 const char *sbody = (f->frequire || f->fensure) ? "body " : "";
4409 error("missing %s{ ... } for function literal", sbody);
4410 }
4411 else if (!f->frequire && !f->fensure) // allow these even with no body
4412 {
4413 error("semicolon expected following function declaration");
4414 }
4415 break;
4416 }
4417 if (literal && !f->fbody)
4418 {
4419 // Set empty function body for error recovery
4420 f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
4421 }
4422
4423 linkage = linksave;
4424
4425 return f;
4426}
4427
4428/*****************************************
4429 * Parse initializer for variable declaration.
4430 */
4431
4432Initializer *Parser::parseInitializer()
4433{
4434 StructInitializer *is;
4435 ArrayInitializer *ia;
4436 ExpInitializer *ie;
4437 Expression *e;
4438 Identifier *id;
4439 Initializer *value;
4440 int comma;
4441 Loc loc = token.loc;
4442 Token *t;
4443 int braces;
4444 int brackets;
4445
4446 switch (token.value)
4447 {
4448 case TOKlcurly:
4449 /* Scan ahead to see if it is a struct initializer or
4450 * a function literal.
4451 * If it contains a ';', it is a function literal.
4452 * Treat { } as a struct initializer.
4453 */
4454 braces = 1;
4455 for (t = peek(&token); 1; t = peek(t))
4456 {
4457 switch (t->value)
4458 {
4459 case TOKsemicolon:
4460 case TOKreturn:
4461 goto Lexpression;
4462
4463 case TOKlcurly:
4464 braces++;
4465 continue;
4466
4467 case TOKrcurly:
4468 if (--braces == 0)
4469 break;
4470 continue;
4471
4472 case TOKeof:
4473 break;
4474
4475 default:
4476 continue;
4477 }
4478 break;
4479 }
4480
4481 is = new StructInitializer(loc);
4482 nextToken();
4483 comma = 2;
4484 while (1)
4485 {
4486 switch (token.value)
4487 {
4488 case TOKidentifier:
4489 if (comma == 1)
4490 error("comma expected separating field initializers");
4491 t = peek(&token);
4492 if (t->value == TOKcolon)
4493 {
4494 id = token.ident;
4495 nextToken();
4496 nextToken(); // skip over ':'
4497 }
4498 else
4499 { id = NULL;
4500 }
4501 value = parseInitializer();
4502 is->addInit(id, value);
4503 comma = 1;
4504 continue;
4505
4506 case TOKcomma:
4507 if (comma == 2)
4508 error("expression expected, not ','");
4509 nextToken();
4510 comma = 2;
4511 continue;
4512
4513 case TOKrcurly: // allow trailing comma's
4514 nextToken();
4515 break;
4516
4517 case TOKeof:
4518 error("found EOF instead of initializer");
4519 break;
4520
4521 default:
4522 if (comma == 1)
4523 error("comma expected separating field initializers");
4524 value = parseInitializer();
4525 is->addInit(NULL, value);
4526 comma = 1;
4527 continue;
4528 //error("found '%s' instead of field initializer", token.toChars());
4529 //break;
4530 }
4531 break;
4532 }
4533 return is;
4534
4535 case TOKlbracket:
4536 /* Scan ahead to see if it is an array initializer or
4537 * an expression.
4538 * If it ends with a ';' ',' or '}', it is an array initializer.
4539 */
4540 brackets = 1;
4541 for (t = peek(&token); 1; t = peek(t))
4542 {
4543 switch (t->value)
4544 {
4545 case TOKlbracket:
4546 brackets++;
4547 continue;
4548
4549 case TOKrbracket:
4550 if (--brackets == 0)
4551 { t = peek(t);
4552 if (t->value != TOKsemicolon &&
4553 t->value != TOKcomma &&
4554 t->value != TOKrbracket &&
4555 t->value != TOKrcurly)
4556 goto Lexpression;
4557 break;
4558 }
4559 continue;
4560
4561 case TOKeof:
4562 break;
4563
4564 default:
4565 continue;
4566 }
4567 break;
4568 }
4569
4570 ia = new ArrayInitializer(loc);
4571 nextToken();
4572 comma = 2;
4573 while (1)
4574 {
4575 switch (token.value)
4576 {
4577 default:
4578 if (comma == 1)
4579 { error("comma expected separating array initializers, not %s", token.toChars());
4580 nextToken();
4581 break;
4582 }
4583 e = parseAssignExp();
4584 if (!e)
4585 break;
4586 if (token.value == TOKcolon)
4587 {
4588 nextToken();
4589 value = parseInitializer();
4590 }
4591 else
4592 { value = new ExpInitializer(e->loc, e);
4593 e = NULL;
4594 }
4595 ia->addInit(e, value);
4596 comma = 1;
4597 continue;
4598
4599 case TOKlcurly:
4600 case TOKlbracket:
4601 if (comma == 1)
4602 error("comma expected separating array initializers, not %s", token.toChars());
4603 value = parseInitializer();
4604 if (token.value == TOKcolon)
4605 {
4606 nextToken();
4607 e = initializerToExpression(value);
4608 value = parseInitializer();
4609 }
4610 else
4611 e = NULL;
4612 ia->addInit(e, value);
4613 comma = 1;
4614 continue;
4615
4616 case TOKcomma:
4617 if (comma == 2)
4618 error("expression expected, not ','");
4619 nextToken();
4620 comma = 2;
4621 continue;
4622
4623 case TOKrbracket: // allow trailing comma's
4624 nextToken();
4625 break;
4626
4627 case TOKeof:
4628 error("found '%s' instead of array initializer", token.toChars());
4629 break;
4630 }
4631 break;
4632 }
4633 return ia;
4634
4635 case TOKvoid:
4636 t = peek(&token);
4637 if (t->value == TOKsemicolon || t->value == TOKcomma)
4638 {
4639 nextToken();
4640 return new VoidInitializer(loc);
4641 }
4642 goto Lexpression;
4643
4644 default:
4645 Lexpression:
4646 e = parseAssignExp();
4647 ie = new ExpInitializer(loc, e);
4648 return ie;
4649 }
4650}
4651
4652/*****************************************
4653 * Parses default argument initializer expression that is an assign expression,
4654 * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
4655 */
4656
4657Expression *Parser::parseDefaultInitExp()
4658{
4659 if (token.value == TOKfile ||
4660 token.value == TOKfilefullpath ||
4661 token.value == TOKline ||
4662 token.value == TOKmodulestring ||
4663 token.value == TOKfuncstring ||
4664 token.value == TOKprettyfunc)
4665 {
4666 Token *t = peek(&token);
4667 if (t->value == TOKcomma || t->value == TOKrparen)
4668 {
4669 Expression *e = NULL;
4670 if (token.value == TOKfile)
4671 e = new FileInitExp(token.loc, TOKfile);
4672 else if (token.value == TOKfilefullpath)
4673 e = new FileInitExp(token.loc, TOKfilefullpath);
4674 else if (token.value == TOKline)
4675 e = new LineInitExp(token.loc);
4676 else if (token.value == TOKmodulestring)
4677 e = new ModuleInitExp(token.loc);
4678 else if (token.value == TOKfuncstring)
4679 e = new FuncInitExp(token.loc);
4680 else if (token.value == TOKprettyfunc)
4681 e = new PrettyFuncInitExp(token.loc);
4682 else
4683 assert(0);
4684 nextToken();
4685 return e;
4686 }
4687 }
4688
4689 Expression *e = parseAssignExp();
4690 return e;
4691}
4692
4693/*****************************************
4694 */
4695
4696void Parser::checkDanglingElse(Loc elseloc)
4697{
4698 if (token.value != TOKelse &&
4699 token.value != TOKcatch &&
4700 token.value != TOKfinally &&
4701 lookingForElse.linnum != 0)
4702 {
4703 warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
4704 }
4705}
4706
4707void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
4708{
4709 if (!alt)
4710 return;
4711
4712 const char *sp = !ident ? "" : " ";
4713 const char *s = !ident ? "" : ident->toChars();
4714 if (alt & 1) // contains C-style function pointer syntax
4715 error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
4716 else
4717 ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
4718
4719}
4720
5b74dd0a
IB
4721/*****************************************
4722 * Parses `foreach` statements, `static foreach` statements and
4723 * `static foreach` declarations. The template parameter
4724 * `isStatic` is true, iff a `static foreach` should be parsed.
4725 * If `isStatic` is true, `isDecl` can be true to indicate that a
4726 * `static foreach` declaration should be parsed.
4727 */
4728Statement *Parser::parseForeach(Loc loc, bool *isRange, bool isDecl)
4729{
4730 TOK op = token.value;
4731
4732 nextToken();
4733 check(TOKlparen);
4734
4735 Parameters *parameters = new Parameters();
4736
4737 while (1)
4738 {
4739 Identifier *ai = NULL;
4740 Type *at;
4741
4742 StorageClass storageClass = 0;
4743 StorageClass stc = 0;
4744 Lagain:
4745 if (stc)
4746 {
4747 storageClass = appendStorageClass(storageClass, stc);
4748 nextToken();
4749 }
4750 switch (token.value)
4751 {
4752 case TOKref:
4753 stc = STCref;
4754 goto Lagain;
4755
4756 case TOKenum:
4757 stc = STCmanifest;
4758 goto Lagain;
4759
4760 case TOKalias:
4761 storageClass = appendStorageClass(storageClass, STCalias);
4762 nextToken();
4763 break;
4764
4765 case TOKconst:
4766 if (peekNext() != TOKlparen)
4767 {
4768 stc = STCconst;
4769 goto Lagain;
4770 }
4771 break;
4772
4773 case TOKimmutable:
4774 if (peekNext() != TOKlparen)
4775 {
4776 stc = STCimmutable;
4777 goto Lagain;
4778 }
4779 break;
4780
4781 case TOKshared:
4782 if (peekNext() != TOKlparen)
4783 {
4784 stc = STCshared;
4785 goto Lagain;
4786 }
4787 break;
4788
4789 case TOKwild:
4790 if (peekNext() != TOKlparen)
4791 {
4792 stc = STCwild;
4793 goto Lagain;
4794 }
4795 break;
4796
4797 default:
4798 break;
4799 }
4800 if (token.value == TOKidentifier)
4801 {
4802 Token *t = peek(&token);
4803 if (t->value == TOKcomma || t->value == TOKsemicolon)
4804 { ai = token.ident;
4805 at = NULL; // infer argument type
4806 nextToken();
4807 goto Larg;
4808 }
4809 }
4810 at = parseType(&ai);
4811 if (!ai)
4812 error("no identifier for declarator %s", at->toChars());
4813 Larg:
4814 Parameter *p = new Parameter(storageClass, at, ai, NULL);
4815 parameters->push(p);
4816 if (token.value == TOKcomma)
4817 { nextToken();
4818 continue;
4819 }
4820 break;
4821 }
4822 check(TOKsemicolon);
4823
4824 Expression *aggr = parseExpression();
2cbc99d1 4825 if (token.value == TOKslice && parameters->length == 1)
5b74dd0a
IB
4826 {
4827 Parameter *p = (*parameters)[0];
4828 delete parameters;
4829 nextToken();
4830 Expression *upr = parseExpression();
4831 check(TOKrparen);
4832 Loc endloc;
4833 Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
4834 if (isRange)
4835 *isRange = true;
4836 return new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
4837 }
4838 else
4839 {
4840 check(TOKrparen);
4841 Loc endloc;
4842 Statement *body = (!isDecl) ? parseStatement(0, NULL, &endloc) : NULL;
4843 if (isRange)
4844 *isRange = false;
4845 return new ForeachStatement(loc, op, parameters, aggr, body, endloc);
4846 }
4847}
4848
4849Dsymbol *Parser::parseForeachStaticDecl(Loc loc, Dsymbol **pLastDecl)
4850{
4851 nextToken();
4852
4853 bool isRange = false;
4854 Statement *s = parseForeach(loc, &isRange, true);
4855
4856 return new StaticForeachDeclaration(
4857 new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
4858 isRange ? (ForeachRangeStatement *)s : NULL),
4859 parseBlock(pLastDecl)
4860 );
4861}
4862
4863Statement *Parser::parseForeachStatic(Loc loc)
4864{
4865 nextToken();
4866
4867 bool isRange = false;
4868 Statement *s = parseForeach(loc, &isRange, false);
4869
4870 return new StaticForeachStatement(loc,
4871 new StaticForeach(loc, isRange ? NULL : (ForeachStatement *)s,
4872 isRange ? (ForeachRangeStatement *)s : NULL)
4873 );
4874}
4875
b4c522fa
IB
4876/*****************************************
4877 * Input:
4878 * flags PSxxxx
4879 * Output:
4880 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
4881 */
4882
4883Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
4884{
4885 Statement *s = NULL;
4886 Condition *cond;
4887 Statement *ifbody;
4888 Statement *elsebody;
4889 bool isfinal;
4890 Loc loc = token.loc;
4891
4892 //printf("parseStatement()\n");
4893
4894 if (flags & PScurly && token.value != TOKlcurly)
4895 error("statement expected to be { }, not %s", token.toChars());
4896
4897 switch (token.value)
4898 {
4899 case TOKidentifier:
4900 { /* A leading identifier can be a declaration, label, or expression.
4901 * The easiest case to check first is label:
4902 */
4903 Token *t = peek(&token);
4904 if (t->value == TOKcolon)
4905 {
4906 Token *nt = peek(t);
4907 if (nt->value == TOKcolon)
4908 {
4909 // skip ident::
4910 nextToken();
4911 nextToken();
4912 nextToken();
4913 error("use `.` for member lookup, not `::`");
4914 break;
4915 }
4916 // It's a label
4917 Identifier *ident = token.ident;
4918 nextToken();
4919 nextToken();
4920 if (token.value == TOKrcurly)
4921 s = NULL;
4922 else if (token.value == TOKlcurly)
4923 s = parseStatement(PScurly | PSscope);
4924 else
4925 s = parseStatement(PSsemi_ok);
4926 s = new LabelStatement(loc, ident, s);
4927 break;
4928 }
4929 }
4930 /* fall through */
4931 case TOKdot:
4932 case TOKtypeof:
4933 case TOKvector:
5b74dd0a 4934 case TOKtraits:
b4c522fa
IB
4935 /* Bugzilla 15163: If tokens can be handled as
4936 * old C-style declaration or D expression, prefer the latter.
4937 */
4938 if (isDeclaration(&token, 3, TOKreserved, NULL))
4939 goto Ldeclaration;
4940 else
4941 goto Lexp;
4942 break;
4943
4944 case TOKassert:
4945 case TOKthis:
4946 case TOKsuper:
4947 case TOKint32v:
4948 case TOKuns32v:
4949 case TOKint64v:
4950 case TOKuns64v:
4951 case TOKint128v:
4952 case TOKuns128v:
4953 case TOKfloat32v:
4954 case TOKfloat64v:
4955 case TOKfloat80v:
4956 case TOKimaginary32v:
4957 case TOKimaginary64v:
4958 case TOKimaginary80v:
4959 case TOKcharv:
4960 case TOKwcharv:
4961 case TOKdcharv:
4962 case TOKnull:
4963 case TOKtrue:
4964 case TOKfalse:
4965 case TOKstring:
4966 case TOKxstring:
4967 case TOKlparen:
4968 case TOKcast:
4969 case TOKmul:
4970 case TOKmin:
4971 case TOKadd:
4972 case TOKtilde:
4973 case TOKnot:
4974 case TOKplusplus:
4975 case TOKminusminus:
4976 case TOKnew:
4977 case TOKdelete:
4978 case TOKdelegate:
4979 case TOKfunction:
4980 case TOKtypeid:
4981 case TOKis:
4982 case TOKlbracket:
b4c522fa
IB
4983 case TOKfile:
4984 case TOKfilefullpath:
4985 case TOKline:
4986 case TOKmodulestring:
4987 case TOKfuncstring:
4988 case TOKprettyfunc:
4989 Lexp:
4990 {
4991 Expression *exp = parseExpression();
4992 check(TOKsemicolon, "statement");
4993 s = new ExpStatement(loc, exp);
4994 break;
4995 }
4996
4997 case TOKstatic:
4998 { // Look ahead to see if it's static assert() or static if()
4999
5000 Token *t = peek(&token);
5001 if (t->value == TOKassert)
5002 {
5003 s = new StaticAssertStatement(parseStaticAssert());
5004 break;
5005 }
5006 if (t->value == TOKif)
5007 {
5008 cond = parseStaticIfCondition();
5009 goto Lcondition;
5010 }
5b74dd0a
IB
5011 else if (t->value == TOKforeach || t->value == TOKforeach_reverse)
5012 {
5013 s = parseForeachStatic(loc);
5014 if (flags & PSscope)
5015 s = new ScopeStatement(loc, s, token.loc);
5016 break;
5017 }
b4c522fa
IB
5018 if (t->value == TOKimport)
5019 {
5020 Dsymbols *imports = parseImport();
5021 s = new ImportStatement(loc, imports);
5022 if (flags & PSscope)
5023 s = new ScopeStatement(loc, s, token.loc);
5024 break;
5025 }
5026 goto Ldeclaration;
5027 }
5028
5029 case TOKfinal:
5030 if (peekNext() == TOKswitch)
5031 {
5032 nextToken();
5033 isfinal = true;
5034 goto Lswitch;
5035 }
5036 goto Ldeclaration;
5037
5038 case TOKwchar: case TOKdchar:
5039 case TOKbool: case TOKchar:
5040 case TOKint8: case TOKuns8:
5041 case TOKint16: case TOKuns16:
5042 case TOKint32: case TOKuns32:
5043 case TOKint64: case TOKuns64:
5044 case TOKint128: case TOKuns128:
5045 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5046 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5047 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5048 case TOKvoid:
5049 // bug 7773: int.max is always a part of expression
5050 if (peekNext() == TOKdot)
5051 goto Lexp;
5052 if (peekNext() == TOKlparen)
5053 goto Lexp;
5054 /* fall through */
5055
5056 case TOKalias:
5057 case TOKconst:
5058 case TOKauto:
5059 case TOKabstract:
5060 case TOKextern:
5061 case TOKalign:
5062 case TOKimmutable:
5063 case TOKshared:
5064 case TOKwild:
5065 case TOKdeprecated:
5066 case TOKnothrow:
5067 case TOKpure:
5068 case TOKref:
5069 case TOKgshared:
5070 case TOKat:
5071 case TOKstruct:
5072 case TOKunion:
5073 case TOKclass:
5074 case TOKinterface:
5075 Ldeclaration:
5076 {
5077 Dsymbols *a = parseDeclarations(false, NULL, NULL);
2cbc99d1 5078 if (a->length > 1)
b4c522fa
IB
5079 {
5080 Statements *as = new Statements();
2cbc99d1
IB
5081 as->reserve(a->length);
5082 for (size_t i = 0; i < a->length; i++)
b4c522fa
IB
5083 {
5084 Dsymbol *d = (*a)[i];
5085 s = new ExpStatement(loc, d);
5086 as->push(s);
5087 }
5088 s = new CompoundDeclarationStatement(loc, as);
5089 }
2cbc99d1 5090 else if (a->length == 1)
b4c522fa
IB
5091 {
5092 Dsymbol *d = (*a)[0];
5093 s = new ExpStatement(loc, d);
5094 }
5095 else
5096 s = new ExpStatement(loc, (Expression *)NULL);
5097 if (flags & PSscope)
5098 s = new ScopeStatement(loc, s, token.loc);
5099 break;
5100 }
5101
5102 case TOKenum:
5103 { /* Determine if this is a manifest constant declaration,
5104 * or a conventional enum.
5105 */
5106 Dsymbol *d;
5107 Token *t = peek(&token);
5108 if (t->value == TOKlcurly || t->value == TOKcolon)
5109 d = parseEnum();
5110 else if (t->value != TOKidentifier)
5111 goto Ldeclaration;
5112 else
5113 {
5114 t = peek(t);
5115 if (t->value == TOKlcurly || t->value == TOKcolon ||
5116 t->value == TOKsemicolon)
5117 d = parseEnum();
5118 else
5119 goto Ldeclaration;
5120 }
5121 s = new ExpStatement(loc, d);
5122 if (flags & PSscope)
5123 s = new ScopeStatement(loc, s, token.loc);
5124 break;
5125 }
5126
5127 case TOKmixin:
5128 { Token *t = peek(&token);
5129 if (t->value == TOKlparen)
5130 { // mixin(string)
5131 Expression *e = parseAssignExp();
5132 check(TOKsemicolon);
5133 if (e->op == TOKmixin)
5134 {
5135 CompileExp *cpe = (CompileExp *)e;
5136 s = new CompileStatement(loc, cpe->e1);
5137 }
5138 else
5139 {
5140 s = new ExpStatement(loc, e);
5141 }
5142 break;
5143 }
5144 Dsymbol *d = parseMixin();
5145 s = new ExpStatement(loc, d);
5146 if (flags & PSscope)
5147 s = new ScopeStatement(loc, s, token.loc);
5148 break;
5149 }
5150
5151 case TOKlcurly:
5152 {
5153 Loc lookingForElseSave = lookingForElse;
5154 lookingForElse = Loc();
5155
5156 nextToken();
5157 //if (token.value == TOKsemicolon)
5158 //error("use '{ }' for an empty statement, not a ';'");
5159 Statements *statements = new Statements();
5160 while (token.value != TOKrcurly && token.value != TOKeof)
5161 {
5162 statements->push(parseStatement(PSsemi | PScurlyscope));
5163 }
5164 if (endPtr) *endPtr = token.ptr;
5165 endloc = token.loc;
5166 if (pEndloc)
5167 {
5168 *pEndloc = token.loc;
5169 pEndloc = NULL; // don't set it again
5170 }
5171 s = new CompoundStatement(loc, statements);
5172 if (flags & (PSscope | PScurlyscope))
5173 s = new ScopeStatement(loc, s, token.loc);
5174 check(TOKrcurly, "compound statement");
5175 lookingForElse = lookingForElseSave;
5176 break;
5177 }
5178
5179 case TOKwhile:
5180 {
5181 nextToken();
5182 check(TOKlparen);
5183 Expression *condition = parseExpression();
5184 check(TOKrparen);
5185 Loc endloc;
5186 Statement *body = parseStatement(PSscope, NULL, &endloc);
5187 s = new WhileStatement(loc, condition, body, endloc);
5188 break;
5189 }
5190
5191 case TOKsemicolon:
5192 if (!(flags & PSsemi_ok))
5193 {
5194 if (flags & PSsemi)
5195 deprecation("use '{ }' for an empty statement, not a ';'");
5196 else
5197 error("use '{ }' for an empty statement, not a ';'");
5198 }
5199 nextToken();
5200 s = new ExpStatement(loc, (Expression *)NULL);
5201 break;
5202
5203 case TOKdo:
5204 { Statement *body;
5205 Expression *condition;
5206
5207 nextToken();
5208 Loc lookingForElseSave = lookingForElse;
5209 lookingForElse = Loc();
5210 body = parseStatement(PSscope);
5211 lookingForElse = lookingForElseSave;
5212 check(TOKwhile);
5213 check(TOKlparen);
5214 condition = parseExpression();
5215 check(TOKrparen);
5216 if (token.value == TOKsemicolon)
5217 nextToken();
5218 else
5219 error("terminating ';' required after do-while statement");
5220 s = new DoStatement(loc, body, condition, token.loc);
5221 break;
5222 }
5223
5224 case TOKfor:
5225 {
5226 Statement *init;
5227 Expression *condition;
5228 Expression *increment;
5229
5230 nextToken();
5231 check(TOKlparen);
5232 if (token.value == TOKsemicolon)
5233 { init = NULL;
5234 nextToken();
5235 }
5236 else
5237 {
5238 Loc lookingForElseSave = lookingForElse;
5239 lookingForElse = Loc();
5240 init = parseStatement(0);
5241 lookingForElse = lookingForElseSave;
5242 }
5243 if (token.value == TOKsemicolon)
5244 {
5245 condition = NULL;
5246 nextToken();
5247 }
5248 else
5249 {
5250 condition = parseExpression();
5251 check(TOKsemicolon, "for condition");
5252 }
5253 if (token.value == TOKrparen)
5254 { increment = NULL;
5255 nextToken();
5256 }
5257 else
5258 { increment = parseExpression();
5259 check(TOKrparen);
5260 }
5261 Loc endloc;
5262 Statement *body = parseStatement(PSscope, NULL, &endloc);
5263 s = new ForStatement(loc, init, condition, increment, body, endloc);
5264 break;
5265 }
5266
5267 case TOKforeach:
5268 case TOKforeach_reverse:
5269 {
5b74dd0a 5270 s = parseForeach(loc, NULL, false);
b4c522fa
IB
5271 break;
5272 }
5273
5274 case TOKif:
5275 {
5276 Parameter *param = NULL;
5277 Expression *condition;
5278
5279 nextToken();
5280 check(TOKlparen);
5281
5282 StorageClass storageClass = 0;
5283 StorageClass stc = 0;
5284 LagainStc:
5285 if (stc)
5286 {
5287 storageClass = appendStorageClass(storageClass, stc);
5288 nextToken();
5289 }
5290 switch (token.value)
5291 {
5292 case TOKref:
5293 stc = STCref;
5294 goto LagainStc;
5295 case TOKauto:
5296 stc = STCauto;
5297 goto LagainStc;
5298 case TOKconst:
5299 if (peekNext() != TOKlparen)
5300 {
5301 stc = STCconst;
5302 goto LagainStc;
5303 }
5304 break;
5305 case TOKimmutable:
5306 if (peekNext() != TOKlparen)
5307 {
5308 stc = STCimmutable;
5309 goto LagainStc;
5310 }
5311 break;
5312 case TOKshared:
5313 if (peekNext() != TOKlparen)
5314 {
5315 stc = STCshared;
5316 goto LagainStc;
5317 }
5318 break;
5319 case TOKwild:
5320 if (peekNext() != TOKlparen)
5321 {
5322 stc = STCwild;
5323 goto LagainStc;
5324 }
5325 break;
5326 default:
5327 break;
5328 }
5329
5330 if (storageClass != 0 &&
5331 token.value == TOKidentifier &&
5332 peek(&token)->value == TOKassign)
5333 {
5334 Identifier *ai = token.ident;
5335 Type *at = NULL; // infer parameter type
5336 nextToken();
5337 check(TOKassign);
5338 param = new Parameter(storageClass, at, ai, NULL);
5339 }
5340 else if (isDeclaration(&token, 2, TOKassign, NULL))
5341 {
5342 Identifier *ai;
5343 Type *at = parseType(&ai);
5344 check(TOKassign);
5345 param = new Parameter(storageClass, at, ai, NULL);
5346 }
5347
5348 condition = parseExpression();
5349 check(TOKrparen);
5350 {
5351 Loc lookingForElseSave = lookingForElse;
5352 lookingForElse = loc;
5353 ifbody = parseStatement(PSscope);
5354 lookingForElse = lookingForElseSave;
5355 }
5356 if (token.value == TOKelse)
5357 {
5358 Loc elseloc = token.loc;
5359 nextToken();
5360 elsebody = parseStatement(PSscope);
5361 checkDanglingElse(elseloc);
5362 }
5363 else
5364 elsebody = NULL;
5365 if (condition && ifbody)
5366 s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
5367 else
5368 s = NULL; // don't propagate parsing errors
5369 break;
5370 }
5371
5372 case TOKscope:
5373 if (peek(&token)->value != TOKlparen)
5374 goto Ldeclaration; // scope used as storage class
5375 nextToken();
5376 check(TOKlparen);
5377 if (token.value != TOKidentifier)
5378 { error("scope identifier expected");
5379 goto Lerror;
5380 }
5381 else
5382 { TOK t = TOKon_scope_exit;
5383 Identifier *id = token.ident;
5384
5385 if (id == Id::exit)
5386 t = TOKon_scope_exit;
5387 else if (id == Id::failure)
5388 t = TOKon_scope_failure;
5389 else if (id == Id::success)
5390 t = TOKon_scope_success;
5391 else
5392 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
5393 nextToken();
5394 check(TOKrparen);
5395 Statement *st = parseStatement(PSscope);
72acf751 5396 s = new ScopeGuardStatement(loc, t, st);
b4c522fa
IB
5397 break;
5398 }
5399
5400 case TOKdebug:
5401 nextToken();
5402 if (token.value == TOKassign)
5403 {
5404 error("debug conditions can only be declared at module scope");
5405 nextToken();
5406 nextToken();
5407 goto Lerror;
5408 }
5409 cond = parseDebugCondition();
5410 goto Lcondition;
5411
5412 case TOKversion:
5413 nextToken();
5414 if (token.value == TOKassign)
5415 {
5416 error("version conditions can only be declared at module scope");
5417 nextToken();
5418 nextToken();
5419 goto Lerror;
5420 }
5421 cond = parseVersionCondition();
5422 goto Lcondition;
5423
5424 Lcondition:
5425 {
5426 Loc lookingForElseSave = lookingForElse;
5427 lookingForElse = loc;
5428 ifbody = parseStatement(0);
5429 lookingForElse = lookingForElseSave;
5430 }
5431 elsebody = NULL;
5432 if (token.value == TOKelse)
5433 {
5434 Loc elseloc = token.loc;
5435 nextToken();
5436 elsebody = parseStatement(0);
5437 checkDanglingElse(elseloc);
5438 }
5439 s = new ConditionalStatement(loc, cond, ifbody, elsebody);
5440 if (flags & PSscope)
5441 s = new ScopeStatement(loc, s, token.loc);
5442 break;
5443
5444 case TOKpragma:
5445 { Identifier *ident;
5446 Expressions *args = NULL;
5447 Statement *body;
5448
5449 nextToken();
5450 check(TOKlparen);
5451 if (token.value != TOKidentifier)
5452 { error("pragma(identifier expected");
5453 goto Lerror;
5454 }
5455 ident = token.ident;
5456 nextToken();
5457 if (token.value == TOKcomma && peekNext() != TOKrparen)
5458 args = parseArguments(); // pragma(identifier, args...);
5459 else
5460 check(TOKrparen); // pragma(identifier);
5461 if (token.value == TOKsemicolon)
5462 { nextToken();
5463 body = NULL;
5464 }
5465 else
5466 body = parseStatement(PSsemi);
5467 s = new PragmaStatement(loc, ident, args, body);
5468 break;
5469 }
5470
5471 case TOKswitch:
5472 isfinal = false;
5473 goto Lswitch;
5474
5475 Lswitch:
5476 {
5477 nextToken();
5478 check(TOKlparen);
5479 Expression *condition = parseExpression();
5480 check(TOKrparen);
5481 Statement *body = parseStatement(PSscope);
5482 s = new SwitchStatement(loc, condition, body, isfinal);
5483 break;
5484 }
5485
5486 case TOKcase:
5487 { Expression *exp;
5488 Expressions cases; // array of Expression's
5489 Expression *last = NULL;
5490
5491 while (1)
5492 {
5493 nextToken();
5494 exp = parseAssignExp();
5495 cases.push(exp);
5496 if (token.value != TOKcomma)
5497 break;
5498 }
5499 check(TOKcolon);
5500
5501 /* case exp: .. case last:
5502 */
5503 if (token.value == TOKslice)
5504 {
2cbc99d1 5505 if (cases.length > 1)
b4c522fa
IB
5506 error("only one case allowed for start of case range");
5507 nextToken();
5508 check(TOKcase);
5509 last = parseAssignExp();
5510 check(TOKcolon);
5511 }
5512
5513 if (flags & PScurlyscope)
5514 {
5515 Statements *statements = new Statements();
5516 while (token.value != TOKcase &&
5517 token.value != TOKdefault &&
5518 token.value != TOKeof &&
5519 token.value != TOKrcurly)
5520 {
5521 statements->push(parseStatement(PSsemi | PScurlyscope));
5522 }
5523 s = new CompoundStatement(loc, statements);
5524 }
5525 else
5526 s = parseStatement(PSsemi | PScurlyscope);
5527 s = new ScopeStatement(loc, s, token.loc);
5528
5529 if (last)
5530 {
5531 s = new CaseRangeStatement(loc, exp, last, s);
5532 }
5533 else
5534 {
5535 // Keep cases in order by building the case statements backwards
2cbc99d1 5536 for (size_t i = cases.length; i; i--)
b4c522fa
IB
5537 {
5538 exp = cases[i - 1];
5539 s = new CaseStatement(loc, exp, s);
5540 }
5541 }
5542 break;
5543 }
5544
5545 case TOKdefault:
5546 {
5547 nextToken();
5548 check(TOKcolon);
5549
5550 if (flags & PScurlyscope)
5551 {
5552 Statements *statements = new Statements();
5553 while (token.value != TOKcase &&
5554 token.value != TOKdefault &&
5555 token.value != TOKeof &&
5556 token.value != TOKrcurly)
5557 {
5558 statements->push(parseStatement(PSsemi | PScurlyscope));
5559 }
5560 s = new CompoundStatement(loc, statements);
5561 }
5562 else
5563 s = parseStatement(PSsemi | PScurlyscope);
5564 s = new ScopeStatement(loc, s, token.loc);
5565 s = new DefaultStatement(loc, s);
5566 break;
5567 }
5568
5569 case TOKreturn:
5570 { Expression *exp;
5571
5572 nextToken();
5573 if (token.value == TOKsemicolon)
5574 exp = NULL;
5575 else
5576 exp = parseExpression();
5577 check(TOKsemicolon, "return statement");
5578 s = new ReturnStatement(loc, exp);
5579 break;
5580 }
5581
5582 case TOKbreak:
5583 { Identifier *ident;
5584
5585 nextToken();
5586 if (token.value == TOKidentifier)
5587 { ident = token.ident;
5588 nextToken();
5589 }
5590 else
5591 ident = NULL;
5592 check(TOKsemicolon, "break statement");
5593 s = new BreakStatement(loc, ident);
5594 break;
5595 }
5596
5597 case TOKcontinue:
5598 { Identifier *ident;
5599
5600 nextToken();
5601 if (token.value == TOKidentifier)
5602 { ident = token.ident;
5603 nextToken();
5604 }
5605 else
5606 ident = NULL;
5607 check(TOKsemicolon, "continue statement");
5608 s = new ContinueStatement(loc, ident);
5609 break;
5610 }
5611
5612 case TOKgoto:
5613 { Identifier *ident;
5614
5615 nextToken();
5616 if (token.value == TOKdefault)
5617 {
5618 nextToken();
5619 s = new GotoDefaultStatement(loc);
5620 }
5621 else if (token.value == TOKcase)
5622 {
5623 Expression *exp = NULL;
5624
5625 nextToken();
5626 if (token.value != TOKsemicolon)
5627 exp = parseExpression();
5628 s = new GotoCaseStatement(loc, exp);
5629 }
5630 else
5631 {
5632 if (token.value != TOKidentifier)
5633 {
5634 error("identifier expected following goto");
5635 ident = NULL;
5636 }
5637 else
5638 {
5639 ident = token.ident;
5640 nextToken();
5641 }
5642 s = new GotoStatement(loc, ident);
5643 }
5644 check(TOKsemicolon, "goto statement");
5645 break;
5646 }
5647
5648 case TOKsynchronized:
5649 { Expression *exp;
5650 Statement *body;
5651
5652 Token *t = peek(&token);
5653 if (skipAttributes(t, &t) && t->value == TOKclass)
5654 goto Ldeclaration;
5655
5656 nextToken();
5657 if (token.value == TOKlparen)
5658 {
5659 nextToken();
5660 exp = parseExpression();
5661 check(TOKrparen);
5662 }
5663 else
5664 exp = NULL;
5665 body = parseStatement(PSscope);
5666 s = new SynchronizedStatement(loc, exp, body);
5667 break;
5668 }
5669
5670 case TOKwith:
5671 { Expression *exp;
5672 Statement *body;
5673
5674 nextToken();
5675 check(TOKlparen);
5676 exp = parseExpression();
5677 check(TOKrparen);
5678 body = parseStatement(PSscope);
5679 s = new WithStatement(loc, exp, body, token.loc);
5680 break;
5681 }
5682
5683 case TOKtry:
5684 { Statement *body;
5685 Catches *catches = NULL;
5686 Statement *finalbody = NULL;
5687
5688 nextToken();
5689 Loc lookingForElseSave = lookingForElse;
5690 lookingForElse = Loc();
5691 body = parseStatement(PSscope);
5692 lookingForElse = lookingForElseSave;
5693 while (token.value == TOKcatch)
5694 {
5695 Statement *handler;
5696 Catch *c;
5697 Type *t;
5698 Identifier *id;
5699 Loc catchloc = token.loc;
5700
5701 nextToken();
5702 if (token.value == TOKlcurly || token.value != TOKlparen)
5703 {
5704 t = NULL;
5705 id = NULL;
5706 }
5707 else
5708 {
5709 check(TOKlparen);
5710 id = NULL;
5711 t = parseType(&id);
5712 check(TOKrparen);
5713 }
5714 handler = parseStatement(0);
5715 c = new Catch(catchloc, t, id, handler);
5716 if (!catches)
5717 catches = new Catches();
5718 catches->push(c);
5719 }
5720
5721 if (token.value == TOKfinally)
5722 {
5723 nextToken();
5724 finalbody = parseStatement(PSscope);
5725 }
5726
5727 s = body;
5728 if (!catches && !finalbody)
5729 error("catch or finally expected following try");
5730 else
5731 { if (catches)
5732 s = new TryCatchStatement(loc, body, catches);
5733 if (finalbody)
5734 s = new TryFinallyStatement(loc, s, finalbody);
5735 }
5736 break;
5737 }
5738
5739 case TOKthrow:
5740 { Expression *exp;
5741
5742 nextToken();
5743 exp = parseExpression();
5744 check(TOKsemicolon, "throw statement");
5745 s = new ThrowStatement(loc, exp);
5746 break;
5747 }
5748
5749 case TOKasm:
5750 {
5751 // Parse the asm block into a sequence of AsmStatements,
5752 // each AsmStatement is one instruction.
5753 // Separate out labels.
5754 // Defer parsing of AsmStatements until semantic processing.
5755
5756 Loc labelloc;
5757
5758 nextToken();
5759 StorageClass stc = parsePostfix(STCundefined, NULL);
5760 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5761 error("const/immutable/shared/inout attributes are not allowed on asm blocks");
5762
5763 check(TOKlcurly);
5764 Token *toklist = NULL;
5765 Token **ptoklist = &toklist;
5766 Identifier *label = NULL;
5767 Statements *statements = new Statements();
5768 size_t nestlevel = 0;
5769 while (1)
5770 {
5771 switch (token.value)
5772 {
5773 case TOKidentifier:
5774 if (!toklist)
5775 {
5776 // Look ahead to see if it is a label
5777 Token *t = peek(&token);
5778 if (t->value == TOKcolon)
5779 { // It's a label
5780 label = token.ident;
5781 labelloc = token.loc;
5782 nextToken();
5783 nextToken();
5784 continue;
5785 }
5786 }
5787 goto Ldefault;
5788
5789 case TOKlcurly:
5790 ++nestlevel;
5791 goto Ldefault;
5792
5793 case TOKrcurly:
5794 if (nestlevel > 0)
5795 {
5796 --nestlevel;
5797 goto Ldefault;
5798 }
5799
5800 if (toklist || label)
5801 {
5802 error("asm statements must end in ';'");
5803 }
5804 break;
5805
5806 case TOKsemicolon:
5807 if (nestlevel != 0)
5808 error("mismatched number of curly brackets");
5809
5810 s = NULL;
5811 if (toklist || label)
5812 {
5813 // Create AsmStatement from list of tokens we've saved
5814 s = new AsmStatement(token.loc, toklist);
5815 toklist = NULL;
5816 ptoklist = &toklist;
5817 if (label)
5818 { s = new LabelStatement(labelloc, label, s);
5819 label = NULL;
5820 }
5821 statements->push(s);
5822 }
5823 nextToken();
5824 continue;
5825
5826 case TOKeof:
5827 /* { */
5828 error("matching '}' expected, not end of file");
5829 goto Lerror;
5830 /* fall through */
5831
5832 default:
5833 Ldefault:
5834 *ptoklist = Token::alloc();
5835 memcpy(*ptoklist, &token, sizeof(Token));
5836 ptoklist = &(*ptoklist)->next;
5837 *ptoklist = NULL;
5838
5839 nextToken();
5840 continue;
5841 }
5842 break;
5843 }
5844 s = new CompoundAsmStatement(loc, statements, stc);
5845 nextToken();
5846 break;
5847 }
5848
5849 case TOKimport:
5850 {
5851 Dsymbols *imports = parseImport();
5852 s = new ImportStatement(loc, imports);
5853 if (flags & PSscope)
5854 s = new ScopeStatement(loc, s, token.loc);
5855 break;
5856 }
5857
5858 case TOKtemplate:
5859 {
5860 Dsymbol *d = parseTemplateDeclaration();
5861 s = new ExpStatement(loc, d);
5862 break;
5863 }
5864
5865 default:
5866 error("found '%s' instead of statement", token.toChars());
5867 goto Lerror;
5868
5869 Lerror:
5870 while (token.value != TOKrcurly &&
5871 token.value != TOKsemicolon &&
5872 token.value != TOKeof)
5873 nextToken();
5874 if (token.value == TOKsemicolon)
5875 nextToken();
5876 s = NULL;
5877 break;
5878 }
5879 if (pEndloc)
5880 *pEndloc = token.loc;
5881 return s;
5882}
5883
5884void Parser::check(TOK value)
5885{
5886 check(token.loc, value);
5887}
5888
5889void Parser::check(Loc loc, TOK value)
5890{
5891 if (token.value != value)
5892 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
5893 nextToken();
5894}
5895
5896void Parser::check(TOK value, const char *string)
5897{
5898 if (token.value != value)
5899 error("found '%s' when expecting '%s' following %s",
5900 token.toChars(), Token::toChars(value), string);
5901 nextToken();
5902}
5903
5904void Parser::checkParens(TOK value, Expression *e)
5905{
5906 if (precedence[e->op] == PREC_rel && !e->parens)
5907 error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
5908}
5909
5910/************************************
5911 * Determine if the scanner is sitting on the start of a declaration.
5912 * Input:
5913 * needId 0 no identifier
5914 * 1 identifier optional
5915 * 2 must have identifier
5916 * 3 must have identifier, but don't recognize old C-style syntax.
5917 * Output:
5918 * if *pt is not NULL, it is set to the ending token, which would be endtok
5919 */
5920
5921bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
5922{
5923 //printf("isDeclaration(needId = %d)\n", needId);
5924 int haveId = 0;
5925 int haveTpl = 0;
5926
5927 while (1)
5928 {
5929 if ((t->value == TOKconst ||
5930 t->value == TOKimmutable ||
5931 t->value == TOKwild ||
5932 t->value == TOKshared) &&
5933 peek(t)->value != TOKlparen)
5934 {
5935 /* const type
5936 * immutable type
5937 * shared type
5938 * wild type
5939 */
5940 t = peek(t);
5941 continue;
5942 }
5943 break;
5944 }
5945
5946 if (!isBasicType(&t))
5947 {
5948 goto Lisnot;
5949 }
5950 if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3))
5951 goto Lisnot;
c5e94699
IB
5952 if ((needId == 0 && !haveId) ||
5953 (needId == 1) ||
5954 (needId == 2 && haveId) ||
5955 (needId == 3 && haveId))
b4c522fa
IB
5956 {
5957 if (pt)
5958 *pt = t;
5959 goto Lis;
5960 }
5961 else
5962 goto Lisnot;
5963
5964Lis:
5965 //printf("\tis declaration, t = %s\n", t->toChars());
5966 return true;
5967
5968Lisnot:
5969 //printf("\tis not declaration\n");
5970 return false;
5971}
5972
5973bool Parser::isBasicType(Token **pt)
5974{
5975 // This code parallels parseBasicType()
5976 Token *t = *pt;
5977
5978 switch (t->value)
5979 {
5980 case TOKwchar: case TOKdchar:
5981 case TOKbool: case TOKchar:
5982 case TOKint8: case TOKuns8:
5983 case TOKint16: case TOKuns16:
5984 case TOKint32: case TOKuns32:
5985 case TOKint64: case TOKuns64:
5986 case TOKint128: case TOKuns128:
5987 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5988 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5989 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5990 case TOKvoid:
5991 t = peek(t);
5992 break;
5993
5994 case TOKidentifier:
5995 L5:
5996 t = peek(t);
5997 if (t->value == TOKnot)
5998 {
5999 goto L4;
6000 }
6001 goto L3;
6002 while (1)
6003 {
6004 L2:
6005 t = peek(t);
6006 L3:
6007 if (t->value == TOKdot)
6008 {
6009 Ldot:
6010 t = peek(t);
6011 if (t->value != TOKidentifier)
6012 goto Lfalse;
6013 t = peek(t);
6014 if (t->value != TOKnot)
6015 goto L3;
6016 L4:
6017 /* Seen a !
6018 * Look for:
6019 * !( args ), !identifier, etc.
6020 */
6021 t = peek(t);
6022 switch (t->value)
6023 {
6024 case TOKidentifier:
6025 goto L5;
6026 case TOKlparen:
6027 if (!skipParens(t, &t))
6028 goto Lfalse;
6029 goto L3;
6030 case TOKwchar: case TOKdchar:
6031 case TOKbool: case TOKchar:
6032 case TOKint8: case TOKuns8:
6033 case TOKint16: case TOKuns16:
6034 case TOKint32: case TOKuns32:
6035 case TOKint64: case TOKuns64:
6036 case TOKint128: case TOKuns128:
6037 case TOKfloat32: case TOKfloat64: case TOKfloat80:
6038 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
6039 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
6040 case TOKvoid:
6041 case TOKint32v:
6042 case TOKuns32v:
6043 case TOKint64v:
6044 case TOKuns64v:
6045 case TOKint128v:
6046 case TOKuns128v:
6047 case TOKfloat32v:
6048 case TOKfloat64v:
6049 case TOKfloat80v:
6050 case TOKimaginary32v:
6051 case TOKimaginary64v:
6052 case TOKimaginary80v:
6053 case TOKnull:
6054 case TOKtrue:
6055 case TOKfalse:
6056 case TOKcharv:
6057 case TOKwcharv:
6058 case TOKdcharv:
6059 case TOKstring:
6060 case TOKxstring:
6061 case TOKfile:
6062 case TOKfilefullpath:
6063 case TOKline:
6064 case TOKmodulestring:
6065 case TOKfuncstring:
6066 case TOKprettyfunc:
6067 goto L2;
6068 default:
6069 goto Lfalse;
6070 }
6071 }
6072 else
6073 break;
6074 }
6075 break;
6076
6077 case TOKdot:
6078 goto Ldot;
6079
6080 case TOKtypeof:
6081 case TOKvector:
6082 /* typeof(exp).identifier...
6083 */
6084 t = peek(t);
6085 if (!skipParens(t, &t))
6086 goto Lfalse;
6087 goto L3;
6088
5b74dd0a
IB
6089 case TOKtraits:
6090 {
6091 // __traits(getMember
6092 t = peek(t);
6093 if (t->value != TOKlparen)
6094 goto Lfalse;
6095 Token *lp = t;
6096 t = peek(t);
6097 if (t->value != TOKidentifier || t->ident != Id::getMember)
6098 goto Lfalse;
6099 if (!skipParens(lp, &lp))
6100 goto Lfalse;
6101 // we are in a lookup for decl VS statement
6102 // so we expect a declarator following __trait if it's a type.
6103 // other usages wont be ambiguous (alias, template instance, type qual, etc.)
6104 if (lp->value != TOKidentifier)
6105 goto Lfalse;
6106
6107 break;
6108 }
6109
b4c522fa
IB
6110 case TOKconst:
6111 case TOKimmutable:
6112 case TOKshared:
6113 case TOKwild:
6114 // const(type) or immutable(type) or shared(type) or wild(type)
6115 t = peek(t);
6116 if (t->value != TOKlparen)
6117 goto Lfalse;
6118 t = peek(t);
6119 if (!isDeclaration(t, 0, TOKrparen, &t))
6120 {
6121 goto Lfalse;
6122 }
6123 t = peek(t);
6124 break;
6125
6126 default:
6127 goto Lfalse;
6128 }
6129 *pt = t;
6130 //printf("is\n");
6131 return true;
6132
6133Lfalse:
6134 //printf("is not\n");
6135 return false;
6136}
6137
6138bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax)
6139{ // This code parallels parseDeclarator()
6140 Token *t = *pt;
6141 int parens;
6142
6143 //printf("Parser::isDeclarator() %s\n", t->toChars());
6144 if (t->value == TOKassign)
6145 return false;
6146
6147 while (1)
6148 {
6149 parens = false;
6150 switch (t->value)
6151 {
6152 case TOKmul:
6153 //case TOKand:
6154 t = peek(t);
6155 continue;
6156
6157 case TOKlbracket:
6158 t = peek(t);
6159 if (t->value == TOKrbracket)
6160 {
6161 t = peek(t);
6162 }
6163 else if (isDeclaration(t, 0, TOKrbracket, &t))
6164 {
6165 // It's an associative array declaration
6166 t = peek(t);
6167
6168 // ...[type].ident
6169 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6170 {
6171 t = peek(t);
6172 t = peek(t);
6173 }
6174 }
6175 else
6176 {
6177 // [ expression ]
6178 // [ expression .. expression ]
6179 if (!isExpression(&t))
6180 return false;
6181 if (t->value == TOKslice)
6182 {
6183 t = peek(t);
6184 if (!isExpression(&t))
6185 return false;
6186 if (t->value != TOKrbracket)
6187 return false;
6188 t = peek(t);
6189 }
6190 else
6191 {
6192 if (t->value != TOKrbracket)
6193 return false;
6194 t = peek(t);
6195
6196 // ...[index].ident
6197 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6198 {
6199 t = peek(t);
6200 t = peek(t);
6201 }
6202 }
6203 }
6204 continue;
6205
6206 case TOKidentifier:
6207 if (*haveId)
6208 return false;
6209 *haveId = true;
6210 t = peek(t);
6211 break;
6212
6213 case TOKlparen:
6214 if (!allowAltSyntax)
6215 return false; // Do not recognize C-style declarations.
6216
6217 t = peek(t);
6218
6219 if (t->value == TOKrparen)
6220 return false; // () is not a declarator
6221
6222 /* Regard ( identifier ) as not a declarator
6223 * BUG: what about ( *identifier ) in
6224 * f(*p)(x);
6225 * where f is a class instance with overloaded () ?
6226 * Should we just disallow C-style function pointer declarations?
6227 */
6228 if (t->value == TOKidentifier)
6229 { Token *t2 = peek(t);
6230 if (t2->value == TOKrparen)
6231 return false;
6232 }
6233
6234
6235 if (!isDeclarator(&t, haveId, NULL, TOKrparen))
6236 return false;
6237 t = peek(t);
6238 parens = true;
6239 break;
6240
6241 case TOKdelegate:
6242 case TOKfunction:
6243 t = peek(t);
6244 if (!isParameters(&t))
6245 return false;
6246 skipAttributes(t, &t);
6247 continue;
6248 default: break;
6249 }
6250 break;
6251 }
6252
6253 while (1)
6254 {
6255 switch (t->value)
6256 {
6257#if CARRAYDECL
6258 case TOKlbracket:
6259 parens = false;
6260 t = peek(t);
6261 if (t->value == TOKrbracket)
6262 {
6263 t = peek(t);
6264 }
6265 else if (isDeclaration(t, 0, TOKrbracket, &t))
6266 { // It's an associative array declaration
6267 t = peek(t);
6268 }
6269 else
6270 {
6271 // [ expression ]
6272 if (!isExpression(&t))
6273 return false;
6274 if (t->value != TOKrbracket)
6275 return false;
6276 t = peek(t);
6277 }
6278 continue;
6279#endif
6280
6281 case TOKlparen:
6282 parens = false;
6283 if (Token *tk = peekPastParen(t))
6284 {
6285 if (tk->value == TOKlparen)
6286 {
6287 if (!haveTpl) return false;
6288 *haveTpl = 1;
6289 t = tk;
6290 }
6291 else if (tk->value == TOKassign)
6292 {
6293 if (!haveTpl) return false;
6294 *haveTpl = 1;
6295 *pt = tk;
6296 return true;
6297 }
6298 }
6299 if (!isParameters(&t))
6300 return false;
6301 while (1)
6302 {
6303 switch (t->value)
6304 {
6305 case TOKconst:
6306 case TOKimmutable:
6307 case TOKshared:
6308 case TOKwild:
6309 case TOKpure:
6310 case TOKnothrow:
6311 case TOKreturn:
6312 case TOKscope:
6313 t = peek(t);
6314 continue;
6315 case TOKat:
6316 t = peek(t); // skip '@'
6317 t = peek(t); // skip identifier
6318 continue;
6319 default:
6320 break;
6321 }
6322 break;
6323 }
6324 continue;
6325
6326 case TOKidentifier:
6327 if (t->ident != Id::_body)
6328 goto Ldefault;
6329 /* fall through */
6330
6331 // Valid tokens that follow a declaration
6332 case TOKrparen:
6333 case TOKrbracket:
6334 case TOKassign:
6335 case TOKcomma:
6336 case TOKdotdotdot:
6337 case TOKsemicolon:
6338 case TOKlcurly:
6339 case TOKin:
6340 case TOKout:
6341 case TOKdo:
6342 // The !parens is to disallow unnecessary parentheses
6343 if (!parens && (endtok == TOKreserved || endtok == t->value))
6344 { *pt = t;
6345 return true;
6346 }
6347 return false;
6348
6349 case TOKif:
6350 return haveTpl ? true : false;
6351
6352 default:
6353 Ldefault:
6354 return false;
6355 }
6356 }
6357 assert(0);
6358}
6359
6360
6361bool Parser::isParameters(Token **pt)
6362{ // This code parallels parseParameters()
6363 Token *t = *pt;
6364
6365 //printf("isParameters()\n");
6366 if (t->value != TOKlparen)
6367 return false;
6368
6369 t = peek(t);
6370 for (;1; t = peek(t))
6371 {
6372 L1:
6373 switch (t->value)
6374 {
6375 case TOKrparen:
6376 break;
6377
6378 case TOKdotdotdot:
6379 t = peek(t);
6380 break;
6381
6382 case TOKin:
6383 case TOKout:
6384 case TOKref:
6385 case TOKlazy:
6386 case TOKscope:
6387 case TOKfinal:
6388 case TOKauto:
6389 case TOKreturn:
6390 continue;
6391
6392 case TOKconst:
6393 case TOKimmutable:
6394 case TOKshared:
6395 case TOKwild:
6396 t = peek(t);
6397 if (t->value == TOKlparen)
6398 {
6399 t = peek(t);
6400 if (!isDeclaration(t, 0, TOKrparen, &t))
6401 return false;
6402 t = peek(t); // skip past closing ')'
6403 goto L2;
6404 }
6405 goto L1;
6406
6407 default:
6408 { if (!isBasicType(&t))
6409 return false;
6410 L2:
6411 int tmp = false;
6412 if (t->value != TOKdotdotdot &&
6413 !isDeclarator(&t, &tmp, NULL, TOKreserved))
6414 return false;
6415 if (t->value == TOKassign)
6416 { t = peek(t);
6417 if (!isExpression(&t))
6418 return false;
6419 }
6420 if (t->value == TOKdotdotdot)
6421 {
6422 t = peek(t);
6423 break;
6424 }
6425 }
6426 if (t->value == TOKcomma)
6427 {
6428 continue;
6429 }
6430 break;
6431 }
6432 break;
6433 }
6434 if (t->value != TOKrparen)
6435 return false;
6436 t = peek(t);
6437 *pt = t;
6438 return true;
6439}
6440
6441bool Parser::isExpression(Token **pt)
6442{
6443 // This is supposed to determine if something is an expression.
6444 // What it actually does is scan until a closing right bracket
6445 // is found.
6446
6447 Token *t = *pt;
6448 int brnest = 0;
6449 int panest = 0;
6450 int curlynest = 0;
6451
6452 for (;; t = peek(t))
6453 {
6454 switch (t->value)
6455 {
6456 case TOKlbracket:
6457 brnest++;
6458 continue;
6459
6460 case TOKrbracket:
6461 if (--brnest >= 0)
6462 continue;
6463 break;
6464
6465 case TOKlparen:
6466 panest++;
6467 continue;
6468
6469 case TOKcomma:
6470 if (brnest || panest)
6471 continue;
6472 break;
6473
6474 case TOKrparen:
6475 if (--panest >= 0)
6476 continue;
6477 break;
6478
6479 case TOKlcurly:
6480 curlynest++;
6481 continue;
6482
6483 case TOKrcurly:
6484 if (--curlynest >= 0)
6485 continue;
6486 return false;
6487
6488 case TOKslice:
6489 if (brnest)
6490 continue;
6491 break;
6492
6493 case TOKsemicolon:
6494 if (curlynest)
6495 continue;
6496 return false;
6497
6498 case TOKeof:
6499 return false;
6500
6501 default:
6502 continue;
6503 }
6504 break;
6505 }
6506
6507 *pt = t;
6508 return true;
6509}
6510
6511/*******************************************
6512 * Skip parens, brackets.
6513 * Input:
6514 * t is on opening (
6515 * Output:
6516 * *pt is set to closing token, which is ')' on success
6517 * Returns:
6518 * true successful
6519 * false some parsing error
6520 */
6521
6522bool Parser::skipParens(Token *t, Token **pt)
6523{
6524 if (t->value != TOKlparen)
6525 return false;
6526
6527 int parens = 0;
6528
6529 while (1)
6530 {
6531 switch (t->value)
6532 {
6533 case TOKlparen:
6534 parens++;
6535 break;
6536
6537 case TOKrparen:
6538 parens--;
6539 if (parens < 0)
6540 goto Lfalse;
6541 if (parens == 0)
6542 goto Ldone;
6543 break;
6544
6545 case TOKeof:
6546 goto Lfalse;
6547
6548 default:
6549 break;
6550 }
6551 t = peek(t);
6552 }
6553
6554 Ldone:
6555 if (pt)
6556 *pt = peek(t); // skip found rparen
6557 return true;
6558
6559 Lfalse:
6560 return false;
6561}
6562
6563bool Parser::skipParensIf(Token *t, Token **pt)
6564{
6565 if (t->value != TOKlparen)
6566 {
6567 if (pt)
6568 *pt = t;
6569 return true;
6570 }
6571 return skipParens(t, pt);
6572}
6573
6574/*******************************************
6575 * Skip attributes.
6576 * Input:
6577 * t is on a candidate attribute
6578 * Output:
6579 * *pt is set to first non-attribute token on success
6580 * Returns:
6581 * true successful
6582 * false some parsing error
6583 */
6584
6585bool Parser::skipAttributes(Token *t, Token **pt)
6586{
6587 while (1)
6588 {
6589 switch (t->value)
6590 {
6591 case TOKconst:
6592 case TOKimmutable:
6593 case TOKshared:
6594 case TOKwild:
6595 case TOKfinal:
6596 case TOKauto:
6597 case TOKscope:
6598 case TOKoverride:
6599 case TOKabstract:
6600 case TOKsynchronized:
6601 break;
6602 case TOKdeprecated:
6603 if (peek(t)->value == TOKlparen)
6604 {
6605 t = peek(t);
6606 if (!skipParens(t, &t))
6607 goto Lerror;
6608 // t is on the next of closing parenthesis
6609 continue;
6610 }
6611 break;
6612 case TOKnothrow:
6613 case TOKpure:
6614 case TOKref:
6615 case TOKgshared:
6616 case TOKreturn:
6617 //case TOKmanifest:
6618 break;
6619 case TOKat:
6620 t = peek(t);
6621 if (t->value == TOKidentifier)
6622 {
6623 /* @identifier
6624 * @identifier!arg
6625 * @identifier!(arglist)
6626 * any of the above followed by (arglist)
6627 * @predefined_attribute
6628 */
6629 if (t->ident == Id::property ||
6630 t->ident == Id::nogc ||
6631 t->ident == Id::safe ||
6632 t->ident == Id::trusted ||
6633 t->ident == Id::system ||
6634 t->ident == Id::disable)
6635 break;
6636 t = peek(t);
6637 if (t->value == TOKnot)
6638 {
6639 t = peek(t);
6640 if (t->value == TOKlparen)
6641 {
6642 // @identifier!(arglist)
6643 if (!skipParens(t, &t))
6644 goto Lerror;
6645 // t is on the next of closing parenthesis
6646 }
6647 else
6648 {
6649 // @identifier!arg
6650 // Do low rent skipTemplateArgument
6651 if (t->value == TOKvector)
6652 {
6653 // identifier!__vector(type)
6654 t = peek(t);
6655 if (!skipParens(t, &t))
6656 goto Lerror;
6657 }
6658 else
6659 t = peek(t);
6660 }
6661 }
6662 if (t->value == TOKlparen)
6663 {
6664 if (!skipParens(t, &t))
6665 goto Lerror;
6666 // t is on the next of closing parenthesis
6667 continue;
6668 }
6669 continue;
6670 }
6671 if (t->value == TOKlparen)
6672 {
6673 // @( ArgumentList )
6674 if (!skipParens(t, &t))
6675 goto Lerror;
6676 // t is on the next of closing parenthesis
6677 continue;
6678 }
6679 goto Lerror;
6680 default:
6681 goto Ldone;
6682 }
6683 t = peek(t);
6684 }
6685
6686 Ldone:
6687 if (pt)
6688 *pt = t;
6689 return true;
6690
6691 Lerror:
6692 return false;
6693}
6694
6695/********************************* Expression Parser ***************************/
6696
6697Expression *Parser::parsePrimaryExp()
6698{
6699 Expression *e;
6700 Type *t;
6701 Identifier *id;
6702 Loc loc = token.loc;
6703
6704 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
6705 switch (token.value)
6706 {
6707 case TOKidentifier:
6708 {
6709 Token *t1 = peek(&token);
6710 Token *t2 = peek(t1);
6711 if (t1->value == TOKmin && t2->value == TOKgt)
6712 {
6713 // skip ident.
6714 nextToken();
6715 nextToken();
6716 nextToken();
6717 error("use `.` for member lookup, not `->`");
6718 goto Lerr;
6719 }
6720
6721 if (peekNext() == TOKgoesto)
6722 goto case_delegate;
6723
6724 id = token.ident;
6725 nextToken();
6726 TOK save;
6727 if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
6728 {
6729 // identifier!(template-argument-list)
6730 TemplateInstance *tempinst;
6731 tempinst = new TemplateInstance(loc, id);
6732 tempinst->tiargs = parseTemplateArguments();
6733 e = new ScopeExp(loc, tempinst);
6734 }
6735 else
6736 e = new IdentifierExp(loc, id);
6737 break;
6738 }
6739
6740 case TOKdollar:
6741 if (!inBrackets)
6742 error("'$' is valid only inside [] of index or slice");
6743 e = new DollarExp(loc);
6744 nextToken();
6745 break;
6746
6747 case TOKdot:
6748 // Signal global scope '.' operator with "" identifier
6749 e = new IdentifierExp(loc, Id::empty);
6750 break;
6751
6752 case TOKthis:
6753 e = new ThisExp(loc);
6754 nextToken();
6755 break;
6756
6757 case TOKsuper:
6758 e = new SuperExp(loc);
6759 nextToken();
6760 break;
6761
6762 case TOKint32v:
6763 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
6764 nextToken();
6765 break;
6766
6767 case TOKuns32v:
6768 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
6769 nextToken();
6770 break;
6771
6772 case TOKint64v:
6773 e = new IntegerExp(loc, token.int64value, Type::tint64);
6774 nextToken();
6775 break;
6776
6777 case TOKuns64v:
6778 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
6779 nextToken();
6780 break;
6781
6782 case TOKfloat32v:
6783 e = new RealExp(loc, token.floatvalue, Type::tfloat32);
6784 nextToken();
6785 break;
6786
6787 case TOKfloat64v:
6788 e = new RealExp(loc, token.floatvalue, Type::tfloat64);
6789 nextToken();
6790 break;
6791
6792 case TOKfloat80v:
6793 e = new RealExp(loc, token.floatvalue, Type::tfloat80);
6794 nextToken();
6795 break;
6796
6797 case TOKimaginary32v:
6798 e = new RealExp(loc, token.floatvalue, Type::timaginary32);
6799 nextToken();
6800 break;
6801
6802 case TOKimaginary64v:
6803 e = new RealExp(loc, token.floatvalue, Type::timaginary64);
6804 nextToken();
6805 break;
6806
6807 case TOKimaginary80v:
6808 e = new RealExp(loc, token.floatvalue, Type::timaginary80);
6809 nextToken();
6810 break;
6811
6812 case TOKnull:
6813 e = new NullExp(loc);
6814 nextToken();
6815 break;
6816
6817 case TOKfile:
6818 {
6819 const char *s = loc.filename ? loc.filename : mod->ident->toChars();
6820 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6821 nextToken();
6822 break;
6823 }
6824
6825 case TOKfilefullpath:
6826 {
c5e94699
IB
6827 assert(loc.filename); // __FILE_FULL_PATH__ does not work with an invalid location
6828 const char *s = FileName::toAbsolute(loc.filename);
b4c522fa
IB
6829 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6830 nextToken();
6831 break;
6832 }
6833
6834 case TOKline:
6835 e = new IntegerExp(loc, loc.linnum, Type::tint32);
6836 nextToken();
6837 break;
6838
6839 case TOKmodulestring:
6840 {
6841 const char *s = md ? md->toChars() : mod->toChars();
6842 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6843 nextToken();
6844 break;
6845 }
6846
6847 case TOKfuncstring:
6848 e = new FuncInitExp(loc);
6849 nextToken();
6850 break;
6851
6852 case TOKprettyfunc:
6853 e = new PrettyFuncInitExp(loc);
6854 nextToken();
6855 break;
6856
6857 case TOKtrue:
6858 e = new IntegerExp(loc, 1, Type::tbool);
6859 nextToken();
6860 break;
6861
6862 case TOKfalse:
6863 e = new IntegerExp(loc, 0, Type::tbool);
6864 nextToken();
6865 break;
6866
6867 case TOKcharv:
6868 e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
6869 nextToken();
6870 break;
6871
6872 case TOKwcharv:
6873 e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
6874 nextToken();
6875 break;
6876
6877 case TOKdcharv:
6878 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
6879 nextToken();
6880 break;
6881
6882 case TOKstring:
6883 case TOKxstring:
6884 {
6885 // cat adjacent strings
6886 utf8_t *s = token.ustring;
6887 size_t len = token.len;
6888 unsigned char postfix = token.postfix;
6889 while (1)
6890 {
6891 const Token prev = token;
6892 nextToken();
6893 if (token.value == TOKstring ||
6894 token.value == TOKxstring)
6895 {
6896 if (token.postfix)
6897 { if (token.postfix != postfix)
6898 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
6899 postfix = token.postfix;
6900 }
6901
6902 deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
6903 prev.toChars(), token.toChars());
6904
6905 size_t len1 = len;
6906 size_t len2 = token.len;
6907 len = len1 + len2;
6908 utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
6909 memcpy(s2, s, len1 * sizeof(utf8_t));
6910 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
6911 s = s2;
6912 }
6913 else
6914 break;
6915 }
6916 e = new StringExp(loc, s, len, postfix);
6917 break;
6918 }
6919
6920 case TOKvoid: t = Type::tvoid; goto LabelX;
6921 case TOKint8: t = Type::tint8; goto LabelX;
6922 case TOKuns8: t = Type::tuns8; goto LabelX;
6923 case TOKint16: t = Type::tint16; goto LabelX;
6924 case TOKuns16: t = Type::tuns16; goto LabelX;
6925 case TOKint32: t = Type::tint32; goto LabelX;
6926 case TOKuns32: t = Type::tuns32; goto LabelX;
6927 case TOKint64: t = Type::tint64; goto LabelX;
6928 case TOKuns64: t = Type::tuns64; goto LabelX;
6929 case TOKint128: t = Type::tint128; goto LabelX;
6930 case TOKuns128: t = Type::tuns128; goto LabelX;
6931 case TOKfloat32: t = Type::tfloat32; goto LabelX;
6932 case TOKfloat64: t = Type::tfloat64; goto LabelX;
6933 case TOKfloat80: t = Type::tfloat80; goto LabelX;
6934 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
6935 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
6936 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
6937 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
6938 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
6939 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
6940 case TOKbool: t = Type::tbool; goto LabelX;
6941 case TOKchar: t = Type::tchar; goto LabelX;
6942 case TOKwchar: t = Type::twchar; goto LabelX;
6943 case TOKdchar: t = Type::tdchar; goto LabelX;
6944 LabelX:
6945 nextToken();
6946 if (token.value == TOKlparen)
6947 {
6948 e = new TypeExp(loc, t);
6949 e = new CallExp(loc, e, parseArguments());
6950 break;
6951 }
6952 check(TOKdot, t->toChars());
6953 if (token.value != TOKidentifier)
6954 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
6955 goto Lerr;
6956 }
6957 e = typeDotIdExp(loc, t, token.ident);
6958 nextToken();
6959 break;
6960
6961 case TOKtypeof:
6962 {
6963 t = parseTypeof();
6964 e = new TypeExp(loc, t);
6965 break;
6966 }
6967
6968 case TOKvector:
6969 {
6970 t = parseVector();
6971 e = new TypeExp(loc, t);
6972 break;
6973 }
6974
6975 case TOKtypeid:
6976 {
6977 nextToken();
6978 check(TOKlparen, "typeid");
6979 RootObject *o;
6980 if (isDeclaration(&token, 0, TOKreserved, NULL))
6981 { // argument is a type
6982 o = parseType();
6983 }
6984 else
6985 { // argument is an expression
6986 o = parseAssignExp();
6987 }
6988 check(TOKrparen);
6989 e = new TypeidExp(loc, o);
6990 break;
6991 }
6992
6993 case TOKtraits:
6994 { /* __traits(identifier, args...)
6995 */
6996 Identifier *ident;
6997 Objects *args = NULL;
6998
6999 nextToken();
7000 check(TOKlparen);
7001 if (token.value != TOKidentifier)
7002 { error("__traits(identifier, args...) expected");
7003 goto Lerr;
7004 }
7005 ident = token.ident;
7006 nextToken();
7007 if (token.value == TOKcomma)
7008 args = parseTemplateArgumentList(); // __traits(identifier, args...)
7009 else
7010 check(TOKrparen); // __traits(identifier)
7011
7012 e = new TraitsExp(loc, ident, args);
7013 break;
7014 }
7015
7016 case TOKis:
7017 {
7018 Type *targ;
7019 Identifier *ident = NULL;
7020 Type *tspec = NULL;
7021 TOK tok = TOKreserved;
7022 TOK tok2 = TOKreserved;
7023 TemplateParameters *tpl = NULL;
7024
7025 nextToken();
7026 if (token.value == TOKlparen)
7027 {
7028 nextToken();
7029 targ = parseType(&ident);
7030 if (token.value == TOKcolon || token.value == TOKequal)
7031 {
7032 tok = token.value;
7033 nextToken();
7034 if (tok == TOKequal &&
7035 (token.value == TOKstruct ||
7036 token.value == TOKunion ||
7037 token.value == TOKclass ||
7038 token.value == TOKsuper ||
7039 token.value == TOKenum ||
7040 token.value == TOKinterface ||
c5e94699
IB
7041 token.value == TOKmodule ||
7042 token.value == TOKpackage ||
b4c522fa
IB
7043 token.value == TOKargTypes ||
7044 token.value == TOKparameters ||
7045 (token.value == TOKconst && peek(&token)->value == TOKrparen) ||
7046 (token.value == TOKimmutable && peek(&token)->value == TOKrparen) ||
7047 (token.value == TOKshared && peek(&token)->value == TOKrparen) ||
7048 (token.value == TOKwild && peek(&token)->value == TOKrparen) ||
7049 token.value == TOKfunction ||
7050 token.value == TOKdelegate ||
7051 token.value == TOKreturn ||
7052 (token.value == TOKvector && peek(&token)->value == TOKrparen)))
7053 {
7054 tok2 = token.value;
7055 nextToken();
7056 }
7057 else
7058 {
7059 tspec = parseType();
7060 }
7061 }
7062 if (tspec)
7063 {
7064 if (token.value == TOKcomma)
7065 tpl = parseTemplateParameterList(1);
7066 else
7067 {
7068 tpl = new TemplateParameters();
7069 check(TOKrparen);
7070 }
7071 }
7072 else
7073 check(TOKrparen);
7074 }
7075 else
7076 {
7077 error("(type identifier : specialization) expected following is");
7078 goto Lerr;
7079 }
7080 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
7081 break;
7082 }
7083
7084 case TOKassert:
7085 { Expression *msg = NULL;
7086
7087 nextToken();
7088 check(TOKlparen, "assert");
7089 e = parseAssignExp();
7090 if (token.value == TOKcomma)
7091 {
7092 nextToken();
7093 if (token.value != TOKrparen)
7094 {
7095 msg = parseAssignExp();
7096 if (token.value == TOKcomma)
7097 nextToken();
7098 }
7099 }
7100 check(TOKrparen);
7101 e = new AssertExp(loc, e, msg);
7102 break;
7103 }
7104
7105 case TOKmixin:
7106 {
7107 nextToken();
7108 check(TOKlparen, "mixin");
7109 e = parseAssignExp();
7110 check(TOKrparen);
7111 e = new CompileExp(loc, e);
7112 break;
7113 }
7114
7115 case TOKimport:
7116 {
7117 nextToken();
7118 check(TOKlparen, "import");
7119 e = parseAssignExp();
7120 check(TOKrparen);
7121 e = new ImportExp(loc, e);
7122 break;
7123 }
7124
7125 case TOKnew:
7126 e = parseNewExp(NULL);
7127 break;
7128
7129 case TOKlparen:
7130 {
7131 Token *tk = peekPastParen(&token);
7132 if (skipAttributes(tk, &tk) &&
7133 (tk->value == TOKgoesto || tk->value == TOKlcurly))
7134 {
7135 // (arguments) => expression
7136 // (arguments) { statements... }
7137 goto case_delegate;
7138 }
7139
7140 // ( expression )
7141 nextToken();
7142 e = parseExpression();
7143 e->parens = 1;
7144 check(loc, TOKrparen);
7145 break;
7146 }
7147
7148 case TOKlbracket:
7149 { /* Parse array literals and associative array literals:
7150 * [ value, value, value ... ]
7151 * [ key:value, key:value, key:value ... ]
7152 */
7153 Expressions *values = new Expressions();
7154 Expressions *keys = NULL;
7155
7156 nextToken();
7157 while (token.value != TOKrbracket && token.value != TOKeof)
7158 {
7159 e = parseAssignExp();
2cbc99d1 7160 if (token.value == TOKcolon && (keys || values->length == 0))
b4c522fa
IB
7161 { nextToken();
7162 if (!keys)
7163 keys = new Expressions();
7164 keys->push(e);
7165 e = parseAssignExp();
7166 }
7167 else if (keys)
7168 { error("'key:value' expected for associative array literal");
7169 delete keys;
7170 keys = NULL;
7171 }
7172 values->push(e);
7173 if (token.value == TOKrbracket)
7174 break;
7175 check(TOKcomma);
7176 }
7177 check(loc, TOKrbracket);
7178
7179 if (keys)
7180 e = new AssocArrayLiteralExp(loc, keys, values);
7181 else
255b2d91 7182 e = new ArrayLiteralExp(loc, NULL, values);
b4c522fa
IB
7183 break;
7184 }
7185
7186 case TOKlcurly:
7187 case TOKfunction:
7188 case TOKdelegate:
7189 case_delegate:
7190 {
7191 Dsymbol *s = parseFunctionLiteral();
7192 e = new FuncExp(loc, s);
7193 break;
7194 }
7195
7196 default:
7197 error("expression expected, not '%s'", token.toChars());
7198 Lerr:
7199 // Anything for e, as long as it's not NULL
7200 e = new IntegerExp(loc, 0, Type::tint32);
7201 nextToken();
7202 break;
7203 }
7204 return e;
7205}
7206
7207Expression *Parser::parsePostExp(Expression *e)
7208{
7209 Loc loc;
7210
7211 while (1)
7212 {
7213 loc = token.loc;
7214 switch (token.value)
7215 {
7216 case TOKdot:
7217 nextToken();
7218 if (token.value == TOKidentifier)
7219 { Identifier *id = token.ident;
7220
7221 nextToken();
7222 if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
7223 {
7224 Objects *tiargs = parseTemplateArguments();
7225 e = new DotTemplateInstanceExp(loc, e, id, tiargs);
7226 }
7227 else
7228 e = new DotIdExp(loc, e, id);
7229 continue;
7230 }
7231 else if (token.value == TOKnew)
7232 {
7233 e = parseNewExp(e);
7234 continue;
7235 }
7236 else
7237 error("identifier expected following '.', not '%s'", token.toChars());
7238 break;
7239
7240 case TOKplusplus:
7241 e = new PostExp(TOKplusplus, loc, e);
7242 break;
7243
7244 case TOKminusminus:
7245 e = new PostExp(TOKminusminus, loc, e);
7246 break;
7247
7248 case TOKlparen:
7249 e = new CallExp(loc, e, parseArguments());
7250 continue;
7251
7252 case TOKlbracket:
7253 { // array dereferences:
7254 // array[index]
7255 // array[]
7256 // array[lwr .. upr]
7257 Expression *index;
7258 Expression *upr;
7259 Expressions *arguments = new Expressions();
7260
7261 inBrackets++;
7262 nextToken();
7263 while (token.value != TOKrbracket && token.value != TOKeof)
7264 {
7265 index = parseAssignExp();
7266 if (token.value == TOKslice)
7267 {
7268 // array[..., lwr..upr, ...]
7269 nextToken();
7270 upr = parseAssignExp();
7271 arguments->push(new IntervalExp(loc, index, upr));
7272 }
7273 else
7274 arguments->push(index);
7275 if (token.value == TOKrbracket)
7276 break;
7277 check(TOKcomma);
7278 }
7279 check(TOKrbracket);
7280 inBrackets--;
7281 e = new ArrayExp(loc, e, arguments);
7282 continue;
7283 }
7284
7285 default:
7286 return e;
7287 }
7288 nextToken();
7289 }
7290}
7291
7292Expression *Parser::parseUnaryExp()
7293{
7294 Expression *e;
7295 Loc loc = token.loc;
7296
7297 switch (token.value)
7298 {
7299 case TOKand:
7300 nextToken();
7301 e = parseUnaryExp();
7302 e = new AddrExp(loc, e);
7303 break;
7304
7305 case TOKplusplus:
7306 nextToken();
7307 e = parseUnaryExp();
7308 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7309 e = new PreExp(TOKpreplusplus, loc, e);
7310 break;
7311
7312 case TOKminusminus:
7313 nextToken();
7314 e = parseUnaryExp();
7315 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7316 e = new PreExp(TOKpreminusminus, loc, e);
7317 break;
7318
7319 case TOKmul:
7320 nextToken();
7321 e = parseUnaryExp();
7322 e = new PtrExp(loc, e);
7323 break;
7324
7325 case TOKmin:
7326 nextToken();
7327 e = parseUnaryExp();
7328 e = new NegExp(loc, e);
7329 break;
7330
7331 case TOKadd:
7332 nextToken();
7333 e = parseUnaryExp();
7334 e = new UAddExp(loc, e);
7335 break;
7336
7337 case TOKnot:
7338 nextToken();
7339 e = parseUnaryExp();
7340 e = new NotExp(loc, e);
7341 break;
7342
7343 case TOKtilde:
7344 nextToken();
7345 e = parseUnaryExp();
7346 e = new ComExp(loc, e);
7347 break;
7348
7349 case TOKdelete:
7350 nextToken();
7351 e = parseUnaryExp();
7352 e = new DeleteExp(loc, e, false);
7353 break;
7354
7355 case TOKcast: // cast(type) expression
7356 {
7357 nextToken();
7358 check(TOKlparen);
7359 /* Look for cast(), cast(const), cast(immutable),
7360 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7361 */
7362 unsigned char m = 0;
7363 while (1)
7364 {
7365 switch (token.value)
7366 {
7367 case TOKconst:
7368 if (peekNext() == TOKlparen)
7369 break; // const as type constructor
7370 m |= MODconst; // const as storage class
7371 nextToken();
7372 continue;
7373
7374 case TOKimmutable:
7375 if (peekNext() == TOKlparen)
7376 break;
7377 m |= MODimmutable;
7378 nextToken();
7379 continue;
7380
7381 case TOKshared:
7382 if (peekNext() == TOKlparen)
7383 break;
7384 m |= MODshared;
7385 nextToken();
7386 continue;
7387
7388 case TOKwild:
7389 if (peekNext() == TOKlparen)
7390 break;
7391 m |= MODwild;
7392 nextToken();
7393 continue;
7394
7395 default:
7396 break;
7397 }
7398 break;
7399 }
7400 if (token.value == TOKrparen)
7401 {
7402 nextToken();
7403 e = parseUnaryExp();
7404 e = new CastExp(loc, e, m);
7405 }
7406 else
7407 {
7408 Type *t = parseType(); // cast( type )
7409 t = t->addMod(m); // cast( const type )
7410 check(TOKrparen);
7411 e = parseUnaryExp();
7412 e = new CastExp(loc, e, t);
7413 }
7414 break;
7415 }
7416
7417 case TOKwild:
7418 case TOKshared:
7419 case TOKconst:
7420 case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
7421 {
7422 StorageClass stc = parseTypeCtor();
7423 Type *t = parseBasicType();
7424 t = t->addSTC(stc);
7425 e = new TypeExp(loc, t);
7426 if (stc == 0 && token.value == TOKdot)
7427 {
7428 nextToken();
7429 if (token.value != TOKidentifier)
7430 {
7431 error("identifier expected following (type).");
7432 return NULL;
7433 }
7434 e = typeDotIdExp(loc, t, token.ident);
7435 nextToken();
7436 e = parsePostExp(e);
7437 break;
7438 }
7439 else if (token.value != TOKlparen)
7440 {
7441 error("(arguments) expected following %s", t->toChars());
7442 return e;
7443 }
7444 e = new CallExp(loc, e, parseArguments());
7445 break;
7446 }
7447
7448
7449 case TOKlparen:
7450 { Token *tk;
7451
7452 tk = peek(&token);
7453#if CCASTSYNTAX
7454 // If cast
7455 if (isDeclaration(tk, 0, TOKrparen, &tk))
7456 {
7457 tk = peek(tk); // skip over right parenthesis
7458 switch (tk->value)
7459 {
7460 case TOKnot:
7461 tk = peek(tk);
7462 if (tk->value == TOKis || tk->value == TOKin) // !is or !in
7463 break;
7464 /* fall through */
7465
7466 case TOKdot:
7467 case TOKplusplus:
7468 case TOKminusminus:
7469 case TOKdelete:
7470 case TOKnew:
7471 case TOKlparen:
7472 case TOKidentifier:
7473 case TOKthis:
7474 case TOKsuper:
7475 case TOKint32v:
7476 case TOKuns32v:
7477 case TOKint64v:
7478 case TOKuns64v:
7479 case TOKint128v:
7480 case TOKuns128v:
7481 case TOKfloat32v:
7482 case TOKfloat64v:
7483 case TOKfloat80v:
7484 case TOKimaginary32v:
7485 case TOKimaginary64v:
7486 case TOKimaginary80v:
7487 case TOKnull:
7488 case TOKtrue:
7489 case TOKfalse:
7490 case TOKcharv:
7491 case TOKwcharv:
7492 case TOKdcharv:
7493 case TOKstring:
7494 case TOKfunction:
7495 case TOKdelegate:
7496 case TOKtypeof:
5b74dd0a 7497 case TOKtraits:
b4c522fa
IB
7498 case TOKvector:
7499 case TOKfile:
7500 case TOKfilefullpath:
7501 case TOKline:
7502 case TOKmodulestring:
7503 case TOKfuncstring:
7504 case TOKprettyfunc:
7505 case TOKwchar: case TOKdchar:
7506 case TOKbool: case TOKchar:
7507 case TOKint8: case TOKuns8:
7508 case TOKint16: case TOKuns16:
7509 case TOKint32: case TOKuns32:
7510 case TOKint64: case TOKuns64:
7511 case TOKint128: case TOKuns128:
7512 case TOKfloat32: case TOKfloat64: case TOKfloat80:
7513 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
7514 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
7515 case TOKvoid:
7516 { // (type) una_exp
7517 Type *t;
7518
7519 nextToken();
7520 t = parseType();
7521 check(TOKrparen);
7522
7523 // if .identifier
7524 // or .identifier!( ... )
7525 if (token.value == TOKdot)
7526 {
7527 if (peekNext() != TOKidentifier && peekNext() != TOKnew)
7528 {
7529 error("identifier or new keyword expected following (...).");
7530 return NULL;
7531 }
7532 e = new TypeExp(loc, t);
442b5a66 7533 e->parens = 1;
b4c522fa
IB
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}