0
|
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 } |