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