Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

10625 lines (9297 sloc) 279.839 kb
// 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 <ctype.h>
#include <math.h>
#include <assert.h>
#if _MSC_VER
#include <complex>
#else
#include <complex>
#endif
#if _WIN32 && __DMC__
extern "C" char * __cdecl __locale_decpoint;
#endif
#if __MINGW32__
#ifndef isnan
#define isnan _isnan
#endif
#endif
#ifdef __APPLE__
#ifndef isnan
int isnan(double);
#endif
#endif
#include "rmem.h"
#include "port.h"
#include "mtype.h"
#include "init.h"
#include "expression.h"
#include "template.h"
#include "utf.h"
#include "enum.h"
#include "scope.h"
#include "statement.h"
#include "declaration.h"
#include "aggregate.h"
#include "import.h"
#include "id.h"
#include "dsymbol.h"
#include "module.h"
#include "attrib.h"
#include "hdrgen.h"
#include "parse.h"
#include "doc.h"
Expression *createTypeInfoArray(Scope *sc, Expression *args[], unsigned dim);
Expression *expandVar(int result, VarDeclaration *v);
#define LOGSEMANTIC 0
/*************************************************************
* Given var, we need to get the
* right 'this' pointer if var is in an outer class, but our
* existing 'this' pointer is in an inner class.
* Input:
* e1 existing 'this'
* ad struct or class we need the correct 'this' for
* var the specific member of ad we're accessing
*/
Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad,
Expression *e1, Declaration *var)
{
//printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars());
L1:
Type *t = e1->type->toBasetype();
//printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars());
/* If e1 is not the 'this' pointer for ad
*/
if (ad &&
!(t->ty == Tpointer && t->nextOf()->ty == Tstruct &&
((TypeStruct *)t->nextOf())->sym == ad)
&&
!(t->ty == Tstruct &&
((TypeStruct *)t)->sym == ad)
)
{
ClassDeclaration *cd = ad->isClassDeclaration();
ClassDeclaration *tcd = t->isClassHandle();
/* e1 is the right this if ad is a base class of e1
*/
if (!cd || !tcd ||
!(tcd == cd || cd->isBaseOf(tcd, NULL))
)
{
/* Only classes can be inner classes with an 'outer'
* member pointing to the enclosing class instance
*/
if (tcd && tcd->isNested())
{ /* e1 is the 'this' pointer for an inner class: tcd.
* Rewrite it as the 'this' pointer for the outer class.
*/
e1 = new DotVarExp(loc, e1, tcd->vthis);
e1->type = tcd->vthis->type;
// Do not call checkNestedRef()
//e1 = e1->semantic(sc);
// Skip up over nested functions, and get the enclosing
// class type.
int n = 0;
Dsymbol *s;
for (s = tcd->toParent();
s && s->isFuncDeclaration();
s = s->toParent())
{ FuncDeclaration *f = s->isFuncDeclaration();
if (f->vthis)
{
//printf("rewriting e1 to %s's this\n", f->toChars());
n++;
// LDC seems dmd misses it sometimes here :/
f->vthis->nestedref = 1;
e1 = new VarExp(loc, f->vthis);
}
else
{
e1->error("need 'this' of type %s to access member %s"
" from static function %s",
ad->toChars(), var->toChars(), f->toChars());
e1 = new ErrorExp();
return e1;
}
}
if (s && s->isClassDeclaration())
{ e1->type = s->isClassDeclaration()->type;
if (n > 1)
e1 = e1->semantic(sc);
}
else
e1 = e1->semantic(sc);
goto L1;
}
/* Can't find a path from e1 to ad
*/
e1->error("this for %s needs to be type %s not type %s",
var->toChars(), ad->toChars(), t->toChars());
e1 = new ErrorExp();
}
}
return e1;
}
/*****************************************
* Determine if 'this' is available.
* If it is, return the FuncDeclaration that has it.
*/
FuncDeclaration *hasThis(Scope *sc)
{ FuncDeclaration *fd;
FuncDeclaration *fdthis;
//printf("hasThis()\n");
fdthis = sc->parent->isFuncDeclaration();
//printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : "");
// Go upwards until we find the enclosing member function
fd = fdthis;
while (1)
{
if (!fd)
{
goto Lno;
}
if (!fd->isNested())
break;
Dsymbol *parent = fd->parent;
while (1)
{
if (!parent)
goto Lno;
TemplateInstance *ti = parent->isTemplateInstance();
if (ti)
parent = ti->parent;
else
break;
}
fd = parent->isFuncDeclaration();
}
if (!fd->isThis())
{ //printf("test '%s'\n", fd->toChars());
goto Lno;
}
assert(fd->vthis);
return fd;
Lno:
return NULL; // don't have 'this' available
}
/***************************************
* Pull out any properties.
*/
Expression *resolveProperties(Scope *sc, Expression *e)
{
//printf("resolveProperties(%s)\n", e->toChars());
if (e->type)
{
Type *t = e->type->toBasetype();
if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/)
{
e = new CallExp(e->loc, e);
e = e->semantic(sc);
}
/* Look for e being a lazy parameter; rewrite as delegate call
*/
else if (e->op == TOKvar)
{ VarExp *ve = (VarExp *)e;
if (ve->var->storage_class & STClazy)
{
e = new CallExp(e->loc, e);
e = e->semantic(sc);
}
}
else if (e->op == TOKdotexp)
{
e->error("expression has no value");
return new ErrorExp();
}
}
else if (e->op == TOKdottd)
{
e = new CallExp(e->loc, e);
e = e->semantic(sc);
}
return e;
}
/******************************
* Perform semantic() on an array of Expressions.
*/
Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc)
{
if (exps)
{
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (Expression *)exps->data[i];
if (e)
{ e = e->semantic(sc);
exps->data[i] = (void *)e;
}
}
}
return exps;
}
/******************************
* Perform canThrow() on an array of Expressions.
*/
#if DMDV2
int arrayExpressionCanThrow(Expressions *exps)
{
if (exps)
{
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (Expression *)exps->data[i];
if (e && e->canThrow())
return 1;
}
}
return 0;
}
#endif
/****************************************
* Expand tuples.
*/
void expandTuples(Expressions *exps)
{
//printf("expandTuples()\n");
if (exps)
{
for (size_t i = 0; i < exps->dim; i++)
{ Expression *arg = (Expression *)exps->data[i];
if (!arg)
continue;
// Look for tuple with 0 members
if (arg->op == TOKtype)
{ TypeExp *e = (TypeExp *)arg;
if (e->type->toBasetype()->ty == Ttuple)
{ TypeTuple *tt = (TypeTuple *)e->type->toBasetype();
if (!tt->arguments || tt->arguments->dim == 0)
{
exps->remove(i);
if (i == exps->dim)
return;
i--;
continue;
}
}
}
// Inline expand all the tuples
while (arg->op == TOKtuple)
{ TupleExp *te = (TupleExp *)arg;
exps->remove(i); // remove arg
exps->insert(i, te->exps); // replace with tuple contents
if (i == exps->dim)
return; // empty tuple, no more arguments
arg = (Expression *)exps->data[i];
}
}
}
}
Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt)
{
#if DMDV1
/* The first element sets the type
*/
Type *t0 = NULL;
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (*exps)[i];
if (!e->type)
{ error(e->loc, "%s has no value", e->toChars());
e = new ErrorExp();
}
e = resolveProperties(sc, e);
if (!t0)
t0 = e->type;
else
e = e->implicitCastTo(sc, t0);
(*exps)[i] = e;
}
if (!t0)
t0 = Type::tvoid;
if (pt)
*pt = t0;
// Eventually, we want to make this copy-on-write
return exps;
#endif
#if DMDV2
/* The type is determined by applying ?: to each pair.
*/
/* Still have a problem with:
* ubyte[][] = [ cast(ubyte[])"hello", [1]];
* which works if the array literal is initialized top down with the ubyte[][]
* type, but fails with this function doing bottom up typing.
*/
//printf("arrayExpressionToCommonType()\n");
IntegerExp integerexp(0);
CondExp condexp(0, &integerexp, NULL, NULL);
Type *t0 = NULL;
Expression *e0;
int j0;
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (*exps)[i];
e = resolveProperties(sc, e);
if (!e->type)
{ e->error("%s has no value", e->toChars());
e = new ErrorExp();
}
if (t0)
{ if (t0 != e->type)
{
/* This applies ?: to merge the types. It's backwards;
* ?: should call this function to merge types.
*/
condexp.type = NULL;
condexp.e1 = e0;
condexp.e2 = e;
condexp.loc = e->loc;
condexp.semantic(sc);
(*exps)[j0] = condexp.e1;
e = condexp.e2;
j0 = i;
e0 = e;
t0 = e0->type;
}
}
else
{ j0 = i;
e0 = e;
t0 = e->type;
}
(*exps)[i] = e;
}
if (t0)
{
for (size_t i = 0; i < exps->dim; i++)
{ Expression *e = (*exps)[i];
e = e->implicitCastTo(sc, t0);
(*exps)[i] = e;
}
}
else
t0 = Type::tvoid; // [] is typed as void[]
if (pt)
*pt = t0;
// Eventually, we want to make this copy-on-write
return exps;
#endif
}
/****************************************
* Get TemplateDeclaration enclosing FuncDeclaration.
*/
TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s)
{
FuncDeclaration *f = s->isFuncDeclaration();
if (f && f->parent)
{ TemplateInstance *ti = f->parent->isTemplateInstance();
if (ti &&
!ti->isTemplateMixin() &&
(ti->name == f->ident ||
ti->toAlias()->ident == f->ident)
&&
ti->tempdecl && ti->tempdecl->onemember)
{
return ti->tempdecl;
}
}
return NULL;
}
/****************************************
* Preprocess arguments to function.
*/
void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps)
{
if (exps)
{
expandTuples(exps);
for (size_t i = 0; i < exps->dim; i++)
{ Expression *arg = (*exps)[i];
if (!arg->type)
{
#ifdef DEBUG
if (!global.gag)
printf("1: \n");
#endif
arg->error("%s is not an expression", arg->toChars());
arg = new ErrorExp();
}
arg = resolveProperties(sc, arg);
(*exps)[i] = arg;
//arg->rvalue();
#if 0
if (arg->type->ty == Tfunction)
{
arg = new AddrExp(arg->loc, arg);
arg = arg->semantic(sc);
(*exps)[i] = arg;
}
#endif
}
}
}
/*********************************************
* Call copy constructor for struct value argument.
*/
#if DMDV2
Expression *callCpCtor(Loc loc, Scope *sc, Expression *e)
{
Type *tb = e->type->toBasetype();
assert(tb->ty == Tstruct);
StructDeclaration *sd = ((TypeStruct *)tb)->sym;
if (sd->cpctor)
{
/* Create a variable tmp, and replace the argument e with:
* (tmp = e),tmp
* and let AssignExp() handle the construction.
* This is not the most efficent, ideally tmp would be constructed
* directly onto the stack.
*/
Identifier *idtmp = Lexer::uniqueId("__tmp");
VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e));
tmp->storage_class |= STCctfe;
Expression *ae = new DeclarationExp(loc, tmp);
e = new CommaExp(loc, ae, new VarExp(loc, tmp));
e = e->semantic(sc);
}
return e;
}
#endif
/****************************************
* Now that we know the exact type of the function we're calling,
* the arguments[] need to be adjusted:
* 1. implicitly convert argument to the corresponding parameter type
* 2. add default arguments for any missing arguments
* 3. do default promotions on arguments corresponding to ...
* 4. add hidden _arguments[] argument
*/
void functionParameters(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments)
{
//printf("functionParameters()\n");
assert(arguments);
size_t nargs = arguments ? arguments->dim : 0;
size_t nparams = Parameter::dim(tf->parameters);
if (nargs > nparams && tf->varargs == 0)
error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars());
#if DMDV2
// If inferring return type, and semantic3() needs to be run if not already run
if (!tf->next && fd->inferRetType)
{
TemplateInstance *spec = fd->isSpeculative();
int olderrs = global.errors;
fd->semantic3(fd->scope);
// Update the template instantiation with the number
// of errors which occured.
if (spec && global.errors != olderrs)
spec->errors = global.errors - olderrs;
}
#endif
unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
int done = 0;
for (size_t i = 0; i < n; i++)
{
Expression *arg;
if (i < nargs)
arg = (*arguments)[i];
else
arg = NULL;
if (i < nparams)
{
Parameter *p = Parameter::getNth(tf->parameters, i);
if (!arg)
{
if (!p->defaultArg)
{
if (tf->varargs == 2 && i + 1 == nparams)
goto L2;
error(loc, "expected %zu function arguments, not %zu", nparams, nargs);
return;
}
arg = p->defaultArg;
arg = arg->inlineCopy(sc);
#if DMDV2
arg = arg->resolveLoc(loc, sc); // __FILE__ and __LINE__
#endif
arguments->push(arg);
nargs++;
}
if (tf->varargs == 2 && i + 1 == nparams)
{
//printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars());
MATCH m;
if ((m = arg->implicitConvTo(p->type)) != MATCHnomatch)
{
if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf()) >= m)
goto L2;
else if (nargs != nparams)
{ error(loc, "expected %llu function arguments, not %llu", (ulonglong)nparams, (ulonglong)nargs);
return;
}
goto L1;
}
L2:
Type *tb = p->type->toBasetype();
Type *tret = p->isLazyArray();
switch (tb->ty)
{
case Tsarray:
case Tarray:
{ // Create a static array variable v of type arg->type
#ifdef IN_GCC
/* GCC 4.0 does not like zero length arrays used like
this; pass a null array value instead. Could also
just make a one-element array. */
if (nargs - i == 0)
{
arg = new NullExp(loc);
break;
}
#endif
Identifier *id = Lexer::uniqueId("__arrayArg");
Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i));
t = t->semantic(loc, sc);
VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc));
v->storage_class |= STCctfe;
v->semantic(sc);
v->parent = sc->parent;
//sc->insert(v);
Expression *c = new DeclarationExp(0, v);
c->type = v->type;
for (size_t u = i; u < nargs; u++)
{ Expression *a = (*arguments)[u];
if (tret && !((TypeArray *)tb)->next->equals(a->type))
a = a->toDelegate(sc, tret);
Expression *e = new VarExp(loc, v);
e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams));
AssignExp *ae = new AssignExp(loc, e, a);
if (c)
c = new CommaExp(loc, c, ae);
else
c = ae;
}
arg = new VarExp(loc, v);
if (c)
arg = new CommaExp(loc, c, arg);
break;
}
case Tclass:
{ /* Set arg to be:
* new Tclass(arg0, arg1, ..., argn)
*/
Expressions *args = new Expressions();
args->setDim(nargs - i);
for (size_t u = i; u < nargs; u++)
args->data[u - i] = arguments->data[u];
arg = new NewExp(loc, NULL, NULL, p->type, args);
break;
}
default:
if (!arg)
{ error(loc, "not enough arguments");
return;
}
break;
}
arg = arg->semantic(sc);
//printf("\targ = '%s'\n", arg->toChars());
arguments->setDim(i + 1);
done = 1;
}
L1:
if (!(p->storageClass & STClazy && p->type->ty == Tvoid))
{
if (p->type != arg->type)
{
//printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars());
if (arg->op == TOKtype)
arg->error("cannot pass type %s as function argument", arg->toChars());
arg = arg->implicitCastTo(sc, p->type);
arg = arg->optimize(WANTvalue);
}
}
if (p->storageClass & (STCout | STCref))
{
// BUG: should check that argument to ref is type 'invariant'
// BUG: assignments to ref should also be type 'invariant'
arg = arg->modifiableLvalue(sc, arg);
//if (arg->op == TOKslice)
//arg->error("cannot modify slice %s", arg->toChars());
}
// LDC we don't want this!
#if !IN_LLVM
// Convert static arrays to pointers
Type *tb = arg->type->toBasetype();
if (tb->ty == Tsarray)
{
arg = arg->checkToPointer();
}
#endif
#if DMDV2
if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout)))
{
if (arg->op == TOKcall)
{
/* The struct value returned from the function is transferred
* to the function, so the callee should not call the destructor
* on it.
*/
valueNoDtor(arg);
}
else
{ /* Not transferring it, so call the copy constructor
*/
arg = callCpCtor(loc, sc, arg, 1);
}
}
#endif
// Convert lazy argument to a delegate
if (p->storageClass & STClazy)
{
arg = arg->toDelegate(sc, p->type);
}
#if DMDV2
/* Look for arguments that cannot 'escape' from the called
* function.
*/
if (!tf->parameterEscapes(p))
{
Expression *a = arg;
if (a->op == TOKcast)
a = ((CastExp *)a)->e1;
/* Function literals can only appear once, so if this
* appearance was scoped, there cannot be any others.
*/
if (a->op == TOKfunction)
{ FuncExp *fe = (FuncExp *)a;
fe->fd->tookAddressOf = 0;
}
/* For passing a delegate to a scoped parameter,
* this doesn't count as taking the address of it.
* We only worry about 'escaping' references to the function.
*/
else if (a->op == TOKdelegate)
{ DelegateExp *de = (DelegateExp *)a;
if (de->e1->op == TOKvar)
{ VarExp *ve = (VarExp *)de->e1;
FuncDeclaration *f = ve->var->isFuncDeclaration();
if (f)
{ f->tookAddressOf--;
//printf("tookAddressOf = %d\n", f->tookAddressOf);
}
}
}
}
#endif
}
else
{
// If not D linkage, do promotions
// LDC: don't do promotions on intrinsics
if (tf->linkage != LINKd && tf->linkage != LINKintrinsic)
{
// Promote bytes, words, etc., to ints
arg = arg->integralPromotions(sc);
// Promote floats to doubles
switch (arg->type->ty)
{
case Tfloat32:
arg = arg->castTo(sc, Type::tfloat64);
break;
case Timaginary32:
arg = arg->castTo(sc, Type::timaginary64);
break;
}
}
// Convert static arrays to dynamic arrays
// BUG: I don't think this is right for D2
Type *tb = arg->type->toBasetype();
if (tb->ty == Tsarray)
{ TypeSArray *ts = (TypeSArray *)tb;
Type *ta = ts->next->arrayOf();
if (ts->size(arg->loc) == 0)
arg = new NullExp(arg->loc, ta);
else
arg = arg->castTo(sc, ta);
}
#if DMDV2
if (tb->ty == Tstruct)
{
arg = callCpCtor(loc, sc, arg);
}
#endif
// Give error for overloaded function addresses
#if DMDV2
if (arg->op == TOKsymoff)
{ SymOffExp *se = (SymOffExp *)arg;
if (
se->hasOverloads &&
!se->var->isFuncDeclaration()->isUnique())
arg->error("function %s is overloaded", arg->toChars());
}
#endif
arg->rvalue();
}
arg = arg->optimize(WANTvalue);
arguments->data[i] = (void *) arg;
if (done)
break;
}
#if !IN_LLVM
// If D linkage and variadic, add _arguments[] as first argument
if (tf->linkage == LINKd && tf->varargs == 1)
{
assert(arguments->dim >= nparams);
Expression *e = createTypeInfoArray(sc, (Expression **)&arguments->data[nparams],
arguments->dim - nparams);
arguments->insert(0, e);
}
#endif
}
/**************************************************
* Write expression out to buf, but wrap it
* in ( ) if its precedence is less than pr.
*/
void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr)
{
#ifdef DEBUG
if (precedence[e->op] == PREC_zero)
printf("precedence not defined for token '%s'\n",Token::tochars[e->op]);
#endif
assert(precedence[e->op] != PREC_zero);
assert(pr != PREC_zero);
//if (precedence[e->op] == 0) e->dump(0);
if (precedence[e->op] < pr ||
/* Despite precedence, we don't allow a<b<c expressions.
* They must be parenthesized.
*/
(pr == PREC_rel && precedence[e->op] == pr))
{
buf->writeByte('(');
e->toCBuffer(buf, hgs);
buf->writeByte(')');
}
else
e->toCBuffer(buf, hgs);
}
/**************************************************
* Write out argument list to buf.
*/
void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs)
{
if (arguments)
{
for (size_t i = 0; i < arguments->dim; i++)
{ Expression *arg = (Expression *)arguments->data[i];
if (arg)
{ if (i)
buf->writeByte(',');
expToCBuffer(buf, hgs, arg, PREC_assign);
}
}
}
}
/**************************************************
* Write out argument types to buf.
*/
void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs)
{
if (arguments)
{ OutBuffer argbuf;
for (size_t i = 0; i < arguments->dim; i++)
{ Expression *arg = (Expression *)arguments->data[i];
if (i)
buf->writeByte(',');
argbuf.reset();
arg->type->toCBuffer2(&argbuf, hgs, 0);
buf->write(&argbuf);
}
}
}
/******************************** Expression **************************/
Expression::Expression(Loc loc, enum TOK op, int size)
: loc(loc)
{
//printf("Expression::Expression(op = %d) this = %p\n", op, this);
this->loc = loc;
this->op = op;
this->size = size;
type = NULL;
#if IN_LLVM
cachedLvalue = NULL;
#endif
}
Expression *Expression::syntaxCopy()
{
//printf("Expression::syntaxCopy()\n");
//dump(0);
return copy();
}
/*********************************
* Does *not* do a deep copy.
*/
Expression *Expression::copy()
{
Expression *e;
if (!size)
{
#ifdef DEBUG
fprintf(stdmsg, "No expression copy for: %s\n", toChars());
printf("op = %d\n", op);
dump(0);
#endif
assert(0);
}
e = (Expression *)mem.malloc(size);
//printf("Expression::copy(op = %d) e = %p\n", op, e);
return (Expression *)memcpy(e, this, size);
}
/**************************
* Semantically analyze Expression.
* Determine types, fold constants, etc.
*/
Expression *Expression::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("Expression::semantic() %s\n", toChars());
#endif
if (type)
type = type->semantic(loc, sc);
else
type = Type::tvoid;
return this;
}
/**********************************
* Try to run semantic routines.
* If they fail, return NULL.
*/
Expression *Expression::trySemantic(Scope *sc)
{
//printf("+trySemantic(%s)\n", toChars());
unsigned errors = global.startGagging();
Expression *e = semantic(sc);
if (global.endGagging(errors))
{
e = NULL;
}
//printf("-trySemantic(%s)\n", toChars());
return e;
}
void Expression::print()
{
fprintf(stdmsg, "%s\n", toChars());
fflush(stdmsg);
}
char *Expression::toChars()
{ OutBuffer *buf;
HdrGenState hgs;
memset(&hgs, 0, sizeof(hgs));
buf = new OutBuffer();
toCBuffer(buf, &hgs);
return buf->toChars();
}
void Expression::error(const char *format, ...)
{
if (type != Type::terror)
{
va_list ap;
va_start(ap, format);
::verror(loc, format, ap);
va_end( ap );
}
}
void Expression::warning(const char *format, ...)
{
if (type != Type::terror)
{
va_list ap;
va_start(ap, format);
::vwarning(loc, format, ap);
va_end( ap );
}
}
int Expression::rvalue()
{
if (type && type->toBasetype()->ty == Tvoid)
{ error("expression %s is void and has no value", toChars());
#if 0
dump(0);
halt();
#endif
if (!global.gag)
type = Type::terror;
return 0;
}
return 1;
}
Expression *Expression::combine(Expression *e1, Expression *e2)
{
if (e1)
{
if (e2)
{
e1 = new CommaExp(e1->loc, e1, e2);
e1->type = e2->type;
}
}
else
e1 = e2;
return e1;
}
dinteger_t Expression::toInteger()
{
//printf("Expression %s\n", Token::toChars(op));
error("Integer constant expression expected instead of %s", toChars());
return 0;
}
uinteger_t Expression::toUInteger()
{
//printf("Expression %s\n", Token::toChars(op));
return (uinteger_t)toInteger();
}
real_t Expression::toReal()
{
error("Floating point constant expression expected instead of %s", toChars());
return ldouble(0);
}
real_t Expression::toImaginary()
{
error("Floating point constant expression expected instead of %s", toChars());
return ldouble(0);
}
complex_t Expression::toComplex()
{
error("Floating point constant expression expected instead of %s", toChars());
#ifdef IN_GCC
return complex_t(real_t(0)); // %% nicer
#else
return 0.0;
#endif
}
StringExp *Expression::toString()
{
return NULL;
}
void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring(Token::toChars(op));
}
void Expression::toMangleBuffer(OutBuffer *buf)
{
error("expression %s is not a valid template value argument", toChars());
#ifdef DEBUG
dump(0);
#endif
}
/***************************************
* Return !=0 if expression is an lvalue.
*/
#if DMDV2
int Expression::isLvalue()
{
return 0;
}
#endif
/*******************************
* Give error if we're not an lvalue.
* If we can, convert expression to be an lvalue.
*/
Expression *Expression::toLvalue(Scope *sc, Expression *e)
{
if (!e)
e = this;
else if (!loc.filename)
loc = e->loc;
error("%s is not an lvalue", e->toChars());
return this;
}
Expression *Expression::modifiableLvalue(Scope *sc, Expression *e)
{
//printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars());
// See if this expression is a modifiable lvalue (i.e. not const)
#if DMDV2
if (type && (!type->isMutable() || !type->isAssignable()))
error("%s is not mutable", e->toChars());
#endif
return toLvalue(sc, e);
}
/************************************
* Detect cases where pointers to the stack can 'escape' the
* lifetime of the stack frame.
*/
void Expression::checkEscape()
{
}
void Expression::checkEscapeRef()
{
}
void Expression::checkScalar()
{
if (!type->isscalar())
error("'%s' is not a scalar, it is a %s", toChars(), type->toChars());
}
void Expression::checkNoBool()
{
if (type->toBasetype()->ty == Tbool)
error("operation not allowed on bool '%s'", toChars());
}
Expression *Expression::checkIntegral()
{
if (!type->isintegral())
{ error("'%s' is not of integral type, it is a %s", toChars(), type->toChars());
return new ErrorExp();
}
return this;
}
Expression *Expression::checkArithmetic()
{
if (!type->isintegral() && !type->isfloating())
{ if (type->toBasetype() != Type::terror)
error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars());
return new ErrorExp();
}
return this;
}
void Expression::checkDeprecated(Scope *sc, Dsymbol *s)
{
s->checkDeprecated(loc, sc);
}
#if DMDV2
void Expression::checkPurity(Scope *sc, FuncDeclaration *f)
{
if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure())
error("pure function '%s' cannot call impure function '%s'\n",
sc->func->toChars(), f->toChars());
}
#endif
/********************************
* Check for expressions that have no use.
* Input:
* flag 0 not going to use the result, so issue error message if no
* side effects
* 1 the result of the expression is used, but still check
* for useless subexpressions
* 2 do not issue error messages, just return !=0 if expression
* has side effects
*/
int Expression::checkSideEffect(int flag)
{
if (flag == 0)
{ if (op == TOKimport)
{
error("%s has no effect", toChars());
}
else
error("%s has no effect in expression (%s)",
Token::toChars(op), toChars());
}
return 0;
}
/*****************************
* Check that expression can be tested for true or false.
*/
Expression *Expression::checkToBoolean()
{
// Default is 'yes' - do nothing
#ifdef DEBUG
if (!type)
dump(0);
#endif
if (!type->checkBoolean())
{
error("expression %s of type %s does not have a boolean value", toChars(), type->toChars());
}
return this;
}
/****************************
*/
Expression *Expression::checkToPointer()
{
Expression *e;
Type *tb;
//printf("Expression::checkToPointer()\n");
e = this;
// If C static array, convert to pointer
tb = type->toBasetype();
if (tb->ty == Tsarray)
{ TypeSArray *ts = (TypeSArray *)tb;
if (ts->size(loc) == 0)
e = new NullExp(loc);
else
e = new AddrExp(loc, this);
e->type = ts->next->pointerTo();
}
return e;
}
/******************************
* Take address of expression.
*/
Expression *Expression::addressOf(Scope *sc)
{
Expression *e;
Type *t = type;
//printf("Expression::addressOf()\n");
e = toLvalue(sc, NULL);
e = new AddrExp(loc, e);
e->type = t->pointerTo();
return e;
}
/******************************
* If this is a reference, dereference it.
*/
Expression *Expression::deref()
{
//printf("Expression::deref()\n");
// type could be null if forward referencing an 'auto' variable
if (type && type->ty == Treference)
{
Expression *e = new PtrExp(loc, this);
e->type = ((TypeReference *)type)->next;
return e;
}
return this;
}
/********************************
* Does this expression statically evaluate to a boolean TRUE or FALSE?
*/
int Expression::isBool(int result)
{
return FALSE;
}
/********************************
* Does this expression result in either a 1 or a 0?
*/
int Expression::isBit()
{
return FALSE;
}
/********************************
* Can this expression throw an exception?
* Valid only after semantic() pass.
*/
int Expression::canThrow()
{
#if DMDV2
return FALSE;
#else
return TRUE;
#endif
}
Expressions *Expression::arraySyntaxCopy(Expressions *exps)
{ Expressions *a = NULL;
if (exps)
{
a = new Expressions();
a->setDim(exps->dim);
for (size_t i = 0; i < a->dim; i++)
{ Expression *e = (Expression *)exps->data[i];
if (e)
e = e->syntaxCopy();
a->data[i] = e;
}
}
return a;
}
/******************************** IntegerExp **************************/
IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type)
: Expression(loc, TOKint64, sizeof(IntegerExp))
{
//printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : "");
if (type && !type->isscalar())
{
//printf("%s, loc = %d\n", toChars(), loc.linnum);
if (type->ty != Terror)
error("integral constant must be scalar type, not %s", type->toChars());
type = Type::terror;
}
this->type = type;
this->value = value;
}
IntegerExp::IntegerExp(dinteger_t value)
: Expression(0, TOKint64, sizeof(IntegerExp))
{
this->type = Type::tint32;
this->value = value;
}
int IntegerExp::equals(Object *o)
{ IntegerExp *ne;
if (this == o ||
(((Expression *)o)->op == TOKint64 &&
((ne = (IntegerExp *)o), type->equals(ne->type)) &&
value == ne->value))
return 1;
return 0;
}
char *IntegerExp::toChars()
{
#if 1
return Expression::toChars();
#else
static char buffer[sizeof(value) * 3 + 1];
sprintf(buffer, "%jd", value);
return buffer;
#endif
}
dinteger_t IntegerExp::toInteger()
{ Type *t;
t = type;
while (t)
{
switch (t->ty)
{
case Tbit:
case Tbool: value = (value != 0); break;
case Tint8: value = (d_int8) value; break;
case Tchar:
case Tuns8: value = (d_uns8) value; break;
case Tint16: value = (d_int16) value; break;
case Twchar:
case Tuns16: value = (d_uns16) value; break;
case Tint32: value = (d_int32) value; break;
case Tdchar:
case Tuns32: value = (d_uns32) value; break;
case Tint64: value = (d_int64) value; break;
case Tuns64: value = (d_uns64) value; break;
case Tpointer:
if (PTRSIZE == 4)
value = (d_uns32) value;
else if (PTRSIZE == 8)
value = (d_uns64) value;
else
assert(0);
break;
case Tenum:
{
TypeEnum *te = (TypeEnum *)t;
t = te->sym->memtype;
continue;
}
case Ttypedef:
{
TypeTypedef *tt = (TypeTypedef *)t;
t = tt->sym->basetype;
continue;
}
default:
/* This can happen if errors, such as
* the type is painted on like in fromConstInitializer().
*/
if (!global.errors)
{ type->print();
assert(0);
}
break;
}
break;
}
return value;
}
real_t IntegerExp::toReal()
{
Type *t;
toInteger();
t = type->toBasetype();
if (t->ty == Tuns64)
return ldouble((d_uns64)value);
else
return ldouble((d_int64)value);
}
real_t IntegerExp::toImaginary()
{
return ldouble(0);
}
complex_t IntegerExp::toComplex()
{
return toReal();
}
int IntegerExp::isBool(int result)
{
int r = toInteger() != 0;
return result ? r : !r;
}
Expression *IntegerExp::semantic(Scope *sc)
{
if (!type)
{
// Determine what the type of this number is
dinteger_t number = value;
if (number & 0x8000000000000000LL)
type = Type::tuns64;
else if (number & 0xFFFFFFFF80000000LL)
type = Type::tint64;
else
type = Type::tint32;
}
else
{ if (!type->deco)
type = type->semantic(loc, sc);
}
return this;
}
Expression *IntegerExp::toLvalue(Scope *sc, Expression *e)
{
if (!e)
e = this;
else if (!loc.filename)
loc = e->loc;
e->error("constant %s is not an lvalue", e->toChars());
return this;
}
void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
dinteger_t v = toInteger();
if (type)
{ Type *t = type;
L1:
switch (t->ty)
{
case Tenum:
{ TypeEnum *te = (TypeEnum *)t;
buf->printf("cast(%s)", te->sym->toChars());
t = te->sym->memtype;
goto L1;
}
case Ttypedef:
{ TypeTypedef *tt = (TypeTypedef *)t;
buf->printf("cast(%s)", tt->sym->toChars());
t = tt->sym->basetype;
goto L1;
}
case Twchar: // BUG: need to cast(wchar)
case Tdchar: // BUG: need to cast(dchar)
if ((uinteger_t)v > 0xFF)
{
buf->printf("'\\U%08x'", (unsigned)v);
break;
}
case Tchar:
{
unsigned o = buf->offset;
if (v == '\'')
buf->writestring("'\\''");
else if (isprint(v) && v != '\\')
buf->printf("'%c'", (int)v);
else
buf->printf("'\\x%02x'", (int)v);
if (hgs->ddoc)
escapeDdocString(buf, o);
break;
}
case Tint8:
buf->writestring("cast(byte)");
goto L2;
case Tint16:
buf->writestring("cast(short)");
goto L2;
case Tint32:
L2:
buf->printf("%d", (int)v);
break;
case Tuns8:
buf->writestring("cast(ubyte)");
goto L3;
case Tuns16:
buf->writestring("cast(ushort)");
goto L3;
case Tuns32:
L3:
buf->printf("%du", (unsigned)v);
break;
case Tint64:
buf->printf("%jdL", v);
break;
case Tuns64:
L4:
buf->printf("%juLU", v);
break;
case Tbit:
case Tbool:
buf->writestring((char *)(v ? "true" : "false"));
break;
case Tpointer:
buf->writestring("cast(");
buf->writestring(t->toChars());
buf->writeByte(')');
if (PTRSIZE == 4)
goto L3;
else if (PTRSIZE == 8)
goto L4;
else
assert(0);
default:
/* This can happen if errors, such as
* the type is painted on like in fromConstInitializer().
*/
if (!global.errors)
{
#ifdef DEBUG
t->print();
#endif
assert(0);
}
break;
}
}
else if (v & 0x8000000000000000LL)
buf->printf("0x%jx", v);
else
buf->printf("%jd", v);
}
void IntegerExp::toMangleBuffer(OutBuffer *buf)
{
if ((sinteger_t)value < 0)
buf->printf("N%jd", -value);
else
{
/* This is an awful hack to maintain backwards compatibility.
* There really always should be an 'i' before a number, but
* there wasn't in earlier implementations, so to maintain
* backwards compatibility it is only done if necessary to disambiguate.
* See bugzilla 3029
*/
if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1]))
buf->writeByte('i');
buf->printf("%jd", value);
}
}
/******************************** ErrorExp **************************/
/* Use this expression for error recovery.
* It should behave as a 'sink' to prevent further cascaded error messages.
*/
ErrorExp::ErrorExp()
: IntegerExp(0, 0, Type::terror)
{
op = TOKerror;
}
void ErrorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("__error");
}
/******************************** RealExp **************************/
RealExp::RealExp(Loc loc, real_t value, Type *type)
: Expression(loc, TOKfloat64, sizeof(RealExp))
{
//printf("RealExp::RealExp(%Lg)\n", value);
this->value = value;
this->type = type;
}
char *RealExp::toChars()
{
char buffer[sizeof(value) * 3 + 8 + 1 + 1];
#ifdef IN_GCC
value.format(buffer, sizeof(buffer));
if (type->isimaginary())
strcat(buffer, "i");
#else
sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value);
#endif
assert(strlen(buffer) < sizeof(buffer));
return mem.strdup(buffer);
}
dinteger_t RealExp::toInteger()
{
#ifdef IN_GCC
return toReal().toInt();
#else
return (sinteger_t) toReal();
#endif
}
uinteger_t RealExp::toUInteger()
{
#ifdef IN_GCC
return (uinteger_t) toReal().toInt();
#else
return (uinteger_t) toReal();
#endif
}
real_t RealExp::toReal()
{
return type->isreal() ? value : ldouble(0);
}
real_t RealExp::toImaginary()
{
return type->isreal() ? ldouble(0) : value;
}
complex_t RealExp::toComplex()
{
#ifdef __DMC__
return toReal() + toImaginary() * I;
#else
return complex_t(toReal(), toImaginary());
#endif
}
/********************************
* Test to see if two reals are the same.
* Regard NaN's as equivalent.
* Regard +0 and -0 as different.
*/
int RealEquals(real_t x1, real_t x2)
{
return (Port::isNan(x1) && Port::isNan(x2)) ||
/* In some cases, the REALPAD bytes get garbage in them,
* so be sure and ignore them.
*/
memcmp(&x1, &x2, REALSIZE - REALPAD) == 0;
}
int RealExp::equals(Object *o)
{ RealExp *ne;
if (this == o ||
(((Expression *)o)->op == TOKfloat64 &&
((ne = (RealExp *)o), type->equals(ne->type)) &&
RealEquals(value, ne->value)
)
)
return 1;
return 0;
}
Expression *RealExp::semantic(Scope *sc)
{
if (!type)
type = Type::tfloat64;
else
type = type->semantic(loc, sc);
return this;
}
int RealExp::isBool(int result)
{
#ifdef IN_GCC
return result ? (! value.isZero()) : (value.isZero());
#else
return result ? (value != 0)
: (value == 0);
#endif
}
void floatToBuffer(OutBuffer *buf, Type *type, real_t value)
{
/* In order to get an exact representation, try converting it
* to decimal then back again. If it matches, use it.
* If it doesn't, fall back to hex, which is
* always exact.
*/
char buffer[25];
sprintf(buffer, "%Lg", value);
assert(strlen(buffer) < sizeof(buffer));
#if _WIN32 && __DMC__
char *save = __locale_decpoint;
__locale_decpoint = ".";
real_t r = strtold(buffer, NULL);
__locale_decpoint = save;
#else
real_t r = strtold(buffer, NULL);
#endif
if (r == value) // if exact duplication
buf->writestring(buffer);
else
{
#ifdef __HAIKU__ // broken printf workaround
char buffer2[25];
char *ptr = (char *)&value;
for(int i = 0; i < sizeof(value); i++)
snprintf(buffer2, sizeof(char), "%x", ptr[i]);
buf->writestring(buffer2);
#else
buf->printf("%La", value); // ensure exact duplication
#endif
}
if (type)
{
Type *t = type->toBasetype();
switch (t->ty)
{
case Tfloat32:
case Timaginary32:
case Tcomplex32:
buf->writeByte('F');
break;
case Tfloat80:
case Timaginary80:
case Tcomplex80:
buf->writeByte('L');
break;
default:
break;
}
if (t->isimaginary())
buf->writeByte('i');
}
}
void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
floatToBuffer(buf, type, value);
}
void realToMangleBuffer(OutBuffer *buf, real_t value)
{
/* Rely on %A to get portable mangling.
* Must munge result to get only identifier characters.
*
* Possible values from %A => mangled result
* NAN => NAN
* -INF => NINF
* INF => INF
* -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79
* 0X1.9P+2 => 19P2
*/
if (Port::isNan(value))
buf->writestring("NAN"); // no -NAN bugs
else
{
char buffer[32];
int n = sprintf(buffer, "%LA", value);
assert(n > 0 && n < sizeof(buffer));
for (int i = 0; i < n; i++)
{ char c = buffer[i];
switch (c)
{
case '-':
buf->writeByte('N');
break;
case '+':
case 'X':
case '.':
break;
case '0':
if (i < 2)
break; // skip leading 0X
default:
buf->writeByte(c);
break;
}
}
}
}
void RealExp::toMangleBuffer(OutBuffer *buf)
{
buf->writeByte('e');
realToMangleBuffer(buf, value);
}
/******************************** ComplexExp **************************/
ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type)
: Expression(loc, TOKcomplex80, sizeof(ComplexExp))
{
this->value = value;
this->type = type;
//printf("ComplexExp::ComplexExp(%s)\n", toChars());
}
char *ComplexExp::toChars()
{
char buffer[sizeof(value) * 3 + 8 + 1];
#ifdef IN_GCC
char buf1[sizeof(value) * 3 + 8 + 1];
char buf2[sizeof(value) * 3 + 8 + 1];
creall(value).format(buf1, sizeof(buf1));
cimagl(value).format(buf2, sizeof(buf2));
sprintf(buffer, "(%s+%si)", buf1, buf2);
#else
sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value));
assert(strlen(buffer) < sizeof(buffer));
#endif
return mem.strdup(buffer);
}
dinteger_t ComplexExp::toInteger()
{
#ifdef IN_GCC
return (sinteger_t) toReal().toInt();
#else
return (sinteger_t) toReal();
#endif
}
uinteger_t ComplexExp::toUInteger()
{
#ifdef IN_GCC
return (uinteger_t) toReal().toInt();
#else
return (uinteger_t) toReal();
#endif
}
real_t ComplexExp::toReal()
{
return creall(value);
}
real_t ComplexExp::toImaginary()
{
return cimagl(value);
}
complex_t ComplexExp::toComplex()
{
return value;
}
int ComplexExp::equals(Object *o)
{ ComplexExp *ne;
if (this == o ||
(((Expression *)o)->op == TOKcomplex80 &&
((ne = (ComplexExp *)o), type->equals(ne->type)) &&
RealEquals(creall(value), creall(ne->value)) &&
RealEquals(cimagl(value), cimagl(ne->value))
)
)
return 1;
return 0;
}
Expression *ComplexExp::semantic(Scope *sc)
{
if (!type)
type = Type::tcomplex80;
else
type = type->semantic(loc, sc);
return this;
}
int ComplexExp::isBool(int result)
{
if (result)
return (bool)(value);
else
return !value;
}
void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
/* Print as:
* (re+imi)
*/
#ifdef IN_GCC
char buf1[sizeof(value) * 3 + 8 + 1];
char buf2[sizeof(value) * 3 + 8 + 1];
creall(value).format(buf1, sizeof(buf1));
cimagl(value).format(buf2, sizeof(buf2));
buf->printf("(%s+%si)", buf1, buf2);
#else
buf->writeByte('(');
floatToBuffer(buf, type, creall(value));
buf->writeByte('+');
floatToBuffer(buf, type, cimagl(value));
buf->writestring("i)");
#endif
}
void ComplexExp::toMangleBuffer(OutBuffer *buf)
{
buf->writeByte('c');
real_t r = toReal();
realToMangleBuffer(buf, r);
buf->writeByte('c'); // separate the two
r = toImaginary();
realToMangleBuffer(buf, r);
}
/******************************** IdentifierExp **************************/
IdentifierExp::IdentifierExp(Loc loc, Identifier *ident)
: Expression(loc, TOKidentifier, sizeof(IdentifierExp))
{
this->ident = ident;
}
Expression *IdentifierExp::semantic(Scope *sc)
{
Dsymbol *s;
Dsymbol *scopesym;
#if LOGSEMANTIC
printf("IdentifierExp::semantic('%s')\n", ident->toChars());
#endif
s = sc->search(loc, ident, &scopesym);
if (s)
{ Expression *e;
WithScopeSymbol *withsym;
/* See if the symbol was a member of an enclosing 'with'
*/
withsym = scopesym->isWithScopeSymbol();
if (withsym)
{
s = s->toAlias();
// Same as wthis.ident
if (s->needThis() || s->isTemplateDeclaration())
{
e = new VarExp(loc, withsym->withstate->wthis);
e = new DotIdExp(loc, e, ident);
}
else
{ Type *t = withsym->withstate->wthis->type;
if (t->ty == Tpointer)
t = ((TypePointer *)t)->next;
e = typeDotIdExp(loc, t, ident);
}
}
else
{
if (!s->parent && scopesym->isArrayScopeSymbol())
{ // Kludge to run semantic() here because
// ArrayScopeSymbol::search() doesn't have access to sc.
s->semantic(sc);
}
/* If f is really a function template,
* then replace f with the function template declaration.
*/
FuncDeclaration *f = s->isFuncDeclaration();
if (f)
{ TemplateDeclaration *tempdecl = getFuncTemplateDecl(f);
if (tempdecl)
{
if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's
tempdecl = tempdecl->overroot; // then get the start
e = new TemplateExp(loc, tempdecl);
e = e->semantic(sc);
return e;
}
}
e = new DsymbolExp(loc, s);
}
return e->semantic(sc);
}
#if DMDV2
if (ident == Id::ctfe)
{ // Create the magic __ctfe bool variable
VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL);
Expression *e = new VarExp(loc, vd);
e = e->semantic(sc);
return e;
}
#endif
const char *n = importHint(ident->toChars());
if (n)
error("'%s' is not defined, perhaps you need to import %s; ?", ident->toChars(), n);
else
{
s = sc->search_correct(ident);
if (s)
error("undefined identifier %s, did you mean %s %s?", ident->toChars(), s->kind(), s->toChars());
else
error("undefined identifier %s", ident->toChars());
}
return new ErrorExp();
}
char *IdentifierExp::toChars()
{
return ident->toChars();
}
void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (hgs->hdrgen)
buf->writestring(ident->toHChars2());
else
buf->writestring(ident->toChars());
}
#if DMDV2
int IdentifierExp::isLvalue()
{
return 1;
}
#endif
Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e)
{
#if 0
tym = tybasic(e1->ET->Tty);
if (!(tyscalar(tym) ||
tym == TYstruct ||
tym == TYarray && e->Eoper == TOKaddr))
synerr(EM_lvalue); // lvalue expected
#endif
return this;
}
/******************************** DollarExp **************************/
DollarExp::DollarExp(Loc loc)
: IdentifierExp(loc, Id::dollar)
{
}
/******************************** DsymbolExp **************************/
DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s)
: Expression(loc, TOKdsymbol, sizeof(DsymbolExp))
{
this->s = s;
}
Expression *DsymbolExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("DsymbolExp::semantic('%s')\n", s->toChars());
#endif
Lagain:
EnumMember *em;
Expression *e;
VarDeclaration *v;
FuncDeclaration *f;
FuncLiteralDeclaration *fld;
ClassDeclaration *cd;
ClassDeclaration *thiscd = NULL;
Import *imp;
Package *pkg;
Type *t;
//printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
//printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind());
if (type)
return this;
if (!s->isFuncDeclaration()) // functions are checked after overloading
checkDeprecated(sc, s);
Dsymbol *olds = s;
s = s->toAlias();
//printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis());
if (s != olds && !s->isFuncDeclaration())
checkDeprecated(sc, s);
if (sc->func)
thiscd = sc->func->parent->isClassDeclaration();
// BUG: This should happen after overload resolution for functions, not before
if (s->needThis())
{
if (hasThis(sc)
#if DMDV2
&& !s->isFuncDeclaration()
#endif
)
{
// Supply an implicit 'this', as in
// this.ident
DotVarExp *de;
de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration());
return de->semantic(sc);
}
}
em = s->isEnumMember();
if (em)
{
e = em->value->copy();
e->loc = loc;
e = e->semantic(sc);
return e;
}
v = s->isVarDeclaration();
if (v)
{
//printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars());
if (!type)
{ if ((!v->type || !v->type->deco) && v->scope)
v->semantic(v->scope);
type = v->type;
if (!v->type)
{ error("forward reference of %s %s", v->kind(), v->toChars());
return new ErrorExp();
}
}
if (v->isSameAsInitializer() && type->toBasetype()->ty != Tsarray)
{
if (v->init)
{
if (v->inuse)
{
error("circular reference to '%s'", v->toChars());
return new ErrorExp();
}
ExpInitializer *ei = v->init->isExpInitializer();
if (ei)
{
e = ei->exp->copy(); // make copy so we can change loc
if (e->op == TOKstring || !e->type)
e = e->semantic(sc);
e = e->implicitCastTo(sc, type);
e->loc = loc;
return e;
}
}
else
{
e = type->defaultInit();
e->loc = loc;
return e;
}
}
e = new VarExp(loc, v);
e->type = type;
e = e->semantic(sc);
return e->deref();
}
fld = s->isFuncLiteralDeclaration();
if (fld)
{ //printf("'%s' is a function literal\n", fld->toChars());
e = new FuncExp(loc, fld);
return e->semantic(sc);
}
f = s->isFuncDeclaration();
if (f)
{ //printf("'%s' is a function\n", f->toChars());
if (!f->originalType && f->scope) // semantic not yet run
{
unsigned oldgag = global.gag;
if (global.isSpeculativeGagging() && !f->isSpeculative())
global.gag = 0;
f->semantic(f->scope);
global.gag = oldgag;
}
#if DMDV2
// if inferring return type, sematic3 needs to be run
if (f->inferRetType && f->scope && f->type && !f->type->nextOf())
{
TemplateInstance *spec = f->isSpeculative();
int olderrs = global.errors;
f->semantic3(f->scope);
// Update the template instantiation with the number
// of errors which occured.
if (spec && global.errors != olderrs)
spec->errors = global.errors - olderrs;
}
#endif
if (f->isUnitTestDeclaration())
{
error("cannot call unittest function %s", toChars());
return new ErrorExp();
}
if (!f->type->deco)
{
error("forward reference to %s", toChars());
return new ErrorExp();
}
return new VarExp(loc, f);
}
cd = s->isClassDeclaration();
if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis())
{
// We need to add an implicit 'this' if cd is this class or a base class.
DotTypeExp *dte;
dte = new DotTypeExp(loc, new ThisExp(loc), s);
return dte->semantic(sc);
}
imp = s->isImport();
if (imp)
{
if (!imp->pkg)
{ error("forward reference of import %s", imp->toChars());
return new ErrorExp();
}
ScopeExp *ie = new ScopeExp(loc, imp->pkg);
return ie->semantic(sc);
}
pkg = s->isPackage();
if (pkg)
{
ScopeExp *ie;
ie = new ScopeExp(loc, pkg);
return ie->semantic(sc);
}
Module *mod = s->isModule();
if (mod)
{
ScopeExp *ie;
ie = new ScopeExp(loc, mod);
return ie->semantic(sc);
}
t = s->getType();
if (t)
{
TypeExp *te = new TypeExp(loc, t);
return te->semantic(sc);
}
TupleDeclaration *tup = s->isTupleDeclaration();
if (tup)
{
e = new TupleExp(loc, tup);
e = e->semantic(sc);
return e;
}
TemplateInstance *ti = s->isTemplateInstance();
if (ti)
{ if (!ti->semanticRun)
ti->semantic(sc);
s = ti->toAlias();
if (!s->isTemplateInstance())
goto Lagain;
e = new ScopeExp(loc, ti);
e = e->semantic(sc);
return e;
}
TemplateDeclaration *td = s->isTemplateDeclaration();
if (td)
{
e = new TemplateExp(loc, td);
e = e->semantic(sc);
return e;
}
error("%s '%s' is not a variable", s->kind(), s->toChars());
return new ErrorExp();
}
char *DsymbolExp::toChars()
{
return s->toChars();
}
void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring(s->toChars());
}
#if DMDV2
int DsymbolExp::isLvalue()
{
return 1;
}
#endif
Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e)
{
#if 0
tym = tybasic(e1->ET->Tty);
if (!(tyscalar(tym) ||
tym == TYstruct ||
tym == TYarray && e->Eoper == TOKaddr))
synerr(EM_lvalue); // lvalue expected
#endif
return this;
}
/******************************** ThisExp **************************/
ThisExp::ThisExp(Loc loc)
: Expression(loc, TOKthis, sizeof(ThisExp))
{
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
var = NULL;
}
Expression *ThisExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("ThisExp::semantic()\n");
#endif
if (type)
{ //assert(global.errors || var);
return this;
}
FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
/* Special case for typeof(this) and typeof(super) since both
* should work even if they are not inside a non-static member function
*/
if (!fd && sc->intypeof)
{
// Find enclosing struct or class
for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
{
if (!s)
{
error("%s is not in a class or struct scope", toChars());
goto Lerr;
}
ClassDeclaration *cd = s->isClassDeclaration();
if (cd)
{
type = cd->type;
return this;
}
StructDeclaration *sd = s->isStructDeclaration();
if (sd)
{
#if STRUCTTHISREF
type = sd->type;
#else
type = sd->type->pointerTo();
#endif
return this;
}
}
}
if (!fd)
goto Lerr;
assert(fd->vthis);
var = fd->vthis;
assert(var->parent);
type = var->type;
var->isVarDeclaration()->checkNestedReference(sc, loc);
if (!sc->intypeof)
sc->callSuper |= CSXthis;
return this;
Lerr:
error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars());
return new ErrorExp();
}
int ThisExp::isBool(int result)
{
return result ? TRUE : FALSE;
}
void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("this");
}
#if DMDV2
int ThisExp::isLvalue()
{
return 1;
}
#endif
Expression *ThisExp::toLvalue(Scope *sc, Expression *e)
{
return this;
}
/******************************** SuperExp **************************/
SuperExp::SuperExp(Loc loc)
: ThisExp(loc)
{
op = TOKsuper;
}
Expression *SuperExp::semantic(Scope *sc)
{
ClassDeclaration *cd;
Dsymbol *s;
#if LOGSEMANTIC
printf("SuperExp::semantic('%s')\n", toChars());
#endif
if (type)
return this;
FuncDeclaration *fd = hasThis(sc);
/* Special case for typeof(this) and typeof(super) since both
* should work even if they are not inside a non-static member function
*/
if (!fd && sc->intypeof)
{
// Find enclosing class
for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent)
{
if (!s)
{
error("%s is not in a class scope", toChars());
goto Lerr;
}
ClassDeclaration *cd = s->isClassDeclaration();
if (cd)
{
cd = cd->baseClass;
if (!cd)
{ error("class %s has no 'super'", s->toChars());
goto Lerr;
}
type = cd->type;
return this;
}
}
}
if (!fd)
goto Lerr;
assert(fd->vthis);
var = fd->vthis;
assert(var->parent);
s = fd->toParent();
while (s && s->isTemplateInstance())
s = s->toParent();
assert(s);
cd = s->isClassDeclaration();
//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars());
if (!cd)
goto Lerr;
if (!cd->baseClass)
{
error("no base class for %s", cd->toChars());
type = fd->vthis->type;
}
else
{
type = cd->baseClass->type;
#if DMDV2
type = type->castMod(var->type->mod);
#endif
}
var->isVarDeclaration()->checkNestedReference(sc, loc);
if (!sc->intypeof)
sc->callSuper |= CSXsuper;
return this;
Lerr:
error("'super' is only allowed in non-static class member functions");
return new ErrorExp();
}
void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("super");
}
/******************************** NullExp **************************/
NullExp::NullExp(Loc loc, Type *type)
: Expression(loc, TOKnull, sizeof(NullExp))
{
committed = 0;
this->type = type;
}
Expression *NullExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("NullExp::semantic('%s')\n", toChars());
#endif
// NULL is the same as (void *)0
if (!type)
type = Type::tvoid->pointerTo();
return this;
}
int NullExp::isBool(int result)
{
return result ? FALSE : TRUE;
}
StringExp *NullExp::toString()
{
if (implicitConvTo(Type::tstring))
{
StringExp *se = new StringExp(loc, (char*)mem.calloc(1, 1), 0);
se->type = Type::tstring;
return se;
}
return NULL;
}
void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring("null");
}
void NullExp::toMangleBuffer(OutBuffer *buf)
{
buf->writeByte('n');
}
/******************************** StringExp **************************/
StringExp::StringExp(Loc loc, char *string)
: Expression(loc, TOKstring, sizeof(StringExp))
{
this->string = string;
this->len = strlen(string);
this->sz = 1;
this->committed = 0;
this->postfix = 0;
this->ownedByCtfe = false;
}
StringExp::StringExp(Loc loc, void *string, size_t len)
: Expression(loc, TOKstring, sizeof(StringExp))
{
this->string = string;
this->len = len;
this->sz = 1;
this->committed = 0;
this->postfix = 0;
this->ownedByCtfe = false;
}
StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix)
: Expression(loc, TOKstring, sizeof(StringExp))
{
this->string = string;
this->len = len;
this->sz = 1;
this->committed = 0;
this->postfix = postfix;
this->ownedByCtfe = false;
}
#if 0
Expression *StringExp::syntaxCopy()
{
printf("StringExp::syntaxCopy() %s\n", toChars());
return copy();
}
#endif
int StringExp::equals(Object *o)
{
//printf("StringExp::equals('%s') %s\n", o->toChars(), toChars());
if (o && o->dyncast() == DYNCAST_EXPRESSION)
{ Expression *e = (Expression *)o;
if (e->op == TOKstring)
{
return compare(o) == 0;
}
}
return FALSE;
}
char *StringExp::toChars()
{
OutBuffer buf;
HdrGenState hgs;
char *p;
memset(&hgs, 0, sizeof(hgs));
toCBuffer(&buf, &hgs);
buf.writeByte(0);
p = (char *)buf.data;
buf.data = NULL;
return p;
}
Expression *StringExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("StringExp::semantic() %s\n", toChars());
#endif
if (!type)
{ OutBuffer buffer;
size_t newlen = 0;
const char *p;
size_t u;
unsigned c;
switch (postfix)
{
case 'd':
for (u = 0; u < len;)
{
p = utf_decodeChar((unsigned char *)string, len, &u, &c);
if (p)
{ error("%s", p);
return new ErrorExp();
}
else
{ buffer.write4(c);
newlen++;
}
}
buffer.write4(0);
string = buffer.extractData();
len = newlen;
sz = 4;
type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex));
committed = 1;
break;
case 'w':
for (u = 0; u < len;)
{
p = utf_decodeChar((unsigned char *)string, len, &u, &c);
if (p)
{ error("%s", p);
return new ErrorExp();
}
else
{ buffer.writeUTF16(c);
newlen++;
if (c >= 0x10000)
newlen++;
}
}
buffer.writeUTF16(0);
string = buffer.extractData();
len = newlen;
sz = 2;
type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex));
committed = 1;
break;
case 'c':
committed = 1;
default:
type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex));
break;
}
type = type->semantic(loc, sc);
}
return this;
}
/**********************************
* Return length of string.
*/
size_t StringExp::length()
{
size_t result = 0;
dchar_t c;
const char *p;
switch (sz)
{
case 1:
for (size_t u = 0; u < len;)
{
p = utf_decodeChar((unsigned char *)string, len, &u, &c);
if (p)
{ error("%s", p);
return 0;
}
else
result++;
}
break;
case 2:
for (size_t u = 0; u < len;)
{
p = utf_decodeWchar((unsigned short *)string, len, &u, &c);
if (p)
{ error("%s", p);
return 0;
}
else
result++;
}
break;
case 4:
result = len;
break;
default:
assert(0);
}
return result;
}
StringExp *StringExp::toString()
{
return this;
}
/****************************************
* Convert string to char[].
*/
StringExp *StringExp::toUTF8(Scope *sc)
{
if (sz != 1)
{ // Convert to UTF-8 string
committed = 0;
Expression *e = castTo(sc, Type::tchar->arrayOf());
e = e->optimize(WANTvalue);
assert(e->op == TOKstring);
StringExp *se = (StringExp *)e;
assert(se->sz == 1);
return se;
}
return this;
}
int StringExp::compare(Object *obj)
{
//printf("StringExp::compare()\n");
// Used to sort case statement expressions so we can do an efficient lookup
StringExp *se2 = (StringExp *)(obj);
// This is a kludge so isExpression() in template.c will return 5
// for StringExp's.
if (!se2)
return 5;
assert(se2->op == TOKstring);
int len1 = len;
int len2 = se2->len;
//printf("sz = %d, len1 = %d, len2 = %d\n", sz, len1, len2);
if (len1 == len2)
{
switch (sz)
{
case 1:
return memcmp((char *)string, (char *)se2->string, len1);
case 2:
{ unsigned u;
d_wchar *s1 = (d_wchar *)string;
d_wchar *s2 = (d_wchar *)se2->string;
for (u = 0; u < len; u++)
{
if (s1[u] != s2[u])
return s1[u] - s2[u];
}
}
case 4:
{ unsigned u;
d_dchar *s1 = (d_dchar *)string;
d_dchar *s2 = (d_dchar *)se2->string;
for (u = 0; u < len; u++)
{
if (s1[u] != s2[u])
return s1[u] - s2[u];
}
}
break;
default:
assert(0);
}
}
return len1 - len2;
}
int StringExp::isBool(int result)
{
return result ? TRUE : FALSE;
}
#if DMDV2
int StringExp::isLvalue()
{
return 1;
}
#endif
unsigned StringExp::charAt(size_t i)
{ unsigned value;
switch (sz)
{
case 1:
value = ((unsigned char *)string)[i];
break;
case 2:
value = ((unsigned short *)string)[i];
break;
case 4:
value = ((unsigned int *)string)[i];
break;
default:
assert(0);
break;
}
return value;
}
void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writeByte('"');
unsigned o = buf->offset;
for (size_t i = 0; i < len; i++)
{ unsigned c = charAt(i);
switch (c)
{
case '"':
case '\\':
if (!hgs->console)
buf->writeByte('\\');
default:
if (c <= 0xFF)
{ if (c <= 0x7F && (isprint(c) || hgs->console))
buf->writeByte(c);
else
buf->printf("\\x%02x", c);
}
else if (c <= 0xFFFF)
buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
else
buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x",
c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
break;
}
}
if (hgs->ddoc)
escapeDdocString(buf, o);
buf->writeByte('"');
if (postfix)
buf->writeByte(postfix);
}
void StringExp::toMangleBuffer(OutBuffer *buf)
{ char m;
OutBuffer tmp;
const char *p;
unsigned c;
size_t u;
unsigned char *q;
unsigned qlen;
/* Write string in UTF-8 format
*/
switch (sz)
{ case 1:
m = 'a';
q = (unsigned char *)string;
qlen = len;
break;
case 2:
m = 'w';
for (u = 0; u < len; )
{
p = utf_decodeWchar((unsigned short *)string, len, &u, &c);
if (p)
error("%s", p);
else
tmp.writeUTF8(c);
}
q = tmp.data;
qlen = tmp.offset;
break;
case 4:
m = 'd';
for (u = 0; u < len; u++)
{
c = ((unsigned *)string)[u];
if (!utf_isValidDchar(c))
error("invalid UCS-32 char \\U%08x", c);
else
tmp.writeUTF8(c);
}
q = tmp.data;
qlen = tmp.offset;
break;
default:
assert(0);
}
buf->reserve(1 + 11 + 2 * qlen);
buf->writeByte(m);
buf->printf("%d_", qlen); // nbytes <= 11
for (unsigned char *p = buf->data + buf->offset, *pend = p + 2 * qlen;
p < pend; p += 2, ++q)
{
unsigned char hi = *q >> 4 & 0xF;
p[0] = (hi < 10 ? hi + '0' : hi - 10 + 'a');
unsigned char lo = *q & 0xF;
p[1] = (lo < 10 ? lo + '0' : lo - 10 + 'a');
}
buf->offset += 2 * qlen;
}
/************************ ArrayLiteralExp ************************************/
// [ e1, e2, e3, ... ]
ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements)
: Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
{
this->elements = elements;
this->ownedByCtfe = false;
}
ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e)
: Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp))
{
elements = new Expressions;
elements->push(e);
}
Expression *ArrayLiteralExp::syntaxCopy()
{
return new ArrayLiteralExp(loc, arraySyntaxCopy(elements));
}
Expression *ArrayLiteralExp::semantic(Scope *sc)
{ Expression *e;
Type *t0 = NULL;
#if LOGSEMANTIC
printf("ArrayLiteralExp::semantic('%s')\n", toChars());
#endif
if (type)
return this;
// Run semantic() on each element
for (size_t i = 0; i < elements->dim; i++)
{ e = (Expression *)elements->data[i];
e = e->semantic(sc);
elements->data[i] = (void *)e;
}
expandTuples(elements);
for (size_t i = 0; i < elements->dim; i++)
{ e = (Expression *)elements->data[i];
if (!e->type)
error("%s has no value", e->toChars());
e = resolveProperties(sc, e);
unsigned char committed = 1;
if (e->op == TOKstring)
committed = ((StringExp *)e)->committed;
if (!t0)
{ t0 = e->type;
// Convert any static arrays to dynamic arrays
if (t0->ty == Tsarray)
{
t0 = ((TypeSArray *)t0)->next->arrayOf();
e = e->implicitCastTo(sc, t0);
}
}
else
e = e->implicitCastTo(sc, t0);
if (!committed && e->op == TOKstring)
{ StringExp *se = (StringExp *)e;
se->committed = 0;
}
elements->data[i] = (void *)e;
}
if (!t0)
t0 = Type::tvoid;
type = new TypeSArray(t0, new IntegerExp(elements->dim));
type = type->semantic(loc, sc);
/* Disallow array literals of type void being used.
*/
if (elements->dim > 0 && t0->ty == Tvoid)
error("%s of type %s has no value", toChars(), type->toChars());
return this;
}
int ArrayLiteralExp::checkSideEffect(int flag)
{ int f = 0;
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = elements->tdata()[i];
f |= e->hasSideEffect();
}
if (flag == 0 && f == 0)
Expression::checkSideEffect(0);
return f;
}
int ArrayLiteralExp::isBool(int result)
{
size_t dim = elements ? elements->dim : 0;
return result ? (dim != 0) : (dim == 0);
}
#if DMDV2
int ArrayLiteralExp::canThrow()
{
return 1; // because it can fail allocating memory
}
#endif
StringExp *ArrayLiteralExp::toString()
{
TY telem = type->nextOf()->toBasetype()->ty;
if (telem == Tchar || telem == Twchar || telem == Tdchar ||
(telem == Tvoid && (!elements || elements->dim == 0)))
{
OutBuffer buf;
if (elements)
for (int i = 0; i < elements->dim; ++i)
{
Expression *ch = elements->tdata()[i];
if (ch->op != TOKint64)
return NULL;
buf.writedchar(ch->toInteger());
}
buf.writebyte(0);
char prefix = 'c';
if (telem == Twchar) prefix = 'w';
else if (telem == Tdchar) prefix = 'd';
StringExp *se = new StringExp(loc, buf.extractData(), buf.size - 1, prefix);
se->type = type;
return se;
}
return NULL;
}
void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writeByte('[');
argsToCBuffer(buf, elements, hgs);
buf->writeByte(']');
}
void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf)
{
size_t dim = elements ? elements->dim : 0;
buf->printf("A%u", dim);
for (size_t i = 0; i < dim; i++)
{ Expression *e = elements->tdata()[i];
e->toMangleBuffer(buf);
}
}
/************************ AssocArrayLiteralExp ************************************/
// [ key0 : value0, key1 : value1, ... ]
AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc,
Expressions *keys, Expressions *values)
: Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp))
{
assert(keys->dim == values->dim);
this->keys = keys;
this->values = values;
this->ownedByCtfe = false;
}
Expression *AssocArrayLiteralExp::syntaxCopy()
{
return new AssocArrayLiteralExp(loc,
arraySyntaxCopy(keys), arraySyntaxCopy(values));
}
Expression *AssocArrayLiteralExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("AssocArrayLiteralExp::semantic('%s')\n", toChars());
#endif
if (type)
return this;
// Run semantic() on each element
arrayExpressionSemantic(keys, sc);
arrayExpressionSemantic(values, sc);
expandTuples(keys);
expandTuples(values);
if (keys->dim != values->dim)
{
error("number of keys is %u, must match number of values %u", keys->dim, values->dim);
return new ErrorExp();
}
Type *tkey = NULL;
Type *tvalue = NULL;
keys = arrayExpressionToCommonType(sc, keys, &tkey);
values = arrayExpressionToCommonType(sc, values, &tvalue);
if (tkey == Type::terror || tvalue == Type::terror)
return new ErrorExp;
type = new TypeAArray(tvalue, tkey);
type = type->semantic(loc, sc);
return this;
}
int AssocArrayLiteralExp::checkSideEffect(int flag)
{ int f = 0;
for (size_t i = 0; i < keys->dim; i++)
{ Expression *key = (Expression *)keys->data[i];
Expression *value = (Expression *)values->data[i];
f |= key->hasSideEffect();
f |= value->hasSideEffect();
}
if (flag == 0 && f == 0)
Expression::checkSideEffect(0);
return f;
}
int AssocArrayLiteralExp::isBool(int result)
{
size_t dim = keys->dim;
return result ? (dim != 0) : (dim == 0);
}
#if DMDV2
int AssocArrayLiteralExp::canThrow()
{
return 1;
}
#endif
void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writeByte('[');
for (size_t i = 0; i < keys->dim; i++)
{ Expression *key = (Expression *)keys->data[i];
Expression *value = (Expression *)values->data[i];
if (i)
buf->writeByte(',');
expToCBuffer(buf, hgs, key, PREC_assign);
buf->writeByte(':');
expToCBuffer(buf, hgs, value, PREC_assign);
}
buf->writeByte(']');
}
void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf)
{
size_t dim = keys->dim;
buf->printf("A%u", dim);
for (size_t i = 0; i < dim; i++)
{ Expression *key = (Expression *)keys->data[i];
Expression *value = (Expression *)values->data[i];
key->toMangleBuffer(buf);
value->toMangleBuffer(buf);
}
}
/************************ StructLiteralExp ************************************/
// sd( e1, e2, e3, ... )
StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype)
: Expression(loc, TOKstructliteral, sizeof(StructLiteralExp))
{
this->sd = sd;
this->elements = elements;
this->stype = stype;
#if IN_DMD
this->sym = NULL;
#endif
this->soffset = 0;
this->fillHoles = 1;
#if IN_LLVM
constType = NULL;
#endif
}
Expression *StructLiteralExp::syntaxCopy()
{
return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), stype);
}
Expression *StructLiteralExp::semantic(Scope *sc)
{ Expression *e;
#if LOGSEMANTIC
printf("StructLiteralExp::semantic('%s')\n", toChars());
#endif
if (type)
return this;
// Run semantic() on each element
for (size_t i = 0; i < elements->dim; i++)
{ e = (Expression *)elements->data[i];
if (!e)
continue;
e = e->semantic(sc);
elements->data[i] = (void *)e;
}
expandTuples(elements);
size_t offset = 0;
for (size_t i = 0; i < elements->dim; i++)
{ e = (Expression *)elements->data[i];
if (!e)
continue;
if (!e->type)
{ error("%s has no value", e->toChars());
return new ErrorExp();
}
e = resolveProperties(sc, e);
if (i >= sd->fields.dim)
{ error("more initializers than fields of %s", sd->toChars());
break;
}
Dsymbol *s = (Dsymbol *)sd->fields.data[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v);
if (v->offset < offset)
error("overlapping initialization for %s", v->toChars());
offset = v->offset + v->type->size();
Type *telem = v->type;
while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray)
{ /* Static array initialization, as in:
* T[3][5] = e;
*/
telem = telem->toBasetype()->nextOf();
}
e = e->implicitCastTo(sc, telem);
elements->data[i] = (void *)e;
}
/* Fill out remainder of elements[] with default initializers for fields[]
*/
for (size_t i = elements->dim; i < sd->fields.dim; i++)
{ Dsymbol *s = (Dsymbol *)sd->fields.data[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v);
if (v->offset < offset)
{ e = NULL;
sd->hasUnions = 1;
}
else
{
if (v->init)
{ if (v->init->isVoidInitializer())
e = NULL;
else
{ e = v->init->toExpression();
if (!e)
{ error("cannot make expression out of initializer for %s", v->toChars());
return new ErrorExp();
}
else if (v->scope)
{ // Do deferred semantic analysis
Initializer *i2 = v->init->syntaxCopy();
i2 = i2->semantic(v->scope, v->type, WANTinterpret);
e = i2->toExpression();
// remove v->scope (see bug 3426)
// but not if gagged, for we might be called again.
if (!global.gag)
v->scope = NULL;
}
}
}
else
e = v->type->defaultInitLiteral(loc);
offset = v->offset + v->type->size();
}
elements->push(e);
}
type = stype ? stype : sd->type;
return this;
}
/**************************************
* Gets expression at offset of type.
* Returns NULL if not found.
*/
Expression *StructLiteralExp::getField(Type *type, unsigned offset)
{
//printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
// /*toChars()*/"", type->toChars(), offset);
Expression *e = NULL;
int i = getFieldIndex(type, offset);
if (i != -1)
{
//printf("\ti = %d\n", i);
assert(i < elements->dim);
e = (Expression *)elements->data[i];
if (e)
{
//printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars());
/* If type is a static array, and e is an initializer for that array,
* then the field initializer should be an array literal of e.
*/
if (e->type != type && type->ty == Tsarray)
{ TypeSArray *tsa = (TypeSArray *)type;
uinteger_t length = tsa->dim->toInteger();
Expressions *z = new Expressions;
z->setDim(length);
for (int q = 0; q < length; ++q)
z->data[q] = e->copy();
e = new ArrayLiteralExp(loc, z);
e->type = type;
}
else
{
e = e->copy();
e->type = type;
}
}
}
return e;
}
/************************************
* Get index of field.
* Returns -1 if not found.
*/
int StructLiteralExp::getFieldIndex(Type *type, unsigned offset)
{
/* Find which field offset is by looking at the field offsets
*/
if (elements->dim)
{
for (size_t i = 0; i < sd->fields.dim; i++)
{
Dsymbol *s = (Dsymbol *)sd->fields.data[i];
VarDeclaration *v = s->isVarDeclaration();
assert(v);
if (offset == v->offset &&
type->size() == v->type->size())
{ Expression *e = (Expression *)elements->data[i];
if (e)
{
return i;
}
break;
}
}
}
return -1;
}
#if DMDV2
int StructLiteralExp::isLvalue()
{
return 1;
}
#endif
Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e)
{
return this;
}
int StructLiteralExp::checkSideEffect(int flag)
{ int f = 0;
for (size_t i = 0; i < elements->dim; i++)
{ Expression *e = (Expression *)elements->data[i];
if (!e)
continue;
f |= e->hasSideEffect();
}
if (flag == 0 && f == 0)
Expression::checkSideEffect(0);
return f;
}
#if DMDV2
int StructLiteralExp::canThrow()
{
return arrayExpressionCanThrow(elements);
}
#endif
void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring(sd->toChars());
buf->writeByte('(');
argsToCBuffer(buf, elements, hgs);
buf->writeByte(')');
}
void StructLiteralExp::toMangleBuffer(OutBuffer *buf)
{
size_t dim = elements ? elements->dim : 0;
buf->printf("S%u", dim);
for (size_t i = 0; i < dim; i++)
{ Expression *e = (Expression *)elements->data[i];
if (e)
e->toMangleBuffer(buf);
else
buf->writeByte('v'); // 'v' for void
}
}
/************************ TypeDotIdExp ************************************/
/* Things like:
* int.size
* foo.size
* (foo).size
* cast(foo).size
*/
Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident)
{
return new DotIdExp(loc, new TypeExp(loc, type), ident);
}
/************************************************************/
// Mainly just a placeholder
TypeExp::TypeExp(Loc loc, Type *type)
: Expression(loc, TOKtype, sizeof(TypeExp))
{
//printf("TypeExp::TypeExp(%s)\n", type->toChars());
this->type = type;
}
Expression *TypeExp::syntaxCopy()
{
//printf("TypeExp::syntaxCopy()\n");
return new TypeExp(loc, type->syntaxCopy());
}
Expression *TypeExp::semantic(Scope *sc)
{
//printf("TypeExp::semantic(%s)\n", type->toChars());
type = type->semantic(loc, sc);
return this;
}
void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
type->toCBuffer(buf, NULL, hgs);
}
/************************************************************/
// Mainly just a placeholder
ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg)
: Expression(loc, TOKimport, sizeof(ScopeExp))
{
//printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars());
//static int count; if (++count == 38) *(char*)0=0;
this->sds = pkg;
}
Expression *ScopeExp::syntaxCopy()
{
ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL));
return se;
}
Expression *ScopeExp::semantic(Scope *sc)
{
TemplateInstance *ti;
ScopeDsymbol *sds2;
#if LOGSEMANTIC
printf("+ScopeExp::semantic('%s')\n", toChars());
#endif
Lagain:
ti = sds->isTemplateInstance();
if (ti && !ti->errors)
{
unsigned olderrs = global.errors;
if (!ti->semanticRun)
ti->semantic(sc);
if (ti->inst)
{
Dsymbol *s = ti->inst->toAlias();
sds2 = s->isScopeDsymbol();
if (!sds2)
{ Expression *e;
//printf("s = %s, '%s'\n", s->kind(), s->toChars());
if (ti->withsym)
{
// Same as wthis.s
e = new VarExp(loc, ti->withsym->withstate->wthis);
e = new DotVarExp(loc, e, s->isDeclaration());
}
else
e = new DsymbolExp(loc, s);
e = e->semantic(sc);
//printf("-1ScopeExp::semantic()\n");
return e;
}
if (sds2 != sds)
{
sds = sds2;
goto Lagain;
}
//printf("sds = %s, '%s'\n", sds->kind(), sds->toChars());
}
if (olderrs != global.errors)
return new ErrorExp();
}
else
{
//printf("sds = %s, '%s'\n", sds->kind(), sds->toChars());
//printf("\tparent = '%s'\n", sds->parent->toChars());
sds->semantic(sc);
AggregateDeclaration *ad = sds->isAggregateDeclaration();
if (ad)
return (new TypeExp(loc, ad->type))->semantic(sc);
}
type = Type::tvoid;
//printf("-2ScopeExp::semantic() %s\n", toChars());
return this;
}
void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (sds->isTemplateInstance())
{
sds->toCBuffer(buf, hgs);
}
else if (hgs != NULL && hgs->ddoc)
{ // fixes bug 6491
Module *module = sds->isModule();
if (module)
buf->writestring(module->md->toChars());
else
buf->writestring(sds->toChars());
}
else
{
buf->writestring(sds->kind());
buf->writestring(" ");
buf->writestring(sds->toChars());
}
}
/********************** TemplateExp **************************************/
// Mainly just a placeholder
TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td)
: Expression(loc, TOKtemplate, sizeof(TemplateExp))
{
//printf("TemplateExp(): %s\n", td->toChars());
this->td = td;
}
void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring(td->toChars());
}
int TemplateExp::rvalue()
{
error("template %s has no value", toChars());
return 0;
}
/********************** NewExp **************************************/
/* thisexp.new(newargs) newtype(arguments) */
NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs,
Type *newtype, Expressions *arguments)
: Expression(loc, TOKnew, sizeof(NewExp))
{
this->thisexp = thisexp;
this->newargs = newargs;
this->newtype = newtype;
this->arguments = arguments;
member = NULL;
allocator = NULL;
onstack = 0;
}
Expression *NewExp::syntaxCopy()
{
return new NewExp(loc,
thisexp ? thisexp->syntaxCopy() : NULL,
arraySyntaxCopy(newargs),
newtype->syntaxCopy(), arraySyntaxCopy(arguments));
}
Expression *NewExp::semantic(Scope *sc)
{
Type *tb;
ClassDeclaration *cdthis = NULL;
#if LOGSEMANTIC
printf("NewExp::semantic() %s\n", toChars());
if (thisexp)
printf("\tthisexp = %s\n", thisexp->toChars());
printf("\tnewtype: %s\n", newtype->toChars());
#endif
if (type) // if semantic() already run
return this;
Lagain:
if (thisexp)
{ thisexp = thisexp->semantic(sc);
cdthis = thisexp->type->isClassHandle();
if (cdthis)
{
sc = sc->push(cdthis);
type = newtype->semantic(loc, sc);
sc = sc->pop();
}
else
{
error("'this' for nested class must be a class type, not %s", thisexp->type->toChars());
goto Lerr;
}
}
else
type = newtype->semantic(loc, sc);
newtype = type; // in case type gets cast to something else
tb = type->toBasetype();
//printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco);
arrayExpressionSemantic(newargs, sc);
preFunctionParameters(loc, sc, newargs);
arrayExpressionSemantic(arguments, sc);
preFunctionParameters(loc, sc, arguments);
if (thisexp && tb->ty != Tclass)
{ error("e.new is only for allocating nested classes, not %s", tb->toChars());
goto Lerr;
}
if (tb->ty == Tclass)
{ TypeFunction *tf;
TypeClass *tc = (TypeClass *)(tb);
ClassDeclaration *cd = tc->sym->isClassDeclaration();
if (cd->isInterfaceDeclaration())
{ error("cannot create instance of interface %s", cd->toChars());
goto Lerr;
}
else if (cd->isAbstract())
{ error("cannot create instance of abstract class %s", cd->toChars());
for (size_t i = 0; i < cd->vtbl.dim; i++)
{ FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration();
if (fd && fd->isAbstract())
error("function %s is abstract", fd->toChars());
}
goto Lerr;
}
checkDeprecated(sc, cd);
if (cd->isNested())
{ /* We need a 'this' pointer for the nested class.
* Ensure we have the right one.
*/
Dsymbol *s = cd->toParent2();
ClassDeclaration *cdn = s->isClassDeclaration();
FuncDeclaration *fdn = s->isFuncDeclaration();
//printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null");
if (cdn)
{
if (!cdthis)
{
// Supply an implicit 'this' and try again
thisexp = new ThisExp(loc);
for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
{ if (!sp)
{
error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
goto Lerr;
}
ClassDeclaration *cdp = sp->isClassDeclaration();
if (!cdp)
continue;
if (cdp == cdn || cdn->isBaseOf(cdp, NULL))
break;
// Add a '.outer' and try again
thisexp = new DotIdExp(loc, thisexp, Id::outer);
}
if (!global.errors)
goto Lagain;
}
if (cdthis)
{
//printf("cdthis = %s\n", cdthis->toChars());
if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL))
{ error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars());
goto Lerr;
}
}
#if 0
else
{
for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration())
{
if (!sf)
{
error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars());
goto Lerr;
}
printf("sf = %s\n", sf->toChars());
AggregateDeclaration *ad = sf->isThis();
if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL)))
break;
}
}
#endif
}
else if (thisexp)
{ error("e.new is only for allocating nested classes");
goto Lerr;
}
else if (fdn)
{
// make sure the parent context fdn of cd is reachable from sc
for (Dsymbol *sp = sc->parent; 1; sp = sp->parent)
{
if (fdn == sp)
break;
FuncDeclaration *fsp = sp ? sp->isFuncDeclaration() : NULL;
if (!sp || (fsp && fsp->isStatic()))
{
error("outer function context of %s is needed to 'new' nested class %s", fdn->toPrettyChars(), cd->toPrettyChars());
goto Lerr;
}
}
}
}
else if (thisexp)
{ error("e.new is only for allocating nested classes");
goto Lerr;
}
FuncDeclaration *f = cd->ctor;
if (f)
{
assert(f);
f = f->overloadResolve(loc, NULL, arguments, sc->module);
checkDeprecated(sc, f);
member = f->isCtorDeclaration();
assert(member);
cd->accessCheck(loc, sc, member);
tf = (TypeFunction *)f->type;
type = tf->next;
if (!arguments)
arguments = new Expressions();
unsigned olderrors = global.errors;
functionParameters(loc, sc, tf, arguments);
if (olderrors != global.errors)
return new ErrorExp();
}
else
{
if (arguments && arguments->dim)
{ error("no constructor for %s", cd->toChars());
goto Lerr;
}
}
if (cd->aggNew)
{
// Prepend the size argument to newargs[]
Expression *e = new IntegerExp(loc, cd->size(loc), Type::tsize_t);
if (!newargs)
newargs = new Expressions();
newargs->shift(e);
f = cd->aggNew->overloadResolve(loc, NULL, newargs, sc->module);
allocator = f->isNewDeclaration();
assert(allocator);
tf = (TypeFunction *)f->type;
unsigned olderrors = global.errors;
functionParameters(loc, sc, tf, newargs);
if (olderrors != global.errors)
return new ErrorExp();
}
else
{
if (newargs && newargs->dim)
{ error("no allocator for %s", cd->toChars());
goto Lerr;
}
}
}
else if (tb->ty == Tstruct)
{
TypeStruct *ts = (TypeStruct *)tb;
StructDeclaration *sd = ts->sym;
FuncDeclaration *f = sd->aggNew;
TypeFunction *tf;
if (arguments && arguments->dim)
error("no constructor for %s", type->toChars());
if (f)
{
Expression *e;
// Prepend the uint size argument to newargs[]
e = new IntegerExp(loc, sd->size(loc), Type::tuns32);
if (!newargs)
newargs = new Expressions();
newargs->shift(e);
f = f->overloadResolve(loc, NULL, newargs, sc->module);
allocator = f->isNewDeclaration();
assert(allocator);
tf = (TypeFunction *)f->type;
unsigned olderrors = global.errors;
functionParameters(loc, sc, tf, newargs);
if (olderrors != global.errors)
return new ErrorExp();
e = new VarExp(loc, f);
e = new CallExp(loc, e, newargs);
e = e->semantic(sc);
e->type = type->pointerTo();
return e;
}
type = type->pointerTo();
}
else if (tb->ty == Tarray && (arguments && arguments->dim))
{
for (size_t i = 0; i < arguments->dim; i++)
{
if (tb->ty != Tarray)
{ error("too many arguments for array");
goto Lerr;
}
Expression *arg = arguments->tdata()[i];
arg = resolveProperties(sc, arg);
arg = arg->implicitCastTo(sc, Type::tsize_t);
if (arg->op == TOKint64 && (long long)arg->toInteger() < 0)
{ error("negative array index %s", arg->toChars());
goto Lerr;
}
arguments->tdata()[i] = arg;
tb = ((TypeDArray *)tb)->next->toBasetype();
}
}
else if (tb->isscalar())
{
if (arguments && arguments->dim)
{ error("no constructor for %s", type->toChars());
goto Lerr;
}
type = type->pointerTo();
}
else
{
error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars());
goto Lerr;
}
//printf("NewExp: '%s'\n", toChars());
//printf("NewExp:type '%s'\n", type->toChars());
return this;
Lerr:
return new ErrorExp();
}
int NewExp::checkSideEffect(int flag)
{
return 1;
}
#if DMDV2
int NewExp::canThrow(bool mustNotThrow)
{
if (arrayExpressionCanThrow(newargs, mustNotThrow) ||
arrayExpressionCanThrow(arguments, mustNotThrow))
return 1;
if (member)
{
// See if constructor call can throw
Type *t = member->type->toBasetype();
if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow)
{
if (mustNotThrow)
error("constructor %s is not nothrow", member->toChars());
return 1;
}
}
// regard storage allocation failures as not recoverable
return 0;
}
#endif
void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (thisexp)
{ expToCBuffer(buf, hgs, thisexp, PREC_primary);
buf->writeByte('.');
}
buf->writestring("new ");
if (newargs && newargs->dim)
{
buf->writeByte('(');
argsToCBuffer(buf, newargs, hgs);
buf->writeByte(')');
}
newtype->toCBuffer(buf, NULL, hgs);
if (arguments && arguments->dim)
{
buf->writeByte('(');
argsToCBuffer(buf, arguments, hgs);
buf->writeByte(')');
}
}
/********************** NewAnonClassExp **************************************/
NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp,
Expressions *newargs, ClassDeclaration *cd, Expressions *arguments)
: Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp))
{
this->thisexp = thisexp;
this->newargs = newargs;
this->cd = cd;
this->arguments = arguments;
}
Expression *NewAnonClassExp::syntaxCopy()
{
return new NewAnonClassExp(loc,
thisexp ? thisexp->syntaxCopy() : NULL,
arraySyntaxCopy(newargs),
(ClassDeclaration *)cd->syntaxCopy(NULL),
arraySyntaxCopy(arguments));
}
Expression *NewAnonClassExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("NewAnonClassExp::semantic() %s\n", toChars());
//printf("thisexp = %p\n", thisexp);
//printf("type: %s\n", type->toChars());
#endif
Expression *d = new DeclarationExp(loc, cd);
d = d->semantic(sc);
Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments);
Expression *c = new CommaExp(loc, d, n);
return c->semantic(sc);
}
int NewAnonClassExp::checkSideEffect(int flag)
{
return 1;
}
#if DMDV2
int NewAnonClassExp::canThrow()
{
return 1;
}
#endif
void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (thisexp)
{ expToCBuffer(buf, hgs, thisexp, PREC_primary);
buf->writeByte('.');
}
buf->writestring("new");
if (newargs && newargs->dim)
{
buf->writeByte('(');
argsToCBuffer(buf, newargs, hgs);
buf->writeByte(')');
}
buf->writestring(" class ");
if (arguments && arguments->dim)
{
buf->writeByte('(');
argsToCBuffer(buf, arguments, hgs);
buf->writeByte(')');
}
//buf->writestring(" { }");
if (cd)
{
cd->toCBuffer(buf, hgs);
}
}
/********************** SymbolExp **************************************/
#if DMDV2
SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads)
: Expression(loc, op, size)
{
assert(var);
this->var = var;
this->hasOverloads = hasOverloads;
}
#endif
/********************** SymOffExp **************************************/
SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset)
: Expression(loc, TOKsymoff, sizeof(SymOffExp))
{
assert(var);
this->var = var;
this->offset = offset;
m = NULL;
VarDeclaration *v = var->isVarDeclaration();
if (v && v->needThis())
error("need 'this' for address of %s", v->toChars());
}
Expression *SymOffExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("SymOffExp::semantic('%s')\n", toChars());
#endif
//var->semantic(sc);
m = sc->module;
if (!type)
type = var->type->pointerTo();
VarDeclaration *v = var->isVarDeclaration();
if (v)
v->checkNestedReference(sc, loc);
return this;
}
int SymOffExp::isBool(int result)
{
return result ? TRUE : FALSE;
}
void SymOffExp::checkEscape()
{
VarDeclaration *v = var->isVarDeclaration();
if (v)
{
if (!v->isDataseg() && !(v->storage_class & (STCref | STCout)))
{ /* BUG: This should be allowed:
* void foo()
* { int a;
* int* bar() { return &a; }
* }
*/
error("escaping reference to local %s", v->toChars());
}
}
}
void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
if (offset)
buf->printf("(& %s+%u)", var->toChars(), offset);
else
buf->printf("& %s", var->toChars());
}
/******************************** VarExp **************************/
VarExp::VarExp(Loc loc, Declaration *var)
: Expression(loc, TOKvar, sizeof(VarExp))
{
//printf("VarExp(this = %p, '%s')\n", this, var->toChars());
this->var = var;
this->type = var->type;
}
int VarExp::equals(Object *o)
{ VarExp *ne;
if (this == o ||
(((Expression *)o)->op == TOKvar &&
((ne = (VarExp *)o), type->equals(ne->type)) &&
var == ne->var))
return 1;
return 0;
}
Expression *VarExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("VarExp::semantic(%s)\n", toChars());
#endif
if (!type)
{ type = var->type;
#if 0
if (var->storage_class & STClazy)
{
TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd);
type = new TypeDelegate(tf);
type = type->semantic(loc, sc);
}
#endif
}
if (type && !type->deco)
type = type->semantic(loc, sc);
/* Fix for 1161 doesn't work because it causes protection
* problems when instantiating imported templates passing private
* variables as alias template parameters.
*/
//accessCheck(loc, sc, NULL, var);
VarDeclaration *v = var->isVarDeclaration();
if (v)
{
if (v->isSameAsInitializer() && type->toBasetype()->ty != Tsarray && v->init)
{
ExpInitializer *ei = v->init->isExpInitializer();
if (ei && ei->exp->type)
{
//ei->exp->implicitCastTo(sc, type)->print();
return ei->exp->implicitCastTo(sc, type);
}
}
v->checkNestedReference(sc, loc);
#if DMDV2
if (sc->func && sc->func->isPure() && !sc->intypeof)
{
if (v->isDataseg() && !v->isImmutable())
error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars());
}
#endif
}
#if 0
else if ((fd = var->isFuncLiteralDeclaration()) != NULL)
{ Expression *e;
e = new FuncExp(loc, fd);
e->type = type;
return e;
}
#endif
return this;
}
char *VarExp::toChars()
{
return var->toChars();
}
void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
{
buf->writestring(var->toChars());
}
void VarExp::checkEscape()
{
VarDeclaration *v = var->isVarDeclaration();
if (v)
{ Type *tb = v->type->toBasetype();
// if reference type
if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass)
{
if (v->isScope() && !v->noscope)
error("escaping reference to auto local %s", v->toChars());
else if (v->storage_class & STCvariadic)
error("escaping reference to variadic parameter %s", v->toChars());
}
}
}
void VarExp::checkEscapeRef()
{
VarDeclaration *v = var->isVarDeclaration();
if (v)
{
if (!v->isDataseg() && !(v->storage_class & (STCref | STCout)))
error("escaping reference to local variable %s", v->toChars());
}
}
#if DMDV2
int VarExp::isLvalue()
{
if (var->storage_class & STClazy)
return 0;
return 1;
}
#endif
Expression *VarExp::toLvalue(Scope *sc, Expression *e)
{
#if 0
tym = tybasic(e1->ET->Tty);
if (!(tyscalar(tym) ||
tym == TYstruct ||
tym == TYarray && e->Eoper == TOKaddr))
synerr(EM_lvalue); // lvalue expected
#endif
if (var->storage_class & STClazy)
error("lazy variables cannot be lvalues");
return this;
}
Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e)
{
//printf("VarExp::modifiableLvalue('%s')\n", var->toChars());
if (sc->incontract && var->isParameter())
error("cannot modify parameter '%s' in contract", var->toChars());
if (type && type->toBasetype()->ty == Tsarray)
error("cannot change reference to static array '%s'", var->toChars());
VarDeclaration *v = var->isVarDeclaration();
if (v && v->canassign == 0 &&
(var->isConst() || (global.params.Dversion > 1 && var->isFinal())))
error("cannot modify final variable '%s'", var->toChars());
if (var->isCtorinit())
{ // It's only modifiable if inside the right constructor
Dsymbol *s = sc->func;
while (1)
{
FuncDeclaration *fd = NULL;
if (s)
fd = s->isFuncDeclaration();
if (fd &&
((fd->isCtorDeclaration() && var->storage_class & STCfield) ||
(fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) &&
fd->toParent() == var->toParent()
)
{
VarDeclaration *v = var->isVarDeclaration();
assert(v);
v->ctorinit = 1;
//printf("setting ctorinit\n");
}
else
{
if (s)
{ s = s->toParent2();
continue;
}
else
{
const char *p = var->isStatic() ? "static " : "";
error("can only initialize %sconst %s inside %sconstructor",
p, var->toChars(), p);
}
}
break;
}
}
// See if this expression is a modifiable lvalue (i.e. not const)
return toLvalue(sc, e);
}
/******************************** OverExp **************************/
#if DMDV2
OverExp::OverExp(OverloadSet *s)
: Expression(loc, TOKoverloadset, sizeof(OverExp))
{
//printf("OverExp(this = %p, '%s')\n", this, var->toChars());
vars = s;
type = Type::tvoid;
}
int OverExp::isLvalue()
{
return 1;
}
Expression *OverExp::toLvalue(Scope *sc, Expression *e)
{
return this;
}
#endif
/******************************** TupleExp **************************/
TupleExp::TupleExp(Loc loc, Expressions *exps)
: Expression(loc, TOKtuple, sizeof(TupleExp))
{
//printf("TupleExp(this = %p)\n", this);
this->exps = exps;
this->type = NULL;
}
TupleExp::TupleExp(Loc loc, TupleDeclaration *tup)
: Expression(loc, TOKtuple, sizeof(TupleExp))
{
exps = new Expressions();
type = NULL;
exps->reserve(tup->objects->dim);
for (size_t i = 0; i < tup->objects->dim; i++)
{ Object *o = tup->objects->tdata()[i];
if (o->dyncast() == DYNCAST_EXPRESSION)
{
Expression *e = (Expression *)o;
e = e->syntaxCopy();
exps->push(e);
}
else if (o->dyncast() == DYNCAST_DSYMBOL)
{
Dsymbol *s = (Dsymbol *)o;
Expression *e = new DsymbolExp(loc, s);
exps->push(e);
}
else if (o->dyncast() == DYNCAST_TYPE)
{
Type *t = (Type *)o;
Expression *e = new TypeExp(loc, t);
exps->push(e);
}
else
{
error("%s is not an expression", o->toChars());
}
}
}
int TupleExp::equals(Object *o)
{
if (this == o)