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