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