Mercurial > projects > ldc
diff dmd/constfold.c @ 336:aaade6ded589 trunk
[svn r357] Merged DMD 1.033
author | lindquist |
---|---|
date | Sat, 12 Jul 2008 19:38:31 +0200 |
parents | 2b72433d5c8c |
children | 29dc68c949b0 |
line wrap: on
line diff
--- a/dmd/constfold.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/constfold.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,1506 +1,1512 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <math.h> - -#if __DMC__ -#include <complex.h> -#endif - -#include "mem.h" -#include "root.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.h" - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - -#define LOG 0 - -Expression *expType(Type *type, Expression *e) -{ - if (type != e->type) - { - e = e->copy(); - e->type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ - -int Expression::isConst() -{ - //printf("Expression::isConst(): %s\n", toChars()); - return 0; -} - -int IntegerExp::isConst() -{ - return 1; -} - -int RealExp::isConst() -{ - return 1; -} - -int ComplexExp::isConst() -{ - return 1; -} - -int SymOffExp::isConst() -{ - return 2; -} - -/* =============================== constFold() ============================== */ - -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ - -/* ========================================================================== */ - -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->type->isreal()) - { - e = new RealExp(loc, -e1->toReal(), type); - } - else if (e1->type->isimaginary()) - { - e = new RealExp(loc, -e1->toImaginary(), type); - } - else if (e1->type->iscomplex()) - { - e = new ComplexExp(loc, -e1->toComplex(), type); - } - else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; -} - -Expression *Com(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, ~e1->toInteger(), type); - return e; -} - -Expression *Not(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(0), type); - return e; -} - -Expression *Bool(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(1), type); - return e; -} - -Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - -#if LOG - printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); -#endif - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() + e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 + r2); break; - case 0+1: v = r1 + i2 * I; break; - case 0+2: v = r1 + c2; break; - case 3+0: v = i1 * I + r2; break; - case 3+1: v = (complex_t) ((i1 + i2) * I); break; - case 3+2: v = i1 * I + c2; break; - case 6+0: v = c1 + r2; break; - case 6+1: v = c1 + i2 * I; break; - case 6+2: v = c1 + c2; break; -#else - case 0+0: v = complex_t(r1 + r2, 0); break; - case 0+1: v = complex_t(r1, i2); break; - case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; - case 3+0: v = complex_t(r2, i1); break; - case 3+1: v = complex_t(0, i1 + i2); break; - case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; - case 6+2: v = c1 + c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); - e->type = type; - } - else if (e2->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e2; - e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); - e->type = type; - } - else - e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); - return e; -} - - -Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() - e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 - r2); break; - case 0+1: v = r1 - i2 * I; break; - case 0+2: v = r1 - c2; break; - case 3+0: v = i1 * I - r2; break; - case 3+1: v = (complex_t) ((i1 - i2) * I); break; - case 3+2: v = i1 * I - c2; break; - case 6+0: v = c1 - r2; break; - case 6+1: v = c1 - i2 * I; break; - case 6+2: v = c1 - c2; break; -#else - case 0+0: v = complex_t(r1 - r2, 0); break; - case 0+1: v = complex_t(r1, -i2); break; - case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; - case 3+0: v = complex_t(-r2, i1); break; - case 3+1: v = complex_t(0, i1 - i2); break; - case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; - case 6+2: v = c1 - c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); - e->type = type; - } - else - { - e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); - } - return e; -} - -Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - if (e1->type->isreal()) - { -#if __DMC__ - c = e1->toReal() * e2->toComplex(); -#else - r = e1->toReal(); - c = e2->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e1->type->isimaginary()) - { -#if __DMC__ - c = e1->toImaginary() * I * e2->toComplex(); -#else - r = e1->toImaginary(); - c = e2->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else if (e2->type->isreal()) - { -#if __DMC__ - c = e2->toReal() * e1->toComplex(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - c = e1->toComplex() * e2->toImaginary() * I; -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else - c = e1->toComplex() * e2->toComplex(); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { - e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); - } - return e; -} - -Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - //e1->type->print(); - //e2->type->print(); - if (e2->type->isreal()) - { - if (e1->type->isreal()) - { - e = new RealExp(loc, e1->toReal() / e2->toReal(), type); - return e; - } -#if __DMC__ - //r = e2->toReal(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / e2->toReal(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - //r = e2->toImaginary(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / (e2->toImaginary() * I); -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); -#endif - } - else - { - c = e1->toComplex() / e2->toComplex(); - } - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(0, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) / ((d_uns64) n2); - else - n = n1 / n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { - complex_t c; - - if (e2->type->isreal()) - { real_t r2 = e2->toReal(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); -#else - c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); -#endif - } - else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); -#else - c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); -#endif - } - else - assert(0); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(0, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) % ((d_uns64) n2); - else - n = n1 % n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); - return e; -} - -Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - integer_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - value = (d_int8)(value) >> count; - break; - - case Tuns8: - value = (d_uns8)(value) >> count; - break; - - case Tint16: - value = (d_int16)(value) >> count; - break; - - case Tuns16: - value = (d_uns16)(value) >> count; - break; - - case Tint32: - value = (d_int32)(value) >> count; - break; - - case Tuns32: - value = (d_uns32)(value) >> count; - break; - - case Tint64: - value = (d_int64)(value) >> count; - break; - - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - integer_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - assert(0); // no way to trigger this - value = (value & 0xFF) >> count; - break; - - case Tint16: - case Tuns16: - assert(0); // no way to trigger this - value = (value & 0xFFFF) >> count; - break; - - case Tint32: - case Tuns32: - value = (value & 0xFFFFFFFF) >> count; - break; - - case Tint64: - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *And(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - real_t r1; - real_t r2; - - //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - assert(op == TOKequal || op == TOKnotequal); - - if (e1->op == TOKnull) - { - if (e2->op == TOKnull) - cmp = 1; - else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; - cmp = (0 == es2->len); - } - else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - cmp = !es2->elements || (0 == es2->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e2->op == TOKnull) - { - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - cmp = (0 == es1->len); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - cmp = !es1->elements || (0 == es1->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - - assert(es1->sz == es2->sz); - if (es1->len == es2->len && - memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { // Swap operands and use common code - Expression *e = e1; - e1 = e2; - e2 = e; - goto Lsa; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral) - { - Lsa: - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t dim1 = es1->len; - size_t dim2 = es2->elements ? es2->elements->dim : 0; - if (dim1 != dim2) - cmp = 0; - else - { - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1->charAt(i); - Expression *ee2 = (Expression *)es2->elements->data[i]; - if (ee2->isConst() != 1) - return EXP_CANT_INTERPRET; - cmp = (c == ee2->toInteger()); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - - if (es1->sd != es2->sd) - cmp = 0; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - cmp = 1; - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { cmp = 0; - break; - } - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } -#if 0 // Should handle this - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { - } -#endif - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - cmp = (r1 == r2); -#else - if (isnan(r1) || isnan(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - cmp = e1->toComplex() == e2->toComplex(); - } - else if (e1->type->isintegral()) - { - cmp = (e1->toInteger() == e2->toInteger()); - } - else - return EXP_CANT_INTERPRET; - if (op == TOKnotequal) - cmp ^= 1; - e = new IntegerExp(loc, cmp, type); - return e; -} - -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - - if (e1->op == TOKnull && e2->op == TOKnull) - { - cmp = 1; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else if (e1->isConst() == 1 && e2->isConst() == 1) - return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, - type, e1, e2); - else - assert(0); - if (op == TOKnotidentity) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - - -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - integer_t n; - real_t r1; - real_t r2; - - if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - // DMC is the only compiler I know of that handles NAN arguments - // correctly in comparisons. - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = r1 <>= r2; break; - case TOKlg: n = r1 <> r2; break; - case TOKunord: n = r1 !<>= r2; break; - case TOKue: n = r1 !<> r2; break; - case TOKug: n = r1 !<= r2; break; - case TOKuge: n = r1 !< r2; break; - case TOKul: n = r1 !>= r2; break; - case TOKule: n = r1 !> r2; break; - - default: - assert(0); - } -#else - // Don't rely on compiler, handle NAN arguments separately -#if IN_GCC - if (real_isnan(&r1) || real_isnan(&r2)) // if unordered -#else - if (isnan(r1) || isnan(r2)) // if unordered -#endif - { - switch (op) - { - case TOKlt: n = 0; break; - case TOKle: n = 0; break; - case TOKgt: n = 0; break; - case TOKge: n = 0; break; - - case TOKleg: n = 0; break; - case TOKlg: n = 0; break; - case TOKunord: n = 1; break; - case TOKue: n = 1; break; - case TOKug: n = 1; break; - case TOKuge: n = 1; break; - case TOKul: n = 1; break; - case TOKule: n = 1; break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = r1 != r2; break; - case TOKunord: n = 0; break; - case TOKue: n = r1 == r2; break; - case TOKug: n = r1 > r2; break; - case TOKuge: n = r1 >= r2; break; - case TOKul: n = r1 < r2; break; - case TOKule: n = r1 <= r2; break; - - default: - assert(0); - } - } -#endif - } - else if (e1->type->iscomplex()) - { - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (e1->type->isunsigned() || e2->type->isunsigned()) - { - switch (op) - { - case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - - case TOKleg: n = 1; break; - case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; - case TOKunord: n = 0; break; - case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; - case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = n1 < n2; break; - case TOKle: n = n1 <= n2; break; - case TOKgt: n = n1 > n2; break; - case TOKge: n = n1 >= n2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = n1 != n2; break; - case TOKunord: n = 0; break; - case TOKue: n = n1 == n2; break; - case TOKug: n = n1 > n2; break; - case TOKuge: n = n1 >= n2; break; - case TOKul: n = n1 < n2; break; - case TOKule: n = n1 <= n2; break; - - default: - assert(0); - } - } - } - e = new IntegerExp(loc, n, type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ - -Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("e1->type = %s\n", e1->type->toChars()); - if (type->equals(e1->type) && to->equals(type)) - return e1; - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - Type *tb = to->toBasetype(); - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { integer_t result; - real_t r = e1->toReal(); - - switch (type->toBasetype()->ty) - { - case Tint8: result = (d_int8)r; break; - case Tchar: - case Tuns8: result = (d_uns8)r; break; - case Tint16: result = (d_int16)r; break; - case Twchar: - case Tuns16: result = (d_uns16)r; break; - case Tint32: result = (d_int32)r; break; - case Tdchar: - case Tuns32: result = (d_uns32)r; break; - case Tint64: result = (d_int64)r; break; - case Tuns64: result = (d_uns64)r; break; - default: - assert(0); - } - - e = new IntegerExp(loc, result, type); - } - else if (type->isunsigned()) - e = new IntegerExp(loc, e1->toUInteger(), type); - else - e = new IntegerExp(loc, e1->toInteger(), type); - } - else if (tb->isreal()) - { real_t value = e1->toReal(); - - e = new RealExp(loc, value, type); - } - else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); - - e = new RealExp(loc, value, type); - } - else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); - - e = new ComplexExp(loc, value, type); - } - else if (tb->isscalar()) - e = new IntegerExp(loc, e1->toInteger(), type); - else if (tb->ty == Tvoid) - e = EXP_CANT_INTERPRET; - else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; - StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); - assert(sd); - Expressions *elements = new Expressions; - for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - Expression *exp = new IntegerExp(0); - exp = Cast(v->type, v->type, exp); - if (exp == EXP_CANT_INTERPRET) - return exp; - elements->push(exp); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = type; - } - else - { - error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); - e = new IntegerExp(loc, 0, type); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len); - else - { unsigned value = es1->charAt(i); - e = new IntegerExp(loc, value, type); - } - } - else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) - { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); - uinteger_t length = tsa->dim->toInteger(); - uinteger_t i = e2->toInteger(); - - if (i >= length) - { - e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length); - } - else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) - { - uinteger_t i = e2->toInteger(); - - if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (i >= ale->elements->dim) - { - e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); - } - else - { e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - } - else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = (Expression *)ae->keys->data[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = (Expression *)ae->values->data[i]; - e->type = type; - break; - } - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - -#if LOG - printf("Slice()\n"); - if (lwr) - { printf("\te1 = %s\n", e1->toChars()); - printf("\tlwr = %s\n", lwr->toChars()); - printf("\tupr = %s\n", upr->toChars()); - } -#endif - if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->len || ilwr > iupr) - e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr); - else - { integer_t value; - void *s; - size_t len = iupr - ilwr; - int sz = es1->sz; - StringExp *es; - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len, es1->postfix); - es->sz = sz; - es->committed = 1; - es->type = type; - e = es; - } - } - else if (e1->op == TOKarrayliteral && - lwr->op == TOKint64 && upr->op == TOKint64 && - !e1->checkSideEffect(2)) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->elements->dim || ilwr > iupr) - e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr); - else - { - Expressions *elements = new Expressions(); - elements->setDim(iupr - ilwr); - memcpy(elements->data, - es1->elements->data + ilwr, - (iupr - ilwr) * sizeof(es1->elements->data[0])); - e = new ArrayLiteralExp(e1->loc, elements); - e->type = type; - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - Type *t; - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; - goto L2; - } - else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; - L2: - Type *tn = e->type->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { - // Create a StringExp - void *s; - StringExp *es; - size_t len = 1; - int sz = tn->size(); - integer_t v = e->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 1; - e = es; - } - else - { // Create an ArrayLiteralExp - Expressions *elements = new Expressions(); - elements->push(e); - e = new ArrayLiteralExp(e->loc, elements); - } - e->type = type; - return e; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = es1->len + es2->len; - int sz = es1->sz; - - assert(sz == es2->sz); - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed | es2->committed; - if (es1->committed) - t = es1->type; - else - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKstring && e2->op == TOKint64) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es; - Type *t; - size_t len = es1->len + 1; - int sz = es1->sz; - integer_t v = e2->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed; - t = es1->type; - es->type = type; - e = es; - } - else if (e1->op == TOKint64 && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = 1 + es2->len; - int sz = es2->sz; - integer_t v = e1->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es2->committed; - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && - e1->type->equals(e2->type)) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e2->op == TOKarrayliteral && - e2->type->toBasetype()->nextOf()->equals(e1->type)) - { - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); - es2->elements->shift(e1); - e = es2; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKnull && e2->op == TOKstring) - { - t = e1->type; - e = e2; - goto L1; - } - else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; - t = e2->type; - L1: - Type *tb = t->toBasetype(); - if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); - expressions->push(e); - e = new ArrayLiteralExp(loc, expressions); - e->type = t; - } - if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); - e = se->castTo(NULL, type); - } - } - return e; -} - -Expression *Ptr(Type *type, Expression *e1) -{ - //printf("Ptr(e1 = %s)\n", e1->toChars()); - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; - unsigned offset = ae->e2->toInteger(); - Expression *e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - return EXP_CANT_INTERPRET; -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <math.h> + +#if __DMC__ +#include <complex.h> +#endif + +#include "mem.h" +#include "root.h" + +#include "mtype.h" +#include "expression.h" +#include "aggregate.h" +#include "declaration.h" + +#ifdef IN_GCC +#include "d-gcc-real.h" + +/* %% fix? */ +extern "C" bool real_isnan (const real_t *); +#endif + +static real_t zero; // work around DMC bug for now + +#define LOG 0 + +Expression *expType(Type *type, Expression *e) +{ + if (type != e->type) + { + e = e->copy(); + e->type = type; + } + return e; +} + +/* ================================== isConst() ============================== */ + +int Expression::isConst() +{ + //printf("Expression::isConst(): %s\n", toChars()); + return 0; +} + +int IntegerExp::isConst() +{ + return 1; +} + +int RealExp::isConst() +{ + return 1; +} + +int ComplexExp::isConst() +{ + return 1; +} + +int SymOffExp::isConst() +{ + return 2; +} + +/* =============================== constFold() ============================== */ + +/* The constFold() functions were redundant with the optimize() ones, + * and so have been folded in with them. + */ + +/* ========================================================================== */ + +Expression *Neg(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->type->isreal()) + { + e = new RealExp(loc, -e1->toReal(), type); + } + else if (e1->type->isimaginary()) + { + e = new RealExp(loc, -e1->toImaginary(), type); + } + else if (e1->type->iscomplex()) + { + e = new ComplexExp(loc, -e1->toComplex(), type); + } + else + e = new IntegerExp(loc, -e1->toInteger(), type); + return e; +} + +Expression *Com(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, ~e1->toInteger(), type); + return e; +} + +Expression *Not(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(0), type); + return e; +} + +Expression *Bool(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(1), type); + return e; +} + +Expression *Add(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + +#if LOG + printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); +#endif + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() + e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 + r2); break; + case 0+1: v = r1 + i2 * I; break; + case 0+2: v = r1 + c2; break; + case 3+0: v = i1 * I + r2; break; + case 3+1: v = (complex_t) ((i1 + i2) * I); break; + case 3+2: v = i1 * I + c2; break; + case 6+0: v = c1 + r2; break; + case 6+1: v = c1 + i2 * I; break; + case 6+2: v = c1 + c2; break; +#else + case 0+0: v = complex_t(r1 + r2, 0); break; + case 0+1: v = complex_t(r1, i2); break; + case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; + case 3+0: v = complex_t(r2, i1); break; + case 3+1: v = complex_t(0, i1 + i2); break; + case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; + case 6+2: v = c1 + c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); + e->type = type; + } + else if (e2->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e2; + e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); + e->type = type; + } + else + e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); + return e; +} + + +Expression *Min(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() - e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 - r2); break; + case 0+1: v = r1 - i2 * I; break; + case 0+2: v = r1 - c2; break; + case 3+0: v = i1 * I - r2; break; + case 3+1: v = (complex_t) ((i1 - i2) * I); break; + case 3+2: v = i1 * I - c2; break; + case 6+0: v = c1 - r2; break; + case 6+1: v = c1 - i2 * I; break; + case 6+2: v = c1 - c2; break; +#else + case 0+0: v = complex_t(r1 - r2, 0); break; + case 0+1: v = complex_t(r1, -i2); break; + case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; + case 3+0: v = complex_t(-r2, i1); break; + case 3+1: v = complex_t(0, i1 - i2); break; + case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; + case 6+2: v = c1 - c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); + e->type = type; + } + else + { + e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); + } + return e; +} + +Expression *Mul(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + if (e1->type->isreal()) + { +#if __DMC__ + c = e1->toReal() * e2->toComplex(); +#else + r = e1->toReal(); + c = e2->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e1->type->isimaginary()) + { +#if __DMC__ + c = e1->toImaginary() * I * e2->toComplex(); +#else + r = e1->toImaginary(); + c = e2->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else if (e2->type->isreal()) + { +#if __DMC__ + c = e2->toReal() * e1->toComplex(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + c = e1->toComplex() * e2->toImaginary() * I; +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else + c = e1->toComplex() * e2->toComplex(); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); + } + return e; +} + +Expression *Div(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + //e1->type->print(); + //e2->type->print(); + if (e2->type->isreal()) + { + if (e1->type->isreal()) + { + e = new RealExp(loc, e1->toReal() / e2->toReal(), type); + return e; + } +#if __DMC__ + //r = e2->toReal(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / e2->toReal(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(creall(c) / r, cimagl(c) / r); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + //r = e2->toImaginary(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / (e2->toImaginary() * I); +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(cimagl(c) / r, -creall(c) / r); +#endif + } + else + { + c = e1->toComplex() / e2->toComplex(); + } + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(0, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) / ((d_uns64) n2); + else + n = n1 / n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Mod(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { + complex_t c; + + if (e2->type->isreal()) + { real_t r2 = e2->toReal(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); +#else + c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); +#endif + } + else if (e2->type->isimaginary()) + { real_t i2 = e2->toImaginary(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); +#else + c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); +#endif + } + else + assert(0); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(0, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) % ((d_uns64) n2); + else + n = n1 % n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Shl(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); + return e; +} + +Expression *Shr(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + unsigned count; + integer_t value; + + value = e1->toInteger(); + count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + value = (d_int8)(value) >> count; + break; + + case Tuns8: + value = (d_uns8)(value) >> count; + break; + + case Tint16: + value = (d_int16)(value) >> count; + break; + + case Tuns16: + value = (d_uns16)(value) >> count; + break; + + case Tint32: + value = (d_int32)(value) >> count; + break; + + case Tuns32: + value = (d_uns32)(value) >> count; + break; + + case Tint64: + value = (d_int64)(value) >> count; + break; + + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + default: + assert(0); + } + e = new IntegerExp(loc, value, type); + return e; +} + +Expression *Ushr(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + unsigned count; + integer_t value; + + value = e1->toInteger(); + count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + case Tuns8: + assert(0); // no way to trigger this + value = (value & 0xFF) >> count; + break; + + case Tint16: + case Tuns16: + assert(0); // no way to trigger this + value = (value & 0xFFFF) >> count; + break; + + case Tint32: + case Tuns32: + value = (value & 0xFFFFFFFF) >> count; + break; + + case Tint64: + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + default: + assert(0); + } + e = new IntegerExp(loc, value, type); + return e; +} + +Expression *And(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type); + return e; +} + +Expression *Or(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type); + return e; +} + +Expression *Xor(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() ^ e2->toInteger(), type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + */ +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + int cmp; + real_t r1; + real_t r2; + + //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + assert(op == TOKequal || op == TOKnotequal); + + if (e1->op == TOKnull) + { + if (e2->op == TOKnull) + cmp = 1; + else if (e2->op == TOKstring) + { StringExp *es2 = (StringExp *)e2; + cmp = (0 == es2->len); + } + else if (e2->op == TOKarrayliteral) + { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + cmp = !es2->elements || (0 == es2->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e2->op == TOKnull) + { + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + cmp = (0 == es1->len); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + cmp = !es1->elements || (0 == es1->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + + assert(es1->sz == es2->sz); + if (es1->len == es2->len && + memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) + cmp = 1; + else + cmp = 0; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { // Swap operands and use common code + Expression *e = e1; + e1 = e2; + e2 = e; + goto Lsa; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral) + { + Lsa: + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t dim1 = es1->len; + size_t dim2 = es2->elements ? es2->elements->dim : 0; + if (dim1 != dim2) + cmp = 0; + else + { + for (size_t i = 0; i < dim1; i++) + { + uinteger_t c = es1->charAt(i); + Expression *ee2 = (Expression *)es2->elements->data[i]; + if (ee2->isConst() != 1) + return EXP_CANT_INTERPRET; + cmp = (c == ee2->toInteger()); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) + { StructLiteralExp *es1 = (StructLiteralExp *)e1; + StructLiteralExp *es2 = (StructLiteralExp *)e2; + + if (es1->sd != es2->sd) + cmp = 0; + else if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + cmp = 1; + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + { cmp = 0; + break; + } + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } +#if 0 // Should handle this + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { + } +#endif + else if (e1->isConst() != 1 || e2->isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + cmp = (r1 == r2); +#else + if (isnan(r1) || isnan(r2)) // if unordered + { + cmp = 0; + } + else + { + cmp = (r1 == r2); + } +#endif + } + else if (e1->type->iscomplex()) + { + cmp = e1->toComplex() == e2->toComplex(); + } + else if (e1->type->isintegral()) + { + cmp = (e1->toInteger() == e2->toInteger()); + } + else + return EXP_CANT_INTERPRET; + if (op == TOKnotequal) + cmp ^= 1; + e = new IntegerExp(loc, cmp, type); + return e; +} + +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + int cmp; + + if (e1->op == TOKnull && e2->op == TOKnull) + { + cmp = 1; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { + SymOffExp *es1 = (SymOffExp *)e1; + SymOffExp *es2 = (SymOffExp *)e2; + + cmp = (es1->var == es2->var && es1->offset == es2->offset); + } + else if (e1->isConst() == 1 && e2->isConst() == 1) + return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, + type, e1, e2); + else + assert(0); + if (op == TOKnotidentity) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + + +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + integer_t n; + real_t r1; + real_t r2; + + if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + // DMC is the only compiler I know of that handles NAN arguments + // correctly in comparisons. + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = r1 <>= r2; break; + case TOKlg: n = r1 <> r2; break; + case TOKunord: n = r1 !<>= r2; break; + case TOKue: n = r1 !<> r2; break; + case TOKug: n = r1 !<= r2; break; + case TOKuge: n = r1 !< r2; break; + case TOKul: n = r1 !>= r2; break; + case TOKule: n = r1 !> r2; break; + + default: + assert(0); + } +#else + // Don't rely on compiler, handle NAN arguments separately +#if IN_GCC + if (real_isnan(&r1) || real_isnan(&r2)) // if unordered +#else + if (isnan(r1) || isnan(r2)) // if unordered +#endif + { + switch (op) + { + case TOKlt: n = 0; break; + case TOKle: n = 0; break; + case TOKgt: n = 0; break; + case TOKge: n = 0; break; + + case TOKleg: n = 0; break; + case TOKlg: n = 0; break; + case TOKunord: n = 1; break; + case TOKue: n = 1; break; + case TOKug: n = 1; break; + case TOKuge: n = 1; break; + case TOKul: n = 1; break; + case TOKule: n = 1; break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = r1 != r2; break; + case TOKunord: n = 0; break; + case TOKue: n = r1 == r2; break; + case TOKug: n = r1 > r2; break; + case TOKuge: n = r1 >= r2; break; + case TOKul: n = r1 < r2; break; + case TOKule: n = r1 <= r2; break; + + default: + assert(0); + } + } +#endif + } + else if (e1->type->iscomplex()) + { + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (e1->type->isunsigned() || e2->type->isunsigned()) + { + switch (op) + { + case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + + case TOKleg: n = 1; break; + case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; + case TOKunord: n = 0; break; + case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; + case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = n1 < n2; break; + case TOKle: n = n1 <= n2; break; + case TOKgt: n = n1 > n2; break; + case TOKge: n = n1 >= n2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = n1 != n2; break; + case TOKunord: n = 0; break; + case TOKue: n = n1 == n2; break; + case TOKug: n = n1 > n2; break; + case TOKuge: n = n1 >= n2; break; + case TOKul: n = n1 < n2; break; + case TOKule: n = n1 <= n2; break; + + default: + assert(0); + } + } + } + e = new IntegerExp(loc, n, type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + * to: type to cast to + * type: type to paint the result + */ + +Expression *Cast(Type *type, Type *to, Expression *e1) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); + //printf("e1->type = %s\n", e1->type->toChars()); + if (type->equals(e1->type) && to->equals(type)) + return e1; + + if (e1->isConst() != 1) + return EXP_CANT_INTERPRET; + + Type *tb = to->toBasetype(); + if (tb->ty == Tbool) + e = new IntegerExp(loc, e1->toInteger() != 0, type); + else if (type->isintegral()) + { + if (e1->type->isfloating()) + { integer_t result; + real_t r = e1->toReal(); + + switch (type->toBasetype()->ty) + { + case Tint8: result = (d_int8)r; break; + case Tchar: + case Tuns8: result = (d_uns8)r; break; + case Tint16: result = (d_int16)r; break; + case Twchar: + case Tuns16: result = (d_uns16)r; break; + case Tint32: result = (d_int32)r; break; + case Tdchar: + case Tuns32: result = (d_uns32)r; break; + case Tint64: result = (d_int64)r; break; + case Tuns64: result = (d_uns64)r; break; + default: + assert(0); + } + + e = new IntegerExp(loc, result, type); + } + else if (type->isunsigned()) + e = new IntegerExp(loc, e1->toUInteger(), type); + else + e = new IntegerExp(loc, e1->toInteger(), type); + } + else if (tb->isreal()) + { real_t value = e1->toReal(); + + e = new RealExp(loc, value, type); + } + else if (tb->isimaginary()) + { real_t value = e1->toImaginary(); + + e = new RealExp(loc, value, type); + } + else if (tb->iscomplex()) + { complex_t value = e1->toComplex(); + + e = new ComplexExp(loc, value, type); + } + else if (tb->isscalar()) + e = new IntegerExp(loc, e1->toInteger(), type); + else if (tb->ty == Tvoid) + e = EXP_CANT_INTERPRET; + else if (tb->ty == Tstruct && e1->op == TOKint64) + { // Struct = 0; + StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); + assert(sd); + Expressions *elements = new Expressions; + for (size_t i = 0; i < sd->fields.dim; i++) + { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + Expression *exp = new IntegerExp(0); + exp = Cast(v->type, v->type, exp); + if (exp == EXP_CANT_INTERPRET) + return exp; + elements->push(exp); + } + e = new StructLiteralExp(loc, sd, elements); + e->type = type; + } + else + { + error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); + e = new IntegerExp(loc, 0, type); + } + return e; +} + + +Expression *ArrayLength(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + + e = new IntegerExp(loc, es1->len, type); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + size_t dim; + + dim = ale->elements ? ale->elements->dim : 0; + e = new IntegerExp(loc, dim, type); + } + else if (e1->op == TOKassocarrayliteral) + { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; + size_t dim = ale->keys->dim; + + e = new IntegerExp(loc, dim, type); + } + else + e = EXP_CANT_INTERPRET; + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Index(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + assert(e1->type); + if (e1->op == TOKstring && e2->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t i = e2->toInteger(); + + if (i >= es1->len) + e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", i, es1->len); + else + { unsigned value = es1->charAt(i); + e = new IntegerExp(loc, value, type); + } + } + else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) + { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); + uinteger_t length = tsa->dim->toInteger(); + uinteger_t i = e2->toInteger(); + + if (i >= length) + { + e2->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length); + } + else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) + { + uinteger_t i = e2->toInteger(); + + if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + if (i >= ale->elements->dim) + { + e2->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); + } + else + { e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + } + else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) + { + AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; + /* Search the keys backwards, in case there are duplicate keys + */ + for (size_t i = ae->keys->dim; i;) + { + i--; + Expression *ekey = (Expression *)ae->keys->data[i]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); + if (ex == EXP_CANT_INTERPRET) + return ex; + if (ex->isBool(TRUE)) + { e = (Expression *)ae->values->data[i]; + e->type = type; + break; + } + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + +#if LOG + printf("Slice()\n"); + if (lwr) + { printf("\te1 = %s\n", e1->toChars()); + printf("\tlwr = %s\n", lwr->toChars()); + printf("\tupr = %s\n", upr->toChars()); + } +#endif + if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->len || ilwr > iupr) + e1->error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr); + else + { integer_t value; + void *s; + size_t len = iupr - ilwr; + int sz = es1->sz; + StringExp *es; + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len, es1->postfix); + es->sz = sz; + es->committed = 1; + es->type = type; + e = es; + } + } + else if (e1->op == TOKarrayliteral && + lwr->op == TOKint64 && upr->op == TOKint64 && + !e1->checkSideEffect(2)) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->elements->dim || ilwr > iupr) + e1->error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr); + else + { + Expressions *elements = new Expressions(); + elements->setDim(iupr - ilwr); + memcpy(elements->data, + es1->elements->data + ilwr, + (iupr - ilwr) * sizeof(es1->elements->data[0])); + e = new ArrayLiteralExp(e1->loc, elements); + e->type = type; + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Cat(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + Type *t; + + //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) + { e = e2; + goto L2; + } + else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) + { e = e1; + L2: + Type *tn = e->type->toBasetype(); + if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) + { + // Create a StringExp + void *s; + StringExp *es; + size_t len = 1; + int sz = tn->size(); + integer_t v = e->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 1; + e = es; + } + else + { // Create an ArrayLiteralExp + Expressions *elements = new Expressions(); + elements->push(e); + e = new ArrayLiteralExp(e->loc, elements); + } + e->type = type; + return e; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = es1->len + es2->len; + int sz = es1->sz; + + assert(sz == es2->sz); + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed | es2->committed; + if (es1->committed) + t = es1->type; + else + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKstring && e2->op == TOKint64) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es; + Type *t; + size_t len = es1->len + 1; + int sz = es1->sz; + integer_t v = e2->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed; + t = es1->type; + es->type = type; + e = es; + } + else if (e1->op == TOKint64 && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = 1 + es2->len; + int sz = es2->sz; + integer_t v = e1->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es2->committed; + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && + e1->type->equals(e2->type)) + { + // Concatenate the arrays + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->insert(es1->elements->dim, es2->elements); + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && + e1->type->toBasetype()->nextOf()->equals(e2->type)) + { + ArrayLiteralExp *es1; + if (e1->op == TOKarrayliteral) + { es1 = (ArrayLiteralExp *)e1; + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->push(e2); + } + else + { + es1 = new ArrayLiteralExp(e1->loc, e2); + } + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e2->type, new IntegerExp(0, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e2->op == TOKarrayliteral && + e2->type->toBasetype()->nextOf()->equals(e1->type)) + { + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); + es2->elements->shift(e1); + e = es2; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e1->type, new IntegerExp(0, es2->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e1->op == TOKnull && e2->op == TOKstring) + { + t = e1->type; + e = e2; + goto L1; + } + else if (e1->op == TOKstring && e2->op == TOKnull) + { e = e1; + t = e2->type; + L1: + Type *tb = t->toBasetype(); + if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) + { Expressions *expressions = new Expressions(); + expressions->push(e); + e = new ArrayLiteralExp(loc, expressions); + e->type = t; + } + if (!e->type->equals(type)) + { StringExp *se = (StringExp *)e->copy(); + e = se->castTo(NULL, type); + } + } + return e; +} + +Expression *Ptr(Type *type, Expression *e1) +{ + //printf("Ptr(e1 = %s)\n", e1->toChars()); + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + if (ade->e1->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ade->e1; + unsigned offset = ae->e2->toInteger(); + Expression *e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + return EXP_CANT_INTERPRET; +} +