comparison dmd/Parser.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 7427ded8caf7
comparison
equal deleted inserted replaced
-1:000000000000 0:10317f0c89a5
1 module dmd.Parser;
2
3 import dmd.Lexer;
4 import dmd.PostBlitDeclaration;
5 import dmd.FileInitExp;
6 import dmd.LineInitExp;
7 import dmd.EnumMember;
8 import dmd.CtorDeclaration;
9 import dmd.ShlAssignExp;
10 import dmd.ShrAssignExp;
11 import dmd.UshrAssignExp;
12 import dmd.CatAssignExp;
13 import dmd.StaticIfCondition;
14 import dmd.TraitsExp;
15 import dmd.BaseClass;
16 import dmd.AssignExp;
17 import dmd.TemplateInstance;
18 import dmd.NewExp;
19 import dmd.ArrayExp;
20 import dmd.DotTemplateInstanceExp;
21 import dmd.ClassDeclaration;
22 import dmd.NewAnonClassExp;
23 import dmd.InterfaceDeclaration;
24 import dmd.StructDeclaration;
25 import dmd.UnionDeclaration;
26 import dmd.AnonDeclaration;
27 import dmd.StructInitializer;
28 import dmd.ArrayInitializer;
29 import dmd.ExpInitializer;
30 import dmd.TemplateAliasParameter;
31 import dmd.TemplateTupleParameter;
32 import dmd.TemplateThisParameter;
33 import dmd.TemplateValueParameter;
34 import dmd.VoidInitializer;
35 import dmd.VersionCondition;
36 import dmd.DotIdExp;
37 import dmd.DebugCondition;
38 import dmd.PostExp;
39 import dmd.CallExp;
40 import dmd.SliceExp;
41 import dmd.FuncExp;
42 import dmd.AssocArrayLiteralExp;
43 import dmd.ArrayLiteralExp;
44 import dmd.IsExp;
45 import dmd.FuncLiteralDeclaration;
46 import dmd.AssertExp;
47 import dmd.CompileExp;
48 import dmd.FileExp;
49 import dmd.TemplateParameter;
50 import dmd.TemplateTypeParameter;
51 import dmd.TypeidExp;
52 import dmd.StringExp;
53 import dmd.ScopeExp;
54 import dmd.IdentifierExp;
55 import dmd.DollarExp;
56 import dmd.ThisExp;
57 import dmd.SuperExp;
58 import dmd.NullExp;
59 import dmd.RealExp;
60 import dmd.TypeExp;
61 import dmd.AddrExp;
62 import dmd.MOD;
63 import dmd.IntegerExp;
64 import dmd.CastExp;
65 import dmd.PtrExp;
66 import dmd.NegExp;
67 import dmd.XorAssignExp;
68 import dmd.OrAssignExp;
69 import dmd.UAddExp;
70 import dmd.NotExp;
71 import dmd.ComExp;
72 import dmd.DeleteExp;
73 import dmd.MulAssignExp;
74 import dmd.ModAssignExp;
75 import dmd.MinAssignExp;
76 import dmd.DivAssignExp;
77 import dmd.AndAssignExp;
78 import dmd.AddAssignExp;
79 import dmd.ModuleDeclaration;
80 import dmd.CaseRangeStatement;
81 import dmd.CommaExp;
82 import dmd.XorExp;
83 import dmd.CondExp;
84 import dmd.CmpExp;
85 import dmd.InExp;
86 import dmd.OrOrExp;
87 import dmd.OrExp;
88 import dmd.AddExp;
89 import dmd.MinExp;
90 import dmd.CatExp;
91 import dmd.AndAndExp;
92 import dmd.EqualExp;
93 import dmd.ShlExp;
94 import dmd.ShrExp;
95 import dmd.DivExp;
96 import dmd.MulExp;
97 import dmd.ModExp;
98 import dmd.UshrExp;
99 import dmd.IdentityExp;
100 import dmd.AndExp;
101 import dmd.Id;
102 import dmd.LabelStatement;
103 import dmd.ExpStatement;
104 import dmd.StaticAssertStatement;
105 import dmd.DeclarationStatement;
106 import dmd.ScopeStatement;
107 import dmd.PragmaStatement;
108 import dmd.WhileStatement;
109 import dmd.DoStatement;
110 import dmd.ForStatement;
111 import dmd.OnScopeStatement;
112 import dmd.IfStatement;
113 import dmd.SwitchStatement;
114 import dmd.CaseStatement;
115 import dmd.DefaultStatement;
116 import dmd.GotoDefaultStatement;
117 import dmd.GotoCaseStatement;
118 import dmd.GotoStatement;
119 import dmd.SynchronizedStatement;
120 import dmd.WithStatement;
121 import dmd.Catch;
122 import dmd.TryCatchStatement;
123 import dmd.TryFinallyStatement;
124 import dmd.ThrowStatement;
125 import dmd.VolatileStatement;
126 import dmd.ReturnStatement;
127 import dmd.BreakStatement;
128 import dmd.ContinueStatement;
129 import dmd.AsmStatement;
130 import dmd.TypeReturn;
131 import dmd.TypeTypeof;
132 import dmd.ForeachRangeStatement;
133 import dmd.ForeachStatement;
134 import dmd.CompileStatement;
135 import dmd.CompoundStatement;
136 import dmd.ConditionalStatement;
137 import dmd.CompoundDeclarationStatement;
138 import dmd.Argument;
139 import dmd.ParseStatementFlags;
140 import dmd.TypeNext;
141 import dmd.TypeInstance;
142 import dmd.TypePointer;
143 import dmd.TypeDArray;
144 import dmd.TypeAArray;
145 import dmd.TypeSlice;
146 import dmd.TypeSArray;
147 import dmd.TemplateInstance;
148 import dmd.TypeIdentifier;
149 import dmd.VarDeclaration;
150 import dmd.TypeFunction;
151 import dmd.TypeDelegate;
152 import dmd.TY;
153 import dmd.LinkDeclaration;
154 import dmd.Declaration;
155 import dmd.AggregateDeclaration;
156 import dmd.TypedefDeclaration;
157 import dmd.AliasDeclaration;
158 import dmd.LINK;
159 import dmd.Loc;
160 import dmd.Module;
161 import dmd.Array;
162 import dmd.Expression;
163 import dmd.TemplateDeclaration;
164 import dmd.ArrayTypes;
165 import dmd.Dsymbol;
166 import dmd.StaticAssert;
167 import dmd.TypeQualified;
168 import dmd.Condition;
169 import dmd.PostBlitDeclaration;
170 import dmd.DtorDeclaration;
171 import dmd.ConditionalDeclaration;
172 import dmd.StaticCtorDeclaration;
173 import dmd.StaticDtorDeclaration;
174 import dmd.InvariantDeclaration;
175 import dmd.UnitTestDeclaration;
176 import dmd.NewDeclaration;
177 import dmd.DeleteDeclaration;
178 import dmd.EnumDeclaration;
179 import dmd.Import;
180 import dmd.Type;
181 import dmd.Identifier;
182 import dmd.FuncDeclaration;
183 import dmd.Statement;
184 import dmd.Initializer;
185 import dmd.Token;
186 import dmd.TOK;
187 import dmd.ParseStatementFlags;
188 import dmd.PROT;
189 import dmd.STC;
190 import dmd.Util;
191 import dmd.CompileDeclaration;
192 import dmd.StaticIfDeclaration;
193 import dmd.StorageClassDeclaration;
194 import dmd.LinkDeclaration;
195 import dmd.ProtDeclaration;
196 import dmd.AlignDeclaration;
197 import dmd.PragmaDeclaration;
198 import dmd.DebugSymbol;
199 import dmd.VersionSymbol;
200 import dmd.AliasThis;
201 import dmd.Global;
202
203 import core.stdc.string : memcpy;
204 import core.stdc.stdlib : malloc;
205
206 import std.contracts;
207
208 class Parser : Lexer
209 {
210 ModuleDeclaration md;
211 LINK linkage;
212 Loc endloc; // set to location of last right curly
213 int inBrackets; // inside [] of array index or slice
214
215 this(Module module_, ubyte* base, uint length, int doDocComment)
216 {
217 super(module_, base, 0, length, doDocComment, 0);
218 //printf("Parser.Parser()\n");
219 linkage = LINK.LINKd;
220 //nextToken(); // start up the scanner
221 }
222
223 Array parseModule()
224 {
225 Array decldefs;
226
227 // ModuleDeclation leads off
228 if (token.value == TOK.TOKmodule)
229 {
230 ubyte* comment = token.blockComment;
231 bool safe = false;
232
233 nextToken();
234 version (DMDV2) {
235 if (token.value == TOK.TOKlparen)
236 {
237 nextToken();
238 if (token.value != TOK.TOKidentifier)
239 {
240 error("module (system) identifier expected");
241 goto Lerr;
242 }
243 Identifier id = token.ident;
244
245 if (id is Id.system)
246 safe = true;
247 else
248 error("(safe) expected, not %s", id.toChars());
249 nextToken();
250 check(TOK.TOKrparen);
251 }
252 }
253
254 if (token.value != TOK.TOKidentifier)
255 {
256 error("Identifier expected following module");
257 goto Lerr;
258 }
259 else
260 {
261 Array a = null;
262 Identifier id = token.ident;
263 while (nextToken() == TOK.TOKdot)
264 {
265 if (!a)
266 a = new Array();
267 a.push(cast(void*)id);
268 nextToken();
269 if (token.value != TOK.TOKidentifier)
270 { error("Identifier expected following package");
271 goto Lerr;
272 }
273 id = token.ident;
274 }
275
276 md = new ModuleDeclaration(a, id, safe);
277
278 if (token.value != TOK.TOKsemicolon)
279 error("';' expected following module declaration instead of %s", token.toChars());
280
281 nextToken();
282 addComment(mod, comment);
283 }
284 }
285
286 decldefs = parseDeclDefs(0);
287 if (token.value != TOK.TOKeof)
288 {
289 error("unrecognized declaration");
290 goto Lerr;
291 }
292
293 return decldefs;
294
295 Lerr:
296 while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof)
297 nextToken();
298
299 nextToken();
300 return new Array();
301 }
302
303 Array parseDeclDefs(int once)
304 {
305 Dsymbol s;
306 Array decldefs;
307 Array a;
308 Array aelse;
309 PROT prot;
310 STC stc;
311 STC storageClass;
312 Condition condition;
313 ubyte* comment;
314
315 //printf("Parser.parseDeclDefs()\n");
316 decldefs = new Array();
317 do
318 {
319 comment = token.blockComment;
320 storageClass = STC.STCundefined;
321 switch (token.value)
322 {
323 case TOK.TOKenum:
324 { /* Determine if this is a manifest constant declaration,
325 * or a conventional enum.
326 */
327 Token *t = peek(&token);
328 if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon)
329 s = parseEnum();
330 else if (t.value != TOK.TOKidentifier)
331 goto Ldeclaration;
332 else
333 {
334 t = peek(t);
335 if (t.value == TOK.TOKlcurly || t.value == TOK.TOKcolon ||
336 t.value == TOK.TOKsemicolon)
337 s = parseEnum();
338 else
339 goto Ldeclaration;
340 }
341 break;
342 }
343
344 case TOK.TOKstruct:
345 case TOK.TOKunion:
346 case TOK.TOKclass:
347 case TOK.TOKinterface:
348 s = parseAggregate();
349 break;
350
351 case TOK.TOKimport:
352 s = parseImport(decldefs, 0);
353 break;
354
355 case TOK.TOKtemplate:
356 s = cast(Dsymbol)parseTemplateDeclaration();
357 break;
358
359 case TOK.TOKmixin:
360 { Loc loc = this.loc;
361 if (peek(&token).value == TOK.TOKlparen)
362 { // mixin(string)
363 nextToken();
364 check(TOK.TOKlparen, "mixin");
365 Expression e = parseAssignExp();
366 check(TOK.TOKrparen);
367 check(TOK.TOKsemicolon);
368 s = new CompileDeclaration(loc, e);
369 break;
370 }
371 s = parseMixin();
372 break;
373 }
374
375 case TOK.TOKwchar: case TOK.TOKdchar:
376 case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
377 case TOK.TOKint8: case TOK.TOKuns8:
378 case TOK.TOKint16: case TOK.TOKuns16:
379 case TOK.TOKint32: case TOK.TOKuns32:
380 case TOK.TOKint64: case TOK.TOKuns64:
381 case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
382 case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
383 case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
384 case TOK.TOKvoid:
385 case TOK.TOKalias:
386 case TOK.TOKtypedef:
387 case TOK.TOKidentifier:
388 case TOK.TOKtypeof:
389 case TOK.TOKdot:
390 Ldeclaration:
391 a = parseDeclarations(STC.STCundefined);
392 decldefs.append(a);
393 continue;
394
395 case TOK.TOKthis:
396 s = parseCtor();
397 break;
398
399 static if (false) { // dead end, use this(this){} instead
400 case TOK.TOKassign:
401 s = parsePostBlit();
402 break;
403 }
404 case TOK.TOKtilde:
405 s = parseDtor();
406 break;
407
408 case TOK.TOKinvariant:
409 { Token *t;
410 t = peek(&token);
411 if (t.value == TOK.TOKlparen)
412 {
413 if (peek(t).value == TOK.TOKrparen)
414 // invariant() forms start of class invariant
415 s = parseInvariant();
416 else
417 // invariant(type)
418 goto Ldeclaration;
419 }
420 else
421 {
422 stc = STC.STCimmutable;
423 goto Lstc;
424 }
425 break;
426 }
427
428 case TOK.TOKunittest:
429 s = parseUnitTest();
430 break;
431
432 case TOK.TOKnew:
433 s = parseNew();
434 break;
435
436 case TOK.TOKdelete:
437 s = parseDelete();
438 break;
439
440 case TOK.TOKeof:
441 case TOK.TOKrcurly:
442 return decldefs;
443
444 case TOK.TOKstatic:
445 nextToken();
446 if (token.value == TOK.TOKthis)
447 s = parseStaticCtor();
448 else if (token.value == TOK.TOKtilde)
449 s = parseStaticDtor();
450 else if (token.value == TOK.TOKassert)
451 s = parseStaticAssert();
452 else if (token.value == TOK.TOKif)
453 { condition = parseStaticIfCondition();
454 a = parseBlock();
455 aelse = null;
456 if (token.value == TOK.TOKelse)
457 { nextToken();
458 aelse = parseBlock();
459 }
460 s = new StaticIfDeclaration(condition, a, aelse);
461 break;
462 }
463 else if (token.value == TOK.TOKimport)
464 {
465 s = parseImport(decldefs, 1);
466 }
467 else
468 { stc = STC.STCstatic;
469 goto Lstc2;
470 }
471 break;
472
473 case TOK.TOKconst:
474 if (peek(&token).value == TOK.TOKlparen)
475 goto Ldeclaration;
476 stc = STC.STCconst;
477 goto Lstc;
478
479 case TOK.TOKimmutable:
480 if (peek(&token).value == TOK.TOKlparen)
481 goto Ldeclaration;
482 stc = STC.STCimmutable;
483 goto Lstc;
484
485 case TOK.TOKshared:
486 if (peek(&token).value == TOK.TOKlparen)
487 goto Ldeclaration;
488 stc = STC.STCshared;
489 goto Lstc;
490
491 case TOK.TOKfinal: stc = STC.STCfinal; goto Lstc;
492 case TOK.TOKauto: stc = STC.STCauto; goto Lstc;
493 case TOK.TOKscope: stc = STC.STCscope; goto Lstc;
494 case TOK.TOKoverride: stc = STC.STCoverride; goto Lstc;
495 case TOK.TOKabstract: stc = STC.STCabstract; goto Lstc;
496 case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc;
497 case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto Lstc;
498 version (DMDV2) {
499 case TOK.TOKnothrow: stc = STC.STCnothrow; goto Lstc;
500 case TOK.TOKpure: stc = STC.STCpure; goto Lstc;
501 case TOK.TOKref: stc = STC.STCref; goto Lstc;
502 case TOK.TOKtls: stc = STC.STCtls; goto Lstc;
503 case TOK.TOKgshared:
504 stc = STC.STCgshared; goto Lstc;
505 //case TOK.TOKmanifest: stc = STC.STCmanifest; goto Lstc;
506 }
507
508 Lstc:
509 if (storageClass & stc)
510 error("redundant storage class %s", Token.toChars(token.value));
511 composeStorageClass(storageClass | stc);
512 nextToken();
513 Lstc2:
514 storageClass |= stc;
515 switch (token.value)
516 {
517 case TOK.TOKconst:
518 case TOK.TOKinvariant:
519 case TOK.TOKimmutable:
520 case TOK.TOKshared:
521 // If followed by a (, it is not a storage class
522 if (peek(&token).value == TOK.TOKlparen)
523 break;
524 if (token.value == TOK.TOKconst)
525 stc = STC.STCconst;
526 else if (token.value == TOK.TOKshared)
527 stc = STC.STCshared;
528 else
529 stc = STC.STCimmutable;
530 goto Lstc;
531 case TOK.TOKfinal: stc = STC.STCfinal; goto Lstc;
532 case TOK.TOKauto: stc = STC.STCauto; goto Lstc;
533 case TOK.TOKscope: stc = STC.STCscope; goto Lstc;
534 case TOK.TOKoverride: stc = STC.STCoverride; goto Lstc;
535 case TOK.TOKabstract: stc = STC.STCabstract; goto Lstc;
536 case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto Lstc;
537 case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto Lstc;
538 case TOK.TOKnothrow: stc = STC.STCnothrow; goto Lstc;
539 case TOK.TOKpure: stc = STC.STCpure; goto Lstc;
540 case TOK.TOKref: stc = STC.STCref; goto Lstc;
541 case TOK.TOKtls: stc = STC.STCtls; goto Lstc;
542 case TOK.TOKgshared: stc = STC.STCgshared; goto Lstc;
543 //case TOK.TOKmanifest: stc = STC.STCmanifest; goto Lstc;
544 default:
545 break;
546 }
547
548 /* Look for auto initializers:
549 * storage_class identifier = initializer;
550 */
551 if (token.value == TOK.TOKidentifier &&
552 peek(&token).value == TOK.TOKassign)
553 {
554 a = parseAutoDeclarations(storageClass, comment);
555 decldefs.append(a);
556 continue;
557 }
558
559 /* Look for return type inference for template functions.
560 */
561 Token *tk;
562 if (token.value == TOK.TOKidentifier &&
563 (tk = peek(&token)).value == TOK.TOKlparen &&
564 skipParens(tk, &tk) &&
565 (peek(tk).value == TOK.TOKlparen ||
566 peek(tk).value == TOK.TOKlcurly)
567 )
568 {
569 a = parseDeclarations(storageClass);
570 decldefs.append(a);
571 continue;
572 }
573 a = parseBlock();
574 s = new StorageClassDeclaration(storageClass, a);
575 break;
576
577 case TOK.TOKextern:
578 if (peek(&token).value != TOK.TOKlparen)
579 {
580 stc = STC.STCextern;
581 goto Lstc;
582 }
583 {
584 LINK linksave = linkage;
585 linkage = parseLinkage();
586 a = parseBlock();
587 s = new LinkDeclaration(linkage, a);
588 linkage = linksave;
589 break;
590 }
591
592 case TOK.TOKprivate: prot = PROT.PROTprivate; goto Lprot;
593 case TOK.TOKpackage: prot = PROT.PROTpackage; goto Lprot;
594 case TOK.TOKprotected: prot = PROT.PROTprotected; goto Lprot;
595 case TOK.TOKpublic: prot = PROT.PROTpublic; goto Lprot;
596 case TOK.TOKexport: prot = PROT.PROTexport; goto Lprot;
597 Lprot:
598 nextToken();
599 switch (token.value)
600 {
601 case TOK.TOKprivate:
602 case TOK.TOKpackage:
603 case TOK.TOKprotected:
604 case TOK.TOKpublic:
605 case TOK.TOKexport:
606 error("redundant protection attribute");
607 break;
608 default:
609 break;
610 }
611 a = parseBlock();
612 s = new ProtDeclaration(prot, a);
613 break;
614
615 case TOK.TOKalign:
616 { uint n;
617
618 s = null;
619 nextToken();
620 if (token.value == TOK.TOKlparen)
621 {
622 nextToken();
623 if (token.value == TOK.TOKint32v)
624 n = cast(uint)token.uns64value;
625 else
626 { error("integer expected, not %s", token.toChars());
627 n = 1;
628 }
629 nextToken();
630 check(TOK.TOKrparen);
631 }
632 else
633 n = global.structalign; // default
634
635 a = parseBlock();
636 s = new AlignDeclaration(n, a);
637 break;
638 }
639
640 case TOK.TOKpragma:
641 { Identifier ident;
642 Expressions args = null;
643
644 nextToken();
645 check(TOK.TOKlparen);
646 if (token.value != TOK.TOKidentifier)
647 { error("pragma(identifier expected");
648 goto Lerror;
649 }
650 ident = token.ident;
651 nextToken();
652 if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen)
653 args = parseArguments(); // pragma(identifier, args...)
654 else
655 check(TOK.TOKrparen); // pragma(identifier)
656
657 if (token.value == TOK.TOKsemicolon)
658 a = null;
659 else
660 a = parseBlock();
661 s = new PragmaDeclaration(loc, ident, args, a);
662 break;
663 }
664
665 case TOK.TOKdebug:
666 nextToken();
667 if (token.value == TOK.TOKassign)
668 {
669 nextToken();
670 if (token.value == TOK.TOKidentifier)
671 s = new DebugSymbol(loc, token.ident);
672 else if (token.value == TOK.TOKint32v)
673 s = new DebugSymbol(loc, cast(uint)token.uns64value);
674 else
675 { error("identifier or integer expected, not %s", token.toChars());
676 s = null;
677 }
678 nextToken();
679 if (token.value != TOK.TOKsemicolon)
680 error("semicolon expected");
681 nextToken();
682 break;
683 }
684
685 condition = parseDebugCondition();
686 goto Lcondition;
687
688 case TOK.TOKversion:
689 nextToken();
690 if (token.value == TOK.TOKassign)
691 {
692 nextToken();
693 if (token.value == TOK.TOKidentifier)
694 s = new VersionSymbol(loc, token.ident);
695 else if (token.value == TOK.TOKint32v)
696 s = new VersionSymbol(loc, cast(uint)token.uns64value);
697 else
698 { error("identifier or integer expected, not %s", token.toChars());
699 s = null;
700 }
701 nextToken();
702 if (token.value != TOK.TOKsemicolon)
703 error("semicolon expected");
704 nextToken();
705 break;
706 }
707 condition = parseVersionCondition();
708 goto Lcondition;
709
710 Lcondition:
711 a = parseBlock();
712 aelse = null;
713 if (token.value == TOK.TOKelse)
714 { nextToken();
715 aelse = parseBlock();
716 }
717 s = new ConditionalDeclaration(condition, a, aelse);
718 break;
719
720 case TOK.TOKsemicolon: // empty declaration
721 nextToken();
722 continue;
723
724 default:
725 error("Declaration expected, not '%s'",token.toChars());
726 Lerror:
727 while (token.value != TOK.TOKsemicolon && token.value != TOK.TOKeof)
728 nextToken();
729 nextToken();
730 s = null;
731 continue;
732 }
733 if (s)
734 { decldefs.push(cast(void*)s);
735 addComment(s, comment);
736 }
737 } while (!once);
738 return decldefs;
739 }
740
741 /*****************************************
742 * Parse auto declarations of the form:
743 * storageClass ident = init, ident = init, ... ;
744 * and return the array of them.
745 * Starts with token on the first ident.
746 * Ends with scanner past closing ';'
747 */
748 version (DMDV2) {
749 Array parseAutoDeclarations(STC storageClass, ubyte* comment)
750 {
751 Array a = new Array;
752
753 while (true)
754 {
755 Identifier ident = token.ident;
756 nextToken(); // skip over ident
757 assert(token.value == TOKassign);
758 nextToken(); // skip over '='
759 Initializer init = parseInitializer();
760 VarDeclaration v = new VarDeclaration(loc, null, ident, init);
761 v.storage_class = storageClass;
762 a.push(cast(void*)v);
763 if (token.value == TOKsemicolon)
764 {
765 nextToken();
766 addComment(v, comment);
767 }
768 else if (token.value == TOKcomma)
769 {
770 nextToken();
771 if (token.value == TOKidentifier &&
772 peek(&token).value == TOKassign)
773 {
774 addComment(v, comment);
775 continue;
776 }
777 else
778 error("Identifier expected following comma");
779 }
780 else
781 error("semicolon expected following auto declaration, not '%s'", token.toChars());
782 break;
783 }
784 return a;
785 }
786 }
787 /********************************************
788 * Parse declarations after an align, protection, or extern decl.
789 */
790 Array parseBlock()
791 {
792 Array a = null;
793 Dsymbol ss;
794
795 //printf("parseBlock()\n");
796 switch (token.value)
797 {
798 case TOK.TOKsemicolon:
799 error("declaration expected following attribute, not ';'");
800 nextToken();
801 break;
802
803 case TOK.TOKeof:
804 error("declaration expected following attribute, not EOF");
805 break;
806
807 case TOK.TOKlcurly:
808 nextToken();
809 a = parseDeclDefs(0);
810 if (token.value != TOK.TOKrcurly)
811 { /* { */
812 error("matching '}' expected, not %s", token.toChars());
813 }
814 else
815 nextToken();
816 break;
817
818 case TOK.TOKcolon:
819 nextToken();
820 static if (false) {
821 a = null;
822 } else {
823 a = parseDeclDefs(0); // grab declarations up to closing curly bracket
824 }
825 break;
826
827 default:
828 a = parseDeclDefs(1);
829 break;
830 }
831 return a;
832 }
833
834 void composeStorageClass(STC stc)
835 {
836 STC u = stc;
837 u &= STC.STCconst | STC.STCimmutable | STC.STCmanifest;
838 if (u & (u - 1))
839 error("conflicting storage class %s", Token.toChars(token.value));
840
841 u = stc;
842 u &= STC.STCgshared | STC.STCshared | STC.STCtls;
843 if (u & (u - 1))
844 error("conflicting storage class %s", Token.toChars(token.value));
845 }
846
847 /**************************************
848 * Parse constraint.
849 * Constraint is of the form:
850 * if ( ConstraintExpression )
851 */
852 version (DMDV2) {
853 Expression parseConstraint()
854 {
855 Expression e = null;
856
857 if (token.value == TOKif)
858 {
859 nextToken(); // skip over 'if'
860 check(TOKlparen);
861 e = parseExpression();
862 check(TOKrparen);
863 }
864 return e;
865 }
866 }
867 /**************************************
868 * Parse a TemplateDeclaration.
869 */
870 TemplateDeclaration parseTemplateDeclaration()
871 {
872 TemplateDeclaration tempdecl;
873 Identifier id;
874 TemplateParameters tpl;
875 Array decldefs;
876 Expression constraint = null;
877 Loc loc = this.loc;
878
879 nextToken();
880 if (token.value != TOKidentifier)
881 {
882 error("TemplateIdentifier expected following template");
883 goto Lerr;
884 }
885 id = token.ident;
886 nextToken();
887 tpl = parseTemplateParameterList();
888 if (!tpl)
889 goto Lerr;
890
891 constraint = parseConstraint();
892
893 if (token.value != TOKlcurly)
894 {
895 error("members of template declaration expected");
896 goto Lerr;
897 }
898 else
899 {
900 nextToken();
901 decldefs = parseDeclDefs(0);
902 if (token.value != TOKrcurly)
903 {
904 error("template member expected");
905 goto Lerr;
906 }
907 nextToken();
908 }
909
910 tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
911 return tempdecl;
912
913 Lerr:
914 return null;
915 }
916
917 /******************************************
918 * Parse template parameter list.
919 * Input:
920 * flag 0: parsing "( list )"
921 * 1: parsing non-empty "list )"
922 */
923 TemplateParameters parseTemplateParameterList(int flag = 0)
924 {
925 TemplateParameters tpl = new TemplateParameters();
926
927 if (!flag && token.value != TOKlparen)
928 {
929 error("parenthesized TemplateParameterList expected following TemplateIdentifier");
930 goto Lerr;
931 }
932 nextToken();
933
934 // Get array of TemplateParameters
935 if (flag || token.value != TOKrparen)
936 {
937 int isvariadic = 0;
938
939 while (true)
940 {
941 TemplateParameter tp;
942 Identifier tp_ident = null;
943 Type tp_spectype = null;
944 Type tp_valtype = null;
945 Type tp_defaulttype = null;
946 Expression tp_specvalue = null;
947 Expression tp_defaultvalue = null;
948 Token* t;
949
950 // Get TemplateParameter
951
952 // First, look ahead to see if it is a TypeParameter or a ValueParameter
953 t = peek(&token);
954 if (token.value == TOKalias)
955 {
956 // AliasParameter
957 nextToken();
958 Type spectype = null;
959 if (isDeclaration(&token, 2, TOKreserved, null))
960 {
961 spectype = parseType(&tp_ident);
962 }
963 else
964 {
965 if (token.value != TOKidentifier)
966 {
967 error("identifier expected for template alias parameter");
968 goto Lerr;
969 }
970 tp_ident = token.ident;
971 nextToken();
972 }
973 Object spec = null;
974 if (token.value == TOKcolon) // : Type
975 {
976 nextToken();
977 if (isDeclaration(&token, 0, TOKreserved, null))
978 spec = parseType();
979 else
980 spec = parseCondExp();
981 }
982 Object def = null;
983 if (token.value == TOKassign) // = Type
984 {
985 nextToken();
986 if (isDeclaration(&token, 0, TOKreserved, null))
987 def = parseType();
988 else
989 def = parseCondExp();
990 }
991 tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
992 }
993 else if (t.value == TOKcolon || t.value == TOKassign ||
994 t.value == TOKcomma || t.value == TOKrparen)
995 { // TypeParameter
996 if (token.value != TOKidentifier)
997 { error("identifier expected for template type parameter");
998 goto Lerr;
999 }
1000 tp_ident = token.ident;
1001 nextToken();
1002 if (token.value == TOKcolon) // : Type
1003 {
1004 nextToken();
1005 tp_spectype = parseType();
1006 }
1007 if (token.value == TOKassign) // = Type
1008 {
1009 nextToken();
1010 tp_defaulttype = parseType();
1011 }
1012 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1013 }
1014 else if (token.value == TOKidentifier && t.value == TOKdotdotdot)
1015 { // ident...
1016 if (isvariadic)
1017 error("variadic template parameter must be last");
1018 isvariadic = 1;
1019 tp_ident = token.ident;
1020 nextToken();
1021 nextToken();
1022 tp = new TemplateTupleParameter(loc, tp_ident);
1023 }
1024 /// version (DMDV2) {
1025 else if (token.value == TOKthis)
1026 { // ThisParameter
1027 nextToken();
1028 if (token.value != TOKidentifier)
1029 { error("identifier expected for template this parameter");
1030 goto Lerr;
1031 }
1032 tp_ident = token.ident;
1033 nextToken();
1034 if (token.value == TOKcolon) // : Type
1035 {
1036 nextToken();
1037 tp_spectype = parseType();
1038 }
1039 if (token.value == TOKassign) // = Type
1040 {
1041 nextToken();
1042 tp_defaulttype = parseType();
1043 }
1044 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1045 }
1046 /// }
1047 else
1048 { // ValueParameter
1049 tp_valtype = parseType(&tp_ident);
1050 if (!tp_ident)
1051 {
1052 error("identifier expected for template value parameter");
1053 tp_ident = new Identifier("error", TOKidentifier);
1054 }
1055 if (token.value == TOKcolon) // : CondExpression
1056 {
1057 nextToken();
1058 tp_specvalue = parseCondExp();
1059 }
1060 if (token.value == TOKassign) // = CondExpression
1061 {
1062 nextToken();
1063 tp_defaultvalue = parseDefaultInitExp();
1064 }
1065 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1066 }
1067 tpl.push(cast(void*)tp);
1068 if (token.value != TOKcomma)
1069 break;
1070 nextToken();
1071 }
1072 }
1073 check(TOKrparen);
1074
1075 Lerr:
1076 return tpl;
1077 }
1078
1079 Dsymbol parseMixin()
1080 {
1081 assert(false);
1082 }
1083
1084 /******************************************
1085 * Parse template argument list.
1086 * Input:
1087 * current token is opening '('
1088 * Output:
1089 * current token is one after closing ')'
1090 */
1091 Objects parseTemplateArgumentList()
1092 {
1093 //printf("Parser.parseTemplateArgumentList()\n");
1094 if (token.value != TOKlparen && token.value != TOKlcurly)
1095 {
1096 error("!(TemplateArgumentList) expected following TemplateIdentifier");
1097 return new Objects();
1098 }
1099 return parseTemplateArgumentList2();
1100 }
1101
1102 Objects parseTemplateArgumentList2()
1103 {
1104 //printf("Parser.parseTemplateArgumentList2()\n");
1105 Objects tiargs = new Objects();
1106 TOK endtok = TOKrparen;
1107 nextToken();
1108
1109 // Get TemplateArgumentList
1110 if (token.value != endtok)
1111 {
1112 while (1)
1113 {
1114 // See if it is an Expression or a Type
1115 if (isDeclaration(&token, 0, TOKreserved, null))
1116 { // Template argument is a type
1117 Type ta = parseType();
1118 tiargs.push(cast(void*)ta);
1119 }
1120 else
1121 { // Template argument is an expression
1122 Expression ea = parseAssignExp();
1123
1124 if (ea.op == TOKfunction)
1125 {
1126 FuncLiteralDeclaration fd = (cast(FuncExp)ea).fd;
1127 if (fd.type.ty == Tfunction)
1128 {
1129 TypeFunction tf = cast(TypeFunction)fd.type;
1130 /* If there are parameters that consist of only an identifier,
1131 * rather than assuming the identifier is a type, as we would
1132 * for regular function declarations, assume the identifier
1133 * is the parameter name, and we're building a template with
1134 * a deduced type.
1135 */
1136 TemplateParameters tpl = null;
1137 for (int i = 0; i < tf.parameters.dim; i++)
1138 {
1139 Argument param = cast(Argument)tf.parameters.data[i];
1140 if (param.ident is null &&
1141 param.type &&
1142 param.type.ty == Tident &&
1143 (cast(TypeIdentifier)param.type).idents.dim == 0
1144 )
1145 {
1146 /* Switch parameter type to parameter identifier,
1147 * parameterize with template type parameter _T
1148 */
1149 TypeIdentifier pt = cast(TypeIdentifier)param.type;
1150 param.ident = pt.ident;
1151 Identifier id = Lexer.uniqueId("__T");
1152 param.type = new TypeIdentifier(pt.loc, id);
1153 TemplateParameter tp = new TemplateTypeParameter(fd.loc, id, null, null);
1154 if (!tpl)
1155 tpl = new TemplateParameters();
1156 tpl.push(cast(void*)tp);
1157 }
1158 }
1159
1160 if (tpl)
1161 {
1162 // Wrap a template around function fd
1163 Array decldefs = new Array();
1164 decldefs.push(cast(void*)fd);
1165 TemplateDeclaration tempdecl = new TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs);
1166 tempdecl.literal = 1; // it's a template 'literal'
1167 tiargs.push(cast(void*)tempdecl);
1168 goto L1;
1169 }
1170 }
1171 }
1172
1173 tiargs.push(cast(void*)ea);
1174 }
1175 L1:
1176 if (token.value != TOKcomma)
1177 break;
1178 nextToken();
1179 }
1180 }
1181 check(endtok, "template argument list");
1182 return tiargs;
1183 }
1184
1185 Objects parseTemplateArgument()
1186 {
1187 assert(false);
1188 }
1189
1190 /**********************************
1191 * Parse a static assertion.
1192 */
1193 StaticAssert parseStaticAssert()
1194 {
1195 Loc loc = this.loc;
1196 Expression exp;
1197 Expression msg = null;
1198
1199 //printf("parseStaticAssert()\n");
1200 nextToken();
1201 check(TOK.TOKlparen);
1202 exp = parseAssignExp();
1203 if (token.value == TOK.TOKcomma)
1204 {
1205 nextToken();
1206 msg = parseAssignExp();
1207 }
1208
1209 check(TOK.TOKrparen);
1210 check(TOK.TOKsemicolon);
1211
1212 return new StaticAssert(loc, exp, msg);
1213 }
1214
1215 TypeQualified parseTypeof()
1216 {
1217 TypeQualified t;
1218 Loc loc = this.loc;
1219
1220 nextToken();
1221 check(TOK.TOKlparen);
1222 if (token.value == TOK.TOKreturn) // typeof(return)
1223 {
1224 nextToken();
1225 t = new TypeReturn(loc);
1226 }
1227 else
1228 {
1229 Expression exp = parseExpression(); // typeof(expression)
1230 t = new TypeTypeof(loc, exp);
1231 }
1232 check(TOK.TOKrparen);
1233 return t;
1234 }
1235
1236 /***********************************
1237 * Parse extern (linkage)
1238 * The parser is on the 'extern' token.
1239 */
1240 LINK parseLinkage()
1241 {
1242 LINK link = LINK.LINKdefault;
1243 nextToken();
1244 assert(token.value == TOK.TOKlparen);
1245 nextToken();
1246 if (token.value == TOK.TOKidentifier)
1247 {
1248 Identifier id = token.ident;
1249
1250 nextToken();
1251 if (id == Id.Windows)
1252 link = LINK.LINKwindows;
1253 else if (id == Id.Pascal)
1254 link = LINK.LINKpascal;
1255 else if (id == Id.D)
1256 link = LINK.LINKd;
1257 else if (id == Id.C)
1258 {
1259 link = LINK.LINKc;
1260 if (token.value == TOK.TOKplusplus)
1261 {
1262 link = LINK.LINKcpp;
1263 nextToken();
1264 }
1265 }
1266 else if (id == Id.System)
1267 {
1268 version (_WIN32) {
1269 link = LINK.LINKwindows;
1270 } else {
1271 link = LINK.LINKc;
1272 }
1273 }
1274 else
1275 {
1276 error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
1277 link = LINK.LINKd;
1278 }
1279 }
1280 else
1281 {
1282 link = LINK.LINKd; // default
1283 }
1284 check(TOK.TOKrparen);
1285
1286 return link;
1287 }
1288
1289
1290 /**************************************
1291 * Parse a debug conditional
1292 */
1293 Condition parseDebugCondition()
1294 {
1295 Condition c;
1296
1297 if (token.value == TOK.TOKlparen)
1298 {
1299 nextToken();
1300 uint level = 1;
1301 Identifier id = null;
1302
1303 if (token.value == TOK.TOKidentifier)
1304 id = token.ident;
1305 else if (token.value == TOK.TOKint32v)
1306 level = cast(uint)token.uns64value;
1307 else
1308 error("identifier or integer expected, not %s", token.toChars());
1309
1310 nextToken();
1311 check(TOK.TOKrparen);
1312
1313 c = new DebugCondition(mod, level, id);
1314 }
1315 else
1316 c = new DebugCondition(mod, 1, null);
1317
1318 return c;
1319 }
1320
1321 /**************************************
1322 * Parse a version conditional
1323 */
1324 Condition parseVersionCondition()
1325 {
1326 Condition c;
1327 uint level = 1;
1328 Identifier id = null;
1329
1330 if (token.value == TOK.TOKlparen)
1331 {
1332 nextToken();
1333 if (token.value == TOK.TOKidentifier)
1334 id = token.ident;
1335 else if (token.value == TOK.TOKint32v)
1336 level = cast(uint)token.uns64value;
1337 else {
1338 version (DMDV2) {
1339 /* Allow:
1340 * version (unittest)
1341 * even though unittest is a keyword
1342 */
1343 if (token.value == TOK.TOKunittest)
1344 id = Lexer.idPool(Token.toChars(TOK.TOKunittest));
1345 else
1346 error("identifier or integer expected, not %s", token.toChars());
1347 } else {
1348 error("identifier or integer expected, not %s", token.toChars());
1349 }
1350 }
1351 nextToken();
1352 check(TOK.TOKrparen);
1353 }
1354 else
1355 error("(condition) expected following version");
1356
1357 c = new VersionCondition(mod, level, id);
1358
1359 return c;
1360 }
1361
1362 /***********************************************
1363 * static if (expression)
1364 * body
1365 * else
1366 * body
1367 */
1368 Condition parseStaticIfCondition()
1369 {
1370 Expression exp;
1371 Condition condition;
1372 Array aif;
1373 Array aelse;
1374 Loc loc = this.loc;
1375
1376 nextToken();
1377 if (token.value == TOKlparen)
1378 {
1379 nextToken();
1380 exp = parseAssignExp();
1381 check(TOKrparen);
1382 }
1383 else
1384 {
1385 error("(expression) expected following static if");
1386 exp = null;
1387 }
1388 condition = new StaticIfCondition(loc, exp);
1389 return condition;
1390 }
1391
1392 /*****************************************
1393 * Parse a constructor definition:
1394 * this(parameters) { body }
1395 * or postblit:
1396 * this(this) { body }
1397 * or constructor template:
1398 * this(templateparameters)(parameters) { body }
1399 * Current token is 'this'.
1400 */
1401
1402 Dsymbol parseCtor()
1403 {
1404 Loc loc = this.loc;
1405
1406 nextToken();
1407 if (token.value == TOK.TOKlparen && peek(&token).value == TOK.TOKthis)
1408 { // this(this) { ... }
1409 nextToken();
1410 nextToken();
1411 check(TOK.TOKrparen);
1412 PostBlitDeclaration f = new PostBlitDeclaration(loc, Loc(0));
1413 parseContracts(f);
1414 return f;
1415 }
1416
1417 /* Look ahead to see if:
1418 * this(...)(...)
1419 * which is a constructor template
1420 */
1421 TemplateParameters tpl = null;
1422 if (token.value == TOK.TOKlparen && peekPastParen(&token).value == TOK.TOKlparen)
1423 { tpl = parseTemplateParameterList();
1424
1425 int varargs;
1426 Arguments arguments = parseParameters(&varargs);
1427
1428 Expression constraint = null;
1429 if (tpl)
1430 constraint = parseConstraint();
1431
1432 CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs);
1433 parseContracts(f);
1434
1435 // Wrap a template around it
1436 Array decldefs = new Array();
1437 decldefs.push(cast(void*)f);
1438 TemplateDeclaration tempdecl =
1439 new TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
1440 return tempdecl;
1441 }
1442
1443 /* Just a regular constructor
1444 */
1445 int varargs;
1446 Arguments arguments = parseParameters(&varargs);
1447 CtorDeclaration f = new CtorDeclaration(loc, Loc(0), arguments, varargs);
1448 parseContracts(f);
1449 return f;
1450 }
1451
1452 PostBlitDeclaration parsePostBlit()
1453 {
1454 assert(false);
1455 }
1456
1457 /*****************************************
1458 * Parse a destructor definition:
1459 * ~this() { body }
1460 * Current token is '~'.
1461 */
1462 DtorDeclaration parseDtor()
1463 {
1464 DtorDeclaration f;
1465 Loc loc = this.loc;
1466
1467 nextToken();
1468 check(TOKthis);
1469 check(TOKlparen);
1470 check(TOKrparen);
1471
1472 f = new DtorDeclaration(loc, Loc(0));
1473 parseContracts(f);
1474 return f;
1475 }
1476
1477 /*****************************************
1478 * Parse a static constructor definition:
1479 * static this() { body }
1480 * Current token is 'this'.
1481 */
1482 StaticCtorDeclaration parseStaticCtor()
1483 {
1484 StaticCtorDeclaration f;
1485 Loc loc = this.loc;
1486
1487 nextToken();
1488 check(TOKlparen);
1489 check(TOKrparen);
1490
1491 f = new StaticCtorDeclaration(loc, Loc(0));
1492 parseContracts(f);
1493 return f;
1494 }
1495
1496 /*****************************************
1497 * Parse a static destructor definition:
1498 * static ~this() { body }
1499 * Current token is '~'.
1500 */
1501 StaticDtorDeclaration parseStaticDtor()
1502 {
1503 StaticDtorDeclaration f;
1504 Loc loc = this.loc;
1505
1506 nextToken();
1507 check(TOKthis);
1508 check(TOKlparen);
1509 check(TOKrparen);
1510
1511 f = new StaticDtorDeclaration(loc, Loc(0));
1512 parseContracts(f);
1513 return f;
1514 }
1515
1516 /*****************************************
1517 * Parse an invariant definition:
1518 * invariant() { body }
1519 * Current token is 'invariant'.
1520 */
1521 InvariantDeclaration parseInvariant()
1522 {
1523 InvariantDeclaration f;
1524 Loc loc = this.loc;
1525
1526 nextToken();
1527 if (token.value == TOKlparen) // optional ()
1528 {
1529 nextToken();
1530 check(TOKrparen);
1531 }
1532
1533 f = new InvariantDeclaration(loc, Loc(0));
1534 f.fbody = parseStatement(ParseStatementFlags.PScurly);
1535 return f;
1536 }
1537
1538 /*****************************************
1539 * Parse a unittest definition:
1540 * unittest { body }
1541 * Current token is 'unittest'.
1542 */
1543 UnitTestDeclaration parseUnitTest()
1544 {
1545 Loc loc = this.loc;
1546
1547 nextToken();
1548
1549 UnitTestDeclaration f = new UnitTestDeclaration(loc, this.loc);
1550 f.fbody = parseStatement(ParseStatementFlags.PScurly);
1551
1552 return f;
1553 }
1554
1555 NewDeclaration parseNew()
1556 {
1557 assert(false);
1558 }
1559
1560 DeleteDeclaration parseDelete()
1561 {
1562 assert(false);
1563 }
1564
1565 Arguments parseParameters(int* pvarargs)
1566 {
1567 Arguments arguments = new Arguments();
1568 int varargs = 0;
1569 int hasdefault = 0;
1570
1571 check(TOK.TOKlparen);
1572 while (1)
1573 { Type *tb;
1574 Identifier ai = null;
1575 Type at;
1576 Argument a;
1577 STC storageClass = STC.STCundefined;
1578 STC stc;
1579 Expression ae;
1580
1581 for ( ;1; nextToken())
1582 {
1583 switch (token.value)
1584 {
1585 case TOK.TOKrparen:
1586 break;
1587
1588 case TOK.TOKdotdotdot:
1589 varargs = 1;
1590 nextToken();
1591 break;
1592
1593 case TOK.TOKconst:
1594 if (peek(&token).value == TOK.TOKlparen)
1595 goto Ldefault;
1596 stc = STC.STCconst;
1597 goto L2;
1598
1599 case TOK.TOKinvariant:
1600 case TOK.TOKimmutable:
1601 if (peek(&token).value == TOK.TOKlparen)
1602 goto Ldefault;
1603 stc = STC.STCimmutable;
1604 goto L2;
1605
1606 case TOK.TOKshared:
1607 if (peek(&token).value == TOK.TOKlparen)
1608 goto Ldefault;
1609 stc = STC.STCshared;
1610 goto L2;
1611
1612 case TOK.TOKin: stc = STC.STCin; goto L2;
1613 case TOK.TOKout: stc = STC.STCout; goto L2;
1614 case TOK.TOKinout:
1615 case TOK.TOKref: stc = STC.STCref; goto L2;
1616 case TOK.TOKlazy: stc = STC.STClazy; goto L2;
1617 case TOK.TOKscope: stc = STC.STCscope; goto L2;
1618 case TOK.TOKfinal: stc = STC.STCfinal; goto L2;
1619 L2:
1620 if (storageClass & stc ||
1621 (storageClass & STC.STCin && stc & (STC.STCconst | STC.STCscope)) ||
1622 (stc & STC.STCin && storageClass & (STC.STCconst | STC.STCscope))
1623 )
1624 error("redundant storage class %s", Token.toChars(token.value));
1625 storageClass |= stc;
1626 composeStorageClass(storageClass);
1627 continue;
1628
1629 static if (false) {
1630 case TOK.TOKstatic: stc = STC.STCstatic; goto L2;
1631 case TOK.TOKauto: storageClass = STC.STCauto; goto L4;
1632 case TOK.TOKalias: storageClass = STC.STCalias; goto L4;
1633 L4:
1634 nextToken();
1635 if (token.value == TOK.TOKidentifier)
1636 { ai = token.ident;
1637 nextToken();
1638 }
1639 else
1640 ai = null;
1641 at = null; // no type
1642 ae = null; // no default argument
1643 if (token.value == TOK.TOKassign) // = defaultArg
1644 { nextToken();
1645 ae = parseDefaultInitExp();
1646 hasdefault = 1;
1647 }
1648 else
1649 { if (hasdefault)
1650 error("default argument expected for alias %s",
1651 ai ? ai.toChars() : "");
1652 }
1653 goto L3;
1654 }
1655
1656 default:
1657 Ldefault:
1658 stc = (storageClass & (STC.STCin | STC.STCout | STC.STCref | STC.STClazy));
1659 if (stc & (stc - 1)) // if stc is not a power of 2
1660 error("incompatible parameter storage classes");
1661 if ((storageClass & (STC.STCconst | STC.STCout)) == (STC.STCconst | STC.STCout))
1662 error("out cannot be const");
1663 if ((storageClass & (STC.STCimmutable | STC.STCout)) == (STC.STCimmutable | STC.STCout))
1664 error("out cannot be immutable");
1665 if ((storageClass & STC.STCscope) &&
1666 (storageClass & (STC.STCref | STC.STCout)))
1667 error("scope cannot be ref or out");
1668 at = parseType(&ai);
1669 ae = null;
1670 if (token.value == TOK.TOKassign) // = defaultArg
1671 { nextToken();
1672 ae = parseDefaultInitExp();
1673 hasdefault = 1;
1674 }
1675 else
1676 { if (hasdefault)
1677 error("default argument expected for %s",
1678 ai ? ai.toChars() : at.toChars());
1679 }
1680 if (token.value == TOK.TOKdotdotdot)
1681 { /* This is:
1682 * at ai ...
1683 */
1684
1685 if (storageClass & (STC.STCout | STC.STCref))
1686 error("variadic argument cannot be out or ref");
1687 varargs = 2;
1688 a = new Argument(storageClass, at, ai, ae);
1689 arguments.push(cast(void*)a);
1690 nextToken();
1691 break;
1692 }
1693 L3:
1694 a = new Argument(storageClass, at, ai, ae);
1695 arguments.push(cast(void*)a);
1696 if (token.value == TOK.TOKcomma)
1697 { nextToken();
1698 goto L1;
1699 }
1700 break;
1701 }
1702 break;
1703 }
1704 break;
1705
1706 L1: ;
1707 }
1708 check(TOK.TOKrparen);
1709 *pvarargs = varargs;
1710 return arguments;
1711 }
1712
1713 EnumDeclaration parseEnum()
1714 {
1715 EnumDeclaration e;
1716 Identifier id;
1717 Type memtype;
1718 Loc loc = this.loc;
1719
1720 //printf("Parser.parseEnum()\n");
1721 nextToken();
1722 if (token.value == TOK.TOKidentifier)
1723 {
1724 id = token.ident;
1725 nextToken();
1726 }
1727 else
1728 id = null;
1729
1730 if (token.value == TOK.TOKcolon)
1731 {
1732 nextToken();
1733 memtype = parseBasicType();
1734 memtype = parseDeclarator(memtype, null, null);
1735 }
1736 else
1737 memtype = null;
1738
1739 e = new EnumDeclaration(loc, id, memtype);
1740 if (token.value == TOK.TOKsemicolon && id)
1741 nextToken();
1742 else if (token.value == TOK.TOKlcurly)
1743 {
1744 //printf("enum definition\n");
1745 e.members = new Array();
1746 nextToken();
1747 ubyte* comment = token.blockComment;
1748 while (token.value != TOK.TOKrcurly)
1749 {
1750 /* Can take the following forms:
1751 * 1. ident
1752 * 2. ident = value
1753 * 3. type ident = value
1754 */
1755
1756 loc = this.loc;
1757
1758 Type type = null;
1759 Identifier ident;
1760 Token* tp = peek(&token);
1761 if (token.value == TOK.TOKidentifier &&
1762 (tp.value == TOK.TOKassign || tp.value == TOK.TOKcomma || tp.value == TOK.TOKrcurly))
1763 {
1764 ident = token.ident;
1765 type = null;
1766 nextToken();
1767 }
1768 else
1769 {
1770 type = parseType(&ident, null);
1771 if (id || memtype)
1772 error("type only allowed if anonymous enum and no enum type");
1773 }
1774
1775 Expression value;
1776 if (token.value == TOK.TOKassign)
1777 {
1778 nextToken();
1779 value = parseAssignExp();
1780 }
1781 else
1782 {
1783 value = null;
1784 if (type)
1785 error("if type, there must be an initializer");
1786 }
1787
1788 EnumMember em = new EnumMember(loc, ident, value, type);
1789 e.members.push(cast(void*)em);
1790
1791 if (token.value == TOK.TOKrcurly) {
1792 ;
1793 } else {
1794 addComment(em, comment);
1795 comment = null;
1796 check(TOK.TOKcomma);
1797 }
1798 addComment(em, comment);
1799 comment = token.blockComment;
1800 }
1801 nextToken();
1802 }
1803 else
1804 error("enum declaration is invalid");
1805
1806 //printf("-parseEnum() %s\n", e.toChars());
1807 return e;
1808 }
1809
1810 Dsymbol parseAggregate()
1811 {
1812 AggregateDeclaration a = null;
1813 int anon = 0;
1814 TOK tok;
1815 Identifier id;
1816 TemplateParameters tpl = null;
1817 Expression constraint = null;
1818
1819 //printf("Parser.parseAggregate()\n");
1820 tok = token.value;
1821 nextToken();
1822 if (token.value != TOK.TOKidentifier)
1823 {
1824 id = null;
1825 }
1826 else
1827 {
1828 id = token.ident;
1829 nextToken();
1830
1831 if (token.value == TOK.TOKlparen)
1832 {
1833 // Class template declaration.
1834
1835 // Gather template parameter list
1836 tpl = parseTemplateParameterList();
1837 constraint = parseConstraint();
1838 }
1839 }
1840
1841 Loc loc = this.loc;
1842 switch (tok)
1843 { case TOK.TOKclass:
1844 case TOK.TOKinterface:
1845 {
1846 if (!id)
1847 error("anonymous classes not allowed");
1848
1849 // Collect base class(es)
1850 BaseClasses baseclasses = null;
1851 if (token.value == TOK.TOKcolon)
1852 {
1853 nextToken();
1854 baseclasses = parseBaseClasses();
1855
1856 if (token.value != TOK.TOKlcurly)
1857 error("members expected");
1858 }
1859
1860 if (tok == TOK.TOKclass)
1861 a = new ClassDeclaration(loc, id, baseclasses);
1862 else
1863 a = new InterfaceDeclaration(loc, id, baseclasses);
1864 break;
1865 }
1866
1867 case TOK.TOKstruct:
1868 if (id)
1869 a = new StructDeclaration(loc, id);
1870 else
1871 anon = 1;
1872 break;
1873
1874 case TOK.TOKunion:
1875 if (id)
1876 a = new UnionDeclaration(loc, id);
1877 else
1878 anon = 2;
1879 break;
1880
1881 default:
1882 assert(0);
1883 break;
1884 }
1885 if (a && token.value == TOK.TOKsemicolon)
1886 { nextToken();
1887 }
1888 else if (token.value == TOK.TOKlcurly)
1889 {
1890 //printf("aggregate definition\n");
1891 nextToken();
1892 Array decl = parseDeclDefs(0);
1893 if (token.value != TOK.TOKrcurly)
1894 error("} expected following member declarations in aggregate");
1895 nextToken();
1896 if (anon)
1897 {
1898 /* Anonymous structs/unions are more like attributes.
1899 */
1900 return new AnonDeclaration(loc, anon - 1, decl);
1901 }
1902 else
1903 a.members = decl;
1904 }
1905 else
1906 {
1907 error("{ } expected following aggregate declaration");
1908 a = new StructDeclaration(loc, null);
1909 }
1910
1911 if (tpl)
1912 { // Wrap a template around the aggregate declaration
1913
1914 Array decldefs = new Array();
1915 decldefs.push(cast(void*)a);
1916 TemplateDeclaration tempdecl =
1917 new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
1918 return tempdecl;
1919 }
1920
1921 return a;
1922 }
1923
1924 BaseClasses parseBaseClasses()
1925 {
1926 BaseClasses baseclasses = new BaseClasses();
1927
1928 for (; 1; nextToken())
1929 {
1930 PROT protection = PROT.PROTpublic;
1931 switch (token.value)
1932 {
1933 case TOK.TOKprivate:
1934 protection = PROT.PROTprivate;
1935 nextToken();
1936 break;
1937 case TOK.TOKpackage:
1938 protection = PROT.PROTpackage;
1939 nextToken();
1940 break;
1941 case TOK.TOKprotected:
1942 protection = PROT.PROTprotected;
1943 nextToken();
1944 break;
1945 case TOK.TOKpublic:
1946 protection = PROT.PROTpublic;
1947 nextToken();
1948 break;
1949 default:
1950 break; ///
1951 }
1952 if (token.value == TOK.TOKidentifier)
1953 {
1954 BaseClass b = new BaseClass(parseBasicType(), protection);
1955 baseclasses.push(cast(void*)b);
1956 if (token.value != TOK.TOKcomma)
1957 break;
1958 }
1959 else
1960 {
1961 error("base classes expected instead of %s", token.toChars());
1962 return null;
1963 }
1964 }
1965 return baseclasses;
1966 }
1967
1968 Import parseImport(Array decldefs, int isstatic)
1969 {
1970 Import s;
1971 Identifier id;
1972 Identifier aliasid = null;
1973 Array a;
1974 Loc loc;
1975
1976 //printf("Parser.parseImport()\n");
1977 do
1978 {
1979 L1:
1980 nextToken();
1981 if (token.value != TOK.TOKidentifier)
1982 {
1983 error("Identifier expected following import");
1984 break;
1985 }
1986
1987 loc = this.loc;
1988 a = null;
1989 id = token.ident;
1990 nextToken();
1991 if (!aliasid && token.value == TOK.TOKassign)
1992 {
1993 aliasid = id;
1994 goto L1;
1995 }
1996 while (token.value == TOK.TOKdot)
1997 {
1998 if (!a)
1999 a = new Array();
2000 a.push(cast(void*)id);
2001 nextToken();
2002 if (token.value != TOK.TOKidentifier)
2003 {
2004 error("identifier expected following package");
2005 break;
2006 }
2007 id = token.ident;
2008 nextToken();
2009 }
2010
2011 s = new Import(loc, a, id, aliasid, isstatic);
2012 decldefs.push(cast(void*)s);
2013
2014 /* Look for
2015 * : alias=name, alias=name;
2016 * syntax.
2017 */
2018 if (token.value == TOK.TOKcolon)
2019 {
2020 do
2021 {
2022 Identifier name;
2023
2024 nextToken();
2025 if (token.value != TOK.TOKidentifier)
2026 {
2027 error("Identifier expected following :");
2028 break;
2029 }
2030 Identifier alias_ = token.ident;
2031 nextToken();
2032 if (token.value == TOK.TOKassign)
2033 {
2034 nextToken();
2035 if (token.value != TOK.TOKidentifier)
2036 {
2037 error("Identifier expected following %s=", alias_.toChars());
2038 break;
2039 }
2040 name = token.ident;
2041 nextToken();
2042 }
2043 else
2044 {
2045 name = alias_;
2046 alias_ = null;
2047 }
2048 s.addAlias(name, alias_);
2049 } while (token.value == TOK.TOKcomma);
2050
2051 break; // no comma-separated imports of this form
2052 }
2053
2054 aliasid = null;
2055
2056 } while (token.value == TOK.TOKcomma);
2057
2058 if (token.value == TOK.TOKsemicolon)
2059 nextToken();
2060 else
2061 {
2062 error("';' expected");
2063 nextToken();
2064 }
2065
2066 return null;
2067 }
2068
2069 Type parseType(Identifier* pident = null, TemplateParameters* tpl = null)
2070 {
2071 Type t;
2072
2073 /* Take care of the storage class prefixes that
2074 * serve as type attributes:
2075 * const shared, shared const, const, invariant, shared
2076 */
2077 if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() != TOK.TOKlparen ||
2078 token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() != TOK.TOKlparen)
2079 {
2080 nextToken();
2081 nextToken();
2082 /* shared const type
2083 */
2084 t = parseType(pident, tpl);
2085 t = t.makeSharedConst();
2086 return t;
2087 }
2088 else if (token.value == TOK.TOKconst && peekNext() != TOK.TOKlparen)
2089 {
2090 nextToken();
2091 /* const type
2092 */
2093 t = parseType(pident, tpl);
2094 t = t.makeConst();
2095 return t;
2096 }
2097 else if ((token.value == TOK.TOKinvariant || token.value == TOK.TOKimmutable) &&
2098 peekNext() != TOK.TOKlparen)
2099 {
2100 nextToken();
2101 /* invariant type
2102 */
2103 t = parseType(pident, tpl);
2104 t = t.makeInvariant();
2105 return t;
2106 }
2107 else if (token.value == TOK.TOKshared && peekNext() != TOK.TOKlparen)
2108 {
2109 nextToken();
2110 /* shared type
2111 */
2112 t = parseType(pident, tpl);
2113 t = t.makeShared();
2114 return t;
2115 }
2116 else
2117 t = parseBasicType();
2118 t = parseDeclarator(t, pident, tpl);
2119 return t;
2120 }
2121
2122 Type parseBasicType()
2123 {
2124 Type t;
2125 Identifier id;
2126 TypeQualified tid;
2127
2128 //printf("parseBasicType()\n");
2129 switch (token.value)
2130 {
2131 case TOK.TOKvoid: t = Type.tvoid; goto LabelX;
2132 case TOK.TOKint8: t = Type.tint8; goto LabelX;
2133 case TOK.TOKuns8: t = Type.tuns8; goto LabelX;
2134 case TOK.TOKint16: t = Type.tint16; goto LabelX;
2135 case TOK.TOKuns16: t = Type.tuns16; goto LabelX;
2136 case TOK.TOKint32: t = Type.tint32; goto LabelX;
2137 case TOK.TOKuns32: t = Type.tuns32; goto LabelX;
2138 case TOK.TOKint64: t = Type.tint64; goto LabelX;
2139 case TOK.TOKuns64: t = Type.tuns64; goto LabelX;
2140 case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX;
2141 case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX;
2142 case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX;
2143 case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX;
2144 case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX;
2145 case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX;
2146 case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX;
2147 case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX;
2148 case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX;
2149 case TOK.TOKbit: t = Type.tbit; goto LabelX;
2150 case TOK.TOKbool: t = Type.tbool; goto LabelX;
2151 case TOK.TOKchar: t = Type.tchar; goto LabelX;
2152 case TOK.TOKwchar: t = Type.twchar; goto LabelX;
2153 case TOK.TOKdchar: t = Type.tdchar; goto LabelX;
2154 LabelX:
2155 nextToken();
2156 break;
2157
2158 case TOK.TOKidentifier:
2159 id = token.ident;
2160 nextToken();
2161 if (token.value == TOK.TOKnot)
2162 { // ident!(template_arguments)
2163 TemplateInstance tempinst = new TemplateInstance(loc, id);
2164 nextToken();
2165 if (token.value == TOK.TOKlparen)
2166 // ident!(template_arguments)
2167 tempinst.tiargs = parseTemplateArgumentList();
2168 else
2169 // ident!template_argument
2170 tempinst.tiargs = parseTemplateArgument();
2171 tid = new TypeInstance(loc, tempinst);
2172 goto Lident2;
2173 }
2174 Lident:
2175 tid = new TypeIdentifier(loc, id);
2176 Lident2:
2177 while (token.value == TOK.TOKdot)
2178 { nextToken();
2179 if (token.value != TOK.TOKidentifier)
2180 { error("identifier expected following '.' instead of '%s'", token.toChars());
2181 break;
2182 }
2183 id = token.ident;
2184 nextToken();
2185 if (token.value == TOK.TOKnot)
2186 {
2187 TemplateInstance tempinst = new TemplateInstance(loc, id);
2188 nextToken();
2189 if (token.value == TOK.TOKlparen)
2190 // ident!(template_arguments)
2191 tempinst.tiargs = parseTemplateArgumentList();
2192 else
2193 // ident!template_argument
2194 tempinst.tiargs = parseTemplateArgument();
2195 tid.addIdent(cast(Identifier)tempinst);
2196 }
2197 else
2198 tid.addIdent(id);
2199 }
2200 t = tid;
2201 break;
2202
2203 case TOK.TOKdot:
2204 // Leading . as in .foo
2205 id = Id.empty;
2206 goto Lident;
2207
2208 case TOK.TOKtypeof:
2209 // typeof(expression)
2210 tid = parseTypeof();
2211 goto Lident2;
2212
2213 case TOK.TOKconst:
2214 // const(type)
2215 nextToken();
2216 check(TOK.TOKlparen);
2217 t = parseType();
2218 check(TOK.TOKrparen);
2219 if (t.isShared())
2220 t = t.makeSharedConst();
2221 else
2222 t = t.makeConst();
2223 break;
2224
2225 case TOK.TOKinvariant:
2226 case TOK.TOKimmutable:
2227 // invariant(type)
2228 nextToken();
2229 check(TOK.TOKlparen);
2230 t = parseType();
2231 check(TOK.TOKrparen);
2232 t = t.makeInvariant();
2233 break;
2234
2235 case TOK.TOKshared:
2236 // shared(type)
2237 nextToken();
2238 check(TOK.TOKlparen);
2239 t = parseType();
2240 check(TOK.TOKrparen);
2241 if (t.isConst())
2242 t = t.makeSharedConst();
2243 else
2244 t = t.makeShared();
2245 break;
2246
2247 default:
2248 error("basic type expected, not %s", token.toChars());
2249 t = Type.tint32;
2250 break;
2251 }
2252 return t;
2253 }
2254
2255 Type parseBasicType2(Type t)
2256 {
2257 //printf("parseBasicType2()\n");
2258 while (1)
2259 {
2260 switch (token.value)
2261 {
2262 case TOK.TOKmul:
2263 t = new TypePointer(t);
2264 nextToken();
2265 continue;
2266
2267 case TOK.TOKlbracket:
2268 // Handle []. Make sure things like
2269 // int[3][1] a;
2270 // is (array[1] of array[3] of int)
2271 nextToken();
2272 if (token.value == TOK.TOKrbracket)
2273 {
2274 t = new TypeDArray(t); // []
2275 nextToken();
2276 }
2277 else if (isDeclaration(&token, 0, TOK.TOKrbracket, null))
2278 { // It's an associative array declaration
2279
2280 //printf("it's an associative array\n");
2281 Type index = parseType(); // [ type ]
2282 t = new TypeAArray(t, index);
2283 check(TOK.TOKrbracket);
2284 }
2285 else
2286 {
2287 //printf("it's type[expression]\n");
2288 inBrackets++;
2289 Expression e = parseExpression(); // [ expression ]
2290 if (token.value == TOK.TOKslice)
2291 {
2292 nextToken();
2293 Expression e2 = parseExpression(); // [ exp .. exp ]
2294 t = new TypeSlice(t, e, e2);
2295 }
2296 else
2297 t = new TypeSArray(t,e);
2298 inBrackets--;
2299 check(TOK.TOKrbracket);
2300 }
2301 continue;
2302
2303 case TOK.TOKdelegate:
2304 case TOK.TOKfunction:
2305 { // Handle delegate declaration:
2306 // t delegate(parameter list) nothrow pure
2307 // t function(parameter list) nothrow pure
2308 Arguments arguments;
2309 int varargs;
2310 bool ispure = false;
2311 bool isnothrow = false;
2312 TOK save = token.value;
2313
2314 nextToken();
2315 arguments = parseParameters(&varargs);
2316 while (1)
2317 { // Postfixes
2318 if (token.value == TOK.TOKpure)
2319 ispure = true;
2320 else if (token.value == TOK.TOKnothrow)
2321 isnothrow = true;
2322 else
2323 break;
2324 nextToken();
2325 }
2326 TypeFunction tf = new TypeFunction(arguments, t, varargs, linkage);
2327 tf.ispure = ispure;
2328 tf.isnothrow = isnothrow;
2329 if (save == TOK.TOKdelegate)
2330 t = new TypeDelegate(tf);
2331 else
2332 t = new TypePointer(tf); // pointer to function
2333 continue;
2334 }
2335
2336 default:
2337 return t;
2338 }
2339 assert(0);
2340 }
2341 assert(0);
2342 return null;
2343 }
2344
2345 Type parseDeclarator(Type t, Identifier* pident, TemplateParameters* tpl = null)
2346 {
2347 Type ts;
2348
2349 //printf("parseDeclarator(tpl = %p)\n", tpl);
2350 t = parseBasicType2(t);
2351
2352 switch (token.value)
2353 {
2354
2355 case TOK.TOKidentifier:
2356 if (pident)
2357 *pident = token.ident;
2358 else
2359 error("unexpected identifer '%s' in declarator", token.ident.toChars());
2360 ts = t;
2361 nextToken();
2362 break;
2363
2364 case TOK.TOKlparen:
2365 /* Parse things with parentheses around the identifier, like:
2366 * int (*ident[3])[]
2367 * although the D style would be:
2368 * int[]*[3] ident
2369 */
2370 nextToken();
2371 ts = parseDeclarator(t, pident);
2372 check(TOK.TOKrparen);
2373 break;
2374
2375 default:
2376 ts = t;
2377 break;
2378 }
2379
2380 // parse DeclaratorSuffixes
2381 while (1)
2382 {
2383 switch (token.value)
2384 {
2385 version (CARRAYDECL) {
2386 /* Support C style array syntax:
2387 * int ident[]
2388 * as opposed to D-style:
2389 * int[] ident
2390 */
2391 case TOK.TOKlbracket:
2392 { // This is the old C-style post [] syntax.
2393 TypeNext ta;
2394 nextToken();
2395 if (token.value == TOK.TOKrbracket)
2396 { // It's a dynamic array
2397 ta = new TypeDArray(t); // []
2398 nextToken();
2399 }
2400 else if (isDeclaration(&token, 0, TOK.TOKrbracket, null))
2401 { // It's an associative array
2402
2403 //printf("it's an associative array\n");
2404 Type index = parseType(); // [ type ]
2405 check(TOK.TOKrbracket);
2406 ta = new TypeAArray(t, index);
2407 }
2408 else
2409 {
2410 //printf("It's a static array\n");
2411 Expression e = parseExpression(); // [ expression ]
2412 ta = new TypeSArray(t, e);
2413 check(TOK.TOKrbracket);
2414 }
2415
2416 /* Insert ta into
2417 * ts . ... . t
2418 * so that
2419 * ts . ... . ta . t
2420 */
2421 Type* pt;
2422 for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) {
2423 ;
2424 }
2425 *pt = ta;
2426 continue;
2427 }
2428 }
2429 case TOK.TOKlparen:
2430 {
2431 if (tpl)
2432 {
2433 /* Look ahead to see if this is (...)(...),
2434 * i.e. a function template declaration
2435 */
2436 if (peekPastParen(&token).value == TOK.TOKlparen)
2437 {
2438 //printf("function template declaration\n");
2439
2440 // Gather template parameter list
2441 *tpl = parseTemplateParameterList();
2442 }
2443 }
2444
2445 int varargs;
2446 Arguments arguments = parseParameters(&varargs);
2447 Type tf = new TypeFunction(arguments, t, varargs, linkage);
2448
2449 /* Parse const/invariant/nothrow/pure postfix
2450 */
2451 while (1)
2452 {
2453 switch (token.value)
2454 {
2455 case TOK.TOKconst:
2456 if (tf.isShared())
2457 tf = tf.makeSharedConst();
2458 else
2459 tf = tf.makeConst();
2460 nextToken();
2461 continue;
2462
2463 case TOK.TOKinvariant:
2464 case TOK.TOKimmutable:
2465 tf = tf.makeInvariant();
2466 nextToken();
2467 continue;
2468
2469 case TOK.TOKshared:
2470 if (tf.isConst())
2471 tf = tf.makeSharedConst();
2472 else
2473 tf = tf.makeShared();
2474 nextToken();
2475 continue;
2476
2477 case TOK.TOKnothrow:
2478 (cast(TypeFunction)tf).isnothrow = 1;
2479 nextToken();
2480 continue;
2481
2482 case TOK.TOKpure:
2483 (cast(TypeFunction)tf).ispure = 1;
2484 nextToken();
2485 continue;
2486
2487 case TOK.TOKat:
2488 nextToken();
2489 if (token.value != TOK.TOKidentifier)
2490 { error("attribute identifier expected");
2491 nextToken();
2492 continue;
2493 }
2494 Identifier id = token.ident;
2495 if (id is Id.property)
2496 (cast(TypeFunction)tf).ispure = 1;
2497 else
2498 error("valid attribute identifiers are property, not %s", id.toChars());
2499 nextToken();
2500 continue;
2501 default:
2502 break; ///
2503 }
2504 break;
2505 }
2506
2507 /* Insert tf into
2508 * ts . ... . t
2509 * so that
2510 * ts . ... . tf . t
2511 */
2512 Type* pt;
2513 for (pt = &ts; *pt !is t; pt = &(cast(TypeNext)*pt).next) {
2514 ;
2515 }
2516 *pt = tf;
2517 break;
2518 }
2519
2520 default:
2521 break; ///
2522 }
2523 break;
2524 }
2525
2526 return ts;
2527 }
2528
2529 Array parseDeclarations(STC storage_class)
2530 {
2531 STC stc;
2532 Type ts;
2533 Type t;
2534 Type tfirst;
2535 Identifier ident;
2536 Array a;
2537 TOK tok = TOK.TOKreserved;
2538 ubyte* comment = token.blockComment;
2539 LINK link = linkage;
2540
2541 //printf("parseDeclarations() %s\n", token.toChars());
2542 if (storage_class)
2543 { ts = null; // infer type
2544 goto L2;
2545 }
2546
2547 switch (token.value)
2548 {
2549 case TOK.TOKalias:
2550 /* Look for:
2551 * alias identifier this;
2552 */
2553 tok = token.value;
2554 nextToken();
2555 if (token.value == TOK.TOKidentifier && peek(&token).value == TOK.TOKthis)
2556 {
2557 AliasThis s = new AliasThis(this.loc, token.ident);
2558 nextToken();
2559 check(TOK.TOKthis);
2560 check(TOK.TOKsemicolon);
2561 a = new Array();
2562 a.push(cast(void*)s);
2563 addComment(s, comment);
2564 return a;
2565 }
2566 break;
2567 case TOK.TOKtypedef:
2568 tok = token.value;
2569 nextToken();
2570 break;
2571 default:
2572 break;
2573 }
2574
2575 storage_class = STC.STCundefined;
2576 while (1)
2577 {
2578 switch (token.value)
2579 {
2580 case TOK.TOKconst:
2581 if (peek(&token).value == TOK.TOKlparen)
2582 break; // const as type constructor
2583 stc = STC.STCconst; // const as storage class
2584 goto L1;
2585
2586 case TOK.TOKinvariant:
2587 case TOK.TOKimmutable:
2588 if (peek(&token).value == TOK.TOKlparen)
2589 break;
2590 stc = STC.STCimmutable;
2591 goto L1;
2592
2593 case TOK.TOKshared:
2594 if (peek(&token).value == TOK.TOKlparen)
2595 break;
2596 stc = STC.STCshared;
2597 goto L1;
2598
2599 case TOK.TOKstatic: stc = STC.STCstatic; goto L1;
2600 case TOK.TOKfinal: stc = STC.STCfinal; goto L1;
2601 case TOK.TOKauto: stc = STC.STCauto; goto L1;
2602 case TOK.TOKscope: stc = STC.STCscope; goto L1;
2603 case TOK.TOKoverride: stc = STC.STCoverride; goto L1;
2604 case TOK.TOKabstract: stc = STC.STCabstract; goto L1;
2605 case TOK.TOKsynchronized: stc = STC.STCsynchronized; goto L1;
2606 case TOK.TOKdeprecated: stc = STC.STCdeprecated; goto L1;
2607 version (DMDV2) {
2608 case TOK.TOKnothrow: stc = STC.STCnothrow; goto L1;
2609 case TOK.TOKpure: stc = STC.STCpure; goto L1;
2610 case TOK.TOKref: stc = STC.STCref; goto L1;
2611 case TOK.TOKtls: stc = STC.STCtls; goto L1;
2612 case TOK.TOKgshared: stc = STC.STCgshared; goto L1;
2613 case TOK.TOKenum: stc = STC.STCmanifest; goto L1;
2614 }
2615 L1:
2616 if (storage_class & stc)
2617 error("redundant storage class '%s'", token.toChars());
2618 storage_class = (storage_class | stc);
2619 composeStorageClass(storage_class);
2620 nextToken();
2621 continue;
2622
2623 case TOK.TOKextern:
2624 if (peek(&token).value != TOK.TOKlparen)
2625 { stc = STC.STCextern;
2626 goto L1;
2627 }
2628
2629 link = parseLinkage();
2630 continue;
2631
2632 default:
2633 break;
2634 }
2635 break;
2636 }
2637
2638 /* Look for auto initializers:
2639 * storage_class identifier = initializer;
2640 */
2641 if (storage_class &&
2642 token.value == TOK.TOKidentifier &&
2643 peek(&token).value == TOK.TOKassign)
2644 {
2645 return parseAutoDeclarations(storage_class, comment);
2646 }
2647
2648 if (token.value == TOK.TOKclass)
2649 {
2650 AggregateDeclaration s = cast(AggregateDeclaration)parseAggregate();
2651 s.storage_class |= storage_class;
2652 a = new Array();
2653 a.push(cast(void*)s);
2654 addComment(s, comment);
2655 return a;
2656 }
2657
2658 /* Look for return type inference for template functions.
2659 */
2660 {
2661 Token *tk;
2662 if (storage_class &&
2663 token.value == TOK.TOKidentifier &&
2664 (tk = peek(&token)).value == TOK.TOKlparen &&
2665 skipParens(tk, &tk) &&
2666 peek(tk).value == TOK.TOKlparen)
2667 {
2668 ts = null;
2669 }
2670 else
2671 {
2672 ts = parseBasicType();
2673 ts = parseBasicType2(ts);
2674 }
2675 }
2676
2677 L2:
2678 tfirst = null;
2679 a = new Array();
2680
2681 while (1)
2682 {
2683 Loc loc = this.loc;
2684 TemplateParameters tpl = null;
2685
2686 ident = null;
2687 t = parseDeclarator(ts, &ident, &tpl);
2688 assert(t);
2689 if (!tfirst)
2690 tfirst = t;
2691 else if (t != tfirst)
2692 error("multiple declarations must have the same type, not %s and %s",
2693 tfirst.toChars(), t.toChars());
2694 if (!ident)
2695 error("no identifier for declarator %s", t.toChars());
2696
2697 if (tok == TOK.TOKtypedef || tok == TOK.TOKalias)
2698 { Declaration v;
2699 Initializer init = null;
2700
2701 if (token.value == TOK.TOKassign)
2702 {
2703 nextToken();
2704 init = parseInitializer();
2705 }
2706 if (tok == TOK.TOKtypedef)
2707 v = new TypedefDeclaration(loc, ident, t, init);
2708 else
2709 { if (init)
2710 error("alias cannot have initializer");
2711 v = new AliasDeclaration(loc, ident, t);
2712 }
2713 v.storage_class = storage_class;
2714 if (link == linkage)
2715 a.push(cast(void*)v);
2716 else
2717 {
2718 Array ax = new Array();
2719 ax.push(cast(void*)v);
2720 Dsymbol s = new LinkDeclaration(link, ax);
2721 a.push(cast(void*)s);
2722 }
2723 switch (token.value)
2724 { case TOK.TOKsemicolon:
2725 nextToken();
2726 addComment(v, comment);
2727 break;
2728
2729 case TOK.TOKcomma:
2730 nextToken();
2731 addComment(v, comment);
2732 continue;
2733
2734 default:
2735 error("semicolon expected to close %s declaration", Token.toChars(tok));
2736 break;
2737 }
2738 }
2739 else if (t.ty == TY.Tfunction)
2740 {
2741 TypeFunction tf = cast(TypeFunction)t;
2742 Expression constraint = null;
2743 static if (false) {
2744 if (Argument.isTPL(tf.parameters))
2745 {
2746 if (!tpl)
2747 tpl = new TemplateParameters();
2748 }
2749 }
2750 FuncDeclaration f =
2751 new FuncDeclaration(loc, Loc(0), ident, storage_class, t);
2752 addComment(f, comment);
2753 if (tpl)
2754 constraint = parseConstraint();
2755 parseContracts(f);
2756 addComment(f, null);
2757 Dsymbol s;
2758 if (link == linkage)
2759 {
2760 s = f;
2761 }
2762 else
2763 {
2764 Array ax = new Array();
2765 ax.push(cast(void*)f);
2766 s = new LinkDeclaration(link, ax);
2767 }
2768 /* A template parameter list means it's a function template
2769 */
2770 if (tpl)
2771 {
2772 // Wrap a template around the function declaration
2773 Array decldefs = new Array();
2774 decldefs.push(cast(void*)s);
2775 TemplateDeclaration tempdecl =
2776 new TemplateDeclaration(loc, s.ident, tpl, constraint, decldefs);
2777 s = tempdecl;
2778 }
2779 addComment(s, comment);
2780 a.push(cast(void*)s);
2781 }
2782 else
2783 {
2784 Initializer init = null;
2785 if (token.value == TOK.TOKassign)
2786 {
2787 nextToken();
2788 init = parseInitializer();
2789 }
2790
2791 VarDeclaration v = new VarDeclaration(loc, t, ident, init);
2792 v.storage_class = storage_class;
2793 if (link == linkage)
2794 a.push(cast(void*)v);
2795 else
2796 {
2797 Array ax = new Array();
2798 ax.push(cast(void*)v);
2799 Dsymbol s = new LinkDeclaration(link, ax);
2800 a.push(cast(void*)s);
2801 }
2802 switch (token.value)
2803 { case TOK.TOKsemicolon:
2804 nextToken();
2805 addComment(v, comment);
2806 break;
2807
2808 case TOK.TOKcomma:
2809 nextToken();
2810 addComment(v, comment);
2811 continue;
2812
2813 default:
2814 error("semicolon expected, not '%s'", token.toChars());
2815 break;
2816 }
2817 }
2818 break;
2819 }
2820 return a;
2821 }
2822
2823 void parseContracts(FuncDeclaration f)
2824 {
2825 Type tb;
2826 LINK linksave = linkage;
2827
2828 // The following is irrelevant, as it is overridden by sc.linkage in
2829 // TypeFunction.semantic
2830 linkage = LINK.LINKd; // nested functions have D linkage
2831 L1:
2832 switch (token.value)
2833 {
2834 case TOK.TOKlcurly:
2835 if (f.frequire || f.fensure)
2836 error("missing body { ... } after in or out");
2837 f.fbody = parseStatement(ParseStatementFlags.PSsemi);
2838 f.endloc = endloc;
2839 break;
2840
2841 case TOK.TOKbody:
2842 nextToken();
2843 f.fbody = parseStatement(ParseStatementFlags.PScurly);
2844 f.endloc = endloc;
2845 break;
2846
2847 case TOK.TOKsemicolon:
2848 if (f.frequire || f.fensure)
2849 error("missing body { ... } after in or out");
2850 nextToken();
2851 break;
2852
2853 static if (false) { // Do we want this for function declarations, so we can do:
2854 // int x, y, foo(), z;
2855 case TOK.TOKcomma:
2856 nextToken();
2857 continue;
2858 }
2859
2860 static if (false) { // Dumped feature
2861 case TOK.TOKthrow:
2862 if (!f.fthrows)
2863 f.fthrows = new Array();
2864 nextToken();
2865 check(TOK.TOKlparen);
2866 while (1)
2867 {
2868 tb = parseBasicType();
2869 f.fthrows.push(tb);
2870 if (token.value == TOK.TOKcomma)
2871 { nextToken();
2872 continue;
2873 }
2874 break;
2875 }
2876 check(TOK.TOKrparen);
2877 goto L1;
2878 }
2879
2880 case TOK.TOKin:
2881 nextToken();
2882 if (f.frequire)
2883 error("redundant 'in' statement");
2884 f.frequire = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope);
2885 goto L1;
2886
2887 case TOK.TOKout:
2888 // parse: out (identifier) { statement }
2889 nextToken();
2890 if (token.value != TOK.TOKlcurly)
2891 {
2892 check(TOK.TOKlparen);
2893 if (token.value != TOK.TOKidentifier)
2894 error("(identifier) following 'out' expected, not %s", token.toChars());
2895 f.outId = token.ident;
2896 nextToken();
2897 check(TOK.TOKrparen);
2898 }
2899 if (f.fensure)
2900 error("redundant 'out' statement");
2901 f.fensure = parseStatement(ParseStatementFlags.PScurly | ParseStatementFlags.PSscope);
2902 goto L1;
2903
2904 default:
2905 error("semicolon expected following function declaration");
2906 break;
2907 }
2908 linkage = linksave;
2909 }
2910
2911 Statement parseStatement(ParseStatementFlags flags)
2912 {
2913 Statement s;
2914 Token* t;
2915 Condition condition;
2916 Statement ifbody;
2917 Statement elsebody;
2918 bool isfinal;
2919 Loc loc = this.loc;
2920
2921 //printf("parseStatement()\n");
2922
2923 if (flags & ParseStatementFlags.PScurly && token.value != TOK.TOKlcurly)
2924 error("statement expected to be { }, not %s", token.toChars());
2925
2926 switch (token.value)
2927 {
2928 case TOK.TOKidentifier:
2929 /* A leading identifier can be a declaration, label, or expression.
2930 * The easiest case to check first is label:
2931 */
2932 t = peek(&token);
2933 if (t.value == TOK.TOKcolon)
2934 { // It's a label
2935
2936 Identifier ident = token.ident;
2937 nextToken();
2938 nextToken();
2939 s = parseStatement(ParseStatementFlags.PSsemi);
2940 s = new LabelStatement(loc, ident, s);
2941 break;
2942 }
2943 // fallthrough to TOK.TOKdot
2944 case TOK.TOKdot:
2945 case TOK.TOKtypeof:
2946 if (isDeclaration(&token, 2, TOK.TOKreserved, null))
2947 goto Ldeclaration;
2948 else
2949 goto Lexp;
2950 break;
2951
2952 case TOK.TOKassert:
2953 case TOK.TOKthis:
2954 case TOK.TOKsuper:
2955 case TOK.TOKint32v:
2956 case TOK.TOKuns32v:
2957 case TOK.TOKint64v:
2958 case TOK.TOKuns64v:
2959 case TOK.TOKfloat32v:
2960 case TOK.TOKfloat64v:
2961 case TOK.TOKfloat80v:
2962 case TOK.TOKimaginary32v:
2963 case TOK.TOKimaginary64v:
2964 case TOK.TOKimaginary80v:
2965 case TOK.TOKcharv:
2966 case TOK.TOKwcharv:
2967 case TOK.TOKdcharv:
2968 case TOK.TOKnull:
2969 case TOK.TOKtrue:
2970 case TOK.TOKfalse:
2971 case TOK.TOKstring:
2972 case TOK.TOKlparen:
2973 case TOK.TOKcast:
2974 case TOK.TOKmul:
2975 case TOK.TOKmin:
2976 case TOK.TOKadd:
2977 case TOK.TOKplusplus:
2978 case TOK.TOKminusminus:
2979 case TOK.TOKnew:
2980 case TOK.TOKdelete:
2981 case TOK.TOKdelegate:
2982 case TOK.TOKfunction:
2983 case TOK.TOKtypeid:
2984 case TOK.TOKis:
2985 case TOK.TOKlbracket:
2986 version (DMDV2) {
2987 case TOK.TOKtraits:
2988 case TOK.TOKfile:
2989 case TOK.TOKline:
2990 }
2991 Lexp:
2992 { Expression exp;
2993
2994 exp = parseExpression();
2995 check(TOK.TOKsemicolon, "statement");
2996 s = new ExpStatement(loc, exp);
2997 break;
2998 }
2999
3000 case TOK.TOKstatic:
3001 { // Look ahead to see if it's static assert() or static if()
3002 Token *tt;
3003
3004 tt = peek(&token);
3005 if (tt.value == TOK.TOKassert)
3006 {
3007 nextToken();
3008 s = new StaticAssertStatement(parseStaticAssert());
3009 break;
3010 }
3011 if (tt.value == TOK.TOKif)
3012 {
3013 nextToken();
3014 condition = parseStaticIfCondition();
3015 goto Lcondition;
3016 }
3017 goto Ldeclaration;
3018 }
3019
3020 case TOK.TOKfinal:
3021 if (peekNext() == TOK.TOKswitch)
3022 {
3023 nextToken();
3024 isfinal = true;
3025 goto Lswitch;
3026 }
3027 goto Ldeclaration;
3028
3029 case TOK.TOKwchar: case TOK.TOKdchar:
3030 case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
3031 case TOK.TOKint8: case TOK.TOKuns8:
3032 case TOK.TOKint16: case TOK.TOKuns16:
3033 case TOK.TOKint32: case TOK.TOKuns32:
3034 case TOK.TOKint64: case TOK.TOKuns64:
3035 case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
3036 case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
3037 case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
3038 case TOK.TOKvoid:
3039 case TOK.TOKtypedef:
3040 case TOK.TOKalias:
3041 case TOK.TOKconst:
3042 case TOK.TOKauto:
3043 case TOK.TOKextern:
3044 case TOK.TOKinvariant:
3045 version (DMDV2) {
3046 case TOK.TOKimmutable:
3047 case TOK.TOKshared:
3048 case TOK.TOKnothrow:
3049 case TOK.TOKpure:
3050 case TOK.TOKtls:
3051 case TOK.TOKgshared:
3052 }
3053 // case TOK.TOKtypeof:
3054 Ldeclaration:
3055 { Array a;
3056
3057 a = parseDeclarations(STC.STCundefined);
3058 if (a.dim > 1)
3059 {
3060 Statements as = new Statements();
3061 as.reserve(a.dim);
3062 for (int i = 0; i < a.dim; i++)
3063 {
3064 Dsymbol d = cast(Dsymbol)a.data[i];
3065 s = new DeclarationStatement(loc, d);
3066 as.push(cast(void*)s);
3067 }
3068 s = new CompoundDeclarationStatement(loc, as);
3069 }
3070 else if (a.dim == 1)
3071 {
3072 Dsymbol d = cast(Dsymbol)a.data[0];
3073 s = new DeclarationStatement(loc, d);
3074 }
3075 else
3076 assert(0);
3077 if (flags & ParseStatementFlags.PSscope)
3078 s = new ScopeStatement(loc, s);
3079 break;
3080 }
3081
3082 case TOK.TOKstruct:
3083 case TOK.TOKunion:
3084 case TOK.TOKclass:
3085 case TOK.TOKinterface:
3086 { Dsymbol d;
3087
3088 d = parseAggregate();
3089 s = new DeclarationStatement(loc, d);
3090 break;
3091 }
3092
3093 case TOK.TOKenum:
3094 { /* Determine if this is a manifest constant declaration,
3095 * or a conventional enum.
3096 */
3097 Dsymbol d;
3098 Token* tt = peek(&token);
3099 if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon)
3100 d = parseEnum();
3101 else if (tt.value != TOK.TOKidentifier)
3102 goto Ldeclaration;
3103 else
3104 {
3105 tt = peek(tt);
3106 if (tt.value == TOK.TOKlcurly || tt.value == TOK.TOKcolon ||
3107 tt.value == TOK.TOKsemicolon)
3108 d = parseEnum();
3109 else
3110 goto Ldeclaration;
3111 }
3112 s = new DeclarationStatement(loc, d);
3113 break;
3114 }
3115
3116 case TOK.TOKmixin:
3117 { t = peek(&token);
3118 if (t.value == TOK.TOKlparen)
3119 { // mixin(string)
3120 nextToken();
3121 check(TOK.TOKlparen, "mixin");
3122 Expression e = parseAssignExp();
3123 check(TOK.TOKrparen);
3124 check(TOK.TOKsemicolon);
3125 s = new CompileStatement(loc, e);
3126 break;
3127 }
3128 Dsymbol d = parseMixin();
3129 s = new DeclarationStatement(loc, d);
3130 break;
3131 }
3132
3133 case TOK.TOKlcurly:
3134 { Statements statements;
3135
3136 nextToken();
3137 statements = new Statements();
3138 while (token.value != TOK.TOKrcurly)
3139 {
3140 statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
3141 }
3142 endloc = this.loc;
3143 s = new CompoundStatement(loc, statements);
3144 if (flags & (ParseStatementFlags.PSscope | ParseStatementFlags.PScurlyscope))
3145 s = new ScopeStatement(loc, s);
3146 nextToken();
3147 break;
3148 }
3149
3150 case TOK.TOKwhile:
3151 { Expression condition2;
3152 Statement body_;
3153
3154 nextToken();
3155 check(TOK.TOKlparen);
3156 condition2 = parseExpression();
3157 check(TOK.TOKrparen);
3158 body_ = parseStatement(ParseStatementFlags.PSscope);
3159 s = new WhileStatement(loc, condition2, body_);
3160 break;
3161 }
3162
3163 case TOK.TOKsemicolon:
3164 if (!(flags & ParseStatementFlags.PSsemi))
3165 error("use '{ }' for an empty statement, not a ';'");
3166 nextToken();
3167 s = new ExpStatement(loc, null);
3168 break;
3169
3170 case TOK.TOKdo:
3171 { Statement body_;
3172 Expression condition2;
3173
3174 nextToken();
3175 body_ = parseStatement(ParseStatementFlags.PSscope);
3176 check(TOK.TOKwhile);
3177 check(TOK.TOKlparen);
3178 condition2 = parseExpression();
3179 check(TOK.TOKrparen);
3180 s = new DoStatement(loc, body_, condition2);
3181 break;
3182 }
3183
3184 case TOK.TOKfor:
3185 {
3186 Statement init;
3187 Expression condition2;
3188 Expression increment;
3189 Statement body_;
3190
3191 nextToken();
3192 check(TOK.TOKlparen);
3193 if (token.value == TOK.TOKsemicolon)
3194 { init = null;
3195 nextToken();
3196 }
3197 else
3198 { init = parseStatement(cast(ParseStatementFlags)0);
3199 }
3200 if (token.value == TOK.TOKsemicolon)
3201 {
3202 condition2 = null;
3203 nextToken();
3204 }
3205 else
3206 {
3207 condition2 = parseExpression();
3208 check(TOK.TOKsemicolon, "for condition");
3209 }
3210 if (token.value == TOK.TOKrparen)
3211 { increment = null;
3212 nextToken();
3213 }
3214 else
3215 { increment = parseExpression();
3216 check(TOK.TOKrparen);
3217 }
3218 body_ = parseStatement(ParseStatementFlags.PSscope);
3219 s = new ForStatement(loc, init, condition2, increment, body_);
3220 if (init)
3221 s = new ScopeStatement(loc, s);
3222 break;
3223 }
3224
3225 case TOK.TOKforeach:
3226 case TOK.TOKforeach_reverse:
3227 {
3228 TOK op = token.value;
3229 Arguments arguments;
3230
3231 Statement d;
3232 Statement body_;
3233 Expression aggr;
3234
3235 nextToken();
3236 check(TOK.TOKlparen);
3237
3238 arguments = new Arguments();
3239
3240 while (1)
3241 {
3242 Type tb;
3243 Identifier ai = null;
3244 Type at;
3245 STC storageClass = STC.STCundefined;
3246 Argument a;
3247
3248 if (token.value == TOK.TOKinout || token.value == TOK.TOKref)
3249 { storageClass = STC.STCref;
3250 nextToken();
3251 }
3252 if (token.value == TOK.TOKidentifier)
3253 {
3254 Token *tt = peek(&token);
3255 if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon)
3256 { ai = token.ident;
3257 at = null; // infer argument type
3258 nextToken();
3259 goto Larg;
3260 }
3261 }
3262 at = parseType(&ai);
3263 if (!ai)
3264 error("no identifier for declarator %s", at.toChars());
3265 Larg:
3266 a = new Argument(storageClass, at, ai, null);
3267 arguments.push(cast(void*)a);
3268 if (token.value == TOK.TOKcomma)
3269 { nextToken();
3270 continue;
3271 }
3272 break;
3273 }
3274 check(TOK.TOKsemicolon);
3275
3276 aggr = parseExpression();
3277 if (token.value == TOK.TOKslice && arguments.dim == 1)
3278 {
3279 Argument a = cast(Argument)arguments.data[0];
3280 delete arguments;
3281 nextToken();
3282 Expression upr = parseExpression();
3283 check(TOK.TOKrparen);
3284 body_ = parseStatement(cast(ParseStatementFlags)0);
3285 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body_);
3286 }
3287 else
3288 {
3289 check(TOK.TOKrparen);
3290 body_ = parseStatement(cast(ParseStatementFlags)0);
3291 s = new ForeachStatement(loc, op, arguments, aggr, body_);
3292 }
3293 break;
3294 }
3295
3296 case TOK.TOKif:
3297 { Argument arg = null;
3298 Expression condition2;
3299 Statement ifbody2;
3300 Statement elsebody2;
3301
3302 nextToken();
3303 check(TOK.TOKlparen);
3304
3305 if (token.value == TOK.TOKauto)
3306 {
3307 nextToken();
3308 if (token.value == TOK.TOKidentifier)
3309 {
3310 Token *tt = peek(&token);
3311 if (tt.value == TOK.TOKassign)
3312 {
3313 arg = new Argument(STC.STCundefined, null, token.ident, null);
3314 nextToken();
3315 nextToken();
3316 }
3317 else
3318 { error("= expected following auto identifier");
3319 goto Lerror;
3320 }
3321 }
3322 else
3323 { error("identifier expected following auto");
3324 goto Lerror;
3325 }
3326 }
3327 else if (isDeclaration(&token, 2, TOK.TOKassign, null))
3328 {
3329 Type at;
3330 Identifier ai;
3331
3332 at = parseType(&ai);
3333 check(TOK.TOKassign);
3334 arg = new Argument(STC.STCundefined, at, ai, null);
3335 }
3336
3337 // Check for " ident;"
3338 else if (token.value == TOK.TOKidentifier)
3339 {
3340 Token *tt = peek(&token);
3341 if (tt.value == TOK.TOKcomma || tt.value == TOK.TOKsemicolon)
3342 {
3343 arg = new Argument(STC.STCundefined, null, token.ident, null);
3344 nextToken();
3345 nextToken();
3346 if (1 || !global.params.useDeprecated)
3347 error("if (v; e) is deprecated, use if (auto v = e)");
3348 }
3349 }
3350
3351 condition2 = parseExpression();
3352 check(TOK.TOKrparen);
3353 ifbody2 = parseStatement(ParseStatementFlags.PSscope);
3354 if (token.value == TOK.TOKelse)
3355 {
3356 nextToken();
3357 elsebody2 = parseStatement(ParseStatementFlags.PSscope);
3358 }
3359 else
3360 elsebody2 = null;
3361 s = new IfStatement(loc, arg, condition2, ifbody2, elsebody2);
3362 break;
3363 }
3364
3365 case TOK.TOKscope:
3366 if (peek(&token).value != TOK.TOKlparen)
3367 goto Ldeclaration; // scope used as storage class
3368 nextToken();
3369 check(TOK.TOKlparen);
3370 if (token.value != TOK.TOKidentifier)
3371 { error("scope identifier expected");
3372 goto Lerror;
3373 }
3374 else
3375 { TOK tt = TOK.TOKon_scope_exit;
3376 Identifier id = token.ident;
3377
3378 if (id == Id.exit)
3379 tt = TOK.TOKon_scope_exit;
3380 else if (id == Id.failure)
3381 tt = TOK.TOKon_scope_failure;
3382 else if (id == Id.success)
3383 tt = TOK.TOKon_scope_success;
3384 else
3385 error("valid scope identifiers are exit, failure, or success, not %s", id.toChars());
3386 nextToken();
3387 check(TOK.TOKrparen);
3388 Statement st = parseStatement(ParseStatementFlags.PScurlyscope);
3389 s = new OnScopeStatement(loc, tt, st);
3390 break;
3391 }
3392
3393 case TOK.TOKdebug:
3394 nextToken();
3395 condition = parseDebugCondition();
3396 goto Lcondition;
3397
3398 case TOK.TOKversion:
3399 nextToken();
3400 condition = parseVersionCondition();
3401 goto Lcondition;
3402
3403 Lcondition:
3404 ifbody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/);
3405 elsebody = null;
3406 if (token.value == TOK.TOKelse)
3407 {
3408 nextToken();
3409 elsebody = parseStatement(cast(ParseStatementFlags)0 /*ParseStatementFlags.PSsemi*/);
3410 }
3411 s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3412 break;
3413
3414 case TOK.TOKpragma:
3415 { Identifier ident;
3416 Expressions args = null;
3417 Statement body_;
3418
3419 nextToken();
3420 check(TOK.TOKlparen);
3421 if (token.value != TOK.TOKidentifier)
3422 { error("pragma(identifier expected");
3423 goto Lerror;
3424 }
3425 ident = token.ident;
3426 nextToken();
3427 if (token.value == TOK.TOKcomma && peekNext() != TOK.TOKrparen)
3428 args = parseArguments(); // pragma(identifier, args...);
3429 else
3430 check(TOK.TOKrparen); // pragma(identifier);
3431 if (token.value == TOK.TOKsemicolon)
3432 { nextToken();
3433 body_ = null;
3434 }
3435 else
3436 body_ = parseStatement(ParseStatementFlags.PSsemi);
3437 s = new PragmaStatement(loc, ident, args, body_);
3438 break;
3439 }
3440
3441 case TOK.TOKswitch:
3442 isfinal = false;
3443 goto Lswitch;
3444
3445 Lswitch:
3446 {
3447 nextToken();
3448 check(TOK.TOKlparen);
3449 Expression condition2 = parseExpression();
3450 check(TOK.TOKrparen);
3451 Statement body_ = parseStatement(ParseStatementFlags.PSscope);
3452 s = new SwitchStatement(loc, condition2, body_, isfinal);
3453 break;
3454 }
3455
3456 case TOK.TOKcase:
3457 { Expression exp;
3458 Statements statements;
3459 scope Array cases = new Array(); // array of Expression's
3460 Expression last = null;
3461
3462 while (1)
3463 {
3464 nextToken();
3465 exp = parseAssignExp();
3466 cases.push(cast(void*)exp);
3467 if (token.value != TOK.TOKcomma)
3468 break;
3469 }
3470 check(TOK.TOKcolon);
3471
3472 version (DMDV2) {
3473 /* case exp: .. case last:
3474 */
3475 if (token.value == TOK.TOKslice)
3476 {
3477 if (cases.dim > 1)
3478 error("only one case allowed for start of case range");
3479 nextToken();
3480 check(TOK.TOKcase);
3481 last = parseAssignExp();
3482 check(TOK.TOKcolon);
3483 }
3484 }
3485
3486 statements = new Statements();
3487 while (token.value != TOK.TOKcase &&
3488 token.value != TOK.TOKdefault &&
3489 token.value != TOK.TOKrcurly)
3490 {
3491 statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
3492 }
3493 s = new CompoundStatement(loc, statements);
3494 s = new ScopeStatement(loc, s);
3495
3496 ///version (DMDV2) {
3497 if (last)
3498 {
3499 s = new CaseRangeStatement(loc, exp, last, s);
3500 }
3501 else
3502 ///}
3503 {
3504 // Keep cases in order by building the case statements backwards
3505 for (int i = cases.dim; i; i--)
3506 {
3507 exp = cast(Expression)cases.data[i - 1];
3508 s = new CaseStatement(loc, exp, s);
3509 }
3510 }
3511 break;
3512 }
3513
3514 case TOK.TOKdefault:
3515 {
3516 Statements statements;
3517
3518 nextToken();
3519 check(TOK.TOKcolon);
3520
3521 statements = new Statements();
3522 while (token.value != TOK.TOKcase &&
3523 token.value != TOK.TOKdefault &&
3524 token.value != TOK.TOKrcurly)
3525 {
3526 statements.push(cast(void*)parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope));
3527 }
3528 s = new CompoundStatement(loc, statements);
3529 s = new ScopeStatement(loc, s);
3530 s = new DefaultStatement(loc, s);
3531 break;
3532 }
3533
3534 case TOK.TOKreturn:
3535 { Expression exp;
3536
3537 nextToken();
3538 if (token.value == TOK.TOKsemicolon)
3539 exp = null;
3540 else
3541 exp = parseExpression();
3542 check(TOK.TOKsemicolon, "return statement");
3543 s = new ReturnStatement(loc, exp);
3544 break;
3545 }
3546
3547 case TOK.TOKbreak:
3548 { Identifier ident;
3549
3550 nextToken();
3551 if (token.value == TOK.TOKidentifier)
3552 { ident = token.ident;
3553 nextToken();
3554 }
3555 else
3556 ident = null;
3557 check(TOK.TOKsemicolon, "break statement");
3558 s = new BreakStatement(loc, ident);
3559 break;
3560 }
3561
3562 case TOK.TOKcontinue:
3563 { Identifier ident;
3564
3565 nextToken();
3566 if (token.value == TOK.TOKidentifier)
3567 { ident = token.ident;
3568 nextToken();
3569 }
3570 else
3571 ident = null;
3572 check(TOK.TOKsemicolon, "continue statement");
3573 s = new ContinueStatement(loc, ident);
3574 break;
3575 }
3576
3577 case TOK.TOKgoto:
3578 { Identifier ident;
3579
3580 nextToken();
3581 if (token.value == TOK.TOKdefault)
3582 {
3583 nextToken();
3584 s = new GotoDefaultStatement(loc);
3585 }
3586 else if (token.value == TOK.TOKcase)
3587 {
3588 Expression exp = null;
3589
3590 nextToken();
3591 if (token.value != TOK.TOKsemicolon)
3592 exp = parseExpression();
3593 s = new GotoCaseStatement(loc, exp);
3594 }
3595 else
3596 {
3597 if (token.value != TOK.TOKidentifier)
3598 { error("Identifier expected following goto");
3599 ident = null;
3600 }
3601 else
3602 { ident = token.ident;
3603 nextToken();
3604 }
3605 s = new GotoStatement(loc, ident);
3606 }
3607 check(TOK.TOKsemicolon, "goto statement");
3608 break;
3609 }
3610
3611 case TOK.TOKsynchronized:
3612 { Expression exp;
3613 Statement body_;
3614
3615 nextToken();
3616 if (token.value == TOK.TOKlparen)
3617 {
3618 nextToken();
3619 exp = parseExpression();
3620 check(TOK.TOKrparen);
3621 }
3622 else
3623 exp = null;
3624 body_ = parseStatement(ParseStatementFlags.PSscope);
3625 s = new SynchronizedStatement(loc, exp, body_);
3626 break;
3627 }
3628
3629 case TOK.TOKwith:
3630 { Expression exp;
3631 Statement body_;
3632
3633 nextToken();
3634 check(TOK.TOKlparen);
3635 exp = parseExpression();
3636 check(TOK.TOKrparen);
3637 body_ = parseStatement(ParseStatementFlags.PSscope);
3638 s = new WithStatement(loc, exp, body_);
3639 break;
3640 }
3641
3642 case TOK.TOKtry:
3643 { Statement body_;
3644 Array catches = null;
3645 Statement finalbody = null;
3646
3647 nextToken();
3648 body_ = parseStatement(ParseStatementFlags.PSscope);
3649 while (token.value == TOK.TOKcatch)
3650 {
3651 Statement handler;
3652 Catch c;
3653 Type tt;
3654 Identifier id;
3655 Loc loc2 = this.loc;
3656
3657 nextToken();
3658 if (token.value == TOK.TOKlcurly)
3659 {
3660 tt = null;
3661 id = null;
3662 }
3663 else
3664 {
3665 check(TOK.TOKlparen);
3666 id = null;
3667 tt = parseType(&id);
3668 check(TOK.TOKrparen);
3669 }
3670 handler = parseStatement(cast(ParseStatementFlags)0);
3671 c = new Catch(loc2, tt, id, handler);
3672 if (!catches)
3673 catches = new Array();
3674 catches.push(cast(void*)c);
3675 }
3676
3677 if (token.value == TOK.TOKfinally)
3678 { nextToken();
3679 finalbody = parseStatement(cast(ParseStatementFlags)0);
3680 }
3681
3682 s = body_;
3683 if (!catches && !finalbody)
3684 error("catch or finally expected following try");
3685 else
3686 { if (catches)
3687 s = new TryCatchStatement(loc, body_, catches);
3688 if (finalbody)
3689 s = new TryFinallyStatement(loc, s, finalbody);
3690 }
3691 break;
3692 }
3693
3694 case TOK.TOKthrow:
3695 { Expression exp;
3696
3697 nextToken();
3698 exp = parseExpression();
3699 check(TOK.TOKsemicolon, "throw statement");
3700 s = new ThrowStatement(loc, exp);
3701 break;
3702 }
3703
3704 case TOK.TOKvolatile:
3705 nextToken();
3706 s = parseStatement(ParseStatementFlags.PSsemi | ParseStatementFlags.PScurlyscope);
3707 version (DMDV2) {
3708 if (!global.params.useDeprecated)
3709 error("volatile statements deprecated; used synchronized statements instead");
3710 }
3711 s = new VolatileStatement(loc, s);
3712 break;
3713
3714 case TOK.TOKasm:
3715 { Statements statements;
3716 Identifier label;
3717 Loc labelloc;
3718 Token* toklist;
3719 Token** ptoklist;
3720
3721 // Parse the asm block into a sequence of AsmStatements,
3722 // each AsmStatement is one instruction.
3723 // Separate out labels.
3724 // Defer parsing of AsmStatements until semantic processing.
3725
3726 nextToken();
3727 check(TOK.TOKlcurly);
3728 toklist = null;
3729 ptoklist = &toklist;
3730 label = null;
3731 statements = new Statements();
3732 while (1)
3733 {
3734 switch (token.value)
3735 {
3736 case TOK.TOKidentifier:
3737 if (!toklist)
3738 {
3739 // Look ahead to see if it is a label
3740 t = peek(&token);
3741 if (t.value == TOK.TOKcolon)
3742 { // It's a label
3743 label = token.ident;
3744 labelloc = this.loc;
3745 nextToken();
3746 nextToken();
3747 continue;
3748 }
3749 }
3750 goto Ldefault;
3751
3752 case TOK.TOKrcurly:
3753 if (toklist || label)
3754 {
3755 error("asm statements must end in ';'");
3756 }
3757 break;
3758
3759 case TOK.TOKsemicolon:
3760 s = null;
3761 if (toklist || label)
3762 { // Create AsmStatement from list of tokens we've saved
3763 s = new AsmStatement(this.loc, toklist);
3764 toklist = null;
3765 ptoklist = &toklist;
3766 if (label)
3767 {
3768 s = new LabelStatement(labelloc, label, s);
3769 label = null;
3770 }
3771 statements.push(cast(void*)s);
3772 }
3773 nextToken();
3774 continue;
3775
3776 case TOK.TOKeof:
3777 /* { */
3778 error("matching '}' expected, not end of file");
3779 break;
3780
3781 default:
3782 Ldefault:
3783 *ptoklist = new Token();
3784 memcpy(*ptoklist, &token, Token.sizeof);
3785 ptoklist = &(*ptoklist).next;
3786 *ptoklist = null;
3787
3788 nextToken();
3789 continue;
3790 }
3791 break;
3792 }
3793 s = new CompoundStatement(loc, statements);
3794 nextToken();
3795 break;
3796 }
3797
3798 default:
3799 error("found '%s' instead of statement", token.toChars());
3800 goto Lerror;
3801
3802 Lerror:
3803 while (token.value != TOK.TOKrcurly &&
3804 token.value != TOK.TOKsemicolon &&
3805 token.value != TOK.TOKeof)
3806 nextToken();
3807 if (token.value == TOK.TOKsemicolon)
3808 nextToken();
3809 s = null;
3810 break;
3811 }
3812
3813 return s;
3814 }
3815
3816 /*****************************************
3817 * Parse initializer for variable declaration.
3818 */
3819 Initializer parseInitializer()
3820 {
3821 StructInitializer is_;
3822 ArrayInitializer ia;
3823 ExpInitializer ie;
3824 Expression e;
3825 Identifier id;
3826 Initializer value;
3827 int comma;
3828 Loc loc = this.loc;
3829 Token* t;
3830 int braces;
3831 int brackets;
3832
3833 switch (token.value)
3834 {
3835 case TOK.TOKlcurly:
3836 /* Scan ahead to see if it is a struct initializer or
3837 * a function literal.
3838 * If it contains a ';', it is a function literal.
3839 * Treat { } as a struct initializer.
3840 */
3841 braces = 1;
3842 for (t = peek(&token); 1; t = peek(t))
3843 {
3844 switch (t.value)
3845 {
3846 case TOK.TOKsemicolon:
3847 case TOK.TOKreturn:
3848 goto Lexpression;
3849
3850 case TOK.TOKlcurly:
3851 braces++;
3852 continue;
3853
3854 case TOK.TOKrcurly:
3855 if (--braces == 0)
3856 break;
3857 continue;
3858
3859 case TOK.TOKeof:
3860 break;
3861
3862 default:
3863 continue;
3864 }
3865 break;
3866 }
3867
3868 is_ = new StructInitializer(loc);
3869 nextToken();
3870 comma = 0;
3871 while (1)
3872 {
3873 switch (token.value)
3874 {
3875 case TOK.TOKidentifier:
3876 if (comma == 1)
3877 error("comma expected separating field initializers");
3878 t = peek(&token);
3879 if (t.value == TOK.TOKcolon)
3880 {
3881 id = token.ident;
3882 nextToken();
3883 nextToken(); // skip over ':'
3884 }
3885 else
3886 {
3887 id = null;
3888 }
3889 value = parseInitializer();
3890 is_.addInit(id, value);
3891 comma = 1;
3892 continue;
3893
3894 case TOK.TOKcomma:
3895 nextToken();
3896 comma = 2;
3897 continue;
3898
3899 case TOK.TOKrcurly: // allow trailing comma's
3900 nextToken();
3901 break;
3902
3903 case TOK.TOKeof:
3904 error("found EOF instead of initializer");
3905 break;
3906
3907 default:
3908 value = parseInitializer();
3909 is_.addInit(null, value);
3910 comma = 1;
3911 continue;
3912 //error("found '%s' instead of field initializer", token.toChars());
3913 //break;
3914 }
3915 break;
3916 }
3917 return is_;
3918
3919 case TOK.TOKlbracket:
3920 /* Scan ahead to see if it is an array initializer or
3921 * an expression.
3922 * If it ends with a ';' ',' or '}', it is an array initializer.
3923 */
3924 brackets = 1;
3925 for (t = peek(&token); 1; t = peek(t))
3926 {
3927 switch (t.value)
3928 {
3929 case TOK.TOKlbracket:
3930 brackets++;
3931 continue;
3932
3933 case TOK.TOKrbracket:
3934 if (--brackets == 0)
3935 {
3936 t = peek(t);
3937 if (t.value != TOK.TOKsemicolon &&
3938 t.value != TOK.TOKcomma &&
3939 t.value != TOK.TOKrcurly)
3940 goto Lexpression;
3941 break;
3942 }
3943 continue;
3944
3945 case TOK.TOKeof:
3946 break;
3947
3948 default:
3949 continue;
3950 }
3951 break;
3952 }
3953
3954 ia = new ArrayInitializer(loc);
3955 nextToken();
3956 comma = 0;
3957 while (true)
3958 {
3959 switch (token.value)
3960 {
3961 default:
3962 if (comma == 1)
3963 {
3964 error("comma expected separating array initializers, not %s", token.toChars());
3965 nextToken();
3966 break;
3967 }
3968 e = parseAssignExp();
3969 if (!e)
3970 break;
3971 if (token.value == TOK.TOKcolon)
3972 {
3973 nextToken();
3974 value = parseInitializer();
3975 }
3976 else
3977 { value = new ExpInitializer(e.loc, e);
3978 e = null;
3979 }
3980 ia.addInit(e, value);
3981 comma = 1;
3982 continue;
3983
3984 case TOK.TOKlcurly:
3985 case TOK.TOKlbracket:
3986 if (comma == 1)
3987 error("comma expected separating array initializers, not %s", token.toChars());
3988 value = parseInitializer();
3989 ia.addInit(null, value);
3990 comma = 1;
3991 continue;
3992
3993 case TOK.TOKcomma:
3994 nextToken();
3995 comma = 2;
3996 continue;
3997
3998 case TOK.TOKrbracket: // allow trailing comma's
3999 nextToken();
4000 break;
4001
4002 case TOK.TOKeof:
4003 error("found '%s' instead of array initializer", token.toChars());
4004 break;
4005 }
4006 break;
4007 }
4008 return ia;
4009
4010 case TOK.TOKvoid:
4011 t = peek(&token);
4012 if (t.value == TOK.TOKsemicolon || t.value == TOK.TOKcomma)
4013 {
4014 nextToken();
4015 return new VoidInitializer(loc);
4016 }
4017 goto Lexpression;
4018
4019 default:
4020 Lexpression:
4021 e = parseAssignExp();
4022 ie = new ExpInitializer(loc, e);
4023 return ie;
4024 }
4025 }
4026
4027 /*****************************************
4028 * Parses default argument initializer expression that is an assign expression,
4029 * with special handling for __FILE__ and __LINE__.
4030 */
4031 version (DMDV2) {
4032 Expression parseDefaultInitExp()
4033 {
4034 if (token.value == TOK.TOKfile ||
4035 token.value == TOK.TOKline)
4036 {
4037 Token* t = peek(&token);
4038 if (t.value == TOK.TOKcomma || t.value == TOK.TOKrparen)
4039 {
4040 Expression e;
4041
4042 if (token.value == TOK.TOKfile)
4043 e = new FileInitExp(loc);
4044 else
4045 e = new LineInitExp(loc);
4046 nextToken();
4047 return e;
4048 }
4049 }
4050
4051 Expression e = parseAssignExp();
4052 return e;
4053 }
4054 }
4055 void check(Loc loc, TOK value)
4056 {
4057 if (token.value != value)
4058 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token.toChars(value));
4059 nextToken();
4060 }
4061
4062 void check(TOK value)
4063 {
4064 check(loc, value);
4065 }
4066
4067 void check(TOK value, string string_)
4068 {
4069 if (token.value != value) {
4070 error("found '%s' when expecting '%s' following '%s'", token.toChars(), Token.toChars(value), string_);
4071 }
4072 nextToken();
4073 }
4074
4075 /************************************
4076 * Determine if the scanner is sitting on the start of a declaration.
4077 * Input:
4078 * needId 0 no identifier
4079 * 1 identifier optional
4080 * 2 must have identifier
4081 * Output:
4082 * if *pt is not null, it is set to the ending token, which would be endtok
4083 */
4084
4085 bool isDeclaration(Token* t, int needId, TOK endtok, Token** pt)
4086 {
4087 //printf("isDeclaration(needId = %d)\n", needId);
4088 int haveId = 0;
4089
4090 version (DMDV2) {
4091 if ((t.value == TOK.TOKconst ||
4092 t.value == TOK.TOKinvariant ||
4093 t.value == TOK.TOKimmutable ||
4094 t.value == TOK.TOKshared) &&
4095 peek(t).value != TOK.TOKlparen)
4096 {
4097 /* const type
4098 * immutable type
4099 * shared type
4100 */
4101 t = peek(t);
4102 }
4103 }
4104
4105 if (!isBasicType(&t))
4106 {
4107 goto Lisnot;
4108 }
4109 if (!isDeclarator(&t, &haveId, endtok))
4110 goto Lisnot;
4111 if ( needId == 1 ||
4112 (needId == 0 && !haveId) ||
4113 (needId == 2 && haveId))
4114 {
4115 if (pt)
4116 *pt = t;
4117 goto Lis;
4118 }
4119 else
4120 goto Lisnot;
4121
4122 Lis:
4123 //printf("\tis declaration, t = %s\n", t.toChars());
4124 return true;
4125
4126 Lisnot:
4127 //printf("\tis not declaration\n");
4128 return false;
4129 }
4130
4131 bool isBasicType(Token** pt)
4132 {
4133 // This code parallels parseBasicType()
4134 Token* t = *pt;
4135 Token* t2;
4136 int parens;
4137 int haveId = 0;
4138
4139 switch (t.value)
4140 {
4141 case TOKwchar:
4142 case TOKdchar:
4143 case TOKbit:
4144 case TOKbool:
4145 case TOKchar:
4146 case TOKint8:
4147 case TOKuns8:
4148 case TOKint16:
4149 case TOKuns16:
4150 case TOKint32:
4151 case TOKuns32:
4152 case TOKint64:
4153 case TOKuns64:
4154 case TOKfloat32:
4155 case TOKfloat64:
4156 case TOKfloat80:
4157 case TOKimaginary32:
4158 case TOKimaginary64:
4159 case TOKimaginary80:
4160 case TOKcomplex32:
4161 case TOKcomplex64:
4162 case TOKcomplex80:
4163 case TOKvoid:
4164 t = peek(t);
4165 break;
4166
4167 case TOK.TOKidentifier:
4168 L5:
4169 t = peek(t);
4170 if (t.value == TOK.TOKnot)
4171 {
4172 goto L4;
4173 }
4174 goto L3;
4175 while (1)
4176 {
4177 L2:
4178 t = peek(t);
4179 L3:
4180 if (t.value == TOK.TOKdot)
4181 {
4182 Ldot:
4183 t = peek(t);
4184 if (t.value != TOK.TOKidentifier)
4185 goto Lfalse;
4186 t = peek(t);
4187 if (t.value != TOK.TOKnot)
4188 goto L3;
4189 L4:
4190 /* Seen a !
4191 * Look for:
4192 * !( args ), !identifier, etc.
4193 */
4194 t = peek(t);
4195 switch (t.value)
4196 { case TOK.TOKidentifier:
4197 goto L5;
4198 case TOK.TOKlparen:
4199 if (!skipParens(t, &t))
4200 goto Lfalse;
4201 break;
4202 case TOK.TOKwchar: case TOK.TOKdchar:
4203 case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
4204 case TOK.TOKint8: case TOK.TOKuns8:
4205 case TOK.TOKint16: case TOK.TOKuns16:
4206 case TOK.TOKint32: case TOK.TOKuns32:
4207 case TOK.TOKint64: case TOK.TOKuns64:
4208 case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
4209 case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
4210 case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
4211 case TOK.TOKvoid:
4212 case TOK.TOKint32v:
4213 case TOK.TOKuns32v:
4214 case TOK.TOKint64v:
4215 case TOK.TOKuns64v:
4216 case TOK.TOKfloat32v:
4217 case TOK.TOKfloat64v:
4218 case TOK.TOKfloat80v:
4219 case TOK.TOKimaginary32v:
4220 case TOK.TOKimaginary64v:
4221 case TOK.TOKimaginary80v:
4222 case TOK.TOKnull:
4223 case TOK.TOKtrue:
4224 case TOK.TOKfalse:
4225 case TOK.TOKcharv:
4226 case TOK.TOKwcharv:
4227 case TOK.TOKdcharv:
4228 case TOK.TOKstring:
4229 case TOK.TOKfile:
4230 case TOK.TOKline:
4231 goto L2;
4232 default:
4233 goto Lfalse;
4234 }
4235 }
4236 else
4237 break;
4238 }
4239 break;
4240
4241 case TOK.TOKdot:
4242 goto Ldot;
4243
4244 case TOK.TOKtypeof:
4245 /* typeof(exp).identifier...
4246 */
4247 t = peek(t);
4248 if (t.value != TOK.TOKlparen)
4249 goto Lfalse;
4250 if (!skipParens(t, &t))
4251 goto Lfalse;
4252 goto L2;
4253
4254 case TOK.TOKconst:
4255 case TOK.TOKinvariant:
4256 case TOK.TOKimmutable:
4257 case TOK.TOKshared:
4258 // const(type) or immutable(type) or shared(type)
4259 t = peek(t);
4260 if (t.value != TOK.TOKlparen)
4261 goto Lfalse;
4262 t = peek(t);
4263 if (!isDeclaration(t, 0, TOK.TOKrparen, &t))
4264 {
4265 goto Lfalse;
4266 }
4267 t = peek(t);
4268 break;
4269
4270 default:
4271 goto Lfalse;
4272 }
4273 *pt = t;
4274 //printf("is\n");
4275 return true;
4276
4277 Lfalse:
4278 //printf("is not\n");
4279 return false;
4280 }
4281
4282 bool isDeclarator(Token** pt, int* haveId, TOK endtok)
4283 {
4284 // This code parallels parseDeclarator()
4285 Token* t = *pt;
4286 bool parens;
4287
4288 //printf("Parser.isDeclarator()\n");
4289 //t.print();
4290 if (t.value == TOK.TOKassign)
4291 return false;
4292
4293 while (true)
4294 {
4295 parens = false;
4296 switch (t.value)
4297 {
4298 case TOK.TOKmul:
4299 //case TOKand:
4300 t = peek(t);
4301 continue;
4302
4303 case TOK.TOKlbracket:
4304 t = peek(t);
4305 if (t.value == TOK.TOKrbracket)
4306 {
4307 t = peek(t);
4308 }
4309 else if (isDeclaration(t, 0, TOK.TOKrbracket, &t))
4310 {
4311 // It's an associative array declaration
4312 t = peek(t);
4313 }
4314 else
4315 {
4316 // [ expression ]
4317 // [ expression .. expression ]
4318 if (!isExpression(&t))
4319 return false;
4320 if (t.value == TOK.TOKslice)
4321 {
4322 t = peek(t);
4323 if (!isExpression(&t))
4324 return false;
4325 }
4326 if (t.value != TOK.TOKrbracket)
4327 return false;
4328 t = peek(t);
4329 }
4330 continue;
4331
4332 case TOK.TOKidentifier:
4333 if (*haveId)
4334 return false;
4335 *haveId = true;
4336 t = peek(t);
4337 break;
4338
4339 case TOK.TOKlparen:
4340 t = peek(t);
4341
4342 if (t.value == TOK.TOKrparen)
4343 return false; // () is not a declarator
4344
4345 /* Regard ( identifier ) as not a declarator
4346 * BUG: what about ( *identifier ) in
4347 * f(*p)(x);
4348 * where f is a class instance with overloaded () ?
4349 * Should we just disallow C-style function pointer declarations?
4350 */
4351 if (t.value == TOK.TOKidentifier)
4352 {
4353 Token *t2 = peek(t);
4354 if (t2.value == TOK.TOKrparen)
4355 return false;
4356 }
4357
4358 if (!isDeclarator(&t, haveId, TOK.TOKrparen))
4359 return false;
4360 t = peek(t);
4361 parens = true;
4362 break;
4363
4364 case TOK.TOKdelegate:
4365 case TOK.TOKfunction:
4366 t = peek(t);
4367 if (!isParameters(&t))
4368 return false;
4369 continue;
4370 default:
4371 break; ///
4372 }
4373 break;
4374 }
4375
4376 while (1)
4377 {
4378 switch (t.value)
4379 {
4380 version (CARRAYDECL) {
4381 case TOK.TOKlbracket:
4382 parens = false;
4383 t = peek(t);
4384 if (t.value == TOK.TOKrbracket)
4385 {
4386 t = peek(t);
4387 }
4388 else if (isDeclaration(t, 0, TOKrbracket, &t))
4389 {
4390 // It's an associative array declaration
4391 t = peek(t);
4392 }
4393 else
4394 {
4395 // [ expression ]
4396 if (!isExpression(&t))
4397 return false;
4398 if (t.value != TOK.TOKrbracket)
4399 return false;
4400 t = peek(t);
4401 }
4402 continue;
4403 }
4404
4405 case TOK.TOKlparen:
4406 parens = false;
4407 if (!isParameters(&t))
4408 return false;
4409 version (DMDV2) {
4410 while (true)
4411 {
4412 switch (t.value)
4413 {
4414 case TOK.TOKconst:
4415 case TOK.TOKinvariant:
4416 case TOK.TOKimmutable:
4417 case TOK.TOKshared:
4418 case TOK.TOKpure:
4419 case TOK.TOKnothrow:
4420 t = peek(t);
4421 continue;
4422 case TOK.TOKat:
4423 t = peek(t); // skip '@'
4424 t = peek(t); // skip identifier
4425 continue;
4426 default:
4427 break;
4428 }
4429 break;
4430 }
4431 }
4432 continue;
4433
4434 // Valid tokens that follow a declaration
4435 case TOK.TOKrparen:
4436 case TOK.TOKrbracket:
4437 case TOK.TOKassign:
4438 case TOK.TOKcomma:
4439 case TOK.TOKsemicolon:
4440 case TOK.TOKlcurly:
4441 case TOK.TOKin:
4442 // The !parens is to disallow unnecessary parentheses
4443 if (!parens && (endtok == TOK.TOKreserved || endtok == t.value))
4444 {
4445 *pt = t;
4446 return true;
4447 }
4448 return false;
4449
4450 default:
4451 return false;
4452 }
4453 }
4454 }
4455
4456 bool isParameters(Token** pt)
4457 {
4458 // This code parallels parseParameters()
4459 Token* t = *pt;
4460
4461 //printf("isParameters()\n");
4462 if (t.value != TOKlparen)
4463 return false;
4464
4465 t = peek(t);
4466 for (;1; t = peek(t))
4467 {
4468 L1:
4469 switch (t.value)
4470 {
4471 case TOKrparen:
4472 break;
4473
4474 case TOKdotdotdot:
4475 t = peek(t);
4476 break;
4477
4478 case TOKin:
4479 case TOKout:
4480 case TOKinout:
4481 case TOKref:
4482 case TOKlazy:
4483 case TOKfinal:
4484 continue;
4485
4486 case TOKconst:
4487 case TOKinvariant:
4488 case TOKimmutable:
4489 case TOKshared:
4490 t = peek(t);
4491 if (t.value == TOKlparen)
4492 {
4493 t = peek(t);
4494 if (!isDeclaration(t, 0, TOKrparen, &t))
4495 return false;
4496 t = peek(t); // skip past closing ')'
4497 goto L2;
4498 }
4499 goto L1;
4500
4501 static if (false) {
4502 case TOKstatic:
4503 continue;
4504 case TOKauto:
4505 case TOKalias:
4506 t = peek(t);
4507 if (t.value == TOKidentifier)
4508 t = peek(t);
4509 if (t.value == TOKassign)
4510 { t = peek(t);
4511 if (!isExpression(&t))
4512 return false;
4513 }
4514 goto L3;
4515 }
4516
4517 default:
4518 {
4519 if (!isBasicType(&t))
4520 return false;
4521 L2:
4522 int tmp = false;
4523 if (t.value != TOKdotdotdot &&
4524 !isDeclarator(&t, &tmp, TOKreserved))
4525 return false;
4526 if (t.value == TOKassign)
4527 {
4528 t = peek(t);
4529 if (!isExpression(&t))
4530 return false;
4531 }
4532 if (t.value == TOKdotdotdot)
4533 {
4534 t = peek(t);
4535 break;
4536 }
4537 }
4538 L3:
4539 if (t.value == TOKcomma)
4540 {
4541 continue;
4542 }
4543 break;
4544 }
4545 break;
4546 }
4547
4548 if (t.value != TOKrparen)
4549 return false;
4550
4551 t = peek(t);
4552 *pt = t;
4553 return true;
4554 }
4555
4556 bool isExpression(Token** pt)
4557 {
4558 // This is supposed to determine if something is an expression.
4559 // What it actually does is scan until a closing right bracket
4560 // is found.
4561
4562 Token* t = *pt;
4563 int brnest = 0;
4564 int panest = 0;
4565 int curlynest = 0;
4566
4567 for (;; t = peek(t))
4568 {
4569 switch (t.value)
4570 {
4571 case TOKlbracket:
4572 brnest++;
4573 continue;
4574
4575 case TOKrbracket:
4576 if (--brnest >= 0)
4577 continue;
4578 break;
4579
4580 case TOKlparen:
4581 panest++;
4582 continue;
4583
4584 case TOKcomma:
4585 if (brnest || panest)
4586 continue;
4587 break;
4588
4589 case TOKrparen:
4590 if (--panest >= 0)
4591 continue;
4592 break;
4593
4594 case TOKlcurly:
4595 curlynest++;
4596 continue;
4597
4598 case TOKrcurly:
4599 if (--curlynest >= 0)
4600 continue;
4601 return false;
4602
4603 case TOKslice:
4604 if (brnest)
4605 continue;
4606 break;
4607
4608 case TOKsemicolon:
4609 if (curlynest)
4610 continue;
4611 return false;
4612
4613 case TOKeof:
4614 return false;
4615
4616 default:
4617 continue;
4618 }
4619 break;
4620 }
4621
4622 *pt = t;
4623 return true;
4624 }
4625
4626 int isTemplateInstance(Token t, Token* pt)
4627 {
4628 assert(false);
4629 }
4630
4631 /*******************************************
4632 * Skip parens, brackets.
4633 * Input:
4634 * t is on opening (
4635 * Output:
4636 * *pt is set to closing token, which is ')' on success
4637 * Returns:
4638 * !=0 successful
4639 * 0 some parsing error
4640 */
4641 bool skipParens(Token* t, Token** pt)
4642 {
4643 int parens = 0;
4644
4645 while (1)
4646 {
4647 switch (t.value)
4648 {
4649 case TOKlparen:
4650 parens++;
4651 break;
4652
4653 case TOKrparen:
4654 parens--;
4655 if (parens < 0)
4656 goto Lfalse;
4657 if (parens == 0)
4658 goto Ldone;
4659 break;
4660
4661 case TOKeof:
4662 case TOKsemicolon:
4663 goto Lfalse;
4664
4665 default:
4666 break;
4667 }
4668 t = peek(t);
4669 }
4670
4671 Ldone:
4672 if (*pt)
4673 *pt = t;
4674 return true;
4675
4676 Lfalse:
4677 return false;
4678 }
4679
4680 Expression parseExpression()
4681 {
4682 Expression e;
4683 Expression e2;
4684 Loc loc = this.loc;
4685
4686 //printf("Parser.parseExpression() loc = %d\n", loc.linnum);
4687 e = parseAssignExp();
4688 while (token.value == TOK.TOKcomma)
4689 {
4690 nextToken();
4691 e2 = parseAssignExp();
4692 e = new CommaExp(loc, e, e2);
4693 loc = this.loc;
4694 }
4695 return e;
4696 }
4697
4698 Expression parsePrimaryExp()
4699 {
4700 Expression e;
4701 Type t;
4702 Identifier id;
4703 TOK save;
4704 Loc loc = this.loc;
4705
4706 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4707 switch (token.value)
4708 {
4709 case TOK.TOKidentifier:
4710 id = token.ident;
4711 nextToken();
4712 if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis)
4713 { // identifier!(template-argument-list)
4714 TemplateInstance tempinst;
4715
4716 tempinst = new TemplateInstance(loc, id);
4717 nextToken();
4718 if (token.value == TOK.TOKlparen)
4719 // ident!(template_arguments)
4720 tempinst.tiargs = parseTemplateArgumentList();
4721 else
4722 // ident!template_argument
4723 tempinst.tiargs = parseTemplateArgument();
4724 e = new ScopeExp(loc, tempinst);
4725 }
4726 else
4727 e = new IdentifierExp(loc, id);
4728 break;
4729
4730 case TOK.TOKdollar:
4731 if (!inBrackets)
4732 error("'$' is valid only inside [] of index or slice");
4733 e = new DollarExp(loc);
4734 nextToken();
4735 break;
4736
4737 case TOK.TOKdot:
4738 // Signal global scope '.' operator with "" identifier
4739 e = new IdentifierExp(loc, Id.empty);
4740 break;
4741
4742 case TOK.TOKthis:
4743 e = new ThisExp(loc);
4744 nextToken();
4745 break;
4746
4747 case TOK.TOKsuper:
4748 e = new SuperExp(loc);
4749 nextToken();
4750 break;
4751
4752 case TOK.TOKint32v:
4753 e = new IntegerExp(loc, token.int32value, Type.tint32);
4754 nextToken();
4755 break;
4756
4757 case TOK.TOKuns32v:
4758 e = new IntegerExp(loc, token.uns32value, Type.tuns32);
4759 nextToken();
4760 break;
4761
4762 case TOK.TOKint64v:
4763 e = new IntegerExp(loc, token.int64value, Type.tint64);
4764 nextToken();
4765 break;
4766
4767 case TOK.TOKuns64v:
4768 e = new IntegerExp(loc, token.uns64value, Type.tuns64);
4769 nextToken();
4770 break;
4771
4772 case TOK.TOKfloat32v:
4773 e = new RealExp(loc, token.float80value, Type.tfloat32);
4774 nextToken();
4775 break;
4776
4777 case TOK.TOKfloat64v:
4778 e = new RealExp(loc, token.float80value, Type.tfloat64);
4779 nextToken();
4780 break;
4781
4782 case TOK.TOKfloat80v:
4783 e = new RealExp(loc, token.float80value, Type.tfloat80);
4784 nextToken();
4785 break;
4786
4787 case TOK.TOKimaginary32v:
4788 e = new RealExp(loc, token.float80value, Type.timaginary32);
4789 nextToken();
4790 break;
4791
4792 case TOK.TOKimaginary64v:
4793 e = new RealExp(loc, token.float80value, Type.timaginary64);
4794 nextToken();
4795 break;
4796
4797 case TOK.TOKimaginary80v:
4798 e = new RealExp(loc, token.float80value, Type.timaginary80);
4799 nextToken();
4800 break;
4801
4802 case TOK.TOKnull:
4803 e = new NullExp(loc);
4804 nextToken();
4805 break;
4806
4807 version (DMDV2) {
4808 case TOK.TOKfile:
4809 {
4810 string s = loc.filename ? loc.filename : mod.ident.toChars();
4811 e = new StringExp(loc, s, 0);
4812 nextToken();
4813 break;
4814 }
4815
4816 case TOK.TOKline:
4817 e = new IntegerExp(loc, loc.linnum, Type.tint32);
4818 nextToken();
4819 break;
4820 }
4821
4822 case TOK.TOKtrue:
4823 e = new IntegerExp(loc, 1, Type.tbool);
4824 nextToken();
4825 break;
4826
4827 case TOK.TOKfalse:
4828 e = new IntegerExp(loc, 0, Type.tbool);
4829 nextToken();
4830 break;
4831
4832 case TOK.TOKcharv:
4833 e = new IntegerExp(loc, token.uns32value, Type.tchar);
4834 nextToken();
4835 break;
4836
4837 case TOK.TOKwcharv:
4838 e = new IntegerExp(loc, token.uns32value, Type.twchar);
4839 nextToken();
4840 break;
4841
4842 case TOK.TOKdcharv:
4843 e = new IntegerExp(loc, token.uns32value, Type.tdchar);
4844 nextToken();
4845 break;
4846
4847 case TOK.TOKstring:
4848 {
4849 const(char)* s;
4850 uint len;
4851 ubyte postfix;
4852
4853 // cat adjacent strings
4854 s = token.ustring;
4855 len = token.len;
4856 postfix = token.postfix;
4857 while (1)
4858 {
4859 nextToken();
4860 if (token.value == TOK.TOKstring)
4861 { uint len1;
4862 uint len2;
4863 char* s2;
4864
4865 if (token.postfix)
4866 { if (token.postfix != postfix)
4867 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
4868 postfix = token.postfix;
4869 }
4870
4871 len1 = len;
4872 len2 = token.len;
4873 len = len1 + len2;
4874 s2 = cast(char*)malloc((len + 1) * ubyte.sizeof);
4875 memcpy(s2, s, len1 * ubyte.sizeof);
4876 memcpy(s2 + len1, token.ustring, (len2 + 1) * ubyte.sizeof);
4877 s = s2;
4878 }
4879 else
4880 break;
4881 }
4882 e = new StringExp(loc, assumeUnique(s[0..len]), postfix);
4883 break;
4884 }
4885
4886 case TOK.TOKvoid: t = Type.tvoid; goto LabelX;
4887 case TOK.TOKint8: t = Type.tint8; goto LabelX;
4888 case TOK.TOKuns8: t = Type.tuns8; goto LabelX;
4889 case TOK.TOKint16: t = Type.tint16; goto LabelX;
4890 case TOK.TOKuns16: t = Type.tuns16; goto LabelX;
4891 case TOK.TOKint32: t = Type.tint32; goto LabelX;
4892 case TOK.TOKuns32: t = Type.tuns32; goto LabelX;
4893 case TOK.TOKint64: t = Type.tint64; goto LabelX;
4894 case TOK.TOKuns64: t = Type.tuns64; goto LabelX;
4895 case TOK.TOKfloat32: t = Type.tfloat32; goto LabelX;
4896 case TOK.TOKfloat64: t = Type.tfloat64; goto LabelX;
4897 case TOK.TOKfloat80: t = Type.tfloat80; goto LabelX;
4898 case TOK.TOKimaginary32: t = Type.timaginary32; goto LabelX;
4899 case TOK.TOKimaginary64: t = Type.timaginary64; goto LabelX;
4900 case TOK.TOKimaginary80: t = Type.timaginary80; goto LabelX;
4901 case TOK.TOKcomplex32: t = Type.tcomplex32; goto LabelX;
4902 case TOK.TOKcomplex64: t = Type.tcomplex64; goto LabelX;
4903 case TOK.TOKcomplex80: t = Type.tcomplex80; goto LabelX;
4904 case TOK.TOKbit: t = Type.tbit; goto LabelX;
4905 case TOK.TOKbool: t = Type.tbool; goto LabelX;
4906 case TOK.TOKchar: t = Type.tchar; goto LabelX;
4907 case TOK.TOKwchar: t = Type.twchar; goto LabelX;
4908 case TOK.TOKdchar: t = Type.tdchar; goto LabelX;
4909 LabelX:
4910 nextToken();
4911 L1:
4912 check(TOK.TOKdot, t.toChars());
4913 if (token.value != TOK.TOKidentifier)
4914 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t.toChars());
4915 goto Lerr;
4916 }
4917 e = typeDotIdExp(loc, t, token.ident);
4918 nextToken();
4919 break;
4920
4921 case TOK.TOKtypeof:
4922 {
4923 t = parseTypeof();
4924 e = new TypeExp(loc, t);
4925 break;
4926 }
4927
4928 case TOK.TOKtypeid:
4929 { Type tt;
4930
4931 nextToken();
4932 check(TOK.TOKlparen, "typeid");
4933 tt = parseType(); // ( type )
4934 check(TOK.TOKrparen);
4935 e = new TypeidExp(loc, tt);
4936 break;
4937 }
4938
4939 version (DMDV2) {
4940 case TOK.TOKtraits:
4941 { /* __traits(identifier, args...)
4942 */
4943 Identifier ident;
4944 Objects args = null;
4945
4946 nextToken();
4947 check(TOK.TOKlparen);
4948 if (token.value != TOK.TOKidentifier)
4949 { error("__traits(identifier, args...) expected");
4950 goto Lerr;
4951 }
4952 ident = token.ident;
4953 nextToken();
4954 if (token.value == TOK.TOKcomma)
4955 args = parseTemplateArgumentList2(); // __traits(identifier, args...)
4956 else
4957 check(TOK.TOKrparen); // __traits(identifier)
4958
4959 e = new TraitsExp(loc, ident, args);
4960 break;
4961 }
4962 }
4963
4964 case TOK.TOKis:
4965 { Type targ;
4966 Identifier ident = null;
4967 Type tspec = null;
4968 TOK tok = TOK.TOKreserved;
4969 TOK tok2 = TOK.TOKreserved;
4970 TemplateParameters tpl = null;
4971 Loc loc2 = this.loc;
4972
4973 nextToken();
4974 if (token.value == TOK.TOKlparen)
4975 {
4976 nextToken();
4977 targ = parseType(&ident);
4978 if (token.value == TOK.TOKcolon || token.value == TOK.TOKequal)
4979 {
4980 tok = token.value;
4981 nextToken();
4982 if (tok == TOK.TOKequal &&
4983 (token.value == TOK.TOKtypedef ||
4984 token.value == TOK.TOKstruct ||
4985 token.value == TOK.TOKunion ||
4986 token.value == TOK.TOKclass ||
4987 token.value == TOK.TOKsuper ||
4988 token.value == TOK.TOKenum ||
4989 token.value == TOK.TOKinterface ||
4990 ///version (DMDV2) {
4991 token.value == TOK.TOKconst && peek(&token).value == TOK.TOKrparen ||
4992 token.value == TOK.TOKinvariant && peek(&token).value == TOK.TOKrparen ||
4993 token.value == TOK.TOKimmutable && peek(&token).value == TOK.TOKrparen ||
4994 token.value == TOK.TOKshared && peek(&token).value == TOK.TOKrparen ||
4995 ///}
4996 token.value == TOK.TOKfunction ||
4997 token.value == TOK.TOKdelegate ||
4998 token.value == TOK.TOKreturn))
4999 {
5000 tok2 = token.value;
5001 nextToken();
5002 }
5003 else
5004 {
5005 tspec = parseType();
5006 }
5007 }
5008 if (ident && tspec)
5009 {
5010 if (token.value == TOK.TOKcomma)
5011 tpl = parseTemplateParameterList(1);
5012 else
5013 { tpl = new TemplateParameters();
5014 check(TOK.TOKrparen);
5015 }
5016 TemplateParameter tp = new TemplateTypeParameter(loc2, ident, null, null);
5017 tpl.insert(0, cast(void*)tp);
5018 }
5019 else
5020 check(TOK.TOKrparen);
5021 }
5022 else
5023 { error("(type identifier : specialization) expected following is");
5024 goto Lerr;
5025 }
5026 e = new IsExp(loc2, targ, ident, tok, tspec, tok2, tpl);
5027 break;
5028 }
5029
5030 case TOK.TOKassert:
5031 {
5032 Expression msg = null;
5033
5034 nextToken();
5035 check(TOK.TOKlparen, "assert");
5036 e = parseAssignExp();
5037 if (token.value == TOK.TOKcomma)
5038 { nextToken();
5039 msg = parseAssignExp();
5040 }
5041 check(TOK.TOKrparen);
5042 e = new AssertExp(loc, e, msg);
5043 break;
5044 }
5045
5046 case TOK.TOKmixin:
5047 {
5048 nextToken();
5049 check(TOK.TOKlparen, "mixin");
5050 e = parseAssignExp();
5051 check(TOK.TOKrparen);
5052 e = new CompileExp(loc, e);
5053 break;
5054 }
5055
5056 case TOK.TOKimport:
5057 {
5058 nextToken();
5059 check(TOK.TOKlparen, "import");
5060 e = parseAssignExp();
5061 check(TOK.TOKrparen);
5062 e = new FileExp(loc, e);
5063 break;
5064 }
5065
5066 case TOK.TOKlparen:
5067 if (peekPastParen(&token).value == TOK.TOKlcurly)
5068 { // (arguments) { statements... }
5069 save = TOK.TOKdelegate;
5070 goto case_delegate;
5071 }
5072 // ( expression )
5073 nextToken();
5074 e = parseExpression();
5075 check(loc, TOK.TOKrparen);
5076 break;
5077
5078 case TOK.TOKlbracket:
5079 { /* Parse array literals and associative array literals:
5080 * [ value, value, value ... ]
5081 * [ key:value, key:value, key:value ... ]
5082 */
5083 Expressions values = new Expressions();
5084 Expressions keys = null;
5085
5086 nextToken();
5087 if (token.value != TOK.TOKrbracket)
5088 {
5089 while (token.value != TOK.TOKeof)
5090 {
5091 Expression e2 = parseAssignExp();
5092 if (token.value == TOK.TOKcolon && (keys || values.dim == 0))
5093 {
5094 nextToken();
5095 if (!keys)
5096 keys = new Expressions();
5097 keys.push(cast(void*)e2);
5098 e2 = parseAssignExp();
5099 }
5100 else if (keys)
5101 {
5102 error("'key:value' expected for associative array literal");
5103 delete keys;
5104 keys = null;
5105 }
5106 values.push(cast(void*)e2);
5107 if (token.value == TOK.TOKrbracket)
5108 break;
5109 check(TOK.TOKcomma);
5110 }
5111 }
5112 check(TOK.TOKrbracket);
5113
5114 if (keys)
5115 e = new AssocArrayLiteralExp(loc, keys, values);
5116 else
5117 e = new ArrayLiteralExp(loc, values);
5118 break;
5119 }
5120
5121 case TOK.TOKlcurly:
5122 // { statements... }
5123 save = TOK.TOKdelegate;
5124 goto case_delegate;
5125
5126 case TOK.TOKfunction:
5127 case TOK.TOKdelegate:
5128 save = token.value;
5129 nextToken();
5130 case_delegate:
5131 {
5132 /* function type(parameters) { body } pure nothrow
5133 * delegate type(parameters) { body } pure nothrow
5134 * (parameters) { body }
5135 * { body }
5136 */
5137 Arguments arguments;
5138 int varargs;
5139 FuncLiteralDeclaration fd;
5140 Type tt;
5141 bool isnothrow = false;
5142 bool ispure = false;
5143
5144 if (token.value == TOK.TOKlcurly)
5145 {
5146 tt = null;
5147 varargs = 0;
5148 arguments = new Arguments();
5149 }
5150 else
5151 {
5152 if (token.value == TOK.TOKlparen)
5153 tt = null;
5154 else
5155 {
5156 tt = parseBasicType();
5157 tt = parseBasicType2(tt); // function return type
5158 }
5159 arguments = parseParameters(&varargs);
5160 while (1)
5161 {
5162 if (token.value == TOK.TOKpure)
5163 ispure = true;
5164 else if (token.value == TOK.TOKnothrow)
5165 isnothrow = true;
5166 else
5167 break;
5168 nextToken();
5169 }
5170 }
5171
5172 TypeFunction tf = new TypeFunction(arguments, tt, varargs, linkage);
5173 tf.ispure = ispure;
5174 tf.isnothrow = isnothrow;
5175 fd = new FuncLiteralDeclaration(loc, Loc(0), tf, save, null);
5176 parseContracts(fd);
5177 e = new FuncExp(loc, fd);
5178 break;
5179 }
5180
5181 default:
5182 error("expression expected, not '%s'", token.toChars());
5183 Lerr:
5184 // Anything for e, as long as it's not null
5185 e = new IntegerExp(loc, 0, Type.tint32);
5186 nextToken();
5187 break;
5188 }
5189 return e;
5190 }
5191
5192 Expression parseUnaryExp()
5193 {
5194 Expression e;
5195 Loc loc = this.loc;
5196
5197 switch (token.value)
5198 {
5199 case TOK.TOKand:
5200 nextToken();
5201 e = parseUnaryExp();
5202 e = new AddrExp(loc, e);
5203 break;
5204
5205 case TOK.TOKplusplus:
5206 nextToken();
5207 e = parseUnaryExp();
5208 e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32));
5209 break;
5210
5211 case TOK.TOKminusminus:
5212 nextToken();
5213 e = parseUnaryExp();
5214 e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type.tint32));
5215 break;
5216
5217 case TOK.TOKmul:
5218 nextToken();
5219 e = parseUnaryExp();
5220 e = new PtrExp(loc, e);
5221 break;
5222
5223 case TOK.TOKmin:
5224 nextToken();
5225 e = parseUnaryExp();
5226 e = new NegExp(loc, e);
5227 break;
5228
5229 case TOK.TOKadd:
5230 nextToken();
5231 e = parseUnaryExp();
5232 e = new UAddExp(loc, e);
5233 break;
5234
5235 case TOK.TOKnot:
5236 nextToken();
5237 e = parseUnaryExp();
5238 e = new NotExp(loc, e);
5239 break;
5240
5241 case TOK.TOKtilde:
5242 nextToken();
5243 e = parseUnaryExp();
5244 e = new ComExp(loc, e);
5245 break;
5246
5247 case TOK.TOKdelete:
5248 nextToken();
5249 e = parseUnaryExp();
5250 e = new DeleteExp(loc, e);
5251 break;
5252
5253 case TOK.TOKnew:
5254 e = parseNewExp(null);
5255 break;
5256
5257 case TOK.TOKcast: // cast(type) expression
5258 {
5259 nextToken();
5260 check(TOK.TOKlparen);
5261 /* Look for cast(), cast(const), cast(immutable),
5262 * cast(shared), cast(shared const)
5263 */
5264 MOD m;
5265 if (token.value == TOK.TOKrparen)
5266 {
5267 m = MOD.MODundefined;
5268 goto Lmod1;
5269 }
5270 else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKrparen)
5271 {
5272 m = MOD.MODconst;
5273 goto Lmod2;
5274 }
5275 else if ((token.value == TOK.TOKimmutable || token.value == TOK.TOKinvariant) && peekNext() == TOK.TOKrparen)
5276 {
5277 m = MOD.MODinvariant;
5278 goto Lmod2;
5279 }
5280 else if (token.value == TOK.TOKshared && peekNext() == TOK.TOKrparen)
5281 {
5282 m = MOD.MODshared;
5283 goto Lmod2;
5284 }
5285 else if (token.value == TOK.TOKconst && peekNext() == TOK.TOKshared && peekNext2() == TOK.TOKrparen ||
5286 token.value == TOK.TOKshared && peekNext() == TOK.TOKconst && peekNext2() == TOK.TOKrparen)
5287 {
5288 m = MOD.MODshared | MOD.MODconst;
5289 nextToken();
5290 Lmod2:
5291 nextToken();
5292 Lmod1:
5293 nextToken();
5294 e = parseUnaryExp();
5295 e = new CastExp(loc, e, m);
5296 }
5297 else
5298 {
5299 Type t = parseType(); // ( type )
5300 check(TOK.TOKrparen);
5301 e = parseUnaryExp();
5302 e = new CastExp(loc, e, t);
5303 }
5304 break;
5305 }
5306
5307 case TOK.TOKlparen:
5308 { Token *tk;
5309
5310 tk = peek(&token);
5311 version (CCASTSYNTAX) {
5312 // If cast
5313 if (isDeclaration(tk, 0, TOK.TOKrparen, &tk))
5314 {
5315 tk = peek(tk); // skip over right parenthesis
5316 switch (tk.value)
5317 {
5318 case TOK.TOKnot:
5319 tk = peek(tk);
5320 if (tk.value == TOK.TOKis) // !is
5321 break;
5322 case TOK.TOKdot:
5323 case TOK.TOKplusplus:
5324 case TOK.TOKminusminus:
5325 case TOK.TOKdelete:
5326 case TOK.TOKnew:
5327 case TOK.TOKlparen:
5328 case TOK.TOKidentifier:
5329 case TOK.TOKthis:
5330 case TOK.TOKsuper:
5331 case TOK.TOKint32v:
5332 case TOK.TOKuns32v:
5333 case TOK.TOKint64v:
5334 case TOK.TOKuns64v:
5335 case TOK.TOKfloat32v:
5336 case TOK.TOKfloat64v:
5337 case TOK.TOKfloat80v:
5338 case TOK.TOKimaginary32v:
5339 case TOK.TOKimaginary64v:
5340 case TOK.TOKimaginary80v:
5341 case TOK.TOKnull:
5342 case TOK.TOKtrue:
5343 case TOK.TOKfalse:
5344 case TOK.TOKcharv:
5345 case TOK.TOKwcharv:
5346 case TOK.TOKdcharv:
5347 case TOK.TOKstring:
5348 static if (false) {
5349 case TOK.TOKtilde:
5350 case TOK.TOKand:
5351 case TOK.TOKmul:
5352 case TOK.TOKmin:
5353 case TOK.TOKadd:
5354 }
5355 case TOK.TOKfunction:
5356 case TOK.TOKdelegate:
5357 case TOK.TOKtypeof:
5358 version (DMDV2) {
5359 case TOK.TOKfile:
5360 case TOK.TOKline:
5361 }
5362 case TOK.TOKwchar: case TOK.TOKdchar:
5363 case TOK.TOKbit: case TOK.TOKbool: case TOK.TOKchar:
5364 case TOK.TOKint8: case TOK.TOKuns8:
5365 case TOK.TOKint16: case TOK.TOKuns16:
5366 case TOK.TOKint32: case TOK.TOKuns32:
5367 case TOK.TOKint64: case TOK.TOKuns64:
5368 case TOK.TOKfloat32: case TOK.TOKfloat64: case TOK.TOKfloat80:
5369 case TOK.TOKimaginary32: case TOK.TOKimaginary64: case TOK.TOKimaginary80:
5370 case TOK.TOKcomplex32: case TOK.TOKcomplex64: case TOK.TOKcomplex80:
5371 case TOK.TOKvoid: // (type)int.size
5372 {
5373 // (type) una_exp
5374 nextToken();
5375 Type t = parseType();
5376 check(TOK.TOKrparen);
5377
5378 // if .identifier
5379 if (token.value == TOK.TOKdot)
5380 {
5381 nextToken();
5382 if (token.value != TOK.TOKidentifier)
5383 {
5384 error("Identifier expected following (type).");
5385 return null;
5386 }
5387 e = typeDotIdExp(loc, t, token.ident);
5388 nextToken();
5389 e = parsePostExp(e);
5390 }
5391 else
5392 {
5393 e = parseUnaryExp();
5394 e = new CastExp(loc, e, t);
5395 error("C style cast illegal, use %s", e.toChars());
5396 }
5397 return e;
5398 }
5399
5400 default:
5401 break; ///
5402 }
5403 }
5404 }
5405 e = parsePrimaryExp();
5406 e = parsePostExp(e);
5407 break;
5408 }
5409 default:
5410 e = parsePrimaryExp();
5411 e = parsePostExp(e);
5412 break;
5413 }
5414 assert(e);
5415 return e;
5416 }
5417
5418 Expression parsePostExp(Expression e)
5419 {
5420 Loc loc;
5421
5422 while (1)
5423 {
5424 loc = this.loc;
5425 switch (token.value)
5426 {
5427 case TOK.TOKdot:
5428 nextToken();
5429 if (token.value == TOK.TOKidentifier)
5430 { Identifier id = token.ident;
5431
5432 nextToken();
5433 if (token.value == TOK.TOKnot && peekNext() != TOK.TOKis)
5434 { // identifier!(template-argument-list)
5435 TemplateInstance tempinst = new TemplateInstance(loc, id);
5436 nextToken();
5437 if (token.value == TOK.TOKlparen)
5438 // ident!(template_arguments)
5439 tempinst.tiargs = parseTemplateArgumentList();
5440 else
5441 // ident!template_argument
5442 tempinst.tiargs = parseTemplateArgument();
5443 e = new DotTemplateInstanceExp(loc, e, tempinst);
5444 }
5445 else
5446 e = new DotIdExp(loc, e, id);
5447 continue;
5448 }
5449 else if (token.value == TOK.TOKnew)
5450 {
5451 e = parseNewExp(e);
5452 continue;
5453 }
5454 else
5455 error("identifier expected following '.', not '%s'", token.toChars());
5456 break;
5457
5458 case TOK.TOKplusplus:
5459 e = new PostExp(TOK.TOKplusplus, loc, e);
5460 break;
5461
5462 case TOK.TOKminusminus:
5463 e = new PostExp(TOK.TOKminusminus, loc, e);
5464 break;
5465
5466 case TOK.TOKlparen:
5467 e = new CallExp(loc, e, parseArguments());
5468 continue;
5469
5470 case TOK.TOKlbracket:
5471 { // array dereferences:
5472 // array[index]
5473 // array[]
5474 // array[lwr .. upr]
5475 Expression index;
5476 Expression upr;
5477
5478 inBrackets++;
5479 nextToken();
5480 if (token.value == TOK.TOKrbracket)
5481 { // array[]
5482 e = new SliceExp(loc, e, null, null);
5483 nextToken();
5484 }
5485 else
5486 {
5487 index = parseAssignExp();
5488 if (token.value == TOK.TOKslice)
5489 { // array[lwr .. upr]
5490 nextToken();
5491 upr = parseAssignExp();
5492 e = new SliceExp(loc, e, index, upr);
5493 }
5494 else
5495 { // array[index, i2, i3, i4, ...]
5496 Expressions arguments = new Expressions();
5497 arguments.push(cast(void*)index);
5498 if (token.value == TOK.TOKcomma)
5499 {
5500 nextToken();
5501 while (1)
5502 { Expression arg;
5503
5504 arg = parseAssignExp();
5505 arguments.push(cast(void*)arg);
5506 if (token.value == TOK.TOKrbracket)
5507 break;
5508 check(TOK.TOKcomma);
5509 }
5510 }
5511 e = new ArrayExp(loc, e, arguments);
5512 }
5513 check(TOK.TOKrbracket);
5514 inBrackets--;
5515 }
5516 continue;
5517 }
5518
5519 default:
5520 return e;
5521 }
5522 nextToken();
5523 }
5524
5525 assert(false);
5526 }
5527
5528 Expression parseMulExp()
5529 {
5530 Expression e;
5531 Expression e2;
5532 Loc loc = this.loc;
5533
5534 e = parseUnaryExp();
5535 while (1)
5536 {
5537 switch (token.value)
5538 {
5539 case TOK.TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5540 case TOK.TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5541 case TOK.TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5542
5543 default:
5544 break;
5545 }
5546 break;
5547 }
5548 return e;
5549 }
5550
5551 Expression parseShiftExp()
5552 {
5553 Expression e;
5554 Expression e2;
5555 Loc loc = this.loc;
5556
5557 e = parseAddExp();
5558 while (1)
5559 {
5560 switch (token.value)
5561 {
5562 case TOK.TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
5563 case TOK.TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
5564 case TOK.TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5565
5566 default:
5567 break;
5568 }
5569 break;
5570 }
5571 return e;
5572 }
5573
5574 Expression parseAddExp()
5575 {
5576 Expression e;
5577 Expression e2;
5578 Loc loc = this.loc;
5579
5580 e = parseMulExp();
5581 while (1)
5582 {
5583 switch (token.value)
5584 {
5585 case TOK.TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5586 case TOK.TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5587 case TOK.TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5588
5589 default:
5590 break;
5591 }
5592 break;
5593 }
5594 return e;
5595 }
5596
5597 Expression parseRelExp()
5598 {
5599 assert(false);
5600 }
5601
5602 Expression parseEqualExp()
5603 {
5604 assert(false);
5605 }
5606
5607 Expression parseCmpExp()
5608 {
5609 Expression e;
5610 Expression e2;
5611 Token* t;
5612 Loc loc = this.loc;
5613
5614 e = parseShiftExp();
5615 TOK op = token.value;
5616
5617 switch (op)
5618 {
5619 case TOK.TOKequal:
5620 case TOK.TOKnotequal:
5621 nextToken();
5622 e2 = parseShiftExp();
5623 e = new EqualExp(op, loc, e, e2);
5624 break;
5625
5626 case TOK.TOKis:
5627 op = TOK.TOKidentity;
5628 goto L1;
5629
5630 case TOK.TOKnot:
5631 // Attempt to identify '!is'
5632 t = peek(&token);
5633 if (t.value != TOK.TOKis)
5634 break;
5635 nextToken();
5636 op = TOK.TOKnotidentity;
5637 goto L1;
5638
5639 L1:
5640 nextToken();
5641 e2 = parseShiftExp();
5642 e = new IdentityExp(op, loc, e, e2);
5643 break;
5644
5645 case TOK.TOKlt:
5646 case TOK.TOKle:
5647 case TOK.TOKgt:
5648 case TOK.TOKge:
5649 case TOK.TOKunord:
5650 case TOK.TOKlg:
5651 case TOK.TOKleg:
5652 case TOK.TOKule:
5653 case TOK.TOKul:
5654 case TOK.TOKuge:
5655 case TOK.TOKug:
5656 case TOK.TOKue:
5657 nextToken();
5658 e2 = parseShiftExp();
5659 e = new CmpExp(op, loc, e, e2);
5660 break;
5661
5662 case TOK.TOKin:
5663 nextToken();
5664 e2 = parseShiftExp();
5665 e = new InExp(loc, e, e2);
5666 break;
5667
5668 default:
5669 break;
5670 }
5671 return e;
5672 }
5673
5674 Expression parseAndExp()
5675 {
5676 Expression e;
5677 Expression e2;
5678 Loc loc = this.loc;
5679
5680 if (global.params.Dversion == 1)
5681 {
5682 e = parseEqualExp();
5683 while (token.value == TOK.TOKand)
5684 {
5685 nextToken();
5686 e2 = parseEqualExp();
5687 e = new AndExp(loc,e,e2);
5688 loc = this.loc;
5689 }
5690 }
5691 else
5692 {
5693 e = parseCmpExp();
5694 while (token.value == TOK.TOKand)
5695 {
5696 nextToken();
5697 e2 = parseCmpExp();
5698 e = new AndExp(loc,e,e2);
5699 loc = this.loc;
5700 }
5701 }
5702 return e;
5703 }
5704
5705 Expression parseXorExp()
5706 {
5707 Expression e;
5708 Expression e2;
5709 Loc loc = this.loc;
5710
5711 e = parseAndExp();
5712 while (token.value == TOK.TOKxor)
5713 {
5714 nextToken();
5715 e2 = parseAndExp();
5716 e = new XorExp(loc, e, e2);
5717 }
5718
5719 return e;
5720 }
5721
5722 Expression parseOrExp()
5723 {
5724 Expression e;
5725 Expression e2;
5726 Loc loc = this.loc;
5727
5728 e = parseXorExp();
5729 while (token.value == TOK.TOKor)
5730 {
5731 nextToken();
5732 e2 = parseXorExp();
5733 e = new OrExp(loc, e, e2);
5734 }
5735 return e;
5736 }
5737
5738 Expression parseAndAndExp()
5739 {
5740 Expression e;
5741 Expression e2;
5742 Loc loc = this.loc;
5743
5744 e = parseOrExp();
5745 while (token.value == TOK.TOKandand)
5746 {
5747 nextToken();
5748 e2 = parseOrExp();
5749 e = new AndAndExp(loc, e, e2);
5750 }
5751 return e;
5752 }
5753
5754 Expression parseOrOrExp()
5755 {
5756 Expression e;
5757 Expression e2;
5758 Loc loc = this.loc;
5759
5760 e = parseAndAndExp();
5761 while (token.value == TOK.TOKoror)
5762 {
5763 nextToken();
5764 e2 = parseAndAndExp();
5765 e = new OrOrExp(loc, e, e2);
5766 }
5767
5768 return e;
5769 }
5770
5771 Expression parseCondExp()
5772 {
5773 Expression e;
5774 Expression e1;
5775 Expression e2;
5776 Loc loc = this.loc;
5777
5778 e = parseOrOrExp();
5779 if (token.value == TOK.TOKquestion)
5780 {
5781 nextToken();
5782 e1 = parseExpression();
5783 check(TOK.TOKcolon);
5784 e2 = parseCondExp();
5785 e = new CondExp(loc, e, e1, e2);
5786 }
5787 return e;
5788 }
5789
5790 Expression parseAssignExp()
5791 {
5792 Expression e;
5793 Expression e2;
5794 Loc loc;
5795
5796 e = parseCondExp();
5797 while (1)
5798 {
5799 loc = this.loc;
5800 switch (token.value)
5801 {
5802 case TOK.TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
5803 case TOK.TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
5804 case TOK.TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
5805 case TOK.TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
5806 case TOK.TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
5807 case TOK.TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
5808 case TOK.TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
5809 case TOK.TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
5810 case TOK.TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
5811 case TOK.TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
5812 case TOK.TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
5813 case TOK.TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
5814 case TOK.TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
5815
5816 default:
5817 break;
5818 }
5819 break;
5820 }
5821
5822 return e;
5823 }
5824
5825 /*************************
5826 * Collect argument list.
5827 * Assume current token is ',', '(' or '['.
5828 */
5829 Expressions parseArguments()
5830 {
5831 // function call
5832 Expressions arguments = new Expressions();
5833 Expression arg;
5834 TOK endtok;
5835
5836 if (token.value == TOK.TOKlbracket)
5837 endtok = TOK.TOKrbracket;
5838 else
5839 endtok = TOK.TOKrparen;
5840
5841 {
5842 nextToken();
5843 if (token.value != endtok)
5844 {
5845 while (1)
5846 {
5847 arg = parseAssignExp();
5848 arguments.push(cast(void*)arg);
5849 if (token.value == endtok)
5850 break;
5851 check(TOK.TOKcomma);
5852 }
5853 }
5854 check(endtok);
5855 }
5856 return arguments;
5857 }
5858
5859 Expression parseNewExp(Expression thisexp)
5860 {
5861 Type t;
5862 Expressions newargs;
5863 Expressions arguments = null;
5864 Expression e;
5865 Loc loc = this.loc;
5866
5867 nextToken();
5868 newargs = null;
5869 if (token.value == TOKlparen)
5870 {
5871 newargs = parseArguments();
5872 }
5873
5874 // An anonymous nested class starts with "class"
5875 if (token.value == TOKclass)
5876 {
5877 nextToken();
5878 if (token.value == TOKlparen)
5879 arguments = parseArguments();
5880
5881 BaseClasses baseclasses = null;
5882 if (token.value != TOKlcurly)
5883 baseclasses = parseBaseClasses();
5884
5885 Identifier id = null;
5886 ClassDeclaration cd = new ClassDeclaration(loc, id, baseclasses);
5887
5888 if (token.value != TOKlcurly)
5889 {
5890 error("{ members } expected for anonymous class");
5891 cd.members = null;
5892 }
5893 else
5894 {
5895 nextToken();
5896 Array decl = parseDeclDefs(0);
5897 if (token.value != TOKrcurly)
5898 error("class member expected");
5899 nextToken();
5900 cd.members = decl;
5901 }
5902
5903 e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
5904
5905 return e;
5906 }
5907
5908 t = parseBasicType();
5909 t = parseBasicType2(t);
5910 if (t.ty == Taarray)
5911 {
5912 TypeAArray taa = cast(TypeAArray)t;
5913 Type index = taa.index;
5914
5915 Expression e2 = index.toExpression();
5916 if (e2)
5917 {
5918 arguments = new Expressions();
5919 arguments.push(cast(void*)e2);
5920 t = new TypeDArray(taa.next);
5921 }
5922 else
5923 {
5924 error("need size of rightmost array, not type %s", index.toChars());
5925 return new NullExp(loc);
5926 }
5927 }
5928 else if (t.ty == Tsarray)
5929 {
5930 TypeSArray tsa = cast(TypeSArray)t;
5931 Expression ee = tsa.dim;
5932
5933 arguments = new Expressions();
5934 arguments.push(cast(void*)ee);
5935 t = new TypeDArray(tsa.next);
5936 }
5937 else if (token.value == TOKlparen)
5938 {
5939 arguments = parseArguments();
5940 }
5941
5942 e = new NewExp(loc, thisexp, newargs, t, arguments);
5943 return e;
5944 }
5945
5946 void addComment(Dsymbol s, ubyte* blockComment)
5947 {
5948 s.addComment(combineComments(blockComment, token.lineComment));
5949 token.lineComment = null;
5950 }
5951 }