Mercurial > projects > ddmd
comparison dmd/BinExp.d @ 174:af724d3510d7
lot os toCBuffer methods implemented
moved shared Type.* stuff into Global
author | korDen |
---|---|
date | Sun, 10 Oct 2010 03:47:23 +0400 |
parents | 14feb7ae01a6 |
children | 94b6033c07f3 |
comparison
equal
deleted
inserted
replaced
173:d237b38b5858 | 174:af724d3510d7 |
---|---|
275 else if (i1) | 275 else if (i1) |
276 { | 276 { |
277 goto Lt1; | 277 goto Lt1; |
278 } | 278 } |
279 else if (t1.ty == TY.Tclass && t2.ty == TY.Tclass) | 279 else if (t1.ty == TY.Tclass && t2.ty == TY.Tclass) |
280 { | 280 { |
281 TypeClass tc1 = cast(TypeClass)t1; | 281 TypeClass tc1 = cast(TypeClass)t1; |
282 TypeClass tc2 = cast(TypeClass)t2; | 282 TypeClass tc2 = cast(TypeClass)t2; |
283 | 283 |
284 /* Pick 'tightest' type | 284 /* Pick 'tightest' type |
285 */ | 285 */ |
397 { | 397 { |
398 super(loc, op, size); | 398 super(loc, op, size); |
399 this.e1 = e1; | 399 this.e1 = e1; |
400 this.e2 = e2; | 400 this.e2 = e2; |
401 } | 401 } |
402 | 402 |
403 override Expression syntaxCopy() | 403 override Expression syntaxCopy() |
404 { | 404 { |
405 BinExp e = cast(BinExp)copy(); | 405 BinExp e = cast(BinExp)copy(); |
406 e.type = null; | 406 e.type = null; |
407 e.e1 = e.e1.syntaxCopy(); | 407 e.e1 = e.e1.syntaxCopy(); |
427 error("%s has no value", e2.toChars()); | 427 error("%s has no value", e2.toChars()); |
428 e2.type = Type.terror; | 428 e2.type = Type.terror; |
429 } | 429 } |
430 return this; | 430 return this; |
431 } | 431 } |
432 | 432 |
433 Expression semanticp(Scope sc) | 433 Expression semanticp(Scope sc) |
434 { | 434 { |
435 BinExp.semantic(sc); | 435 BinExp.semantic(sc); |
436 | 436 |
437 e1 = resolveProperties(sc, e1); | 437 e1 = resolveProperties(sc, e1); |
438 e2 = resolveProperties(sc, e2); | 438 e2 = resolveProperties(sc, e2); |
439 return this; | 439 return this; |
440 } | 440 } |
441 | 441 |
442 /*************************** | 442 /*************************** |
443 * Common semantic routine for some xxxAssignExp's. | 443 * Common semantic routine for some xxxAssignExp's. |
444 */ | 444 */ |
445 Expression commonSemanticAssign(Scope sc) | 445 Expression commonSemanticAssign(Scope sc) |
446 { | 446 { |
459 { | 459 { |
460 e = ArrayLengthExp.rewriteOpAssign(this); | 460 e = ArrayLengthExp.rewriteOpAssign(this); |
461 e = e.semantic(sc); | 461 e = e.semantic(sc); |
462 return e; | 462 return e; |
463 } | 463 } |
464 | 464 |
465 if (e1.op == TOKslice) | 465 if (e1.op == TOKslice) |
466 { | 466 { |
467 // T[] op= ... | 467 // T[] op= ... |
468 typeCombine(sc); | 468 typeCombine(sc); |
469 type = e1.type; | 469 type = e1.type; |
470 return arrayOp(sc); | 470 return arrayOp(sc); |
471 } | 471 } |
506 { | 506 { |
507 e = ArrayLengthExp.rewriteOpAssign(this); | 507 e = ArrayLengthExp.rewriteOpAssign(this); |
508 e = e.semantic(sc); | 508 e = e.semantic(sc); |
509 return e; | 509 return e; |
510 } | 510 } |
511 | 511 |
512 if (e1.op == TOK.TOKslice) | 512 if (e1.op == TOK.TOKslice) |
513 { // T[] op= ... | 513 { // T[] op= ... |
514 typeCombine(sc); | 514 typeCombine(sc); |
515 type = e1.type; | 515 type = e1.type; |
516 return arrayOp(sc); | 516 return arrayOp(sc); |
529 e2.checkIntegral(); | 529 e2.checkIntegral(); |
530 } | 530 } |
531 | 531 |
532 return this; | 532 return this; |
533 } | 533 } |
534 | 534 |
535 override bool checkSideEffect(int flag) | 535 override bool checkSideEffect(int flag) |
536 { | 536 { |
537 switch (op) { | 537 switch (op) { |
538 case TOK.TOKplusplus: | 538 case TOK.TOKplusplus: |
539 case TOK.TOKminusminus: | 539 case TOK.TOKminusminus: |
559 | 559 |
560 default: | 560 default: |
561 return Expression.checkSideEffect(flag); | 561 return Expression.checkSideEffect(flag); |
562 } | 562 } |
563 } | 563 } |
564 | 564 |
565 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) | 565 override void toCBuffer(OutBuffer buf, HdrGenState* hgs) |
566 { | 566 { |
567 expToCBuffer(buf, hgs, e1, precedence[op]); | 567 expToCBuffer(buf, hgs, e1, precedence[op]); |
568 buf.writeByte(' '); | 568 buf.writeByte(' '); |
569 buf.writestring(Token.toChars(op)); | 569 buf.writestring(Token.toChars(op)); |
579 ulong stride; | 579 ulong stride; |
580 Type t1b = e1.type.toBasetype(); | 580 Type t1b = e1.type.toBasetype(); |
581 Type t2b = e2.type.toBasetype(); | 581 Type t2b = e2.type.toBasetype(); |
582 | 582 |
583 if (t1b.ty == Tpointer && t2b.isintegral()) | 583 if (t1b.ty == Tpointer && t2b.isintegral()) |
584 { | 584 { |
585 // Need to adjust operator by the stride | 585 // Need to adjust operator by the stride |
586 // Replace (ptr + int) with (ptr + (int * stride)) | 586 // Replace (ptr + int) with (ptr + (int * stride)) |
587 Type t = Type.tptrdiff_t; | 587 Type t = Type.tptrdiff_t; |
588 | 588 |
589 stride = t1b.nextOf().size(loc); | 589 stride = t1b.nextOf().size(loc); |
592 e2 = new MulExp(loc, e2, new IntegerExp(Loc(0), stride, t)); | 592 e2 = new MulExp(loc, e2, new IntegerExp(Loc(0), stride, t)); |
593 e2.type = t; | 593 e2.type = t; |
594 type = e1.type; | 594 type = e1.type; |
595 } | 595 } |
596 else if (t2b.ty == Tpointer && t1b.isintegral()) | 596 else if (t2b.ty == Tpointer && t1b.isintegral()) |
597 { | 597 { |
598 // Need to adjust operator by the stride | 598 // Need to adjust operator by the stride |
599 // Replace (int + ptr) with (ptr + (int * stride)) | 599 // Replace (int + ptr) with (ptr + (int * stride)) |
600 Type t = Type.tptrdiff_t; | 600 Type t = Type.tptrdiff_t; |
601 Expression e; | 601 Expression e; |
602 | 602 |
611 e1 = e2; | 611 e1 = e2; |
612 e2 = e; | 612 e2 = e; |
613 } | 613 } |
614 return this; | 614 return this; |
615 } | 615 } |
616 | 616 |
617 /************************************ | 617 /************************************ |
618 * Bring leaves to common type. | 618 * Bring leaves to common type. |
619 */ | 619 */ |
620 Expression typeCombine(Scope sc) | 620 Expression typeCombine(Scope sc) |
621 { | 621 { |
661 { | 661 { |
662 long i2 = e2.toInteger(); | 662 long i2 = e2.toInteger(); |
663 ulong sz = e1.type.size() * 8; | 663 ulong sz = e1.type.size() * 8; |
664 | 664 |
665 if (i2 < 0 || i2 > sz) | 665 if (i2 < 0 || i2 > sz) |
666 { | 666 { |
667 error("shift assign by %jd is outside the range 0..%zu", i2, sz); | 667 error("shift assign by %jd is outside the range 0..%zu", i2, sz); |
668 e2 = new IntegerExp(0); | 668 e2 = new IntegerExp(0); |
669 } | 669 } |
670 } | 670 } |
671 } | 671 } |
675 | 675 |
676 bool isunsigned() | 676 bool isunsigned() |
677 { | 677 { |
678 return e1.type.isunsigned() || e2.type.isunsigned(); | 678 return e1.type.isunsigned() || e2.type.isunsigned(); |
679 } | 679 } |
680 | 680 |
681 void incompatibleTypes() | 681 void incompatibleTypes() |
682 { | 682 { |
683 error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", | 683 error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", |
684 e1.toChars(), Token.toChars(op), e2.toChars(), | 684 e1.toChars(), Token.toChars(op), e2.toChars(), |
685 e1.type.toChars(), e2.type.toChars()); | 685 e1.type.toChars(), e2.type.toChars()); |
759 return e; | 759 return e; |
760 | 760 |
761 Lcant: | 761 Lcant: |
762 return EXP_CANT_INTERPRET; | 762 return EXP_CANT_INTERPRET; |
763 } | 763 } |
764 | 764 |
765 Expression interpretAssignCommon(InterState istate, Expression function(Type, Expression, Expression) fp, int post = 0) | 765 Expression interpretAssignCommon(InterState istate, Expression function(Type, Expression, Expression) fp, int post = 0) |
766 { | 766 { |
767 version (LOG) | 767 version (LOG) |
768 { | 768 { |
769 writef("BinExp.interpretAssignCommon() %.*s\n", toChars()); | 769 writef("BinExp.interpretAssignCommon() %.*s\n", toChars()); |
772 Expression e1 = this.e1; | 772 Expression e1 = this.e1; |
773 | 773 |
774 if (fp) | 774 if (fp) |
775 { | 775 { |
776 if (e1.op == TOKcast) | 776 if (e1.op == TOKcast) |
777 { | 777 { |
778 CastExp ce = cast(CastExp)e1; | 778 CastExp ce = cast(CastExp)e1; |
779 e1 = ce.e1; | 779 e1 = ce.e1; |
780 } | 780 } |
781 } | 781 } |
782 if (e1 is EXP_CANT_INTERPRET) | 782 if (e1 is EXP_CANT_INTERPRET) |
783 return e1; | 783 return e1; |
784 Expression e2 = this.e2.interpret(istate); | 784 Expression e2 = this.e2.interpret(istate); |
785 if (e2 is EXP_CANT_INTERPRET) | 785 if (e2 is EXP_CANT_INTERPRET) |
786 return e2; | 786 return e2; |
787 | 787 |
788 // Chase down rebinding of out and ref. | 788 // Chase down rebinding of out and ref. |
789 if (e1.op == TOKvar) | 789 if (e1.op == TOKvar) |
790 { | 790 { |
791 VarExp ve = cast(VarExp)e1; | 791 VarExp ve = cast(VarExp)e1; |
792 VarDeclaration v = ve.var.isVarDeclaration(); | 792 VarDeclaration v = ve.var.isVarDeclaration(); |
793 if (v && v.value && v.value.op == TOKvar) | 793 if (v && v.value && v.value.op == TOKvar) |
794 { | 794 { |
795 VarExp ve2 = cast(VarExp)v.value; | 795 VarExp ve2 = cast(VarExp)v.value; |
796 if (ve2.var.isSymbolDeclaration()) | 796 if (ve2.var.isSymbolDeclaration()) |
797 { | 797 { |
798 // This can happen if v is a struct initialized to | 798 // This can happen if v is a struct initialized to |
799 // 0 using an __initZ SymbolDeclaration from | 799 // 0 using an __initZ SymbolDeclaration from |
800 // TypeStruct.defaultInit() | 800 // TypeStruct.defaultInit() |
801 } | 801 } |
802 else | 802 else |
803 e1 = v.value; | 803 e1 = v.value; |
804 } | 804 } |
805 else if (v && v.value && (v.value.op==TOKindex || v.value.op == TOKdotvar)) | 805 else if (v && v.value && (v.value.op==TOKindex || v.value.op == TOKdotvar)) |
806 { | 806 { |
807 // It is no longer a TOKvar, eg when a[4] is passed by ref. | 807 // It is no longer a TOKvar, eg when a[4] is passed by ref. |
808 e1 = v.value; | 808 e1 = v.value; |
809 } | 809 } |
810 } | 810 } |
811 | 811 |
812 // To reduce code complexity of handling dotvar expressions, | 812 // To reduce code complexity of handling dotvar expressions, |
813 // extract the aggregate now. | 813 // extract the aggregate now. |
814 Expression aggregate; | 814 Expression aggregate; |
815 if (e1.op == TOKdotvar) { | 815 if (e1.op == TOKdotvar) { |
816 aggregate = (cast(DotVarExp)e1).e1; | 816 aggregate = (cast(DotVarExp)e1).e1; |
817 // Get rid of 'this'. | 817 // Get rid of 'this'. |
818 if (aggregate.op == TOKthis && istate.localThis) | 818 if (aggregate.op == TOKthis && istate.localThis) |
819 aggregate = istate.localThis; | 819 aggregate = istate.localThis; |
820 } | 820 } |
821 | 821 |
822 /* Assignment to variable of the form: | 822 /* Assignment to variable of the form: |
823 * v = e2 | 823 * v = e2 |
824 */ | 824 */ |
825 if (e1.op == TOKvar) | 825 if (e1.op == TOKvar) |
826 { | 826 { |
827 VarExp ve = cast(VarExp)e1; | 827 VarExp ve = cast(VarExp)e1; |
828 VarDeclaration v = ve.var.isVarDeclaration(); | 828 VarDeclaration v = ve.var.isVarDeclaration(); |
829 assert(v); | 829 assert(v); |
830 if (v && !v.isCTFE()) | 830 if (v && !v.isCTFE()) |
831 { | 831 { |
832 // Can't modify global or static data | 832 // Can't modify global or static data |
833 error("%s cannot be modified at compile time", v.toChars()); | 833 error("%s cannot be modified at compile time", v.toChars()); |
834 return EXP_CANT_INTERPRET; | 834 return EXP_CANT_INTERPRET; |
835 } | 835 } |
836 if (v && v.isCTFE()) | 836 if (v && v.isCTFE()) |
837 { | 837 { |
838 Expression ev = v.value; | 838 Expression ev = v.value; |
839 if (fp && !ev) | 839 if (fp && !ev) |
840 { | 840 { |
841 error("variable %s is used before initialization", v.toChars()); | 841 error("variable %s is used before initialization", v.toChars()); |
842 return e; | 842 return e; |
843 } | 843 } |
844 if (fp) | 844 if (fp) |
845 e2 = (*fp)(v.type, ev, e2); | 845 e2 = (*fp)(v.type, ev, e2); |
846 else | 846 else |
847 { | 847 { |
848 /* Look for special case of struct being initialized with 0. | 848 /* Look for special case of struct being initialized with 0. |
849 */ | 849 */ |
850 if (v.type.toBasetype().ty == Tstruct && e2.op == TOKint64) | 850 if (v.type.toBasetype().ty == Tstruct && e2.op == TOKint64) |
851 { | 851 { |
852 e2 = v.type.defaultInitLiteral(Loc(0)); | 852 e2 = v.type.defaultInitLiteral(Loc(0)); |
860 v.value = e2; | 860 v.value = e2; |
861 e = Cast(type, type, post ? ev : e2); | 861 e = Cast(type, type, post ? ev : e2); |
862 } | 862 } |
863 } | 863 } |
864 else if (e1.op == TOKdotvar && aggregate.op == TOKdotvar) | 864 else if (e1.op == TOKdotvar && aggregate.op == TOKdotvar) |
865 { | 865 { |
866 // eg v.u.var = e2, v[3].u.var = e2, etc. | 866 // eg v.u.var = e2, v[3].u.var = e2, etc. |
867 error("Nested struct assignment %s is not yet supported in CTFE", toChars()); | 867 error("Nested struct assignment %s is not yet supported in CTFE", toChars()); |
868 } | 868 } |
869 /* Assignment to struct member of the form: | 869 /* Assignment to struct member of the form: |
870 * v.var = e2 | 870 * v.var = e2 |
871 */ | 871 */ |
872 else if (e1.op == TOKdotvar && aggregate.op == TOKvar) | 872 else if (e1.op == TOKdotvar && aggregate.op == TOKvar) |
873 { | 873 { |
874 VarDeclaration v = (cast(VarExp)aggregate).var.isVarDeclaration(); | 874 VarDeclaration v = (cast(VarExp)aggregate).var.isVarDeclaration(); |
875 | 875 |
876 if (!v.isCTFE()) | 876 if (!v.isCTFE()) |
877 { | 877 { |
878 // Can't modify global or static data | 878 // Can't modify global or static data |
879 error("%s cannot be modified at compile time", v.toChars()); | 879 error("%s cannot be modified at compile time", v.toChars()); |
880 return EXP_CANT_INTERPRET; | 880 return EXP_CANT_INTERPRET; |
881 } else { | 881 } else { |
882 // Chase down rebinding of out and ref | 882 // Chase down rebinding of out and ref |
883 if (v.value && v.value.op == TOKvar) | 883 if (v.value && v.value.op == TOKvar) |
884 { | 884 { |
885 VarExp ve2 = cast(VarExp)v.value; | 885 VarExp ve2 = cast(VarExp)v.value; |
886 if (ve2.var.isSymbolDeclaration()) | 886 if (ve2.var.isSymbolDeclaration()) |
887 { | 887 { |
888 // This can happen if v is a struct initialized to | 888 // This can happen if v is a struct initialized to |
889 // 0 using an __initZ SymbolDeclaration from | 889 // 0 using an __initZ SymbolDeclaration from |
890 // TypeStruct.defaultInit() | 890 // TypeStruct.defaultInit() |
891 } | 891 } |
892 else | 892 else |
893 v = ve2.var.isVarDeclaration(); | 893 v = ve2.var.isVarDeclaration(); |
894 assert(v); | 894 assert(v); |
895 } | 895 } |
896 } | 896 } |
897 if (fp && !v.value) | 897 if (fp && !v.value) |
898 { | 898 { |
899 error("variable %s is used before initialization", v.toChars()); | 899 error("variable %s is used before initialization", v.toChars()); |
900 return e; | 900 return e; |
901 } | 901 } |
902 if (v.value is null && v.init.isVoidInitializer()) | 902 if (v.value is null && v.init.isVoidInitializer()) |
903 { | 903 { |
904 /* Since a void initializer initializes to undefined | 904 /* Since a void initializer initializes to undefined |
905 * values, it is valid here to use the default initializer. | 905 * values, it is valid here to use the default initializer. |
906 * No attempt is made to determine if someone actually relies | 906 * No attempt is made to determine if someone actually relies |
907 * on the void value - to do that we'd need a VoidExp. | 907 * on the void value - to do that we'd need a VoidExp. |
908 * That's probably a good enhancement idea. | 908 * That's probably a good enhancement idea. |
944 } | 944 } |
945 /* Assignment to struct member of the form: | 945 /* Assignment to struct member of the form: |
946 * *(symoffexp) = e2 | 946 * *(symoffexp) = e2 |
947 */ | 947 */ |
948 else if (e1.op == TOKstar && (cast(PtrExp)e1).e1.op == TOKsymoff) | 948 else if (e1.op == TOKstar && (cast(PtrExp)e1).e1.op == TOKsymoff) |
949 { | 949 { |
950 SymOffExp soe = cast(SymOffExp)(cast(PtrExp)e1).e1; | 950 SymOffExp soe = cast(SymOffExp)(cast(PtrExp)e1).e1; |
951 VarDeclaration v = soe.var.isVarDeclaration(); | 951 VarDeclaration v = soe.var.isVarDeclaration(); |
952 | 952 |
953 if (!v.isCTFE()) | 953 if (!v.isCTFE()) |
954 { | 954 { |
955 error("%s cannot be modified at compile time", v.toChars()); | 955 error("%s cannot be modified at compile time", v.toChars()); |
956 return EXP_CANT_INTERPRET; | 956 return EXP_CANT_INTERPRET; |
957 } | 957 } |
958 if (fp && !v.value) | 958 if (fp && !v.value) |
959 { | 959 { |
960 error("variable %s is used before initialization", v.toChars()); | 960 error("variable %s is used before initialization", v.toChars()); |
961 return e; | 961 return e; |
962 } | 962 } |
963 Expression vie = v.value; | 963 Expression vie = v.value; |
964 if (vie.op == TOKvar) | 964 if (vie.op == TOKvar) |
992 } | 992 } |
993 /* Assignment to array element of the form: | 993 /* Assignment to array element of the form: |
994 * a[i] = e2 | 994 * a[i] = e2 |
995 */ | 995 */ |
996 else if (e1.op == TOKindex && (cast(IndexExp)e1).e1.op == TOKvar) | 996 else if (e1.op == TOKindex && (cast(IndexExp)e1).e1.op == TOKvar) |
997 { | 997 { |
998 IndexExp ie = cast(IndexExp)e1; | 998 IndexExp ie = cast(IndexExp)e1; |
999 VarExp ve = cast(VarExp)ie.e1; | 999 VarExp ve = cast(VarExp)ie.e1; |
1000 VarDeclaration v = ve.var.isVarDeclaration(); | 1000 VarDeclaration v = ve.var.isVarDeclaration(); |
1001 if (!v || !v.isCTFE()) | 1001 if (!v || !v.isCTFE()) |
1002 { | 1002 { |
1005 } | 1005 } |
1006 if (v.value && v.value.op == TOKvar) | 1006 if (v.value && v.value.op == TOKvar) |
1007 { | 1007 { |
1008 VarExp ve2 = cast(VarExp)v.value; | 1008 VarExp ve2 = cast(VarExp)v.value; |
1009 if (ve2.var.isSymbolDeclaration()) | 1009 if (ve2.var.isSymbolDeclaration()) |
1010 { | 1010 { |
1011 // This can happen if v is a struct initialized to | 1011 // This can happen if v is a struct initialized to |
1012 // 0 using an __initZ SymbolDeclaration from | 1012 // 0 using an __initZ SymbolDeclaration from |
1013 // TypeStruct.defaultInit() | 1013 // TypeStruct.defaultInit() |
1014 } | 1014 } |
1015 else | 1015 else |
1017 assert(v); | 1017 assert(v); |
1018 } | 1018 } |
1019 if (!v.value) | 1019 if (!v.value) |
1020 { | 1020 { |
1021 if (fp) | 1021 if (fp) |
1022 { | 1022 { |
1023 error("variable %s is used before initialization", v.toChars()); | 1023 error("variable %s is used before initialization", v.toChars()); |
1024 return e; | 1024 return e; |
1025 } | 1025 } |
1026 | 1026 |
1027 Type t = v.type.toBasetype(); | 1027 Type t = v.type.toBasetype(); |
1081 e2 = (*fp)(type, ev, e2); | 1081 e2 = (*fp)(type, ev, e2); |
1082 else | 1082 else |
1083 e2 = Cast(type, type, e2); | 1083 e2 = Cast(type, type, e2); |
1084 if (e2 is EXP_CANT_INTERPRET) | 1084 if (e2 is EXP_CANT_INTERPRET) |
1085 return e2; | 1085 return e2; |
1086 | 1086 |
1087 addVarToInterstate(istate, v); | 1087 addVarToInterstate(istate, v); |
1088 if (ae) | 1088 if (ae) |
1089 { | 1089 { |
1090 /* Create new array literal reflecting updated elem | 1090 /* Create new array literal reflecting updated elem |
1091 */ | 1091 */ |
1101 Expressions keysx = aae.keys; | 1101 Expressions keysx = aae.keys; |
1102 Expressions valuesx = new Expressions(); | 1102 Expressions valuesx = new Expressions(); |
1103 valuesx.setDim(aae.values.dim); | 1103 valuesx.setDim(aae.values.dim); |
1104 int updated = 0; | 1104 int updated = 0; |
1105 for (size_t j = valuesx.dim; j; ) | 1105 for (size_t j = valuesx.dim; j; ) |
1106 { | 1106 { |
1107 j--; | 1107 j--; |
1108 Expression ekey = aae.keys[j]; | 1108 Expression ekey = aae.keys[j]; |
1109 Expression ex = Equal(TOKequal, Type.tbool, ekey, index); | 1109 Expression ex = Equal(TOKequal, Type.tbool, ekey, index); |
1110 if (ex is EXP_CANT_INTERPRET) | 1110 if (ex is EXP_CANT_INTERPRET) |
1111 return EXP_CANT_INTERPRET; | 1111 return EXP_CANT_INTERPRET; |
1112 if (ex.isBool(true)) | 1112 if (ex.isBool(true)) |
1113 { | 1113 { |
1114 valuesx[j] = e2; | 1114 valuesx[j] = e2; |
1115 updated = 1; | 1115 updated = 1; |
1116 } | 1116 } |
1117 else | 1117 else |
1118 valuesx[j] = aae.values[j]; | 1118 valuesx[j] = aae.values[j]; |
1119 } | 1119 } |
1120 if (!updated) | 1120 if (!updated) |
1121 { | 1121 { |
1122 // Append index/e2 to keysx[]/valuesx[] | 1122 // Append index/e2 to keysx[]/valuesx[] |
1123 valuesx.push(e2); | 1123 valuesx.push(e2); |
1124 keysx = keysx.copy(); | 1124 keysx = keysx.copy(); |
1125 keysx.push(index); | 1125 keysx.push(index); |
1126 } | 1126 } |
1154 else | 1154 else |
1155 assert(0); | 1155 assert(0); |
1156 | 1156 |
1157 e = Cast(type, type, post ? ev : e2); | 1157 e = Cast(type, type, post ? ev : e2); |
1158 } | 1158 } |
1159 | 1159 |
1160 /* Assignment to struct element in array, of the form: | 1160 /* Assignment to struct element in array, of the form: |
1161 * a[i].var = e2 | 1161 * a[i].var = e2 |
1162 */ | 1162 */ |
1163 else if (e1.op == TOKdotvar && aggregate.op == TOKindex && | 1163 else if (e1.op == TOKdotvar && aggregate.op == TOKindex && |
1164 (cast(IndexExp)aggregate).e1.op == TOKvar) | 1164 (cast(IndexExp)aggregate).e1.op == TOKvar) |
1212 return EXP_CANT_INTERPRET; | 1212 return EXP_CANT_INTERPRET; |
1213 | 1213 |
1214 int elemi = cast(int)index.toInteger(); | 1214 int elemi = cast(int)index.toInteger(); |
1215 if (elemi >= ae.elements.dim) | 1215 if (elemi >= ae.elements.dim) |
1216 { | 1216 { |
1217 error("array index %d is out of bounds %s[0..%d]", elemi, | 1217 error("array index %d is out of bounds %s[0..%d]", elemi, |
1218 v.toChars(), ae.elements.dim); | 1218 v.toChars(), ae.elements.dim); |
1219 return EXP_CANT_INTERPRET; | 1219 return EXP_CANT_INTERPRET; |
1220 } | 1220 } |
1221 // Get old element | 1221 // Get old element |
1222 auto vie = ae.elements[elemi]; | 1222 auto vie = ae.elements[elemi]; |
1230 return EXP_CANT_INTERPRET; | 1230 return EXP_CANT_INTERPRET; |
1231 | 1231 |
1232 int fieldi = se.getFieldIndex(type, vf.offset); | 1232 int fieldi = se.getFieldIndex(type, vf.offset); |
1233 if (fieldi == -1) | 1233 if (fieldi == -1) |
1234 return EXP_CANT_INTERPRET; | 1234 return EXP_CANT_INTERPRET; |
1235 | 1235 |
1236 Expression ev = se.getField(type, vf.offset); | 1236 Expression ev = se.getField(type, vf.offset); |
1237 if (fp) | 1237 if (fp) |
1238 e2 = (*fp)(type, ev, e2); | 1238 e2 = (*fp)(type, ev, e2); |
1239 else | 1239 else |
1240 e2 = Cast(type, type, e2); | 1240 e2 = Cast(type, type, e2); |
1265 // Chase down rebinding of out and ref | 1265 // Chase down rebinding of out and ref |
1266 if (v.value && v.value.op == TOKvar) | 1266 if (v.value && v.value.op == TOKvar) |
1267 { | 1267 { |
1268 VarExp ve2 = cast(VarExp)v.value; | 1268 VarExp ve2 = cast(VarExp)v.value; |
1269 if (ve2.var.isSymbolDeclaration()) | 1269 if (ve2.var.isSymbolDeclaration()) |
1270 { | 1270 { |
1271 // This can happen if v is a struct initialized to | 1271 // This can happen if v is a struct initialized to |
1272 // 0 using an __initZ SymbolDeclaration from | 1272 // 0 using an __initZ SymbolDeclaration from |
1273 // TypeStruct.defaultInit() | 1273 // TypeStruct.defaultInit() |
1274 } | 1274 } |
1275 else | 1275 else |
1296 if (lower is EXP_CANT_INTERPRET) | 1296 if (lower is EXP_CANT_INTERPRET) |
1297 return EXP_CANT_INTERPRET; | 1297 return EXP_CANT_INTERPRET; |
1298 } | 1298 } |
1299 Type t = v.type.toBasetype(); | 1299 Type t = v.type.toBasetype(); |
1300 size_t dim; | 1300 size_t dim; |
1301 if (t.ty == Tsarray) | 1301 if (t.ty == Tsarray) |
1302 dim = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); | 1302 dim = cast(size_t)(cast(TypeSArray)t).dim.toInteger(); |
1303 else if (t.ty == Tarray) | 1303 else if (t.ty == Tarray) |
1304 { | 1304 { |
1305 if (!v.value || v.value.op == TOKnull) | 1305 if (!v.value || v.value.op == TOKnull) |
1306 { | 1306 { |
1344 } | 1344 } |
1345 | 1345 |
1346 if (e2.op == TOKarrayliteral) | 1346 if (e2.op == TOKarrayliteral) |
1347 { | 1347 { |
1348 // Static array assignment from literal | 1348 // Static array assignment from literal |
1349 ArrayLiteralExp ae = cast(ArrayLiteralExp)e2; | 1349 ArrayLiteralExp ae = cast(ArrayLiteralExp)e2; |
1350 if (ae.elements.dim != (upperbound - lowerbound)) | 1350 if (ae.elements.dim != (upperbound - lowerbound)) |
1351 { | 1351 { |
1352 error("Array length mismatch assigning [0..%d] to [%d..%d]", ae.elements.dim, lowerbound, upperbound); | 1352 error("Array length mismatch assigning [0..%d] to [%d..%d]", ae.elements.dim, lowerbound, upperbound); |
1353 return e; | 1353 return e; |
1354 } | 1354 } |
1370 else | 1370 else |
1371 { | 1371 { |
1372 // value[] = value[0..lower] ~ ae ~ value[upper..$] | 1372 // value[] = value[0..lower] ~ ae ~ value[upper..$] |
1373 existing.elements = spliceElements(existing.elements, createBlockDuplicatedArrayLiteral(v.type, e2, upperbound-lowerbound).elements, lowerbound); | 1373 existing.elements = spliceElements(existing.elements, createBlockDuplicatedArrayLiteral(v.type, e2, upperbound-lowerbound).elements, lowerbound); |
1374 v.value = existing; | 1374 v.value = existing; |
1375 } | 1375 } |
1376 return e2; | 1376 return e2; |
1377 } | 1377 } |
1378 else if (e2.op == TOKstring) | 1378 else if (e2.op == TOKstring) |
1379 { | 1379 { |
1380 StringExp se = cast(StringExp)e2; | 1380 StringExp se = cast(StringExp)e2; |
1405 version(DMDV2) | 1405 version(DMDV2) |
1406 override bool canThrow() | 1406 override bool canThrow() |
1407 { | 1407 { |
1408 return e1.canThrow() || e2.canThrow(); | 1408 return e1.canThrow() || e2.canThrow(); |
1409 } | 1409 } |
1410 | 1410 |
1411 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary | 1411 // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary |
1412 void checkComplexMulAssign() | 1412 void checkComplexMulAssign() |
1413 { | 1413 { |
1414 // Any multiplication by an imaginary or complex number yields a complex result. | 1414 // Any multiplication by an imaginary or complex number yields a complex result. |
1415 // r *= c, i*=c, r*=i, i*=i are all forbidden operations. | 1415 // r *= c, i*=c, r*=i, i*=i are all forbidden operations. |
1416 string opstr = Token.toChars(op); | 1416 string opstr = Token.toChars(op); |
1417 if ( e1.type.isreal() && e2.type.iscomplex()) | 1417 if ( e1.type.isreal() && e2.type.iscomplex()) |
1418 { | 1418 { |
1419 error("%s %s %s is undefined. Did you mean %s %s %s.re ?", | 1419 error("%s %s %s is undefined. Did you mean %s %s %s.re ?", |
1420 e1.type.toChars(), opstr, e2.type.toChars(), | 1420 e1.type.toChars(), opstr, e2.type.toChars(), |
1421 e1.type.toChars(), opstr, e2.type.toChars()); | 1421 e1.type.toChars(), opstr, e2.type.toChars()); |
1422 } | 1422 } |
1423 else if (e1.type.isimaginary() && e2.type.iscomplex()) | 1423 else if (e1.type.isimaginary() && e2.type.iscomplex()) |
1424 { | 1424 { |
1425 error("%s %s %s is undefined. Did you mean %s %s %s.im ?", | 1425 error("%s %s %s is undefined. Did you mean %s %s %s.im ?", |
1437 void checkComplexAddAssign() | 1437 void checkComplexAddAssign() |
1438 { | 1438 { |
1439 // Addition or subtraction of a real and an imaginary is a complex result. | 1439 // Addition or subtraction of a real and an imaginary is a complex result. |
1440 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. | 1440 // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. |
1441 if ( (e1.type.isreal() && (e2.type.isimaginary() || e2.type.iscomplex())) || | 1441 if ( (e1.type.isreal() && (e2.type.isimaginary() || e2.type.iscomplex())) || |
1442 (e1.type.isimaginary() && (e2.type.isreal() || e2.type.iscomplex())) | 1442 (e1.type.isimaginary() && (e2.type.isreal() || e2.type.iscomplex())) |
1443 ) | 1443 ) |
1444 { | 1444 { |
1445 error("%s %s %s is undefined (result is complex)", | 1445 error("%s %s %s is undefined (result is complex)", |
1446 e1.type.toChars(), Token.toChars(op), e2.type.toChars()); | 1446 e1.type.toChars(), Token.toChars(op), e2.type.toChars()); |
1447 } | 1447 } |
1452 * Construct the array operation expression. | 1452 * Construct the array operation expression. |
1453 */ | 1453 */ |
1454 Expression arrayOp(Scope sc) | 1454 Expression arrayOp(Scope sc) |
1455 { | 1455 { |
1456 //printf("BinExp.arrayOp() %s\n", toChars()); | 1456 //printf("BinExp.arrayOp() %s\n", toChars()); |
1457 | 1457 |
1458 if (type.toBasetype().nextOf().toBasetype().ty == Tvoid) | 1458 if (type.toBasetype().nextOf().toBasetype().ty == Tvoid) |
1459 { | 1459 { |
1460 error("Cannot perform array operations on void[] arrays"); | 1460 error("Cannot perform array operations on void[] arrays"); |
1461 return new ErrorExp(); | 1461 return new ErrorExp(); |
1462 } | 1462 } |
1463 | 1463 |
1464 auto arguments = new Expressions(); | 1464 auto arguments = new Expressions(); |
1465 | 1465 |
1466 /* The expression to generate an array operation for is mangled | 1466 /* The expression to generate an array operation for is mangled |
1467 * into a name to use as the array operation function name. | 1467 * into a name to use as the array operation function name. |
1468 * Mangle in the operands and operators in RPN order, and type. | 1468 * Mangle in the operands and operators in RPN order, and type. |
1738 | 1738 |
1739 override int inlineCost(InlineCostState* ics) | 1739 override int inlineCost(InlineCostState* ics) |
1740 { | 1740 { |
1741 return 1 + e1.inlineCost(ics) + e2.inlineCost(ics); | 1741 return 1 + e1.inlineCost(ics) + e2.inlineCost(ics); |
1742 } | 1742 } |
1743 | 1743 |
1744 override Expression doInline(InlineDoState ids) | 1744 override Expression doInline(InlineDoState ids) |
1745 { | 1745 { |
1746 BinExp be = cast(BinExp)copy(); | 1746 BinExp be = cast(BinExp)copy(); |
1747 | 1747 |
1748 be.e1 = e1.doInline(ids); | 1748 be.e1 = e1.doInline(ids); |
1749 be.e2 = e2.doInline(ids); | 1749 be.e2 = e2.doInline(ids); |
1750 return be; | 1750 return be; |
1751 } | 1751 } |
1752 | 1752 |
1753 override Expression inlineScan(InlineScanState* iss) | 1753 override Expression inlineScan(InlineScanState* iss) |
1754 { | 1754 { |
1755 e1 = e1.inlineScan(iss); | 1755 e1 = e1.inlineScan(iss); |
1756 e2 = e2.inlineScan(iss); | 1756 e2 = e2.inlineScan(iss); |
1757 return this; | 1757 return this; |
1826 if (fd) | 1826 if (fd) |
1827 { | 1827 { |
1828 overloadResolveX(&m, fd, null, args2); | 1828 overloadResolveX(&m, fd, null, args2); |
1829 } | 1829 } |
1830 else | 1830 else |
1831 { | 1831 { |
1832 td = s.isTemplateDeclaration(); | 1832 td = s.isTemplateDeclaration(); |
1833 templateResolve(&m, td, sc, loc, null, null, args2); | 1833 templateResolve(&m, td, sc, loc, null, null, args2); |
1834 } | 1834 } |
1835 } | 1835 } |
1836 | 1836 |
1837 lastf = m.lastf; | 1837 lastf = m.lastf; |
1838 | 1838 |
1839 if (s_r) | 1839 if (s_r) |
1840 { | 1840 { |
1841 fd = s_r.isFuncDeclaration(); | 1841 fd = s_r.isFuncDeclaration(); |
1842 if (fd) | 1842 if (fd) |
1843 { | 1843 { |
1844 overloadResolveX(&m, fd, null, args1); | 1844 overloadResolveX(&m, fd, null, args1); |
1845 } | 1845 } |
1846 else | 1846 else |
1847 { | 1847 { |
1848 td = s_r.isTemplateDeclaration(); | 1848 td = s_r.isTemplateDeclaration(); |
1849 templateResolve(&m, td, sc, loc, null, null, args1); | 1849 templateResolve(&m, td, sc, loc, null, null, args1); |
1850 } | 1850 } |
1851 } | 1851 } |
1852 | 1852 |
1898 * b.opfunc(a) | 1898 * b.opfunc(a) |
1899 * and see which is better. | 1899 * and see which is better. |
1900 */ | 1900 */ |
1901 | 1901 |
1902 if (!argsset) | 1902 if (!argsset) |
1903 { | 1903 { |
1904 args1.setDim(1); | 1904 args1.setDim(1); |
1905 args1[0] = e1; | 1905 args1[0] = e1; |
1906 args2.setDim(1); | 1906 args2.setDim(1); |
1907 args2[0] = e2; | 1907 args2[0] = e2; |
1908 } | 1908 } |
2029 el_setLoc(e,loc); | 2029 el_setLoc(e,loc); |
2030 | 2030 |
2031 return e; | 2031 return e; |
2032 } | 2032 } |
2033 final void AssignExp_buildArrayIdent(OutBuffer buf, Expressions arguments, string Str) | 2033 final void AssignExp_buildArrayIdent(OutBuffer buf, Expressions arguments, string Str) |
2034 { | 2034 { |
2035 /* Evaluate assign expressions right to left | 2035 /* Evaluate assign expressions right to left |
2036 */ | 2036 */ |
2037 e2.buildArrayIdent(buf, arguments); | 2037 e2.buildArrayIdent(buf, arguments); |
2038 e1.buildArrayIdent(buf, arguments); | 2038 e1.buildArrayIdent(buf, arguments); |
2039 buf.writestring(Str); | 2039 buf.writestring(Str); |
2040 buf.writestring("ass"); | 2040 buf.writestring("ass"); |
2041 } | 2041 } |
2042 | 2042 |
2043 final void Exp_buildArrayIdent(OutBuffer buf, Expressions arguments, string Str) | 2043 final void Exp_buildArrayIdent(OutBuffer buf, Expressions arguments, string Str) |
2044 { | 2044 { |
2045 /* Evaluate assign expressions left to right | 2045 /* Evaluate assign expressions left to right |
2046 */ | 2046 */ |
2047 e1.buildArrayIdent(buf, arguments); | 2047 e1.buildArrayIdent(buf, arguments); |
2048 e2.buildArrayIdent(buf, arguments); | 2048 e2.buildArrayIdent(buf, arguments); |
2049 buf.writestring(Str); | 2049 buf.writestring(Str); |
2050 } | 2050 } |
2051 | 2051 |
2052 final Expression AssignExp_buildArrayLoop(AssignExpType)(Parameters fparams)// if (is (AssignExpType : AssignExp)) | 2052 final Expression AssignExp_buildArrayLoop(AssignExpType)(Parameters fparams)// if (is (AssignExpType : AssignExp)) |
2053 { | 2053 { |
2054 /* Evaluate assign expressions right to left | 2054 /* Evaluate assign expressions right to left |
2055 */ | 2055 */ |
2056 Expression ex2 = e2.buildArrayLoop(fparams); | 2056 Expression ex2 = e2.buildArrayLoop(fparams); |
2058 auto param = fparams[0]; | 2058 auto param = fparams[0]; |
2059 param.storageClass = STCundefined; | 2059 param.storageClass = STCundefined; |
2060 Expression e = new AssignExpType(Loc(0), ex1, ex2); | 2060 Expression e = new AssignExpType(Loc(0), ex1, ex2); |
2061 return e; | 2061 return e; |
2062 } | 2062 } |
2063 | 2063 |
2064 final Expression Exp_buildArrayLoop(ExpType)(Parameters fparams) if (is (ExpType : BinExp)) | 2064 final Expression Exp_buildArrayLoop(ExpType)(Parameters fparams) if (is (ExpType : BinExp)) |
2065 { | 2065 { |
2066 /* Evaluate assign expressions left to right | 2066 /* Evaluate assign expressions left to right |
2067 */ | 2067 */ |
2068 Expression ex1 = e1.buildArrayLoop(fparams); | 2068 Expression ex1 = e1.buildArrayLoop(fparams); |