mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-09 04:15:58 +03:00
440 lines
10 KiB
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);
|
|
}
|
|
|
|
|