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.misc; 10 11 import vdc.lexer; 12 import vdc.semantic; 13 import vdc.interpret; 14 import vdc.util; 15 16 import vdc.ast.node; 17 import vdc.ast.expr; 18 import vdc.ast.decl; 19 import vdc.ast.stmt; 20 import vdc.ast.type; 21 import vdc.ast.writer; 22 23 import stdext.util; 24 25 import std.algorithm; 26 27 //EnumDeclaration: 28 // enum EnumTag EnumBody 29 // enum EnumBody 30 // enum EnumTag : EnumBaseType EnumBody 31 // enum : EnumBaseType EnumBody 32 // enum Identifier = AssignExpression ; 33 // 34 //EnumTag: 35 // Identifier 36 // 37 //EnumBaseType: 38 // Type 39 class EnumDeclaration : Type 40 { 41 mixin ForwardCtor!(); 42 43 string ident; 44 bool isDecl; // does not have body syntax 45 46 override bool propertyNeedsParens() const { return false; } 47 48 override EnumDeclaration clone() 49 { 50 EnumDeclaration n = static_cast!EnumDeclaration(super.clone()); 51 n.ident = ident; 52 n.isDecl = isDecl; 53 return n; 54 } 55 override bool compare(const(Node) n) const 56 { 57 if(!super.compare(n)) 58 return false; 59 60 auto tn = static_cast!(typeof(this))(n); 61 return tn.isDecl == isDecl 62 && tn.ident == ident; 63 } 64 65 Type getBaseType() { return members.length > 1 ? getMember!Type(0) : null; } 66 EnumBody getBody() { return members.length > 0 ? getMember!EnumBody(members.length - 1) : null; } 67 68 override void toD(CodeWriter writer) 69 { 70 if(!writer.writeDeclarations) 71 return; 72 if(writer.writeReferencedOnly) 73 { 74 if(ident.length) 75 { 76 if(semanticSearches == 0) 77 return; 78 } 79 else if(auto bdy = getBody()) 80 if(!bdy.hasSemanticSearches()) 81 return; 82 } 83 if(isDecl) 84 { 85 writer("enum "); 86 if (auto type = getBaseType()) 87 writer(type, " "); 88 writer.writeArray(getBody().getEnumMembers().members); 89 writer(";"); 90 writer.nl; 91 } 92 else 93 { 94 writer("enum "); 95 writer.writeIdentifier(ident); 96 if(writer.writeClassImplementations) 97 { 98 if(Type type = getBaseType()) 99 writer(" : ", type); 100 if (members.length > 0) 101 { 102 writer.nl(); 103 writer(getBody()); 104 } 105 else 106 { 107 writer(";"); 108 writer.nl; 109 } 110 } 111 } 112 } 113 114 override bool createsScope() const { return ident.length > 0; } 115 116 override void addSymbols(Scope sc) 117 { 118 if(ident.length) 119 sc.addSymbol(ident, this); 120 121 else if(auto bdy = getBody()) 122 bdy.addSymbols(sc); 123 } 124 125 override Value createValue(Context ctx, Value initValue) 126 { 127 if(auto bt = getBaseType()) 128 return getBaseType().createValue(ctx, initValue); 129 if(initValue) 130 return initValue.getType().createValue(ctx, initValue); 131 return Value.create(0); 132 } 133 } 134 135 // forward declaration not needed with proper handling 136 //EnumBody: 137 // ; 138 // { EnumMembers } 139 class EnumBody : Node 140 { 141 mixin ForwardCtor!(); 142 143 EnumMembers getEnumMembers() { return getMember!EnumMembers(0); } 144 145 override void toD(CodeWriter writer) 146 { 147 writer("{"); 148 writer.nl(); 149 { 150 CodeIndenter indent = CodeIndenter(writer); 151 writer(getMember(0)); 152 } 153 writer("}"); 154 writer.nl(); 155 } 156 157 bool hasSemanticSearches() 158 { 159 return getEnumMembers().hasSemanticSearches(); 160 } 161 162 override void addSymbols(Scope sc) 163 { 164 getMember(0).addSymbols(sc); 165 } 166 } 167 168 //EnumMembers: 169 // EnumMember 170 // EnumMember , 171 // EnumMember , EnumMembers 172 class EnumMembers : Node 173 { 174 mixin ForwardCtor!(); 175 176 override void toD(CodeWriter writer) 177 { 178 foreach(m; members) 179 { 180 writer(m, ","); 181 writer.nl(); 182 } 183 } 184 185 bool hasSemanticSearches() 186 { 187 foreach(m; members) 188 if(m.semanticSearches > 0) 189 return true; 190 return false; 191 } 192 193 override void addSymbols(Scope sc) 194 { 195 addMemberSymbols(sc); 196 } 197 } 198 199 //EnumMember: 200 // Identifier 201 // Identifier = AssignExpression 202 // Type Identifier = AssignExpression 203 class EnumMember : Node 204 { 205 mixin ForwardCtor!(); 206 207 string ident; 208 Type type; 209 Value value; 210 211 override EnumMember clone() 212 { 213 EnumMember n = static_cast!EnumMember(super.clone()); 214 n.ident = ident; 215 return n; 216 } 217 override bool compare(const(Node) n) const 218 { 219 if(!super.compare(n)) 220 return false; 221 222 auto tn = static_cast!(typeof(this))(n); 223 return tn.ident == ident; 224 } 225 226 string getIdentifier() { return ident; } 227 Expression getInitializer() { return members.length > 0 ? getMember!Expression(members.length - 1) : null; } 228 Type getType() { return members.length > 1 ? getMember!Type(0) : null; } 229 230 override Type calcType() 231 { 232 if(type) 233 return type; 234 235 if(auto dtype = getType()) 236 type = dtype.calcType(); 237 else if(parent && parent.parent && parent.parent) 238 if(auto ed = cast(EnumDeclaration)parent.parent.parent) 239 type = ed.calcType(); 240 241 if(!type) 242 type = semanticErrorType("cannot determine type of enum member ", ident); 243 return type; 244 } 245 246 override void toD(CodeWriter writer) 247 { 248 if(Type type = getType()) 249 writer(type, " "); 250 writer.writeIdentifier(ident); 251 if(auto expr = getInitializer()) 252 writer(" = ", expr); 253 } 254 255 override void addSymbols(Scope sc) 256 { 257 sc.addSymbol(ident, this); 258 } 259 260 override Value interpret(Context sc) 261 { 262 if(value) 263 return value; 264 265 Value ival; 266 if(Expression expr = getInitializer()) 267 ival = expr.interpret(sc); 268 else if(auto em = cast(EnumMembers)parent) 269 { 270 auto n = countUntil(parent.members, this); 271 if(n > 0) 272 { 273 ival = parent.members[n - 1].interpret(sc); 274 ival = ival.opBin(sc, TOK_add, Value.create(cast(byte)1)); 275 } 276 } 277 value = calcType().createValue(sc, ival); 278 return value; 279 } 280 } 281 282 //////////////////////////////////////////////////////////////// 283 //FunctionBody: 284 // [InStatement_opt OutStatement_opt BodyStatement] outIdentifier 285 class FunctionBody : Node 286 { 287 mixin ForwardCtor!(); 288 289 Statement inStatement; 290 Statement outStatement; 291 Statement bodyStatement; 292 OutIdentifier outIdentifier; 293 294 Scope inScop; 295 Scope outScop; 296 297 override FunctionBody clone() 298 { 299 FunctionBody n = static_cast!FunctionBody(super.clone()); 300 for(int m = 0; m < members.length; m++) 301 { 302 if(members[m] is inStatement) 303 n.inStatement = static_cast!Statement(n.members[m]); 304 if(members[m] is outStatement) 305 n.outStatement = static_cast!Statement(n.members[m]); 306 if(members[m] is bodyStatement) 307 n.bodyStatement = static_cast!Statement(n.members[m]); 308 if(members[m] is outIdentifier) 309 n.outIdentifier = static_cast!OutIdentifier(n.members[m]); 310 } 311 return n; 312 } 313 314 override void toD(CodeWriter writer) 315 { 316 if(inStatement) 317 { 318 writer("in"); 319 writer.nl(); 320 writer(inStatement); 321 } 322 if(outStatement) 323 { 324 if(outIdentifier) 325 writer("out(", outIdentifier, ")"); 326 else 327 writer("out"); 328 writer.nl(); 329 writer(outStatement); 330 } 331 if(bodyStatement) 332 { 333 if(inStatement || outStatement) 334 { 335 writer("body"); 336 writer.nl(); 337 } 338 writer(bodyStatement); 339 } 340 writer.nl; // should not be written for function literals 341 } 342 343 override bool createsScope() const { return true; } 344 345 override Scope enterScope(ref Scope nscope, Scope sc) 346 { 347 if(!nscope) 348 { 349 nscope = new Scope; 350 nscope.annotations = sc.annotations; 351 nscope.attributes = sc.attributes; 352 nscope.mod = sc.mod; 353 nscope.parent = sc; 354 nscope.node = this; 355 356 ParameterList pl; 357 if(auto callable = cast(CallableNode) parent) 358 pl = callable.getParameterList(); 359 if(auto decl = cast(Decl) parent) 360 if(auto decls = decl.getDeclarators()) 361 if(auto callable = cast(CallableNode) decls.getDeclarator(0)) 362 pl = callable.getParameterList(); 363 if(pl) 364 pl.addSymbols(nscope); 365 return nscope; 366 } 367 return sc.push(nscope); 368 } 369 370 override void _semantic(Scope sc) 371 { 372 if(inStatement) 373 { 374 sc = enterScope(inScop, sc); 375 inStatement.semantic(sc); 376 sc = sc.pop(); 377 } 378 if(bodyStatement) 379 { 380 sc = super.enterScope(sc); 381 bodyStatement.semantic(sc); 382 sc = sc.pop(); 383 } 384 if(outStatement) 385 { 386 // TODO: put into scope of inStatement? 387 sc = enterScope(outScop, sc); 388 if(outIdentifier) 389 sc.addSymbol(outIdentifier.ident, outIdentifier); // TODO: create Symbol for outIdentifier 390 outStatement.semantic(sc); 391 sc = sc.pop(); 392 } 393 } 394 395 override Value interpret(Context sc) 396 { 397 Value value; 398 if(inStatement) 399 { 400 inStatement.interpret(sc); 401 } 402 if(bodyStatement) 403 { 404 value = bodyStatement.interpret(sc); 405 } 406 if(outStatement) 407 { 408 // TODO: put into scope of inStatement? 409 outStatement.interpret(sc); 410 } 411 if(!value) 412 return theVoidValue; 413 return value; 414 } 415 } 416 417 class OutIdentifier : Identifier 418 { 419 mixin ForwardCtorTok!(); 420 421 override Type calcType() 422 { 423 auto fb = cast(FunctionBody)parent; 424 if(fb) 425 { 426 auto type = fb.parent.calcType(); 427 if(auto tf = cast(TypeFunction) type) 428 return tf.getReturnType(); 429 } 430 return semanticErrorType("cannot calculate type of out identifier ", ident); 431 } 432 } 433 434 //////////////////////////////////////////////////////////////// 435 class ConditionalDeclaration : Node 436 { 437 mixin ForwardCtor!(); 438 439 Condition getCondition() { return getMember!Condition(0); } 440 Node getThenDeclarations() { return getMember(1); } 441 Node getElseDeclarations() { return getMember(2); } 442 443 override void toD(CodeWriter writer) 444 { 445 writer(getMember(0)); 446 if(id == TOK_colon) 447 writer(":"); 448 writer.nl; 449 { 450 CodeIndenter indent = CodeIndenter(writer); 451 writer(getMember(1)); 452 } 453 if(members.length > 2) 454 { 455 writer("else"); 456 writer.nl; 457 { 458 CodeIndenter indent = CodeIndenter(writer); 459 writer(getMember(2)); 460 } 461 } 462 } 463 464 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 465 { 466 Node n; 467 if(getCondition().evalCondition(sc)) 468 n = getThenDeclarations(); 469 else 470 n = getElseDeclarations(); 471 if(!n) 472 return null; 473 athis[0] = removeMember(n); 474 return athis; 475 } 476 } 477 478 class ConditionalStatement : Statement 479 { 480 mixin ForwardCtor!(); 481 482 Condition getCondition() { return getMember!Condition(0); } 483 Statement getThenStatement() { return getMember!Statement(1); } 484 Statement getElseStatement() { return getMember!Statement(2); } 485 486 override void toD(CodeWriter writer) 487 { 488 writer(getMember(0)); 489 writer.nl; 490 { 491 CodeIndenter indent = CodeIndenter(writer); 492 writer(getMember(1)); 493 } 494 if(members.length > 2) 495 { 496 writer("else"); 497 writer.nl; 498 { 499 CodeIndenter indent = CodeIndenter(writer); 500 writer(getMember(2)); 501 } 502 } 503 } 504 505 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 506 { 507 if(cast(StaticIfCondition) getCondition()) 508 return athis; 509 510 Node n; 511 if(getCondition().evalCondition(sc)) 512 n = getThenStatement(); 513 else 514 n = getElseStatement(); 515 if(!n) 516 return null; 517 athis[0] = removeMember(n); 518 return athis; 519 } 520 521 override Node[] expandNonScopeInterpret(Scope sc, Node[] athis) 522 { 523 if(!cast(StaticIfCondition) getCondition()) 524 return athis; 525 526 Node n; 527 if(getCondition().evalCondition(sc)) 528 n = getThenStatement(); 529 else 530 n = getElseStatement(); 531 if(!n) 532 return null; 533 athis[0] = n; 534 return athis; 535 } 536 } 537 538 mixin template GetIdentifierOrInteger(int pos = 0) 539 { 540 bool isIdentifier() { return getMember(pos).id == TOK_Identifier; } 541 string getIdentifier() { return getMember!Identifier(pos).ident; } 542 int getInteger() { return getMember!IntegerLiteralExpression(pos).getInt(); } 543 } 544 545 class VersionSpecification : Node 546 { 547 mixin ForwardCtor!(); 548 mixin GetIdentifierOrInteger!(); 549 550 override void toD(CodeWriter writer) 551 { 552 writer("version = ", getMember(0), ";"); 553 writer.nl; 554 } 555 556 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 557 { 558 auto mod = sc.mod; 559 if(isIdentifier()) 560 mod.specifyVersion(getIdentifier(), span.start); 561 else 562 mod.specifyVersion(getInteger()); 563 return []; 564 } 565 } 566 567 class DebugSpecification : Node 568 { 569 mixin ForwardCtor!(); 570 mixin GetIdentifierOrInteger!(); 571 572 override void toD(CodeWriter writer) 573 { 574 writer("debug = ", getMember(0), ";"); 575 writer.nl; 576 } 577 578 override Node[] expandNonScopeBlock(Scope sc, Node[] athis) 579 { 580 auto mod = sc.mod; 581 if(isIdentifier()) 582 mod.specifyDebug(getIdentifier(), span.start); 583 else 584 mod.specifyDebug(getInteger()); 585 return []; 586 } 587 } 588 589 class Condition : Node 590 { 591 mixin ForwardCtor!(); 592 593 abstract bool evalCondition(Scope sc); 594 } 595 596 class VersionCondition : Condition 597 { 598 mixin ForwardCtor!(); 599 mixin GetIdentifierOrInteger!(); 600 601 override bool evalCondition(Scope sc) 602 { 603 if(members.length == 0) 604 { 605 assert(id == TOK_unittest || id == TOK_assert); 606 if(auto mod = getModule()) 607 if(auto prj = mod.getProject()) 608 return prj.options.unittestOn || (id == TOK_assert && prj.options.debugOn); 609 return false; 610 } 611 auto mod = getModule(); 612 if(isIdentifier()) 613 return mod.versionEnabled(getIdentifier(), span.start); 614 return mod.versionEnabled(getInteger()); 615 } 616 617 override void toD(CodeWriter writer) 618 { 619 if(members.length > 0) 620 writer("version(", getMember(0), ") "); 621 else 622 { 623 assert(id == TOK_unittest); 624 writer("version(", id, ")"); 625 } 626 } 627 } 628 629 class DebugCondition : Condition 630 { 631 mixin ForwardCtor!(); 632 mixin GetIdentifierOrInteger!(); 633 634 override bool evalCondition(Scope sc) 635 { 636 auto mod = getModule(); 637 if(members.length == 0) 638 return mod.debugEnabled(); 639 if(isIdentifier()) 640 return mod.debugEnabled(getIdentifier(), span.start); 641 return mod.debugEnabled(getInteger()); 642 } 643 644 override void toD(CodeWriter writer) 645 { 646 if(members.length > 0) 647 writer("debug(", getMember(0), ") "); 648 else 649 writer("debug "); 650 } 651 } 652 653 class StaticIfCondition : Condition 654 { 655 mixin ForwardCtor!(); 656 657 override bool evalCondition(Scope sc) 658 { 659 Context ctx = new Context(nullContext); 660 ctx.scop = sc; 661 return getMember!Expression(0).interpret(ctx).toBool(); 662 } 663 664 override void toD(CodeWriter writer) 665 { 666 writer("static if(", getMember(0), ")"); 667 } 668 } 669 670 //Aggregate: 671 // [ArgumentList] 672 class StaticAssert : Statement 673 { 674 mixin ForwardCtor!(); 675 676 ArgumentList getArgumentList() { return getMember!ArgumentList(0); } 677 678 override void toD(CodeWriter writer) 679 { 680 if(writer.writeImplementations) 681 { 682 writer("static assert(", getMember(0), ");"); 683 writer.nl(); 684 } 685 } 686 override void toC(CodeWriter writer) 687 { 688 } 689 690 override void _semantic(Scope sc) 691 { 692 auto args = getArgumentList(); 693 auto expr = args.getMember!Expression(0); 694 if(!expr.interpretCatch(globalContext).toBool()) 695 { 696 string txt; 697 for(int a = 1; a < args.members.length; a++) 698 { 699 auto arg = args.getMember!Expression(a); 700 txt ~= arg.interpret(globalContext).toMixin(); 701 } 702 if(txt.length == 0) 703 txt = "static assertion " ~ writeD(expr) ~ " failed"; 704 semanticErrorPos(span.start, txt); 705 } 706 } 707 708 override Value interpret(Context sc) 709 { 710 return null; // "execution" done in _sementic 711 } 712 }