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