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.ast.tmpl; 10 11 import vdc.util; 12 import vdc.lexer; 13 import vdc.ast.node; 14 import vdc.ast.decl; 15 import vdc.ast.expr; 16 import vdc.ast.type; 17 import vdc.ast.writer; 18 import vdc.interpret; 19 import vdc.semantic; 20 21 import stdext.util; 22 23 //TemplateDeclaration: 24 // [Identifier TemplateParameterList Constraint_opt DeclarationBlock] 25 class TemplateDeclaration : Node 26 { 27 mixin ForwardCtor!(); 28 29 Identifier getIdentifier() { return getMember!Identifier(0); } 30 TemplateParameterList getTemplateParameterList() { return getMember!TemplateParameterList(1); } 31 Constraint getConstraint() { return members.length > 3 ? getMember!Constraint(2) : null; } 32 Node getBody() { return getMember(members.length - 1); } 33 bool isMixin() { return id == TOK_mixin; } 34 35 override TemplateDeclaration clone() 36 { 37 TemplateDeclaration n = static_cast!TemplateDeclaration(super.clone()); 38 return n; 39 } 40 41 override void toD(CodeWriter writer) 42 { 43 if(isMixin()) 44 writer("mixin "); 45 writer("template ", getIdentifier(), getTemplateParameterList()); 46 writer.nl(); 47 if(getConstraint()) 48 { 49 writer(getConstraint()); 50 writer.nl(); 51 } 52 // writer("{"); 53 // writer.nl(); 54 // { 55 // CodeIndenter indent = CodeIndenter(writer); 56 writer(getBody()); 57 // } 58 // writer("}"); 59 // writer.nl(); 60 writer.nl(); 61 } 62 override void toC(CodeWriter writer) 63 { 64 // we never write the template, only instantiations 65 } 66 67 override void addSymbols(Scope sc) 68 { 69 string ident = getIdentifier().ident; 70 sc.addSymbol(ident, this); 71 } 72 73 override void _semantic(Scope sc) 74 { 75 // do not recurse into declaration, it only makes sense for an instance 76 } 77 78 override bool isTemplate() const { return true; } 79 80 override Node expandTemplate(Scope sc, TemplateArgumentList args) 81 { 82 TemplateParameterList tpl = getTemplateParameterList(); 83 string ident = getIdentifier().ident; 84 85 ArgMatch[] vargs = matchTemplateArgs(ident, sc, args, tpl); 86 ParameterList pl = createTemplateParameterList(vargs); 87 88 auto bdy = getBody().clone(); 89 auto inst = new TemplateMixinInstance; 90 inst.addMember(pl); 91 inst.addMember(bdy); 92 return inst; 93 } 94 } 95 96 //TemplateMixinInstance: 97 // name [ParameterList DeclarationBlock] 98 class TemplateMixinInstance : Type 99 { 100 mixin ForwardCtor!(); 101 102 // semantic data 103 string instanceName; // set when named instance created by cloning 104 TypeValue typeVal; 105 106 ParameterList getTemplateParameterList() { return getMember!ParameterList(0); } 107 Node getBody() { return getMember(1); } 108 109 override bool propertyNeedsParens() const { return false; } 110 111 override void toD(CodeWriter writer) 112 { 113 writer("mixin ", getBody(), " ", instanceName); 114 } 115 116 override void _semantic(Scope sc) 117 { 118 // TODO: TemplateParameterList, Constraint 119 sc = enterScope(sc); 120 super._semantic(sc); 121 sc = sc.pop(); 122 } 123 124 override void addSymbols(Scope sc) 125 { 126 if(instanceName.length) 127 sc.addSymbol(instanceName, this); 128 else 129 { 130 sc = enterScope(sc).pop(); 131 132 // put symbols into parent scope aswell 133 foreach(id, sym; scop.symbols) 134 foreach(s, b; sym) 135 sc.addSymbol(id, s); 136 } 137 } 138 139 override Type calcType() 140 { 141 return this; 142 } 143 144 override Value interpret(Context sc) 145 { 146 if(!typeVal) 147 typeVal = new TypeValue(calcType()); 148 return typeVal; 149 } 150 } 151 152 //TemplateParameterList: 153 // [ TemplateParameter... ] 154 class TemplateParameterList : Node 155 { 156 mixin ForwardCtor!(); 157 158 override void toD(CodeWriter writer) 159 { 160 writer("("); 161 writer.writeArray(members); 162 writer(")"); 163 } 164 } 165 166 //TemplateParameter: 167 // TemplateTypeParameter 168 // TemplateValueParameter 169 // TemplateAliasParameter 170 // TemplateTupleParameter 171 // TemplateThisParameter 172 class TemplateParameter : Node 173 { 174 mixin ForwardCtor!(); 175 } 176 177 //TemplateInstance: 178 // ident [ TemplateArgumentList ] 179 class TemplateInstance : Identifier 180 { 181 mixin ForwardCtorTok!(); 182 183 TemplateArgumentList getTemplateArgumentList() { return getMember!TemplateArgumentList(0); } 184 185 override void toD(CodeWriter writer) 186 { 187 writer.writeIdentifier(ident); 188 writer("!(", getMember(0), ")"); 189 } 190 191 override Value interpret(Context sc) 192 { 193 return super.interpret(sc); 194 } 195 } 196 // 197 // 198 //TemplateArgumentList: 199 // [ TemplateArgument... ] 200 class TemplateArgumentList : Node 201 { 202 mixin ForwardCtorNoId!(); 203 204 override void toD(CodeWriter writer) 205 { 206 bool writeSep = false; 207 foreach(m; members) 208 { 209 if(writeSep) 210 writer(", "); 211 writeSep = true; 212 213 bool paren = false; 214 if(auto expr = cast(Expression) m) 215 paren = (expr.getPrecedence() <= PREC.expr); 216 217 if(paren) 218 writer("(", m, ")"); 219 else 220 writer(m); 221 } 222 } 223 } 224 225 // 226 //TemplateArgument: 227 // Type 228 // AssignExpression 229 // Symbol 230 // 231 //// identical to IdentifierList 232 //Symbol: 233 // SymbolTail 234 // . SymbolTail 235 // 236 //SymbolTail: 237 // Identifier 238 // Identifier . SymbolTail 239 // TemplateInstance 240 // TemplateInstance . SymbolTail 241 // 242 //TemplateSingleArgument: 243 // Identifier 244 // BasicTypeX 245 // CharacterLiteral 246 // StringLiteral 247 // IntegerLiteral 248 // FloatLiteral 249 // true 250 // false 251 // null 252 // __FILE__ 253 // __LINE__ 254 255 //TemplateTypeParameter: 256 // Identifier 257 // Identifier TemplateTypeParameterSpecialization 258 // Identifier TemplateTypeParameterDefault 259 // Identifier TemplateTypeParameterSpecialization TemplateTypeParameterDefault 260 class TemplateTypeParameter : TemplateParameter 261 { 262 string ident; 263 Type specialization; 264 Node def; 265 266 this() {} // default constructor needed for clone() 267 268 this(Token tok) 269 { 270 super(tok); 271 ident = tok.txt; 272 } 273 274 override TemplateTypeParameter clone() 275 { 276 TemplateTypeParameter n = static_cast!TemplateTypeParameter(super.clone()); 277 n.ident = ident; 278 for(int m = 0; m < members.length; m++) 279 { 280 if(members[m] is specialization) 281 n.specialization = static_cast!Type(n.members[m]); 282 if(members[m] is def) 283 n.def = n.members[m]; 284 } 285 return n; 286 } 287 override bool compare(const(Node) n) const 288 { 289 if(!super.compare(n)) 290 return false; 291 292 auto tn = static_cast!(typeof(this))(n); 293 return tn.ident == ident; 294 } 295 296 override void toD(CodeWriter writer) 297 { 298 writer.writeIdentifier(ident); 299 if(specialization) 300 writer(" : ", specialization); 301 if(def) 302 writer(" = ", def); 303 } 304 } 305 306 //TemplateTypeParameterSpecialization: 307 // : Type 308 // 309 //TemplateTypeParameterDefault: 310 // = Type 311 312 //TemplateThisParameter: 313 // [ TemplateTypeParameter ] 314 class TemplateThisParameter : TemplateParameter 315 { 316 mixin ForwardCtor!(); 317 318 override void toD(CodeWriter writer) 319 { 320 writer("this ", getMember(0)); 321 } 322 } 323 // 324 //TemplateValueParameter: 325 // Declaration 326 // Declaration TemplateValueParameterSpecialization 327 // Declaration TemplateValueParameterDefault 328 // Declaration TemplateValueParameterSpecialization TemplateValueParameterDefault 329 class TemplateValueParameter : TemplateParameter 330 { 331 mixin ForwardCtor!(); 332 333 Expression specialization; 334 Expression def; 335 336 ParameterDeclarator getParameterDeclarator() { return getMember!ParameterDeclarator(0); } 337 338 override TemplateValueParameter clone() 339 { 340 TemplateValueParameter n = static_cast!TemplateValueParameter(super.clone()); 341 for(int m = 0; m < members.length; m++) 342 { 343 if(members[m] is specialization) 344 n.specialization = static_cast!Expression(n.members[m]); 345 if(members[m] is def) 346 n.def = static_cast!Expression(n.members[m]); 347 } 348 return n; 349 } 350 351 override void toD(CodeWriter writer) 352 { 353 writer(getMember(0)); 354 if(specialization) 355 writer(" : ", specialization); 356 if(def) 357 writer(" = ", def); 358 } 359 } 360 // 361 //TemplateValueParameterSpecialization: 362 // : ConditionalExpression 363 // 364 //TemplateValueParameterDefault: 365 // = __FILE__ 366 // = __LINE__ 367 // = ConditionalExpression 368 // 369 //TemplateAliasParameter: 370 // alias Identifier TemplateAliasParameterSpecialization_opt TemplateAliasParameterDefault_opt 371 // 372 //TemplateAliasParameterSpecialization: 373 // : Type 374 // 375 //TemplateAliasParameterDefault: 376 // = Type 377 class TemplateAliasParameter : TemplateParameter 378 { 379 mixin ForwardCtor!(); 380 381 string getIdent() { return getMember!TemplateTypeParameter(0).ident; } 382 383 override void toD(CodeWriter writer) 384 { 385 writer("alias ", getMember(0)); 386 } 387 } 388 // 389 //TemplateTupleParameter: 390 // Identifier ... 391 class TemplateTupleParameter : TemplateParameter 392 { 393 string ident; 394 395 override TemplateTupleParameter clone() 396 { 397 TemplateTupleParameter n = static_cast!TemplateTupleParameter(super.clone()); 398 n.ident = ident; 399 return n; 400 } 401 override bool compare(const(Node) n) const 402 { 403 if(!super.compare(n)) 404 return false; 405 406 auto tn = static_cast!(typeof(this))(n); 407 return tn.ident == ident; 408 } 409 410 this() {} // default constructor needed for clone() 411 412 this(Token tok) 413 { 414 super(tok); 415 ident = tok.txt; 416 } 417 override void toD(CodeWriter writer) 418 { 419 writer.writeIdentifier(ident); 420 writer("..."); 421 } 422 } 423 // 424 //ClassTemplateDeclaration: 425 // class Identifier ( TemplateParameterList ) BaseClassList_opt ClassBody 426 // 427 //InterfaceTemplateDeclaration: 428 // interface Identifier ( TemplateParameterList ) Constraint_opt BaseInterfaceList_opt InterfaceBody 429 // 430 //TemplateMixinDeclaration: 431 // mixin template TemplateIdentifier ( TemplateParameterList ) Constraint_opt { DeclDefs } 432 433 //TemplateMixin: 434 // mixin TemplateIdentifier ; 435 // mixin TemplateIdentifier MixinIdentifier ; 436 // mixin TemplateIdentifier ! ( TemplateArgumentList ) ; 437 // mixin TemplateIdentifier ! ( TemplateArgumentList ) MixinIdentifier ; 438 // 439 // translated to 440 //TemplateMixin: 441 // [IdentifierList MixinIdentifier_opt] 442 // [Typeof MixinIdentifier] 443 class TemplateMixin : Node 444 { 445 mixin ForwardCtor!(); 446 447 override void toD(CodeWriter writer) 448 { 449 writer("mixin ", getMember(0)); 450 if(members.length > 1) 451 writer(" ", getMember(1)); 452 writer(";"); 453 writer.nl(); 454 } 455 456 override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) 457 { 458 Node tmpl = getMember(0); 459 Node n; 460 if(auto prop = cast(TypeProperty) tmpl) 461 n = prop.resolve(); 462 else if(auto idlist = cast(IdentifierList) tmpl) 463 n = idlist.doResolve(true); 464 465 if(!n) 466 semanticError("cannot resolve ", tmpl); 467 else if(auto tmi = cast(TemplateMixinInstance) n) 468 { 469 // TODO: match constraints, replace parameters 470 if(members.length > 1) 471 { 472 // named instance 473 string name = getMember!Identifier(1).ident; 474 tmi.instanceName = name; 475 } 476 return [ tmi ]; 477 } 478 else 479 semanticError(n, " is not a TemplateMixinInstance"); 480 return athis; 481 } 482 } 483 484 // 485 //Constraint: 486 // if ( ConstraintExpression ) 487 class Constraint : Node 488 { 489 mixin ForwardCtor!(); 490 491 override void toD(CodeWriter writer) 492 { 493 writer(" if(", getMember(0), ")"); 494 } 495 } 496 // 497 //ConstraintExpression: 498 // Expression 499 // 500 //MixinIdentifier: 501 // Identifier 502 // 503 504 ArgMatch[] matchTemplateArgs(string ident, Scope sc, TemplateArgumentList args, TemplateParameterList tpl) 505 { 506 if(args.members.length != tpl.members.length) 507 { 508 semanticError("incorrect number of arguments for template expansion of ", ident); 509 return null; 510 } 511 ArgMatch[] vargs; 512 Context ctx = new Context(nullContext); 513 ctx.scop = sc; 514 int m; 515 for(m = 0; m < args.members.length; m++) 516 { 517 Value v; 518 string name; 519 auto am = args.members[m]; 520 auto pm = tpl.members[m]; 521 if(auto typeparam = cast(TemplateTypeParameter) pm) 522 { 523 v = am.interpret(ctx); 524 name = typeparam.ident; 525 if(!cast(TypeValue) v) 526 { 527 semanticError(ident, ": ", m+1, ". argument must evaluate to a type, not ", v.toStr()); 528 v = null; 529 } 530 } 531 else if(auto thisparam = cast(TemplateThisParameter) pm) 532 { 533 semanticError("cannot infer this parameter for ", ident); 534 } 535 else if(auto valueparam = cast(TemplateValueParameter) pm) 536 { 537 v = am.interpret(ctx); 538 auto decl = valueparam.getParameterDeclarator().getDeclarator(); 539 v = decl.calcType().createValue(ctx, v); 540 name = decl.ident; 541 } 542 else if(auto aliasparam = cast(TemplateAliasParameter) pm) 543 { 544 if(auto idtype = cast(IdentifierType) am) 545 v = new AliasValue(idtype.getIdentifierList()); 546 else if(auto type = cast(Type) am) 547 v = new TypeValue(type); 548 else if(auto id = cast(IdentifierExpression) am) 549 { 550 auto idlist = new IdentifierList; 551 idlist.addMember(id.getIdentifier().clone()); 552 v = new AliasValue(idlist); 553 } 554 else 555 semanticError(ident, ": ", m+1, ". argument must evaluate to an identifier, not ", am); 556 name = aliasparam.getIdent(); 557 } 558 else if(auto tupleparam = cast(TemplateTupleParameter) pm) 559 { 560 semanticError("cannot infer template tuple parameter for ", ident); 561 } 562 if(!v) 563 return null; 564 vargs ~= ArgMatch(v, name); 565 } 566 return vargs; 567 } 568 569 570 ParameterList createTemplateParameterList(ArgMatch[] vargs) 571 { 572 ParameterList pl = new ParameterList; 573 for(int m = 0; m < vargs.length; m++) 574 { 575 auto pd = new ParameterDeclarator; 576 pd.addMember(vargs[m].value.getType().clone()); 577 578 auto d = new Declarator; 579 d.ident = vargs[m].name; 580 if(auto av = cast(AliasValue) vargs[m].value) 581 { 582 d.isAlias = true; 583 d.aliasTo = av.resolve(); 584 } 585 else 586 { 587 d.value = vargs[m].value; 588 } 589 pd.addMember(d); 590 pl.addMember(pd); 591 } 592 return pl; 593 }