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