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