view dmd/PowExp.d @ 135:af1bebfd96a4 dmd2037

dmd 2.038
author Eldar Insafutdinov <e.insafutdinov@gmail.com>
date Mon, 13 Sep 2010 22:19:42 +0100
parents 206db751bd4c
children e7769d53e750
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.IntegerExp;
import dmd.Type;
import dmd.Lexer;
import dmd.VarDeclaration;
import dmd.ExpInitializer;
import dmd.VarExp;
import dmd.DeclarationExp;
import dmd.MulExp;
import dmd.WANT;

version(DMDV2) {

class PowExp : BinExp
{
    this(Loc loc, Expression e1, Expression e2)
    {
        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();
	        }
	
	        // Deal with x^^2, x^^3 immediately, since they are of practical importance.
	        // Don't bother if x is a literal, since it will be constant-folded anyway.
	        if ( (  (e2.op == TOK.TOKint64 && (e2.toInteger() == 2 || e2.toInteger() == 3)) 
	             ||	(e2.op == TOK.TOKfloat64 && (e2.toReal() == 2.0 || e2.toReal() == 3.0))
	             ) && (e1.op == TOK.TOKint64 || e1.op == TOK.TOKfloat64)
	           )
	        {
	            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));
	            VarExp ve = new VarExp(loc, tmp);
	            Expression ae = new DeclarationExp(loc, tmp);
	            Expression me = new MulExp(loc, ve, ve);
	            if ( (e2.op == TOK.TOKint64 && e2.toInteger() == 3) 
	              || (e2.op == TOK.TOKfloat64 && e2.toReal() == 3.0))
		        me = new MulExp(loc, me, ve);
	            e = new CommaExp(loc, ae, me);
	            e = e.semantic(sc);
	            return e;
	        }

	        static int importMathChecked = 0;
	        if (!importMathChecked)
	        {
	            importMathChecked = 1;
	            for (int i = 0; i < Module.amodules.dim; i++)
	            {
                    auto mi = cast(Module)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);
	            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;
    }
}

}