mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
In many parts the DMD frontend assumes a little endian CPU. In some parts there are checks for endianess but they are incomplete and the used definition is wrong. (Test for endianess will be removed in dmd 2.062.) In this commit I add the required #if's and also add a CMake test for endianess because there is no single compiler definition to check for.
1947 lines
56 KiB
C
1947 lines
56 KiB
C
|
|
// Compiler implementation of the D programming language
|
|
// Copyright (c) 1999-2012 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 <string.h> // mem{cpy|set|cmp}()
|
|
#include <math.h>
|
|
|
|
#if __DMC__
|
|
#include <complex.h>
|
|
#endif
|
|
|
|
#include "rmem.h"
|
|
#include "root.h"
|
|
#include "port.h"
|
|
|
|
#include "mtype.h"
|
|
#include "expression.h"
|
|
#include "aggregate.h"
|
|
#include "declaration.h"
|
|
#include "utf.h"
|
|
|
|
#define LOG 0
|
|
|
|
int RealEquals(real_t x1, real_t x2);
|
|
|
|
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 NullExp::isConst()
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
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 = Port::fmodl(e1->toReal(), r2) + Port::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(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2));
|
|
#endif
|
|
}
|
|
else if (e2->type->isimaginary())
|
|
{ real_t i2 = e2->toImaginary();
|
|
|
|
#ifdef __DMC__
|
|
c = Port::fmodl(e1->toReal(), i2) + Port::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(Port::fmodl(e1->toReal(), i2), Port::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 (n2 == -1 && !type->isunsigned())
|
|
{ // Check for int.min % -1
|
|
if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64)
|
|
{
|
|
e2->error("integer overflow: int.min % -1");
|
|
e2 = new IntegerExp(loc, 1, e2->type);
|
|
n2 = 1;
|
|
}
|
|
else if (n1 == 0x8000000000000000LL) // long.min % -1
|
|
{
|
|
e2->error("integer overflow: long.min % -1");
|
|
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 *Pow(Type *type, Expression *e1, Expression *e2)
|
|
{ Expression *e;
|
|
Loc loc = e1->loc;
|
|
|
|
// Handle integer power operations.
|
|
if (e2->type->isintegral())
|
|
{
|
|
Expression * r;
|
|
Expression * v;
|
|
dinteger_t n = e2->toInteger();
|
|
bool neg;
|
|
|
|
if (!e2->type->isunsigned() && (sinteger_t)n < 0)
|
|
{
|
|
if (e1->type->isintegral())
|
|
return EXP_CANT_INTERPRET;
|
|
|
|
// Don't worry about overflow, from now on n is unsigned.
|
|
neg = true;
|
|
n = -n;
|
|
}
|
|
else
|
|
neg = false;
|
|
|
|
if (e1->type->isfloating())
|
|
{
|
|
r = new RealExp(loc, e1->toReal(), e1->type);
|
|
v = new RealExp(loc, ldouble(1.0), e1->type);
|
|
}
|
|
else
|
|
{
|
|
r = new RealExp(loc, e1->toReal(), Type::tfloat64);
|
|
v = new RealExp(loc, ldouble(1.0), Type::tfloat64);
|
|
}
|
|
|
|
while (n != 0)
|
|
{
|
|
if (n & 1)
|
|
v = Mul(v->type, v, r);
|
|
n >>= 1;
|
|
r = Mul(r->type, r, r);
|
|
}
|
|
|
|
if (neg)
|
|
v = Div(v->type, new RealExp(loc, ldouble(1.0), v->type), v);
|
|
|
|
if (type->isintegral())
|
|
e = new IntegerExp(loc, v->toInteger(), type);
|
|
else
|
|
e = new RealExp(loc, v->toReal(), type);
|
|
}
|
|
else if (e2->type->isfloating())
|
|
{
|
|
// x ^^ y for x < 0 and y not an integer is not defined
|
|
if (e1->toReal() < 0.0)
|
|
{
|
|
e = new RealExp(loc, ldouble(Port::nan), type);
|
|
}
|
|
else if (e2->toReal() == 0.5)
|
|
{
|
|
// Special case: call sqrt directly.
|
|
Expressions args;
|
|
args.setDim(1);
|
|
args[0] = e1;
|
|
e = eval_builtin(loc, BUILTINsqrt, &args);
|
|
if (!e)
|
|
e = EXP_CANT_INTERPRET;
|
|
}
|
|
else
|
|
e = EXP_CANT_INTERPRET;
|
|
}
|
|
else
|
|
e = EXP_CANT_INTERPRET;
|
|
|
|
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)
|
|
{
|
|
Loc loc = e1->loc;
|
|
|
|
dinteger_t value = e1->toInteger();
|
|
dinteger_t dcount = e2->toInteger();
|
|
assert(dcount <= 0xFFFFFFFF);
|
|
unsigned count = (unsigned)dcount;
|
|
switch (e1->type->toBasetype()->ty)
|
|
{
|
|
case Tint8:
|
|
value = (d_int8)(value) >> count;
|
|
break;
|
|
|
|
case Tuns8:
|
|
case Tchar:
|
|
value = (d_uns8)(value) >> count;
|
|
break;
|
|
|
|
case Tint16:
|
|
value = (d_int16)(value) >> count;
|
|
break;
|
|
|
|
case Tuns16:
|
|
case Twchar:
|
|
value = (d_uns16)(value) >> count;
|
|
break;
|
|
|
|
case Tint32:
|
|
value = (d_int32)(value) >> count;
|
|
break;
|
|
|
|
case Tuns32:
|
|
case Tdchar:
|
|
value = (d_uns32)(value) >> count;
|
|
break;
|
|
|
|
case Tint64:
|
|
value = (d_int64)(value) >> count;
|
|
break;
|
|
|
|
case Tuns64:
|
|
value = (d_uns64)(value) >> count;
|
|
break;
|
|
|
|
case Terror:
|
|
return e1;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
Expression *e = new IntegerExp(loc, value, type);
|
|
return e;
|
|
}
|
|
|
|
Expression *Ushr(Type *type, Expression *e1, Expression *e2)
|
|
{
|
|
Loc loc = e1->loc;
|
|
|
|
dinteger_t value = e1->toInteger();
|
|
dinteger_t dcount = e2->toInteger();
|
|
assert(dcount <= 0xFFFFFFFF);
|
|
unsigned count = (unsigned)dcount;
|
|
switch (e1->type->toBasetype()->ty)
|
|
{
|
|
case Tint8:
|
|
case Tuns8:
|
|
case Tchar:
|
|
// Possible only with >>>=. >>> always gets promoted to int.
|
|
value = (value & 0xFF) >> count;
|
|
break;
|
|
|
|
case Tint16:
|
|
case Tuns16:
|
|
case Twchar:
|
|
// Possible only with >>>=. >>> always gets promoted to int.
|
|
value = (value & 0xFFFF) >> count;
|
|
break;
|
|
|
|
case Tint32:
|
|
case Tuns32:
|
|
case Tdchar:
|
|
value = (value & 0xFFFFFFFF) >> count;
|
|
break;
|
|
|
|
case Tint64:
|
|
case Tuns64:
|
|
value = (d_uns64)(value) >> count;
|
|
break;
|
|
|
|
case Terror:
|
|
return e1;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
Expression *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 = (*es1->elements)[i];
|
|
Expression *ee2 = (*es2->elements)[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 *etmp = e1;
|
|
e1 = e2;
|
|
e2 = etmp;
|
|
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
|
|
{
|
|
cmp = 1; // if dim1 winds up being 0
|
|
for (size_t i = 0; i < dim1; i++)
|
|
{
|
|
uinteger_t c = es1->charAt(i);
|
|
Expression *ee2 = (*es2->elements)[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 = (*es1->elements)[i];
|
|
Expression *ee2 = (*es2->elements)[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 (Port::isNan(r1) || Port::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() || e1->type->toBasetype()->ty == Tpointer)
|
|
{
|
|
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)
|
|
{
|
|
Loc loc = e1->loc;
|
|
int cmp;
|
|
|
|
if (e1->op == TOKnull)
|
|
{
|
|
cmp = (e2->op == TOKnull);
|
|
}
|
|
else if (e2->op == TOKnull)
|
|
{
|
|
cmp = 0;
|
|
}
|
|
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->type->isreal())
|
|
{
|
|
cmp = RealEquals(e1->toReal(), e2->toReal());
|
|
}
|
|
else if (e1->type->isimaginary())
|
|
{
|
|
cmp = RealEquals(e1->toImaginary(), e2->toImaginary());
|
|
}
|
|
else if (e1->type->iscomplex())
|
|
{
|
|
complex_t v1 = e1->toComplex();
|
|
complex_t v2 = e2->toComplex();
|
|
cmp = RealEquals(creall(v1), creall(v2)) &&
|
|
RealEquals(cimagl(v1), cimagl(v1));
|
|
}
|
|
else
|
|
return Equal((op == TOKidentity) ? TOKequal : TOKnotequal,
|
|
type, e1, e2);
|
|
}
|
|
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;
|
|
dinteger_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 (Port::isNan(r1) || Port::isNan(r2)) // if unordered
|
|
{
|
|
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);
|
|
|
|
// Allow covariant converions of delegates
|
|
// (Perhaps implicit conversion from pure to impure should be a MATCHconst,
|
|
// then we wouldn't need this extra check.)
|
|
if (e1->type->toBasetype()->ty == Tdelegate &&
|
|
e1->type->implicitConvTo(to) == MATCHconvert)
|
|
return expType(to, e1);
|
|
|
|
Type *tb = to->toBasetype();
|
|
Type *typeb = type->toBasetype();
|
|
|
|
/* Allow casting from one string type to another
|
|
*/
|
|
if (e1->op == TOKstring)
|
|
{
|
|
if (tb->ty == Tarray && typeb->ty == Tarray &&
|
|
tb->nextOf()->size() == typeb->nextOf()->size())
|
|
{
|
|
return expType(to, e1);
|
|
}
|
|
}
|
|
|
|
if (e1->op == TOKarrayliteral && typeb == tb)
|
|
return 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())
|
|
{ dinteger_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 = sd->fields[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
|
|
{
|
|
if (type != Type::terror)
|
|
error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars());
|
|
e = new ErrorExp();
|
|
}
|
|
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 .. %llu]", i, (ulonglong)es1->len);
|
|
e = new ErrorExp();
|
|
}
|
|
else
|
|
{
|
|
e = new IntegerExp(loc, es1->charAt(i), 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)
|
|
{
|
|
e1->error("array index %llu is out of bounds %s[0 .. %llu]", i, e1->toChars(), length);
|
|
e = new ErrorExp();
|
|
}
|
|
else if (e1->op == TOKarrayliteral)
|
|
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
|
|
e = (*ale->elements)[i];
|
|
e->type = type;
|
|
if (e->hasSideEffect())
|
|
e = EXP_CANT_INTERPRET;
|
|
}
|
|
}
|
|
else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64)
|
|
{
|
|
uinteger_t i = e2->toInteger();
|
|
|
|
if (e1->op == TOKarrayliteral)
|
|
{ ArrayLiteralExp *ale = (ArrayLiteralExp *)e1;
|
|
if (i >= ale->elements->dim)
|
|
{
|
|
e1->error("array index %llu is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim);
|
|
e = new ErrorExp();
|
|
}
|
|
else
|
|
{ e = (*ale->elements)[i];
|
|
e->type = type;
|
|
if (e->hasSideEffect())
|
|
e = EXP_CANT_INTERPRET;
|
|
}
|
|
}
|
|
}
|
|
else if (e1->op == TOKassocarrayliteral)
|
|
{
|
|
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 = (*ae->keys)[i];
|
|
Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2);
|
|
if (ex == EXP_CANT_INTERPRET)
|
|
return ex;
|
|
if (ex->isBool(TRUE))
|
|
{ e = (*ae->values)[i];
|
|
e->type = type;
|
|
if (e->hasSideEffect())
|
|
e = EXP_CANT_INTERPRET;
|
|
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);
|
|
e = new ErrorExp();
|
|
}
|
|
else
|
|
{
|
|
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->hasSideEffect())
|
|
{ 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);
|
|
e = new ErrorExp();
|
|
}
|
|
else
|
|
{
|
|
Expressions *elements = new Expressions();
|
|
elements->setDim(iupr - ilwr);
|
|
memcpy(elements->tdata(),
|
|
es1->elements->tdata() + ilwr,
|
|
(iupr - ilwr) * sizeof((*es1->elements)[0]));
|
|
e = new ArrayLiteralExp(e1->loc, elements);
|
|
e->type = type;
|
|
}
|
|
}
|
|
return e;
|
|
}
|
|
|
|
/* Set a slice of char array literal 'existingAE' from a string 'newval'.
|
|
* existingAE[firstIndex..firstIndex+newval.length] = newval.
|
|
*/
|
|
void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex)
|
|
{
|
|
size_t newlen = newval->len;
|
|
size_t sz = newval->sz;
|
|
unsigned char *s = (unsigned char *)newval->string;
|
|
Type *elemType = existingAE->type->nextOf();
|
|
for (size_t j = 0; j < newlen; j++)
|
|
{
|
|
dinteger_t val;
|
|
switch (sz)
|
|
{
|
|
case 1: val = s[j]; break;
|
|
case 2: val = ((unsigned short *)s)[j]; break;
|
|
case 4: val = ((unsigned *)s)[j]; break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
(*existingAE->elements)[j+firstIndex]
|
|
= new IntegerExp(newval->loc, val, elemType);
|
|
}
|
|
}
|
|
|
|
/* Set a slice of string 'existingSE' from a char array literal 'newae'.
|
|
* existingSE[firstIndex..firstIndex+newae.length] = newae.
|
|
*/
|
|
void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex)
|
|
{
|
|
unsigned char *s = (unsigned char *)existingSE->string;
|
|
for (size_t j = 0; j < newae->elements->dim; j++)
|
|
{
|
|
unsigned value = (unsigned)((*newae->elements)[j]->toInteger());
|
|
switch (existingSE->sz)
|
|
{
|
|
case 1: s[j+firstIndex] = value; break;
|
|
case 2: ((unsigned short *)s)[j+firstIndex] = value; break;
|
|
case 4: ((unsigned *)s)[j+firstIndex] = value; break;
|
|
default:
|
|
assert(0);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set a slice of string 'existingSE' from a string 'newstr'.
|
|
* existingSE[firstIndex..firstIndex+newstr.length] = newstr.
|
|
*/
|
|
void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex)
|
|
{
|
|
unsigned char *s = (unsigned char *)existingSE->string;
|
|
size_t sz = existingSE->sz;
|
|
assert(sz == newstr->sz);
|
|
memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len);
|
|
}
|
|
|
|
/* Compare a string slice with another string slice.
|
|
* Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
|
|
*/
|
|
int sliceCmpStringWithString(StringExp *se1, StringExp *se2, size_t lo1, size_t lo2, size_t len)
|
|
{
|
|
unsigned char *s1 = (unsigned char *)se1->string;
|
|
unsigned char *s2 = (unsigned char *)se2->string;
|
|
size_t sz = se1->sz;
|
|
assert(sz == se2->sz);
|
|
|
|
return memcmp(s1 + sz * lo1, s2 + sz * lo2, sz * len);
|
|
}
|
|
|
|
/* Compare a string slice with an array literal slice
|
|
* Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
|
|
*/
|
|
int sliceCmpStringWithArray(StringExp *se1, ArrayLiteralExp *ae2, size_t lo1, size_t lo2, size_t len)
|
|
{
|
|
unsigned char *s = (unsigned char *)se1->string;
|
|
size_t sz = se1->sz;
|
|
|
|
int c = 0;
|
|
|
|
for (size_t j = 0; j < len; j++)
|
|
{
|
|
unsigned value = (unsigned)((*ae2->elements)[j + lo2]->toInteger());
|
|
unsigned svalue;
|
|
switch (sz)
|
|
{
|
|
case 1: svalue = s[j + lo1]; break;
|
|
case 2: svalue = ((unsigned short *)s)[j+lo1]; break;
|
|
case 4: svalue = ((unsigned *)s)[j + lo1]; break;
|
|
default:
|
|
assert(0);
|
|
}
|
|
int c = svalue - value;
|
|
if (c)
|
|
return c;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* 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, type = %s\n", t1->toChars(), t2->toChars(), type->toChars());
|
|
|
|
if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral))
|
|
{ e = e2;
|
|
t = t1;
|
|
goto L2;
|
|
}
|
|
else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull)
|
|
{ e = e1;
|
|
t = t2;
|
|
L2:
|
|
Type *tn = e->type->toBasetype();
|
|
if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar)
|
|
{
|
|
// Create a StringExp
|
|
void *s;
|
|
StringExp *es;
|
|
if (t->nextOf())
|
|
t = t->nextOf()->toBasetype();
|
|
int sz = t->size();
|
|
|
|
dinteger_t v = e->toInteger();
|
|
|
|
size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v);
|
|
s = mem.malloc((len + 1) * sz);
|
|
if (t->ty == tn->ty)
|
|
#if IN_LLVM
|
|
#if __LITTLE_ENDIAN__
|
|
memcpy((unsigned char *)s, &v, sz);
|
|
#else
|
|
memcpy((unsigned char *)s,
|
|
(unsigned char *)&v + (sizeof(dinteger_t) - sz), sz);
|
|
#endif
|
|
#else
|
|
memcpy((unsigned char *)s, &v, sz);
|
|
#endif
|
|
else
|
|
utf_encode(sz, s, v);
|
|
|
|
// 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 == TOKnull && e2->op == TOKnull)
|
|
{
|
|
if (type == e1->type)
|
|
{
|
|
// Handle null ~= null
|
|
if (t1->ty == Tarray && t2 == t1->nextOf())
|
|
{
|
|
e = new ArrayLiteralExp(e1->loc, e2);
|
|
e->type = type;
|
|
return e;
|
|
}
|
|
else
|
|
return e1;
|
|
}
|
|
if (type == e2->type)
|
|
return e2;
|
|
return new NullExp(e1->loc, type);
|
|
}
|
|
else if (e1->op == TOKstring && e2->op == TOKstring)
|
|
{
|
|
// Concatenate the strings
|
|
void *s;
|
|
StringExp *es1 = (StringExp *)e1;
|
|
StringExp *es2 = (StringExp *)e2;
|
|
StringExp *es;
|
|
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;
|
|
es->type = type;
|
|
e = es;
|
|
}
|
|
else if (e2->op == TOKstring && e1->op == TOKarrayliteral &&
|
|
t1->nextOf()->isintegral())
|
|
{
|
|
// [chars] ~ string --> [chars]
|
|
StringExp *es = (StringExp *)e2;
|
|
ArrayLiteralExp *ea = (ArrayLiteralExp *)e1;
|
|
size_t len = es->len + ea->elements->dim;
|
|
Expressions * elems = new Expressions;
|
|
elems->setDim(len);
|
|
for (size_t i= 0; i < ea->elements->dim; ++i)
|
|
{
|
|
(*elems)[i] = (*ea->elements)[i];
|
|
}
|
|
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
|
|
dest->type = type;
|
|
sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim);
|
|
return dest;
|
|
}
|
|
else if (e1->op == TOKstring && e2->op == TOKarrayliteral &&
|
|
t2->nextOf()->isintegral())
|
|
{
|
|
// string ~ [chars] --> [chars]
|
|
StringExp *es = (StringExp *)e1;
|
|
ArrayLiteralExp *ea = (ArrayLiteralExp *)e2;
|
|
size_t len = es->len + ea->elements->dim;
|
|
Expressions * elems = new Expressions;
|
|
elems->setDim(len);
|
|
for (size_t i= 0; i < ea->elements->dim; ++i)
|
|
{
|
|
(*elems)[es->len + i] = (*ea->elements)[i];
|
|
}
|
|
ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems);
|
|
dest->type = type;
|
|
sliceAssignArrayLiteralFromString(dest, es, 0);
|
|
return dest;
|
|
}
|
|
else if (e1->op == TOKstring && e2->op == TOKint64)
|
|
{
|
|
// string ~ char --> string
|
|
void *s;
|
|
StringExp *es1 = (StringExp *)e1;
|
|
StringExp *es;
|
|
int sz = es1->sz;
|
|
dinteger_t v = e2->toInteger();
|
|
|
|
// Is it a concatentation of homogenous types?
|
|
// (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
|
|
bool homoConcat = (sz == t2->size());
|
|
size_t len = es1->len;
|
|
len += homoConcat ? 1 : utf_codeLength(sz, v);
|
|
|
|
s = mem.malloc((len + 1) * sz);
|
|
memcpy(s, es1->string, es1->len * sz);
|
|
if (homoConcat)
|
|
#if IN_LLVM
|
|
#if __LITTLE_ENDIAN__
|
|
memcpy((unsigned char *)s + (sz * es1->len), &v, sz);
|
|
#else
|
|
memcpy((unsigned char *)s + (sz * es1->len),
|
|
(unsigned char *)&v + (sizeof(dinteger_t) - sz), sz);
|
|
#endif
|
|
#else
|
|
memcpy((unsigned char *)s + (sz * es1->len), &v, sz);
|
|
#endif
|
|
else
|
|
utf_encode(sz, (unsigned char *)s + (sz * es1->len), v);
|
|
|
|
// Add terminating 0
|
|
memset((unsigned char *)s + len * sz, 0, sz);
|
|
|
|
es = new StringExp(loc, s, len);
|
|
es->sz = sz;
|
|
es->committed = es1->committed;
|
|
es->type = type;
|
|
e = es;
|
|
}
|
|
else if (e1->op == TOKint64 && e2->op == TOKstring)
|
|
{
|
|
// Concatenate the strings
|
|
void *s;
|
|
StringExp *es2 = (StringExp *)e2;
|
|
StringExp *es;
|
|
size_t len = 1 + es2->len;
|
|
int sz = es2->sz;
|
|
dinteger_t v = e1->toInteger();
|
|
|
|
s = mem.malloc((len + 1) * sz);
|
|
#if IN_LLVM
|
|
#if __LITTLE_ENDIAN__
|
|
memcpy((unsigned char *)s, &v, sz);
|
|
#else
|
|
memcpy((unsigned char *)s,
|
|
(unsigned char *)&v + (sizeof(dinteger_t) - sz), sz);
|
|
#endif
|
|
#else
|
|
memcpy((unsigned char *)s, &v, sz);
|
|
#endif
|
|
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;
|
|
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;
|
|
}
|
|
|