1 /// Author: Aziz Köksal
2 /// License: GPL3
3 /// $(Maturity very high)
4 module dil.ast.Parameters;
5 
6 import dil.ast.Node,
7        dil.ast.Type,
8        dil.ast.Expression,
9        dil.ast.NodeCopier,
10        dil.ast.Meta;
11 import dil.lexer.Identifier;
12 import dil.semantic.Symbols;
13 import dil.Enums;
14 
15 import common;
16 
17 /// A function or foreach parameter.
18 class Parameter : Node
19 {
20   StorageClass stcs; /// The storage classes of the parameter.
21   Token* stok; /// Token of the last storage class.
22   TypeNode type; /// The parameter's type.
23   Token* name; /// The name of the parameter.
24   Expression defValue; /// The default initialization value.
25   ParameterSymbol symbol; /// Semantic symbol.
26   mixin(memberInfo("stcs", "stok?", "type?", "name?", "defValue?"));
27 
28   this(StorageClass stcs, Token* stok, TypeNode type,
29     Token* name, Expression defValue)
30   {
31     mixin(set_kind);
32     // type can be null when param in foreach statement
33     addOptChild(type);
34     addOptChild(defValue);
35 
36     this.stcs = stcs;
37     this.stok = stok;
38     this.type = type;
39     this.name = name;
40     this.defValue = defValue;
41   }
42 
43   /// Returns true if this parameter has a name.
44   bool hasName()
45   {
46     return name !is null;
47   }
48 
49   /// Returns the name of the parameter as a string.
50   cstring nameStr()
51   {
52     assert(hasName);
53     return name.ident.str;
54   }
55 
56   /// Returns true if this is a D-style variadic parameter.
57   /// E.g.: func(int[] values ...)
58   bool isDVariadic()
59   {
60     return isVariadic && !isCVariadic;
61   }
62 
63   /// Returns true if this is a C-style variadic parameter.
64   /// E.g.: func(...)
65   bool isCVariadic()
66   {
67     return stcs == StorageClass.Variadic &&
68            type is null && name is null;
69   }
70 
71   /// Returns true if this is a D- or C-style variadic parameter.
72   bool isVariadic()
73   {
74     return !!(stcs & StorageClass.Variadic);
75   }
76 
77   /// Returns true if this parameter is lazy.
78   bool isLazy()
79   {
80     return !!(stcs & StorageClass.Lazy);
81   }
82 
83   /// Returns the token of the storage class that comes before the type.
84   Token* tokenOfLastSTC()
85   {
86     return stok;
87   }
88 
89   mixin methods;
90 }
91 
92 /// Array of parameters.
93 class Parameters : Node
94 {
95   StorageClass postSTCs;
96   ParametersSymbol symbol; /// Semantic symbol.
97 
98   this()
99   {
100     mixin(set_kind);
101   }
102 
103   /// For ASTSerializer.
104   this(Parameter[] params)
105   {
106     this();
107     addChildren(params);
108   }
109 
110   bool hasVariadic()
111   {
112     if (children.length != 0)
113       return items[$-1].isVariadic();
114     return false;
115   }
116 
117   bool hasLazy()
118   {
119     foreach (param; items)
120       if (param.isLazy())
121         return true;
122     return false;
123   }
124 
125   void opCatAssign(Parameter param)
126   { addChild(param); }
127 
128   Parameter[] items() @property
129   { return cast(Parameter[])children; }
130 
131   void items(Parameter[] items) @property
132   { children = cast(Node[])items; }
133 
134   size_t length()
135   { return children.length; }
136 
137   mixin(memberInfo("items"));
138   mixin methods;
139 }
140 
141 /*~~~~~~~~~~~~~~~~~~~~~~
142 ~ Template parameters: ~
143 ~~~~~~~~~~~~~~~~~~~~~~*/
144 
145 /// Abstract base class for all template parameters.
146 abstract class TemplateParam : Node
147 {
148   Token* name;
149   this(Token* name)
150   {
151     this.name = name;
152   }
153 
154   /// Returns the name of the parameter as a string.
155   cstring nameStr()
156   {
157     return name.ident.str;
158   }
159 
160   override TemplateParam copy();
161 }
162 
163 /// $(BNF TemplateAliasParam := "alias" Identifier SpecOrDefaultType)
164 class TemplateAliasParam : TemplateParam
165 {
166   Node spec; /// Specialization. Can be a Type or an Expression (in D2).
167   Node def; /// Default. Can be a Type or an Expression (in D2).
168   mixin(memberInfo("name", "spec?", "def?"));
169   this(Token* name, Node spec, Node def)
170   {
171     assert(!spec || spec.isType() || spec.isExpression());
172     assert(!def || def.isType() || def.isExpression());
173     super(name);
174     mixin(set_kind);
175     addOptChild(spec);
176     addOptChild(def);
177     this.spec = spec;
178     this.def = def;
179   }
180   mixin methods;
181 }
182 
183 /// $(BNF TemplateTypeParam := Identifier SpecOrDefaultType)
184 class TemplateTypeParam : TemplateParam
185 {
186   TypeNode specType, defType;
187   mixin(memberInfo("name", "specType?", "defType?"));
188   this(Token* name, TypeNode specType, TypeNode defType)
189   {
190     super(name);
191     mixin(set_kind);
192     addOptChild(specType);
193     addOptChild(defType);
194     this.specType = specType;
195     this.defType = defType;
196   }
197   mixin methods;
198 }
199 
200 // version(D2)
201 // {
202 /// $(BNF TemplateThisParam  := "this" Identifier SpecOrDefaultType)
203 class TemplateThisParam : TemplateParam
204 {
205   TypeNode specType, defType;
206   mixin(memberInfo("name", "specType?", "defType?"));
207   this(Token* name, TypeNode specType, TypeNode defType)
208   {
209     super(name);
210     mixin(set_kind);
211     addOptChild(specType);
212     addOptChild(defType);
213     this.specType = specType;
214     this.defType = defType;
215   }
216   mixin methods;
217 }
218 // }
219 
220 /// $(BNF TemplateValueParamer := Declarator SpecOrDefaultValue)
221 class TemplateValueParam : TemplateParam
222 {
223   TypeNode valueType;
224   Expression specValue, defValue;
225   mixin(memberInfo("valueType", "name", "specValue?", "defValue?"));
226   this(TypeNode valueType, Token* name, Expression specValue,
227     Expression defValue)
228   {
229     super(name);
230     mixin(set_kind);
231     addChild(valueType);
232     addOptChild(specValue);
233     addOptChild(defValue);
234     this.valueType = valueType;
235     this.specValue = specValue;
236     this.defValue = defValue;
237   }
238   mixin methods;
239 }
240 
241 /// $(BNF TemplateTupleParam := Identifier "...")
242 class TemplateTupleParam : TemplateParam
243 {
244   mixin(memberInfo("name"));
245   this(Token* name)
246   {
247     super(name);
248     mixin(set_kind);
249   }
250   mixin methods;
251 }
252 
253 /// Array of template parameters.
254 class TemplateParameters : Node
255 {
256   this()
257   {
258     mixin(set_kind);
259   }
260 
261   /// For ASTSerializer.
262   this(TemplateParam[] params)
263   {
264     this();
265     addChildren(params);
266   }
267 
268   void opCatAssign(TemplateParam parameter)
269   {
270     addChild(parameter);
271   }
272 
273   TemplateParam[] items() @property
274   {
275     return cast(TemplateParam[])children;
276   }
277 
278   void items(TemplateParam[] items) @property
279   {
280     children = cast(Node[])items;
281   }
282 
283   mixin(memberInfo("items"));
284   mixin methods;
285 }
286 
287 /// Array of template arguments.
288 class TemplateArguments : Node
289 {
290   this()
291   {
292     mixin(set_kind);
293   }
294 
295   /// For ASTSerializer.
296   this(Node[] args)
297   {
298     this();
299     addChildren(args);
300   }
301 
302   void opCatAssign(Node argument)
303   {
304     addChild(argument);
305   }
306 
307   Node[] items() @property
308   {
309     return children;
310   }
311 
312   void items(Node[] items) @property
313   {
314     children = items;
315   }
316 
317   mixin(memberInfo("items"));
318   mixin methods;
319 }