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