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.tmpl;
10 
11 import vdc.util;
12 import vdc.lexer;
13 import vdc.parser.engine;
14 import vdc.parser.decl;
15 import vdc.parser.expr;
16 import vdc.parser.mod;
17 import ast = vdc.ast.all;
18 
19 //-- GRAMMAR_BEGIN --
20 //TemplateDeclaration:
21 //    template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs }
22 class TemplateDeclaration
23 {
24     mixin SequenceNode!(ast.TemplateDeclaration, TOK_template, Identifier, TOK_lparen,
25                         TemplateParameterList, TOK_rparen, Opt!(Constraint, TOK_if), DeclDefsBlock);
26 }
27 
28 class DeclDefsBlock
29 {
30     mixin SequenceNode!(ast.DeclarationBlock, TOK_lcurly, DeclDefs, TOK_rcurly);
31 }
32 
33 //-- GRAMMAR_BEGIN --
34 //TemplateIdentifier:
35 //    Identifier
36 //
37 //TemplateParameters:
38 //    ( TemplateParameterList )
39 class TemplateParameters
40 {
41     mixin SequenceNode!(NoASTNode, TOK_lparen, TemplateParameterList, TOK_rparen);
42 }
43 
44 //-- GRAMMAR_BEGIN --
45 //TemplateParameterList:
46 //    TemplateParameter
47 //    TemplateParameter ,
48 //    TemplateParameter , TemplateParameterList
49 class TemplateParameterList
50 {
51     mixin ListNode!(ast.TemplateParameterList, TemplateParameter, TOK_comma, true, true);
52 }
53 
54 //-- GRAMMAR_BEGIN --
55 //TemplateParameter:
56 //    TemplateTypeParameter
57 //    TemplateValueParameter
58 //    TemplateAliasParameter
59 //    TemplateTupleParameter
60 //    TemplateThisParameter
61 //
62 //TemplateTupleParameter:
63 //    Identifier ...
64 class TemplateParameter
65 {
66     static Action enter(Parser p)
67     {
68         switch(p.tok.id)
69         {
70             case TOK_Identifier:
71                 p.pushToken(p.tok);
72                 p.pushState(&shiftIdentifier);
73                 return Accept;
74 
75             case TOK_this:
76                 return TemplateThisParameter.enter(p);
77             case TOK_alias:
78                 return TemplateAliasParameter.enter(p);
79             default:
80                 return TemplateValueParameter.enter(p);
81         }
82     }
83 
84     static Action shiftIdentifier(Parser p)
85     {
86         switch(p.tok.id)
87         {
88             case TOK_comma:
89             case TOK_rparen:
90                 Token tok = p.popToken();
91                 p.pushNode(new ast.TemplateTypeParameter(tok));
92                 return Forward;
93 
94             case TOK_colon:
95             case TOK_assign:
96                 return TemplateTypeParameter!false.enterIdentifier(p);
97 
98             case TOK_dotdotdot:
99                 Token tok = p.popToken();
100                 p.pushNode(new ast.TemplateTupleParameter(tok));
101                 return Accept;
102 
103             default:
104                 return TemplateValueParameter.enterIdentifier(p);
105         }
106     }
107 }
108 
109 //-- GRAMMAR_BEGIN --
110 //IdentifierOrTemplateInstance:
111 //    Identifier
112 //    TemplateInstance
113 //
114 //TemplateInstance:
115 //    TemplateIdentifier ! ( TemplateArgumentList )
116 //    TemplateIdentifier ! TemplateSingleArgument
117 class IdentifierOrTemplateInstance
118 {
119     static Action enter(Parser p)
120     {
121         switch(p.tok.id)
122         {
123             case TOK_Identifier:
124                 p.pushToken(p.tok);
125                 p.pushState(&shiftIdentifier);
126                 return Accept;
127             default:
128                 return p.parseError("identifier expected");
129         }
130     }
131 
132     // assumes identifier token on the info stack
133     static Action enterIdentifier(Parser p)
134     {
135         return shiftIdentifier(p);
136     }
137 
138     static Action shiftIdentifier(Parser p)
139     {
140         auto tok = p.popToken();
141         switch(p.tok.id)
142         {
143             case TOK_not:
144                 p.pushNode(new ast.TemplateInstance(tok));
145                 p.pushState(&shiftNot);
146                 return Accept;
147             default:
148                 p.pushNode(new ast.Identifier(tok));
149                 return Forward;
150         }
151     }
152 
153     static Action shiftNot(Parser p)
154     {
155         switch(p.tok.id)
156         {
157             case TOK_lparen:
158                 p.pushState(&shiftArgumentList);
159                 p.pushState(&TemplateArgumentList.enter);
160                 return Accept;
161 
162             mixin(case_TOKs_TemplateSingleArgument);
163                 p.pushNode(new ast.TemplateArgumentList(p.tok));
164                 p.pushState(&shiftSingleArgument);
165                 return PrimaryExpression.enter(p);
166 
167             case TOK___vector:
168             mixin(case_TOKs_BasicTypeX);
169                 auto n = new ast.TemplateArgumentList(p.tok);
170                 n.addMember(new ast.BasicType(p.tok));
171                 p.topNode!(ast.TemplateInstance).addMember(n);
172                 return Accept;
173 
174             default:
175                 return p.parseError("'(' or single argument template expected after '!'");
176         }
177     }
178 
179     static Action shiftArgumentList(Parser p)
180     {
181         p.popAppendTopNode!(ast.TemplateInstance);
182         switch(p.tok.id)
183         {
184             case TOK_rparen:
185                 return Accept;
186             default:
187                 return p.parseError("closing parenthesis expected");
188         }
189     }
190 
191     static Action shiftSingleArgument(Parser p)
192     {
193         p.popAppendTopNode!(ast.TemplateArgumentList);
194         p.popAppendTopNode!(ast.TemplateInstance);
195         return Forward;
196     }
197 }
198 
199 //-- GRAMMAR_BEGIN --
200 //TemplateArgumentList:
201 //    TemplateArgument
202 //    TemplateArgument ,
203 //    TemplateArgument , TemplateArgumentList
204 //
205 //TemplateArgument:
206 //    Type
207 //    AssignExpression
208 //    Symbol /* same as IdentifierList, so already in Type and AssignExpression */
209 
210 //Symbol:
211 //    SymbolTail
212 //    . SymbolTail
213 //
214 //// identical to IdentifierList
215 //SymbolTail:
216 //    Identifier
217 //    Identifier . SymbolTail
218 //    TemplateInstance
219 //    TemplateInstance . SymbolTail
220 class TemplateArgumentList
221 {
222     mixin ListNode!(ast.TemplateArgumentList, TypeOrExpression!(TOK_comma, TOK_rparen), TOK_comma, true, true);
223 }
224 
225 //-- GRAMMAR_BEGIN --
226 //TemplateSingleArgument:
227 //    Identifier
228 //    BasicTypeX
229 //    CharacterLiteral
230 //    StringLiteral
231 //    IntegerLiteral
232 //    FloatLiteral
233 //    true
234 //    false
235 //    null
236 //    __FILE__
237 //    __LINE__
238 
239 //-- GRAMMAR_BEGIN --
240 //TemplateTypeParameter:
241 //    Identifier
242 //    Identifier TemplateTypeParameterSpecialization
243 //    Identifier TemplateTypeParameterDefault
244 //    Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault
245 //
246 //TemplateTypeParameterSpecialization:
247 //    : Type
248 //
249 //TemplateTypeParameterDefault:
250 //    = Type
251 class TemplateTypeParameter(bool exprDefault = false)
252 {
253     static Action enter(Parser p)
254     {
255         switch(p.tok.id)
256         {
257             case TOK_Identifier:
258                 p.pushNode(new ast.TemplateTypeParameter(p.tok));
259                 p.pushState(&shiftIdentifier);
260                 return Accept;
261             default:
262                 return p.parseError("identifier expected");
263         }
264     }
265 
266     static Action enterIdentifier(Parser p)
267     {
268         Token tok = p.popToken();
269         p.pushNode(new ast.TemplateTypeParameter(tok));
270         return shiftIdentifier(p);
271     }
272 
273     static Action shiftIdentifier(Parser p)
274     {
275         switch(p.tok.id)
276         {
277             case TOK_colon:
278                 p.pushState(&shiftSpecialization);
279                 p.pushState(&Type.enter);
280                 return Accept;
281             case TOK_assign:
282                 p.pushState(&shiftDefault);
283                 static if(exprDefault)
284                     p.pushState(&TypeOrExpression!(TOK_rparen, TOK_comma).enter);
285                 else
286                     p.pushState(&Type.enter);
287                 return Accept;
288             default:
289                 return Forward;
290         }
291     }
292 
293     static Action shiftSpecialization(Parser p)
294     {
295         auto special = p.popNode!(ast.Type)();
296         auto param = p.topNode!(ast.TemplateTypeParameter);
297         param.specialization = special;
298         param.addMember(special);
299 
300         switch(p.tok.id)
301         {
302             case TOK_assign:
303                 p.pushState(&shiftDefault);
304                 static if(exprDefault)
305                     p.pushState(&TypeOrExpression!(TOK_rparen, TOK_comma).enter);
306                 else
307                     p.pushState(&Type.enter);
308                 return Accept;
309             default:
310                 return Forward;
311         }
312     }
313 
314     static Action shiftDefault(Parser p)
315     {
316         auto def = p.popNode();
317         auto param = p.topNode!(ast.TemplateTypeParameter);
318         param.def = def;
319         param.addMember(def);
320         return Forward;
321     }
322 }
323 
324 //TemplateThisParameter:
325 //    this TemplateTypeParameter
326 class TemplateThisParameter
327 {
328     mixin SequenceNode!(ast.TemplateThisParameter, TOK_this, TemplateTypeParameter!false);
329 }
330 
331 //-- GRAMMAR_BEGIN --
332 //TemplateValueParameter:
333 //    TemplateValueDeclaration
334 //    TemplateValueDeclaration TemplateValueParameterSpecialization
335 //    TemplateValueDeclaration TemplateValueParameterDefault
336 //    TemplateValueDeclaration TemplateValueParameterSpecialization TemplateValueParameterDefault
337 //
338 //TemplateValueDeclaration:
339 //    ParameterDeclarator /* without storage classes */
340 //
341 //TemplateValueParameterSpecialization:
342 //    : ConditionalExpression
343 //
344 //TemplateValueParameterDefault:
345 //    = __FILE__ /* already part of ConditionalExpression */
346 //    = __LINE__ /* already part of ConditionalExpression */
347 //    = ConditionalExpression
348 class TemplateValueParameter
349 {
350     static Action enter(Parser p)
351     {
352         p.pushNode(new ast.TemplateValueParameter(p.tok));
353         p.pushState(&shiftDecl);
354         return ParameterDeclarator.enter(p);
355     }
356 
357     static Action enterIdentifier(Parser p)
358     {
359         p.pushNode(new ast.TemplateValueParameter(p.tok));
360         p.pushState(&shiftDecl);
361         return ParameterDeclarator.enterTypeIdentifier(p);
362     }
363 
364     static Action shiftDecl(Parser p)
365     {
366         p.popAppendTopNode!(ast.TemplateValueParameter)();
367         switch(p.tok.id)
368         {
369             case TOK_colon:
370                 p.pushState(&shiftSpecialization);
371                 p.pushState(&ConditionalExpression.enter);
372                 return Accept;
373             case TOK_assign:
374                 p.pushState(&shiftDefault);
375                 p.pushState(&ConditionalExpression.enter);
376                 return Accept;
377             default:
378                 return Forward;
379         }
380     }
381 
382     static Action shiftSpecialization(Parser p)
383     {
384         auto special = p.popNode!(ast.Expression)();
385         auto param = p.topNode!(ast.TemplateValueParameter);
386         param.specialization = special;
387         param.addMember(special);
388 
389         switch(p.tok.id)
390         {
391             case TOK_assign:
392                 p.pushState(&shiftDefault);
393                 p.pushState(&ConditionalExpression.enter);
394                 return Accept;
395             default:
396                 return Forward;
397         }
398     }
399 
400     static Action shiftDefault(Parser p)
401     {
402         auto def = p.popNode!(ast.Expression)();
403         auto param = p.topNode!(ast.TemplateValueParameter);
404         param.def = def;
405         param.addMember(def);
406         return Forward;
407     }
408 }
409 
410 //-- GRAMMAR_BEGIN --
411 //TemplateAliasParameter:
412 //    alias Type_opt Identifier TemplateAliasParameterSpecialization_opt TemplateAliasParameterDefault_opt
413 //
414 //TemplateAliasParameterSpecialization:
415 //    : Type
416 //
417 //TemplateAliasParameterDefault:
418 //    = TypeOrExpression
419 class TemplateAliasParameter
420 {
421     mixin SequenceNode!(ast.TemplateAliasParameter, TOK_alias, TemplateTypeParameter!true);
422 }
423 
424 //-- GRAMMAR_BEGIN --
425 //ClassTemplateDeclaration:
426 //    class Identifier ( TemplateParameterList ) Constraint_opt BaseClassList_opt ClassBody
427 //
428 //InterfaceTemplateDeclaration:
429 //    interface Identifier ( TemplateParameterList ) Constraint_opt BaseInterfaceList_opt InterfaceBody
430 //
431 //TemplateMixinDeclaration:
432 //    mixin template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs }
433 class TemplateMixinDeclaration
434 {
435     static Action enter(Parser p)
436     {
437         switch(p.tok.id)
438         {
439             case TOK_mixin:
440                 p.pushState(&shiftTemplateDeclaration);
441                 p.pushState(&TemplateDeclaration.enter);
442                 return Accept;
443             default:
444                 return p.parseError("mixin expected in mixin template declaration");
445         }
446     }
447 
448     static Action enterAfterMixin(Parser p)
449     {
450         p.pushState(&shiftTemplateDeclaration);
451         return TemplateDeclaration.enter(p);
452     }
453 
454     static Action shiftTemplateDeclaration(Parser p)
455     {
456         p.topNode!(ast.TemplateDeclaration).id = TOK_mixin;
457         return Forward;
458     }
459 }
460 
461 //TemplateMixin:
462 //    mixin TemplateIdentifier ;
463 //    mixin TemplateIdentifier MixinIdentifier ;
464 //    mixin TemplateIdentifier ! ( TemplateArgumentList ) ;
465 //    mixin TemplateIdentifier ! ( TemplateArgumentList ) MixinIdentifier ;
466 //
467 //MixinIdentifier:
468 //    Identifier
469 //
470 // translated to
471 //-- GRAMMAR_BEGIN --
472 //TemplateMixin:
473 //    mixin GlobalIdentifierList MixinIdentifier_opt ;
474 //    mixin Typeof . IdentifierList MixinIdentifier_opt ;
475 class TemplateMixin
476 {
477     mixin SequenceNode!(ast.TemplateMixin, TOK_mixin, GlobalIdentifierList, Opt!(Identifier, TOK_Identifier), TOK_semicolon);
478 
479     static Action enterAfterMixin(Parser p)
480     {
481         p.pushNode(new ast.TemplateMixin(p.tok));
482         switch(p.tok.id)
483         {
484             case TOK_typeof:
485                 p.pushState(&shiftTypeof);
486                 return PostfixExpression.enter(p);
487             default:
488                 return shift1.shift(p);
489         }
490     }
491 
492     static Action shiftTypeof(Parser p)
493     {
494         // already in shift2.shift(): p.popAppendTopNode!(ast.TemplateMixin)();
495         return shift2.shift(p);
496     }
497 }
498 
499 //-- GRAMMAR_BEGIN --
500 //Constraint:
501 //    if ( ConstraintExpression )
502 //
503 //ConstraintExpression:
504 //    Expression
505 class Constraint
506 {
507     mixin SequenceNode!(ast.Constraint, TOK_if, TOK_lparen, Expression, TOK_rparen);
508 }