Mercurial > projects > ddmd
view dmd/PowExp.d @ 187:b0d41ff5e0df
Added expandability scheme outlined in http://www.dsource.org/forums/viewtopic.php?t=5659&sid=6f2150ff5b0bffcd47512a6a7608d218
author | Abscissa |
---|---|
date | Tue, 07 Jun 2011 23:37:34 -0400 |
parents | cd48cb899aee |
children |
line wrap: on
line source
module dmd.PowExp; import dmd.BinExp; import dmd.Scope; import dmd.Loc; import dmd.Identifier; import dmd.Expression; import dmd.TOK; import dmd.Module; import dmd.Id; import dmd.IdentifierExp; import dmd.DotIdExp; import dmd.CallExp; import dmd.ErrorExp; import dmd.CommaExp; import dmd.AndExp; import dmd.CondExp; import dmd.Global; import dmd.IntegerExp; import dmd.Type; import dmd.STC; import dmd.Lexer; import dmd.VarDeclaration; import dmd.ExpInitializer; import dmd.VarExp; import dmd.DeclarationExp; import dmd.MulExp; import dmd.WANT; import dmd.DDMDExtensions; version(DMDV2) { class PowExp : BinExp { mixin insertMemberExtension!(typeof(this)); this(Loc loc, Expression e1, Expression e2) { register(); super(loc, TOK.TOKpow, PowExp.sizeof, e1, e2); } override Expression semantic(Scope sc) { Expression e; if (type) return this; //printf("PowExp::semantic() %s\n", toChars()); BinExp.semanticp(sc); e = op_overload(sc); if (e) return e; assert(e1.type && e2.type); if ( (e1.type.isintegral() || e1.type.isfloating()) && (e2.type.isintegral() || e2.type.isfloating())) { // For built-in numeric types, there are several cases. // TODO: backend support, especially for e1 ^^ 2. bool wantSqrt = false; e1 = e1.optimize(0); e2 = e2.optimize(0); // Replace 1 ^^ x or 1.0^^x by (x, 1) if ((e1.op == TOK.TOKint64 && e1.toInteger() == 1) || (e1.op == TOK.TOKfloat64 && e1.toReal() == 1.0)) { typeCombine(sc); e = new CommaExp(loc, e2, e1); e = e.semantic(sc); return e; } // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral if (e2.type.isintegral() && e1.op == TOKint64 && cast(long)e1.toInteger() == -1) { typeCombine(sc); Type resultType = type; e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2.type)); e = new CondExp(loc, e, new IntegerExp(loc, -1, resultType), new IntegerExp(loc, 1, resultType)); e = e.semantic(sc); return e; } // All other negative integral powers are illegal if ((e1.type.isintegral()) && (e2.op == TOK.TOKint64) && cast(long)e2.toInteger() < 0) { error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?", e1.type.toBasetype().toChars(), e1.toChars(), e2.toChars()); return new ErrorExp(); } // Determine if we're raising to an integer power. long intpow = 0; if (e2.op == TOKint64 && (cast(long)e2.toInteger() == 2 || cast(long)e2.toInteger() == 3)) intpow = e2.toInteger(); else if (e2.op == TOKfloat64 && (e2.toReal() == cast(long)(e2.toReal()))) intpow = cast(long)(e2.toReal()); // Deal with x^^2, x^^3 immediately, since they are of practical importance. if (intpow == 2 || intpow == 3) { typeCombine(sc); // Replace x^^2 with (tmp = x, tmp*tmp) // Replace x^^3 with (tmp = x, tmp*tmp*tmp) Identifier idtmp = Lexer.uniqueId("__tmp"); VarDeclaration tmp = new VarDeclaration(loc, e1.type.toBasetype(), idtmp, new ExpInitializer(Loc(0), e1)); tmp.storage_class = STC.STCctfe; Expression ve = new VarExp(loc, tmp); Expression ae = new DeclarationExp(loc, tmp); /* Note that we're reusing ve. This should be ok. */ Expression me = new MulExp(loc, ve, ve); if (intpow == 3) me = new MulExp(loc, me, ve); e = new CommaExp(loc, ae, me); e = e.semantic(sc); return e; } if (!global.importMathChecked) { global.importMathChecked = true; auto amodules = global.amodules; for (int i = 0; i < amodules.dim; i++) { auto mi = cast(Module)amodules.data[i]; //printf("\t[%d] %s\n", i, mi->toChars()); if (mi.ident == Id.math && mi.parent.ident == Id.std && !mi.parent.parent) goto L1; } error("must import std.math to use ^^ operator"); L1: ; } e = new IdentifierExp(loc, Id.empty); e = new DotIdExp(loc, e, Id.std); e = new DotIdExp(loc, e, Id.math); if (e2.op == TOK.TOKfloat64 && e2.toReal() == 0.5) { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) typeCombine(sc); e = new CallExp(loc, new DotIdExp(loc, e, Id._sqrt), e1); } else { // Replace e1 ^^ e2 with .std.math.pow(e1, e2) // We don't combine the types if raising to an integer power (because // integer powers are treated specially by std.math.pow). if (!e2.type.isintegral()) typeCombine(sc); // In fact, if it *could* have been an integer, make it one. if (e2.op == TOKfloat64 && intpow != 0) e2 = new IntegerExp(loc, intpow, Type.tint64); e = new CallExp(loc, new DotIdExp(loc, e, Id._pow), e1, e2); } e = e.semantic(sc); // Always constant fold integer powers of literals. This will run the interpreter // on .std.math.pow if ((e1.op == TOK.TOKfloat64 || e1.op == TOK.TOKint64) && (e2.op == TOK.TOKint64)) e = e.optimize(WANT.WANTvalue | WANT.WANTinterpret); return e; } error("%s ^^ %s is not supported", e1.type.toChars(), e2.type.toChars() ); return new ErrorExp(); } // For operator overloading override Identifier opId() { return Id.pow; } override Identifier opId_r() { return Id.pow_r; } } }