mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-12 10:53:14 +01:00
Fixed problems with label collisions when using labels inside inline asm. LabelStatement is now easily reached given its Identifier, which should be useful elsewhere too. Enabled inline asm for building the lib/compiler/llvmdc runtime code, fixing branches out of asm makes this possible.
1507 lines
36 KiB
C
1507 lines
36 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(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;
|
|
}
|
|
|