ldc/dmd2/traits.c

440 lines
10 KiB
C

// Compiler implementation of the D programming language
// Copyright (c) 1999-2007 by Digital Mars
// All Rights Reserved
// written by Walter Bright
// http://www.digitalmars.com
// License for redistribution is by either the Artistic License
// in artistic.txt, or the GNU General Public License in gnu.txt.
// See the included readme.txt for details.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <assert.h>
#include <complex.h>
#include <math.h>
#if IN_GCC
// Issues with using -include total.h (defines integer_t) and then complex.h fails...
#undef integer_t
#endif
#ifdef __APPLE__
#define integer_t dmd_integer_t
#endif
#if IN_GCC || IN_LLVM
#include "mem.h"
#elif _WIN32
#include "..\root\mem.h"
#elif linux
#include "../root/mem.h"
#endif
//#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"
#define LOGSEMANTIC 0
/************************************************
* Delegate to be passed to overloadApply() that looks
* for virtual functions.
*/
struct Pvirtuals
{
Expression *e1;
Expressions *exps;
};
static int fpvirtuals(void *param, FuncDeclaration *f)
{ Pvirtuals *p = (Pvirtuals *)param;
if (f->isVirtual())
{ Expression *e;
if (p->e1->op == TOKdotvar)
{ DotVarExp *dve = (DotVarExp *)p->e1;
e = new DotVarExp(0, dve->e1, f);
}
else
e = new DsymbolExp(0, f);
p->exps->push(e);
}
return 0;
}
/************************ TraitsExp ************************************/
Expression *TraitsExp::semantic(Scope *sc)
{
#if LOGSEMANTIC
printf("TraitsExp::semantic() %s\n", toChars());
#endif
if (ident != Id::compiles && ident != Id::isSame)
TemplateInstance::semanticTiargs(loc, sc, args, 1);
size_t dim = args ? args->dim : 0;
Object *o;
FuncDeclaration *f;
#define ISTYPE(cond) \
for (size_t i = 0; i < dim; i++) \
{ Type *t = getType((Object *)args->data[i]); \
if (!t) \
goto Lfalse; \
if (!(cond)) \
goto Lfalse; \
} \
if (!dim) \
goto Lfalse; \
goto Ltrue;
#define ISDSYMBOL(cond) \
for (size_t i = 0; i < dim; i++) \
{ Dsymbol *s = getDsymbol((Object *)args->data[i]); \
if (!s) \
goto Lfalse; \
if (!(cond)) \
goto Lfalse; \
} \
if (!dim) \
goto Lfalse; \
goto Ltrue;
if (ident == Id::isArithmetic)
{
ISTYPE(t->isintegral() || t->isfloating())
}
else if (ident == Id::isFloating)
{
ISTYPE(t->isfloating())
}
else if (ident == Id::isIntegral)
{
ISTYPE(t->isintegral())
}
else if (ident == Id::isScalar)
{
ISTYPE(t->isscalar())
}
else if (ident == Id::isUnsigned)
{
ISTYPE(t->isunsigned())
}
else if (ident == Id::isAssociativeArray)
{
ISTYPE(t->toBasetype()->ty == Taarray)
}
else if (ident == Id::isStaticArray)
{
ISTYPE(t->toBasetype()->ty == Tsarray)
}
else if (ident == Id::isAbstractClass)
{
ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract())
}
else if (ident == Id::isFinalClass)
{
ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal)
}
else if (ident == Id::isAbstractFunction)
{
ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract())
}
else if (ident == Id::isVirtualFunction)
{
ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual())
}
else if (ident == Id::isFinalFunction)
{
ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal())
}
else if (ident == Id::hasMember ||
ident == Id::getMember ||
ident == Id::getVirtualFunctions)
{
if (dim != 2)
goto Ldimerror;
Object *o = (Object *)args->data[0];
Expression *e = isExpression((Object *)args->data[1]);
if (!e)
{ error("expression expected as second argument of __traits %s", ident->toChars());
goto Lfalse;
}
e = e->optimize(WANTvalue | WANTinterpret);
if (e->op != TOKstring)
{ error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars());
goto Lfalse;
}
StringExp *se = (StringExp *)e;
se = se->toUTF8(sc);
if (se->sz != 1)
{ error("string must be chars");
goto Lfalse;
}
Identifier *id = Lexer::idPool((char *)se->string);
Type *t = isType(o);
e = isExpression(o);
Dsymbol *s = isDsymbol(o);
if (t)
e = new TypeDotIdExp(loc, t, id);
else if (e)
e = new DotIdExp(loc, e, id);
else if (s)
{ e = new DsymbolExp(loc, s);
e = new DotIdExp(loc, e, id);
}
else
{ error("invalid first argument");
goto Lfalse;
}
if (ident == Id::hasMember)
{ /* Take any errors as meaning it wasn't found
*/
unsigned errors = global.errors;
global.gag++;
e = e->semantic(sc);
global.gag--;
if (errors != global.errors)
{ if (global.gag == 0)
global.errors = errors;
goto Lfalse;
}
else
goto Ltrue;
}
else if (ident == Id::getMember)
{
e = e->semantic(sc);
return e;
}
else if (ident == Id::getVirtualFunctions)
{
unsigned errors = global.errors;
Expression *ex = e;
e = e->semantic(sc);
if (errors < global.errors)
error("%s cannot be resolved", ex->toChars());
/* Create tuple of virtual function overloads of e
*/
//e->dump(0);
Expressions *exps = new Expressions();
FuncDeclaration *f;
if (e->op == TOKvar)
{ VarExp *ve = (VarExp *)e;
f = ve->var->isFuncDeclaration();
}
else if (e->op == TOKdotvar)
{ DotVarExp *dve = (DotVarExp *)e;
f = dve->var->isFuncDeclaration();
}
else
f = NULL;
Pvirtuals p;
p.exps = exps;
p.e1 = e;
overloadApply(f, fpvirtuals, &p);
TupleExp *tup = new TupleExp(loc, exps);
return tup->semantic(sc);
}
else
assert(0);
}
else if (ident == Id::classInstanceSize)
{
if (dim != 1)
goto Ldimerror;
Object *o = (Object *)args->data[0];
Dsymbol *s = getDsymbol(o);
ClassDeclaration *cd;
if (!s || (cd = s->isClassDeclaration()) == NULL)
{
error("first argument is not a class");
goto Lfalse;
}
return new IntegerExp(loc, cd->structsize, Type::tsize_t);
}
else if (ident == Id::allMembers || ident == Id::derivedMembers)
{
if (dim != 1)
goto Ldimerror;
Object *o = (Object *)args->data[0];
Dsymbol *s = getDsymbol(o);
ScopeDsymbol *sd;
if (!s)
{
error("argument has no members");
goto Lfalse;
}
if ((sd = s->isScopeDsymbol()) == NULL)
{
error("%s %s has no members", s->kind(), s->toChars());
goto Lfalse;
}
Expressions *exps = new Expressions;
while (1)
{ size_t dim = ScopeDsymbol::dim(sd->members);
for (size_t i = 0; i < dim; i++)
{
Dsymbol *sm = ScopeDsymbol::getNth(sd->members, i);
//printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars());
if (sm->ident)
{
//printf("\t%s\n", sm->ident->toChars());
char *str = sm->ident->toChars();
/* Skip if already present in exps[]
*/
for (size_t j = 0; j < exps->dim; j++)
{ StringExp *se2 = (StringExp *)exps->data[j];
if (strcmp(str, (char *)se2->string) == 0)
goto Lnext;
}
StringExp *se = new StringExp(loc, str);
exps->push(se);
}
Lnext:
;
}
ClassDeclaration *cd = sd->isClassDeclaration();
if (cd && cd->baseClass && ident == Id::allMembers)
sd = cd->baseClass; // do again with base class
else
break;
}
Expression *e = new ArrayLiteralExp(loc, exps);
e = e->semantic(sc);
return e;
}
else if (ident == Id::compiles)
{
/* Determine if all the objects - types, expressions, or symbols -
* compile without error
*/
if (!dim)
goto Lfalse;
for (size_t i = 0; i < dim; i++)
{ Object *o = (Object *)args->data[i];
Type *t;
Expression *e;
Dsymbol *s;
unsigned errors = global.errors;
global.gag++;
t = isType(o);
if (t)
{ t->resolve(loc, sc, &e, &t, &s);
if (t)
t->semantic(loc, sc);
else if (e)
e->semantic(sc);
}
else
{ e = isExpression(o);
if (e)
e->semantic(sc);
}
global.gag--;
if (errors != global.errors)
{ if (global.gag == 0)
global.errors = errors;
goto Lfalse;
}
}
goto Ltrue;
}
else if (ident == Id::isSame)
{ /* Determine if two symbols are the same
*/
if (dim != 2)
goto Ldimerror;
TemplateInstance::semanticTiargs(loc, sc, args, 0);
Object *o1 = (Object *)args->data[0];
Object *o2 = (Object *)args->data[1];
Dsymbol *s1 = getDsymbol(o1);
Dsymbol *s2 = getDsymbol(o2);
#if 0
printf("o1: %p\n", o1);
printf("o2: %p\n", o2);
if (!s1)
{ Expression *ea = isExpression(o1);
if (ea)
printf("%s\n", ea->toChars());
Type *ta = isType(o1);
if (ta)
printf("%s\n", ta->toChars());
goto Lfalse;
}
else
printf("%s %s\n", s1->kind(), s1->toChars());
#endif
if (!s1 && !s2)
{ Expression *ea1 = isExpression(o1);
Expression *ea2 = isExpression(o2);
if (ea1 && ea2 && ea1->equals(ea2))
goto Ltrue;
}
if (!s1 || !s2)
goto Lfalse;
s1 = s1->toAlias();
s2 = s2->toAlias();
if (s1 == s2)
goto Ltrue;
else
goto Lfalse;
}
else
{ error("unrecognized trait %s", ident->toChars());
goto Lfalse;
}
return NULL;
Lnottype:
error("%s is not a type", o->toChars());
goto Lfalse;
Ldimerror:
error("wrong number of arguments %d", dim);
goto Lfalse;
Lfalse:
return new IntegerExp(loc, 0, Type::tbool);
Ltrue:
return new IntegerExp(loc, 1, Type::tbool);
}