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 }