mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-08 03:46:02 +03:00
1606 lines
38 KiB
C
1606 lines
38 KiB
C
|
|
// 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(loc, 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);
|
|
#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
|
|
// freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?!
|
|
// arm also doesn't like fmodl
|
|
c = complex_t(fmod(e1->toReal(), r2), fmod(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);
|
|
#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__)
|
|
// freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?!
|
|
// arm also doesn't like fmodl
|
|
c = complex_t(fmod(e1->toReal(), i2), fmod(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(loc, 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;
|
|
e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type);
|
|
return e;
|
|
}
|
|
|
|
Expression *Or(Type *type, Expression *e1, Expression *e2)
|
|
{ Expression *e;
|
|
e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type);
|
|
return e;
|
|
}
|
|
|
|
Expression *Xor(Type *type, Expression *e1, Expression *e2)
|
|
{ Expression *e;
|
|
e = new IntegerExp(e1->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;
|
|
|
|
if (es1->sz != es2->sz)
|
|
{
|
|
assert(global.errors);
|
|
return EXP_CANT_INTERPRET;
|
|
}
|
|
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;
|
|
|
|
//printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
|
|
|
|
if (e1->op == TOKstring && e2->op == TOKstring)
|
|
{ StringExp *es1 = (StringExp *)e1;
|
|
StringExp *es2 = (StringExp *)e2;
|
|
size_t sz = es1->sz;
|
|
assert(sz == es2->sz);
|
|
|
|
size_t len = es1->len;
|
|
if (es2->len < len)
|
|
len = es2->len;
|
|
|
|
int cmp = memcmp(es1->string, es2->string, sz * len);
|
|
if (cmp == 0)
|
|
cmp = es1->len - es2->len;
|
|
|
|
switch (op)
|
|
{
|
|
case TOKlt: n = cmp < 0; break;
|
|
case TOKle: n = cmp <= 0; break;
|
|
case TOKgt: n = cmp > 0; break;
|
|
case TOKge: n = cmp >= 0; break;
|
|
|
|
case TOKleg: n = 1; break;
|
|
case TOKlg: n = cmp != 0; break;
|
|
case TOKunord: n = 0; break;
|
|
case TOKue: n = cmp == 0; break;
|
|
case TOKug: n = cmp > 0; break;
|
|
case TOKuge: n = cmp >= 0; break;
|
|
case TOKul: n = cmp < 0; break;
|
|
case TOKule: n = cmp <= 0; break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
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__
|
|
// 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("\te1->type = %s\n", e1->type->toChars());
|
|
if (e1->type->equals(type) && type->equals(to))
|
|
return e1;
|
|
if (e1->type->implicitConvTo(to) >= MATCHconst ||
|
|
to->implicitConvTo(e1->type) >= MATCHconst)
|
|
return expType(to, e1);
|
|
|
|
Type *tb = to->toBasetype();
|
|
Type *typeb = type->toBasetype();
|
|
|
|
if (e1->op == TOKstring)
|
|
{
|
|
if (tb->ty == Tarray && typeb->ty == Tarray &&
|
|
tb->nextOf()->size() == typeb->nextOf()->size())
|
|
{
|
|
return expType(to, e1);
|
|
}
|
|
}
|
|
|
|
if (e1->isConst() != 1)
|
|
return EXP_CANT_INTERPRET;
|
|
|
|
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 (typeb->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::tint32);
|
|
}
|
|
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;
|
|
Type *t1 = e1->type->toBasetype();
|
|
Type *t2 = e2->type->toBasetype();
|
|
|
|
//printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
|
|
//printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->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;
|
|
|
|
if (sz != es2->sz)
|
|
{
|
|
/* Can happen with:
|
|
* auto s = "foo"d ~ "bar"c;
|
|
*/
|
|
assert(global.errors);
|
|
return e;
|
|
}
|
|
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 &&
|
|
t1->nextOf()->equals(t2->nextOf()))
|
|
{
|
|
// 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(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex));
|
|
e->type = e->type->semantic(loc, NULL);
|
|
}
|
|
else
|
|
e->type = type;
|
|
}
|
|
else if (e1->op == TOKarrayliteral && e2->op == TOKnull &&
|
|
t1->nextOf()->equals(t2->nextOf()))
|
|
{
|
|
e = e1;
|
|
goto L3;
|
|
}
|
|
else if (e1->op == TOKnull && e2->op == TOKarrayliteral &&
|
|
t1->nextOf()->equals(t2->nextOf()))
|
|
{
|
|
e = e2;
|
|
L3:
|
|
// Concatenate the array with null
|
|
ArrayLiteralExp *es = (ArrayLiteralExp *)e;
|
|
|
|
es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy());
|
|
e = es;
|
|
|
|
if (type->toBasetype()->ty == Tsarray)
|
|
{
|
|
e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->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(loc, 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(loc, 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;
|
|
}
|
|
|