1 module d.parser.dtemplate;
2 
3 import d.ast.declaration;
4 import d.ast.expression;
5 import d.ast.identifier;
6 import d.ast.type;
7 
8 import d.parser.base;
9 import d.parser.declaration;
10 import d.parser.expression;
11 import d.parser.type;
12 
13 auto parseTemplate(ref TokenRange trange, StorageClass stc) {
14 	auto location = trange.front.location;
15 	trange.match(TokenType.Template);
16 	
17 	auto name = trange.front.name;
18 	trange.match(TokenType.Identifier);
19 	
20 	auto parameters = trange.parseTemplateParameters();
21 	auto declarations = trange.parseAggregate();
22 	
23 	location.spanTo(declarations[$ - 1].location);
24 	
25 	return new TemplateDeclaration(location, stc, name, parameters, declarations);
26 }
27 
28 auto parseConstraint(ref TokenRange trange) {
29 	trange.match(TokenType.If);
30 	trange.match(TokenType.OpenParen);
31 	
32 	trange.parseExpression();
33 	
34 	trange.match(TokenType.CloseParen);
35 }
36 
37 auto parseTemplateParameters(ref TokenRange trange) {
38 	trange.match(TokenType.OpenParen);
39 	
40 	AstTemplateParameter[] parameters;
41 	
42 	if (trange.front.type != TokenType.CloseParen) {
43 		parameters ~= trange.parseTemplateParameter();
44 		
45 		while(trange.front.type != TokenType.CloseParen) {
46 			trange.match(TokenType.Comma);
47 			
48 			parameters ~= trange.parseTemplateParameter();
49 		}
50 	}
51 	
52 	trange.match(TokenType.CloseParen);
53 	
54 	return parameters;
55 }
56 
57 private AstTemplateParameter parseTemplateParameter(ref TokenRange trange) {
58 	switch(trange.front.type) with(TokenType) {
59 		case Identifier :
60 			auto lookahead = trange.getLookahead();
61 			lookahead.popFront();
62 			switch(lookahead.front.type) {
63 				// Identifier followed by ":", "=", "," or ")" are type parameters.
64 				case Colon, Equal, Comma, CloseParen :
65 					return trange.parseTypeParameter();
66 				
67 				case DotDotDot :
68 					auto name = trange.front.name;
69 					auto location = lookahead.front.location;
70 					
71 					import std.range;
72 					trange.popFrontN(2);
73 					return new AstTupleTemplateParameter(location, name);
74 				
75 				default :
76 					// We probably have a value parameter (or an error).
77 					return trange.parseValueParameter();
78 			}
79 		
80 		case Alias :
81 			return trange.parseAliasParameter();
82 		
83 		case This :
84 			auto location = trange.front.location;
85 			trange.popFront();
86 			
87 			auto name = trange.front.name;
88 			location.spanTo(trange.front.location);
89 			
90 			trange.match(Identifier);
91 			
92 			return new AstThisTemplateParameter(location, name);
93 		
94 		default :
95 			// We probably have a value parameter (or an error).
96 			return trange.parseValueParameter();
97 	}
98 }
99 
100 private auto parseTypeParameter(ref TokenRange trange) {
101 	auto name = trange.front.name;
102 	auto location = trange.front.location;
103 	
104 	trange.match(TokenType.Identifier);
105 	
106 	AstType defaultType;
107 	switch(trange.front.type) with(TokenType) {
108 		case Colon :
109 			trange.popFront();
110 			auto specialization = trange.parseType();
111 			
112 			if(trange.front.type == Equal) {
113 				trange.popFront();
114 				defaultType = trange.parseType();
115 			}
116 			
117 			location.spanTo(trange.front.location);
118 			return new AstTypeTemplateParameter(location, name, specialization, defaultType);
119 		
120 		case Equal :
121 			trange.popFront();
122 			defaultType = trange.parseType();
123 			
124 			goto default;
125 		
126 		default :
127 			auto specialization = AstType.get(new BasicIdentifier(location, name));
128 			
129 			location.spanTo(trange.front.location);
130 			return new AstTypeTemplateParameter(location, name, specialization, defaultType);
131 	}
132 }
133 
134 private auto parseValueParameter(ref TokenRange trange) {
135 	auto location = trange.front.location;
136 	
137 	auto type = trange.parseType();
138 	auto name = trange.front.name;
139 	
140 	location.spanTo(trange.front.location);
141 	trange.match(TokenType.Identifier);
142 	
143 	AstExpression defaultValue;
144 	if (trange.front.type == TokenType.Equal) {
145 		trange.popFront();
146 		switch(trange.front.type) with(TokenType) {
147 			case __File__, __Line__ :
148 				location.spanTo(trange.front.location);
149 				
150 				trange.popFront();
151 				break;
152 			
153 			default :
154 				defaultValue = trange.parseAssignExpression();
155 				location.spanTo(defaultValue.location);
156 		}
157 	}
158 	
159 	return new AstValueTemplateParameter(location, name, type, defaultValue);
160 }
161 
162 private AstTemplateParameter parseAliasParameter(ref TokenRange trange) {
163 	auto location = trange.front.location;
164 	trange.match(TokenType.Alias);
165 	
166 	bool isTyped = false;
167 	if (trange.front.type != TokenType.Identifier) {
168 		isTyped = true;
169 	} else {
170 		// Identifier followed by ":", "=", "," or ")" are untyped alias parameters.
171 		auto lookahead = trange.getLookahead();
172 		lookahead.popFront();
173 		auto nextType = lookahead.front.type;
174 		switch(lookahead.front.type) with(TokenType) {
175 			case Colon, Equal, Comma, CloseParen :
176 				break;
177 			
178 			default:
179 				isTyped = true;
180 				break;
181 		}
182 	}
183 	
184 	if (isTyped) {
185 		auto type = trange.parseType();
186 		auto name = trange.front.name;
187 		
188 		location.spanTo(trange.front.location);
189 		trange.match(TokenType.Identifier);
190 		
191 		return new AstTypedAliasTemplateParameter(location, name, type);
192 	} else {
193 		auto name = trange.front.name;
194 		
195 		location.spanTo(trange.front.location);
196 		trange.match(TokenType.Identifier);
197 		
198 		return new AstAliasTemplateParameter(location, name);
199 	}
200 }
201 
202 auto parseTemplateArguments(ref TokenRange trange) {
203 	AstTemplateArgument[] arguments;
204 	
205 	switch (trange.front.type) with(TokenType) {
206 		case OpenParen:
207 			trange.popFront();
208 			
209 			while (trange.front.type != CloseParen) {
210 				import d.parser.ambiguous;
211 				arguments ~= trange
212 					.parseAmbiguous!(p => AstTemplateArgument(p))();
213 				
214 				if (trange.front.type != Comma) {
215 					break;
216 				}
217 				
218 				trange.popFront();
219 			}
220 			
221 			trange.match(CloseParen);
222 			break;
223 		
224 		case Identifier:
225 			auto identifier = new BasicIdentifier(trange.front.location, trange.front.name);
226 			arguments = [AstTemplateArgument(identifier)];
227 			
228 			trange.popFront();
229 			break;
230 		
231 		case True, False, Null, IntegerLiteral, StringLiteral, CharacterLiteral, FloatLiteral, __File__, __Line__ :
232 			arguments = [AstTemplateArgument(trange.parsePrimaryExpression())];
233 			break;
234 		
235 		/+
236 		case This :
237 			// This can be passed as alias parameter.
238 		+/
239 		
240 		default:
241 			arguments = [AstTemplateArgument(trange.parseBasicType())];
242 			break;
243 	}
244 	
245 	return arguments;
246 }