1 // This file is part of Visual D
2 //
3 // Visual D integrates the D programming language into Visual Studio
4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt
8 
9 module vdc.parser.aggr;
10 
11 import vdc.util;
12 import vdc.lexer;
13 import vdc.parser.engine;
14 import vdc.parser.mod;
15 import vdc.parser.tmpl;
16 import vdc.parser.decl;
17 import vdc.parser.misc;
18 import vdc.parser.stmt;
19 
20 import ast = vdc.ast.all;
21 
22 import stdext.util;
23 
24 //-- GRAMMAR_BEGIN --
25 //AggregateDeclaration:
26 //    struct Identifier StructBody
27 //    union Identifier StructBody
28 //    struct Identifier ;
29 //    union Identifier ;
30 //    StructTemplateDeclaration
31 //    UnionTemplateDeclaration
32 //    ClassDeclaration
33 //    InterfaceDeclaration
34 //
35 //StructTemplateDeclaration:
36 //    struct Identifier ( TemplateParameterList ) Constraint_opt StructBody
37 //
38 //UnionTemplateDeclaration:
39 //    union Identifier ( TemplateParameterList ) Constraint_opt StructBody
40 //
41 //ClassDeclaration:
42 //    class Identifier BaseClassList_opt ClassBody
43 //    ClassTemplateDeclaration
44 //
45 //BaseClassList:
46 //    : SuperClass
47 //    : SuperClass , InterfaceClasses
48 //    : InterfaceClass
49 //
50 //SuperClass:
51 //    GlobalIdentifierList
52 //    Protection GlobalIdentifierList
53 //
54 //InterfaceClasses:
55 //    InterfaceClass
56 //    InterfaceClass , InterfaceClasses
57 //
58 //InterfaceClass:
59 //    GlobalIdentifierList
60 //    Protection GlobalIdentifierList
61 //
62 //InterfaceDeclaration:
63 //    interface Identifier BaseInterfaceList_opt InterfaceBody
64 //    InterfaceTemplateDeclaration
65 //
66 //BaseInterfaceList:
67 //    : InterfaceClasses
68 //
69 //StructBody:
70 //    { DeclDefs_opt }
71 //
72 //ClassBody:
73 //    { DeclDefs_opt }
74 //
75 //InterfaceBody:
76 //    { DeclDefs_opt }
77 //
78 //Protection:
79 //    private
80 //    package
81 //    public
82 //    export
83 class AggregateDeclaration
84 {
85     static Action enter(Parser p)
86     {
87         switch(p.tok.id)
88         {
89             case TOK_union:
90                 p.pushState(&shiftUnion);
91                 return Accept;
92             case TOK_struct:
93                 p.pushState(&shiftStruct);
94                 return Accept;
95             case TOK_class:
96                 p.pushState(&shiftClass);
97                 return Accept;
98             case TOK_interface:
99                 p.pushState(&shiftInterface);
100                 return Accept;
101             default:
102                 return p.parseError("class, struct or union expected");
103         }
104     }
105 
106     static Action shiftStruct(Parser p)
107     {
108         switch(p.tok.id)
109         {
110             case TOK_Identifier:
111                 p.pushNode(new ast.Struct(p.tok));
112                 p.pushState(&shiftIdentifier);
113                 return Accept;
114 
115             case TOK_lcurly:
116             case TOK_lparen:
117                 p.pushNode(new ast.Struct(p.tok.span));
118                 return shiftIdentifier(p);
119 
120             default:
121                 return p.parseError("struct identifier expected");
122         }
123     }
124 
125     static Action shiftUnion(Parser p)
126     {
127         switch(p.tok.id)
128         {
129             case TOK_Identifier:
130                 p.pushNode(new ast.Union(p.tok));
131                 p.pushState(&shiftIdentifier);
132                 return Accept;
133 
134             case TOK_lcurly:
135             case TOK_lparen:
136                 p.pushNode(new ast.Union(p.tok.span));
137                 return shiftIdentifier(p);
138 
139             default:
140                 return p.parseError("union identifier expected");
141         }
142     }
143 
144     static Action shiftClass(Parser p)
145     {
146         switch(p.tok.id)
147         {
148             case TOK_Identifier:
149                 p.pushNode(new ast.Class(p.tok));
150                 p.pushState(&shiftIdentifier);
151                 return Accept;
152             default:
153                 return p.parseError("class identifier expected");
154         }
155     }
156 
157     static Action shiftInterface(Parser p)
158     {
159         switch(p.tok.id)
160         {
161             case TOK_Identifier:
162                 p.pushNode(new ast.Intrface(p.tok));
163                 p.pushState(&shiftIdentifier);
164                 return Accept;
165             default:
166                 return p.parseError("interface identifier expected");
167         }
168     }
169 
170     static Action shiftIdentifier(Parser p)
171     {
172         switch(p.tok.id)
173         {
174             case TOK_semicolon:
175                 p.topNode!(ast.Aggregate).hasBody = false;
176                 return Accept;
177             case TOK_lcurly:
178                 return shiftLcurly(p);
179             case TOK_lparen:
180                 p.pushState(&shiftLparen);
181                 return Accept;
182 
183             case TOK_colon:
184                 if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode())
185                     return p.parseError("only classes and interfaces support inheritance");
186                 p.pushState(&shiftColon);
187                 return Accept;
188 
189             default:
190                 return p.parseError("';', '(' or '{' expected after struct or union identifier");
191         }
192     }
193 
194     // NewArguments ClassArguments $ BaseClassList_opt ClassBody
195     static Action enterAnonymousClass(Parser p)
196     {
197         p.pushNode(new ast.AnonymousClass(p.tok));
198         switch(p.tok.id)
199         {
200             case TOK_lparen:
201                 p.pushState(&shiftLparen);
202                 return Accept;
203             case TOK_lcurly:
204                 return shiftLcurly(p);
205             default:
206                 return shiftColon(p);
207         }
208     }
209 
210     static Action shiftColon(Parser p)
211     {
212         switch(p.tok.id)
213         {
214             case TOK_dot:
215             case TOK_Identifier:
216                 p.pushNode(new ast.BaseClass(TOK_public, p.tok.span));
217                 p.pushState(&shiftBaseClass);
218                 return GlobalIdentifierList.enter(p);
219             case TOK_private:
220             case TOK_package:
221             case TOK_public:
222             case TOK_export:
223                 p.pushToken(p.tok);
224                 p.pushState(&shiftProtection);
225                 return Accept;
226             default:
227                 return p.parseError("identifier or protection attribute expected");
228         }
229     }
230 
231     static Action shiftProtection(Parser p)
232     {
233         Token tok = p.popToken();
234         switch(p.tok.id)
235         {
236             case TOK_dot:
237             case TOK_Identifier:
238                 p.pushNode(new ast.BaseClass(tok.id, tok.span));
239                 p.pushState(&shiftBaseClass);
240                 return GlobalIdentifierList.enter(p);
241             default:
242                 return p.parseError("identifier expected after protection attribute");
243         }
244     }
245 
246     static Action shiftBaseClass(Parser p)
247     {
248         p.popAppendTopNode();
249         auto bc = p.popNode!(ast.BaseClass)();
250         p.topNode!(ast.InheritingAggregate).addBaseClass(bc);
251         switch(p.tok.id)
252         {
253             case TOK_comma:
254                 p.pushState(&shiftColon);
255                 return Accept;
256             case TOK_lcurly:
257                 return shiftLcurly(p);
258             default:
259                 return p.parseError("'{' expected after base class list");
260         }
261     }
262 
263     static Action shiftLparen(Parser p)
264     {
265         p.pushState(&shiftTemplateParameterList);
266         return TemplateParameterList.enter(p);
267     }
268 
269     static Action shiftTemplateParameterList(Parser p)
270     {
271         switch(p.tok.id)
272         {
273             case TOK_rparen:
274                 p.popAppendTopNode!(ast.Aggregate)();
275                 p.topNode!(ast.Aggregate).hasTemplArgs = true;
276                 p.pushState(&shiftRparen);
277                 return Accept;
278             default:
279                 return p.parseError("')' expected after template parameter list");
280         }
281     }
282 
283     static Action shiftRparen(Parser p)
284     {
285         switch(p.tok.id)
286         {
287             case TOK_semicolon:
288                 p.topNode!(ast.Aggregate).hasBody = false;
289                 return Accept;
290             case TOK_colon:
291                 if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode())
292                     return p.parseError("only classes and interfaces support inheritance");
293                 p.pushState(&shiftColon);
294                 return Accept;
295             case TOK_if:
296                 p.pushState(&shiftConstraint);
297                 return Constraint.enter(p);
298             case TOK_lcurly:
299                 return shiftLcurly(p);
300             default:
301                 return p.parseError("'{' expected after template parameter list");
302         }
303     }
304 
305     static Action shiftConstraint(Parser p)
306     {
307         p.popAppendTopNode!(ast.Aggregate)();
308         p.topNode!(ast.Aggregate).hasConstraint = true;
309         switch(p.tok.id)
310         {
311             case TOK_semicolon:
312                 p.topNode!(ast.Aggregate).hasBody = false;
313                 return Accept;
314             case TOK_lcurly:
315                 return shiftLcurly(p);
316             case TOK_colon:
317                 if(!cast(ast.Class) p.topNode() && !cast(ast.Intrface) p.topNode())
318                     return p.parseError("only classes and interfaces support inheritance");
319                 p.pushState(&shiftColon);
320                 return Accept;
321             default:
322                 return p.parseError("'{' expected after constraint");
323         }
324     }
325 
326     static Action shiftLcurly(Parser p)
327     {
328         assert(p.tok.id == TOK_lcurly);
329 
330         p.pushNode(new ast.StructBody(p.tok));
331         p.pushState(&shiftDeclDefs);
332         p.pushState(&DeclDefs.enter);
333         return Accept;
334     }
335 
336     static Action shiftDeclDefs(Parser p)
337     {
338         switch(p.tok.id)
339         {
340             case TOK_rcurly:
341                 p.popAppendTopNode!(ast.Aggregate)();
342                 return Accept;
343             default:
344                 return p.parseError("closing curly brace expected to terminate aggregate body");
345         }
346     }
347 }
348 
349 //-- GRAMMAR_BEGIN --
350 //Constructor:
351 //    this TemplateParameters_opt Parameters MemberFunctionAttributes_opt Constraint_opt FunctionBody
352 //    this ( this ) Constraint_opt FunctionBody
353 class Constructor
354 {
355     mixin stateAppendClass!(FunctionBody, Parser.forward) stateFunctionBody;
356     //////////////////////////////////////////////////////////////
357 
358     mixin stateAppendClass!(Constraint, stateFunctionBody.shift) stateConstraint;
359 
360     static Action stateMemberFunctionAttributes(Parser p)
361     {
362         switch(p.tok.id)
363         {
364             mixin(case_TOKs_MemberFunctionAttribute);
365                 {
366                     auto ctor = p.topNode!(ast.Constructor);
367                     auto list = static_cast!(ast.ParameterList)(ctor.members[$-1]);
368                     if(auto attr = tokenToAttribute(p.tok.id))
369                         p.combineAttributes(list.attr, attr);
370                     if(auto annot = tokenToAnnotation(p.tok.id))
371                         p.combineAnnotations(list.annotation, annot);
372 
373                     p.pushState(&stateMemberFunctionAttributes);
374                     return Accept;
375                 }
376             case TOK_if:
377                 return stateConstraint.shift(p);
378             default:
379                 return stateFunctionBody.shift(p);
380         }
381     }
382 
383     mixin stateAppendClass!(Parameters, stateMemberFunctionAttributes) stateParametersTemplate;
384 
385     mixin stateAppendClass!(TemplateParameters, stateParametersTemplate.shift) stateTemplateParameterList;
386 
387     //////////////////////////////////////////////////////////////
388     static Action shiftRparen(Parser p)
389     {
390         switch(p.tok.id)
391         {
392             case TOK_lparen:
393                 return Reject; // retry with template arguments
394             default:
395                 p.popRollback();
396                 return stateMemberFunctionAttributes(p);
397         }
398     }
399 
400     static Action shiftParameters(Parser p)
401     {
402         p.popAppendTopNode!(ast.Constructor)();
403         switch(p.tok.id)
404         {
405             case TOK_rparen:
406                 p.pushState(&shiftRparen);
407                 return Accept;
408             default:
409                 return p.parseError("')' expected");
410         }
411     }
412 
413     static Action gotoParameters(Parser p)
414     {
415         switch(p.tok.id)
416         {
417             case TOK_rparen:
418                 p.topNode!(ast.Constructor)().addMember(new ast.ParameterList(p.tok));
419                 p.pushState(&shiftRparen);
420                 return Accept;
421             default:
422                 p.pushState(&shiftParameters);
423                 return ParameterList.enter(p);
424         }
425     }
426 
427     mixin stateShiftToken!(TOK_rparen, stateFunctionBody.shift) stateThis;
428 
429     static Action gotoThis(Parser p)
430     {
431         p.popRollback();
432         return stateThis.shift(p);
433     }
434 
435     mixin stateShiftToken!(TOK_this, gotoThis,
436                            -1, gotoParameters) stateParameters;
437 
438     static Action rollbackParameters(Parser p)
439     {
440         p.topNode!(ast.Constructor)().reinit();
441 
442         assert(p.tok.id == TOK_lparen);
443         return stateTemplateParameterList.shift(p);
444     }
445 
446     static Action stateLparen(Parser p)
447     {
448         switch(p.tok.id)
449         {
450             case TOK_lparen:
451                 p.pushRollback(&rollbackParameters);
452                 p.pushState(&stateParameters.shift);
453                 return Accept;
454             default:
455                 return p.parseError("'(' expected in constructor");
456         }
457     }
458 
459     mixin stateEnterToken!(TOK_this, ast.Constructor, stateLparen);
460 }
461 
462 //-- GRAMMAR_BEGIN --
463 //Destructor:
464 //    ~ this ( ) FunctionBody
465 class Destructor
466 {
467     mixin SequenceNode!(ast.Destructor, TOK_tilde, TOK_this, TOK_lparen, TOK_rparen, FunctionBody);
468 }
469 
470 //-- GRAMMAR_BEGIN --
471 //StaticConstructor:
472 //    static this ( ) FunctionBody
473 //
474 //StaticDestructor:
475 //    static ~ this ( ) FunctionBody
476 //
477 //SharedStaticConstructor:
478 //    shared static this ( ) FunctionBody
479 //
480 //SharedStaticDestructor:
481 //    shared static ~ this ( ) FunctionBody
482 //
483 //
484 //StructAllocator:
485 //    ClassAllocator
486 //
487 //StructDeallocator:
488 //    ClassDeallocator
489 //
490 //StructConstructor:
491 //    this ( ParameterList ) FunctionBody
492 //
493 //StructPostblit:
494 //    this ( this ) FunctionBody
495 //
496 //StructDestructor:
497 //    ~ this ( ) FunctionBody
498 //
499 //
500 //Invariant:
501 //    invariant ( ) BlockStatement
502 class Invariant
503 {
504     mixin SequenceNode!(ast.Unittest, TOK_invariant, TOK_lparen, TOK_rparen, BlockStatement);
505 }
506 
507 //-- GRAMMAR_BEGIN --
508 //ClassAllocator:
509 //    new Parameters FunctionBody
510 class ClassAllocator
511 {
512     mixin SequenceNode!(ast.ClassAllocator, TOK_new, Parameters, FunctionBody);
513 }
514 
515 //-- GRAMMAR_BEGIN --
516 //ClassDeallocator:
517 //    delete Parameters FunctionBody
518 class ClassDeallocator
519 {
520     mixin SequenceNode!(ast.ClassDeallocator, TOK_delete, Parameters, FunctionBody);
521 }