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