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