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