Mercurial > projects > dil
comparison src/dil/parser/Parser.d @ 806:bcb74c9b895c
Moved out files in the trunk folder to the root.
author | Aziz K?ksal <aziz.koeksal@gmail.com> |
---|---|
date | Sun, 09 Mar 2008 00:12:19 +0100 |
parents | trunk/src/dil/parser/Parser.d@9e6c6bb73e5f |
children | 1abffc396594 |
comparison
equal
deleted
inserted
replaced
805:a3fab8b74a7d | 806:bcb74c9b895c |
---|---|
1 /++ | |
2 Author: Aziz Köksal | |
3 License: GPL3 | |
4 +/ | |
5 module dil.parser.Parser; | |
6 | |
7 import dil.lexer.Lexer; | |
8 import dil.ast.Node; | |
9 import dil.ast.Declarations; | |
10 import dil.ast.Statements; | |
11 import dil.ast.Expressions; | |
12 import dil.ast.Types; | |
13 import dil.ast.Parameters; | |
14 import dil.lexer.IdTable; | |
15 import dil.Messages; | |
16 import dil.Information; | |
17 import dil.Enums; | |
18 import dil.CompilerInfo; | |
19 import dil.SourceText; | |
20 import dil.Unicode; | |
21 import common; | |
22 | |
23 /// The Parser produces a full parse tree by examining | |
24 /// the list of tokens provided by the Lexer. | |
25 class Parser | |
26 { | |
27 Lexer lexer; /// Used to lex the source code. | |
28 Token* token; /// Current non-whitespace token. | |
29 Token* prevToken; /// Previous non-whitespace token. | |
30 | |
31 InfoManager infoMan; | |
32 ParserError[] errors; | |
33 | |
34 ImportDeclaration[] imports; /// ImportDeclarations in the source text. | |
35 | |
36 /// Attributes are evaluated in the parsing phase. | |
37 /// TODO: will be removed. SemanticPass1 takes care of attributes. | |
38 LinkageType linkageType; | |
39 Protection protection; /// ditto | |
40 StorageClass storageClass; /// ditto | |
41 uint alignSize = DEFAULT_ALIGN_SIZE; /// ditto | |
42 | |
43 private alias TOK T; /// Used often in this class. | |
44 private alias TypeNode Type; | |
45 | |
46 /// Constructs a Parser object. | |
47 /// Params: | |
48 /// text = the UTF-8 source code. | |
49 /// infoMan = used for collecting error messages. | |
50 this(SourceText srcText, InfoManager infoMan = null) | |
51 { | |
52 this.infoMan = infoMan; | |
53 lexer = new Lexer(srcText, infoMan); | |
54 } | |
55 | |
56 /// Moves to the first token. | |
57 protected void init() | |
58 { | |
59 nT(); | |
60 prevToken = token; | |
61 } | |
62 | |
63 /// Moves to the next token. | |
64 void nT() | |
65 { | |
66 prevToken = token; | |
67 do | |
68 { | |
69 lexer.nextToken(); | |
70 token = lexer.token; | |
71 } while (token.isWhitespace) // Skip whitespace | |
72 } | |
73 | |
74 /// Start the parser and return the parsed Declarations. | |
75 CompoundDeclaration start() | |
76 { | |
77 init(); | |
78 auto begin = token; | |
79 auto decls = new CompoundDeclaration; | |
80 if (token.kind == T.Module) | |
81 decls ~= parseModuleDeclaration(); | |
82 decls.addOptChildren(parseDeclarationDefinitions()); | |
83 set(decls, begin); | |
84 return decls; | |
85 } | |
86 | |
87 /// Start the parser and return the parsed Expression. | |
88 Expression start2() | |
89 { | |
90 init(); | |
91 return parseExpression(); | |
92 } | |
93 | |
94 // Members related to the method try_(). | |
95 uint trying; /// Greater than 0 if Parser is in try_(). | |
96 uint errorCount; /// Used to track nr. of errors while being in try_(). | |
97 | |
98 /// This method executes the delegate parseMethod and when an error occurred | |
99 /// the state of the lexer and parser are restored. | |
100 /// Returns: the return value of parseMethod(). | |
101 ReturnType try_(ReturnType)(ReturnType delegate() parseMethod, out bool success) | |
102 { | |
103 // Save members. | |
104 auto oldToken = this.token; | |
105 auto oldPrevToken = this.prevToken; | |
106 auto oldCount = this.errorCount; | |
107 | |
108 ++trying; | |
109 auto result = parseMethod(); | |
110 --trying; | |
111 // Check if an error occurred. | |
112 if (errorCount != oldCount) | |
113 { // Restore members. | |
114 token = oldToken; | |
115 prevToken = oldPrevToken; | |
116 lexer.token = oldToken; | |
117 errorCount = oldCount; | |
118 success = false; | |
119 } | |
120 else | |
121 success = true; | |
122 return result; | |
123 } | |
124 | |
125 /// Sets the begin and end tokens of a syntax tree node. | |
126 Class set(Class)(Class node, Token* begin) | |
127 { | |
128 node.setTokens(begin, this.prevToken); | |
129 return node; | |
130 } | |
131 | |
132 /// Sets the begin and end tokens of a syntax tree node. | |
133 Class set(Class)(Class node, Token* begin, Token* end) | |
134 { | |
135 node.setTokens(begin, end); | |
136 return node; | |
137 } | |
138 | |
139 /// Returns true if set() has been called on a node. | |
140 static bool isNodeSet(Node node) | |
141 { | |
142 return node.begin !is null && node.end !is null; | |
143 } | |
144 | |
145 /// Returns the token kind of the next token. | |
146 TOK peekNext() | |
147 { | |
148 Token* next = token; | |
149 do | |
150 lexer.peek(next); | |
151 while (next.isWhitespace) // Skip whitespace | |
152 return next.kind; | |
153 } | |
154 | |
155 /// Returns the token kind of the token that comes after t. | |
156 TOK peekAfter(ref Token* t) | |
157 { | |
158 assert(t !is null); | |
159 do | |
160 lexer.peek(t); | |
161 while (t.isWhitespace) // Skip whitespace | |
162 return t.kind; | |
163 } | |
164 | |
165 /// Consumes the current token if its kind matches k and returns true. | |
166 bool consumed()(TOK k) // Templatized, so it's inlined. | |
167 { | |
168 return token.kind == k ? (nT(), true) : false; | |
169 } | |
170 | |
171 /// Asserts that the current token is of kind expectedKind, | |
172 /// and then moves to the next token. | |
173 void skip()(TOK expectedKind) | |
174 { | |
175 assert(token.kind == expectedKind /+|| *(int*).init+/, token.srcText()); | |
176 nT(); | |
177 } | |
178 | |
179 /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
180 | Declaration parsing methods | | |
181 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/ | |
182 | |
183 Declaration parseModuleDeclaration() | |
184 { | |
185 skip(T.Module); | |
186 auto begin = token; | |
187 ModuleFQN moduleFQN; | |
188 do | |
189 moduleFQN ~= requireIdentifier(MSG.ExpectedModuleIdentifier); | |
190 while (consumed(T.Dot)) | |
191 require(T.Semicolon); | |
192 return set(new ModuleDeclaration(moduleFQN), begin); | |
193 } | |
194 | |
195 /// Parses DeclarationDefinitions until the end of file is hit. | |
196 /// $(PRE | |
197 /// DeclDefs := | |
198 /// DeclDef | |
199 /// DeclDefs | |
200 /// ) | |
201 Declaration[] parseDeclarationDefinitions() | |
202 { | |
203 Declaration[] decls; | |
204 while (token.kind != T.EOF) | |
205 decls ~= parseDeclarationDefinition(); | |
206 return decls; | |
207 } | |
208 | |
209 /// Parse the body of a template, class, interface, struct or union. | |
210 /// $(PRE | |
211 /// DeclDefsBlock := | |
212 /// { } | |
213 /// { DeclDefs } | |
214 /// ) | |
215 CompoundDeclaration parseDeclarationDefinitionsBody() | |
216 { | |
217 // Save attributes. | |
218 auto linkageType = this.linkageType; | |
219 auto protection = this.protection; | |
220 auto storageClass = this.storageClass; | |
221 // Clear attributes. | |
222 this.linkageType = LinkageType.None; | |
223 this.protection = Protection.None; | |
224 this.storageClass = StorageClass.None; | |
225 | |
226 // Parse body. | |
227 auto begin = token; | |
228 auto decls = new CompoundDeclaration; | |
229 require(T.LBrace); | |
230 while (token.kind != T.RBrace && token.kind != T.EOF) | |
231 decls ~= parseDeclarationDefinition(); | |
232 require(T.RBrace); | |
233 set(decls, begin); | |
234 | |
235 // Restore original values. | |
236 this.linkageType = linkageType; | |
237 this.protection = protection; | |
238 this.storageClass = storageClass; | |
239 | |
240 return decls; | |
241 } | |
242 | |
243 /// Parses a DeclarationDefinition. | |
244 Declaration parseDeclarationDefinition() | |
245 out(decl) | |
246 { assert(isNodeSet(decl)); } | |
247 body | |
248 { | |
249 auto begin = token; | |
250 Declaration decl; | |
251 switch (token.kind) | |
252 { | |
253 case T.Align, | |
254 T.Pragma, | |
255 // Protection attributes | |
256 T.Export, | |
257 T.Private, | |
258 T.Package, | |
259 T.Protected, | |
260 T.Public: | |
261 decl = parseAttributeSpecifier(); | |
262 break; | |
263 // Storage classes | |
264 case T.Extern, | |
265 T.Deprecated, | |
266 T.Override, | |
267 T.Abstract, | |
268 T.Synchronized, | |
269 //T.Static, | |
270 T.Final, | |
271 T.Const, | |
272 //T.Invariant, // D 2.0 | |
273 T.Auto, | |
274 T.Scope: | |
275 case_StaticAttribute: | |
276 case_InvariantAttribute: // D 2.0 | |
277 return parseStorageAttribute(); | |
278 case T.Alias: | |
279 nT(); | |
280 decl = new AliasDeclaration(parseVariableOrFunction()); | |
281 break; | |
282 case T.Typedef: | |
283 nT(); | |
284 decl = new TypedefDeclaration(parseVariableOrFunction()); | |
285 break; | |
286 case T.Static: | |
287 switch (peekNext()) | |
288 { | |
289 case T.Import: | |
290 goto case_Import; | |
291 case T.This: | |
292 decl = parseStaticConstructorDeclaration(); | |
293 break; | |
294 case T.Tilde: | |
295 decl = parseStaticDestructorDeclaration(); | |
296 break; | |
297 case T.If: | |
298 decl = parseStaticIfDeclaration(); | |
299 break; | |
300 case T.Assert: | |
301 decl = parseStaticAssertDeclaration(); | |
302 break; | |
303 default: | |
304 goto case_StaticAttribute; | |
305 } | |
306 break; | |
307 case T.Import: | |
308 case_Import: | |
309 decl = parseImportDeclaration(); | |
310 imports ~= decl.to!(ImportDeclaration); | |
311 // Handle specially. StorageClass mustn't be set. | |
312 decl.setProtection(this.protection); | |
313 return set(decl, begin); | |
314 case T.Enum: | |
315 decl = parseEnumDeclaration(); | |
316 break; | |
317 case T.Class: | |
318 decl = parseClassDeclaration(); | |
319 break; | |
320 case T.Interface: | |
321 decl = parseInterfaceDeclaration(); | |
322 break; | |
323 case T.Struct, T.Union: | |
324 decl = parseStructOrUnionDeclaration(); | |
325 break; | |
326 case T.This: | |
327 decl = parseConstructorDeclaration(); | |
328 break; | |
329 case T.Tilde: | |
330 decl = parseDestructorDeclaration(); | |
331 break; | |
332 case T.Invariant: | |
333 version(D2) | |
334 { | |
335 auto next = token; | |
336 if (peekAfter(next) == T.LParen) | |
337 { | |
338 if (peekAfter(next) != T.RParen) | |
339 goto case_Declaration; | |
340 } | |
341 else | |
342 goto case_InvariantAttribute; | |
343 } | |
344 decl = parseInvariantDeclaration(); | |
345 break; | |
346 case T.Unittest: | |
347 decl = parseUnittestDeclaration(); | |
348 break; | |
349 case T.Debug: | |
350 decl = parseDebugDeclaration(); | |
351 break; | |
352 case T.Version: | |
353 decl = parseVersionDeclaration(); | |
354 break; | |
355 case T.Template: | |
356 decl = parseTemplateDeclaration(); | |
357 break; | |
358 case T.New: | |
359 decl = parseNewDeclaration(); | |
360 break; | |
361 case T.Delete: | |
362 decl = parseDeleteDeclaration(); | |
363 break; | |
364 case T.Mixin: | |
365 decl = parseMixin!(MixinDeclaration)(); | |
366 break; | |
367 case T.Semicolon: | |
368 nT(); | |
369 decl = new EmptyDeclaration(); | |
370 break; | |
371 // Declaration | |
372 case T.Identifier, T.Dot, T.Typeof: | |
373 case_Declaration: | |
374 return parseVariableOrFunction(this.storageClass, this.protection, this.linkageType); | |
375 default: | |
376 if (token.isIntegralType) | |
377 goto case_Declaration; | |
378 else if (token.kind == T.Module) | |
379 { | |
380 decl = parseModuleDeclaration(); | |
381 error(begin, MSG.ModuleDeclarationNotFirst); | |
382 return decl; | |
383 } | |
384 | |
385 decl = new IllegalDeclaration(); | |
386 // Skip to next valid token. | |
387 do | |
388 nT(); | |
389 while (!token.isDeclDefStart && | |
390 token.kind != T.RBrace && | |
391 token.kind != T.EOF) | |
392 auto text = Token.textSpan(begin, this.prevToken); | |
393 error(begin, MSG.IllegalDeclaration, text); | |
394 } | |
395 decl.setProtection(this.protection); | |
396 decl.setStorageClass(this.storageClass); | |
397 assert(!isNodeSet(decl)); | |
398 set(decl, begin); | |
399 return decl; | |
400 } | |
401 | |
402 /// Parses a DeclarationsBlock. | |
403 /// $(PRE | |
404 /// DeclarationsBlock := | |
405 /// : DeclDefs | |
406 /// { } | |
407 /// { DeclDefs } | |
408 /// DeclDef | |
409 /// ) | |
410 Declaration parseDeclarationsBlock(/+bool noColon = false+/) | |
411 { | |
412 Declaration d; | |
413 switch (token.kind) | |
414 { | |
415 case T.LBrace: | |
416 auto begin = token; | |
417 nT(); | |
418 auto decls = new CompoundDeclaration; | |
419 while (token.kind != T.RBrace && token.kind != T.EOF) | |
420 decls ~= parseDeclarationDefinition(); | |
421 require(T.RBrace); | |
422 d = set(decls, begin); | |
423 break; | |
424 case T.Colon: | |
425 // if (noColon == true) | |
426 // goto default; | |
427 nT(); | |
428 auto begin = token; | |
429 auto decls = new CompoundDeclaration; | |
430 while (token.kind != T.RBrace && token.kind != T.EOF) | |
431 decls ~= parseDeclarationDefinition(); | |
432 d = set(decls, begin); | |
433 break; | |
434 default: | |
435 d = parseDeclarationDefinition(); | |
436 } | |
437 assert(isNodeSet(d)); | |
438 return d; | |
439 } | |
440 | |
441 // Declaration parseDeclarationsBlockNoColon() | |
442 // { | |
443 // return parseDeclarationsBlock(true); | |
444 // } | |
445 | |
446 /// Parses either a VariableDeclaration or a FunctionDeclaration. | |
447 /// Params: | |
448 /// stc = previously parsed storage classes | |
449 /// protection = previously parsed protection attribute | |
450 /// linkType = previously parsed linkage type | |
451 /// testAutoDeclaration = whether to check for an AutoDeclaration | |
452 /// optionalParameterList = a hint for how to parse C-style function pointers | |
453 Declaration parseVariableOrFunction(StorageClass stc = StorageClass.None, | |
454 Protection protection = Protection.None, | |
455 LinkageType linkType = LinkageType.None, | |
456 bool testAutoDeclaration = false, | |
457 bool optionalParameterList = true) | |
458 { | |
459 auto begin = token; | |
460 Type type; | |
461 Identifier* name; | |
462 | |
463 // Check for AutoDeclaration: StorageClasses Identifier = | |
464 if (testAutoDeclaration && | |
465 token.kind == T.Identifier && | |
466 peekNext() == T.Assign) | |
467 { | |
468 name = token.ident; | |
469 skip(T.Identifier); | |
470 } | |
471 else | |
472 { | |
473 type = parseType(); // VariableType or ReturnType | |
474 if (token.kind == T.LParen) | |
475 { | |
476 // C-style function pointers make the grammar ambiguous. | |
477 // We have to treat them specially at function scope. | |
478 // Example: | |
479 // void foo() { | |
480 // // A pointer to a function taking an integer and returning 'some_type'. | |
481 // some_type (*p_func)(int); | |
482 // // In the following case precedence is given to a CallExpression. | |
483 // something(*p); // 'something' may be a function/method or an object having opCall overloaded. | |
484 // } | |
485 // // A pointer to a function taking no parameters and returning 'something'. | |
486 // something(*p); | |
487 type = parseCFunctionPointerType(type, name, optionalParameterList); | |
488 } | |
489 else if (peekNext() == T.LParen) | |
490 { // Type FunctionName ( ParameterList ) FunctionBody | |
491 name = requireIdentifier(MSG.ExpectedFunctionName); | |
492 name || nT(); // Skip non-identifier token. | |
493 assert(token.kind == T.LParen); | |
494 // It's a function declaration | |
495 TemplateParameters tparams; | |
496 if (tokenAfterParenIs(T.LParen)) | |
497 // ( TemplateParameterList ) ( ParameterList ) | |
498 tparams = parseTemplateParameterList(); | |
499 | |
500 auto params = parseParameterList(); | |
501 version(D2) | |
502 { | |
503 switch (token.kind) | |
504 { | |
505 case T.Const: | |
506 stc |= StorageClass.Const; | |
507 nT(); | |
508 break; | |
509 case T.Invariant: | |
510 stc |= StorageClass.Invariant; | |
511 nT(); | |
512 break; | |
513 default: | |
514 } | |
515 } | |
516 // ReturnType FunctionName ( ParameterList ) | |
517 auto funcBody = parseFunctionBody(); | |
518 auto fd = new FunctionDeclaration(type, name,/+ tparams,+/ params, funcBody); | |
519 fd.setStorageClass(stc); | |
520 fd.setLinkageType(linkType); | |
521 fd.setProtection(protection); | |
522 if (tparams) | |
523 { | |
524 auto d = putInsideTemplateDeclaration(begin, name, fd, tparams); | |
525 d.setStorageClass(stc); | |
526 d.setProtection(protection); | |
527 return set(d, begin); | |
528 } | |
529 return set(fd, begin); | |
530 } | |
531 else | |
532 { // Type VariableName DeclaratorSuffix | |
533 name = requireIdentifier(MSG.ExpectedVariableName); | |
534 type = parseDeclaratorSuffix(type); | |
535 } | |
536 } | |
537 | |
538 // It's a variables declaration. | |
539 Identifier*[] names = [name]; // One identifier has been parsed already. | |
540 Expression[] values; | |
541 goto LenterLoop; // Enter the loop and check for an initializer. | |
542 while (consumed(T.Comma)) | |
543 { | |
544 names ~= requireIdentifier(MSG.ExpectedVariableName); | |
545 LenterLoop: | |
546 if (consumed(T.Assign)) | |
547 values ~= parseInitializer(); | |
548 else | |
549 values ~= null; | |
550 } | |
551 require(T.Semicolon); | |
552 auto d = new VariablesDeclaration(type, names, values); | |
553 d.setStorageClass(stc); | |
554 d.setLinkageType(linkType); | |
555 d.setProtection(protection); | |
556 return set(d, begin); | |
557 } | |
558 | |
559 /// Parses a variable initializer. | |
560 Expression parseInitializer() | |
561 { | |
562 if (token.kind == T.Void) | |
563 { | |
564 auto begin = token; | |
565 auto next = peekNext(); | |
566 if (next == T.Comma || next == T.Semicolon) | |
567 { | |
568 skip(T.Void); | |
569 return set(new VoidInitExpression(), begin); | |
570 } | |
571 } | |
572 return parseNonVoidInitializer(); | |
573 } | |
574 | |
575 Expression parseNonVoidInitializer() | |
576 { | |
577 auto begin = token; | |
578 Expression init; | |
579 switch (token.kind) | |
580 { | |
581 case T.LBracket: | |
582 // ArrayInitializer: | |
583 // [ ] | |
584 // [ ArrayMemberInitializations ] | |
585 Expression[] keys; | |
586 Expression[] values; | |
587 | |
588 skip(T.LBracket); | |
589 while (token.kind != T.RBracket) | |
590 { | |
591 auto e = parseNonVoidInitializer(); | |
592 if (consumed(T.Colon)) | |
593 { | |
594 keys ~= e; | |
595 values ~= parseNonVoidInitializer(); | |
596 } | |
597 else | |
598 { | |
599 keys ~= null; | |
600 values ~= e; | |
601 } | |
602 | |
603 if (!consumed(T.Comma)) | |
604 break; | |
605 } | |
606 require(T.RBracket); | |
607 init = new ArrayInitExpression(keys, values); | |
608 break; | |
609 case T.LBrace: | |
610 // StructInitializer: | |
611 // { } | |
612 // { StructMemberInitializers } | |
613 Expression parseStructInitializer() | |
614 { | |
615 Identifier*[] idents; | |
616 Expression[] values; | |
617 | |
618 skip(T.LBrace); | |
619 while (token.kind != T.RBrace) | |
620 { | |
621 if (token.kind == T.Identifier && | |
622 // Peek for colon to see if this is a member identifier. | |
623 peekNext() == T.Colon) | |
624 { | |
625 idents ~= token.ident; | |
626 skip(T.Identifier), skip(T.Colon); | |
627 } | |
628 else | |
629 idents ~= null; | |
630 | |
631 // NonVoidInitializer | |
632 values ~= parseNonVoidInitializer(); | |
633 | |
634 if (!consumed(T.Comma)) | |
635 break; | |
636 } | |
637 require(T.RBrace); | |
638 return new StructInitExpression(idents, values); | |
639 } | |
640 | |
641 bool success; | |
642 auto si = try_(&parseStructInitializer, success); | |
643 if (success) | |
644 { | |
645 init = si; | |
646 break; | |
647 } | |
648 assert(token.kind == T.LBrace); | |
649 //goto default; | |
650 default: | |
651 init = parseAssignExpression(); | |
652 } | |
653 set(init, begin); | |
654 return init; | |
655 } | |
656 | |
657 FuncBodyStatement parseFunctionBody() | |
658 { | |
659 auto begin = token; | |
660 auto func = new FuncBodyStatement; | |
661 while (1) | |
662 { | |
663 switch (token.kind) | |
664 { | |
665 case T.LBrace: | |
666 func.funcBody = parseStatements(); | |
667 break; | |
668 case T.Semicolon: | |
669 nT(); | |
670 break; | |
671 case T.In: | |
672 if (func.inBody) | |
673 error(MID.InContract); | |
674 nT(); | |
675 func.inBody = parseStatements(); | |
676 continue; | |
677 case T.Out: | |
678 if (func.outBody) | |
679 error(MID.OutContract); | |
680 nT(); | |
681 if (consumed(T.LParen)) | |
682 { | |
683 func.outIdent = requireIdentifier(MSG.ExpectedAnIdentifier); | |
684 require(T.RParen); | |
685 } | |
686 func.outBody = parseStatements(); | |
687 continue; | |
688 case T.Body: | |
689 nT(); | |
690 goto case T.LBrace; | |
691 default: | |
692 error(token, MSG.ExpectedFunctionBody, token.srcText); | |
693 } | |
694 break; // Exit loop. | |
695 } | |
696 set(func, begin); | |
697 func.finishConstruction(); | |
698 return func; | |
699 } | |
700 | |
701 LinkageType parseLinkageType() | |
702 { | |
703 LinkageType linkageType; | |
704 | |
705 if (!consumed(T.LParen)) | |
706 return linkageType; | |
707 | |
708 if (consumed(T.RParen)) | |
709 { // extern() | |
710 error(MID.MissingLinkageType); | |
711 return linkageType; | |
712 } | |
713 | |
714 auto identTok = requireId(); | |
715 | |
716 IDK idKind = identTok ? identTok.ident.idKind : IDK.Null; | |
717 | |
718 switch (idKind) | |
719 { | |
720 case IDK.C: | |
721 if (consumed(T.PlusPlus)) | |
722 { | |
723 linkageType = LinkageType.Cpp; | |
724 break; | |
725 } | |
726 linkageType = LinkageType.C; | |
727 break; | |
728 case IDK.D: | |
729 linkageType = LinkageType.D; | |
730 break; | |
731 case IDK.Windows: | |
732 linkageType = LinkageType.Windows; | |
733 break; | |
734 case IDK.Pascal: | |
735 linkageType = LinkageType.Pascal; | |
736 break; | |
737 case IDK.System: | |
738 linkageType = LinkageType.System; | |
739 break; | |
740 default: | |
741 error(MID.UnrecognizedLinkageType, token.srcText); | |
742 } | |
743 require(T.RParen); | |
744 return linkageType; | |
745 } | |
746 | |
747 void checkLinkageType(ref LinkageType prev_lt, LinkageType lt, Token* begin) | |
748 { | |
749 if (prev_lt == LinkageType.None) | |
750 prev_lt = lt; | |
751 else | |
752 error(begin, MSG.RedundantLinkageType, Token.textSpan(begin, this.prevToken)); | |
753 } | |
754 | |
755 Declaration parseStorageAttribute() | |
756 { | |
757 StorageClass stc, stc_tmp; | |
758 LinkageType prev_linkageType; | |
759 | |
760 auto saved_storageClass = this.storageClass; // Save. | |
761 // Nested function. | |
762 Declaration parse() | |
763 { | |
764 Declaration decl; | |
765 auto begin = token; | |
766 switch (token.kind) | |
767 { | |
768 case T.Extern: | |
769 if (peekNext() != T.LParen) | |
770 { | |
771 stc_tmp = StorageClass.Extern; | |
772 goto Lcommon; | |
773 } | |
774 | |
775 nT(); | |
776 auto linkageType = parseLinkageType(); | |
777 checkLinkageType(prev_linkageType, linkageType, begin); | |
778 | |
779 auto saved = this.linkageType; // Save. | |
780 this.linkageType = linkageType; // Set. | |
781 decl = new LinkageDeclaration(linkageType, parse()); | |
782 set(decl, begin); | |
783 this.linkageType = saved; // Restore. | |
784 break; | |
785 case T.Override: | |
786 stc_tmp = StorageClass.Override; | |
787 goto Lcommon; | |
788 case T.Deprecated: | |
789 stc_tmp = StorageClass.Deprecated; | |
790 goto Lcommon; | |
791 case T.Abstract: | |
792 stc_tmp = StorageClass.Abstract; | |
793 goto Lcommon; | |
794 case T.Synchronized: | |
795 stc_tmp = StorageClass.Synchronized; | |
796 goto Lcommon; | |
797 case T.Static: | |
798 stc_tmp = StorageClass.Static; | |
799 goto Lcommon; | |
800 case T.Final: | |
801 stc_tmp = StorageClass.Final; | |
802 goto Lcommon; | |
803 case T.Const: | |
804 version(D2) | |
805 { | |
806 if (peekNext() == T.LParen) | |
807 goto case_Declaration; | |
808 } | |
809 stc_tmp = StorageClass.Const; | |
810 goto Lcommon; | |
811 version(D2) | |
812 { | |
813 case T.Invariant: // D 2.0 | |
814 auto next = token; | |
815 if (peekAfter(next) == T.LParen) | |
816 { | |
817 if (peekAfter(next) != T.RParen) | |
818 goto case_Declaration; // invariant ( Type ) | |
819 decl = parseDeclarationDefinition(); // invariant ( ) | |
820 decl.setStorageClass(stc); | |
821 break; | |
822 } | |
823 // invariant as StorageClass. | |
824 stc_tmp = StorageClass.Invariant; | |
825 goto Lcommon; | |
826 } | |
827 case T.Auto: | |
828 stc_tmp = StorageClass.Auto; | |
829 goto Lcommon; | |
830 case T.Scope: | |
831 stc_tmp = StorageClass.Scope; | |
832 goto Lcommon; | |
833 Lcommon: | |
834 // Issue error if redundant. | |
835 if (stc & stc_tmp) | |
836 error(MID.RedundantStorageClass, token.srcText); | |
837 else | |
838 stc |= stc_tmp; | |
839 | |
840 nT(); | |
841 decl = new StorageClassDeclaration(stc_tmp, parse()); | |
842 set(decl, begin); | |
843 break; | |
844 case T.Identifier: | |
845 case_Declaration: | |
846 // This could be a normal Declaration or an AutoDeclaration | |
847 decl = parseVariableOrFunction(stc, this.protection, prev_linkageType, true); | |
848 break; | |
849 default: | |
850 this.storageClass = stc; // Set. | |
851 decl = parseDeclarationsBlock(); | |
852 this.storageClass = saved_storageClass; // Reset. | |
853 } | |
854 assert(isNodeSet(decl)); | |
855 return decl; | |
856 } | |
857 return parse(); | |
858 } | |
859 | |
860 uint parseAlignAttribute() | |
861 { | |
862 skip(T.Align); | |
863 uint size = DEFAULT_ALIGN_SIZE; // Global default. | |
864 if (consumed(T.LParen)) | |
865 { | |
866 if (token.kind == T.Int32) | |
867 (size = token.int_), skip(T.Int32); | |
868 else | |
869 expected(T.Int32); | |
870 require(T.RParen); | |
871 } | |
872 return size; | |
873 } | |
874 | |
875 Declaration parseAttributeSpecifier() | |
876 { | |
877 Declaration decl; | |
878 | |
879 switch (token.kind) | |
880 { | |
881 case T.Align: | |
882 uint alignSize = parseAlignAttribute(); | |
883 auto saved = this.alignSize; // Save. | |
884 this.alignSize = alignSize; // Set. | |
885 decl = new AlignDeclaration(alignSize, parseDeclarationsBlock()); | |
886 this.alignSize = saved; // Restore. | |
887 break; | |
888 case T.Pragma: | |
889 // Pragma: | |
890 // pragma ( Identifier ) | |
891 // pragma ( Identifier , ExpressionList ) | |
892 nT(); | |
893 Identifier* ident; | |
894 Expression[] args; | |
895 | |
896 require(T.LParen); | |
897 ident = requireIdentifier(MSG.ExpectedPragmaIdentifier); | |
898 | |
899 if (consumed(T.Comma)) | |
900 args = parseExpressionList(); | |
901 require(T.RParen); | |
902 | |
903 decl = new PragmaDeclaration(ident, args, parseDeclarationsBlock()); | |
904 break; | |
905 default: | |
906 // Protection attributes | |
907 Protection prot; | |
908 switch (token.kind) | |
909 { | |
910 case T.Private: | |
911 prot = Protection.Private; break; | |
912 case T.Package: | |
913 prot = Protection.Package; break; | |
914 case T.Protected: | |
915 prot = Protection.Protected; break; | |
916 case T.Public: | |
917 prot = Protection.Public; break; | |
918 case T.Export: | |
919 prot = Protection.Export; break; | |
920 default: | |
921 assert(0); | |
922 } | |
923 nT(); | |
924 auto saved = this.protection; // Save. | |
925 this.protection = prot; // Set. | |
926 decl = new ProtectionDeclaration(prot, parseDeclarationsBlock()); | |
927 this.protection = saved; // Restore. | |
928 } | |
929 return decl; | |
930 } | |
931 | |
932 Declaration parseImportDeclaration() | |
933 { | |
934 bool isStatic = consumed(T.Static); | |
935 skip(T.Import); | |
936 | |
937 ModuleFQN[] moduleFQNs; | |
938 Identifier*[] moduleAliases; | |
939 Identifier*[] bindNames; | |
940 Identifier*[] bindAliases; | |
941 | |
942 do | |
943 { | |
944 ModuleFQN moduleFQN; | |
945 Identifier* moduleAlias; | |
946 // AliasName = ModuleName | |
947 if (peekNext() == T.Assign) | |
948 { | |
949 moduleAlias = requireIdentifier(MSG.ExpectedAliasModuleName); | |
950 skip(T.Assign); | |
951 } | |
952 // Identifier ("." Identifier)* | |
953 do | |
954 moduleFQN ~= requireIdentifier(MSG.ExpectedModuleIdentifier); | |
955 while (consumed(T.Dot)) | |
956 // Push identifiers. | |
957 moduleFQNs ~= moduleFQN; | |
958 moduleAliases ~= moduleAlias; | |
959 } while (consumed(T.Comma)) | |
960 | |
961 if (consumed(T.Colon)) | |
962 { // BindAlias "=" BindName ("," BindAlias "=" BindName)*; | |
963 // BindName ("," BindName)*; | |
964 do | |
965 { | |
966 Identifier* bindAlias; | |
967 // BindAlias = BindName | |
968 if (peekNext() == T.Assign) | |
969 { | |
970 bindAlias = requireIdentifier(MSG.ExpectedAliasImportName); | |
971 skip(T.Assign); | |
972 } | |
973 // Push identifiers. | |
974 bindNames ~= requireIdentifier(MSG.ExpectedImportName); | |
975 bindAliases ~= bindAlias; | |
976 } while (consumed(T.Comma)) | |
977 } | |
978 require(T.Semicolon); | |
979 | |
980 return new ImportDeclaration(moduleFQNs, moduleAliases, bindNames, bindAliases, isStatic); | |
981 } | |
982 | |
983 Declaration parseEnumDeclaration() | |
984 { | |
985 skip(T.Enum); | |
986 | |
987 Identifier* enumName; | |
988 Type baseType; | |
989 EnumMemberDeclaration[] members; | |
990 bool hasBody; | |
991 | |
992 enumName = optionalIdentifier(); | |
993 | |
994 if (consumed(T.Colon)) | |
995 baseType = parseBasicType(); | |
996 | |
997 if (enumName && consumed(T.Semicolon)) | |
998 {} | |
999 else if (consumed(T.LBrace)) | |
1000 { | |
1001 hasBody = true; | |
1002 while (token.kind != T.RBrace) | |
1003 { | |
1004 auto begin = token; | |
1005 auto name = requireIdentifier(MSG.ExpectedEnumMember); | |
1006 Expression value; | |
1007 | |
1008 if (consumed(T.Assign)) | |
1009 value = parseAssignExpression(); | |
1010 else | |
1011 value = null; | |
1012 | |
1013 members ~= set(new EnumMemberDeclaration(name, value), begin); | |
1014 | |
1015 if (!consumed(T.Comma)) | |
1016 break; | |
1017 } | |
1018 require(T.RBrace); | |
1019 } | |
1020 else | |
1021 error(token, MSG.ExpectedEnumBody, token.srcText); | |
1022 | |
1023 return new EnumDeclaration(enumName, baseType, members, hasBody); | |
1024 } | |
1025 | |
1026 /// Wraps a declaration inside a template declaration. | |
1027 /// Params: | |
1028 /// begin = begin token of decl. | |
1029 /// name = name of decl. | |
1030 /// decl = the declaration to be wrapped. | |
1031 /// tparams = the template parameters. | |
1032 TemplateDeclaration putInsideTemplateDeclaration(Token* begin, | |
1033 Identifier* name, | |
1034 Declaration decl, | |
1035 TemplateParameters tparams) | |
1036 { | |
1037 set(decl, begin); | |
1038 auto cd = new CompoundDeclaration; | |
1039 cd ~= decl; | |
1040 set(cd, begin); | |
1041 return new TemplateDeclaration(name, tparams, cd); | |
1042 } | |
1043 | |
1044 Declaration parseClassDeclaration() | |
1045 { | |
1046 auto begin = token; | |
1047 skip(T.Class); | |
1048 | |
1049 Identifier* className; | |
1050 TemplateParameters tparams; | |
1051 BaseClassType[] bases; | |
1052 CompoundDeclaration decls; | |
1053 | |
1054 className = requireIdentifier(MSG.ExpectedClassName); | |
1055 | |
1056 if (token.kind == T.LParen) | |
1057 tparams = parseTemplateParameterList(); | |
1058 | |
1059 if (token.kind == T.Colon) | |
1060 bases = parseBaseClasses(); | |
1061 | |
1062 if (bases.length == 0 && consumed(T.Semicolon)) | |
1063 {} | |
1064 else if (token.kind == T.LBrace) | |
1065 decls = parseDeclarationDefinitionsBody(); | |
1066 else | |
1067 error(token, MSG.ExpectedClassBody, token.srcText); | |
1068 | |
1069 Declaration d = new ClassDeclaration(className, /+tparams, +/bases, decls); | |
1070 if (tparams) | |
1071 d = putInsideTemplateDeclaration(begin, className, d, tparams); | |
1072 return d; | |
1073 } | |
1074 | |
1075 BaseClassType[] parseBaseClasses(bool colonLeadsOff = true) | |
1076 { | |
1077 colonLeadsOff && skip(T.Colon); | |
1078 | |
1079 BaseClassType[] bases; | |
1080 do | |
1081 { | |
1082 Protection prot = Protection.Public; | |
1083 switch (token.kind) | |
1084 { | |
1085 case T.Identifier, T.Dot, T.Typeof: goto LparseBasicType; | |
1086 case T.Private: prot = Protection.Private; break; | |
1087 case T.Protected: prot = Protection.Protected; break; | |
1088 case T.Package: prot = Protection.Package; break; | |
1089 case T.Public: /*prot = Protection.Public;*/ break; | |
1090 default: | |
1091 error(MID.ExpectedBaseClasses, token.srcText); | |
1092 return bases; | |
1093 } | |
1094 nT(); // Skip protection attribute. | |
1095 LparseBasicType: | |
1096 auto begin = token; | |
1097 auto type = parseBasicType(); | |
1098 bases ~= set(new BaseClassType(prot, type), begin); | |
1099 } while (consumed(T.Comma)) | |
1100 return bases; | |
1101 } | |
1102 | |
1103 Declaration parseInterfaceDeclaration() | |
1104 { | |
1105 auto begin = token; | |
1106 skip(T.Interface); | |
1107 | |
1108 Identifier* name; | |
1109 TemplateParameters tparams; | |
1110 BaseClassType[] bases; | |
1111 CompoundDeclaration decls; | |
1112 | |
1113 name = requireIdentifier(MSG.ExpectedInterfaceName); | |
1114 | |
1115 if (token.kind == T.LParen) | |
1116 tparams = parseTemplateParameterList(); | |
1117 | |
1118 if (token.kind == T.Colon) | |
1119 bases = parseBaseClasses(); | |
1120 | |
1121 if (bases.length == 0 && consumed(T.Semicolon)) | |
1122 {} | |
1123 else if (token.kind == T.LBrace) | |
1124 decls = parseDeclarationDefinitionsBody(); | |
1125 else | |
1126 error(token, MSG.ExpectedInterfaceBody, token.srcText); | |
1127 | |
1128 Declaration d = new InterfaceDeclaration(name, /+tparams, +/bases, decls); | |
1129 if (tparams) | |
1130 d = putInsideTemplateDeclaration(begin, name, d, tparams); | |
1131 return d; | |
1132 } | |
1133 | |
1134 Declaration parseStructOrUnionDeclaration() | |
1135 { | |
1136 assert(token.kind == T.Struct || token.kind == T.Union); | |
1137 auto begin = token; | |
1138 skip(token.kind); | |
1139 | |
1140 Identifier* name; | |
1141 TemplateParameters tparams; | |
1142 CompoundDeclaration decls; | |
1143 | |
1144 name = optionalIdentifier(); | |
1145 | |
1146 if (name && token.kind == T.LParen) | |
1147 tparams = parseTemplateParameterList(); | |
1148 | |
1149 if (name && consumed(T.Semicolon)) | |
1150 {} | |
1151 else if (token.kind == T.LBrace) | |
1152 decls = parseDeclarationDefinitionsBody(); | |
1153 else | |
1154 error(token, begin.kind == T.Struct ? | |
1155 MSG.ExpectedStructBody : | |
1156 MSG.ExpectedUnionBody, token.srcText); | |
1157 | |
1158 Declaration d; | |
1159 if (begin.kind == T.Struct) | |
1160 { | |
1161 auto sd = new StructDeclaration(name, /+tparams, +/decls); | |
1162 sd.setAlignSize(this.alignSize); | |
1163 d = sd; | |
1164 } | |
1165 else | |
1166 d = new UnionDeclaration(name, /+tparams, +/decls); | |
1167 | |
1168 if (tparams) | |
1169 d = putInsideTemplateDeclaration(begin, name, d, tparams); | |
1170 return d; | |
1171 } | |
1172 | |
1173 Declaration parseConstructorDeclaration() | |
1174 { | |
1175 skip(T.This); | |
1176 auto parameters = parseParameterList(); | |
1177 auto funcBody = parseFunctionBody(); | |
1178 return new ConstructorDeclaration(parameters, funcBody); | |
1179 } | |
1180 | |
1181 Declaration parseDestructorDeclaration() | |
1182 { | |
1183 skip(T.Tilde); | |
1184 require(T.This); | |
1185 require(T.LParen); | |
1186 require(T.RParen); | |
1187 auto funcBody = parseFunctionBody(); | |
1188 return new DestructorDeclaration(funcBody); | |
1189 } | |
1190 | |
1191 Declaration parseStaticConstructorDeclaration() | |
1192 { | |
1193 skip(T.Static); | |
1194 skip(T.This); | |
1195 require(T.LParen); | |
1196 require(T.RParen); | |
1197 auto funcBody = parseFunctionBody(); | |
1198 return new StaticConstructorDeclaration(funcBody); | |
1199 } | |
1200 | |
1201 Declaration parseStaticDestructorDeclaration() | |
1202 { | |
1203 skip(T.Static); | |
1204 skip(T.Tilde); | |
1205 require(T.This); | |
1206 require(T.LParen); | |
1207 require(T.RParen); | |
1208 auto funcBody = parseFunctionBody(); | |
1209 return new StaticDestructorDeclaration(funcBody); | |
1210 } | |
1211 | |
1212 Declaration parseInvariantDeclaration() | |
1213 { | |
1214 skip(T.Invariant); | |
1215 // Optional () for getting ready porting to D 2.0 | |
1216 if (consumed(T.LParen)) | |
1217 require(T.RParen); | |
1218 auto funcBody = parseFunctionBody(); | |
1219 return new InvariantDeclaration(funcBody); | |
1220 } | |
1221 | |
1222 Declaration parseUnittestDeclaration() | |
1223 { | |
1224 skip(T.Unittest); | |
1225 auto funcBody = parseFunctionBody(); | |
1226 return new UnittestDeclaration(funcBody); | |
1227 } | |
1228 | |
1229 Token* parseIdentOrInt() | |
1230 { | |
1231 if (consumed(T.Int32) || consumed(T.Identifier)) | |
1232 return this.prevToken; | |
1233 error(token, MSG.ExpectedIdentOrInt, token.srcText); | |
1234 return null; | |
1235 } | |
1236 | |
1237 Declaration parseDebugDeclaration() | |
1238 { | |
1239 skip(T.Debug); | |
1240 | |
1241 Token* spec; | |
1242 Token* cond; | |
1243 Declaration decls, elseDecls; | |
1244 | |
1245 if (consumed(T.Assign)) | |
1246 { // debug = Integer ; | |
1247 // debug = Identifier ; | |
1248 spec = parseIdentOrInt(); | |
1249 require(T.Semicolon); | |
1250 } | |
1251 else | |
1252 { // ( Condition ) | |
1253 if (consumed(T.LParen)) | |
1254 { | |
1255 cond = parseIdentOrInt(); | |
1256 require(T.RParen); | |
1257 } | |
1258 // debug DeclarationsBlock | |
1259 // debug ( Condition ) DeclarationsBlock | |
1260 decls = parseDeclarationsBlock(); | |
1261 // else DeclarationsBlock | |
1262 if (consumed(T.Else)) | |
1263 elseDecls = parseDeclarationsBlock(); | |
1264 } | |
1265 | |
1266 return new DebugDeclaration(spec, cond, decls, elseDecls); | |
1267 } | |
1268 | |
1269 Declaration parseVersionDeclaration() | |
1270 { | |
1271 skip(T.Version); | |
1272 | |
1273 Token* spec; | |
1274 Token* cond; | |
1275 Declaration decls, elseDecls; | |
1276 | |
1277 if (consumed(T.Assign)) | |
1278 { // version = Integer ; | |
1279 // version = Identifier ; | |
1280 spec = parseIdentOrInt(); | |
1281 require(T.Semicolon); | |
1282 } | |
1283 else | |
1284 { // ( Condition ) | |
1285 require(T.LParen); | |
1286 cond = parseIdentOrInt(); | |
1287 require(T.RParen); | |
1288 // version ( Condition ) DeclarationsBlock | |
1289 decls = parseDeclarationsBlock(); | |
1290 // else DeclarationsBlock | |
1291 if (consumed(T.Else)) | |
1292 elseDecls = parseDeclarationsBlock(); | |
1293 } | |
1294 | |
1295 return new VersionDeclaration(spec, cond, decls, elseDecls); | |
1296 } | |
1297 | |
1298 Declaration parseStaticIfDeclaration() | |
1299 { | |
1300 skip(T.Static); | |
1301 skip(T.If); | |
1302 | |
1303 Expression condition; | |
1304 Declaration ifDecls, elseDecls; | |
1305 | |
1306 require(T.LParen); | |
1307 condition = parseAssignExpression(); | |
1308 require(T.RParen); | |
1309 | |
1310 ifDecls = parseDeclarationsBlock(); | |
1311 | |
1312 if (consumed(T.Else)) | |
1313 elseDecls = parseDeclarationsBlock(); | |
1314 | |
1315 return new StaticIfDeclaration(condition, ifDecls, elseDecls); | |
1316 } | |
1317 | |
1318 Declaration parseStaticAssertDeclaration() | |
1319 { | |
1320 skip(T.Static); | |
1321 skip(T.Assert); | |
1322 Expression condition, message; | |
1323 require(T.LParen); | |
1324 condition = parseAssignExpression(); | |
1325 if (consumed(T.Comma)) | |
1326 message = parseAssignExpression(); | |
1327 require(T.RParen); | |
1328 require(T.Semicolon); | |
1329 return new StaticAssertDeclaration(condition, message); | |
1330 } | |
1331 | |
1332 Declaration parseTemplateDeclaration() | |
1333 { | |
1334 skip(T.Template); | |
1335 auto templateName = requireIdentifier(MSG.ExpectedTemplateName); | |
1336 auto templateParams = parseTemplateParameterList(); | |
1337 auto decls = parseDeclarationDefinitionsBody(); | |
1338 return new TemplateDeclaration(templateName, templateParams, decls); | |
1339 } | |
1340 | |
1341 Declaration parseNewDeclaration() | |
1342 { | |
1343 skip(T.New); | |
1344 auto parameters = parseParameterList(); | |
1345 auto funcBody = parseFunctionBody(); | |
1346 return new NewDeclaration(parameters, funcBody); | |
1347 } | |
1348 | |
1349 Declaration parseDeleteDeclaration() | |
1350 { | |
1351 skip(T.Delete); | |
1352 auto parameters = parseParameterList(); | |
1353 auto funcBody = parseFunctionBody(); | |
1354 return new DeleteDeclaration(parameters, funcBody); | |
1355 } | |
1356 | |
1357 Type parseTypeofType() | |
1358 { | |
1359 auto begin = token; | |
1360 skip(T.Typeof); | |
1361 require(T.LParen); | |
1362 Type type; | |
1363 switch (token.kind) | |
1364 { | |
1365 version(D2) | |
1366 { | |
1367 case T.Return: | |
1368 nT(); | |
1369 type = new TypeofType(); | |
1370 break; | |
1371 } | |
1372 default: | |
1373 type = new TypeofType(parseExpression()); | |
1374 } | |
1375 require(T.RParen); | |
1376 set(type, begin); | |
1377 return type; | |
1378 } | |
1379 | |
1380 /// Parses a MixinDeclaration or MixinStatement. | |
1381 /// $(PRE | |
1382 /// TemplateMixin := | |
1383 /// mixin ( AssignExpression ) ; | |
1384 /// mixin TemplateIdentifier ; | |
1385 /// mixin TemplateIdentifier MixinIdentifier ; | |
1386 /// mixin TemplateIdentifier !( TemplateArguments ) ; | |
1387 /// mixin TemplateIdentifier !( TemplateArguments ) MixinIdentifier ; | |
1388 /// ) | |
1389 Class parseMixin(Class)() | |
1390 { | |
1391 static assert(is(Class == MixinDeclaration) || is(Class == MixinStatement)); | |
1392 skip(T.Mixin); | |
1393 | |
1394 static if (is(Class == MixinDeclaration)) | |
1395 { | |
1396 if (consumed(T.LParen)) | |
1397 { | |
1398 auto e = parseAssignExpression(); | |
1399 require(T.RParen); | |
1400 require(T.Semicolon); | |
1401 return new MixinDeclaration(e); | |
1402 } | |
1403 } | |
1404 | |
1405 auto begin = token; | |
1406 Expression e; | |
1407 Identifier* mixinIdent; | |
1408 | |
1409 if (consumed(T.Dot)) | |
1410 e = set(new ModuleScopeExpression(parseIdentifierExpression()), begin); | |
1411 else | |
1412 e = parseIdentifierExpression(); | |
1413 | |
1414 while (consumed(T.Dot)) | |
1415 e = set(new DotExpression(e, parseIdentifierExpression()), begin); | |
1416 | |
1417 mixinIdent = optionalIdentifier(); | |
1418 require(T.Semicolon); | |
1419 | |
1420 return new Class(e, mixinIdent); | |
1421 } | |
1422 | |
1423 /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
1424 | Statement parsing methods | | |
1425 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/ | |
1426 | |
1427 CompoundStatement parseStatements() | |
1428 { | |
1429 auto begin = token; | |
1430 require(T.LBrace); | |
1431 auto statements = new CompoundStatement(); | |
1432 while (token.kind != T.RBrace && token.kind != T.EOF) | |
1433 statements ~= parseStatement(); | |
1434 require(T.RBrace); | |
1435 return set(statements, begin); | |
1436 } | |
1437 | |
1438 /// Parses a Statement. | |
1439 Statement parseStatement() | |
1440 { | |
1441 auto begin = token; | |
1442 Statement s; | |
1443 Declaration d; | |
1444 | |
1445 if (token.isIntegralType) | |
1446 { | |
1447 d = parseVariableOrFunction(); | |
1448 goto LreturnDeclarationStatement; | |
1449 } | |
1450 | |
1451 switch (token.kind) | |
1452 { | |
1453 case T.Align: | |
1454 uint size = parseAlignAttribute(); | |
1455 // Restrict align attribute to structs in parsing phase. | |
1456 StructDeclaration structDecl; | |
1457 if (token.kind == T.Struct) | |
1458 { | |
1459 auto begin2 = token; | |
1460 structDecl = parseStructOrUnionDeclaration().to!(StructDeclaration); | |
1461 structDecl.setAlignSize(size); | |
1462 set(structDecl, begin2); | |
1463 } | |
1464 else | |
1465 expected(T.Struct); | |
1466 | |
1467 d = new AlignDeclaration(size, structDecl ? cast(Declaration)structDecl : new CompoundDeclaration); | |
1468 goto LreturnDeclarationStatement; | |
1469 /+ Not applicable for statements. | |
1470 T.Private, T.Package, T.Protected, T.Public, T.Export, | |
1471 T.Deprecated, T.Override, T.Abstract,+/ | |
1472 case T.Extern, | |
1473 T.Final, | |
1474 T.Const, | |
1475 T.Auto: | |
1476 //T.Scope | |
1477 //T.Static | |
1478 case_parseAttribute: | |
1479 s = parseAttributeStatement(); | |
1480 return s; | |
1481 case T.Identifier: | |
1482 if (peekNext() == T.Colon) | |
1483 { | |
1484 auto ident = token.ident; | |
1485 skip(T.Identifier); skip(T.Colon); | |
1486 s = new LabeledStatement(ident, parseNoScopeOrEmptyStatement()); | |
1487 break; | |
1488 } | |
1489 goto case T.Dot; | |
1490 case T.Dot, T.Typeof: | |
1491 bool success; | |
1492 d = try_(delegate { | |
1493 return parseVariableOrFunction(StorageClass.None, | |
1494 Protection.None, | |
1495 LinkageType.None, false, false); | |
1496 }, success | |
1497 ); | |
1498 if (success) | |
1499 goto LreturnDeclarationStatement; // Declaration | |
1500 else | |
1501 goto case_parseExpressionStatement; // Expression | |
1502 | |
1503 case T.If: | |
1504 s = parseIfStatement(); | |
1505 break; | |
1506 case T.While: | |
1507 s = parseWhileStatement(); | |
1508 break; | |
1509 case T.Do: | |
1510 s = parseDoWhileStatement(); | |
1511 break; | |
1512 case T.For: | |
1513 s = parseForStatement(); | |
1514 break; | |
1515 case T.Foreach, T.Foreach_reverse: | |
1516 s = parseForeachStatement(); | |
1517 break; | |
1518 case T.Switch: | |
1519 s = parseSwitchStatement(); | |
1520 break; | |
1521 case T.Case: | |
1522 s = parseCaseStatement(); | |
1523 break; | |
1524 case T.Default: | |
1525 s = parseDefaultStatement(); | |
1526 break; | |
1527 case T.Continue: | |
1528 s = parseContinueStatement(); | |
1529 break; | |
1530 case T.Break: | |
1531 s = parseBreakStatement(); | |
1532 break; | |
1533 case T.Return: | |
1534 s = parseReturnStatement(); | |
1535 break; | |
1536 case T.Goto: | |
1537 s = parseGotoStatement(); | |
1538 break; | |
1539 case T.With: | |
1540 s = parseWithStatement(); | |
1541 break; | |
1542 case T.Synchronized: | |
1543 s = parseSynchronizedStatement(); | |
1544 break; | |
1545 case T.Try: | |
1546 s = parseTryStatement(); | |
1547 break; | |
1548 case T.Throw: | |
1549 s = parseThrowStatement(); | |
1550 break; | |
1551 case T.Scope: | |
1552 if (peekNext() != T.LParen) | |
1553 goto case_parseAttribute; | |
1554 s = parseScopeGuardStatement(); | |
1555 break; | |
1556 case T.Volatile: | |
1557 s = parseVolatileStatement(); | |
1558 break; | |
1559 case T.Asm: | |
1560 s = parseAsmBlockStatement(); | |
1561 break; | |
1562 case T.Pragma: | |
1563 s = parsePragmaStatement(); | |
1564 break; | |
1565 case T.Mixin: | |
1566 if (peekNext() == T.LParen) | |
1567 goto case_parseExpressionStatement; // Parse as expression. | |
1568 s = parseMixin!(MixinStatement)(); | |
1569 break; | |
1570 case T.Static: | |
1571 switch (peekNext()) | |
1572 { | |
1573 case T.If: | |
1574 s = parseStaticIfStatement(); | |
1575 break; | |
1576 case T.Assert: | |
1577 s = parseStaticAssertStatement(); | |
1578 break; | |
1579 default: | |
1580 goto case_parseAttribute; | |
1581 } | |
1582 break; | |
1583 case T.Debug: | |
1584 s = parseDebugStatement(); | |
1585 break; | |
1586 case T.Version: | |
1587 s = parseVersionStatement(); | |
1588 break; | |
1589 // DeclDef | |
1590 case T.Alias, T.Typedef: | |
1591 d = parseDeclarationDefinition(); | |
1592 goto LreturnDeclarationStatement; | |
1593 case T.Enum: | |
1594 d = parseEnumDeclaration(); | |
1595 goto LreturnDeclarationStatement; | |
1596 case T.Class: | |
1597 d = parseClassDeclaration(); | |
1598 goto LreturnDeclarationStatement; | |
1599 case T.Interface: | |
1600 d = parseInterfaceDeclaration(); | |
1601 goto LreturnDeclarationStatement; | |
1602 case T.Struct, T.Union: | |
1603 d = parseStructOrUnionDeclaration(); | |
1604 // goto LreturnDeclarationStatement; | |
1605 LreturnDeclarationStatement: | |
1606 set(d, begin); | |
1607 s = new DeclarationStatement(d); | |
1608 break; | |
1609 case T.LBrace: | |
1610 s = parseScopeStatement(); | |
1611 break; | |
1612 case T.Semicolon: | |
1613 nT(); | |
1614 s = new EmptyStatement(); | |
1615 break; | |
1616 // Parse an ExpressionStatement: | |
1617 // Tokens that start a PrimaryExpression. | |
1618 // case T.Identifier, T.Dot, T.Typeof: | |
1619 case T.This: | |
1620 case T.Super: | |
1621 case T.Null: | |
1622 case T.True, T.False: | |
1623 // case T.Dollar: | |
1624 case T.Int32, T.Int64, T.Uint32, T.Uint64: | |
1625 case T.Float32, T.Float64, T.Float80, | |
1626 T.Imaginary32, T.Imaginary64, T.Imaginary80: | |
1627 case T.CharLiteral: | |
1628 case T.String: | |
1629 case T.LBracket: | |
1630 // case T.LBrace: | |
1631 case T.Function, T.Delegate: | |
1632 case T.Assert: | |
1633 // case T.Mixin: | |
1634 case T.Import: | |
1635 case T.Typeid: | |
1636 case T.Is: | |
1637 case T.LParen: | |
1638 case T.Traits: // D2.0 | |
1639 // Tokens that can start a UnaryExpression: | |
1640 case T.AndBinary, T.PlusPlus, T.MinusMinus, T.Mul, T.Minus, | |
1641 T.Plus, T.Not, T.Tilde, T.New, T.Delete, T.Cast: | |
1642 case_parseExpressionStatement: | |
1643 s = new ExpressionStatement(parseExpression()); | |
1644 require(T.Semicolon); | |
1645 break; | |
1646 default: | |
1647 if (token.isSpecialToken) | |
1648 goto case_parseExpressionStatement; | |
1649 | |
1650 if (token.kind != T.Dollar) | |
1651 // Assert that this isn't a valid expression. | |
1652 assert(delegate bool(){ | |
1653 bool success; | |
1654 auto expression = try_(&parseExpression, success); | |
1655 return success; | |
1656 }() == false, "Didn't expect valid expression." | |
1657 ); | |
1658 | |
1659 // Report error: it's an illegal statement. | |
1660 s = new IllegalStatement(); | |
1661 // Skip to next valid token. | |
1662 do | |
1663 nT(); | |
1664 while (!token.isStatementStart && | |
1665 token.kind != T.RBrace && | |
1666 token.kind != T.EOF) | |
1667 auto text = Token.textSpan(begin, this.prevToken); | |
1668 error(begin, MSG.IllegalStatement, text); | |
1669 } | |
1670 assert(s !is null); | |
1671 set(s, begin); | |
1672 return s; | |
1673 } | |
1674 | |
1675 /// $(PRE | |
1676 /// Parses a ScopeStatement. | |
1677 /// ScopeStatement := | |
1678 /// NoScopeStatement | |
1679 /// ) | |
1680 Statement parseScopeStatement() | |
1681 { | |
1682 return new ScopeStatement(parseNoScopeStatement()); | |
1683 } | |
1684 | |
1685 /// $(PRE | |
1686 /// NoScopeStatement := | |
1687 /// NonEmptyStatement | |
1688 /// BlockStatement | |
1689 /// BlockStatement := | |
1690 /// { } | |
1691 /// { StatementList } | |
1692 /// ) | |
1693 Statement parseNoScopeStatement() | |
1694 { | |
1695 auto begin = token; | |
1696 Statement s; | |
1697 if (consumed(T.LBrace)) | |
1698 { | |
1699 auto ss = new CompoundStatement(); | |
1700 while (token.kind != T.RBrace && token.kind != T.EOF) | |
1701 ss ~= parseStatement(); | |
1702 require(T.RBrace); | |
1703 s = set(ss, begin); | |
1704 } | |
1705 else if (token.kind == T.Semicolon) | |
1706 { | |
1707 error(token, MSG.ExpectedNonEmptyStatement); | |
1708 nT(); | |
1709 s = set(new EmptyStatement(), begin); | |
1710 } | |
1711 else | |
1712 s = parseStatement(); | |
1713 return s; | |
1714 } | |
1715 | |
1716 /// $(PRE | |
1717 /// NoScopeOrEmptyStatement := | |
1718 /// ; | |
1719 /// NoScopeStatement | |
1720 /// ) | |
1721 Statement parseNoScopeOrEmptyStatement() | |
1722 { | |
1723 if (consumed(T.Semicolon)) | |
1724 return set(new EmptyStatement(), this.prevToken); | |
1725 else | |
1726 return parseNoScopeStatement(); | |
1727 } | |
1728 | |
1729 Statement parseAttributeStatement() | |
1730 { | |
1731 StorageClass stc, stc_tmp; | |
1732 LinkageType prev_linkageType; | |
1733 | |
1734 Declaration parse() // Nested function. | |
1735 { | |
1736 auto begin = token; | |
1737 Declaration d; | |
1738 switch (token.kind) | |
1739 { | |
1740 case T.Extern: | |
1741 if (peekNext() != T.LParen) | |
1742 { | |
1743 stc_tmp = StorageClass.Extern; | |
1744 goto Lcommon; | |
1745 } | |
1746 | |
1747 nT(); | |
1748 auto linkageType = parseLinkageType(); | |
1749 checkLinkageType(prev_linkageType, linkageType, begin); | |
1750 | |
1751 d = new LinkageDeclaration(linkageType, parse()); | |
1752 break; | |
1753 case T.Static: | |
1754 stc_tmp = StorageClass.Static; | |
1755 goto Lcommon; | |
1756 case T.Final: | |
1757 stc_tmp = StorageClass.Final; | |
1758 goto Lcommon; | |
1759 case T.Const: | |
1760 version(D2) | |
1761 { | |
1762 if (peekNext() == T.LParen) | |
1763 goto case_Declaration; | |
1764 } | |
1765 stc_tmp = StorageClass.Const; | |
1766 goto Lcommon; | |
1767 version(D2) | |
1768 { | |
1769 case T.Invariant: // D 2.0 | |
1770 if (peekNext() == T.LParen) | |
1771 goto case_Declaration; | |
1772 stc_tmp = StorageClass.Invariant; | |
1773 goto Lcommon; | |
1774 } | |
1775 case T.Auto: | |
1776 stc_tmp = StorageClass.Auto; | |
1777 goto Lcommon; | |
1778 case T.Scope: | |
1779 stc_tmp = StorageClass.Scope; | |
1780 goto Lcommon; | |
1781 Lcommon: | |
1782 // Issue error if redundant. | |
1783 if (stc & stc_tmp) | |
1784 error(MID.RedundantStorageClass, token.srcText); | |
1785 else | |
1786 stc |= stc_tmp; | |
1787 | |
1788 nT(); | |
1789 d = new StorageClassDeclaration(stc_tmp, parse()); | |
1790 break; | |
1791 // TODO: allow "scope class", "abstract scope class" in function bodies? | |
1792 //case T.Class: | |
1793 default: | |
1794 case_Declaration: | |
1795 return parseVariableOrFunction(stc, Protection.None, prev_linkageType, true); | |
1796 } | |
1797 return set(d, begin); | |
1798 } | |
1799 return new DeclarationStatement(parse()); | |
1800 } | |
1801 | |
1802 Statement parseIfStatement() | |
1803 { | |
1804 skip(T.If); | |
1805 | |
1806 Statement variable; | |
1807 Expression condition; | |
1808 Statement ifBody, elseBody; | |
1809 | |
1810 require(T.LParen); | |
1811 | |
1812 Identifier* ident; | |
1813 auto begin = token; // For start of AutoDeclaration or normal Declaration. | |
1814 // auto Identifier = Expression | |
1815 if (consumed(T.Auto)) | |
1816 { | |
1817 ident = requireIdentifier(MSG.ExpectedVariableName); | |
1818 require(T.Assign); | |
1819 auto init = parseExpression(); | |
1820 auto v = new VariablesDeclaration(null, [ident], [init]); | |
1821 set(v, begin.nextNWS); | |
1822 auto d = new StorageClassDeclaration(StorageClass.Auto, v); | |
1823 set(d, begin); | |
1824 variable = new DeclarationStatement(d); | |
1825 set(variable, begin); | |
1826 } | |
1827 else | |
1828 { // Declarator = Expression | |
1829 Type parseDeclaratorAssign() | |
1830 { | |
1831 auto type = parseDeclarator(ident); | |
1832 require(T.Assign); | |
1833 return type; | |
1834 } | |
1835 bool success; | |
1836 auto type = try_(&parseDeclaratorAssign, success); | |
1837 if (success) | |
1838 { | |
1839 auto init = parseExpression(); | |
1840 auto v = new VariablesDeclaration(type, [ident], [init]); | |
1841 set(v, begin); | |
1842 variable = new DeclarationStatement(v); | |
1843 set(variable, begin); | |
1844 } | |
1845 else | |
1846 condition = parseExpression(); | |
1847 } | |
1848 require(T.RParen); | |
1849 ifBody = parseScopeStatement(); | |
1850 if (consumed(T.Else)) | |
1851 elseBody = parseScopeStatement(); | |
1852 return new IfStatement(variable, condition, ifBody, elseBody); | |
1853 } | |
1854 | |
1855 Statement parseWhileStatement() | |
1856 { | |
1857 skip(T.While); | |
1858 require(T.LParen); | |
1859 auto condition = parseExpression(); | |
1860 require(T.RParen); | |
1861 return new WhileStatement(condition, parseScopeStatement()); | |
1862 } | |
1863 | |
1864 Statement parseDoWhileStatement() | |
1865 { | |
1866 skip(T.Do); | |
1867 auto doBody = parseScopeStatement(); | |
1868 require(T.While); | |
1869 require(T.LParen); | |
1870 auto condition = parseExpression(); | |
1871 require(T.RParen); | |
1872 return new DoWhileStatement(condition, doBody); | |
1873 } | |
1874 | |
1875 Statement parseForStatement() | |
1876 { | |
1877 skip(T.For); | |
1878 | |
1879 Statement init, forBody; | |
1880 Expression condition, increment; | |
1881 | |
1882 require(T.LParen); | |
1883 if (!consumed(T.Semicolon)) | |
1884 init = parseNoScopeStatement(); | |
1885 if (token.kind != T.Semicolon) | |
1886 condition = parseExpression(); | |
1887 require(T.Semicolon); | |
1888 if (token.kind != T.RParen) | |
1889 increment = parseExpression(); | |
1890 require(T.RParen); | |
1891 forBody = parseScopeStatement(); | |
1892 return new ForStatement(init, condition, increment, forBody); | |
1893 } | |
1894 | |
1895 Statement parseForeachStatement() | |
1896 { | |
1897 assert(token.kind == T.Foreach || token.kind == T.Foreach_reverse); | |
1898 TOK tok = token.kind; | |
1899 nT(); | |
1900 | |
1901 auto params = new Parameters; | |
1902 Expression e; // Aggregate or LwrExpression | |
1903 | |
1904 require(T.LParen); | |
1905 auto paramsBegin = token; | |
1906 do | |
1907 { | |
1908 auto paramBegin = token; | |
1909 StorageClass stc; | |
1910 Type type; | |
1911 Identifier* ident; | |
1912 | |
1913 switch (token.kind) | |
1914 { | |
1915 case T.Ref, T.Inout: | |
1916 stc = StorageClass.Ref; | |
1917 nT(); | |
1918 // fall through | |
1919 case T.Identifier: | |
1920 auto next = peekNext(); | |
1921 if (next == T.Comma || next == T.Semicolon || next == T.RParen) | |
1922 { | |
1923 ident = requireIdentifier(MSG.ExpectedVariableName); | |
1924 break; | |
1925 } | |
1926 // fall through | |
1927 default: | |
1928 type = parseDeclarator(ident); | |
1929 } | |
1930 | |
1931 params ~= set(new Parameter(stc, type, ident, null), paramBegin); | |
1932 } while (consumed(T.Comma)) | |
1933 set(params, paramsBegin); | |
1934 require(T.Semicolon); | |
1935 e = parseExpression(); | |
1936 version(D2) | |
1937 { //Foreach (ForeachType; LwrExpression .. UprExpression ) ScopeStatement | |
1938 if (consumed(T.Slice)) | |
1939 { | |
1940 // if (params.length != 1) | |
1941 // error(MID.XYZ); // TODO: issue error msg | |
1942 auto upper = parseExpression(); | |
1943 require(T.RParen); | |
1944 auto forBody = parseScopeStatement(); | |
1945 return new ForeachRangeStatement(tok, params, e, upper, forBody); | |
1946 } | |
1947 } | |
1948 // Foreach (ForeachTypeList; Aggregate) ScopeStatement | |
1949 require(T.RParen); | |
1950 auto forBody = parseScopeStatement(); | |
1951 return new ForeachStatement(tok, params, e, forBody); | |
1952 } | |
1953 | |
1954 Statement parseSwitchStatement() | |
1955 { | |
1956 skip(T.Switch); | |
1957 require(T.LParen); | |
1958 auto condition = parseExpression(); | |
1959 require(T.RParen); | |
1960 auto switchBody = parseScopeStatement(); | |
1961 return new SwitchStatement(condition, switchBody); | |
1962 } | |
1963 | |
1964 /// Helper function for parsing the body of a default or case statement. | |
1965 Statement parseCaseOrDefaultBody() | |
1966 { | |
1967 // This function is similar to parseNoScopeStatement() | |
1968 auto begin = token; | |
1969 auto s = new CompoundStatement(); | |
1970 while (token.kind != T.Case && | |
1971 token.kind != T.Default && | |
1972 token.kind != T.RBrace && | |
1973 token.kind != T.EOF) | |
1974 s ~= parseStatement(); | |
1975 set(s, begin); | |
1976 return set(new ScopeStatement(s), begin); | |
1977 } | |
1978 | |
1979 Statement parseCaseStatement() | |
1980 { | |
1981 skip(T.Case); | |
1982 auto values = parseExpressionList(); | |
1983 require(T.Colon); | |
1984 auto caseBody = parseCaseOrDefaultBody(); | |
1985 return new CaseStatement(values, caseBody); | |
1986 } | |
1987 | |
1988 Statement parseDefaultStatement() | |
1989 { | |
1990 skip(T.Default); | |
1991 require(T.Colon); | |
1992 auto defaultBody = parseCaseOrDefaultBody(); | |
1993 return new DefaultStatement(defaultBody); | |
1994 } | |
1995 | |
1996 Statement parseContinueStatement() | |
1997 { | |
1998 skip(T.Continue); | |
1999 auto ident = optionalIdentifier(); | |
2000 require(T.Semicolon); | |
2001 return new ContinueStatement(ident); | |
2002 } | |
2003 | |
2004 Statement parseBreakStatement() | |
2005 { | |
2006 skip(T.Break); | |
2007 auto ident = optionalIdentifier(); | |
2008 require(T.Semicolon); | |
2009 return new BreakStatement(ident); | |
2010 } | |
2011 | |
2012 Statement parseReturnStatement() | |
2013 { | |
2014 skip(T.Return); | |
2015 Expression expr; | |
2016 if (token.kind != T.Semicolon) | |
2017 expr = parseExpression(); | |
2018 require(T.Semicolon); | |
2019 return new ReturnStatement(expr); | |
2020 } | |
2021 | |
2022 Statement parseGotoStatement() | |
2023 { | |
2024 skip(T.Goto); | |
2025 Identifier* ident; | |
2026 Expression caseExpr; | |
2027 switch (token.kind) | |
2028 { | |
2029 case T.Case: | |
2030 ident = token.ident; | |
2031 nT(); | |
2032 if (token.kind == T.Semicolon) | |
2033 break; | |
2034 caseExpr = parseExpression(); | |
2035 break; | |
2036 case T.Default: | |
2037 ident = token.ident; | |
2038 nT(); | |
2039 break; | |
2040 default: | |
2041 ident = requireIdentifier(MSG.ExpectedAnIdentifier); | |
2042 } | |
2043 require(T.Semicolon); | |
2044 return new GotoStatement(ident, caseExpr); | |
2045 } | |
2046 | |
2047 Statement parseWithStatement() | |
2048 { | |
2049 skip(T.With); | |
2050 require(T.LParen); | |
2051 auto expr = parseExpression(); | |
2052 require(T.RParen); | |
2053 return new WithStatement(expr, parseScopeStatement()); | |
2054 } | |
2055 | |
2056 Statement parseSynchronizedStatement() | |
2057 { | |
2058 skip(T.Synchronized); | |
2059 Expression expr; | |
2060 if (consumed(T.LParen)) | |
2061 { | |
2062 expr = parseExpression(); | |
2063 require(T.RParen); | |
2064 } | |
2065 return new SynchronizedStatement(expr, parseScopeStatement()); | |
2066 } | |
2067 | |
2068 Statement parseTryStatement() | |
2069 { | |
2070 auto begin = token; | |
2071 skip(T.Try); | |
2072 | |
2073 auto tryBody = parseScopeStatement(); | |
2074 CatchStatement[] catchBodies; | |
2075 FinallyStatement finBody; | |
2076 | |
2077 while (consumed(T.Catch)) | |
2078 { | |
2079 Parameter param; | |
2080 if (consumed(T.LParen)) | |
2081 { | |
2082 auto begin2 = token; | |
2083 Identifier* ident; | |
2084 auto type = parseDeclarator(ident, true); | |
2085 param = new Parameter(StorageClass.None, type, ident, null); | |
2086 set(param, begin2); | |
2087 require(T.RParen); | |
2088 } | |
2089 catchBodies ~= set(new CatchStatement(param, parseNoScopeStatement()), begin); | |
2090 if (param is null) | |
2091 break; // This is a LastCatch | |
2092 begin = token; | |
2093 } | |
2094 | |
2095 if (consumed(T.Finally)) | |
2096 finBody = set(new FinallyStatement(parseNoScopeStatement()), prevToken); | |
2097 | |
2098 if (catchBodies.length == 0 && finBody is null) | |
2099 assert(begin.kind == T.Try), error(begin, MSG.MissingCatchOrFinally); | |
2100 | |
2101 return new TryStatement(tryBody, catchBodies, finBody); | |
2102 } | |
2103 | |
2104 Statement parseThrowStatement() | |
2105 { | |
2106 skip(T.Throw); | |
2107 auto expr = parseExpression(); | |
2108 require(T.Semicolon); | |
2109 return new ThrowStatement(expr); | |
2110 } | |
2111 | |
2112 Statement parseScopeGuardStatement() | |
2113 { | |
2114 skip(T.Scope); | |
2115 skip(T.LParen); | |
2116 auto condition = requireIdentifier(MSG.ExpectedScopeIdentifier); | |
2117 if (condition) | |
2118 switch (condition.idKind) | |
2119 { | |
2120 case IDK.exit, IDK.success, IDK.failure: | |
2121 break; | |
2122 default: | |
2123 error(this.prevToken, MSG.InvalidScopeIdentifier, this.prevToken.srcText); | |
2124 } | |
2125 require(T.RParen); | |
2126 Statement scopeBody; | |
2127 if (token.kind == T.LBrace) | |
2128 scopeBody = parseScopeStatement(); | |
2129 else | |
2130 scopeBody = parseNoScopeStatement(); | |
2131 return new ScopeGuardStatement(condition, scopeBody); | |
2132 } | |
2133 | |
2134 Statement parseVolatileStatement() | |
2135 { | |
2136 skip(T.Volatile); | |
2137 Statement volatileBody; | |
2138 if (token.kind == T.Semicolon) | |
2139 nT(); | |
2140 else if (token.kind == T.LBrace) | |
2141 volatileBody = parseScopeStatement(); | |
2142 else | |
2143 volatileBody = parseStatement(); | |
2144 return new VolatileStatement(volatileBody); | |
2145 } | |
2146 | |
2147 Statement parsePragmaStatement() | |
2148 { | |
2149 skip(T.Pragma); | |
2150 | |
2151 Identifier* ident; | |
2152 Expression[] args; | |
2153 Statement pragmaBody; | |
2154 | |
2155 require(T.LParen); | |
2156 ident = requireIdentifier(MSG.ExpectedPragmaIdentifier); | |
2157 | |
2158 if (consumed(T.Comma)) | |
2159 args = parseExpressionList(); | |
2160 require(T.RParen); | |
2161 | |
2162 pragmaBody = parseNoScopeOrEmptyStatement(); | |
2163 | |
2164 return new PragmaStatement(ident, args, pragmaBody); | |
2165 } | |
2166 | |
2167 Statement parseStaticIfStatement() | |
2168 { | |
2169 skip(T.Static); | |
2170 skip(T.If); | |
2171 Expression condition; | |
2172 Statement ifBody, elseBody; | |
2173 | |
2174 require(T.LParen); | |
2175 condition = parseExpression(); | |
2176 require(T.RParen); | |
2177 ifBody = parseNoScopeStatement(); | |
2178 if (consumed(T.Else)) | |
2179 elseBody = parseNoScopeStatement(); | |
2180 return new StaticIfStatement(condition, ifBody, elseBody); | |
2181 } | |
2182 | |
2183 Statement parseStaticAssertStatement() | |
2184 { | |
2185 skip(T.Static); | |
2186 skip(T.Assert); | |
2187 Expression condition, message; | |
2188 | |
2189 require(T.LParen); | |
2190 condition = parseAssignExpression(); // Condition. | |
2191 if (consumed(T.Comma)) | |
2192 message = parseAssignExpression(); // Error message. | |
2193 require(T.RParen); | |
2194 require(T.Semicolon); | |
2195 return new StaticAssertStatement(condition, message); | |
2196 } | |
2197 | |
2198 Statement parseDebugStatement() | |
2199 { | |
2200 skip(T.Debug); | |
2201 Token* cond; | |
2202 Statement debugBody, elseBody; | |
2203 | |
2204 // ( Condition ) | |
2205 if (consumed(T.LParen)) | |
2206 { | |
2207 cond = parseIdentOrInt(); | |
2208 require(T.RParen); | |
2209 } | |
2210 // debug Statement | |
2211 // debug ( Condition ) Statement | |
2212 debugBody = parseNoScopeStatement(); | |
2213 // else Statement | |
2214 if (consumed(T.Else)) | |
2215 elseBody = parseNoScopeStatement(); | |
2216 | |
2217 return new DebugStatement(cond, debugBody, elseBody); | |
2218 } | |
2219 | |
2220 Statement parseVersionStatement() | |
2221 { | |
2222 skip(T.Version); | |
2223 Token* cond; | |
2224 Statement versionBody, elseBody; | |
2225 | |
2226 // ( Condition ) | |
2227 require(T.LParen); | |
2228 cond = parseIdentOrInt(); | |
2229 require(T.RParen); | |
2230 // version ( Condition ) Statement | |
2231 versionBody = parseNoScopeStatement(); | |
2232 // else Statement | |
2233 if (consumed(T.Else)) | |
2234 elseBody = parseNoScopeStatement(); | |
2235 | |
2236 return new VersionStatement(cond, versionBody, elseBody); | |
2237 } | |
2238 | |
2239 /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
2240 | Assembler parsing methods | | |
2241 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/ | |
2242 | |
2243 /// Parses an AsmBlockStatement. | |
2244 Statement parseAsmBlockStatement() | |
2245 { | |
2246 skip(T.Asm); | |
2247 require(T.LBrace); | |
2248 auto ss = new CompoundStatement; | |
2249 while (token.kind != T.RBrace && token.kind != T.EOF) | |
2250 ss ~= parseAsmStatement(); | |
2251 require(T.RBrace); | |
2252 return new AsmBlockStatement(ss); | |
2253 } | |
2254 | |
2255 Statement parseAsmStatement() | |
2256 { | |
2257 auto begin = token; | |
2258 Statement s; | |
2259 Identifier* ident; | |
2260 switch (token.kind) | |
2261 { | |
2262 // Keywords that are valid opcodes. | |
2263 case T.In, T.Int, T.Out: | |
2264 ident = token.ident; | |
2265 nT(); | |
2266 goto LOpcode; | |
2267 case T.Identifier: | |
2268 ident = token.ident; | |
2269 nT(); | |
2270 if (consumed(T.Colon)) | |
2271 { // Identifier : AsmStatement | |
2272 s = new LabeledStatement(ident, parseAsmStatement()); | |
2273 break; | |
2274 } | |
2275 | |
2276 LOpcode: | |
2277 // Opcode ; | |
2278 // Opcode Operands ; | |
2279 // Opcode | |
2280 // Identifier | |
2281 Expression[] es; | |
2282 if (token.kind != T.Semicolon) | |
2283 do | |
2284 es ~= parseAsmExpression(); | |
2285 while (consumed(T.Comma)) | |
2286 require(T.Semicolon); | |
2287 s = new AsmStatement(ident, es); | |
2288 break; | |
2289 case T.Align: | |
2290 // align Integer; | |
2291 nT(); | |
2292 int number = -1; | |
2293 if (token.kind == T.Int32) | |
2294 (number = token.int_), skip(T.Int32); | |
2295 else | |
2296 error(token, MSG.ExpectedIntegerAfterAlign, token.srcText); | |
2297 require(T.Semicolon); | |
2298 s = new AsmAlignStatement(number); | |
2299 break; | |
2300 case T.Semicolon: | |
2301 s = new EmptyStatement(); | |
2302 nT(); | |
2303 break; | |
2304 default: | |
2305 s = new IllegalAsmStatement(); | |
2306 // Skip to next valid token. | |
2307 do | |
2308 nT(); | |
2309 while (!token.isAsmStatementStart && | |
2310 token.kind != T.RBrace && | |
2311 token.kind != T.EOF) | |
2312 auto text = Token.textSpan(begin, this.prevToken); | |
2313 error(begin, MSG.IllegalAsmStatement, text); | |
2314 } | |
2315 set(s, begin); | |
2316 return s; | |
2317 } | |
2318 | |
2319 Expression parseAsmExpression() | |
2320 { | |
2321 auto begin = token; | |
2322 auto e = parseAsmOrOrExpression(); | |
2323 if (consumed(T.Question)) | |
2324 { | |
2325 auto tok = this.prevToken; | |
2326 auto iftrue = parseAsmExpression(); | |
2327 require(T.Colon); | |
2328 auto iffalse = parseAsmExpression(); | |
2329 e = new CondExpression(e, iftrue, iffalse, tok); | |
2330 set(e, begin); | |
2331 } | |
2332 // TODO: create AsmExpression that contains e? | |
2333 return e; | |
2334 } | |
2335 | |
2336 Expression parseAsmOrOrExpression() | |
2337 { | |
2338 alias parseAsmAndAndExpression parseNext; | |
2339 auto begin = token; | |
2340 auto e = parseNext(); | |
2341 while (token.kind == T.OrLogical) | |
2342 { | |
2343 auto tok = token; | |
2344 nT(); | |
2345 e = new OrOrExpression(e, parseNext(), tok); | |
2346 set(e, begin); | |
2347 } | |
2348 return e; | |
2349 } | |
2350 | |
2351 Expression parseAsmAndAndExpression() | |
2352 { | |
2353 alias parseAsmOrExpression parseNext; | |
2354 auto begin = token; | |
2355 auto e = parseNext(); | |
2356 while (token.kind == T.AndLogical) | |
2357 { | |
2358 auto tok = token; | |
2359 nT(); | |
2360 e = new AndAndExpression(e, parseNext(), tok); | |
2361 set(e, begin); | |
2362 } | |
2363 return e; | |
2364 } | |
2365 | |
2366 Expression parseAsmOrExpression() | |
2367 { | |
2368 alias parseAsmXorExpression parseNext; | |
2369 auto begin = token; | |
2370 auto e = parseNext(); | |
2371 while (token.kind == T.OrBinary) | |
2372 { | |
2373 auto tok = token; | |
2374 nT(); | |
2375 e = new OrExpression(e, parseNext(), tok); | |
2376 set(e, begin); | |
2377 } | |
2378 return e; | |
2379 } | |
2380 | |
2381 Expression parseAsmXorExpression() | |
2382 { | |
2383 alias parseAsmAndExpression parseNext; | |
2384 auto begin = token; | |
2385 auto e = parseNext(); | |
2386 while (token.kind == T.Xor) | |
2387 { | |
2388 auto tok = token; | |
2389 nT(); | |
2390 e = new XorExpression(e, parseNext(), tok); | |
2391 set(e, begin); | |
2392 } | |
2393 return e; | |
2394 } | |
2395 | |
2396 Expression parseAsmAndExpression() | |
2397 { | |
2398 alias parseAsmCmpExpression parseNext; | |
2399 auto begin = token; | |
2400 auto e = parseNext(); | |
2401 while (token.kind == T.AndBinary) | |
2402 { | |
2403 auto tok = token; | |
2404 nT(); | |
2405 e = new AndExpression(e, parseNext(), tok); | |
2406 set(e, begin); | |
2407 } | |
2408 return e; | |
2409 } | |
2410 | |
2411 Expression parseAsmCmpExpression() | |
2412 { | |
2413 alias parseAsmShiftExpression parseNext; | |
2414 auto begin = token; | |
2415 auto e = parseNext(); | |
2416 | |
2417 auto operator = token; | |
2418 switch (operator.kind) | |
2419 { | |
2420 case T.Equal, T.NotEqual: | |
2421 nT(); | |
2422 e = new EqualExpression(e, parseNext(), operator); | |
2423 break; | |
2424 case T.LessEqual, T.Less, T.GreaterEqual, T.Greater: | |
2425 nT(); | |
2426 e = new RelExpression(e, parseNext(), operator); | |
2427 break; | |
2428 default: | |
2429 return e; | |
2430 } | |
2431 set(e, begin); | |
2432 return e; | |
2433 } | |
2434 | |
2435 Expression parseAsmShiftExpression() | |
2436 { | |
2437 alias parseAsmAddExpression parseNext; | |
2438 auto begin = token; | |
2439 auto e = parseNext(); | |
2440 while (1) | |
2441 { | |
2442 auto operator = token; | |
2443 switch (operator.kind) | |
2444 { | |
2445 case T.LShift: nT(); e = new LShiftExpression(e, parseNext(), operator); break; | |
2446 case T.RShift: nT(); e = new RShiftExpression(e, parseNext(), operator); break; | |
2447 case T.URShift: nT(); e = new URShiftExpression(e, parseNext(), operator); break; | |
2448 default: | |
2449 return e; | |
2450 } | |
2451 set(e, begin); | |
2452 } | |
2453 assert(0); | |
2454 } | |
2455 | |
2456 Expression parseAsmAddExpression() | |
2457 { | |
2458 alias parseAsmMulExpression parseNext; | |
2459 auto begin = token; | |
2460 auto e = parseNext(); | |
2461 while (1) | |
2462 { | |
2463 auto operator = token; | |
2464 switch (operator.kind) | |
2465 { | |
2466 case T.Plus: nT(); e = new PlusExpression(e, parseNext(), operator); break; | |
2467 case T.Minus: nT(); e = new MinusExpression(e, parseNext(), operator); break; | |
2468 // Not allowed in asm | |
2469 //case T.Tilde: nT(); e = new CatExpression(e, parseNext(), operator); break; | |
2470 default: | |
2471 return e; | |
2472 } | |
2473 set(e, begin); | |
2474 } | |
2475 assert(0); | |
2476 } | |
2477 | |
2478 Expression parseAsmMulExpression() | |
2479 { | |
2480 alias parseAsmPostExpression parseNext; | |
2481 auto begin = token; | |
2482 auto e = parseNext(); | |
2483 while (1) | |
2484 { | |
2485 auto operator = token; | |
2486 switch (operator.kind) | |
2487 { | |
2488 case T.Mul: nT(); e = new MulExpression(e, parseNext(), operator); break; | |
2489 case T.Div: nT(); e = new DivExpression(e, parseNext(), operator); break; | |
2490 case T.Mod: nT(); e = new ModExpression(e, parseNext(), operator); break; | |
2491 default: | |
2492 return e; | |
2493 } | |
2494 set(e, begin); | |
2495 } | |
2496 assert(0); | |
2497 } | |
2498 | |
2499 Expression parseAsmPostExpression() | |
2500 { | |
2501 auto begin = token; | |
2502 auto e = parseAsmUnaryExpression(); | |
2503 while (consumed(T.LBracket)) | |
2504 { | |
2505 e = new AsmPostBracketExpression(e, parseAsmExpression()); | |
2506 require(T.RBracket); | |
2507 set(e, begin); | |
2508 } | |
2509 return e; | |
2510 } | |
2511 | |
2512 Expression parseAsmUnaryExpression() | |
2513 { | |
2514 auto begin = token; | |
2515 Expression e; | |
2516 switch (token.kind) | |
2517 { | |
2518 case T.Byte, T.Short, T.Int, | |
2519 T.Float, T.Double, T.Real: | |
2520 goto LAsmTypePrefix; | |
2521 case T.Identifier: | |
2522 switch (token.ident.idKind) | |
2523 { | |
2524 case IDK.near, IDK.far,/* "byte", "short", "int",*/ | |
2525 IDK.word, IDK.dword, IDK.qword/*, "float", "double", "real"*/: | |
2526 LAsmTypePrefix: | |
2527 nT(); | |
2528 if (token.kind == T.Identifier && token.ident is Ident.ptr) | |
2529 skip(T.Identifier); | |
2530 else | |
2531 error(MID.ExpectedButFound, "ptr", token.srcText); | |
2532 e = new AsmTypeExpression(parseAsmExpression()); | |
2533 break; | |
2534 case IDK.offset: | |
2535 nT(); | |
2536 e = new AsmOffsetExpression(parseAsmExpression()); | |
2537 break; | |
2538 case IDK.seg: | |
2539 nT(); | |
2540 e = new AsmSegExpression(parseAsmExpression()); | |
2541 break; | |
2542 default: | |
2543 goto LparseAsmPrimaryExpression; | |
2544 } | |
2545 break; | |
2546 case T.Minus: | |
2547 case T.Plus: | |
2548 nT(); | |
2549 e = new SignExpression(parseAsmUnaryExpression()); | |
2550 break; | |
2551 case T.Not: | |
2552 nT(); | |
2553 e = new NotExpression(parseAsmUnaryExpression()); | |
2554 break; | |
2555 case T.Tilde: | |
2556 nT(); | |
2557 e = new CompExpression(parseAsmUnaryExpression()); | |
2558 break; | |
2559 case T.Dot: | |
2560 nT(); | |
2561 e = new ModuleScopeExpression(parseIdentifierExpression()); | |
2562 while (consumed(TOK.Dot)) | |
2563 { | |
2564 e = new DotExpression(e, parseIdentifierExpression()); | |
2565 set(e, begin); | |
2566 } | |
2567 break; | |
2568 default: | |
2569 LparseAsmPrimaryExpression: | |
2570 e = parseAsmPrimaryExpression(); | |
2571 return e; | |
2572 } | |
2573 set(e, begin); | |
2574 return e; | |
2575 } | |
2576 | |
2577 Expression parseAsmPrimaryExpression() | |
2578 { | |
2579 auto begin = token; | |
2580 Expression e; | |
2581 switch (token.kind) | |
2582 { | |
2583 case T.Int32, T.Int64, T.Uint32, T.Uint64: | |
2584 e = new IntExpression(token); | |
2585 nT(); | |
2586 break; | |
2587 case T.Float32, T.Float64, T.Float80, | |
2588 T.Imaginary32, T.Imaginary64, T.Imaginary80: | |
2589 e = new RealExpression(token); | |
2590 nT(); | |
2591 break; | |
2592 case T.Dollar: | |
2593 e = new DollarExpression(); | |
2594 nT(); | |
2595 break; | |
2596 case T.LBracket: | |
2597 // [ AsmExpression ] | |
2598 nT(); | |
2599 e = parseAsmExpression(); | |
2600 require(T.RBracket); | |
2601 e = new AsmBracketExpression(e); | |
2602 break; | |
2603 case T.Identifier: | |
2604 auto register = token.ident; | |
2605 switch (register.idKind) | |
2606 { | |
2607 // __LOCAL_SIZE | |
2608 case IDK.__LOCAL_SIZE: | |
2609 nT(); | |
2610 e = new AsmLocalSizeExpression(); | |
2611 break; | |
2612 // Register | |
2613 case IDK.ST: | |
2614 nT(); | |
2615 // (1) - (7) | |
2616 int number = -1; | |
2617 if (consumed(T.LParen)) | |
2618 { | |
2619 if (token.kind == T.Int32) | |
2620 (number = token.int_), skip(T.Int32); | |
2621 else | |
2622 expected(T.Int32); | |
2623 require(T.RParen); | |
2624 } | |
2625 e = new AsmRegisterExpression(register, number); | |
2626 break; | |
2627 case IDK.FS: | |
2628 nT(); | |
2629 // TODO: is the colon-number part optional? | |
2630 int number = -1; | |
2631 if (consumed(T.Colon)) | |
2632 { | |
2633 // :0, :4, :8 | |
2634 if (token.kind == T.Int32) | |
2635 (number = token.int_), skip(T.Int32); | |
2636 if (number != 0 && number != 4 && number != 8) | |
2637 error(MID.ExpectedButFound, "0, 4 or 8", token.srcText); | |
2638 } | |
2639 e = new AsmRegisterExpression(register, number); | |
2640 break; | |
2641 case IDK.AL, IDK.AH, IDK.AX, IDK.EAX, | |
2642 IDK.BL, IDK.BH, IDK.BX, IDK.EBX, | |
2643 IDK.CL, IDK.CH, IDK.CX, IDK.ECX, | |
2644 IDK.DL, IDK.DH, IDK.DX, IDK.EDX, | |
2645 IDK.BP, IDK.EBP, IDK.SP, IDK.ESP, | |
2646 IDK.DI, IDK.EDI, IDK.SI, IDK.ESI, | |
2647 IDK.ES, IDK.CS, IDK.SS, IDK.DS, IDK.GS, | |
2648 IDK.CR0, IDK.CR2, IDK.CR3, IDK.CR4, | |
2649 IDK.DR0, IDK.DR1, IDK.DR2, IDK.DR3, IDK.DR6, IDK.DR7, | |
2650 IDK.TR3, IDK.TR4, IDK.TR5, IDK.TR6, IDK.TR7, | |
2651 IDK.MM0, IDK.MM1, IDK.MM2, IDK.MM3, | |
2652 IDK.MM4, IDK.MM5, IDK.MM6, IDK.MM7, | |
2653 IDK.XMM0, IDK.XMM1, IDK.XMM2, IDK.XMM3, | |
2654 IDK.XMM4, IDK.XMM5, IDK.XMM6, IDK.XMM7: | |
2655 nT(); | |
2656 e = new AsmRegisterExpression(register); | |
2657 break; | |
2658 default: | |
2659 e = parseIdentifierExpression(); | |
2660 while (consumed(TOK.Dot)) | |
2661 { | |
2662 e = new DotExpression(e, parseIdentifierExpression()); | |
2663 set(e, begin); | |
2664 } | |
2665 } // end of switch | |
2666 break; | |
2667 default: | |
2668 error(MID.ExpectedButFound, "Expression", token.srcText); | |
2669 e = new IllegalExpression(); | |
2670 if (!trying) | |
2671 { // Insert a dummy token and don't consume current one. | |
2672 begin = lexer.insertEmptyTokenBefore(token); | |
2673 this.prevToken = begin; | |
2674 } | |
2675 } | |
2676 set(e, begin); | |
2677 return e; | |
2678 } | |
2679 | |
2680 /+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
2681 | Expression parsing methods | | |
2682 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+/ | |
2683 | |
2684 /// Parses an Expression. | |
2685 Expression parseExpression() | |
2686 { | |
2687 alias parseAssignExpression parseNext; | |
2688 auto begin = token; | |
2689 auto e = parseNext(); | |
2690 while (token.kind == T.Comma) | |
2691 { | |
2692 auto comma = token; | |
2693 nT(); | |
2694 e = new CommaExpression(e, parseNext(), comma); | |
2695 set(e, begin); | |
2696 } | |
2697 return e; | |
2698 } | |
2699 | |
2700 Expression parseAssignExpression() | |
2701 { | |
2702 alias parseAssignExpression parseNext; | |
2703 auto begin = token; | |
2704 auto e = parseCondExpression(); | |
2705 switch (token.kind) | |
2706 { | |
2707 case T.Assign: | |
2708 nT(); e = new AssignExpression(e, parseNext()); break; | |
2709 case T.LShiftAssign: | |
2710 nT(); e = new LShiftAssignExpression(e, parseNext()); break; | |
2711 case T.RShiftAssign: | |
2712 nT(); e = new RShiftAssignExpression(e, parseNext()); break; | |
2713 case T.URShiftAssign: | |
2714 nT(); e = new URShiftAssignExpression(e, parseNext()); break; | |
2715 case T.OrAssign: | |
2716 nT(); e = new OrAssignExpression(e, parseNext()); break; | |
2717 case T.AndAssign: | |
2718 nT(); e = new AndAssignExpression(e, parseNext()); break; | |
2719 case T.PlusAssign: | |
2720 nT(); e = new PlusAssignExpression(e, parseNext()); break; | |
2721 case T.MinusAssign: | |
2722 nT(); e = new MinusAssignExpression(e, parseNext()); break; | |
2723 case T.DivAssign: | |
2724 nT(); e = new DivAssignExpression(e, parseNext()); break; | |
2725 case T.MulAssign: | |
2726 nT(); e = new MulAssignExpression(e, parseNext()); break; | |
2727 case T.ModAssign: | |
2728 nT(); e = new ModAssignExpression(e, parseNext()); break; | |
2729 case T.XorAssign: | |
2730 nT(); e = new XorAssignExpression(e, parseNext()); break; | |
2731 case T.CatAssign: | |
2732 nT(); e = new CatAssignExpression(e, parseNext()); break; | |
2733 default: | |
2734 return e; | |
2735 } | |
2736 set(e, begin); | |
2737 return e; | |
2738 } | |
2739 | |
2740 Expression parseCondExpression() | |
2741 { | |
2742 auto begin = token; | |
2743 auto e = parseOrOrExpression(); | |
2744 if (token.kind == T.Question) | |
2745 { | |
2746 auto tok = token; | |
2747 nT(); | |
2748 auto iftrue = parseExpression(); | |
2749 require(T.Colon); | |
2750 auto iffalse = parseCondExpression(); | |
2751 e = new CondExpression(e, iftrue, iffalse, tok); | |
2752 set(e, begin); | |
2753 } | |
2754 return e; | |
2755 } | |
2756 | |
2757 Expression parseOrOrExpression() | |
2758 { | |
2759 alias parseAndAndExpression parseNext; | |
2760 auto begin = token; | |
2761 auto e = parseNext(); | |
2762 while (token.kind == T.OrLogical) | |
2763 { | |
2764 auto tok = token; | |
2765 nT(); | |
2766 e = new OrOrExpression(e, parseNext(), tok); | |
2767 set(e, begin); | |
2768 } | |
2769 return e; | |
2770 } | |
2771 | |
2772 Expression parseAndAndExpression() | |
2773 { | |
2774 alias parseOrExpression parseNext; | |
2775 auto begin = token; | |
2776 auto e = parseNext(); | |
2777 while (token.kind == T.AndLogical) | |
2778 { | |
2779 auto tok = token; | |
2780 nT(); | |
2781 e = new AndAndExpression(e, parseNext(), tok); | |
2782 set(e, begin); | |
2783 } | |
2784 return e; | |
2785 } | |
2786 | |
2787 Expression parseOrExpression() | |
2788 { | |
2789 alias parseXorExpression parseNext; | |
2790 auto begin = token; | |
2791 auto e = parseNext(); | |
2792 while (token.kind == T.OrBinary) | |
2793 { | |
2794 auto tok = token; | |
2795 nT(); | |
2796 e = new OrExpression(e, parseNext(), tok); | |
2797 set(e, begin); | |
2798 } | |
2799 return e; | |
2800 } | |
2801 | |
2802 Expression parseXorExpression() | |
2803 { | |
2804 alias parseAndExpression parseNext; | |
2805 auto begin = token; | |
2806 auto e = parseNext(); | |
2807 while (token.kind == T.Xor) | |
2808 { | |
2809 auto tok = token; | |
2810 nT(); | |
2811 e = new XorExpression(e, parseNext(), tok); | |
2812 set(e, begin); | |
2813 } | |
2814 return e; | |
2815 } | |
2816 | |
2817 Expression parseAndExpression() | |
2818 { | |
2819 alias parseCmpExpression parseNext; | |
2820 auto begin = token; | |
2821 auto e = parseNext(); | |
2822 while (token.kind == T.AndBinary) | |
2823 { | |
2824 auto tok = token; | |
2825 nT(); | |
2826 e = new AndExpression(e, parseNext(), tok); | |
2827 set(e, begin); | |
2828 } | |
2829 return e; | |
2830 } | |
2831 | |
2832 Expression parseCmpExpression() | |
2833 { | |
2834 alias parseShiftExpression parseNext; | |
2835 auto begin = token; | |
2836 auto e = parseShiftExpression(); | |
2837 | |
2838 auto operator = token; | |
2839 switch (operator.kind) | |
2840 { | |
2841 case T.Equal, T.NotEqual: | |
2842 nT(); | |
2843 e = new EqualExpression(e, parseNext(), operator); | |
2844 break; | |
2845 case T.Not: | |
2846 if (peekNext() != T.Is) | |
2847 break; | |
2848 nT(); | |
2849 // fall through | |
2850 case T.Is: | |
2851 nT(); | |
2852 e = new IdentityExpression(e, parseNext(), operator); | |
2853 break; | |
2854 case T.LessEqual, T.Less, T.GreaterEqual, T.Greater, | |
2855 T.Unordered, T.UorE, T.UorG, T.UorGorE, | |
2856 T.UorL, T.UorLorE, T.LorEorG, T.LorG: | |
2857 nT(); | |
2858 e = new RelExpression(e, parseNext(), operator); | |
2859 break; | |
2860 case T.In: | |
2861 nT(); | |
2862 e = new InExpression(e, parseNext(), operator); | |
2863 break; | |
2864 default: | |
2865 return e; | |
2866 } | |
2867 set(e, begin); | |
2868 return e; | |
2869 } | |
2870 | |
2871 Expression parseShiftExpression() | |
2872 { | |
2873 alias parseAddExpression parseNext; | |
2874 auto begin = token; | |
2875 auto e = parseNext(); | |
2876 while (1) | |
2877 { | |
2878 auto operator = token; | |
2879 switch (operator.kind) | |
2880 { | |
2881 case T.LShift: nT(); e = new LShiftExpression(e, parseNext(), operator); break; | |
2882 case T.RShift: nT(); e = new RShiftExpression(e, parseNext(), operator); break; | |
2883 case T.URShift: nT(); e = new URShiftExpression(e, parseNext(), operator); break; | |
2884 default: | |
2885 return e; | |
2886 } | |
2887 set(e, begin); | |
2888 } | |
2889 assert(0); | |
2890 } | |
2891 | |
2892 Expression parseAddExpression() | |
2893 { | |
2894 alias parseMulExpression parseNext; | |
2895 auto begin = token; | |
2896 auto e = parseNext(); | |
2897 while (1) | |
2898 { | |
2899 auto operator = token; | |
2900 switch (operator.kind) | |
2901 { | |
2902 case T.Plus: nT(); e = new PlusExpression(e, parseNext(), operator); break; | |
2903 case T.Minus: nT(); e = new MinusExpression(e, parseNext(), operator); break; | |
2904 case T.Tilde: nT(); e = new CatExpression(e, parseNext(), operator); break; | |
2905 default: | |
2906 return e; | |
2907 } | |
2908 set(e, begin); | |
2909 } | |
2910 assert(0); | |
2911 } | |
2912 | |
2913 Expression parseMulExpression() | |
2914 { | |
2915 alias parsePostExpression parseNext; | |
2916 auto begin = token; | |
2917 auto e = parseNext(); | |
2918 while (1) | |
2919 { | |
2920 auto operator = token; | |
2921 switch (operator.kind) | |
2922 { | |
2923 case T.Mul: nT(); e = new MulExpression(e, parseNext(), operator); break; | |
2924 case T.Div: nT(); e = new DivExpression(e, parseNext(), operator); break; | |
2925 case T.Mod: nT(); e = new ModExpression(e, parseNext(), operator); break; | |
2926 default: | |
2927 return e; | |
2928 } | |
2929 set(e, begin); | |
2930 } | |
2931 assert(0); | |
2932 } | |
2933 | |
2934 Expression parsePostExpression() | |
2935 { | |
2936 auto begin = token; | |
2937 auto e = parseUnaryExpression(); | |
2938 while (1) | |
2939 { | |
2940 while (consumed(T.Dot)) | |
2941 { | |
2942 e = new DotExpression(e, parseNewOrIdentifierExpression()); | |
2943 set(e, begin); | |
2944 } | |
2945 | |
2946 switch (token.kind) | |
2947 { | |
2948 case T.PlusPlus: | |
2949 e = new PostIncrExpression(e); | |
2950 break; | |
2951 case T.MinusMinus: | |
2952 e = new PostDecrExpression(e); | |
2953 break; | |
2954 case T.LParen: | |
2955 e = new CallExpression(e, parseArguments()); | |
2956 goto Lset; | |
2957 case T.LBracket: | |
2958 // parse Slice- and IndexExpression | |
2959 nT(); | |
2960 // [] is a SliceExpression | |
2961 if (token.kind == T.RBracket) | |
2962 { | |
2963 e = new SliceExpression(e, null, null); | |
2964 break; | |
2965 } | |
2966 | |
2967 Expression[] es = [parseAssignExpression()]; | |
2968 | |
2969 // [ AssignExpression .. AssignExpression ] | |
2970 if (consumed(T.Slice)) | |
2971 { | |
2972 e = new SliceExpression(e, es[0], parseAssignExpression()); | |
2973 require(T.RBracket); | |
2974 goto Lset; | |
2975 } | |
2976 | |
2977 // [ ExpressionList ] | |
2978 if (consumed(T.Comma)) | |
2979 es ~= parseExpressionList(); | |
2980 require(T.RBracket); | |
2981 | |
2982 e = new IndexExpression(e, es); | |
2983 goto Lset; | |
2984 default: | |
2985 return e; | |
2986 } | |
2987 nT(); | |
2988 Lset: // Jumped here to skip nT(). | |
2989 set(e, begin); | |
2990 } | |
2991 assert(0); | |
2992 } | |
2993 | |
2994 Expression parseUnaryExpression() | |
2995 { | |
2996 auto begin = token; | |
2997 Expression e; | |
2998 switch (token.kind) | |
2999 { | |
3000 case T.AndBinary: | |
3001 nT(); | |
3002 e = new AddressExpression(parseUnaryExpression()); | |
3003 break; | |
3004 case T.PlusPlus: | |
3005 nT(); | |
3006 e = new PreIncrExpression(parseUnaryExpression()); | |
3007 break; | |
3008 case T.MinusMinus: | |
3009 nT(); | |
3010 e = new PreDecrExpression(parseUnaryExpression()); | |
3011 break; | |
3012 case T.Mul: | |
3013 nT(); | |
3014 e = new DerefExpression(parseUnaryExpression()); | |
3015 break; | |
3016 case T.Minus: | |
3017 case T.Plus: | |
3018 nT(); | |
3019 e = new SignExpression(parseUnaryExpression()); | |
3020 break; | |
3021 case T.Not: | |
3022 nT(); | |
3023 e = new NotExpression(parseUnaryExpression()); | |
3024 break; | |
3025 case T.Tilde: | |
3026 nT(); | |
3027 e = new CompExpression(parseUnaryExpression()); | |
3028 break; | |
3029 case T.New: | |
3030 e = parseNewExpression(); | |
3031 return e; | |
3032 case T.Delete: | |
3033 nT(); | |
3034 e = new DeleteExpression(parseUnaryExpression()); | |
3035 break; | |
3036 case T.Cast: | |
3037 requireNext(T.LParen); | |
3038 Type type; | |
3039 switch (token.kind) | |
3040 { | |
3041 version(D2) | |
3042 { | |
3043 auto begin2 = token; | |
3044 case T.Const: | |
3045 type = new ConstType(null); | |
3046 goto case_break; | |
3047 case T.Invariant: | |
3048 type = new InvariantType(null); | |
3049 case_break: | |
3050 nT(); | |
3051 set(type, begin2); | |
3052 break; | |
3053 } | |
3054 default: | |
3055 type = parseType(); | |
3056 } | |
3057 require(T.RParen); | |
3058 e = new CastExpression(parseUnaryExpression(), type); | |
3059 break; | |
3060 case T.LParen: | |
3061 // ( Type ) . Identifier | |
3062 Type parseType_() | |
3063 { | |
3064 skip(T.LParen); | |
3065 auto type = parseType(); | |
3066 require(T.RParen); | |
3067 require(T.Dot); | |
3068 return type; | |
3069 } | |
3070 bool success; | |
3071 auto type = try_(&parseType_, success); | |
3072 if (success) | |
3073 { | |
3074 auto ident = requireIdentifier(MSG.ExpectedIdAfterTypeDot); | |
3075 e = new TypeDotIdExpression(type, ident); | |
3076 break; | |
3077 } | |
3078 goto default; | |
3079 case T.Dot: | |
3080 nT(); | |
3081 e = new ModuleScopeExpression(parseIdentifierExpression()); | |
3082 break; | |
3083 default: | |
3084 e = parsePrimaryExpression(); | |
3085 return e; | |
3086 } | |
3087 assert(e !is null); | |
3088 set(e, begin); | |
3089 return e; | |
3090 } | |
3091 | |
3092 /// $(PRE | |
3093 /// IdentifierExpression := | |
3094 /// Identifier | |
3095 /// TemplateInstance | |
3096 /// TemplateInstance := | |
3097 /// Identifier !( TemplateArguments ) | |
3098 /// ) | |
3099 Expression parseIdentifierExpression() | |
3100 { | |
3101 auto begin = token; | |
3102 auto ident = requireIdentifier(MSG.ExpectedAnIdentifier); | |
3103 Expression e; | |
3104 // Peek for '(' to avoid matching: id !is id | |
3105 if (token.kind == T.Not && peekNext() == T.LParen) | |
3106 { // Identifier !( TemplateArguments ) | |
3107 skip(T.Not); | |
3108 auto tparams = parseTemplateArguments(); | |
3109 e = new TemplateInstanceExpression(ident, tparams); | |
3110 } | |
3111 else // Identifier | |
3112 e = new IdentifierExpression(ident); | |
3113 return set(e, begin); | |
3114 } | |
3115 | |
3116 Expression parseNewOrIdentifierExpression() | |
3117 { | |
3118 return token.kind == T.New ? parseNewExpression() : parseIdentifierExpression(); | |
3119 } | |
3120 | |
3121 Expression parsePrimaryExpression() | |
3122 { | |
3123 auto begin = token; | |
3124 Expression e; | |
3125 switch (token.kind) | |
3126 { | |
3127 case T.Identifier: | |
3128 e = parseIdentifierExpression(); | |
3129 return e; | |
3130 case T.Typeof: | |
3131 e = new TypeofExpression(parseTypeofType()); | |
3132 break; | |
3133 case T.This: | |
3134 nT(); | |
3135 e = new ThisExpression(); | |
3136 break; | |
3137 case T.Super: | |
3138 nT(); | |
3139 e = new SuperExpression(); | |
3140 break; | |
3141 case T.Null: | |
3142 nT(); | |
3143 e = new NullExpression(); | |
3144 break; | |
3145 case T.True, T.False: | |
3146 nT(); | |
3147 e = new BoolExpression(); | |
3148 break; | |
3149 case T.Dollar: | |
3150 nT(); | |
3151 e = new DollarExpression(); | |
3152 break; | |
3153 case T.Int32, T.Int64, T.Uint32, T.Uint64: | |
3154 e = new IntExpression(token); | |
3155 nT(); | |
3156 break; | |
3157 case T.Float32, T.Float64, T.Float80, | |
3158 T.Imaginary32, T.Imaginary64, T.Imaginary80: | |
3159 e = new RealExpression(token); | |
3160 nT(); | |
3161 break; | |
3162 case T.CharLiteral: | |
3163 e = new CharExpression(token.dchar_); | |
3164 nT(); | |
3165 break; | |
3166 case T.String: | |
3167 char[] str = token.str; | |
3168 char postfix = token.pf; | |
3169 nT(); | |
3170 while (token.kind == T.String) | |
3171 { | |
3172 /+if (postfix == 0) | |
3173 postfix = token.pf; | |
3174 else+/ | |
3175 if (token.pf && token.pf != postfix) | |
3176 error(token, MSG.StringPostfixMismatch); | |
3177 str.length = str.length - 1; // Exclude '\0'. | |
3178 str ~= token.str; | |
3179 nT(); | |
3180 } | |
3181 switch (postfix) | |
3182 { | |
3183 case 'w': | |
3184 if (checkString(begin, str)) | |
3185 goto default; | |
3186 e = new StringExpression(dil.Unicode.toUTF16(str)); break; | |
3187 case 'd': | |
3188 if (checkString(begin, str)) | |
3189 goto default; | |
3190 e = new StringExpression(dil.Unicode.toUTF32(str)); break; | |
3191 case 'c': | |
3192 default: | |
3193 // No checking done to allow for binary data. | |
3194 e = new StringExpression(str); break; | |
3195 } | |
3196 break; | |
3197 case T.LBracket: | |
3198 Expression[] values; | |
3199 | |
3200 nT(); | |
3201 if (!consumed(T.RBracket)) | |
3202 { | |
3203 e = parseAssignExpression(); | |
3204 if (consumed(T.Colon)) | |
3205 goto LparseAssocArray; | |
3206 if (consumed(T.Comma)) | |
3207 values = [e] ~ parseExpressionList(); | |
3208 require(T.RBracket); | |
3209 } | |
3210 | |
3211 e = new ArrayLiteralExpression(values); | |
3212 break; | |
3213 | |
3214 LparseAssocArray: | |
3215 Expression[] keys = [e]; | |
3216 | |
3217 goto LenterLoop; | |
3218 do | |
3219 { | |
3220 keys ~= parseAssignExpression(); | |
3221 require(T.Colon); | |
3222 LenterLoop: | |
3223 values ~= parseAssignExpression(); | |
3224 } while (consumed(T.Comma)) | |
3225 require(T.RBracket); | |
3226 e = new AArrayLiteralExpression(keys, values); | |
3227 break; | |
3228 case T.LBrace: | |
3229 // DelegateLiteral := { Statements } | |
3230 auto funcBody = parseFunctionBody(); | |
3231 e = new FunctionLiteralExpression(funcBody); | |
3232 break; | |
3233 case T.Function, T.Delegate: | |
3234 // FunctionLiteral := ("function"|"delegate") Type? "(" ArgumentList ")" FunctionBody | |
3235 nT(); // Skip function or delegate keyword. | |
3236 Type returnType; | |
3237 Parameters parameters; | |
3238 if (token.kind != T.LBrace) | |
3239 { | |
3240 if (token.kind != T.LParen) // Optional return type | |
3241 returnType = parseType(); | |
3242 parameters = parseParameterList(); | |
3243 } | |
3244 auto funcBody = parseFunctionBody(); | |
3245 e = new FunctionLiteralExpression(returnType, parameters, funcBody); | |
3246 break; | |
3247 case T.Assert: | |
3248 Expression msg; | |
3249 requireNext(T.LParen); | |
3250 e = parseAssignExpression(); | |
3251 if (consumed(T.Comma)) | |
3252 msg = parseAssignExpression(); | |
3253 require(T.RParen); | |
3254 e = new AssertExpression(e, msg); | |
3255 break; | |
3256 case T.Mixin: | |
3257 requireNext(T.LParen); | |
3258 e = parseAssignExpression(); | |
3259 require(T.RParen); | |
3260 e = new MixinExpression(e); | |
3261 break; | |
3262 case T.Import: | |
3263 requireNext(T.LParen); | |
3264 e = parseAssignExpression(); | |
3265 require(T.RParen); | |
3266 e = new ImportExpression(e); | |
3267 break; | |
3268 case T.Typeid: | |
3269 requireNext(T.LParen); | |
3270 auto type = parseType(); | |
3271 require(T.RParen); | |
3272 e = new TypeidExpression(type); | |
3273 break; | |
3274 case T.Is: | |
3275 requireNext(T.LParen); | |
3276 | |
3277 Type type, specType; | |
3278 Identifier* ident; // optional Identifier | |
3279 Token* opTok, specTok; | |
3280 | |
3281 type = parseDeclarator(ident, true); | |
3282 | |
3283 switch (token.kind) | |
3284 { | |
3285 case T.Colon, T.Equal: | |
3286 opTok = token; | |
3287 nT(); | |
3288 switch (token.kind) | |
3289 { | |
3290 case T.Typedef, | |
3291 T.Struct, | |
3292 T.Union, | |
3293 T.Class, | |
3294 T.Interface, | |
3295 T.Enum, | |
3296 T.Function, | |
3297 T.Delegate, | |
3298 T.Super, | |
3299 T.Return: | |
3300 case_Const_Invariant: | |
3301 specTok = token; | |
3302 nT(); | |
3303 break; | |
3304 case T.Const, T.Invariant: | |
3305 if (peekNext() != T.LParen) | |
3306 goto case_Const_Invariant; | |
3307 // Fall through. It's a type. | |
3308 default: | |
3309 specType = parseType(); | |
3310 } | |
3311 default: | |
3312 } | |
3313 | |
3314 TemplateParameters tparams; | |
3315 version(D2) | |
3316 { | |
3317 // is ( Type Identifier : TypeSpecialization , TemplateParameterList ) | |
3318 // is ( Type Identifier == TypeSpecialization , TemplateParameterList ) | |
3319 if (ident && specType && token.kind == T.Comma) | |
3320 tparams = parseTemplateParameterList2(); | |
3321 } | |
3322 require(T.RParen); | |
3323 e = new IsExpression(type, ident, opTok, specTok, specType, tparams); | |
3324 break; | |
3325 case T.LParen: | |
3326 if (tokenAfterParenIs(T.LBrace)) // Check for "(...) {" | |
3327 { // ( ParameterList ) FunctionBody | |
3328 auto parameters = parseParameterList(); | |
3329 auto funcBody = parseFunctionBody(); | |
3330 e = new FunctionLiteralExpression(null, parameters, funcBody); | |
3331 } | |
3332 else | |
3333 { // ( Expression ) | |
3334 skip(T.LParen); | |
3335 e = parseExpression(); | |
3336 require(T.RParen); | |
3337 e = new ParenExpression(e); | |
3338 } | |
3339 break; | |
3340 version(D2) | |
3341 { | |
3342 case T.Traits: | |
3343 requireNext(T.LParen); | |
3344 auto id = requireIdentifier(MSG.ExpectedAnIdentifier); | |
3345 TemplateArguments args; | |
3346 if (token.kind == T.Comma) | |
3347 args = parseTemplateArguments2(); | |
3348 else | |
3349 require(T.RParen); | |
3350 e = new TraitsExpression(id, args); | |
3351 break; | |
3352 } | |
3353 default: | |
3354 if (token.isIntegralType) | |
3355 { // IntegralType . Identifier | |
3356 auto type = new IntegralType(token.kind); | |
3357 nT(); | |
3358 set(type, begin); | |
3359 require(T.Dot); | |
3360 auto ident = requireIdentifier(MSG.ExpectedIdAfterTypeDot); | |
3361 e = new TypeDotIdExpression(type, ident); | |
3362 } | |
3363 else if (token.isSpecialToken) | |
3364 { | |
3365 e = new SpecialTokenExpression(token); | |
3366 nT(); | |
3367 } | |
3368 else | |
3369 { | |
3370 error(MID.ExpectedButFound, "Expression", token.srcText); | |
3371 e = new IllegalExpression(); | |
3372 if (!trying) | |
3373 { // Insert a dummy token and don't consume current one. | |
3374 begin = lexer.insertEmptyTokenBefore(token); | |
3375 this.prevToken = begin; | |
3376 } | |
3377 } | |
3378 } | |
3379 set(e, begin); | |
3380 return e; | |
3381 } | |
3382 | |
3383 Expression parseNewExpression(/*Expression e*/) | |
3384 { | |
3385 auto begin = token; | |
3386 skip(T.New); | |
3387 | |
3388 Expression[] newArguments; | |
3389 Expression[] ctorArguments; | |
3390 | |
3391 if (token.kind == T.LParen) | |
3392 newArguments = parseArguments(); | |
3393 | |
3394 // NewAnonClassExpression: | |
3395 // new (ArgumentList)opt class (ArgumentList)opt SuperClassopt InterfaceClassesopt ClassBody | |
3396 if (consumed(T.Class)) | |
3397 { | |
3398 if (token.kind == T.LParen) | |
3399 ctorArguments = parseArguments(); | |
3400 | |
3401 BaseClassType[] bases = token.kind != T.LBrace ? parseBaseClasses(false) : null ; | |
3402 | |
3403 auto decls = parseDeclarationDefinitionsBody(); | |
3404 return set(new NewAnonClassExpression(/*e, */newArguments, bases, ctorArguments, decls), begin); | |
3405 } | |
3406 | |
3407 // NewExpression: | |
3408 // NewArguments Type [ AssignExpression ] | |
3409 // NewArguments Type ( ArgumentList ) | |
3410 // NewArguments Type | |
3411 auto type = parseType(); | |
3412 | |
3413 if (token.kind == T.LParen) | |
3414 ctorArguments = parseArguments(); | |
3415 | |
3416 return set(new NewExpression(/*e, */newArguments, type, ctorArguments), begin); | |
3417 } | |
3418 | |
3419 /// Parses a Type. | |
3420 Type parseType() | |
3421 { | |
3422 return parseBasicType2(parseBasicType()); | |
3423 } | |
3424 | |
3425 Type parseIdentifierType() | |
3426 { | |
3427 auto begin = token; | |
3428 auto ident = requireIdentifier(MSG.ExpectedAnIdentifier); | |
3429 Type t; | |
3430 if (consumed(T.Not)) // Identifier !( TemplateArguments ) | |
3431 t = new TemplateInstanceType(ident, parseTemplateArguments()); | |
3432 else // Identifier | |
3433 t = new IdentifierType(ident); | |
3434 return set(t, begin); | |
3435 } | |
3436 | |
3437 Type parseQualifiedType() | |
3438 { | |
3439 auto begin = token; | |
3440 Type type; | |
3441 if (token.kind == T.Dot) | |
3442 type = set(new ModuleScopeType(), begin, begin); | |
3443 else if (token.kind == T.Typeof) | |
3444 type = parseTypeofType(); | |
3445 else | |
3446 type = parseIdentifierType(); | |
3447 | |
3448 while (consumed(T.Dot)) | |
3449 type = set(new QualifiedType(type, parseIdentifierType()), begin); | |
3450 return type; | |
3451 } | |
3452 | |
3453 Type parseBasicType() | |
3454 { | |
3455 auto begin = token; | |
3456 Type t; | |
3457 | |
3458 if (token.isIntegralType) | |
3459 { | |
3460 t = new IntegralType(token.kind); | |
3461 nT(); | |
3462 } | |
3463 else | |
3464 switch (token.kind) | |
3465 { | |
3466 case T.Identifier, T.Typeof, T.Dot: | |
3467 t = parseQualifiedType(); | |
3468 return t; | |
3469 version(D2) | |
3470 { | |
3471 case T.Const: | |
3472 // const ( Type ) | |
3473 requireNext(T.LParen); | |
3474 t = parseType(); | |
3475 require(T.RParen); | |
3476 t = new ConstType(t); | |
3477 break; | |
3478 case T.Invariant: | |
3479 // invariant ( Type ) | |
3480 requireNext(T.LParen); | |
3481 t = parseType(); | |
3482 require(T.RParen); | |
3483 t = new InvariantType(t); | |
3484 break; | |
3485 } // version(D2) | |
3486 default: | |
3487 error(MID.ExpectedButFound, "BasicType", token.srcText); | |
3488 t = new IllegalType(); | |
3489 nT(); | |
3490 } | |
3491 return set(t, begin); | |
3492 } | |
3493 | |
3494 Type parseBasicType2(Type t) | |
3495 { | |
3496 while (1) | |
3497 { | |
3498 auto begin = token; | |
3499 switch (token.kind) | |
3500 { | |
3501 case T.Mul: | |
3502 t = new PointerType(t); | |
3503 nT(); | |
3504 break; | |
3505 case T.LBracket: | |
3506 t = parseArrayType(t); | |
3507 continue; | |
3508 case T.Function, T.Delegate: | |
3509 TOK tok = token.kind; | |
3510 nT(); | |
3511 auto parameters = parseParameterList(); | |
3512 if (tok == T.Function) | |
3513 t = new FunctionType(t, parameters); | |
3514 else | |
3515 t = new DelegateType(t, parameters); | |
3516 break; | |
3517 default: | |
3518 return t; | |
3519 } | |
3520 set(t, begin); | |
3521 } | |
3522 assert(0); | |
3523 } | |
3524 | |
3525 /// Returns true if the token after the closing parenthesis | |
3526 /// is of kind tok. | |
3527 bool tokenAfterParenIs(TOK tok) | |
3528 { | |
3529 // We count nested parentheses tokens because template types | |
3530 // may appear inside parameter lists. E.g.: (int x, Foo!(int) y) | |
3531 assert(token.kind == T.LParen); | |
3532 Token* next = token; | |
3533 uint level = 1; | |
3534 Loop: | |
3535 while (1) | |
3536 { | |
3537 lexer.peek(next); | |
3538 switch (next.kind) | |
3539 { | |
3540 case T.RParen: | |
3541 if (--level == 0) | |
3542 { // Last, closing parentheses found. | |
3543 do | |
3544 lexer.peek(next); | |
3545 while (next.isWhitespace) | |
3546 break Loop; | |
3547 } | |
3548 break; | |
3549 case T.LParen: | |
3550 ++level; | |
3551 break; | |
3552 case T.EOF: | |
3553 break Loop; | |
3554 default: | |
3555 } | |
3556 } | |
3557 return next.kind == tok; | |
3558 } | |
3559 | |
3560 /// Parse the array types after the declarator (C-style.) E.g.: int a[] | |
3561 Type parseDeclaratorSuffix(Type lhsType) | |
3562 { | |
3563 // The Type chain should be as follows: | |
3564 // int[3]* Identifier [][32] | |
3565 // <- <- -> -. | |
3566 // ^-----------------´ | |
3567 // Resulting chain: [][32]*[3]int | |
3568 Type parseNext() // Nested function required to accomplish this. | |
3569 { | |
3570 if (token.kind != T.LBracket) | |
3571 return lhsType; // Break recursion; return Type on the left hand side of the Identifier. | |
3572 | |
3573 auto begin = token; | |
3574 Type t; | |
3575 skip(T.LBracket); | |
3576 if (consumed(T.RBracket)) | |
3577 t = new ArrayType(parseNext()); // [ ] | |
3578 else | |
3579 { | |
3580 bool success; | |
3581 Type parseAAType() | |
3582 { | |
3583 auto type = parseType(); | |
3584 require(T.RBracket); | |
3585 return type; | |
3586 } | |
3587 auto assocType = try_(&parseAAType, success); | |
3588 if (success) | |
3589 t = new ArrayType(parseNext(), assocType); // [ Type ] | |
3590 else | |
3591 { | |
3592 Expression e = parseExpression(), e2; | |
3593 if (consumed(T.Slice)) | |
3594 e2 = parseExpression(); | |
3595 require(T.RBracket); | |
3596 t = new ArrayType(parseNext(), e, e2); // [ Expression .. Expression ] | |
3597 } | |
3598 } | |
3599 set(t, begin); | |
3600 return t; | |
3601 } | |
3602 return parseNext(); | |
3603 } | |
3604 | |
3605 Type parseArrayType(Type t) | |
3606 { | |
3607 auto begin = token; | |
3608 skip(T.LBracket); | |
3609 if (consumed(T.RBracket)) | |
3610 t = new ArrayType(t); | |
3611 else | |
3612 { | |
3613 bool success; | |
3614 Type parseAAType() | |
3615 { | |
3616 auto type = parseType(); | |
3617 require(T.RBracket); | |
3618 return type; | |
3619 } | |
3620 auto assocType = try_(&parseAAType, success); | |
3621 if (success) | |
3622 t = new ArrayType(t, assocType); | |
3623 else | |
3624 { | |
3625 Expression e = parseExpression(), e2; | |
3626 if (consumed(T.Slice)) | |
3627 e2 = parseExpression(); | |
3628 require(T.RBracket); | |
3629 t = new ArrayType(t, e, e2); | |
3630 } | |
3631 } | |
3632 set(t, begin); | |
3633 return t; | |
3634 } | |
3635 | |
3636 Type parseCFunctionPointerType(Type type, ref Identifier* ident, bool optionalParamList) | |
3637 { | |
3638 assert(type !is null); | |
3639 auto begin = token; | |
3640 skip(T.LParen); | |
3641 | |
3642 type = parseBasicType2(type); | |
3643 if (token.kind == T.LParen) | |
3644 { // Can be nested. | |
3645 type = parseCFunctionPointerType(type, ident, true); | |
3646 } | |
3647 else if (token.kind == T.Identifier) | |
3648 { // The identifier of the function pointer and the declaration. | |
3649 ident = token.ident; | |
3650 nT(); | |
3651 type = parseDeclaratorSuffix(type); | |
3652 } | |
3653 require(T.RParen); | |
3654 | |
3655 Parameters params; | |
3656 if (optionalParamList) | |
3657 params = token.kind == T.LParen ? parseParameterList() : null; | |
3658 else | |
3659 params = parseParameterList(); | |
3660 | |
3661 type = new CFuncPointerType(type, params); | |
3662 return set(type, begin); | |
3663 } | |
3664 | |
3665 Type parseDeclarator(ref Identifier* ident, bool identOptional = false) | |
3666 { | |
3667 auto t = parseType(); | |
3668 | |
3669 if (token.kind == T.LParen) | |
3670 t = parseCFunctionPointerType(t, ident, true); | |
3671 else if (token.kind == T.Identifier) | |
3672 { | |
3673 ident = token.ident; | |
3674 nT(); | |
3675 t = parseDeclaratorSuffix(t); | |
3676 } | |
3677 | |
3678 if (ident is null && !identOptional) | |
3679 error(token, MSG.ExpectedDeclaratorIdentifier, token.srcText); | |
3680 | |
3681 return t; | |
3682 } | |
3683 | |
3684 /// Parses a list of AssignExpressions. | |
3685 /// $(PRE | |
3686 /// ExpressionList := | |
3687 /// AssignExpression | |
3688 /// AssignExpression , ExpressionList | |
3689 /// ) | |
3690 Expression[] parseExpressionList() | |
3691 { | |
3692 Expression[] expressions; | |
3693 do | |
3694 expressions ~= parseAssignExpression(); | |
3695 while(consumed(T.Comma)) | |
3696 return expressions; | |
3697 } | |
3698 | |
3699 /// Parses a list of Arguments. | |
3700 /// $(PRE | |
3701 /// Arguments := | |
3702 /// ( ) | |
3703 /// ( ExpressionList ) | |
3704 /// ) | |
3705 Expression[] parseArguments() | |
3706 { | |
3707 skip(T.LParen); | |
3708 Expression[] args; | |
3709 if (token.kind != T.RParen) | |
3710 args = parseExpressionList(); | |
3711 require(T.RParen); | |
3712 return args; | |
3713 } | |
3714 | |
3715 /// Parses a ParameterList. | |
3716 Parameters parseParameterList() | |
3717 out(params) | |
3718 { | |
3719 if (params.length > 1) | |
3720 foreach (param; params.items[0..$-1]) | |
3721 { | |
3722 if (param.isVariadic()) | |
3723 assert(0, "variadic arguments can only appear at the end of the parameter list."); | |
3724 } | |
3725 } | |
3726 body | |
3727 { | |
3728 auto begin = token; | |
3729 require(T.LParen); | |
3730 | |
3731 auto params = new Parameters(); | |
3732 | |
3733 if (consumed(T.RParen)) | |
3734 return set(params, begin); | |
3735 | |
3736 do | |
3737 { | |
3738 auto paramBegin = token; | |
3739 StorageClass stc, stc_; | |
3740 Type type; | |
3741 Identifier* ident; | |
3742 Expression defValue; | |
3743 | |
3744 void pushParameter() | |
3745 { | |
3746 params ~= set(new Parameter(stc, type, ident, defValue), paramBegin); | |
3747 } | |
3748 | |
3749 if (consumed(T.Ellipses)) | |
3750 { | |
3751 stc = StorageClass.Variadic; | |
3752 pushParameter(); // type, ident and defValue will be null. | |
3753 break; | |
3754 } | |
3755 | |
3756 while (1) | |
3757 { // Parse storage classes. | |
3758 switch (token.kind) | |
3759 { | |
3760 version(D2) | |
3761 { | |
3762 case T.Invariant: // D2.0 | |
3763 if (peekNext() == T.LParen) | |
3764 break; | |
3765 stc_ = StorageClass.Invariant; | |
3766 goto Lcommon; | |
3767 case T.Const: // D2.0 | |
3768 if (peekNext() == T.LParen) | |
3769 break; | |
3770 stc_ = StorageClass.Const; | |
3771 goto Lcommon; | |
3772 case T.Final: // D2.0 | |
3773 stc_ = StorageClass.Final; | |
3774 goto Lcommon; | |
3775 case T.Scope: // D2.0 | |
3776 stc_ = StorageClass.Scope; | |
3777 goto Lcommon; | |
3778 case T.Static: // D2.0 | |
3779 stc_ = StorageClass.Static; | |
3780 goto Lcommon; | |
3781 } | |
3782 case T.In: | |
3783 stc_ = StorageClass.In; | |
3784 goto Lcommon; | |
3785 case T.Out: | |
3786 stc_ = StorageClass.Out; | |
3787 goto Lcommon; | |
3788 case T.Inout, T.Ref: | |
3789 stc_ = StorageClass.Ref; | |
3790 goto Lcommon; | |
3791 case T.Lazy: | |
3792 stc_ = StorageClass.Lazy; | |
3793 goto Lcommon; | |
3794 Lcommon: | |
3795 // Check for redundancy. | |
3796 if (stc & stc_) | |
3797 error(MID.RedundantStorageClass, token.srcText); | |
3798 else | |
3799 stc |= stc_; | |
3800 nT(); | |
3801 version(D2) | |
3802 continue; | |
3803 else | |
3804 break; // In D1.0 the grammar only allows one storage class. | |
3805 default: | |
3806 } | |
3807 break; // Break out of inner loop. | |
3808 } | |
3809 type = parseDeclarator(ident, true); | |
3810 | |
3811 if (consumed(T.Assign)) | |
3812 defValue = parseAssignExpression(); | |
3813 | |
3814 if (consumed(T.Ellipses)) | |
3815 { | |
3816 stc |= StorageClass.Variadic; | |
3817 pushParameter(); | |
3818 break; | |
3819 } | |
3820 pushParameter(); | |
3821 | |
3822 } while (consumed(T.Comma)) | |
3823 require(T.RParen); | |
3824 return set(params, begin); | |
3825 } | |
3826 | |
3827 TemplateArguments parseTemplateArguments() | |
3828 { | |
3829 TemplateArguments targs; | |
3830 require(T.LParen); | |
3831 if (token.kind != T.RParen) | |
3832 targs = parseTemplateArguments_(); | |
3833 require(T.RParen); | |
3834 return targs; | |
3835 } | |
3836 | |
3837 version(D2) | |
3838 { | |
3839 TemplateArguments parseTemplateArguments2() | |
3840 { | |
3841 skip(T.Comma); | |
3842 TemplateArguments targs; | |
3843 if (token.kind != T.RParen) | |
3844 targs = parseTemplateArguments_(); | |
3845 else | |
3846 error(token, MSG.ExpectedTypeOrExpression); | |
3847 require(T.RParen); | |
3848 return targs; | |
3849 } | |
3850 } // version(D2) | |
3851 | |
3852 TemplateArguments parseTemplateArguments_() | |
3853 { | |
3854 auto begin = token; | |
3855 auto targs = new TemplateArguments; | |
3856 do | |
3857 { | |
3858 Type parseType_() | |
3859 { | |
3860 auto type = parseType(); | |
3861 if (token.kind == T.Comma || token.kind == T.RParen) | |
3862 return type; | |
3863 errorCount++; // Cause try_() to fail. | |
3864 return null; | |
3865 } | |
3866 bool success; | |
3867 auto typeArgument = try_(&parseType_, success); | |
3868 if (success) | |
3869 // TemplateArgument: | |
3870 // Type | |
3871 // Symbol | |
3872 targs ~= typeArgument; | |
3873 else | |
3874 // TemplateArgument: | |
3875 // AssignExpression | |
3876 targs ~= parseAssignExpression(); | |
3877 } while (consumed(T.Comma)) | |
3878 set(targs, begin); | |
3879 return targs; | |
3880 } | |
3881 | |
3882 TemplateParameters parseTemplateParameterList() | |
3883 { | |
3884 auto begin = token; | |
3885 auto tparams = new TemplateParameters; | |
3886 require(T.LParen); | |
3887 if (token.kind != T.RParen) | |
3888 parseTemplateParameterList_(tparams); | |
3889 require(T.RParen); | |
3890 return set(tparams, begin); | |
3891 } | |
3892 | |
3893 version(D2) | |
3894 { | |
3895 TemplateParameters parseTemplateParameterList2() | |
3896 { | |
3897 skip(T.Comma); | |
3898 auto begin = token; | |
3899 auto tparams = new TemplateParameters; | |
3900 if (token.kind != T.RParen) | |
3901 parseTemplateParameterList_(tparams); | |
3902 else | |
3903 error(token, MSG.ExpectedTemplateParameters); | |
3904 return set(tparams, begin); | |
3905 } | |
3906 } // version(D2) | |
3907 | |
3908 /// Parses template parameters. | |
3909 void parseTemplateParameterList_(TemplateParameters tparams) | |
3910 { | |
3911 do | |
3912 { | |
3913 auto paramBegin = token; | |
3914 TemplateParameter tp; | |
3915 Identifier* ident; | |
3916 Type specType, defType; | |
3917 | |
3918 void parseSpecAndOrDefaultType() | |
3919 { | |
3920 // : SpecializationType | |
3921 if (consumed(T.Colon)) | |
3922 specType = parseType(); | |
3923 // = DefaultType | |
3924 if (consumed(T.Assign)) | |
3925 defType = parseType(); | |
3926 } | |
3927 | |
3928 switch (token.kind) | |
3929 { | |
3930 case T.Alias: | |
3931 // TemplateAliasParameter: | |
3932 // alias Identifier | |
3933 skip(T.Alias); | |
3934 ident = requireIdentifier(MSG.ExpectedAliasTemplateParam); | |
3935 parseSpecAndOrDefaultType(); | |
3936 tp = new TemplateAliasParameter(ident, specType, defType); | |
3937 break; | |
3938 case T.Identifier: | |
3939 ident = token.ident; | |
3940 switch (peekNext()) | |
3941 { | |
3942 case T.Ellipses: | |
3943 // TemplateTupleParameter: | |
3944 // Identifier ... | |
3945 skip(T.Identifier); skip(T.Ellipses); | |
3946 if (token.kind == T.Comma) | |
3947 error(MID.TemplateTupleParameter); | |
3948 tp = new TemplateTupleParameter(ident); | |
3949 break; | |
3950 case T.Comma, T.RParen, T.Colon, T.Assign: | |
3951 // TemplateTypeParameter: | |
3952 // Identifier | |
3953 skip(T.Identifier); | |
3954 parseSpecAndOrDefaultType(); | |
3955 tp = new TemplateTypeParameter(ident, specType, defType); | |
3956 break; | |
3957 default: | |
3958 // TemplateValueParameter: | |
3959 // Declarator | |
3960 ident = null; | |
3961 goto LTemplateValueParameter; | |
3962 } | |
3963 break; | |
3964 version(D2) | |
3965 { | |
3966 case T.This: | |
3967 // TemplateThisParameter | |
3968 // this TemplateTypeParameter | |
3969 skip(T.This); | |
3970 ident = requireIdentifier(MSG.ExpectedNameForThisTempParam); | |
3971 parseSpecAndOrDefaultType(); | |
3972 tp = new TemplateThisParameter(ident, specType, defType); | |
3973 break; | |
3974 } | |
3975 default: | |
3976 LTemplateValueParameter: | |
3977 // TemplateValueParameter: | |
3978 // Declarator | |
3979 Expression specValue, defValue; | |
3980 auto valueType = parseDeclarator(ident); | |
3981 // : SpecializationValue | |
3982 if (consumed(T.Colon)) | |
3983 specValue = parseCondExpression(); | |
3984 // = DefaultValue | |
3985 if (consumed(T.Assign)) | |
3986 defValue = parseCondExpression(); | |
3987 tp = new TemplateValueParameter(valueType, ident, specValue, defValue); | |
3988 } | |
3989 | |
3990 // Push template parameter. | |
3991 tparams ~= set(tp, paramBegin); | |
3992 | |
3993 } while (consumed(T.Comma)) | |
3994 } | |
3995 | |
3996 alias require expected; | |
3997 | |
3998 /// Requires a token of kind tok. | |
3999 void require(TOK tok) | |
4000 { | |
4001 if (token.kind == tok) | |
4002 nT(); | |
4003 else | |
4004 error(MID.ExpectedButFound, Token.toString(tok), token.srcText); | |
4005 } | |
4006 | |
4007 /// Requires the next token to be of kind tok. | |
4008 void requireNext(TOK tok) | |
4009 { | |
4010 nT(); | |
4011 require(tok); | |
4012 } | |
4013 | |
4014 /// Optionally parses an identifier. | |
4015 /// Returns: null or the identifier. | |
4016 Identifier* optionalIdentifier() | |
4017 { | |
4018 Identifier* id; | |
4019 if (token.kind == T.Identifier) | |
4020 (id = token.ident), skip(T.Identifier); | |
4021 return id; | |
4022 } | |
4023 | |
4024 Identifier* requireIdentifier() | |
4025 { | |
4026 Identifier* id; | |
4027 if (token.kind == T.Identifier) | |
4028 (id = token.ident), skip(T.Identifier); | |
4029 else | |
4030 error(MID.ExpectedButFound, "Identifier", token.srcText); | |
4031 return id; | |
4032 } | |
4033 | |
4034 /// Reports an error if the current token is not an identifier. | |
4035 /// Params: | |
4036 /// errorMsg = the error message to be used. | |
4037 /// Returns: null or the identifier. | |
4038 Identifier* requireIdentifier(char[] errorMsg) | |
4039 { | |
4040 Identifier* id; | |
4041 if (token.kind == T.Identifier) | |
4042 (id = token.ident), skip(T.Identifier); | |
4043 else | |
4044 error(token, errorMsg, token.srcText); | |
4045 return id; | |
4046 } | |
4047 | |
4048 /// Reports an error if the current token is not an identifier. | |
4049 /// Params: | |
4050 /// mid = the error message ID to be used. | |
4051 /// Returns: null or the identifier. | |
4052 Identifier* requireIdentifier(MID mid) | |
4053 { | |
4054 Identifier* id; | |
4055 if (token.kind == T.Identifier) | |
4056 (id = token.ident), skip(T.Identifier); | |
4057 else | |
4058 error(mid, token.srcText); | |
4059 return id; | |
4060 } | |
4061 | |
4062 /// Reports an error if the current token is not an identifier. | |
4063 /// Returns: null or the token. | |
4064 Token* requireId() | |
4065 { | |
4066 Token* idtok; | |
4067 if (token.kind == T.Identifier) | |
4068 (idtok = token), skip(T.Identifier); | |
4069 else | |
4070 error(MID.ExpectedButFound, "Identifier", token.srcText); | |
4071 return idtok; | |
4072 } | |
4073 | |
4074 Token* requireIdToken(char[] errorMsg) | |
4075 { | |
4076 Token* idtok; | |
4077 if (token.kind == T.Identifier) | |
4078 (idtok = token), skip(T.Identifier); | |
4079 else | |
4080 { | |
4081 error(token, errorMsg, token.srcText); | |
4082 idtok = lexer.insertEmptyTokenBefore(token); | |
4083 this.prevToken = idtok; | |
4084 } | |
4085 return idtok; | |
4086 } | |
4087 | |
4088 /// Returns true if the string str has an invalid UTF-8 sequence. | |
4089 bool checkString(Token* begin, string str) | |
4090 { | |
4091 auto utf8Seq = Lexer.findInvalidUTF8Sequence(str); | |
4092 if (utf8Seq.length) | |
4093 error(begin, MSG.InvalidUTF8SequenceInString, utf8Seq); | |
4094 return utf8Seq.length != 0; | |
4095 } | |
4096 | |
4097 /// Forwards error parameters. | |
4098 void error(Token* token, char[] formatMsg, ...) | |
4099 { | |
4100 error_(token, formatMsg, _arguments, _argptr); | |
4101 } | |
4102 | |
4103 /// ditto | |
4104 void error(MID mid, ...) | |
4105 { | |
4106 error_(this.token, GetMsg(mid), _arguments, _argptr); | |
4107 } | |
4108 | |
4109 /// Creates an error report and appends it to a list. | |
4110 /// Params: | |
4111 /// token = used to get the location of where the error is. | |
4112 /// formatMsg = the compiler error message. | |
4113 void error_(Token* token, char[] formatMsg, TypeInfo[] _arguments, Arg _argptr) | |
4114 { | |
4115 if (trying) | |
4116 { | |
4117 ++errorCount; | |
4118 return; | |
4119 } | |
4120 auto location = token.getErrorLocation(); | |
4121 auto msg = Format(_arguments, _argptr, formatMsg); | |
4122 auto error = new ParserError(location, msg); | |
4123 errors ~= error; | |
4124 if (infoMan !is null) | |
4125 infoMan ~= error; | |
4126 } | |
4127 } |