diff --git a/.hgignore b/.hgignore index 849cb42f..d79da1a2 100644 --- a/.hgignore +++ b/.hgignore @@ -10,11 +10,14 @@ syntax: glob *.so *.swp *.rej +*~ Makefile CMakeFiles CMakeCache.txt cmake_install.cmake .DS_Store +CMakeLists.txt.user +.directory syntax: regexp ^obj/ diff --git a/dmd2/access.c b/dmd2/access.c index 9251bbaf..ef16f226 100644 --- a/dmd2/access.c +++ b/dmd2/access.c @@ -1,425 +1,425 @@ - -// Copyright (c) 1999-2006 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 -#include -#include - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "aggregate.h" -#include "init.h" -#include "attrib.h" -#include "scope.h" -#include "id.h" -#include "mtype.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "module.h" - -#define LOG 0 - -/* Code to do access checks - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s); - -/**************************************** - * Return PROT access for Dsymbol smember in this declaration. - */ - -enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) -{ - return PROTpublic; -} - -enum PROT StructDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - return access_ret; -} - -enum PROT ClassDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else - { - enum PROT access; - int i; - - if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - - for (i = 0; i < baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)baseclasses.data[i]; - - access = b->base->getAccess(smember); - switch (access) - { - case PROTnone: - break; - - case PROTprivate: - access = PROTnone; // private members of base class not accessible - break; - - case PROTpackage: - case PROTprotected: - case PROTpublic: - case PROTexport: - // If access is to be tightened - if (b->protection < access) - access = b->protection; - - // Pick path with loosest access - if (access > access_ret) - access_ret = access; - break; - - default: - assert(0); - } - } - } -#if LOG - printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", - toChars(), smember->toChars(), access_ret); -#endif - return access_ret; -} - -/******************************************************** - * Helper function for ClassDeclaration::accessCheck() - * Returns: - * 0 no access - * 1 access - */ - -static int accessCheckX( - Dsymbol *smember, - Dsymbol *sfunc, - AggregateDeclaration *dthis, - AggregateDeclaration *cdscope) -{ - assert(dthis); - -#if 0 - printf("accessCheckX for %s.%s in function %s() in scope %s\n", - dthis->toChars(), smember->toChars(), - sfunc ? sfunc->toChars() : "NULL", - cdscope ? cdscope->toChars() : "NULL"); -#endif - if (dthis->hasPrivateAccess(sfunc) || - dthis->isFriendOf(cdscope)) - { - if (smember->toParent() == dthis) - return 1; - else - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (int i = 0; i < cdthis->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; - enum PROT access; - - access = b->base->getAccess(smember); - if (access >= PROTprotected || - accessCheckX(smember, sfunc, b->base, cdscope) - ) - return 1; - - } - } - } - } - else - { - if (smember->toParent() != dthis) - { - ClassDeclaration *cdthis = dthis->isClassDeclaration(); - if (cdthis) - { - for (int i = 0; i < cdthis->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cdthis->baseclasses.data[i]; - - if (accessCheckX(smember, sfunc, b->base, cdscope)) - return 1; - } - } - } - } - return 0; -} - -/******************************* - * Do access check for member of this class, this class being the - * type of the 'this' pointer used to access smember. - */ - -void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) -{ - int result; - - FuncDeclaration *f = sc->func; - AggregateDeclaration *cdscope = sc->getStructClassScope(); - enum PROT access; - -#if LOG - printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", - toChars(), smember->toChars(), - f ? f->toChars() : NULL, - cdscope ? cdscope->toChars() : NULL); -#endif - - Dsymbol *smemberparent = smember->toParent(); - if (!smemberparent || !smemberparent->isAggregateDeclaration()) - { -#if LOG - printf("not an aggregate member\n"); -#endif - return; // then it is accessible - } - - // BUG: should enable this check - //assert(smember->parent->isBaseOf(this, NULL)); - - if (smemberparent == this) - { enum PROT access = smember->prot(); - - result = access >= PROTpublic || - hasPrivateAccess(f) || - isFriendOf(cdscope) || - (access == PROTpackage && hasPackageAccess(sc, this)); -#if LOG - printf("result1 = %d\n", result); -#endif - } - else if ((access = this->getAccess(smember)) >= PROTpublic) - { - result = 1; -#if LOG - printf("result2 = %d\n", result); -#endif - } - else if (access == PROTpackage && hasPackageAccess(sc, this)) - { - result = 1; -#if LOG - printf("result3 = %d\n", result); -#endif - } - else - { - result = accessCheckX(smember, f, this, cdscope); -#if LOG - printf("result4 = %d\n", result); -#endif - } - if (!result) - { - error(loc, "member %s is not accessible", smember->toChars()); -halt(); - } -} - -/**************************************** - * Determine if this is the same or friend of cd. - */ - -int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) -{ -#if LOG - printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null"); -#endif - if (this == cd) - return 1; - - // Friends if both are in the same module - //if (toParent() == cd->toParent()) - if (cd && getModule() == cd->getModule()) - { -#if LOG - printf("\tin same module\n"); -#endif - return 1; - } - -#if LOG - printf("\tnot friend\n"); -#endif - return 0; -} - -/**************************************** - * Determine if scope sc has package level access to s. - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s) -{ -#if LOG - printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); -#endif - - for (; s; s = s->parent) - { - if (s->isPackage() && !s->isModule()) - break; - } -#if LOG - if (s) - printf("\tthis is in package '%s'\n", s->toChars()); -#endif - - if (s && s == sc->module->parent) - { -#if LOG - printf("\ts is in same package as sc\n"); -#endif - return 1; - } - - -#if LOG - printf("\tno package access\n"); -#endif - return 0; -} - -/********************************** - * Determine if smember has access to private members of this declaration. - */ - -int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) -{ - if (smember) - { AggregateDeclaration *cd = NULL; - Dsymbol *smemberparent = smember->toParent(); - if (smemberparent) - cd = smemberparent->isAggregateDeclaration(); - -#if LOG - printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", - toChars(), smember->toChars()); -#endif - - if (this == cd) // smember is a member of this class - { -#if LOG - printf("\tyes 1\n"); -#endif - return 1; // so we get private access - } - - // If both are members of the same module, grant access - while (1) - { Dsymbol *sp = smember->toParent(); - if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) - smember = sp; - else - break; - } - if (!cd && toParent() == smember->toParent()) - { -#if LOG - printf("\tyes 2\n"); -#endif - return 1; - } - if (!cd && getModule() == smember->getModule()) - { -#if LOG - printf("\tyes 3\n"); -#endif - return 1; - } - } -#if LOG - printf("\tno\n"); -#endif - return 0; -} - -/**************************************** - * Check access to d for expression e.d - */ - -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) -{ -#if LOG - if (e) - { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); - printf("\te->type = %s\n", e->type->toChars()); - } - else - { - //printf("accessCheck(%s)\n", d->toChars()); - } -#endif - if (!e) - { - if (d->getModule() != sc->module) - if (d->prot() == PROTprivate || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - - error(loc, "%s %s.%s is not accessible from %s", - d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); - } - else if (e->type->ty == Tclass) - { // Do access check - ClassDeclaration *cd; - - cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); -#if 1 - if (e->op == TOKsuper) - { ClassDeclaration *cd2; - - cd2 = sc->func->toParent()->isClassDeclaration(); - if (cd2) - cd = cd2; - } -#endif - cd->accessCheck(loc, sc, d); - } - else if (e->type->ty == Tstruct) - { // Do access check - StructDeclaration *cd; - - cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); - cd->accessCheck(loc, sc, d); - } -} + +// Copyright (c) 1999-2006 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 +#include +#include + +#include "root.h" +#include "rmem.h" + +#include "enum.h" +#include "aggregate.h" +#include "init.h" +#include "attrib.h" +#include "scope.h" +#include "id.h" +#include "mtype.h" +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "module.h" + +#define LOG 0 + +/* Code to do access checks + */ + +int hasPackageAccess(Scope *sc, Dsymbol *s); + +/**************************************** + * Return PROT access for Dsymbol smember in this declaration. + */ + +enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) +{ + return PROTpublic; +} + +enum PROT StructDeclaration::getAccess(Dsymbol *smember) +{ + enum PROT access_ret = PROTnone; + +#if LOG + printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember->toChars()); +#endif + if (smember->toParent() == this) + { + access_ret = smember->prot(); + } + else if (smember->isDeclaration()->isStatic()) + { + access_ret = smember->prot(); + } + return access_ret; +} + +enum PROT ClassDeclaration::getAccess(Dsymbol *smember) +{ + enum PROT access_ret = PROTnone; + +#if LOG + printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", + toChars(), smember->toChars()); +#endif + if (smember->toParent() == this) + { + access_ret = smember->prot(); + } + else + { + enum PROT access; + int i; + + if (smember->isDeclaration()->isStatic()) + { + access_ret = smember->prot(); + } + + for (i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; + + access = b->base->getAccess(smember); + switch (access) + { + case PROTnone: + break; + + case PROTprivate: + access = PROTnone; // private members of base class not accessible + break; + + case PROTpackage: + case PROTprotected: + case PROTpublic: + case PROTexport: + // If access is to be tightened + if (b->protection < access) + access = b->protection; + + // Pick path with loosest access + if (access > access_ret) + access_ret = access; + break; + + default: + assert(0); + } + } + } +#if LOG + printf("-ClassDeclaration::getAccess(this = '%s', smember = '%s') = %d\n", + toChars(), smember->toChars(), access_ret); +#endif + return access_ret; +} + +/******************************************************** + * Helper function for ClassDeclaration::accessCheck() + * Returns: + * 0 no access + * 1 access + */ + +static int accessCheckX( + Dsymbol *smember, + Dsymbol *sfunc, + AggregateDeclaration *dthis, + AggregateDeclaration *cdscope) +{ + assert(dthis); + +#if 0 + printf("accessCheckX for %s.%s in function %s() in scope %s\n", + dthis->toChars(), smember->toChars(), + sfunc ? sfunc->toChars() : "NULL", + cdscope ? cdscope->toChars() : "NULL"); +#endif + if (dthis->hasPrivateAccess(sfunc) || + dthis->isFriendOf(cdscope)) + { + if (smember->toParent() == dthis) + return 1; + else + { + ClassDeclaration *cdthis = dthis->isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis->baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)cdthis->baseclasses->data[i]; + enum PROT access; + + access = b->base->getAccess(smember); + if (access >= PROTprotected || + accessCheckX(smember, sfunc, b->base, cdscope) + ) + return 1; + + } + } + } + } + else + { + if (smember->toParent() != dthis) + { + ClassDeclaration *cdthis = dthis->isClassDeclaration(); + if (cdthis) + { + for (int i = 0; i < cdthis->baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)cdthis->baseclasses->data[i]; + + if (accessCheckX(smember, sfunc, b->base, cdscope)) + return 1; + } + } + } + } + return 0; +} + +/******************************* + * Do access check for member of this class, this class being the + * type of the 'this' pointer used to access smember. + */ + +void AggregateDeclaration::accessCheck(Loc loc, Scope *sc, Dsymbol *smember) +{ + int result; + + FuncDeclaration *f = sc->func; + AggregateDeclaration *cdscope = sc->getStructClassScope(); + enum PROT access; + +#if LOG + printf("AggregateDeclaration::accessCheck() for %s.%s in function %s() in scope %s\n", + toChars(), smember->toChars(), + f ? f->toChars() : NULL, + cdscope ? cdscope->toChars() : NULL); +#endif + + Dsymbol *smemberparent = smember->toParent(); + if (!smemberparent || !smemberparent->isAggregateDeclaration()) + { +#if LOG + printf("not an aggregate member\n"); +#endif + return; // then it is accessible + } + + // BUG: should enable this check + //assert(smember->parent->isBaseOf(this, NULL)); + + if (smemberparent == this) + { enum PROT access = smember->prot(); + + result = access >= PROTpublic || + hasPrivateAccess(f) || + isFriendOf(cdscope) || + (access == PROTpackage && hasPackageAccess(sc, this)); +#if LOG + printf("result1 = %d\n", result); +#endif + } + else if ((access = this->getAccess(smember)) >= PROTpublic) + { + result = 1; +#if LOG + printf("result2 = %d\n", result); +#endif + } + else if (access == PROTpackage && hasPackageAccess(sc, this)) + { + result = 1; +#if LOG + printf("result3 = %d\n", result); +#endif + } + else + { + result = accessCheckX(smember, f, this, cdscope); +#if LOG + printf("result4 = %d\n", result); +#endif + } + if (!result) + { + error(loc, "member %s is not accessible", smember->toChars()); +halt(); + } +} + +/**************************************** + * Determine if this is the same or friend of cd. + */ + +int AggregateDeclaration::isFriendOf(AggregateDeclaration *cd) +{ +#if LOG + printf("AggregateDeclaration::isFriendOf(this = '%s', cd = '%s')\n", toChars(), cd ? cd->toChars() : "null"); +#endif + if (this == cd) + return 1; + + // Friends if both are in the same module + //if (toParent() == cd->toParent()) + if (cd && getModule() == cd->getModule()) + { +#if LOG + printf("\tin same module\n"); +#endif + return 1; + } + +#if LOG + printf("\tnot friend\n"); +#endif + return 0; +} + +/**************************************** + * Determine if scope sc has package level access to s. + */ + +int hasPackageAccess(Scope *sc, Dsymbol *s) +{ +#if LOG + printf("hasPackageAccess(s = '%s', sc = '%p')\n", s->toChars(), sc); +#endif + + for (; s; s = s->parent) + { + if (s->isPackage() && !s->isModule()) + break; + } +#if LOG + if (s) + printf("\tthis is in package '%s'\n", s->toChars()); +#endif + + if (s && s == sc->module->parent) + { +#if LOG + printf("\ts is in same package as sc\n"); +#endif + return 1; + } + + +#if LOG + printf("\tno package access\n"); +#endif + return 0; +} + +/********************************** + * Determine if smember has access to private members of this declaration. + */ + +int AggregateDeclaration::hasPrivateAccess(Dsymbol *smember) +{ + if (smember) + { AggregateDeclaration *cd = NULL; + Dsymbol *smemberparent = smember->toParent(); + if (smemberparent) + cd = smemberparent->isAggregateDeclaration(); + +#if LOG + printf("AggregateDeclaration::hasPrivateAccess(class %s, member %s)\n", + toChars(), smember->toChars()); +#endif + + if (this == cd) // smember is a member of this class + { +#if LOG + printf("\tyes 1\n"); +#endif + return 1; // so we get private access + } + + // If both are members of the same module, grant access + while (1) + { Dsymbol *sp = smember->toParent(); + if (sp->isFuncDeclaration() && smember->isFuncDeclaration()) + smember = sp; + else + break; + } + if (!cd && toParent() == smember->toParent()) + { +#if LOG + printf("\tyes 2\n"); +#endif + return 1; + } + if (!cd && getModule() == smember->getModule()) + { +#if LOG + printf("\tyes 3\n"); +#endif + return 1; + } + } +#if LOG + printf("\tno\n"); +#endif + return 0; +} + +/**************************************** + * Check access to d for expression e.d + */ + +void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d) +{ +#if LOG + if (e) + { printf("accessCheck(%s . %s)\n", e->toChars(), d->toChars()); + printf("\te->type = %s\n", e->type->toChars()); + } + else + { + //printf("accessCheck(%s)\n", d->toChars()); + } +#endif + if (!e) + { + if (d->getModule() != sc->module) + if (d->prot() == PROTprivate || + d->prot() == PROTpackage && !hasPackageAccess(sc, d)) + + error(loc, "%s %s.%s is not accessible from %s", + d->kind(), d->getModule()->toChars(), d->toChars(), sc->module->toChars()); + } + else if (e->type->ty == Tclass) + { // Do access check + ClassDeclaration *cd; + + cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); +#if 1 + if (e->op == TOKsuper) + { ClassDeclaration *cd2; + + cd2 = sc->func->toParent()->isClassDeclaration(); + if (cd2) + cd = cd2; + } +#endif + cd->accessCheck(loc, sc, d); + } + else if (e->type->ty == Tstruct) + { // Do access check + StructDeclaration *cd; + + cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); + cd->accessCheck(loc, sc, d); + } +} diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h index 7bdb9e18..97806872 100644 --- a/dmd2/aggregate.h +++ b/dmd2/aggregate.h @@ -1,325 +1,350 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -#if IN_LLVM -#include -#include -#include -#endif - -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct ClassInfoDeclaration; -struct VarDeclaration; -struct dt_t; - -#if IN_LLVM -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} -#endif - -struct AggregateDeclaration : ScopeDsymbol -{ - Type *type; - unsigned storage_class; - enum PROT protection; - Type *handle; // 'this' type - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - Array fields; // VarDeclaration fields - unsigned sizeok; // set when structsize contains valid data - // 0: no size - // 1: size is correct - // 2: cannot determine size; fwd referenced - int isdeprecated; // !=0 if deprecated - Scope *scope; // !=NULL means context to use - - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this aggregate is nested - - // Special member functions - InvariantDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - -#if DMDV2 - //CtorDeclaration *ctor; - Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration - CtorDeclaration *defaultCtor; // default constructor - Dsymbol *aliasthis; // forward unresolved lookups to aliasthis -#endif - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor - -#ifdef IN_GCC - Array methods; // flat list of all methods for debug information -#endif - - AggregateDeclaration(Loc loc, Identifier *id); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); - Type *getType(); - void addField(Scope *sc, VarDeclaration *v); - int isDeprecated(); // is aggregate deprecated? - FuncDeclaration *buildDtor(Scope *sc); - int isNested(); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - // For access checking - virtual PROT getAccess(Dsymbol *smember); // determine access to smember - int isFriendOf(AggregateDeclaration *cd); - int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? - void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - - enum PROT prot(); - -#if IN_DMD - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - Symbol *toInitializer(); -#endif - - AggregateDeclaration *isAggregateDeclaration() { return this; } - -#if IN_LLVM - // Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; -#endif -}; - -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - -struct StructDeclaration : AggregateDeclaration -{ - int zeroInit; // !=0 if initialize with 0 fill -#if DMDV2 - int hasIdentityAssign; // !=0 if has identity opAssign - FuncDeclaration *cpctor; // generated copy-constructor, if any - - FuncDeclarations postblits; // Array of postblit functions - FuncDeclaration *postblit; // aggregate postblit -#endif - - StructDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); - const char *kind(); - int needOpAssign(); - FuncDeclaration *buildOpAssign(Scope *sc); - FuncDeclaration *buildPostBlit(Scope *sc); - FuncDeclaration *buildCpCtor(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDt(dt_t **pdt); - void toDebug(); // to symbolic debug info -#endif - - StructDeclaration *isStructDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct UnionDeclaration : StructDeclaration -{ - UnionDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } -}; - -// warning: two classes with the same base class share the same -// BaseClass instance. -struct BaseClass -{ - Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface - - ClassDeclaration *base; - int offset; // 'this' pointer offset - Array vtbl; // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - - int baseInterfaces_dim; - BaseClass *baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type, enum PROT protection); - - int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -#if DMDV2 -#define CLASSINFO_SIZE (0x3C+16+4) // value of ClassInfo.size -#else -#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size -#endif - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - - ClassDeclaration *baseClass; // NULL only if this is Object - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Array vtbl; // Array of FuncDeclaration's making up the vtbl[] - Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - int interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - - ClassInfoDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - int com; // !=0 if this is a COM class (meaning - // it derives from IUnknown) - int isauto; // !=0 if this is an auto class - int isabstract; // !=0 if abstract class - - int inuse; // to prevent recursive attempts - - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - virtual int isBaseOf(ClassDeclaration *cd, int *poffset); - - Dsymbol *search(Loc, Identifier *ident, int flags); -#if DMDV2 - int isFuncHidden(FuncDeclaration *fd); -#endif - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); - int isCOMclass(); - virtual int isCOMinterface(); -#if DMDV2 - virtual int isCPPinterface(); -#endif - int isAbstract(); - virtual int vtblOffset(); - const char *kind(); - char *mangle(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void addLocalClass(ClassDeclarations *); - -#if IN_DMD - // Back end - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - unsigned baseVtblOffset(BaseClass *bc); - Symbol *toSymbol(); - Symbol *toVtblSymbol(); - void toDt(dt_t **pdt); - void toDt2(dt_t **pdt, ClassDeclaration *cd); - - Symbol *vtblsym; -#endif - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct InterfaceDeclaration : ClassDeclaration -{ -#if DMDV2 - int cpp; // !=0 if this is a C++ interface -#endif - InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int isBaseOf(ClassDeclaration *cd, int *poffset); - int isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); - int vtblOffset(); -#if DMDV2 - int isCPPinterface(); -#endif - virtual int isCOMinterface(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); -#endif - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -#endif /* DMD_AGGREGATE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +#ifndef DMD_AGGREGATE_H +#define DMD_AGGREGATE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" + +#include "dsymbol.h" + +#if IN_LLVM +#include +#include +#include +#endif + +struct Identifier; +struct Type; +struct TypeFunction; +struct Expression; +struct FuncDeclaration; +struct CtorDeclaration; +struct DtorDeclaration; +struct InvariantDeclaration; +struct NewDeclaration; +struct DeleteDeclaration; +struct InterfaceDeclaration; +struct TypeInfoClassDeclaration; +struct VarDeclaration; +struct dt_t; + +#if IN_LLVM +namespace llvm +{ + class Type; + class Value; + class Constant; + class ConstantStruct; + class GlobalVariable; +} +#endif + +struct AggregateDeclaration : ScopeDsymbol +{ + Type *type; + StorageClass storage_class; + enum PROT protection; + Type *handle; // 'this' type + unsigned structsize; // size of struct + unsigned alignsize; // size of struct for alignment purposes + unsigned structalign; // struct member alignment in effect + int hasUnions; // set if aggregate has overlapping fields + Array fields; // VarDeclaration fields + unsigned sizeok; // set when structsize contains valid data + // 0: no size + // 1: size is correct + // 2: cannot determine size; fwd referenced + int isdeprecated; // !=0 if deprecated + Scope *scope; // !=NULL means context to use + +#if DMDV2 + int isnested; // !=0 if is nested + VarDeclaration *vthis; // 'this' parameter if this aggregate is nested +#endif + // Special member functions + InvariantDeclaration *inv; // invariant + NewDeclaration *aggNew; // allocator + DeleteDeclaration *aggDelete; // deallocator + +#if DMDV2 + //CtorDeclaration *ctor; + Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration + CtorDeclaration *defaultCtor; // default constructor + Dsymbol *aliasthis; // forward unresolved lookups to aliasthis +#endif + + FuncDeclarations dtors; // Array of destructors + FuncDeclaration *dtor; // aggregate destructor + +#ifdef IN_GCC + Array methods; // flat list of all methods for debug information +#endif + + AggregateDeclaration(Loc loc, Identifier *id); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + unsigned size(Loc loc); + static void alignmember(unsigned salign, unsigned size, unsigned *poffset); + Type *getType(); + void addField(Scope *sc, VarDeclaration *v); + int isDeprecated(); // is aggregate deprecated? + FuncDeclaration *buildDtor(Scope *sc); + int isNested(); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + // For access checking + virtual PROT getAccess(Dsymbol *smember); // determine access to smember + int isFriendOf(AggregateDeclaration *cd); + int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? + void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); + + enum PROT prot(); + +#if IN_DMD + // Back end + Symbol *stag; // tag symbol for debug data + Symbol *sinit; + Symbol *toInitializer(); +#endif + + AggregateDeclaration *isAggregateDeclaration() { return this; } + +#if IN_LLVM + // Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; +#endif +}; + +struct AnonymousAggregateDeclaration : AggregateDeclaration +{ + AnonymousAggregateDeclaration() + : AggregateDeclaration(0, NULL) + { + } + + AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } +}; + +struct StructDeclaration : AggregateDeclaration +{ + int zeroInit; // !=0 if initialize with 0 fill +#if DMDV2 + int hasIdentityAssign; // !=0 if has identity opAssign + FuncDeclaration *cpctor; // generated copy-constructor, if any + FuncDeclaration *eq; // bool opEquals(ref const T), if any + + FuncDeclarations postblits; // Array of postblit functions + FuncDeclaration *postblit; // aggregate postblit +#endif + + StructDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + Dsymbol *search(Loc, Identifier *ident, int flags); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *mangle(); + const char *kind(); +#if DMDV1 + Expression *cloneMembers(); +#endif +#if DMDV2 + int needOpAssign(); + int needOpEquals(); + FuncDeclaration *buildOpAssign(Scope *sc); + FuncDeclaration *buildOpEquals(Scope *sc); + FuncDeclaration *buildPostBlit(Scope *sc); + FuncDeclaration *buildCpCtor(Scope *sc); +#endif + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDt(dt_t **pdt); + void toDebug(); // to symbolic debug info +#endif + + StructDeclaration *isStructDeclaration() { return this; } + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +struct UnionDeclaration : StructDeclaration +{ + UnionDeclaration(Loc loc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *s); + const char *kind(); + + UnionDeclaration *isUnionDeclaration() { return this; } +}; + +// warning: two classes with the same base class share the same +// BaseClass instance. +struct BaseClass +{ + Type *type; // (before semantic processing) + enum PROT protection; // protection for the base interface + + ClassDeclaration *base; + int offset; // 'this' pointer offset + Array vtbl; // for interfaces: Array of FuncDeclaration's + // making up the vtbl[] + + int baseInterfaces_dim; + BaseClass *baseInterfaces; // if BaseClass is an interface, these + // are a copy of the InterfaceDeclaration::interfaces + + BaseClass(); + BaseClass(Type *type, enum PROT protection); + + int fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance); + void copyBaseInterfaces(BaseClasses *); +}; + +#if DMDV2 +#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size +#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size +#else +#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size +#endif + +struct ClassDeclaration : AggregateDeclaration +{ + static ClassDeclaration *object; + static ClassDeclaration *classinfo; + + ClassDeclaration *baseClass; // NULL only if this is Object +#if DMDV1 + CtorDeclaration *ctor; + CtorDeclaration *defaultCtor; // default constructor +#endif + FuncDeclaration *staticCtor; + FuncDeclaration *staticDtor; + Array vtbl; // Array of FuncDeclaration's making up the vtbl[] + Array vtblFinal; // More FuncDeclaration's that aren't in vtbl[] + + BaseClasses *baseclasses; // Array of BaseClass's; first is super, + // rest are Interface's + + int interfaces_dim; + BaseClass **interfaces; // interfaces[interfaces_dim] for this class + // (does not include baseClass) + + BaseClasses *vtblInterfaces; // array of base interfaces that have + // their own vtbl[] + + TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration + int com; // !=0 if this is a COM class (meaning + // it derives from IUnknown) + int isscope; // !=0 if this is an auto class + int isabstract; // !=0 if abstract class +#if DMDV1 + int isnested; // !=0 if is nested + VarDeclaration *vthis; // 'this' parameter if this class is nested +#endif + int inuse; // to prevent recursive attempts + + ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isBaseOf2(ClassDeclaration *cd); + + #define OFFSET_RUNTIME 0x76543210 + virtual int isBaseOf(ClassDeclaration *cd, int *poffset); + + virtual int isBaseInfoComplete(); + Dsymbol *search(Loc, Identifier *ident, int flags); +#if DMDV2 + int isFuncHidden(FuncDeclaration *fd); +#endif + FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); + void interfaceSemantic(Scope *sc); +#if DMDV1 + int isNested(); +#endif + int isCOMclass(); + virtual int isCOMinterface(); +#if DMDV2 + virtual int isCPPinterface(); +#endif + int isAbstract(); + virtual int vtblOffset(); + const char *kind(); + char *mangle(); + void toDocBuffer(OutBuffer *buf); + + PROT getAccess(Dsymbol *smember); // determine access to smember + + void addLocalClass(ClassDeclarations *); + +#if IN_DMD + // Back end + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + unsigned baseVtblOffset(BaseClass *bc); + Symbol *toSymbol(); + Symbol *toVtblSymbol(); + void toDt(dt_t **pdt); + void toDt2(dt_t **pdt, ClassDeclaration *cd); + + Symbol *vtblsym; +#endif + + ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } + +#if IN_LLVM + virtual void codegen(Ir*); +#endif +}; + +struct InterfaceDeclaration : ClassDeclaration +{ +#if DMDV2 + int cpp; // !=0 if this is a C++ interface +#endif + InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + int isBaseOf(ClassDeclaration *cd, int *poffset); + int isBaseOf(BaseClass *bc, int *poffset); + const char *kind(); + int isBaseInfoComplete(); + int vtblOffset(); +#if DMDV2 + int isCPPinterface(); +#endif + virtual int isCOMinterface(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); +#endif + + InterfaceDeclaration *isInterfaceDeclaration() { return this; } + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +#endif /* DMD_AGGREGATE_H */ diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c index d79d270c..b379d26e 100644 --- a/dmd2/aliasthis.c +++ b/dmd2/aliasthis.c @@ -1,72 +1,72 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2009-2009 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 -#include - -#include "mars.h" -#include "identifier.h" -#include "aliasthis.h" -#include "scope.h" -#include "aggregate.h" -#include "dsymbol.h" - -#if DMDV2 - - -AliasThis::AliasThis(Loc loc, Identifier *ident) - : Dsymbol(NULL) // it's anonymous (no identifier) -{ - this->loc = loc; - this->ident = ident; -} - -Dsymbol *AliasThis::syntaxCopy(Dsymbol *s) -{ - assert(!s); - /* Since there is no semantic information stored here, - * we don't need to copy it. - */ - return this; -} - -void AliasThis::semantic(Scope *sc) -{ - Dsymbol *parent = sc->parent; - if (parent) - parent = parent->pastMixin(); - AggregateDeclaration *ad = NULL; - if (parent) - ad = parent->isAggregateDeclaration(); - if (ad) - { - if (ad->aliasthis) - error("there can be only one alias this"); - assert(ad->members); - Dsymbol *s = ad->search(loc, ident, 0); - ad->aliasthis = s; - } - else - error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere"); -} - -const char *AliasThis::kind() -{ - return "alias this"; -} - -void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - buf->writestring(ident->toChars()); - buf->writestring(" this;\n"); -} - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 2009-2009 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 +#include + +#include "mars.h" +#include "identifier.h" +#include "aliasthis.h" +#include "scope.h" +#include "aggregate.h" +#include "dsymbol.h" + +#if DMDV2 + + +AliasThis::AliasThis(Loc loc, Identifier *ident) + : Dsymbol(NULL) // it's anonymous (no identifier) +{ + this->loc = loc; + this->ident = ident; +} + +Dsymbol *AliasThis::syntaxCopy(Dsymbol *s) +{ + assert(!s); + /* Since there is no semantic information stored here, + * we don't need to copy it. + */ + return this; +} + +void AliasThis::semantic(Scope *sc) +{ + Dsymbol *parent = sc->parent; + if (parent) + parent = parent->pastMixin(); + AggregateDeclaration *ad = NULL; + if (parent) + ad = parent->isAggregateDeclaration(); + if (ad) + { + if (ad->aliasthis) + error("there can be only one alias this"); + assert(ad->members); + Dsymbol *s = ad->search(loc, ident, 0); + ad->aliasthis = s; + } + else + error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere"); +} + +const char *AliasThis::kind() +{ + return "alias this"; +} + +void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); + buf->writestring(ident->toChars()); + buf->writestring(" this;\n"); +} + +#endif diff --git a/dmd2/aliasthis.h b/dmd2/aliasthis.h index dad489a1..c804cdb5 100644 --- a/dmd2/aliasthis.h +++ b/dmd2/aliasthis.h @@ -1,41 +1,41 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2009-2009 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. - -#ifndef DMD_ALIASTHIS_H -#define DMD_ALIASTHIS_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "mars.h" -#include "dsymbol.h" - -/**************************************************************/ - -#if DMDV2 - -struct AliasThis : Dsymbol -{ - // alias Identifier this; - Identifier *ident; - - AliasThis(Loc loc, Identifier *ident); - - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - AliasThis *isAliasThis() { return this; } -}; - -#endif - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 2009-2009 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. + +#ifndef DMD_ALIASTHIS_H +#define DMD_ALIASTHIS_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "mars.h" +#include "dsymbol.h" + +/**************************************************************/ + +#if DMDV2 + +struct AliasThis : Dsymbol +{ + // alias Identifier this; + Identifier *ident; + + AliasThis(Loc loc, Identifier *ident); + + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + AliasThis *isAliasThis() { return this; } +}; + +#endif + +#endif diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c index 6cd6163c..e794070b 100644 --- a/dmd2/arrayop.c +++ b/dmd2/arrayop.c @@ -1,535 +1,619 @@ - -// Copyright (c) 1999-2009 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 -#include -#include - -#include "rmem.h" - -#include "stringtable.h" - -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "declaration.h" -#include "scope.h" -#include "id.h" -#include "module.h" -#include "init.h" - -#if IN_DMD -extern int binary(const char *p , const char **tab, int high); - -/************************************** - * Hash table of array op functions already generated or known about. - */ - -StringTable arrayfuncs; -#endif - -/*********************************** - * Construct the array operation expression. - */ - -Expression *BinExp::arrayOp(Scope *sc) -{ - Expressions *arguments = new Expressions(); - - /* The expression to generate an array operation for is mangled - * into a name to use as the array operation function name. - * Mangle in the operands and operators in RPN order, and type. - */ - OutBuffer buf; - buf.writestring("_array"); - buildArrayIdent(&buf, arguments); - buf.writeByte('_'); - - /* Append deco of array element type - */ -#if DMDV2 - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); -#else - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); -#endif - - size_t namelen = buf.offset; - buf.writeByte(0); - char *name = (char *)buf.extractData(); - - /* Look up name in hash table - */ -#if IN_LLVM - StringValue *sv = sc->module->arrayfuncs.update(name, namelen); -#else - StringValue *sv = arrayfuncs.update(name, namelen); -#endif - FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; - if (!fd) - { -#if IN_DMD - /* Some of the array op functions are written as library functions, - * presumably to optimize them with special CPU vector instructions. - * List those library functions here, in alpha order. - */ - static const char *libArrayopFuncs[] = - { - "_arrayExpSliceAddass_a", - "_arrayExpSliceAddass_d", // T[]+=T - "_arrayExpSliceAddass_f", // T[]+=T - "_arrayExpSliceAddass_g", - "_arrayExpSliceAddass_h", - "_arrayExpSliceAddass_i", - "_arrayExpSliceAddass_k", - "_arrayExpSliceAddass_s", - "_arrayExpSliceAddass_t", - "_arrayExpSliceAddass_u", - "_arrayExpSliceAddass_w", - - "_arrayExpSliceDivass_d", // T[]/=T - "_arrayExpSliceDivass_f", // T[]/=T - - "_arrayExpSliceMinSliceAssign_a", - "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_g", - "_arrayExpSliceMinSliceAssign_h", - "_arrayExpSliceMinSliceAssign_i", - "_arrayExpSliceMinSliceAssign_k", - "_arrayExpSliceMinSliceAssign_s", - "_arrayExpSliceMinSliceAssign_t", - "_arrayExpSliceMinSliceAssign_u", - "_arrayExpSliceMinSliceAssign_w", - - "_arrayExpSliceMinass_a", - "_arrayExpSliceMinass_d", // T[]-=T - "_arrayExpSliceMinass_f", // T[]-=T - "_arrayExpSliceMinass_g", - "_arrayExpSliceMinass_h", - "_arrayExpSliceMinass_i", - "_arrayExpSliceMinass_k", - "_arrayExpSliceMinass_s", - "_arrayExpSliceMinass_t", - "_arrayExpSliceMinass_u", - "_arrayExpSliceMinass_w", - - "_arrayExpSliceMulass_d", // T[]*=T - "_arrayExpSliceMulass_f", // T[]*=T - "_arrayExpSliceMulass_i", - "_arrayExpSliceMulass_k", - "_arrayExpSliceMulass_s", - "_arrayExpSliceMulass_t", - "_arrayExpSliceMulass_u", - "_arrayExpSliceMulass_w", - - "_arraySliceExpAddSliceAssign_a", - "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_g", - "_arraySliceExpAddSliceAssign_h", - "_arraySliceExpAddSliceAssign_i", - "_arraySliceExpAddSliceAssign_k", - "_arraySliceExpAddSliceAssign_s", - "_arraySliceExpAddSliceAssign_t", - "_arraySliceExpAddSliceAssign_u", - "_arraySliceExpAddSliceAssign_w", - - "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T - "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T - - "_arraySliceExpMinSliceAssign_a", - "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_g", - "_arraySliceExpMinSliceAssign_h", - "_arraySliceExpMinSliceAssign_i", - "_arraySliceExpMinSliceAssign_k", - "_arraySliceExpMinSliceAssign_s", - "_arraySliceExpMinSliceAssign_t", - "_arraySliceExpMinSliceAssign_u", - "_arraySliceExpMinSliceAssign_w", - - "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T - "_arraySliceExpMulSliceAddass_f", - "_arraySliceExpMulSliceAddass_r", - - "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_i", - "_arraySliceExpMulSliceAssign_k", - "_arraySliceExpMulSliceAssign_s", - "_arraySliceExpMulSliceAssign_t", - "_arraySliceExpMulSliceAssign_u", - "_arraySliceExpMulSliceAssign_w", - - "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T - "_arraySliceExpMulSliceMinass_f", - "_arraySliceExpMulSliceMinass_r", - - "_arraySliceSliceAddSliceAssign_a", - "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_g", - "_arraySliceSliceAddSliceAssign_h", - "_arraySliceSliceAddSliceAssign_i", - "_arraySliceSliceAddSliceAssign_k", - "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_s", - "_arraySliceSliceAddSliceAssign_t", - "_arraySliceSliceAddSliceAssign_u", - "_arraySliceSliceAddSliceAssign_w", - - "_arraySliceSliceAddass_a", - "_arraySliceSliceAddass_d", // T[]+=T[] - "_arraySliceSliceAddass_f", // T[]+=T[] - "_arraySliceSliceAddass_g", - "_arraySliceSliceAddass_h", - "_arraySliceSliceAddass_i", - "_arraySliceSliceAddass_k", - "_arraySliceSliceAddass_s", - "_arraySliceSliceAddass_t", - "_arraySliceSliceAddass_u", - "_arraySliceSliceAddass_w", - - "_arraySliceSliceMinSliceAssign_a", - "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_g", - "_arraySliceSliceMinSliceAssign_h", - "_arraySliceSliceMinSliceAssign_i", - "_arraySliceSliceMinSliceAssign_k", - "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_s", - "_arraySliceSliceMinSliceAssign_t", - "_arraySliceSliceMinSliceAssign_u", - "_arraySliceSliceMinSliceAssign_w", - - "_arraySliceSliceMinass_a", - "_arraySliceSliceMinass_d", // T[]-=T[] - "_arraySliceSliceMinass_f", // T[]-=T[] - "_arraySliceSliceMinass_g", - "_arraySliceSliceMinass_h", - "_arraySliceSliceMinass_i", - "_arraySliceSliceMinass_k", - "_arraySliceSliceMinass_s", - "_arraySliceSliceMinass_t", - "_arraySliceSliceMinass_u", - "_arraySliceSliceMinass_w", - - "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_i", - "_arraySliceSliceMulSliceAssign_k", - "_arraySliceSliceMulSliceAssign_s", - "_arraySliceSliceMulSliceAssign_t", - "_arraySliceSliceMulSliceAssign_u", - "_arraySliceSliceMulSliceAssign_w", - - "_arraySliceSliceMulass_d", // T[]*=T[] - "_arraySliceSliceMulass_f", // T[]*=T[] - "_arraySliceSliceMulass_i", - "_arraySliceSliceMulass_k", - "_arraySliceSliceMulass_s", - "_arraySliceSliceMulass_t", - "_arraySliceSliceMulass_u", - "_arraySliceSliceMulass_w", - }; - - int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); - if (i == -1) - { -#ifdef DEBUG // Make sure our array is alphabetized - for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) - { - if (strcmp(name, libArrayopFuncs[i]) == 0) - assert(0); - } -#endif -#endif - /* Not in library, so generate it. - * Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Arguments *fparams = new Arguments(); - Expression *loopbody = buildArrayLoop(fparams); - Argument *p = (Argument *)fparams->data[0 /*fparams->dim - 1*/]; -#if DMDV1 - // for (size_t i = 0; i < p.length; i++) - Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); - Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); - Statement *s1 = new ForStatement(0, - new DeclarationStatement(0, d), - new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), - new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), - new ExpStatement(0, loopbody)); -#else - // foreach (i; 0 .. p.length) - Statement *s1 = new ForeachRangeStatement(0, TOKforeach, - new Argument(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tint32), - new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), - new ExpStatement(0, loopbody)); -#endif - Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); - //printf("s2: %s\n", s2->toChars()); - Statement *fbody = new CompoundStatement(0, s1, s2); - - /* Construct the function - */ - TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); - //printf("ftype: %s\n", ftype->toChars()); - fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype); - fd->fbody = fbody; - fd->protection = PROTpublic; - fd->linkage = LINKd; - - // special attention for array ops - fd->isArrayOp = true; - - sc->module->importedFrom->members->push(fd); - - sc = sc->push(); - sc->parent = sc->module->importedFrom; - sc->stc = 0; - sc->linkage = LINKc; - fd->semantic(sc); - sc->pop(); -#if IN_DMD - } - else - { /* In library, refer to it. - */ - fd = FuncDeclaration::genCfunc(type, name); - } -#endif - sv->ptrvalue = fd; // cache symbol in hash table - } - - /* Call the function fd(arguments) - */ - Expression *ec = new VarExp(0, fd); - Expression *e = new CallExp(loc, ec, arguments); - e->type = type; - return e; -} - -/****************************************** - * Construct the identifier for the array operation function, - * and build the argument list to pass to it. - */ - -void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Exp"); - arguments->shift(this); -} - -void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - e1->buildArrayIdent(buf, arguments); - } - else - Expression::buildArrayIdent(buf, arguments); -} - -void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Slice"); - arguments->shift(this); -} - -void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - /* Evaluate assign expressions right to left - */ - e2->buildArrayIdent(buf, arguments); - e1->buildArrayIdent(buf, arguments); - buf->writestring("Assign"); -} - -#define X(Str) \ -void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - e2->buildArrayIdent(buf, arguments); \ - e1->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ - buf->writestring("ass"); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Neg"); -} - -void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Com"); -} - -#define X(Str) \ -void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - e1->buildArrayIdent(buf, arguments); \ - e2->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -/****************************************** - * Construct the inner loop for the array operation function, - * and build the parameter list. - */ - -Expression *Expression::buildArrayLoop(Arguments *fparams) -{ - Identifier *id = Identifier::generateId("c", fparams->dim); - Argument *param = new Argument(0, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - return e; -} - -Expression *CastExp::buildArrayLoop(Arguments *fparams) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - return e1->buildArrayLoop(fparams); - } - else - Expression::buildArrayLoop(fparams); -} - -Expression *SliceExp::buildArrayLoop(Arguments *fparams) -{ - Identifier *id = Identifier::generateId("p", fparams->dim); - Argument *param = new Argument(STCconst, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - Expressions *arguments = new Expressions(); - Expression *index = new IdentifierExp(0, Id::p); - arguments->push(index); - e = new ArrayExp(0, e, arguments); - return e; -} - -Expression *AssignExp::buildArrayLoop(Arguments *fparams) -{ - /* Evaluate assign expressions right to left - */ - Expression *ex2 = e2->buildArrayLoop(fparams); -#if DMDV2 - /* Need the cast because: - * b = c + p[i]; - * where b is a byte fails because (c + p[i]) is an int - * which cannot be implicitly cast to byte. - */ - ex2 = new CastExp(0, ex2, e1->type->nextOf()); -#endif - Expression *ex1 = e1->buildArrayLoop(fparams); - Argument *param = (Argument *)fparams->data[0]; - param->storageClass = 0; - Expression *e = new AssignExp(0, ex1, ex2); - return e; -} - -#define X(Str) \ -Expression *Str##AssignExp::buildArrayLoop(Arguments *fparams) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Argument *param = (Argument *)fparams->data[0]; \ - param->storageClass = 0; \ - Expression *e = new Str##AssignExp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - -Expression *NegExp::buildArrayLoop(Arguments *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new NegExp(0, ex1); - return e; -} - -Expression *ComExp::buildArrayLoop(Arguments *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new ComExp(0, ex1); - return e; -} - -#define X(Str) \ -Expression *Str##Exp::buildArrayLoop(Arguments *fparams) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *e = new Str##Exp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) - -#undef X - - + +// Copyright (c) 1999-2010 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 +#include +#include + +#include "rmem.h" + +#include "stringtable.h" + +#include "expression.h" +#include "statement.h" +#include "mtype.h" +#include "declaration.h" +#include "scope.h" +#include "id.h" +#include "module.h" +#include "init.h" + +#if IN_DMD +extern int binary(const char *p , const char **tab, int high); + +/************************************** + * Hash table of array op functions already generated or known about. + */ + +StringTable arrayfuncs; +#endif + +/********************************************** + * Check that there are no uses of arrays without []. + */ +bool isArrayOpValid(Expression *e) +{ + if (e->op == TOKslice) + return true; + Type *tb = e->type->toBasetype(); + + if ( (tb->ty == Tarray) || (tb->ty == Tsarray) ) + { + switch (e->op) + { + case TOKadd: + case TOKmin: + case TOKmul: + case TOKdiv: + case TOKmod: + case TOKxor: + case TOKand: + case TOKor: + case TOKpow: + return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2); + + case TOKcall: + return false; // TODO: Decide if [] is required after arrayop calls. + + case TOKneg: + case TOKtilde: + return isArrayOpValid(((UnaExp *)e)->e1); + + default: + return false; + } + } + return true; +} + +/*********************************** + * Construct the array operation expression. + */ + +Expression *BinExp::arrayOp(Scope *sc) +{ + + if (type->toBasetype()->nextOf()->toBasetype()->ty == Tvoid) + { + error("Cannot perform array operations on void[] arrays"); + return new ErrorExp(); + } + + if (!isArrayOpValid(e2)) + { + e2->error("invalid array operation %s (did you forget a [] ?)", toChars()); + return new ErrorExp(); + } + + Expressions *arguments = new Expressions(); + + /* The expression to generate an array operation for is mangled + * into a name to use as the array operation function name. + * Mangle in the operands and operators in RPN order, and type. + */ + OutBuffer buf; + buf.writestring("_array"); + buildArrayIdent(&buf, arguments); + buf.writeByte('_'); + + /* Append deco of array element type + */ +#if DMDV2 + buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); +#else + buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); +#endif + + size_t namelen = buf.offset; + buf.writeByte(0); + char *name = (char *)buf.extractData(); + + /* Look up name in hash table + */ +#if IN_LLVM + StringValue *sv = sc->module->arrayfuncs.update(name, namelen); +#else + StringValue *sv = arrayfuncs.update(name, namelen); +#endif + FuncDeclaration *fd = (FuncDeclaration *)sv->ptrvalue; + if (!fd) + { +#if IN_DMD + /* Some of the array op functions are written as library functions, + * presumably to optimize them with special CPU vector instructions. + * List those library functions here, in alpha order. + */ + static const char *libArrayopFuncs[] = + { + "_arrayExpSliceAddass_a", + "_arrayExpSliceAddass_d", // T[]+=T + "_arrayExpSliceAddass_f", // T[]+=T + "_arrayExpSliceAddass_g", + "_arrayExpSliceAddass_h", + "_arrayExpSliceAddass_i", + "_arrayExpSliceAddass_k", + "_arrayExpSliceAddass_s", + "_arrayExpSliceAddass_t", + "_arrayExpSliceAddass_u", + "_arrayExpSliceAddass_w", + + "_arrayExpSliceDivass_d", // T[]/=T + "_arrayExpSliceDivass_f", // T[]/=T + + "_arrayExpSliceMinSliceAssign_a", + "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] + "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] + "_arrayExpSliceMinSliceAssign_g", + "_arrayExpSliceMinSliceAssign_h", + "_arrayExpSliceMinSliceAssign_i", + "_arrayExpSliceMinSliceAssign_k", + "_arrayExpSliceMinSliceAssign_s", + "_arrayExpSliceMinSliceAssign_t", + "_arrayExpSliceMinSliceAssign_u", + "_arrayExpSliceMinSliceAssign_w", + + "_arrayExpSliceMinass_a", + "_arrayExpSliceMinass_d", // T[]-=T + "_arrayExpSliceMinass_f", // T[]-=T + "_arrayExpSliceMinass_g", + "_arrayExpSliceMinass_h", + "_arrayExpSliceMinass_i", + "_arrayExpSliceMinass_k", + "_arrayExpSliceMinass_s", + "_arrayExpSliceMinass_t", + "_arrayExpSliceMinass_u", + "_arrayExpSliceMinass_w", + + "_arrayExpSliceMulass_d", // T[]*=T + "_arrayExpSliceMulass_f", // T[]*=T + "_arrayExpSliceMulass_i", + "_arrayExpSliceMulass_k", + "_arrayExpSliceMulass_s", + "_arrayExpSliceMulass_t", + "_arrayExpSliceMulass_u", + "_arrayExpSliceMulass_w", + + "_arraySliceExpAddSliceAssign_a", + "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T + "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T + "_arraySliceExpAddSliceAssign_g", + "_arraySliceExpAddSliceAssign_h", + "_arraySliceExpAddSliceAssign_i", + "_arraySliceExpAddSliceAssign_k", + "_arraySliceExpAddSliceAssign_s", + "_arraySliceExpAddSliceAssign_t", + "_arraySliceExpAddSliceAssign_u", + "_arraySliceExpAddSliceAssign_w", + + "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T + "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T + + "_arraySliceExpMinSliceAssign_a", + "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T + "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T + "_arraySliceExpMinSliceAssign_g", + "_arraySliceExpMinSliceAssign_h", + "_arraySliceExpMinSliceAssign_i", + "_arraySliceExpMinSliceAssign_k", + "_arraySliceExpMinSliceAssign_s", + "_arraySliceExpMinSliceAssign_t", + "_arraySliceExpMinSliceAssign_u", + "_arraySliceExpMinSliceAssign_w", + + "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T + "_arraySliceExpMulSliceAddass_f", + "_arraySliceExpMulSliceAddass_r", + + "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T + "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T + "_arraySliceExpMulSliceAssign_i", + "_arraySliceExpMulSliceAssign_k", + "_arraySliceExpMulSliceAssign_s", + "_arraySliceExpMulSliceAssign_t", + "_arraySliceExpMulSliceAssign_u", + "_arraySliceExpMulSliceAssign_w", + + "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T + "_arraySliceExpMulSliceMinass_f", + "_arraySliceExpMulSliceMinass_r", + + "_arraySliceSliceAddSliceAssign_a", + "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_g", + "_arraySliceSliceAddSliceAssign_h", + "_arraySliceSliceAddSliceAssign_i", + "_arraySliceSliceAddSliceAssign_k", + "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] + "_arraySliceSliceAddSliceAssign_s", + "_arraySliceSliceAddSliceAssign_t", + "_arraySliceSliceAddSliceAssign_u", + "_arraySliceSliceAddSliceAssign_w", + + "_arraySliceSliceAddass_a", + "_arraySliceSliceAddass_d", // T[]+=T[] + "_arraySliceSliceAddass_f", // T[]+=T[] + "_arraySliceSliceAddass_g", + "_arraySliceSliceAddass_h", + "_arraySliceSliceAddass_i", + "_arraySliceSliceAddass_k", + "_arraySliceSliceAddass_s", + "_arraySliceSliceAddass_t", + "_arraySliceSliceAddass_u", + "_arraySliceSliceAddass_w", + + "_arraySliceSliceMinSliceAssign_a", + "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_g", + "_arraySliceSliceMinSliceAssign_h", + "_arraySliceSliceMinSliceAssign_i", + "_arraySliceSliceMinSliceAssign_k", + "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] + "_arraySliceSliceMinSliceAssign_s", + "_arraySliceSliceMinSliceAssign_t", + "_arraySliceSliceMinSliceAssign_u", + "_arraySliceSliceMinSliceAssign_w", + + "_arraySliceSliceMinass_a", + "_arraySliceSliceMinass_d", // T[]-=T[] + "_arraySliceSliceMinass_f", // T[]-=T[] + "_arraySliceSliceMinass_g", + "_arraySliceSliceMinass_h", + "_arraySliceSliceMinass_i", + "_arraySliceSliceMinass_k", + "_arraySliceSliceMinass_s", + "_arraySliceSliceMinass_t", + "_arraySliceSliceMinass_u", + "_arraySliceSliceMinass_w", + + "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] + "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] + "_arraySliceSliceMulSliceAssign_i", + "_arraySliceSliceMulSliceAssign_k", + "_arraySliceSliceMulSliceAssign_s", + "_arraySliceSliceMulSliceAssign_t", + "_arraySliceSliceMulSliceAssign_u", + "_arraySliceSliceMulSliceAssign_w", + + "_arraySliceSliceMulass_d", // T[]*=T[] + "_arraySliceSliceMulass_f", // T[]*=T[] + "_arraySliceSliceMulass_i", + "_arraySliceSliceMulass_k", + "_arraySliceSliceMulass_s", + "_arraySliceSliceMulass_t", + "_arraySliceSliceMulass_u", + "_arraySliceSliceMulass_w", + }; + + int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); + if (i == -1) + { +#ifdef DEBUG // Make sure our array is alphabetized + for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) + { + if (strcmp(name, libArrayopFuncs[i]) == 0) + assert(0); + } +#endif +#endif + /* Not in library, so generate it. + * Construct the function body: + * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) + * loopbody; + * return p; + */ + + Parameters *fparams = new Parameters(); + Expression *loopbody = buildArrayLoop(fparams); + Parameter *p = (Parameter *)fparams->data[0 /*fparams->dim - 1*/]; +#if DMDV1 + // for (size_t i = 0; i < p.length; i++) + Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); + Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); + Statement *s1 = new ForStatement(0, + new DeclarationStatement(0, d), + new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), + new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), + new ExpStatement(0, loopbody)); +#else + // foreach (i; 0 .. p.length) + Statement *s1 = new ForeachRangeStatement(0, TOKforeach, + new Parameter(0, NULL, Id::p, NULL), + new IntegerExp(0, 0, Type::tint32), + new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), + new ExpStatement(0, loopbody)); +#endif + Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); + //printf("s2: %s\n", s2->toChars()); + Statement *fbody = new CompoundStatement(0, s1, s2); + + /* Construct the function + */ + TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); + //printf("ftype: %s\n", ftype->toChars()); + fd = new FuncDeclaration(0, 0, Lexer::idPool(name), STCundefined, ftype); + fd->fbody = fbody; + fd->protection = PROTpublic; + fd->linkage = LINKd; + + // special attention for array ops + fd->isArrayOp = true; + + sc->module->importedFrom->members->push(fd); + + sc = sc->push(); + sc->parent = sc->module->importedFrom; + sc->stc = 0; + sc->linkage = LINKc; + fd->semantic(sc); + fd->semantic2(sc); + fd->semantic3(sc); + sc->pop(); +#if IN_DMD + } + else + { /* In library, refer to it. + */ + fd = FuncDeclaration::genCfunc(type, name); + } +#endif + sv->ptrvalue = fd; // cache symbol in hash table + } + + /* Call the function fd(arguments) + */ + Expression *ec = new VarExp(0, fd); + Expression *e = new CallExp(loc, ec, arguments); + e->type = type; + return e; +} + +/****************************************** + * Construct the identifier for the array operation function, + * and build the argument list to pass to it. + */ + +void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Exp"); + arguments->shift(this); +} + +void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + Type *tb = type->toBasetype(); + if (tb->ty == Tarray || tb->ty == Tsarray) + { + e1->buildArrayIdent(buf, arguments); + } + else + Expression::buildArrayIdent(buf, arguments); +} + +void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + buf->writestring("Slice"); + arguments->shift(this); +} + +void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + /* Evaluate assign expressions right to left + */ + e2->buildArrayIdent(buf, arguments); + e1->buildArrayIdent(buf, arguments); + buf->writestring("Assign"); +} + +#define X(Str) \ +void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ +{ \ + /* Evaluate assign expressions right to left \ + */ \ + e2->buildArrayIdent(buf, arguments); \ + e1->buildArrayIdent(buf, arguments); \ + buf->writestring(#Str); \ + buf->writestring("ass"); \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + e1->buildArrayIdent(buf, arguments); + buf->writestring("Neg"); +} + +void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) +{ + e1->buildArrayIdent(buf, arguments); + buf->writestring("Com"); +} + +#define X(Str) \ +void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ +{ \ + /* Evaluate assign expressions left to right \ + */ \ + e1->buildArrayIdent(buf, arguments); \ + e2->buildArrayIdent(buf, arguments); \ + buf->writestring(#Str); \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +/****************************************** + * Construct the inner loop for the array operation function, + * and build the parameter list. + */ + +Expression *Expression::buildArrayLoop(Parameters *fparams) +{ + Identifier *id = Identifier::generateId("c", fparams->dim); + Parameter *param = new Parameter(0, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(0, id); + return e; +} + +Expression *CastExp::buildArrayLoop(Parameters *fparams) +{ + Type *tb = type->toBasetype(); + if (tb->ty == Tarray || tb->ty == Tsarray) + { + return e1->buildArrayLoop(fparams); + } + else + return Expression::buildArrayLoop(fparams); +} + +Expression *SliceExp::buildArrayLoop(Parameters *fparams) +{ + Identifier *id = Identifier::generateId("p", fparams->dim); + Parameter *param = new Parameter(STCconst, type, id, NULL); + fparams->shift(param); + Expression *e = new IdentifierExp(0, id); + Expressions *arguments = new Expressions(); + Expression *index = new IdentifierExp(0, Id::p); + arguments->push(index); + e = new ArrayExp(0, e, arguments); + return e; +} + +Expression *AssignExp::buildArrayLoop(Parameters *fparams) +{ + /* Evaluate assign expressions right to left + */ + Expression *ex2 = e2->buildArrayLoop(fparams); +#if DMDV2 + /* Need the cast because: + * b = c + p[i]; + * where b is a byte fails because (c + p[i]) is an int + * which cannot be implicitly cast to byte. + */ + ex2 = new CastExp(0, ex2, e1->type->nextOf()); +#endif + Expression *ex1 = e1->buildArrayLoop(fparams); + Parameter *param = (Parameter *)fparams->data[0]; + param->storageClass = 0; + Expression *e = new AssignExp(0, ex1, ex2); + return e; +} + +#define X(Str) \ +Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ +{ \ + /* Evaluate assign expressions right to left \ + */ \ + Expression *ex2 = e2->buildArrayLoop(fparams); \ + Expression *ex1 = e1->buildArrayLoop(fparams); \ + Parameter *param = (Parameter *)fparams->data[0]; \ + param->storageClass = 0; \ + Expression *e = new Str##AssignExp(0, ex1, ex2); \ + return e; \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + +Expression *NegExp::buildArrayLoop(Parameters *fparams) +{ + Expression *ex1 = e1->buildArrayLoop(fparams); + Expression *e = new NegExp(0, ex1); + return e; +} + +Expression *ComExp::buildArrayLoop(Parameters *fparams) +{ + Expression *ex1 = e1->buildArrayLoop(fparams); + Expression *e = new ComExp(0, ex1); + return e; +} + +#define X(Str) \ +Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \ +{ \ + /* Evaluate assign expressions left to right \ + */ \ + Expression *ex1 = e1->buildArrayLoop(fparams); \ + Expression *ex2 = e2->buildArrayLoop(fparams); \ + Expression *e = new Str##Exp(0, ex1, ex2); \ + return e; \ +} + +X(Add) +X(Min) +X(Mul) +X(Div) +X(Mod) +X(Xor) +X(And) +X(Or) + +#undef X + + +/*********************************************** + * Test if operand is a valid array op operand. + */ + +int Expression::isArrayOperand() +{ + //printf("Expression::isArrayOperand() %s\n", toChars()); + if (op == TOKslice) + return 1; + if (type->toBasetype()->ty == Tarray) + { + switch (op) + { + case TOKadd: + case TOKmin: + case TOKmul: + case TOKdiv: + case TOKmod: + case TOKxor: + case TOKand: + case TOKor: + case TOKneg: + case TOKtilde: + return 1; + + default: + break; + } + } + return 0; +} diff --git a/dmd2/arraytypes.h b/dmd2/arraytypes.h index c9c2450d..ef3d6fe4 100644 --- a/dmd2/arraytypes.h +++ b/dmd2/arraytypes.h @@ -1,51 +1,51 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2006-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. - -#ifndef DMD_ARRAYTYPES_H -#define DMD_ARRAYTYPES_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - - -#include "root.h" - -struct Expression; -struct Statement; -struct BaseClass; -struct TemplateParameter; -struct FuncDeclaration; -struct Identifier; -struct Initializer; - -struct TemplateParameters : Array { }; - -struct Expressions : Array { }; - -struct Statements : Array { }; - -struct BaseClasses : Array { }; - -struct ClassDeclarations : Array { }; - -struct Dsymbols : Array { }; - -struct Objects : Array { }; - -struct FuncDeclarations : Array { }; - -struct Arguments : Array { }; - -struct Identifiers : Array { }; - -struct Initializers : Array { }; - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 2006-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. + +#ifndef DMD_ARRAYTYPES_H +#define DMD_ARRAYTYPES_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + + +#include "root.h" + +struct Expression; +struct Statement; +struct BaseClass; +struct TemplateParameter; +struct FuncDeclaration; +struct Identifier; +struct Initializer; + +struct TemplateParameters : Array { }; + +struct Expressions : Array { }; + +struct Statements : Array { }; + +struct BaseClasses : Array { }; + +struct ClassDeclarations : Array { }; + +struct Dsymbols : Array { }; + +struct Objects : Array { }; + +struct FuncDeclarations : Array { }; + +struct Parameters : Array { }; + +struct Identifiers : Array { }; + +struct Initializers : Array { }; + +#endif diff --git a/dmd2/attrib.c b/dmd2/attrib.c index 6c94e90d..2556a859 100644 --- a/dmd2/attrib.c +++ b/dmd2/attrib.c @@ -1,1674 +1,1771 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#include "rmem.h" - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "template.h" -#if TARGET_NET - #include "frontend.net/pragma.h" -#endif - -#if IN_LLVM -#include "../gen/enums.h" - -#include "llvm/Support/CommandLine.h" - -static llvm::cl::opt ignoreUnsupportedPragmas("ignore", - llvm::cl::desc("Ignore unsupported pragmas"), - llvm::cl::ZeroOrMore); - -#endif - - -extern void obj_includelib(const char *name); - -#if IN_DMD -void obj_startaddress(Symbol *s); -#endif - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Array *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Array *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Array *d = include(sc, sd); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::setScopeNewSc(Scope *sc, - unsigned stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->setScope(newsc); // yes, the only difference from semanticNewSc() - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semanticNewSc(Scope *sc, - unsigned stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(newsc); - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - Array *d = include(sc, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - if (comment) - { - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* A general problem with this, illustrated by BUGZILLA 2516, - * is that attributes are not transmitted through to the underlying - * member declarations for template bodies, because semantic analysis - * is not done for template declaration bodies - * (only template instantiations). - * Hence, Ddoc omits attributes from template members. - */ - - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -#if IN_DMD - -void AttribDeclaration::toObjFile(int multiobj) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->toObjFile(multiobj); - } - } -} - -int AttribDeclaration::cvMember(unsigned char *p) -{ - int nwritten = 0; - int n; - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; - } - } - return nwritten; -} -#endif - -int AttribDeclaration::hasPointers() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -const char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps) -{ - Array *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Array *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(unsigned stc, Array *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -void StorageClassDeclaration::setScope(Scope *sc) -{ - if (decl) - { - unsigned scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - scstc |= stc; - - setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { - unsigned scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - scstc |= stc; - - semanticNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, int stc) -{ - struct SCstring - { - int stc; - enum TOK tok; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - { STClazy, TOKlazy }, - { STCalias, TOKalias }, - { STCout, TOKout }, - { STCin, TOKin }, -#if DMDV2 - { STCimmutable, TOKimmutable }, - { STCshared, TOKshared }, - { STCnothrow, TOKnothrow }, - { STCpure, TOKpure }, - { STCref, TOKref }, - { STCtls, TOKtls }, - { STCgshared, TOKgshared }, -#endif - }; - - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - buf->writestring(Token::toChars(table[i].tok)); - buf->writeByte(' '); - } - } -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - stcToCBuffer(buf, stc); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Array *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::setScope(Scope *sc) -{ - //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - setScopeNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - semanticNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - -#if IN_LLVM - case LINKintrinsic: p = "Intrinsic"; break; -#endif - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return (char *)"extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Array *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::setScope(Scope *sc) -{ - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) -{ - const char *p; - - switch (protection) - { - case PROTprivate: p = "private"; break; - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTpublic: p = "public"; break; - case PROTexport: p = "export"; break; - default: - assert(0); - break; - } - buf->writestring(p); - buf->writeByte(' '); -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - protectionToCBuffer(buf, protection); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::setScope(Scope *sc) -{ - //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } -} - -void AlignDeclaration::semantic(Scope *sc) -{ - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } - else - assert(0 && "what kind of align use triggers this?"); -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - if (decl) - { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - - sc = sc->push(); - sc->anonAgg = &aad; - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } - } - sc = sc->pop(); - - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) - { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - //printf("\tforward reference %p\n", this); - return; - } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); - - // 0 sized structs are set to 1 byte - if (aad.structsize == 0) - { - aad.structsize = 1; - aad.alignsize = 1; - } - - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); - - // Add members of aad to ad - //printf("\tadding members of aad to '%s'\n", ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) - { - VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; - -#if IN_LLVM - v->offset2 = sc->offset; -#endif - v->offset += sc->offset; - -#if IN_LLVM - if (!v->anonDecl) - v->anonDecl = this; -#endif - ad->fields.push(v); - } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -static bool parseStringExp(Expression* e, std::string& res) -{ - StringExp *s = NULL; - - e = e->optimize(WANTvalue); - if (e->op == TOKstring && (s = (StringExp *)e)) - { - char* str = (char*)s->string; - res = str; - return true; - } - return false; -} - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::setScope(Scope *sc) -{ -#if TARGET_NET - if (ident == Lexer::idPool("assembly")) - { - if (!args || args->dim != 1) - { - error("pragma has invalid number of arguments"); - } - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - { - error("string expected, not '%s'", e->toChars()); - } - PragmaScope* pragma = new PragmaScope(this, sc->parent, static_cast(e)); - - assert(sc); - pragma->setScope(sc); - - //add to module members - assert(sc->module); - assert(sc->module->members); - sc->module->members->push(pragma); - } - } -#endif // TARGET_NET -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - int llvm_internal = 0; - std::string arg1str; -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = (Expression *)args->data[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = (Expression *)args->data[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue); - if (e->op == TOKstring && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a char string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - } - goto Lnodecl; - } -#if TARGET_NET - else if (ident == Lexer::idPool("assembly")) - { - } -#endif // TARGET_NET -// LDC -#if IN_LLVM - - // pragma(intrinsic, "string") { funcdecl(s) } - else if (ident == Id::intrinsic) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - llvm_internal = LLVMintrinsic; - } - - // pragma(notypeinfo) { typedecl(s) } - else if (ident == Id::no_typeinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_typeinfo; - } - - // pragma(nomoduleinfo) ; - else if (ident == Id::no_moduleinfo) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMno_moduleinfo; - } - - // pragma(alloca) { funcdecl(s) } - else if (ident == Id::Alloca) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMalloca; - } - - // pragma(va_start) { templdecl(s) } - else if (ident == Id::vastart) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_start; - } - - // pragma(va_copy) { funcdecl(s) } - else if (ident == Id::vacopy) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_copy; - } - - // pragma(va_end) { funcdecl(s) } - else if (ident == Id::vaend) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_end; - } - - // pragma(va_arg) { templdecl(s) } - else if (ident == Id::vaarg) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMva_arg; - } - - // pragma(ldc, "string") { templdecl(s) } - else if (ident == Id::ldc) - { - Expression* expr = (Expression *)args->data[0]; - expr = expr->semantic(sc); - if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) - { - error("requires exactly 1 string literal parameter"); - fatal(); - } - else if (arg1str == "verbose") - { - sc->module->llvmForceLogging = true; - } - else - { - error("command '%s' invalid", expr->toChars()); - fatal(); - } - } - - // pragma(llvm_inline_asm) { templdecl(s) } - else if (ident == Id::llvm_inline_asm) - { - if (args && args->dim > 0) - { - error("takes no parameters"); - fatal(); - } - llvm_internal = LLVMinline_asm; - } - -#endif // LDC - - else if (ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - printf("pragma %s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - // ignore errors in ignored pragmas. - global.gag++; - unsigned errors_save = global.errors; - - Expression *e = (Expression *)args->data[i]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - - // restore error state. - global.gag--; - global.errors = errors_save; - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - } - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - s->semantic(sc); - -// LDC -#if IN_LLVM - - if (llvm_internal) - { - if (s->llvmInternal) - { - error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); - fatal(); - } - switch(llvm_internal) - { - case LLVMintrinsic: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - fd->intrinsicName = arg1str; - fd->linkage = LINKintrinsic; - ((TypeFunction*)fd->type)->linkage = LINKintrinsic; - } - else if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - td->llvmInternal = llvm_internal; - td->intrinsicName = arg1str; - } - else - { - error("only allowed on function declarations"); - fatal(); - } - break; - - case LLVMva_start: - case LLVMva_arg: - if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - if (td->parameters->dim != 1) - { - error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); - fatal(); - } - else if (!td->onemember) - { - error("the '%s' pragma template must have exactly one member", ident->toChars()); - fatal(); - } - else if (td->overnext || td->overroot) - { - error("the '%s' pragma template must not be overloaded", ident->toChars()); - fatal(); - } - td->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on template declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMva_copy: - case LLVMva_end: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on function declarations", ident->toChars()); - fatal(); - } - break; - - case LLVMno_typeinfo: - s->llvmInternal = llvm_internal; - break; - - case LLVMalloca: - if (FuncDeclaration* fd = s->isFuncDeclaration()) - { - fd->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); - fatal(); - } - break; - - case LLVMinline_asm: - if (TemplateDeclaration* td = s->isTemplateDeclaration()) - { - if (td->parameters->dim > 1) - { - error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars()); - fatal(); - } - else if (!td->onemember) - { - error("the '%s' pragma template must have exactly one member", ident->toChars()); - fatal(); - } - td->llvmInternal = llvm_internal; - } - else - { - error("the '%s' pragma is only allowed on template declarations", ident->toChars()); - fatal(); - } - break; - - default: - warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); - } - } - -#endif // LDC - - } - } - return; - -Lnodecl: - if (decl) - error("pragma is missing closing ';'"); -} - -int PragmaDeclaration::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -const char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -#if IN_DMD -void PragmaDeclaration::toObjFile(int multiobj) -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = (Expression *)args->data[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; -#if OMFOBJ - /* The OMF format allows library names to be inserted - * into the object file. The linker will then automatically - * search that library, too. - */ - obj_includelib(name); -#elif ELFOBJ || MACHOBJ - /* The format does not allow embedded library names, - * so instead append the library name to the list to be passed - * to the linker. - */ - global.params.libfiles->push((void *) name); -#else - error("pragma lib not supported"); -#endif - } -#if DMDV2 - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = (Expression *)args->data[0]; - Dsymbol *sa = getDsymbol(e); - FuncDeclaration *f = sa->isFuncDeclaration(); - assert(f); - Symbol *s = f->toSymbol(); - obj_startaddress(s); - } -#endif - AttribDeclaration::toObjFile(multiobj); -} -#endif - -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma (%s", ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Array *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } - else if (sc->docbuf) - { - /* If generating doc comment, be careful because if we're inside - * a template, then include(NULL, NULL) will fail. - */ - Array *d = decl ? decl : elsedecl; - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = (Dsymbol *)d->data[i]; - s->emitComment(sc); - } - } -} - -// Decide if 'then' or 'else' code should be included - -Array *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Array *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = (Dsymbol *)decl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = (Dsymbol *)elsedecl->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Array *decl, Array *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Array *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = (Dsymbol *)d->data[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exp = exp; - this->sd = NULL; - this->compiled = 0; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; -} - -int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("CompileDeclaration::addMember(sc = %p, memnum = %d)\n", sc, memnum); - this->sd = sd; - if (memnum == 0) - { /* No members yet, so parse the mixin now - */ - compileIt(sc); - memnum |= AttribDeclaration::addMember(sc, sd, memnum); - compiled = 1; - } - return memnum; -} - -void CompileDeclaration::compileIt(Scope *sc) -{ - //printf("CompileDeclaration::compileIt(loc = %d)\n", loc.linnum); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); - } - else - { - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp->error("incomplete mixin declaration (%s)", se->toChars()); - } -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - - if (!compiled) - { - compileIt(sc); - AttribDeclaration::addMember(sc, sd, 0); - compiled = 1; - } - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include + +#include "rmem.h" + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "cond.h" +#include "scope.h" +#include "id.h" +#include "expression.h" +#include "dsymbol.h" +#include "aggregate.h" +#include "module.h" +#include "parse.h" +#include "template.h" +#if TARGET_NET + #include "frontend.net/pragma.h" +#endif + +#if IN_LLVM +#include "../gen/enums.h" + +#include "llvm/Support/CommandLine.h" + +static llvm::cl::opt ignoreUnsupportedPragmas("ignore", + llvm::cl::desc("Ignore unsupported pragmas"), + llvm::cl::ZeroOrMore); + +#endif + + +extern void obj_includelib(const char *name); + +#if IN_DMD +void obj_startaddress(Symbol *s); +#endif + + +/********************************* AttribDeclaration ****************************/ + +AttribDeclaration::AttribDeclaration(Dsymbols *decl) + : Dsymbol() +{ + this->decl = decl; +} + +Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + return decl; +} + +int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + int m = 0; + Dsymbols *d = include(sc, sd); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("\taddMember %s to %s\n", s->toChars(), sd->toChars()); + m |= s->addMember(sc, sd, m | memnum); + } + } + return m; +} + +void AttribDeclaration::setScopeNewSc(Scope *sc, + StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, + unsigned structalign) +{ + if (decl) + { + Scope *newsc = sc; + if (stc != sc->stc || + linkage != sc->linkage || + protection != sc->protection || + explicitProtection != sc->explicitProtection || + structalign != sc->structalign) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->stc = stc; + newsc->linkage = linkage; + newsc->protection = protection; + newsc->explicitProtection = explicitProtection; + newsc->structalign = structalign; + } + for (unsigned i = 0; i < decl->dim; i++) + { Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->setScope(newsc); // yes, the only difference from semanticNewSc() + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + +void AttribDeclaration::semanticNewSc(Scope *sc, + StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, + unsigned structalign) +{ + if (decl) + { + Scope *newsc = sc; + if (stc != sc->stc || + linkage != sc->linkage || + protection != sc->protection || + explicitProtection != sc->explicitProtection || + structalign != sc->structalign) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->stc = stc; + newsc->linkage = linkage; + newsc->protection = protection; + newsc->explicitProtection = explicitProtection; + newsc->structalign = structalign; + } + for (unsigned i = 0; i < decl->dim; i++) + { Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(newsc); + } + if (newsc != sc) + { + sc->offset = newsc->offset; + newsc->pop(); + } + } +} + +void AttribDeclaration::semantic(Scope *sc) +{ + Dsymbols *d = include(sc, NULL); + + //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +void AttribDeclaration::semantic2(Scope *sc) +{ + Dsymbols *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic2(sc); + } + } +} + +void AttribDeclaration::semantic3(Scope *sc) +{ + Dsymbols *d = include(sc, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->semantic3(sc); + } + } +} + +void AttribDeclaration::inlineScan() +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); + s->inlineScan(); + } + } +} + +void AttribDeclaration::addComment(unsigned char *comment) +{ + if (comment) + { + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + } +} + +void AttribDeclaration::emitComment(Scope *sc) +{ + //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); + + /* A general problem with this, illustrated by BUGZILLA 2516, + * is that attributes are not transmitted through to the underlying + * member declarations for template bodies, because semantic analysis + * is not done for template declaration bodies + * (only template instantiations). + * Hence, Ddoc omits attributes from template members. + */ + + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::emitComment %s\n", s->toChars()); + s->emitComment(sc); + } + } +} + +#if IN_DMD + +void AttribDeclaration::toObjFile(int multiobj) +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->toObjFile(multiobj); + } + } +} + +int AttribDeclaration::cvMember(unsigned char *p) +{ + int nwritten = 0; + int n; + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + n = s->cvMember(p); + if (p) + p += n; + nwritten += n; + } + } + return nwritten; +} +#endif + +int AttribDeclaration::hasPointers() +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (size_t i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + if (s->hasPointers()) + return 1; + } + } + return 0; +} + +const char *AttribDeclaration::kind() +{ + return "attribute"; +} + +int AttribDeclaration::oneMember(Dsymbol **ps) +{ + Dsymbols *d = include(NULL, NULL); + + return Dsymbol::oneMembers(d, ps); +} + +void AttribDeclaration::checkCtorConstInit() +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->checkCtorConstInit(); + } + } +} + +/**************************************** + */ + +void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ + Dsymbols *d = include(NULL, NULL); + + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->addLocalClass(aclasses); + } + } +} + + +void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (decl) + { + if (decl->dim == 0) + buf->writestring("{}"); + else if (decl->dim == 1) + ((Dsymbol *)decl->data[0])->toCBuffer(buf, hgs); + else + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + } + else + buf->writeByte(';'); + buf->writenl(); +} + +/************************* StorageClassDeclaration ****************************/ + +StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) + : AttribDeclaration(decl) +{ + this->stc = stc; +} + +Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) +{ + StorageClassDeclaration *scd; + + assert(!s); + scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); + return scd; +} + +void StorageClassDeclaration::setScope(Scope *sc) +{ + if (decl) + { + StorageClass scstc = sc->stc; + + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) + scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); + if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) + scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); + if (stc & (STCconst | STCimmutable | STCmanifest)) + scstc &= ~(STCconst | STCimmutable | STCmanifest); + if (stc & (STCgshared | STCshared | STCtls)) + scstc &= ~(STCgshared | STCshared | STCtls); + if (stc & (STCsafe | STCtrusted | STCsystem)) + scstc &= ~(STCsafe | STCtrusted | STCsystem); + scstc |= stc; + + setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + +void StorageClassDeclaration::semantic(Scope *sc) +{ + if (decl) + { + StorageClass scstc = sc->stc; + + /* These sets of storage classes are mutually exclusive, + * so choose the innermost or most recent one. + */ + if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) + scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); + if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) + scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); + if (stc & (STCconst | STCimmutable | STCmanifest)) + scstc &= ~(STCconst | STCimmutable | STCmanifest); + if (stc & (STCgshared | STCshared | STCtls)) + scstc &= ~(STCgshared | STCshared | STCtls); + if (stc & (STCsafe | STCtrusted | STCsystem)) + scstc &= ~(STCsafe | STCtrusted | STCsystem); + scstc |= stc; + + semanticNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + +void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) +{ + struct SCstring + { + StorageClass stc; + enum TOK tok; + Identifier *id; + }; + + static SCstring table[] = + { + { STCauto, TOKauto }, + { STCscope, TOKscope }, + { STCstatic, TOKstatic }, + { STCextern, TOKextern }, + { STCconst, TOKconst }, + { STCfinal, TOKfinal }, + { STCabstract, TOKabstract }, + { STCsynchronized, TOKsynchronized }, + { STCdeprecated, TOKdeprecated }, + { STCoverride, TOKoverride }, + { STClazy, TOKlazy }, + { STCalias, TOKalias }, + { STCout, TOKout }, + { STCin, TOKin }, +#if DMDV2 + { STCmanifest, TOKenum }, + { STCimmutable, TOKimmutable }, + { STCshared, TOKshared }, + { STCnothrow, TOKnothrow }, + { STCpure, TOKpure }, + { STCref, TOKref }, + { STCtls, TOKtls }, + { STCgshared, TOKgshared }, + { STCproperty, TOKat, Id::property }, + { STCsafe, TOKat, Id::safe }, + { STCtrusted, TOKat, Id::trusted }, + { STCsystem, TOKat, Id::system }, + { STCdisable, TOKat, Id::disable }, +#endif + }; + + for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) + { + if (stc & table[i].stc) + { + enum TOK tok = table[i].tok; +#if DMDV2 + if (tok == TOKat) + { + buf->writeByte('@'); + buf->writestring(table[i].id->toChars()); + } + else +#endif + buf->writestring(Token::toChars(tok)); + buf->writeByte(' '); + } + } +} + +void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + stcToCBuffer(buf, stc); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* LinkDeclaration ****************************/ + +LinkDeclaration::LinkDeclaration(enum LINK p, Dsymbols *decl) + : AttribDeclaration(decl) +{ + //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); + linkage = p; +} + +Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) +{ + LinkDeclaration *ld; + + assert(!s); + ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); + return ld; +} + +void LinkDeclaration::setScope(Scope *sc) +{ + //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + setScopeNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + +void LinkDeclaration::semantic(Scope *sc) +{ + //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { + semanticNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); + } +} + +void LinkDeclaration::semantic3(Scope *sc) +{ + //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); + if (decl) + { enum LINK linkage_save = sc->linkage; + + sc->linkage = linkage; + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic3(sc); + } + sc->linkage = linkage_save; + } + else + { + sc->linkage = linkage; + } +} + +void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ const char *p; + + switch (linkage) + { + case LINKd: p = "D"; break; + case LINKc: p = "C"; break; + case LINKcpp: p = "C++"; break; + case LINKwindows: p = "Windows"; break; + case LINKpascal: p = "Pascal"; break; + +#if IN_LLVM + case LINKintrinsic: p = "Intrinsic"; break; +#endif + default: + assert(0); + break; + } + buf->writestring("extern ("); + buf->writestring(p); + buf->writestring(") "); + AttribDeclaration::toCBuffer(buf, hgs); +} + +char *LinkDeclaration::toChars() +{ + return (char *)"extern ()"; +} + +/********************************* ProtDeclaration ****************************/ + +ProtDeclaration::ProtDeclaration(enum PROT p, Dsymbols *decl) + : AttribDeclaration(decl) +{ + protection = p; + //printf("decl = %p\n", decl); +} + +Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) +{ + ProtDeclaration *pd; + + assert(!s); + pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void ProtDeclaration::setScope(Scope *sc) +{ + if (decl) + { + setScopeNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); + } +} + +void ProtDeclaration::importAll(Scope *sc) +{ + Scope *newsc = sc; + if (sc->protection != protection || + sc->explicitProtection != 1) + { + // create new one for changes + newsc = new Scope(*sc); + newsc->flags &= ~SCOPEfree; + newsc->protection = protection; + newsc->explicitProtection = 1; + } + + for (int i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + s->importAll(newsc); + } + + if (newsc != sc) + newsc->pop(); +} + +void ProtDeclaration::semantic(Scope *sc) +{ + if (decl) + { + semanticNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); + } +} + +void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) +{ + const char *p; + + switch (protection) + { + case PROTprivate: p = "private"; break; + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTpublic: p = "public"; break; + case PROTexport: p = "export"; break; + default: + assert(0); + break; + } + buf->writestring(p); + buf->writeByte(' '); +} + +void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + protectionToCBuffer(buf, protection); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AlignDeclaration ****************************/ + +AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + salign = sa; +} + +Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) +{ + AlignDeclaration *ad; + + assert(!s); + ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AlignDeclaration::setScope(Scope *sc) +{ + //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); + if (decl) + { + setScopeNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); + } +} + +void AlignDeclaration::semantic(Scope *sc) +{ + //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); + if (decl) + { + semanticNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); + } + else + assert(0 && "what kind of align use triggers this?"); +} + + +void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("align (%d)", salign); + AttribDeclaration::toCBuffer(buf, hgs); +} + +/********************************* AnonDeclaration ****************************/ + +AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->isunion = isunion; + this->sem = 0; +} + +Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) +{ + AnonDeclaration *ad; + + assert(!s); + ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); + return ad; +} + +void AnonDeclaration::semantic(Scope *sc) +{ + //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; + scope = NULL; + } + + unsigned dprogress_save = Module::dprogress; + + assert(sc->parent); + + Dsymbol *parent = sc->parent->pastMixin(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + + if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) + { + error("can only be a part of an aggregate"); + return; + } + + if (decl) + { + AnonymousAggregateDeclaration aad; + int adisunion; + + if (sc->anonAgg) + { ad = sc->anonAgg; + adisunion = sc->inunion; + } + else + adisunion = ad->isUnionDeclaration() != NULL; + +// printf("\tsc->anonAgg = %p\n", sc->anonAgg); +// printf("\tad = %p\n", ad); +// printf("\taad = %p\n", &aad); + + sc = sc->push(); + sc->anonAgg = &aad; + sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); + sc->inunion = isunion; + sc->offset = 0; + sc->flags = 0; + aad.structalign = sc->structalign; + aad.parent = ad; + + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + if (isunion) + sc->offset = 0; + if (aad.sizeok == 2) + { + break; + } + } + sc = sc->pop(); + + // If failed due to forward references, unwind and try again later + if (aad.sizeok == 2) + { + ad->sizeok = 2; + //printf("\tsetting ad->sizeok %p to 2\n", ad); + if (!sc->anonAgg) + { + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + Module::dprogress = dprogress_save; + //printf("\tforward reference %p\n", this); + return; + } + if (sem == 0) + { Module::dprogress++; + sem = 1; + //printf("\tcompleted %p\n", this); + } + else + ;//printf("\talready completed %p\n", this); + + // 0 sized structs are set to 1 byte + if (aad.structsize == 0) + { + aad.structsize = 1; + aad.alignsize = 1; + } + + // Align size of anonymous aggregate +//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); + ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); + //ad->structsize = sc->offset; +//printf("sc->offset = %d\n", sc->offset); + + // Add members of aad to ad + //printf("\tadding members of aad to '%s'\n", ad->toChars()); + for (unsigned i = 0; i < aad.fields.dim; i++) + { + VarDeclaration *v = (VarDeclaration *)aad.fields.data[i]; + +#if IN_LLVM + v->offset2 = sc->offset; +#endif + v->offset += sc->offset; + +#if IN_LLVM + if (!v->anonDecl) + v->anonDecl = this; +#endif + ad->fields.push(v); + } + + // Add size of aad to ad + if (adisunion) + { + if (aad.structsize > ad->structsize) + ad->structsize = aad.structsize; + sc->offset = 0; + } + else + { + ad->structsize = sc->offset + aad.structsize; + sc->offset = ad->structsize; + } + + if (ad->alignsize < aad.alignsize) + ad->alignsize = aad.alignsize; + } +} + + +void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf(isunion ? "union" : "struct"); + buf->writestring("\n{\n"); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + //buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writestring("}\n"); +} + +const char *AnonDeclaration::kind() +{ + return (isunion ? "anonymous union" : "anonymous struct"); +} + +/********************************* PragmaDeclaration ****************************/ + +static bool parseStringExp(Expression* e, std::string& res) +{ + StringExp *s = NULL; + + e = e->optimize(WANTvalue); + if (e->op == TOKstring && (s = (StringExp *)e)) + { + char* str = (char*)s->string; + res = str; + return true; + } + return false; +} + +PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) + : AttribDeclaration(decl) +{ + this->loc = loc; + this->ident = ident; + this->args = args; +} + +Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); + PragmaDeclaration *pd; + + assert(!s); + pd = new PragmaDeclaration(loc, ident, + Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); + return pd; +} + +void PragmaDeclaration::setScope(Scope *sc) +{ +#if TARGET_NET + if (ident == Lexer::idPool("assembly")) + { + if (!args || args->dim != 1) + { + error("pragma has invalid number of arguments"); + } + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + { + error("string expected, not '%s'", e->toChars()); + } + PragmaScope* pragma = new PragmaScope(this, sc->parent, static_cast(e)); + + assert(sc); + pragma->setScope(sc); + + //add to module members + assert(sc->module); + assert(sc->module->members); + sc->module->members->push(pragma); + } + } +#endif // TARGET_NET +} + +void PragmaDeclaration::semantic(Scope *sc) +{ // Should be merged with PragmaStatement + +#if IN_LLVM + int llvm_internal = 0; + std::string arg1str; +#endif + + //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); + } + else + fprintf(stdmsg, "%s", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + goto Lnodecl; + } + else if (ident == Id::lib) + { + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } + goto Lnodecl; + } +#if IN_GCC + else if (ident == Id::GNU_asm) + { + if (! args || args->dim != 2) + error("identifier and string expected for asm name"); + else + { + Expression *e; + Declaration *d = NULL; + StringExp *s = NULL; + + e = (Expression *)args->data[0]; + e = e->semantic(sc); + if (e->op == TOKvar) + { + d = ((VarExp *)e)->var; + if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) + d = NULL; + } + if (!d) + error("first argument of GNU_asm must be a function or variable declaration"); + + e = (Expression *)args->data[1]; + e = e->semantic(sc); + e = e->optimize(WANTvalue); + if (e->op == TOKstring && ((StringExp *)e)->sz == 1) + s = ((StringExp *)e); + else + error("second argument of GNU_asm must be a char string"); + + if (d && s) + d->c_ident = Lexer::idPool((char*) s->string); + } + goto Lnodecl; + } +#endif +#if DMDV2 + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + } + goto Lnodecl; + } +#endif +#if TARGET_NET + else if (ident == Lexer::idPool("assembly")) + { + } +#endif // TARGET_NET +// LDC +#if IN_LLVM + + // pragma(intrinsic, "string") { funcdecl(s) } + else if (ident == Id::intrinsic) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + llvm_internal = LLVMintrinsic; + } + + // pragma(notypeinfo) { typedecl(s) } + else if (ident == Id::no_typeinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_typeinfo; + } + + // pragma(nomoduleinfo) ; + else if (ident == Id::no_moduleinfo) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMno_moduleinfo; + } + + // pragma(alloca) { funcdecl(s) } + else if (ident == Id::Alloca) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMalloca; + } + + // pragma(va_start) { templdecl(s) } + else if (ident == Id::vastart) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_start; + } + + // pragma(va_copy) { funcdecl(s) } + else if (ident == Id::vacopy) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_copy; + } + + // pragma(va_end) { funcdecl(s) } + else if (ident == Id::vaend) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_end; + } + + // pragma(va_arg) { templdecl(s) } + else if (ident == Id::vaarg) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMva_arg; + } + + // pragma(ldc, "string") { templdecl(s) } + else if (ident == Id::ldc) + { + Expression* expr = (Expression *)args->data[0]; + expr = expr->semantic(sc); + if (!args || args->dim != 1 || !parseStringExp(expr, arg1str)) + { + error("requires exactly 1 string literal parameter"); + fatal(); + } + else if (arg1str == "verbose") + { + sc->module->llvmForceLogging = true; + } + else + { + error("command '%s' invalid", expr->toChars()); + fatal(); + } + } + + // pragma(llvm_inline_asm) { templdecl(s) } + else if (ident == Id::llvm_inline_asm) + { + if (args && args->dim > 0) + { + error("takes no parameters"); + fatal(); + } + llvm_internal = LLVMinline_asm; + } + +#endif // LDC + + else if (ignoreUnsupportedPragmas) + { + if (global.params.verbose) + { + /* Print unrecognized pragmas + */ + printf("pragma %s", ident->toChars()); + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + // ignore errors in ignored pragmas. + global.gag++; + unsigned errors_save = global.errors; + + Expression *e = (Expression *)args->data[i]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (i == 0) + printf(" ("); + else + printf(","); + printf("%s", e->toChars()); + + // restore error state. + global.gag--; + global.errors = errors_save; + } + if (args->dim) + printf(")"); + } + printf("\n"); + } + } + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + s->semantic(sc); + +// LDC +#if IN_LLVM + + if (llvm_internal) + { + if (s->llvmInternal) + { + error("multiple LDC specific pragmas not allowed not affect the same declaration ('%s' at '%s')", s->toChars(), s->loc.toChars()); + fatal(); + } + switch(llvm_internal) + { + case LLVMintrinsic: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + fd->intrinsicName = arg1str; + fd->linkage = LINKintrinsic; + ((TypeFunction*)fd->type)->linkage = LINKintrinsic; + } + else if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + td->llvmInternal = llvm_internal; + td->intrinsicName = arg1str; + } + else + { + error("only allowed on function declarations"); + fatal(); + } + break; + + case LLVMva_start: + case LLVMva_arg: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim != 1) + { + error("the '%s' pragma template must have exactly one template parameter", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + else if (td->overnext || td->overroot) + { + error("the '%s' pragma template must not be overloaded", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMva_copy: + case LLVMva_end: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on function declarations", ident->toChars()); + fatal(); + } + break; + + case LLVMno_typeinfo: + s->llvmInternal = llvm_internal; + break; + + case LLVMalloca: + if (FuncDeclaration* fd = s->isFuncDeclaration()) + { + fd->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma must only be used on function declarations of type 'void* function(uint nbytes)'", ident->toChars()); + fatal(); + } + break; + + case LLVMinline_asm: + if (TemplateDeclaration* td = s->isTemplateDeclaration()) + { + if (td->parameters->dim > 1) + { + error("the '%s' pragma template must have exactly zero or one template parameters", ident->toChars()); + fatal(); + } + else if (!td->onemember) + { + error("the '%s' pragma template must have exactly one member", ident->toChars()); + fatal(); + } + td->llvmInternal = llvm_internal; + } + else + { + error("the '%s' pragma is only allowed on template declarations", ident->toChars()); + fatal(); + } + break; + + default: + warning("the LDC specific pragma '%s' is not yet implemented, ignoring", ident->toChars()); + } + } + +#endif // LDC + + } + } + return; + +Lnodecl: + if (decl) + error("pragma is missing closing ';'"); +} + +int PragmaDeclaration::oneMember(Dsymbol **ps) +{ + *ps = NULL; + return TRUE; +} + +const char *PragmaDeclaration::kind() +{ + return "pragma"; +} + +#if IN_DMD +void PragmaDeclaration::toObjFile(int multiobj) +{ + if (ident == Id::lib) + { + assert(args && args->dim == 1); + + Expression *e = (Expression *)args->data[0]; + + assert(e->op == TOKstring); + + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; +#if OMFOBJ + /* The OMF format allows library names to be inserted + * into the object file. The linker will then automatically + * search that library, too. + */ + obj_includelib(name); +#elif ELFOBJ || MACHOBJ + /* The format does not allow embedded library names, + * so instead append the library name to the list to be passed + * to the linker. + */ + global.params.libfiles->push((void *) name); +#else + error("pragma lib not supported"); +#endif + } +#if DMDV2 + else if (ident == Id::startaddress) + { + assert(args && args->dim == 1); + Expression *e = (Expression *)args->data[0]; + Dsymbol *sa = getDsymbol(e); + FuncDeclaration *f = sa->isFuncDeclaration(); + assert(f); + Symbol *s = f->toSymbol(); + obj_startaddress(s); + } +#endif + AttribDeclaration::toObjFile(multiobj); +} +#endif + +void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("pragma (%s", ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + AttribDeclaration::toCBuffer(buf, hgs); +} + + +/********************************* ConditionalDeclaration ****************************/ + +ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) + : AttribDeclaration(decl) +{ + //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); + this->condition = condition; + this->elsedecl = elsedecl; +} + +Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) +{ + ConditionalDeclaration *dd; + + assert(!s); + dd = new ConditionalDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int ConditionalDeclaration::oneMember(Dsymbol **ps) +{ + //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); + if (condition->inc) + { + Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; + return Dsymbol::oneMembers(d, ps); + } + *ps = NULL; + return TRUE; +} + +void ConditionalDeclaration::emitComment(Scope *sc) +{ + //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); + if (condition->inc) + { + AttribDeclaration::emitComment(sc); + } + else if (sc->docbuf) + { + /* If generating doc comment, be careful because if we're inside + * a template, then include(NULL, NULL) will fail. + */ + Dsymbols *d = decl ? decl : elsedecl; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->emitComment(sc); + } + } +} + +// Decide if 'then' or 'else' code should be included + +Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("ConditionalDeclaration::include()\n"); + assert(condition); + return condition->include(sc, sd) ? decl : elsedecl; +} + +void ConditionalDeclaration::setScope(Scope *sc) +{ + Dsymbols *d = include(sc, NULL); + + //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->setScope(sc); + } + } +} + +void ConditionalDeclaration::importAll(Scope *sc) +{ + Dsymbols *d = include(sc, NULL); + + //printf("\tConditionalDeclaration::importAll '%s', d = %p\n",toChars(), d); + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->importAll(sc); + } + } +} + +void ConditionalDeclaration::addComment(unsigned char *comment) +{ + /* Because addComment is called by the parser, if we called + * include() it would define a version before it was used. + * But it's no problem to drill down to both decl and elsedecl, + * so that's the workaround. + */ + + if (comment) + { + Dsymbols *d = decl; + + for (int j = 0; j < 2; j++) + { + if (d) + { + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)d->data[i]; + //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); + s->addComment(comment); + } + } + d = elsedecl; + } + } +} + +void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + if (decl || elsedecl) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (decl) + { + for (unsigned i = 0; i < decl->dim; i++) + { + Dsymbol *s = (Dsymbol *)decl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + } + buf->writeByte('}'); + if (elsedecl) + { + buf->writenl(); + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (unsigned i = 0; i < elsedecl->dim; i++) + { + Dsymbol *s = (Dsymbol *)elsedecl->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + } + } + else + buf->writeByte(':'); + buf->writenl(); +} + +/***************************** StaticIfDeclaration ****************************/ + +StaticIfDeclaration::StaticIfDeclaration(Condition *condition, + Dsymbols *decl, Dsymbols *elsedecl) + : ConditionalDeclaration(condition, decl, elsedecl) +{ + //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); + sd = NULL; + addisdone = 0; +} + + +Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) +{ + StaticIfDeclaration *dd; + + assert(!s); + dd = new StaticIfDeclaration(condition->syntaxCopy(), + Dsymbol::arraySyntaxCopy(decl), + Dsymbol::arraySyntaxCopy(elsedecl)); + return dd; +} + + +int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); + /* This is deferred until semantic(), so that + * expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + this->sd = sd; + int m = 0; + + if (memnum == 0) + { m = AttribDeclaration::addMember(sc, sd, memnum); + addisdone = 1; + } + return m; +} + + +void StaticIfDeclaration::importAll(Scope *sc) +{ + // do not evaluate condition before semantic pass +} + +void StaticIfDeclaration::setScope(Scope *sc) +{ + // do not evaluate condition before semantic pass +} + +void StaticIfDeclaration::semantic(Scope *sc) +{ + Dsymbols *d = include(sc, sd); + + //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); + if (d) + { + if (!addisdone) + { AttribDeclaration::addMember(sc, sd, 1); + addisdone = 1; + } + + for (unsigned i = 0; i < d->dim; i++) + { + Dsymbol *s = (Dsymbol *)d->data[i]; + + s->semantic(sc); + } + } +} + +const char *StaticIfDeclaration::kind() +{ + return "static if"; +} + + +/***************************** CompileDeclaration *****************************/ + +CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) + : AttribDeclaration(NULL) +{ + //printf("CompileDeclaration(loc = %d)\n", loc.linnum); + this->loc = loc; + this->exp = exp; + this->sd = NULL; + this->compiled = 0; +} + +Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); + CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); + return sc; +} + +int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("CompileDeclaration::addMember(sc = %p, sd = %p, memnum = %d)\n", sc, sd, memnum); + this->sd = sd; + if (memnum == 0) + { /* No members yet, so parse the mixin now + */ + compileIt(sc); + memnum |= AttribDeclaration::addMember(sc, sd, memnum); + compiled = 1; + } + return memnum; +} + +void CompileDeclaration::compileIt(Scope *sc) +{ + //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); + } + else + { + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + decl = p.parseDeclDefs(0); + if (p.token.value != TOKeof) + exp->error("incomplete mixin declaration (%s)", se->toChars()); + } +} + +void CompileDeclaration::semantic(Scope *sc) +{ + //printf("CompileDeclaration::semantic()\n"); + + if (!compiled) + { + compileIt(sc); + AttribDeclaration::addMember(sc, sd, 0); + compiled = 1; + } + AttribDeclaration::semantic(sc); +} + +void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + buf->writenl(); +} diff --git a/dmd2/attrib.h b/dmd2/attrib.h index 16449bb1..2e3bcfe6 100644 --- a/dmd2/attrib.h +++ b/dmd2/attrib.h @@ -1,195 +1,202 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_ATTRIB_H -#define DMD_ATTRIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct Condition; -#ifdef _DH -struct HdrGenState; -#endif - -/**************************************************************/ - -struct AttribDeclaration : Dsymbol -{ - Array *decl; // array of Dsymbol's - - AttribDeclaration(Array *decl); - virtual Array *include(Scope *sc, ScopeDsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void setScopeNewSc(Scope *sc, - unsigned newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); - void semanticNewSc(Scope *sc, - unsigned newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void addComment(unsigned char *comment); - void emitComment(Scope *sc); - const char *kind(); - int oneMember(Dsymbol **ps); - int hasPointers(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - AttribDeclaration *isAttribDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); -#endif - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct StorageClassDeclaration: AttribDeclaration -{ - unsigned stc; - - StorageClassDeclaration(unsigned stc, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void stcToCBuffer(OutBuffer *buf, int stc); -}; - -struct LinkDeclaration : AttribDeclaration -{ - enum LINK linkage; - - LinkDeclaration(enum LINK p, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); -}; - -struct ProtDeclaration : AttribDeclaration -{ - enum PROT protection; - - ProtDeclaration(enum PROT p, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); -}; - -struct AlignDeclaration : AttribDeclaration -{ - unsigned salign; - - AlignDeclaration(Loc loc, unsigned sa, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AnonDeclaration : AttribDeclaration -{ - int isunion; - int sem; // 1 if successful semantic() - - AnonDeclaration(Loc loc, int isunion, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct PragmaDeclaration : AttribDeclaration -{ - Expressions *args; // array of Expression's - - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Array *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setScope(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct ConditionalDeclaration : AttribDeclaration -{ - Condition *condition; - Array *elsedecl; // array of Dsymbol's for else block - - ConditionalDeclaration(Condition *condition, Array *decl, Array *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps); - void emitComment(Scope *sc); - Array *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol *sd; - int addisdone; - - StaticIfDeclaration(Condition *condition, Array *decl, Array *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - const char *kind(); -}; - -// Mixin declarations - -struct CompileDeclaration : AttribDeclaration -{ - Expression *exp; - - ScopeDsymbol *sd; - int compiled; - - CompileDeclaration(Loc loc, Expression *exp); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void compileIt(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif /* DMD_ATTRIB_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_ATTRIB_H +#define DMD_ATTRIB_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +struct Initializer; +struct Module; +struct Condition; +#ifdef _DH +struct HdrGenState; +#endif + +/**************************************************************/ + +struct AttribDeclaration : Dsymbol +{ + Dsymbols *decl; // array of Dsymbol's + + AttribDeclaration(Dsymbols *decl); + virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void setScopeNewSc(Scope *sc, + StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, + unsigned structalign); + void semanticNewSc(Scope *sc, + StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, + unsigned structalign); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + void addComment(unsigned char *comment); + void emitComment(Scope *sc); + const char *kind(); + int oneMember(Dsymbol **ps); + int hasPointers(); + void checkCtorConstInit(); + void addLocalClass(ClassDeclarations *); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + AttribDeclaration *isAttribDeclaration() { return this; } + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + int cvMember(unsigned char *p); +#endif + +#if IN_LLVM + virtual void codegen(Ir*); +#endif +}; + +struct StorageClassDeclaration: AttribDeclaration +{ + StorageClass stc; + + StorageClassDeclaration(StorageClass stc, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + static void stcToCBuffer(OutBuffer *buf, StorageClass stc); +}; + +struct LinkDeclaration : AttribDeclaration +{ + enum LINK linkage; + + LinkDeclaration(enum LINK p, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void semantic3(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + char *toChars(); +}; + +struct ProtDeclaration : AttribDeclaration +{ + enum PROT protection; + + ProtDeclaration(enum PROT p, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void importAll(Scope *sc); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); +}; + +struct AlignDeclaration : AttribDeclaration +{ + unsigned salign; + + AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void setScope(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AnonDeclaration : AttribDeclaration +{ + int isunion; + int sem; // 1 if successful semantic() + + AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); +}; + +struct PragmaDeclaration : AttribDeclaration +{ + Expressions *args; // array of Expression's + + PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void setScope(Scope *sc); + int oneMember(Dsymbol **ps); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +struct ConditionalDeclaration : AttribDeclaration +{ + Condition *condition; + Dsymbols *elsedecl; // array of Dsymbol's for else block + + ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); + Dsymbol *syntaxCopy(Dsymbol *s); + int oneMember(Dsymbol **ps); + void emitComment(Scope *sc); + Dsymbols *include(Scope *sc, ScopeDsymbol *s); + void addComment(unsigned char *comment); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + void importAll(Scope *sc); + void setScope(Scope *sc); +}; + +struct StaticIfDeclaration : ConditionalDeclaration +{ + ScopeDsymbol *sd; + int addisdone; + + StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); + Dsymbol *syntaxCopy(Dsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void semantic(Scope *sc); + void importAll(Scope *sc); + void setScope(Scope *sc); + const char *kind(); +}; + +// Mixin declarations + +struct CompileDeclaration : AttribDeclaration +{ + Expression *exp; + + ScopeDsymbol *sd; + int compiled; + + CompileDeclaration(Loc loc, Expression *exp); + Dsymbol *syntaxCopy(Dsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); + void compileIt(Scope *sc); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#endif /* DMD_ATTRIB_H */ diff --git a/dmd2/backendlicense.txt b/dmd2/backendlicense.txt deleted file mode 100644 index e168b93c..00000000 --- a/dmd2/backendlicense.txt +++ /dev/null @@ -1,42 +0,0 @@ - -The Software is not generally available software. It has not undergone -testing and may contain errors. The Software was not designed to operate -after December 31, 1999. It may be incomplete and it may not function -properly. No support or maintenance is provided with this Software. Do -not install or distribute the Software if -you are not accustomed to using or distributing experimental software. -Do not use this software for life critical applications, or applications -that could cause significant harm or property damage. - -Digital Mars licenses the Software to you on an "AS IS" basis, without -warranty of any kind. DIGITAL MARS AND SYMANTEC HEREBY EXPRESSLY DISCLAIM -ALL WARRANTIES AND CONDITIONS, EITHER EXPRESS OR IMPLIED, INCLUDING, -BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OR CONDITIONS OF MERCHANTABILITY, -NONINFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE. You are solely -responsible for determining the appropriateness of using this Software and -assume all risks associated with the use of this Software, including but not -limited to the risks of program errors, damage -to or loss of data, programs or equipment, unavailability or interruption of -operations and third party claims. You agree to defend, indemnify and hold -Digital Mars and Symantec, its subsidiaries, affiliates, directors, officers, -employees and agents harmless from all claims or demands made against them -(and any related losses, damages, expenses -and costs) arising out of your use of the Software. DIGITAL MARS AND SYMANTEC -WILL NOT BE LIABLE FOR ANY DIRECT DAMAGES OR FOR ANY SPECIAL, INCIDENTAL, OR -INDIRECT DAMAGES OR FOR ANY ECONOMIC CONSEQUENTIAL DAMAGES (INCLUDING -LOST PROFITS OR SAVINGS), EVEN IF DIGITAL MARS OR SYMANTEC HAS BEEN ADVISED -OF THE POSSIBILITY OF SUCH DAMAGES. -Digital Mars and Symantec will not be liable for the loss of, or damage to, -your records or data, the records or -data of any third party, or any damages claimed by you based on a third party -claim. - -If you send any messages to Digital Mars, on either the Digital Mars -newsgroups, the Digital Mars mailing list, or via email, you agree not -to make any claims of intellectual -property rights over the contents of those messages. - -The Software is copyrighted and comes with a single user license, -and may not be redistributed. If you wish to obtain a redistribution license, -please contact Digital Mars. - diff --git a/dmd2/builtin.c b/dmd2/builtin.c index 5f9e2ff6..30cd380b 100644 --- a/dmd2/builtin.c +++ b/dmd2/builtin.c @@ -1,116 +1,127 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#include "mars.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if DMDV2 - -/********************************** - * Determine if function is a builtin one that we can - * evaluate at compile time. - */ -enum BUILTIN FuncDeclaration::isBuiltin() -{ - static const char FeZe[] = "FNaNbeZe"; // pure nothrow real function(real) - - //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); - if (builtin == BUILTINunknown) - { - builtin = BUILTINnot; - if (parent && parent->isModule()) - { - // If it's in the std.math package - if (parent->ident == Id::math && - parent->parent && parent->parent->ident == Id::std && - !parent->parent->parent) - { - //printf("deco = %s\n", type->deco); - if (strcmp(type->deco, FeZe) == 0) - { - if (ident == Id::sin) - builtin = BUILTINsin; - else if (ident == Id::cos) - builtin = BUILTINcos; - else if (ident == Id::tan) - builtin = BUILTINtan; - else if (ident == Id::_sqrt) - builtin = BUILTINsqrt; - else if (ident == Id::fabs) - builtin = BUILTINfabs; - //printf("builtin = %d\n", builtin); - } - // if float or double versions - else if (strcmp(type->deco, "FNaNbdZd") == 0 || - strcmp(type->deco, "FNaNbfZf") == 0) - { - if (ident == Id::_sqrt) - builtin = BUILTINsqrt; - } - } - } - } - return builtin; -} - - -/************************************** - * Evaluate builtin function. - * Return result; NULL if cannot evaluate it. - */ - -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments) -{ - assert(arguments && arguments->dim); - Expression *arg0 = (Expression *)arguments->data[0]; - Expression *e = NULL; - switch (builtin) - { - case BUILTINsin: - if (arg0->op == TOKfloat64) - e = new RealExp(0, sinl(arg0->toReal()), arg0->type); - break; - - case BUILTINcos: - if (arg0->op == TOKfloat64) - e = new RealExp(0, cosl(arg0->toReal()), arg0->type); - break; - - case BUILTINtan: - if (arg0->op == TOKfloat64) - e = new RealExp(0, tanl(arg0->toReal()), arg0->type); - break; - - case BUILTINsqrt: - if (arg0->op == TOKfloat64) - e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type); - break; - - case BUILTINfabs: - if (arg0->op == TOKfloat64) - e = new RealExp(0, fabsl(arg0->toReal()), arg0->type); - break; - } - return e; -} - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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 +#include +#include + +#if __FreeBSD__ +extern "C" +{ + long double sinl(long double); + long double cosl(long double); + long double tanl(long double); + long double sqrtl(long double); +} +#endif + +#include "mars.h" +#include "declaration.h" +#include "attrib.h" +#include "expression.h" +#include "scope.h" +#include "mtype.h" +#include "aggregate.h" +#include "identifier.h" +#include "id.h" +#include "module.h" + +#if DMDV2 + +/********************************** + * Determine if function is a builtin one that we can + * evaluate at compile time. + */ +enum BUILTIN FuncDeclaration::isBuiltin() +{ + static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) + static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) + + //printf("FuncDeclaration::isBuiltin() %s\n", toChars()); + if (builtin == BUILTINunknown) + { + builtin = BUILTINnot; + if (parent && parent->isModule()) + { + // If it's in the std.math package + if (parent->ident == Id::math && + parent->parent && parent->parent->ident == Id::std && + !parent->parent->parent) + { + //printf("deco = %s\n", type->deco); + if (strcmp(type->deco, FeZe) == 0 || strcmp(type->deco, FeZe2) == 0) + { + if (ident == Id::sin) + builtin = BUILTINsin; + else if (ident == Id::cos) + builtin = BUILTINcos; + else if (ident == Id::tan) + builtin = BUILTINtan; + else if (ident == Id::_sqrt) + builtin = BUILTINsqrt; + else if (ident == Id::fabs) + builtin = BUILTINfabs; + //printf("builtin = %d\n", builtin); + } + // if float or double versions + else if (strcmp(type->deco, "FNaNbNfdZd") == 0 || + strcmp(type->deco, "FNaNbNffZf") == 0) + { + if (ident == Id::_sqrt) + builtin = BUILTINsqrt; + } + } + } + } + return builtin; +} + + +/************************************** + * Evaluate builtin function. + * Return result; NULL if cannot evaluate it. + */ + +Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments) +{ + assert(arguments && arguments->dim); + Expression *arg0 = (Expression *)arguments->data[0]; + Expression *e = NULL; + switch (builtin) + { + case BUILTINsin: + if (arg0->op == TOKfloat64) + e = new RealExp(0, sinl(arg0->toReal()), arg0->type); + break; + + case BUILTINcos: + if (arg0->op == TOKfloat64) + e = new RealExp(0, cosl(arg0->toReal()), arg0->type); + break; + + case BUILTINtan: + if (arg0->op == TOKfloat64) + e = new RealExp(0, tanl(arg0->toReal()), arg0->type); + break; + + case BUILTINsqrt: + if (arg0->op == TOKfloat64) + e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type); + break; + + case BUILTINfabs: + if (arg0->op == TOKfloat64) + e = new RealExp(0, fabsl(arg0->toReal()), arg0->type); + break; + } + return e; +} + +#endif diff --git a/dmd2/cast.c b/dmd2/cast.c index 8c9292e4..fb86c241 100644 --- a/dmd2/cast.c +++ b/dmd2/cast.c @@ -1,2109 +1,2175 @@ - -// Copyright (c) 1999-2009 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 -#include - -#include "rmem.h" - -#include "expression.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" - -/* ==================== implicitCast ====================== */ - -/************************************** - * Do an implicit cast. - * Issue error if it can't be done. - */ - -Expression *Expression::implicitCastTo(Scope *sc, Type *t) -{ - //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - - MATCH match = implicitConvTo(t); - if (match) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; -#if DMDV1 - if (global.params.warnings && - Type::impcnvWarn[tyfrom][tyto] && - op != TOKint64) - { - Expression *e = optimize(WANTflags | WANTvalue); - - if (e->op == TOKint64) - return e->implicitCastTo(sc, t); - if (tyfrom == Tint32 && - (op == TOKadd || op == TOKmin || - op == TOKand || op == TOKor || op == TOKxor) - ) - { - /* This is really only a semi-kludge fix, - * we really should look at the operands of op - * and see if they are narrower types. - * For example, b=b|b and b=b|7 and s=b+b should be allowed, - * but b=b|i should be an error. - */ - ; - } - else - { - warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", - toChars(), type->toChars(), t->toChars()); - } - } -#endif -#if DMDV2 - if (match == MATCHconst && t == type->constOf()) - { - Expression *e = copy(); - e->type = t; - return e; - } -#endif - return castTo(sc, t); - } - - Expression *e = optimize(WANTflags | WANTvalue); - if (e != this) - return e->implicitCastTo(sc, t); - -#if 0 -printf("ty = %d\n", type->ty); -print(); -type->print(); -printf("to:\n"); -t->print(); -printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); -//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); -fflush(stdout); -#endif - if (!t->deco) - { /* Can happen with: - * enum E { One } - * class A - * { static void fork(EDG dg) { dg(E.One); } - * alias void delegate(E) EDG; - * } - * Should eventually make it work. - */ - error("forward reference to type %s", t->toChars()); - } - else if (t->reliesOnTident()) - error("forward reference to type %s", t->reliesOnTident()->toChars()); - - error("cannot implicitly convert expression (%s) of type %s to %s", - toChars(), type->toChars(), t->toChars()); - return castTo(sc, t); -} - -Expression *StringExp::implicitCastTo(Scope *sc, Type *t) -{ - //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - unsigned char committed = this->committed; - Expression *e = Expression::implicitCastTo(sc, t); - if (e->op == TOKstring) - { - // Retain polysemous nature if it started out that way - ((StringExp *)e)->committed = committed; - } - return e; -} - -/******************************************* - * Return !=0 if we can implicitly convert this to type t. - * Don't do the actual cast. - */ - -MATCH Expression::implicitConvTo(Type *t) -{ -#if 0 - printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - //static int nest; if (++nest == 10) halt(); - if (!type) - { error("%s is not an expression", toChars()); - type = Type::terror; - } - Expression *e = optimize(WANTvalue | WANTflags); - if (e->type == t) - return MATCHexact; - if (e != this) - { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); - return e->implicitConvTo(t); - } - MATCH match = type->implicitConvTo(t); - if (match != MATCHnomatch) - return match; - - /* See if we can do integral narrowing conversions - */ - if (type->isintegral() && t->isintegral() && - type->isTypeBasic() && t->isTypeBasic()) - { IntRange ir = getIntRange(); - if (ir.imax <= t->sizemask()) - return MATCHconvert; - } - -#if 0 - Type *tb = t->toBasetype(); - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - match = type->implicitConvTo(tf->nextOf()); - if (match) - return match; - if (tf->nextOf()->toBasetype()->ty == Tvoid) - return MATCHconvert; - } - } -#endif - return MATCHnomatch; -} - - -MATCH IntegerExp::implicitConvTo(Type *t) -{ -#if 0 - printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = type->implicitConvTo(t); - if (m >= MATCHconst) - return m; - - TY ty = type->toBasetype()->ty; - TY toty = t->toBasetype()->ty; - - if (m == MATCHnomatch && t->ty == Tenum) - goto Lno; - - switch (ty) - { - case Tbit: - case Tbool: - value &= 1; - ty = Tint32; - break; - - case Tint8: - value = (signed char)value; - ty = Tint32; - break; - - case Tchar: - case Tuns8: - value &= 0xFF; - ty = Tint32; - break; - - case Tint16: - value = (short)value; - ty = Tint32; - break; - - case Tuns16: - case Twchar: - value &= 0xFFFF; - ty = Tint32; - break; - - case Tint32: - value = (int)value; - break; - - case Tuns32: - case Tdchar: - value &= 0xFFFFFFFF; - ty = Tuns32; - break; - - default: - break; - } - - // Only allow conversion if no change in value - switch (toty) - { - case Tbit: - case Tbool: - if ((value & 1) != value) - goto Lno; - goto Lyes; - - case Tint8: - if ((signed char)value != value) - goto Lno; - goto Lyes; - - case Tchar: - case Tuns8: - //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); - if ((unsigned char)value != value) - goto Lno; - goto Lyes; - - case Tint16: - if ((short)value != value) - goto Lno; - goto Lyes; - - case Tuns16: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tint32: - if (ty == Tuns32) - { - } - else if ((int)value != value) - goto Lno; - goto Lyes; - - case Tuns32: - if (ty == Tint32) - { - } - else if ((unsigned)value != value) - goto Lno; - goto Lyes; - - case Tdchar: - if (value > 0x10FFFFUL) - goto Lno; - goto Lyes; - - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tfloat32: - { - volatile float f; - if (type->isunsigned()) - { - f = (float)value; - if (f != value) - goto Lno; - } - else - { - f = (float)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat64: - { - volatile double f; - if (type->isunsigned()) - { - f = (double)value; - if (f != value) - goto Lno; - } - else - { - f = (double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat80: - { - volatile long double f; - if (type->isunsigned()) - { - f = (long double)value; - if (f != value) - goto Lno; - } - else - { - f = (long double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tpointer: -//printf("type = %s\n", type->toBasetype()->toChars()); -//printf("t = %s\n", t->toBasetype()->toChars()); - if (ty == Tpointer && - type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) - { /* Allow things like: - * const char* P = cast(char *)3; - * char* q = P; - */ - goto Lyes; - } - break; - } - return Expression::implicitConvTo(t); - -Lyes: - //printf("MATCHconvert\n"); - return MATCHconvert; - -Lno: - //printf("MATCHnomatch\n"); - return MATCHnomatch; -} - -MATCH NullExp::implicitConvTo(Type *t) -{ -#if 0 - printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", - toChars(), type->toChars(), t->toChars(), committed); -#endif - if (this->type->equals(t)) - return MATCHexact; - - /* Allow implicit conversions from invariant to mutable|const, - * and mutable to invariant. It works because, after all, a null - * doesn't actually point to anything. - */ - if (t->invariantOf()->equals(type->invariantOf())) - return MATCHconst; - - // NULL implicitly converts to any pointer type or dynamic array - if (type->ty == Tpointer && type->nextOf()->ty == Tvoid) - { - if (t->ty == Ttypedef) - t = ((TypeTypedef *)t)->sym->basetype; - if (t->ty == Tpointer || t->ty == Tarray || - t->ty == Taarray || t->ty == Tclass || - t->ty == Tdelegate) - return committed ? MATCHconvert : MATCHexact; - } - return Expression::implicitConvTo(t); -} - -#if DMDV2 -MATCH StructLiteralExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = Expression::implicitConvTo(t); - if (m != MATCHnomatch) - return m; - if (type->ty == t->ty && type->ty == Tstruct && - ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) - { - m = MATCHconst; - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - Type *te = e->type; - if (t->mod == 0) - te = te->mutableOf(); - else - { assert(t->mod == MODinvariant); - te = te->invariantOf(); - } - MATCH m2 = e->implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); - if (m2 < m) - m = m2; - } - } - return m; -} -#endif - -MATCH StringExp::implicitConvTo(Type *t) -{ MATCH m; - -#if 0 - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", - toChars(), committed, type->toChars(), t->toChars()); -#endif - if (!committed) - { - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - return MATCHnomatch; - } - if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) - { - TY tyn = type->nextOf()->ty; - if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) - { Type *tn; - MATCH m; - - switch (t->ty) - { - case Tsarray: - if (type->ty == Tsarray) - { - if (((TypeSArray *)type)->dim->toInteger() != - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - TY tynto = t->nextOf()->ty; - if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) - return MATCHexact; - } - else if (type->ty == Tarray) - { - if (length() > - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - TY tynto = t->nextOf()->ty; - if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) - return MATCHexact; - } - case Tarray: - case Tpointer: - tn = t->nextOf(); - m = MATCHexact; - if (type->nextOf()->mod != tn->mod) - { if (!tn->isConst()) - return MATCHnomatch; - m = MATCHconst; - } - switch (tn->ty) - { - case Tchar: - case Twchar: - case Tdchar: - return m; - } - break; - } - } - } - } - return Expression::implicitConvTo(t); -#if 0 - m = (MATCH)type->implicitConvTo(t); - if (m) - { - return m; - } - - return MATCHnomatch; -#endif -} - -MATCH ArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - -#if 0 - printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - result = MATCHnomatch; - } - - for (int i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - e = (Expression *)values->data[i]; - m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AddrExp::implicitConvTo(Type *t) -{ -#if 0 - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf(), m)) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - result = MATCHexact; - } - } - } - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - t->ty == Tpointer && t->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { - /* I don't think this can ever happen - - * it should have been - * converted to a SymOffExp. - */ - assert(0); - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH SymOffExp::implicitConvTo(Type *t) -{ -#if 0 - printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { f = f->overloadExactMatch(t->nextOf(), m); - if (f) - { if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || - (t->ty == Tpointer && !(f->needThis() || f->isNested()))) - { - result = MATCHexact; - } - } - } - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH DelegateExp::implicitConvTo(Type *t) -{ -#if 0 - printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && - t->ty == Tdelegate && t->nextOf()->ty == Tfunction) - { - if (func && func->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - return result; -} - -MATCH OrExp::implicitConvTo(Type *t) -{ - MATCH result = Expression::implicitConvTo(t); - - if (result == MATCHnomatch) - { - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } - return result; -} - -MATCH XorExp::implicitConvTo(Type *t) -{ - MATCH result = Expression::implicitConvTo(t); - - if (result == MATCHnomatch) - { - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } - return result; -} - -MATCH CondExp::implicitConvTo(Type *t) -{ - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - //printf("CondExp: m1 %d m2 %d\n", m1, m2); - - // Pick the worst match - return (m1 < m2) ? m1 : m2; -} - -MATCH CommaExp::implicitConvTo(Type *t) -{ - return e2->implicitConvTo(t); -} - -MATCH CastExp::implicitConvTo(Type *t) -{ -#if 0 - printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == MATCHnomatch) - { - if (t->isintegral() && - e1->type->isintegral() && - e1->implicitConvTo(t) != MATCHnomatch) - result = MATCHconvert; - else - result = Expression::implicitConvTo(t); - } - return result; -} - -/* ==================== castTo ====================== */ - -/************************************** - * Do an explicit cast. - */ - -Expression *Expression::castTo(Scope *sc, Type *t) -{ - //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); -#if 0 - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Do (type *) cast of (type [dim]) - if (tb->ty == Tpointer && - typeb->ty == Tsarray - ) - { - //printf("Converting [dim] to *\n"); - - if (typeb->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, e); - } -#if 0 - else if (tb->ty == Tdelegate && type->ty != Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - return toDelegate(sc, tf->nextOf()); - } -#endif - else - { - if (typeb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)typeb; - if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) && - ts->sym->aliasthis) - { /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); - Expression *e = new CastExp(loc, e1, tb); - e = e->semantic(sc); - return e; - } - } - else if (typeb->ty == Tclass) - { TypeClass *ts = (TypeClass *)typeb; - if (tb->ty != Tclass && - ts->sym->aliasthis) - { /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); - Expression *e = new CastExp(loc, e1, tb); - e = e->semantic(sc); - return e; - } - } - e = new CastExp(loc, e, tb); - } - } - else - { - e = e->copy(); // because of COW for assignment to e->type - } - assert(e != this); - e->type = t; - //printf("Returning: %s\n", e->toChars()); - return e; -} - - -Expression *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if ((type->isreal() && t->isreal()) || - (type->isimaginary() && t->isimaginary()) - ) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if (type->iscomplex() && t->iscomplex()) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *NullExp::castTo(Scope *sc, Type *t) -{ NullExp *e; - Type *tb; - - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - e = (NullExp *)copy(); - e->committed = 1; - tb = t->toBasetype(); - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { -#if 0 - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } -#endif - } - else - { - return e->Expression::castTo(sc, t); - } - } - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - StringExp *se; - Type *tb; - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - } - - se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (committed && tb->ty == Tsarray && typeb->ty == Tarray) - { - se = (StringExp *)copy(); - se->sz = tb->nextOf()->size(); - se->len = (len * sz) / se->sz; - se->committed = 1; - se->type = t; - return se; - } - - if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - - if (typeb->nextOf()->size() == tb->nextOf()->size()) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - if (tb->ty == Tsarray) - goto L2; // handle possible change in static array dimension - se->type = t; - return se; - } - - if (committed) - goto Lcast; - -#define X(tf,tt) ((tf) * 256 + (tt)) - { - OutBuffer buffer; - size_t newlen = 0; - int tfty = typeb->nextOf()->toBasetype()->ty; - int ttty = tb->nextOf()->toBasetype()->ty; - switch (X(tfty, ttty)) - { - case X(Tchar, Tchar): - case X(Twchar,Twchar): - case X(Tdchar,Tdchar): - break; - - case X(Tchar, Twchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF16(c); - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - case X(Tchar, Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Twchar,Tchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF8(c); - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Twchar,Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar,Tchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar,Twchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->string = buffer.extractData(); - se->len = newlen; - se->sz = tb->nextOf()->size(); - break; - - default: - assert(typeb->nextOf()->size() != tb->nextOf()->size()); - goto Lcast; - } - } -#undef X -L2: - assert(copied); - - // See if need to truncate or extend the literal - if (tb->ty == Tsarray) - { - int dim2 = ((TypeSArray *)tb)->dim->toInteger(); - - //printf("dim from = %d, to = %d\n", se->len, dim2); - - // Changing dimensions - if (dim2 != se->len) - { - // Copy when changing the string literal - unsigned newsz = se->sz; - void *s; - int d; - - d = (dim2 < se->len) ? dim2 : se->len; - s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); - memcpy(s, se->string, d * newsz); - // Extend with 0, add terminating 0 - memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se->string = s; - se->len = dim2; - } - } - se->type = t; - return se; - -Lcast: - Expression *e = new CastExp(loc, se, t); - e->type = t; // so semantic() won't be run on e - return e; -} - -Expression *AddrExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // Look for pointers to functions where the functions are overloaded. - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf(), m)) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } - if (f) - { f->tookAddressOf++; - SymOffExp *se = new SymOffExp(loc, f, 0, 0); - se->semantic(sc); - // Let SymOffExp::castTo() do the heavy lifting - return se->castTo(sc, t); - } - } - - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { - assert(0); // should be SymOffExp instead - f = f->overloadExactMatch(tb->nextOf(), m); - if (f) - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } - } - } - e = Expression::castTo(sc, t); - } - e->type = t; - return e; -} - - -Expression *TupleExp::castTo(Scope *sc, Type *t) -{ TupleExp *e = (TupleExp *)copy(); - e->exps = (Expressions *)exps->copy(); - for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = (Expression *)e->exps->data[i]; - ex = ex->castTo(sc, t); - e->exps->data[i] = (void *)ex; - } - return e; -} - - -Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - ArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray) && - // Not trying to convert non-void[] to void[] - !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (int i = 0; i < elements->dim; i++) - { Expression *ex = (Expression *)elements->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->elements->data[i] = (void *)ex; - } - e->type = t; - return e; - } - if (tb->ty == Tpointer && typeb->ty == Tsarray) - { - Type *tp = typeb->nextOf()->pointerTo(); - if (!tp->equals(e->type)) - { e = (ArrayLiteralExp *)copy(); - e->type = tp; - } - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = (Expression *)values->data[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->data[i] = (void *)ex; - - ex = (Expression *)keys->data[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->data[i] = (void *)ex; - } - e->type = t; - return e; - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *SymOffExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t && hasOverloads == 0) - return this; - Expression *e; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - if (hasOverloads && - typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && - (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->nextOf(), m); - if (f) - { - if (tb->ty == Tdelegate) - { - if (f->needThis() && hasThis(sc)) - { - e = new DelegateExp(loc, new ThisExp(loc), f); - e = e->semantic(sc); - } - else if (f->isNested()) - { - e = new DelegateExp(loc, new IntegerExp(0), f); - e = e->semantic(sc); - } - else if (f->needThis()) - { error("no 'this' to create delegate for %s", f->toChars()); - e = new ErrorExp(); - } - else - { error("cannot cast from function pointer to delegate"); - e = new ErrorExp(); - } - } - else - { - e = new SymOffExp(loc, f, 0); - e->type = t; - } -#if DMDV2 - f->tookAddressOf++; -#endif - return e; - } - } - } - e = Expression::castTo(sc, t); - } - else - { e = copy(); - e->type = t; - ((SymOffExp *)e)->hasOverloads = 0; - } - return e; -} - -Expression *DelegateExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - static char msg[] = "cannot form delegate due to covariant return type"; - - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for delegates to functions where the functions are overloaded. - FuncDeclaration *f; - - if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction && - tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction) - { - if (func) - { - f = func->overloadExactMatch(tb->nextOf(), m); - if (f) - { int offset; - if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) - error("%s", msg); - f->tookAddressOf++; - e = new DelegateExp(loc, e1, f); - e->type = t; - return e; - } - if (func->tintro) - error("%s", msg); - } - } - e = Expression::castTo(sc, t); - } - else - { int offset; - - func->tookAddressOf++; - if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset) - error("%s", msg); - e = copy(); - e->type = t; - } - return e; -} - -Expression *CondExp::castTo(Scope *sc, Type *t) -{ - Expression *e = this; - - if (type != t) - { - if (1 || e1->op == TOKstring || e2->op == TOKstring) - { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - -Expression *CommaExp::castTo(Scope *sc, Type *t) -{ - Expression *e2c = e2->castTo(sc, t); - Expression *e; - - if (e2c != e2) - { - e = new CommaExp(loc, e1, e2c); - e->type = e2c->type; - } - else - { e = this; - e->type = e2->type; - } - return e; -} - -/* ==================== ====================== */ - -/**************************************** - * Scale addition/subtraction to/from pointer. - */ - -Expression *BinExp::scaleFactor(Scope *sc) -{ d_uns64 stride; - Type *t1b = e1->type->toBasetype(); - Type *t2b = e2->type->toBasetype(); - - if (t1b->ty == Tpointer && t2b->isintegral()) - { // Need to adjust operator by the stride - // Replace (ptr + int) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - - stride = t1b->nextOf()->size(loc); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); - e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); - e2->type = t; - type = e1->type; - } - else if (t2b->ty == Tpointer && t1b->isintegral()) - { // Need to adjust operator by the stride - // Replace (int + ptr) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - Expression *e; - - stride = t2b->nextOf()->size(loc); - if (!t->equals(t1b)) - e = e1->castTo(sc, t); - else - e = e1; - e = new MulExp(loc, e, new IntegerExp(0, stride, t)); - e->type = t; - type = e2->type; - e1 = e2; - e2 = e; - } - return this; -} - -/************************************** - * Combine types. - * Output: - * *pt merged type, if *pt is not NULL - * *pe1 rewritten e1 - * *pe2 rewritten e2 - * Returns: - * !=0 success - * 0 failed - */ - -int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2) -{ - //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); - //dump(0); - - Expression *e1 = (*pe1)->integralPromotions(sc); - Expression *e2 = (*pe2)->integralPromotions(sc); - - Type *t1 = e1->type; - Type *t2 = e2->type; - assert(t1); - Type *t = t1; - - //if (t1) printf("\tt1 = %s\n", t1->toChars()); - //if (t2) printf("\tt2 = %s\n", t2->toChars()); -#ifdef DEBUG - if (!t2) printf("\te2 = '%s'\n", e2->toChars()); -#endif - assert(t2); - - Type *t1b = t1->toBasetype(); - Type *t2b = t2->toBasetype(); - - TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; - if (ty != Terror) - { TY ty1; - TY ty2; - - ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; - ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; - - if (t1b->ty == ty1) // if no promotions - { - if (t1 == t2) - { - t = t1; - goto Lret; - } - - if (t1b == t2b) - { - t = t1b; - goto Lret; - } - } - - t = Type::basic[ty]; - - t1 = Type::basic[ty1]; - t2 = Type::basic[ty2]; - e1 = e1->castTo(sc, t1); - e2 = e2->castTo(sc, t2); - //printf("after typeCombine():\n"); - //dump(0); - //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); - goto Lret; - } - - t1 = t1b; - t2 = t2b; - -Lagain: - if (t1 == t2) - { - } - else if (t1->ty == Tpointer && t2->ty == Tpointer) - { - // Bring pointers to compatible type - Type *t1n = t1->nextOf(); - Type *t2n = t2->nextOf(); - - if (t1n == t2n) - ; - else if (t1n->ty == Tvoid) // pointers to void are always compatible - t = t2; - else if (t2n->ty == Tvoid) - ; - else if (t1n->mod != t2n->mod) - { - t1 = t1n->mutableOf()->constOf()->pointerTo(); - t2 = t2n->mutableOf()->constOf()->pointerTo(); - t = t1; - goto Lagain; - } - else if (t1n->ty == Tclass && t2n->ty == Tclass) - { ClassDeclaration *cd1 = t1n->isClassHandle(); - ClassDeclaration *cd2 = t2n->isClassHandle(); - int offset; - - if (cd1->isBaseOf(cd2, &offset)) - { - if (offset) - e2 = e2->castTo(sc, t); - } - else if (cd2->isBaseOf(cd1, &offset)) - { - t = t2; - if (offset) - e1 = e1->castTo(sc, t); - } - else - goto Lincompatible; - } - else - goto Lincompatible; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && - e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid) - { /* (T[n] op void*) - * (T[] op void*) - */ - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid) - { /* (void* op T[n]) - * (void* op T[]) - */ - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) - { - goto Lt1; - } - /* If one is mutable and the other invariant, then retry - * with both of them as const - */ - else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) && - (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && - t1->nextOf()->mod != t2->nextOf()->mod - ) - { - if (t1->ty == Tpointer) - t1 = t1->nextOf()->mutableOf()->constOf()->pointerTo(); - else - t1 = t1->nextOf()->mutableOf()->constOf()->arrayOf(); - - if (t2->ty == Tpointer) - t2 = t2->nextOf()->mutableOf()->constOf()->pointerTo(); - else - t2 = t2->nextOf()->mutableOf()->constOf()->arrayOf(); - t = t1; - goto Lagain; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { - while (1) - { - int i1 = e2->implicitConvTo(t1); - int i2 = e1->implicitConvTo(t2); - - if (i1 && i2) - { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } - - if (i2) - { - goto Lt2; - } - else if (i1) - { - goto Lt1; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { TypeClass *tc1 = (TypeClass *)t1; - TypeClass *tc2 = (TypeClass *)t2; - - /* Pick 'tightest' type - */ - ClassDeclaration *cd1 = tc1->sym->baseClass; - ClassDeclaration *cd2 = tc2->sym->baseClass; - - if (cd1 && cd2) - { t1 = cd1->type; - t2 = cd2->type; - } - else if (cd1) - t1 = cd1->type; - else if (cd2) - t2 = cd2->type; - else - goto Lincompatible; - } - else - goto Lincompatible; - } - } - else if (t1->ty == Tstruct && t2->ty == Tstruct) - { - if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym) - goto Lincompatible; - } - else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e2->implicitConvTo(t1->nextOf()->arrayOf())) - { - Lx1: - t = t1->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->nextOf()->arrayOf())) - { - Lx2: - t = t2->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->isintegral() && t2->isintegral()) - { - assert(0); - } - else if (e1->op == TOKslice && t1->ty == Tarray && - e2->implicitConvTo(t1->nextOf())) - { // T[] op T - e2 = e2->castTo(sc, t1->nextOf()); - t = t1->nextOf()->arrayOf(); - } - else if (e2->op == TOKslice && t2->ty == Tarray && - e1->implicitConvTo(t2->nextOf())) - { // T op T[] - e1 = e1->castTo(sc, t2->nextOf()); - t = t2->nextOf()->arrayOf(); - - //printf("test %s\n", e->toChars()); - e1 = e1->optimize(WANTvalue); - if (e && e->isCommutative() && e1->isConst()) - { /* Swap operands to minimize number of functions generated - */ - //printf("swap %s\n", e->toChars()); - Expression *tmp = e1; - e1 = e2; - e2 = tmp; - } - } - else - { - Lincompatible: - return 0; - } -Lret: - if (!*pt) - *pt = t; - *pe1 = e1; - *pe2 = e2; -#if 0 - printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars()); - if (e1->type) printf("\tt1 = %s\n", e1->type->toChars()); - if (e2->type) printf("\tt2 = %s\n", e2->type->toChars()); - printf("\ttype = %s\n", t->toChars()); -#endif - //dump(0); - return 1; - - -Lt1: - e2 = e2->castTo(sc, t1); - t = t1; - goto Lret; - -Lt2: - e1 = e1->castTo(sc, t2); - t = t2; - goto Lret; -} - -/************************************ - * Bring leaves to common type. - */ - -Expression *BinExp::typeCombine(Scope *sc) -{ - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - if (op == TOKmin || op == TOKadd) - { - if (t1->ty == Tstruct) - { - if (t2->ty == Tstruct && - ((TypeStruct *)t1)->sym == ((TypeStruct *)t2)->sym) - goto Lerror; - } - else if (t1->ty == Tclass) - { - if (t2->ty == Tclass) - goto Lerror; - } - } - - if (!typeMerge(sc, this, &type, &e1, &e2)) - goto Lerror; - return this; - -Lerror: - incompatibleTypes(); - type = Type::terror; - e1 = new ErrorExp(); - e2 = new ErrorExp(); - return this; -} - -/*********************************** - * Do integral promotions (convertchk). - * Don't convert to - */ - -Expression *Expression::integralPromotions(Scope *sc) -{ - Expression *e = this; - - //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - break; - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbit: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - -/*********************************** - * See if both types are arrays that can be compared - * for equality. Return !=0 if so. - * If they are arrays, but incompatible, issue error. - * This is to enable comparing things like an immutable - * array with a mutable one. - */ - -int arrayTypeCompatible(Loc loc, Type *t1, Type *t2) -{ - t1 = t1->toBasetype(); - t2 = t2->toBasetype(); - - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - { - error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars()); - } - return 1; - } - return 0; -} - -/******************************************************************/ - -/* Determine the integral ranges of an expression. - * This is used to determine if implicit narrowing conversions will - * be allowed. - */ - -uinteger_t getMask(uinteger_t v) -{ - uinteger_t u = 0; - if (v >= 0x80) - u = 0xFF; - while (u < v) - u = (u << 1) | 1; - return u; -} - -IntRange Expression::getIntRange() -{ - IntRange ir; - ir.imin = 0; - ir.imax = type->sizemask(); - return ir; -} - -IntRange IntegerExp::getIntRange() -{ - IntRange ir; - ir.imin = value & type->sizemask(); - ir.imax = ir.imin; - return ir; -} - -IntRange CastExp::getIntRange() -{ - IntRange ir; - ir = e1->getIntRange(); - // Do sign extension - switch (e1->type->toBasetype()->ty) - { - case Tint8: - if (ir.imax & 0x80) - ir.imax |= 0xFFFFFFFFFFFFFF00ULL; - break; - case Tint16: - if (ir.imax & 0x8000) - ir.imax |= 0xFFFFFFFFFFFF0000ULL; - break; - case Tint32: - if (ir.imax & 0x80000000) - ir.imax |= 0xFFFFFFFF00000000ULL; - break; - } - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); -//printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); - return ir; -} - -IntRange DivExp::getIntRange() -{ - if (!e1->type->isunsigned() && !e2->type->isunsigned()) - return Expression::getIntRange(); - - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - if (ir2.imax == 0 || ir2.imin == 0) - return Expression::getIntRange(); - - ir.imin = ir1.imin / ir2.imax; - ir.imax = ir1.imax / ir2.imin; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("DivExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange AndExp::getIntRange() -{ - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = ir1.imin; - if (ir2.imin < ir.imin) - ir.imin = ir2.imin; - - ir.imax = ir1.imax; - if (ir2.imax > ir.imax) - ir.imax = ir2.imax; - - uinteger_t u; - - u = getMask(ir1.imax); - ir.imin &= u; - ir.imax &= u; - - u = getMask(ir2.imax); - ir.imin &= u; - ir.imax &= u; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("AndExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange OrExp::getIntRange() -{ - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = ir1.imin; - if (ir2.imin < ir.imin) - ir.imin = ir2.imin; - - ir.imax = ir1.imax; - if (ir2.imax > ir.imax) - ir.imax = ir2.imax; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("OrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange XorExp::getIntRange() -{ - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = ir1.imin; - if (ir2.imin < ir.imin) - ir.imin = ir2.imin; - - ir.imax = ir1.imax; - if (ir2.imax > ir.imax) - ir.imax = ir2.imax; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("XorExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange ShlExp::getIntRange() -{ - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = getMask(ir1.imin) << ir2.imin; - ir.imax = getMask(ir1.imax) << ir2.imax; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("ShlExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange ShrExp::getIntRange() -{ - if (!e1->type->isunsigned()) - return Expression::getIntRange(); - - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = ir1.imin >> ir2.imax; - ir.imax = ir1.imax >> ir2.imin; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("ShrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange UshrExp::getIntRange() -{ - IntRange ir; - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - ir.imin = ir1.imin >> ir2.imax; - ir.imax = ir1.imax >> ir2.imin; - - ir.imin &= type->sizemask(); - ir.imax &= type->sizemask(); - -//printf("UshrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); -//e1->dump(0); - - return ir; -} - -IntRange CommaExp::getIntRange() -{ - return e2->getIntRange(); -} - - + +// Copyright (c) 1999-2010 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 +#include + +#include "rmem.h" + +#include "expression.h" +#include "mtype.h" +#include "utf.h" +#include "declaration.h" +#include "aggregate.h" + +/* ==================== implicitCast ====================== */ + +/************************************** + * Do an implicit cast. + * Issue error if it can't be done. + */ + +Expression *Expression::implicitCastTo(Scope *sc, Type *t) +{ + //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); + + MATCH match = implicitConvTo(t); + if (match) + { TY tyfrom = type->toBasetype()->ty; + TY tyto = t->toBasetype()->ty; +#if DMDV1 + if (global.params.warnings && + Type::impcnvWarn[tyfrom][tyto] && + op != TOKint64) + { + Expression *e = optimize(WANTflags | WANTvalue); + + if (e->op == TOKint64) + return e->implicitCastTo(sc, t); + if (tyfrom == Tint32 && + (op == TOKadd || op == TOKmin || + op == TOKand || op == TOKor || op == TOKxor) + ) + { + /* This is really only a semi-kludge fix, + * we really should look at the operands of op + * and see if they are narrower types. + * For example, b=b|b and b=b|7 and s=b+b should be allowed, + * but b=b|i should be an error. + */ + ; + } + else + { + warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", + toChars(), type->toChars(), t->toChars()); + } + } +#endif +#if DMDV2 + if (match == MATCHconst && t == type->constOf()) + { + Expression *e = copy(); + e->type = t; + return e; + } +#endif + return castTo(sc, t); + } + + Expression *e = optimize(WANTflags | WANTvalue); + if (e != this) + return e->implicitCastTo(sc, t); + +#if 0 +printf("ty = %d\n", type->ty); +print(); +type->print(); +printf("to:\n"); +t->print(); +printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); +//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); +fflush(stdout); +#endif + if (t->ty != Terror && type->ty != Terror) + { + if (!t->deco) + { /* Can happen with: + * enum E { One } + * class A + * { static void fork(EDG dg) { dg(E.One); } + * alias void delegate(E) EDG; + * } + * Should eventually make it work. + */ + error("forward reference to type %s", t->toChars()); + } + else if (t->reliesOnTident()) + error("forward reference to type %s", t->reliesOnTident()->toChars()); + + error("cannot implicitly convert expression (%s) of type %s to %s", + toChars(), type->toChars(), t->toChars()); + } + return new ErrorExp(); +} + +Expression *StringExp::implicitCastTo(Scope *sc, Type *t) +{ + //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); + unsigned char committed = this->committed; + Expression *e = Expression::implicitCastTo(sc, t); + if (e->op == TOKstring) + { + // Retain polysemous nature if it started out that way + ((StringExp *)e)->committed = committed; + } + return e; +} + +Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) +{ + return this; +} + +/******************************************* + * Return !=0 if we can implicitly convert this to type t. + * Don't do the actual cast. + */ + +MATCH Expression::implicitConvTo(Type *t) +{ +#if 0 + printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + //static int nest; if (++nest == 10) halt(); + if (!type) + { error("%s is not an expression", toChars()); + type = Type::terror; + } + Expression *e = optimize(WANTvalue | WANTflags); + if (e->type == t) + return MATCHexact; + if (e != this) + { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); + return e->implicitConvTo(t); + } + MATCH match = type->implicitConvTo(t); + if (match != MATCHnomatch) + return match; + + /* See if we can do integral narrowing conversions + */ + if (type->isintegral() && t->isintegral() && + type->isTypeBasic() && t->isTypeBasic()) + { IntRange ir = getIntRange(); + if (ir.imax <= t->sizemask()) + return MATCHconvert; + } + +#if 0 + Type *tb = t->toBasetype(); + if (tb->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + match = type->implicitConvTo(tf->nextOf()); + if (match) + return match; + if (tf->nextOf()->toBasetype()->ty == Tvoid) + return MATCHconvert; + } + } +#endif + return MATCHnomatch; +} + + +MATCH IntegerExp::implicitConvTo(Type *t) +{ +#if 0 + printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH m = type->implicitConvTo(t); + if (m >= MATCHconst) + return m; + + TY ty = type->toBasetype()->ty; + TY toty = t->toBasetype()->ty; + + if (m == MATCHnomatch && t->ty == Tenum) + goto Lno; + + switch (ty) + { + case Tbit: + case Tbool: + value &= 1; + ty = Tint32; + break; + + case Tint8: + value = (signed char)value; + ty = Tint32; + break; + + case Tchar: + case Tuns8: + value &= 0xFF; + ty = Tint32; + break; + + case Tint16: + value = (short)value; + ty = Tint32; + break; + + case Tuns16: + case Twchar: + value &= 0xFFFF; + ty = Tint32; + break; + + case Tint32: + value = (int)value; + break; + + case Tuns32: + case Tdchar: + value &= 0xFFFFFFFF; + ty = Tuns32; + break; + + default: + break; + } + + // Only allow conversion if no change in value + switch (toty) + { + case Tbit: + case Tbool: + if ((value & 1) != value) + goto Lno; + goto Lyes; + + case Tint8: + if ((signed char)value != value) + goto Lno; + goto Lyes; + + case Tchar: + case Tuns8: + //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); + if ((unsigned char)value != value) + goto Lno; + goto Lyes; + + case Tint16: + if ((short)value != value) + goto Lno; + goto Lyes; + + case Tuns16: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tint32: + if (ty == Tuns32) + { + } + else if ((int)value != value) + goto Lno; + goto Lyes; + + case Tuns32: + if (ty == Tint32) + { + } + else if ((unsigned)value != value) + goto Lno; + goto Lyes; + + case Tdchar: + if (value > 0x10FFFFUL) + goto Lno; + goto Lyes; + + case Twchar: + if ((unsigned short)value != value) + goto Lno; + goto Lyes; + + case Tfloat32: + { + volatile float f; + if (type->isunsigned()) + { + f = (float)value; + if (f != value) + goto Lno; + } + else + { + f = (float)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat64: + { + volatile double f; + if (type->isunsigned()) + { + f = (double)value; + if (f != value) + goto Lno; + } + else + { + f = (double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tfloat80: + { + volatile long double f; + if (type->isunsigned()) + { + f = (long double)value; + if (f != value) + goto Lno; + } + else + { + f = (long double)(long long)value; + if (f != (long long)value) + goto Lno; + } + goto Lyes; + } + + case Tpointer: +//printf("type = %s\n", type->toBasetype()->toChars()); +//printf("t = %s\n", t->toBasetype()->toChars()); + if (ty == Tpointer && + type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) + { /* Allow things like: + * const char* P = cast(char *)3; + * char* q = P; + */ + goto Lyes; + } + break; + } + return Expression::implicitConvTo(t); + +Lyes: + //printf("MATCHconvert\n"); + return MATCHconvert; + +Lno: + //printf("MATCHnomatch\n"); + return MATCHnomatch; +} + +MATCH NullExp::implicitConvTo(Type *t) +{ +#if 0 + printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", + toChars(), type->toChars(), t->toChars(), committed); +#endif + if (this->type->equals(t)) + return MATCHexact; + + /* Allow implicit conversions from invariant to mutable|const, + * and mutable to invariant. It works because, after all, a null + * doesn't actually point to anything. + */ + if (t->invariantOf()->equals(type->invariantOf())) + return MATCHconst; + + // NULL implicitly converts to any pointer type or dynamic array + if (type->ty == Tpointer && type->nextOf()->ty == Tvoid) + { + if (t->ty == Ttypedef) + t = ((TypeTypedef *)t)->sym->basetype; + if (t->ty == Tpointer || t->ty == Tarray || + t->ty == Taarray || t->ty == Tclass || + t->ty == Tdelegate) + return committed ? MATCHconvert : MATCHexact; + } + return Expression::implicitConvTo(t); +} + +#if DMDV2 +MATCH StructLiteralExp::implicitConvTo(Type *t) +{ +#if 0 + printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH m = Expression::implicitConvTo(t); + if (m != MATCHnomatch) + return m; + if (type->ty == t->ty && type->ty == Tstruct && + ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) + { + m = MATCHconst; + for (int i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + Type *te = e->type; + if (t->mod == 0) + te = te->mutableOf(); + else + { assert(t->mod == MODimmutable); + te = te->invariantOf(); + } + MATCH m2 = e->implicitConvTo(te); + //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); + if (m2 < m) + m = m2; + } + } + return m; +} +#endif + +MATCH StringExp::implicitConvTo(Type *t) +{ MATCH m; + +#if 0 + printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", + toChars(), committed, type->toChars(), t->toChars()); +#endif + if (!committed) + { + if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) + { + return MATCHnomatch; + } + if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) + { + TY tyn = type->nextOf()->ty; + if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) + { Type *tn; + MATCH m; + + switch (t->ty) + { + case Tsarray: + if (type->ty == Tsarray) + { + if (((TypeSArray *)type)->dim->toInteger() != + ((TypeSArray *)t)->dim->toInteger()) + return MATCHnomatch; + TY tynto = t->nextOf()->ty; + if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) + return MATCHexact; + } + else if (type->ty == Tarray) + { + if (length() > + ((TypeSArray *)t)->dim->toInteger()) + return MATCHnomatch; + TY tynto = t->nextOf()->ty; + if (tynto == Tchar || tynto == Twchar || tynto == Tdchar) + return MATCHexact; + } + case Tarray: + case Tpointer: + tn = t->nextOf(); + m = MATCHexact; + if (type->nextOf()->mod != tn->mod) + { if (!tn->isConst()) + return MATCHnomatch; + m = MATCHconst; + } + switch (tn->ty) + { + case Tchar: + case Twchar: + case Tdchar: + return m; + } + break; + } + } + } + } + return Expression::implicitConvTo(t); +#if 0 + m = (MATCH)type->implicitConvTo(t); + if (m) + { + return m; + } + + return MATCHnomatch; +#endif +} + +MATCH ArrayLiteralExp::implicitConvTo(Type *t) +{ MATCH result = MATCHexact; + +#if 0 + printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + result = MATCHnomatch; + } + + for (int i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression::implicitConvTo(t); +} + +MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) +{ MATCH result = MATCHexact; + + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray) + { + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (Expression *)keys->data[i]; + MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + e = (Expression *)values->data[i]; + m = (MATCH)e->implicitConvTo(tb->nextOf()); + if (m < result) + result = m; // remember worst match + if (result == MATCHnomatch) + break; // no need to check for worse + } + return result; + } + else + return Expression::implicitConvTo(t); +} + +MATCH AddrExp::implicitConvTo(Type *t) +{ +#if 0 + printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + + t = t->toBasetype(); + + if (e1->op == TOKoverloadset && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + assert(f2); + if (f2->overloadExactMatch(t->nextOf(), m)) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + result = MATCHexact; + } + } + } + + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + t->ty == Tpointer && t->nextOf()->ty == Tfunction && + e1->op == TOKvar) + { + /* I don't think this can ever happen - + * it should have been + * converted to a SymOffExp. + */ + assert(0); + VarExp *ve = (VarExp *)e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f && f->overloadExactMatch(t->nextOf(), m)) + result = MATCHexact; + } + } + //printf("\tresult = %d\n", result); + return result; +} + +MATCH SymOffExp::implicitConvTo(Type *t) +{ +#if 0 + printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + //printf("\tresult = %d\n", result); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + t = t->toBasetype(); + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { + f = var->isFuncDeclaration(); + if (f) + { f = f->overloadExactMatch(t->nextOf(), m); + if (f) + { if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || + (t->ty == Tpointer && !(f->needThis() || f->isNested()))) + { + result = MATCHexact; + } + } + } + } + } + //printf("\tresult = %d\n", result); + return result; +} + +MATCH DelegateExp::implicitConvTo(Type *t) +{ +#if 0 + printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + t = t->toBasetype(); + if (type->ty == Tdelegate && type->nextOf()->ty == Tfunction && + t->ty == Tdelegate && t->nextOf()->ty == Tfunction) + { + if (func && func->overloadExactMatch(t->nextOf(), m)) + result = MATCHexact; + } + } + return result; +} + +MATCH OrExp::implicitConvTo(Type *t) +{ + MATCH result = Expression::implicitConvTo(t); + + if (result == MATCHnomatch) + { + MATCH m1 = e1->implicitConvTo(t); + MATCH m2 = e2->implicitConvTo(t); + + // Pick the worst match + result = (m1 < m2) ? m1 : m2; + } + return result; +} + +MATCH XorExp::implicitConvTo(Type *t) +{ + MATCH result = Expression::implicitConvTo(t); + + if (result == MATCHnomatch) + { + MATCH m1 = e1->implicitConvTo(t); + MATCH m2 = e2->implicitConvTo(t); + + // Pick the worst match + result = (m1 < m2) ? m1 : m2; + } + return result; +} + +MATCH CondExp::implicitConvTo(Type *t) +{ + MATCH m1 = e1->implicitConvTo(t); + MATCH m2 = e2->implicitConvTo(t); + //printf("CondExp: m1 %d m2 %d\n", m1, m2); + + // Pick the worst match + return (m1 < m2) ? m1 : m2; +} + +MATCH CommaExp::implicitConvTo(Type *t) +{ + return e2->implicitConvTo(t); +} + +MATCH CastExp::implicitConvTo(Type *t) +{ +#if 0 + printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + MATCH result; + + result = type->implicitConvTo(t); + + if (result == MATCHnomatch) + { + if (t->isintegral() && + e1->type->isintegral() && + e1->implicitConvTo(t) != MATCHnomatch) + result = MATCHconvert; + else + result = Expression::implicitConvTo(t); + } + return result; +} + +/* ==================== castTo ====================== */ + +/************************************** + * Do an explicit cast. + */ + +Expression *Expression::castTo(Scope *sc, Type *t) +{ + //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); +#if 0 + printf("Expression::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t) + return this; + Expression *e = this; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Do (type *) cast of (type [dim]) + if (tb->ty == Tpointer && + typeb->ty == Tsarray + ) + { + //printf("Converting [dim] to *\n"); + + if (typeb->size(loc) == 0) + e = new NullExp(loc); + else + e = new AddrExp(loc, e); + } +#if 0 + else if (tb->ty == Tdelegate && type->ty != Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + return toDelegate(sc, tf->nextOf()); + } +#endif + else + { + if (typeb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)typeb; + if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) && + ts->sym->aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e = new CastExp(loc, e1, tb); + e = e->semantic(sc); + return e; + } + } + else if (typeb->ty == Tclass) + { TypeClass *ts = (TypeClass *)typeb; + if (tb->ty != Tclass && + ts->sym->aliasthis) + { /* Forward the cast to our alias this member, rewrite to: + * cast(to)e1.aliasthis + */ + Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); + Expression *e = new CastExp(loc, e1, tb); + e = e->semantic(sc); + return e; + } + } + e = new CastExp(loc, e, tb); + } + } + else + { + e = e->copy(); // because of COW for assignment to e->type + } + assert(e != this); + e->type = t; + //printf("Returning: %s\n", e->toChars()); + return e; +} + + +Expression *RealExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if ((type->isreal() && t->isreal()) || + (type->isimaginary() && t->isimaginary()) + ) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *ComplexExp::castTo(Scope *sc, Type *t) +{ Expression *e = this; + if (type != t) + { + if (type->iscomplex() && t->iscomplex()) + { e = copy(); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + + +Expression *NullExp::castTo(Scope *sc, Type *t) +{ NullExp *e; + Type *tb; + + //printf("NullExp::castTo(t = %p)\n", t); + if (type == t) + { + committed = 1; + return this; + } + e = (NullExp *)copy(); + e->committed = 1; + tb = t->toBasetype(); + e->type = type->toBasetype(); + if (tb != e->type) + { + // NULL implicitly converts to any pointer type or dynamic array + if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && + (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || + tb->ty == Tdelegate)) + { +#if 0 + if (tb->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)tb; + TypeFunction *tf = (TypeFunction *)td->nextOf(); + + if (!tf->varargs && + !(tf->arguments && tf->arguments->dim) + ) + { + return Expression::castTo(sc, t); + } + } +#endif + } + else + { + return e->Expression::castTo(sc, t); + } + } + e->type = t; + return e; +} + +Expression *StringExp::castTo(Scope *sc, Type *t) +{ + /* This follows copy-on-write; any changes to 'this' + * will result in a copy. + * The this->string member is considered immutable. + */ + int copied = 0; + + //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); + + if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) + { + error("cannot convert string literal to void*"); + return new ErrorExp(); + } + + StringExp *se = this; + if (!committed) + { se = (StringExp *)copy(); + se->committed = 1; + copied = 1; + } + + if (type == t) + { + return se; + } + + Type *tb = t->toBasetype(); + //printf("\ttype = %s\n", type->toChars()); + if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) + return Expression::castTo(sc, t); + + Type *typeb = type->toBasetype(); + if (typeb == tb) + { + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->type = t; + return se; + } + + if (committed && tb->ty == Tsarray && typeb->ty == Tarray) + { + se = (StringExp *)copy(); + se->sz = tb->nextOf()->size(); + se->len = (len * sz) / se->sz; + se->committed = 1; + se->type = t; + return se; + } + + if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) + { if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + goto Lcast; + } + if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) + { if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + goto Lcast; + } + + if (typeb->nextOf()->size() == tb->nextOf()->size()) + { + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + if (tb->ty == Tsarray) + goto L2; // handle possible change in static array dimension + se->type = t; + return se; + } + + if (committed) + goto Lcast; + +#define X(tf,tt) ((tf) * 256 + (tt)) + { + OutBuffer buffer; + size_t newlen = 0; + int tfty = typeb->nextOf()->toBasetype()->ty; + int ttty = tb->nextOf()->toBasetype()->ty; + switch (X(tfty, ttty)) + { + case X(Tchar, Tchar): + case X(Twchar,Twchar): + case X(Tdchar,Tdchar): + break; + + case X(Tchar, Twchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + if (p) + error("%s", p); + else + buffer.writeUTF16(c); + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + case X(Tchar, Tdchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(Twchar,Tchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); + if (p) + error("%s", p); + else + buffer.writeUTF8(c); + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(Twchar,Tdchar): + for (size_t u = 0; u < len;) + { unsigned c; + const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); + if (p) + error("%s", p); + buffer.write4(c); + newlen++; + } + buffer.write4(0); + goto L1; + + case X(Tdchar,Tchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF8(c); + newlen++; + } + newlen = buffer.offset; + buffer.writeUTF8(0); + goto L1; + + case X(Tdchar,Twchar): + for (size_t u = 0; u < len; u++) + { + unsigned c = ((unsigned *)se->string)[u]; + if (!utf_isValidDchar(c)) + error("invalid UCS-32 char \\U%08x", c); + else + buffer.writeUTF16(c); + newlen++; + } + newlen = buffer.offset / 2; + buffer.writeUTF16(0); + goto L1; + + L1: + if (!copied) + { se = (StringExp *)copy(); + copied = 1; + } + se->string = buffer.extractData(); + se->len = newlen; + se->sz = tb->nextOf()->size(); + break; + + default: + assert(typeb->nextOf()->size() != tb->nextOf()->size()); + goto Lcast; + } + } +#undef X +L2: + assert(copied); + + // See if need to truncate or extend the literal + if (tb->ty == Tsarray) + { + int dim2 = ((TypeSArray *)tb)->dim->toInteger(); + + //printf("dim from = %d, to = %d\n", se->len, dim2); + + // Changing dimensions + if (dim2 != se->len) + { + // Copy when changing the string literal + unsigned newsz = se->sz; + void *s; + int d; + + d = (dim2 < se->len) ? dim2 : se->len; + s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); + memcpy(s, se->string, d * newsz); + // Extend with 0, add terminating 0 + memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); + se->string = s; + se->len = dim2; + } + } + se->type = t; + return se; + +Lcast: + Expression *e = new CastExp(loc, se, t); + e->type = t; // so semantic() won't be run on e + return e; +} + +Expression *AddrExp::castTo(Scope *sc, Type *t) +{ + Type *tb; + +#if 0 + printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + Expression *e = this; + + tb = t->toBasetype(); + type = type->toBasetype(); + if (tb != type) + { + // Look for pointers to functions where the functions are overloaded. + + if (e1->op == TOKoverloadset && + (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) + { OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + assert(f2); + if (f2->overloadExactMatch(t->nextOf(), m)) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + } + } + if (f) + { f->tookAddressOf++; + SymOffExp *se = new SymOffExp(loc, f, 0, 0); + se->semantic(sc); + // Let SymOffExp::castTo() do the heavy lifting + return se->castTo(sc, t); + } + } + + + if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && + tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && + e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { + assert(0); // should be SymOffExp instead + f = f->overloadExactMatch(tb->nextOf(), m); + if (f) + { + e = new VarExp(loc, f); + e->type = f->type; + e = new AddrExp(loc, e); + e->type = t; + return e; + } + } + } + e = Expression::castTo(sc, t); + } + e->type = t; + return e; +} + + +Expression *TupleExp::castTo(Scope *sc, Type *t) +{ TupleExp *e = (TupleExp *)copy(); + e->exps = (Expressions *)exps->copy(); + for (size_t i = 0; i < e->exps->dim; i++) + { Expression *ex = (Expression *)e->exps->data[i]; + ex = ex->castTo(sc, t); + e->exps->data[i] = (void *)ex; + } + return e; +} + + +Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t) + return this; + ArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if ((tb->ty == Tarray || tb->ty == Tsarray) && + (typeb->ty == Tarray || typeb->ty == Tsarray) && + // Not trying to convert non-void[] to void[] + !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) + { + if (tb->ty == Tsarray) + { TypeSArray *tsa = (TypeSArray *)tb; + if (elements->dim != tsa->dim->toInteger()) + goto L1; + } + + e = (ArrayLiteralExp *)copy(); + e->elements = (Expressions *)elements->copy(); + for (int i = 0; i < elements->dim; i++) + { Expression *ex = (Expression *)elements->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->elements->data[i] = (void *)ex; + } + e->type = t; + return e; + } + if (tb->ty == Tpointer && typeb->ty == Tsarray) + { + Type *tp = typeb->nextOf()->pointerTo(); + if (!tp->equals(e->type)) + { e = (ArrayLiteralExp *)copy(); + e->type = tp; + } + } +L1: + return e->Expression::castTo(sc, t); +} + +Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) +{ + if (type == t) + return this; + AssocArrayLiteralExp *e = this; + Type *typeb = type->toBasetype(); + Type *tb = t->toBasetype(); + if (tb->ty == Taarray && typeb->ty == Taarray && + tb->nextOf()->toBasetype()->ty != Tvoid) + { + e = (AssocArrayLiteralExp *)copy(); + e->keys = (Expressions *)keys->copy(); + e->values = (Expressions *)values->copy(); + assert(keys->dim == values->dim); + for (size_t i = 0; i < keys->dim; i++) + { Expression *ex = (Expression *)values->data[i]; + ex = ex->castTo(sc, tb->nextOf()); + e->values->data[i] = (void *)ex; + + ex = (Expression *)keys->data[i]; + ex = ex->castTo(sc, ((TypeAArray *)tb)->index); + e->keys->data[i] = (void *)ex; + } + e->type = t; + return e; + } +L1: + return e->Expression::castTo(sc, t); +} + +Expression *SymOffExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + if (type == t && hasOverloads == 0) + return this; + Expression *e; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration *f; + + if (hasOverloads && + typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && + (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) + { + f = var->isFuncDeclaration(); + if (f) + { + f = f->overloadExactMatch(tb->nextOf(), m); + if (f) + { + if (tb->ty == Tdelegate) + { + if (f->needThis() && hasThis(sc)) + { + e = new DelegateExp(loc, new ThisExp(loc), f); + e = e->semantic(sc); + } + else if (f->isNested()) + { + e = new DelegateExp(loc, new IntegerExp(0), f); + e = e->semantic(sc); + } + else if (f->needThis()) + { error("no 'this' to create delegate for %s", f->toChars()); + return new ErrorExp(); + } + else + { error("cannot cast from function pointer to delegate"); + return new ErrorExp(); + } + } + else + { + e = new SymOffExp(loc, f, 0); + e->type = t; + } +#if DMDV2 + f->tookAddressOf++; +#endif + return e; + } + } + } + e = Expression::castTo(sc, t); + } + else + { e = copy(); + e->type = t; + ((SymOffExp *)e)->hasOverloads = 0; + } + return e; +} + +Expression *DelegateExp::castTo(Scope *sc, Type *t) +{ +#if 0 + printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", + toChars(), type->toChars(), t->toChars()); +#endif + static char msg[] = "cannot form delegate due to covariant return type"; + + Expression *e = this; + Type *tb = t->toBasetype(); + Type *typeb = type->toBasetype(); + if (tb != typeb) + { + // Look for delegates to functions where the functions are overloaded. + FuncDeclaration *f; + + if (typeb->ty == Tdelegate && typeb->nextOf()->ty == Tfunction && + tb->ty == Tdelegate && tb->nextOf()->ty == Tfunction) + { + if (func) + { + f = func->overloadExactMatch(tb->nextOf(), m); + if (f) + { int offset; + if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) + error("%s", msg); + f->tookAddressOf++; + e = new DelegateExp(loc, e1, f); + e->type = t; + return e; + } + if (func->tintro) + error("%s", msg); + } + } + e = Expression::castTo(sc, t); + } + else + { int offset; + + func->tookAddressOf++; + if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset) + error("%s", msg); + e = copy(); + e->type = t; + } + return e; +} + +Expression *CondExp::castTo(Scope *sc, Type *t) +{ + Expression *e = this; + + if (type != t) + { + if (1 || e1->op == TOKstring || e2->op == TOKstring) + { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); + e->type = t; + } + else + e = Expression::castTo(sc, t); + } + return e; +} + +Expression *CommaExp::castTo(Scope *sc, Type *t) +{ + Expression *e2c = e2->castTo(sc, t); + Expression *e; + + if (e2c != e2) + { + e = new CommaExp(loc, e1, e2c); + e->type = e2c->type; + } + else + { e = this; + e->type = e2->type; + } + return e; +} + +/* ==================== ====================== */ + +/**************************************** + * Scale addition/subtraction to/from pointer. + */ + +Expression *BinExp::scaleFactor(Scope *sc) +{ d_uns64 stride; + Type *t1b = e1->type->toBasetype(); + Type *t2b = e2->type->toBasetype(); + + if (t1b->ty == Tpointer && t2b->isintegral()) + { // Need to adjust operator by the stride + // Replace (ptr + int) with (ptr + (int * stride)) + Type *t = Type::tptrdiff_t; + + stride = t1b->nextOf()->size(loc); + if (!t->equals(t2b)) + e2 = e2->castTo(sc, t); + e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); + e2->type = t; + type = e1->type; + } + else if (t2b->ty == Tpointer && t1b->isintegral()) + { // Need to adjust operator by the stride + // Replace (int + ptr) with (ptr + (int * stride)) + Type *t = Type::tptrdiff_t; + Expression *e; + + stride = t2b->nextOf()->size(loc); + if (!t->equals(t1b)) + e = e1->castTo(sc, t); + else + e = e1; + e = new MulExp(loc, e, new IntegerExp(0, stride, t)); + e->type = t; + type = e2->type; + e1 = e2; + e2 = e; + } + return this; +} + +/************************************** + * Return true if e is an empty array literal with dimensionality + * equal to or less than type of other array. + * [], [[]], [[[]]], etc. + * I.e., make sure that [1,2] is compatible with [], + * [[1,2]] is compatible with [[]], etc. + */ +bool isVoidArrayLiteral(Expression *e, Type *other) +{ + while (e->op == TOKarrayliteral && e->type->ty == Tarray + && (((ArrayLiteralExp *)e)->elements->dim == 1)) + { + e = (Expression *)((ArrayLiteralExp *)e)->elements->data[0]; + if (other->ty == Tsarray || other->ty == Tarray) + other = other->nextOf(); + else + return false; + } + if (other->ty != Tsarray && other->ty != Tarray) + return false; + Type *t = e->type; + return (e->op == TOKarrayliteral && t->ty == Tarray && + t->nextOf()->ty == Tvoid && + ((ArrayLiteralExp *)e)->elements->dim == 0); +} + + +/************************************** + * Combine types. + * Output: + * *pt merged type, if *pt is not NULL + * *pe1 rewritten e1 + * *pe2 rewritten e2 + * Returns: + * !=0 success + * 0 failed + */ + +int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2) +{ + //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); + //dump(0); + + Expression *e1 = (*pe1)->integralPromotions(sc); + Expression *e2 = (*pe2)->integralPromotions(sc); + + Type *t1 = e1->type; + Type *t2 = e2->type; + assert(t1); + Type *t = t1; + + //if (t1) printf("\tt1 = %s\n", t1->toChars()); + //if (t2) printf("\tt2 = %s\n", t2->toChars()); +#ifdef DEBUG + if (!t2) printf("\te2 = '%s'\n", e2->toChars()); +#endif + assert(t2); + + Type *t1b = t1->toBasetype(); + Type *t2b = t2->toBasetype(); + + TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; + if (ty != Terror) + { + TY ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; + TY ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; + + if (t1b->ty == ty1) // if no promotions + { + if (t1 == t2) + { + t = t1; + goto Lret; + } + + if (t1b == t2b) + { + t = t1b; + goto Lret; + } + } + + t = Type::basic[ty]; + + t1 = Type::basic[ty1]; + t2 = Type::basic[ty2]; + e1 = e1->castTo(sc, t1); + e2 = e2->castTo(sc, t2); + //printf("after typeCombine():\n"); + //dump(0); + //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); + goto Lret; + } + + t1 = t1b; + t2 = t2b; + +Lagain: + if (t1 == t2) + { + } + else if (t1->ty == Tpointer && t2->ty == Tpointer) + { + // Bring pointers to compatible type + Type *t1n = t1->nextOf(); + Type *t2n = t2->nextOf(); + + if (t1n == t2n) + ; + else if (t1n->ty == Tvoid) // pointers to void are always compatible + t = t2; + else if (t2n->ty == Tvoid) + ; + else if (t1n->mod != t2n->mod) + { + t1 = t1n->mutableOf()->constOf()->pointerTo(); + t2 = t2n->mutableOf()->constOf()->pointerTo(); + t = t1; + goto Lagain; + } + else if (t1n->ty == Tclass && t2n->ty == Tclass) + { ClassDeclaration *cd1 = t1n->isClassHandle(); + ClassDeclaration *cd2 = t2n->isClassHandle(); + int offset; + + if (cd1->isBaseOf(cd2, &offset)) + { + if (offset) + e2 = e2->castTo(sc, t); + } + else if (cd2->isBaseOf(cd1, &offset)) + { + t = t2; + if (offset) + e1 = e1->castTo(sc, t); + } + else + goto Lincompatible; + } + else + goto Lincompatible; + } + else if ((t1->ty == Tsarray || t1->ty == Tarray) && + (e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid || + // if e2 is void[] + e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0 || + isVoidArrayLiteral(e2, t1)) + ) + { /* (T[n] op void*) => T[] + * (T[] op void*) => T[] + * (T[n] op void[0]) => T[] + * (T[] op void[0]) => T[] + * (T[n] op void[]) => T[] + * (T[] op void[]) => T[] + */ + goto Lx1; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && + (e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid || + e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0 || + isVoidArrayLiteral(e1, t2)) + ) + { /* (void* op T[n]) => T[] + * (void* op T[]) => T[] + * (void[0] op T[n]) => T[] + * (void[0] op T[]) => T[] + * (void[] op T[n]) => T[] + * (void[] op T[]) => T[] + */ + goto Lx2; + } + else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) + { + goto Lt2; + } + else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) + { + goto Lt1; + } + /* If one is mutable and the other invariant, then retry + * with both of them as const + */ + else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) && + (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && + t1->nextOf()->mod != t2->nextOf()->mod + ) + { unsigned char mod = MODmerge(t1->nextOf()->mod, t2->nextOf()->mod); + + if (t1->ty == Tpointer) + t1 = t1->nextOf()->castMod(mod)->pointerTo(); + else + t1 = t1->nextOf()->castMod(mod)->arrayOf(); + + if (t2->ty == Tpointer) + t2 = t2->nextOf()->castMod(mod)->pointerTo(); + else + t2 = t2->nextOf()->castMod(mod)->arrayOf(); + t = t1; + goto Lagain; + } + else if (t1->ty == Tclass || t2->ty == Tclass) + { + if (t1->mod != t2->mod) + { unsigned char mod = MODmerge(t1->mod, t2->mod); + t1 = t1->castMod(mod); + t2 = t2->castMod(mod); + t = t1; + goto Lagain; + } + + while (1) + { + int i1 = e2->implicitConvTo(t1); + int i2 = e1->implicitConvTo(t2); + + if (i1 && i2) + { + // We have the case of class vs. void*, so pick class + if (t1->ty == Tpointer) + i1 = 0; + else if (t2->ty == Tpointer) + i2 = 0; + } + + if (i2) + { + goto Lt2; + } + else if (i1) + { + goto Lt1; + } + else if (t1->ty == Tclass && t2->ty == Tclass) + { TypeClass *tc1 = (TypeClass *)t1; + TypeClass *tc2 = (TypeClass *)t2; + + /* Pick 'tightest' type + */ + ClassDeclaration *cd1 = tc1->sym->baseClass; + ClassDeclaration *cd2 = tc2->sym->baseClass; + + if (cd1 && cd2) + { t1 = cd1->type; + t2 = cd2->type; + } + else if (cd1) + t1 = cd1->type; + else if (cd2) + t2 = cd2->type; + else + goto Lincompatible; + } + else + goto Lincompatible; + } + } + else if (t1->ty == Tstruct && t2->ty == Tstruct) + { + if (((TypeStruct *)t1)->sym != ((TypeStruct *)t2)->sym) + goto Lincompatible; + } + else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) + { + goto Lt2; + } + else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) + { + goto Lt1; + } + else if (t1->ty == Tsarray && t2->ty == Tsarray && + e2->implicitConvTo(t1->nextOf()->arrayOf())) + { + Lx1: + t = t1->nextOf()->arrayOf(); // T[] + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else if (t1->ty == Tsarray && t2->ty == Tsarray && + e1->implicitConvTo(t2->nextOf()->arrayOf())) + { + Lx2: + t = t2->nextOf()->arrayOf(); + e1 = e1->castTo(sc, t); + e2 = e2->castTo(sc, t); + } + else if (t1->isintegral() && t2->isintegral()) + { + assert(0); + } + else if (e1->isArrayOperand() && t1->ty == Tarray && + e2->implicitConvTo(t1->nextOf())) + { // T[] op T + e2 = e2->castTo(sc, t1->nextOf()); + t = t1->nextOf()->arrayOf(); + } + else if (e2->isArrayOperand() && t2->ty == Tarray && + e1->implicitConvTo(t2->nextOf())) + { // T op T[] + e1 = e1->castTo(sc, t2->nextOf()); + t = t2->nextOf()->arrayOf(); + + //printf("test %s\n", e->toChars()); + e1 = e1->optimize(WANTvalue); + if (e && e->isCommutative() && e1->isConst()) + { /* Swap operands to minimize number of functions generated + */ + //printf("swap %s\n", e->toChars()); + Expression *tmp = e1; + e1 = e2; + e2 = tmp; + } + } + else + { + Lincompatible: + return 0; + } +Lret: + if (!*pt) + *pt = t; + *pe1 = e1; + *pe2 = e2; +#if 0 + printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars()); + if (e1->type) printf("\tt1 = %s\n", e1->type->toChars()); + if (e2->type) printf("\tt2 = %s\n", e2->type->toChars()); + printf("\ttype = %s\n", t->toChars()); +#endif + //dump(0); + return 1; + + +Lt1: + e2 = e2->castTo(sc, t1); + t = t1; + goto Lret; + +Lt2: + e1 = e1->castTo(sc, t2); + t = t2; + goto Lret; +} + +/************************************ + * Bring leaves to common type. + */ + +Expression *BinExp::typeCombine(Scope *sc) +{ + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + if (op == TOKmin || op == TOKadd) + { + // struct+struct, where the structs are the same type, and class+class are errors + if (t1->ty == Tstruct) + { + if (t2->ty == Tstruct && + ((TypeStruct *)t1)->sym == ((TypeStruct *)t2)->sym) + goto Lerror; + } + else if (t1->ty == Tclass) + { + if (t2->ty == Tclass) + goto Lerror; + } + } + + if (!typeMerge(sc, this, &type, &e1, &e2)) + goto Lerror; + return this; + +Lerror: + incompatibleTypes(); + type = Type::terror; + e1 = new ErrorExp(); + e2 = new ErrorExp(); + return new ErrorExp(); +} + +/*********************************** + * Do integral promotions (convertchk). + * Don't convert to + */ + +Expression *Expression::integralPromotions(Scope *sc) +{ + Expression *e = this; + + //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); + switch (type->toBasetype()->ty) + { + case Tvoid: + error("void has no value"); + return new ErrorExp(); + + case Tint8: + case Tuns8: + case Tint16: + case Tuns16: + case Tbit: + case Tbool: + case Tchar: + case Twchar: + e = e->castTo(sc, Type::tint32); + break; + + case Tdchar: + e = e->castTo(sc, Type::tuns32); + break; + } + return e; +} + +/*********************************** + * See if both types are arrays that can be compared + * for equality. Return !=0 if so. + * If they are arrays, but incompatible, issue error. + * This is to enable comparing things like an immutable + * array with a mutable one. + */ + +int arrayTypeCompatible(Loc loc, Type *t1, Type *t2) +{ + t1 = t1->toBasetype(); + t2 = t2->toBasetype(); + + if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && + (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) + { + if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && + t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && + (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) + { + error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars()); + } + return 1; + } + return 0; +} + +/******************************************************************/ + +/* Determine the integral ranges of an expression. + * This is used to determine if implicit narrowing conversions will + * be allowed. + */ + +uinteger_t getMask(uinteger_t v) +{ + uinteger_t u = 0; + if (v >= 0x80) + u = 0xFF; + while (u < v) + u = (u << 1) | 1; + return u; +} + +IntRange Expression::getIntRange() +{ + IntRange ir; + ir.imin = 0; + if (type->isintegral()) + ir.imax = type->sizemask(); + else + ir.imax = 0xFFFFFFFFFFFFFFFFULL; // assume the worst + return ir; +} + +IntRange IntegerExp::getIntRange() +{ + IntRange ir; + ir.imin = value & type->sizemask(); + ir.imax = ir.imin; + return ir; +} + +IntRange CastExp::getIntRange() +{ + IntRange ir; + ir = e1->getIntRange(); + // Do sign extension + switch (e1->type->toBasetype()->ty) + { + case Tint8: + if (ir.imax & 0x80) + ir.imax |= 0xFFFFFFFFFFFFFF00ULL; + break; + case Tint16: + if (ir.imax & 0x8000) + ir.imax |= 0xFFFFFFFFFFFF0000ULL; + break; + case Tint32: + if (ir.imax & 0x80000000) + ir.imax |= 0xFFFFFFFF00000000ULL; + break; + } + if (type->isintegral()) + { + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + } +//printf("CastExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); + return ir; +} + +IntRange DivExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + if (!(e1->type->isunsigned() || ir1.imax < 0x8000000000000000ULL) && + !(e2->type->isunsigned() || ir2.imax < 0x8000000000000000ULL)) + { + return Expression::getIntRange(); + } + + if (ir2.imax == 0 || ir2.imin == 0) + return Expression::getIntRange(); + + ir.imin = ir1.imin / ir2.imax; + ir.imax = ir1.imax / ir2.imin; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("DivExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange AndExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = ir1.imin; + if (ir2.imin < ir.imin) + ir.imin = ir2.imin; + + ir.imax = ir1.imax; + if (ir2.imax > ir.imax) + ir.imax = ir2.imax; + + uinteger_t u; + + u = getMask(ir1.imax); + ir.imin &= u; + ir.imax &= u; + + u = getMask(ir2.imax); + ir.imin &= u; + ir.imax &= u; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("AndExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange OrExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = ir1.imin; + if (ir2.imin < ir.imin) + ir.imin = ir2.imin; + + ir.imax = ir1.imax; + if (ir2.imax > ir.imax) + ir.imax = ir2.imax; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("OrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange XorExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = ir1.imin; + if (ir2.imin < ir.imin) + ir.imin = ir2.imin; + + ir.imax = ir1.imax; + if (ir2.imax > ir.imax) + ir.imax = ir2.imax; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("XorExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange ShlExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = getMask(ir1.imin) << ir2.imin; + ir.imax = getMask(ir1.imax) << ir2.imax; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("ShlExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange ShrExp::getIntRange() +{ + if (!e1->type->isunsigned()) + return Expression::getIntRange(); + + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = ir1.imin >> ir2.imax; + ir.imax = ir1.imax >> ir2.imin; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("ShrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange UshrExp::getIntRange() +{ + IntRange ir; + IntRange ir1 = e1->getIntRange(); + IntRange ir2 = e2->getIntRange(); + + ir.imin = ir1.imin >> ir2.imax; + ir.imax = ir1.imax >> ir2.imin; + + ir.imin &= type->sizemask(); + ir.imax &= type->sizemask(); + +//printf("UshrExp: imin = x%llx, imax = x%llx\n", ir.imin, ir.imax); +//e1->dump(0); + + return ir; +} + +IntRange CommaExp::getIntRange() +{ + return e2->getIntRange(); +} + + diff --git a/dmd2/class.c b/dmd2/class.c index 0660f3b7..a8d1073c 100644 --- a/dmd2/class.c +++ b/dmd2/class.c @@ -1,1471 +1,1539 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "init.h" -#include "attrib.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "expression.h" -#include "statement.h" - -/********************************* ClassDeclaration ****************************/ - -ClassDeclaration *ClassDeclaration::classinfo; -ClassDeclaration *ClassDeclaration::object; - -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : AggregateDeclaration(loc, id) -{ - static char msg[] = "only object.d can define this reserved class name"; - - if (baseclasses) - this->baseclasses = *baseclasses; - baseClass = NULL; - - interfaces_dim = 0; - interfaces = NULL; - - vtblInterfaces = NULL; - - //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses.dim); - - // For forward references - type = new TypeClass(this); - handle = type; - - staticCtor = NULL; - staticDtor = NULL; - -#if IN_DMD - vtblsym = NULL; -#endif - vclassinfo = NULL; - - if (id) - { // Look for special class names - - if (id == Id::__sizeof || id == Id::alignof || id == Id::mangleof) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id->toChars()[0] == 'T') - { - if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; - } - - if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); - Type::typeinfoclass = this; - } - - if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); - Type::typeinfointerface = this; - } - - if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); - Type::typeinfostruct = this; - } - - if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); - Type::typeinfotypedef = this; - } - - if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); - Type::typeinfopointer = this; - } - - if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); - Type::typeinfoarray = this; - } - - if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) - //Type::typeinfostaticarray->error("%s", msg); - Type::typeinfostaticarray = this; - } - - if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); - Type::typeinfoassociativearray = this; - } - - if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); - Type::typeinfoenum = this; - } - - if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); - Type::typeinfofunction = this; - } - - if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); - Type::typeinfodelegate = this; - } - - if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); - Type::typeinfotypelist = this; - } - -#if DMDV2 - if (id == Id::TypeInfo_Const) - { if (Type::typeinfoconst) - Type::typeinfoconst->error("%s", msg); - Type::typeinfoconst = this; - } - - if (id == Id::TypeInfo_Invariant) - { if (Type::typeinfoinvariant) - Type::typeinfoinvariant->error("%s", msg); - Type::typeinfoinvariant = this; - } - - if (id == Id::TypeInfo_Shared) - { if (Type::typeinfoshared) - Type::typeinfoshared->error("%s", msg); - Type::typeinfoshared = this; - } -#endif - } - - if (id == Id::Object) - { if (object) - object->error("%s", msg); - object = this; - } - - if (id == Id::ClassInfo) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } - } - - com = 0; - isauto = 0; - isabstract = 0; - inuse = 0; -} - -Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) -{ - ClassDeclaration *cd; - - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); - - cd->storage_class |= storage_class; - - cd->baseclasses.setDim(this->baseclasses.dim); - for (int i = 0; i < cd->baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)this->baseclasses.data[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses.data[i] = b2; - } - - ScopeDsymbol::syntaxCopy(cd); - return cd; -} - -void ClassDeclaration::semantic(Scope *sc) -{ int i; - unsigned offset; - - //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); - //printf("sc->stc = %x\n", sc->stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { const char *id = "__anonclass"; - - ident = Identifier::generateId(id); - } - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (!scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } -#ifdef IN_GCC - methods.setDim(0); -#endif - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - if (sc->linkage == LINKcpp) - error("cannot create C++ classes"); - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[i]; -//printf("test1 %s %s\n", toChars(), b->type->toChars()); - b->type = b->type->semantic(loc, sc); -//printf("test2\n"); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses.remove(i); - size_t dim = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses.dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { error("base type must be class or interface, not %s", b->type->toChars()); - baseclasses.remove(0); - } - else - { - tc = (TypeClass *)(tb); - - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - if (tc->sym->isInterfaceDeclaration()) - ; - else - { - for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses.remove(0); - goto L7; - } - } - if (!tc->sym->symtab || tc->sym->sizeok == 0) - { // Try to resolve forward reference - if (sc->mustsemantic && tc->sym->scope) - tc->sym->semantic(NULL); - } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) - { - //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base class, try again later - //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - else - { baseClass = tc->sym; - b->base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (i = (baseClass ? 1 : 0); i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = 1; - - tc->checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - if (!tc->sym->symtab) - { // Try to resolve forward reference - if (sc->mustsemantic && tc->sym->scope) - tc->sym->semantic(NULL); - } - - b->base = tc->sym; - if (!b->base->symtab || b->base->scope) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); - baseclasses.shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - - if (baseClass) - { - if (baseClass->storage_class & STCfinal) - error("cannot inherit from final class %s", baseClass->toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass->vtbl.dim); - memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isauto = baseClass->isauto; - vthis = baseClass->vthis; - storage_class |= baseClass->storage_class & STC_TYPECTOR; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = 1; - if (storage_class & STCstatic) - error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) - { - if (toParent2()) - { - error("is nested within %s, but super class %s is nested within %s", - toParent2()->toChars(), - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - else - { - error("is not nested, but super class %s is nested within %s", - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - isnested = 0; - } - } - else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - AggregateDeclaration *ad = s->isClassDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - - if (ad || fd) - { isnested = 1; - Type *t; - if (ad) - t = ad->handle; - else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; - else - { - t = Type::tvoidptr; - } - } - else - assert(0); - if (t->ty == Tstruct) // ref to struct - t = Type::tvoidptr; - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - members->push(vthis); - } - } - } - } - - if (storage_class & (STCauto | STCscope)) - isauto = 1; - if (storage_class & STCabstract) - isabstract = 1; - if (storage_class & STCimmutable) - type = type->invariantOf(); - else if (storage_class & STCconst) - type = type->constOf(); - else if (storage_class & STCshared) - type = type->sharedOf(); - - sc = sc->push(this); - sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | - STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); - sc->stc |= storage_class & STC_TYPECTOR; - sc->parent = this; - sc->inunion = 0; - - if (isCOMclass()) - { -#if _WIN32 - sc->linkage = LINKwindows; -#else - /* This enables us to use COM objects under Linux and - * work with things like XPCOM - */ - sc->linkage = LINKc; -#endif - } - sc->protection = PROTpublic; - sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; - if (baseClass) - { sc->offset = baseClass->structsize; - alignsize = baseClass->alignsize; -// if (isnested) -// sc->offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = PTRSIZE; - } - structsize = sc->offset; - Scope scsave = *sc; - int members_dim = members->dim; - sizeok = 0; - for (i = 0; i < members_dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc->pop(); - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - //printf("\tsemantic('%s') failed due to forward references\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - structsize = sc->offset; - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; - -// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); -// if (inv && inv->toParent() != this) -// inv = NULL; - - // Can be in base class - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass->ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; - ctor->semantic(sc); - this->ctor = ctor; - defaultCtor = ctor; - } - -#if 0 - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass->aggDelete; - if (!aggNew) - aggNew = baseClass->aggNew; - } -#endif - - // Allocate instance of each new interface - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; - sizeok = 1; - Module::dprogress++; - - dtor = buildDtor(sc); - - sc->pop(); - -#if 0 // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses.dim) - buf->writestring(" : "); - } - for (int i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (i) - buf->writeByte(','); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writestring("}"); - buf->writenl(); -} - -#if 0 -void ClassDeclaration::defineRef(Dsymbol *s) -{ - ClassDeclaration *cd; - - AggregateDeclaration::defineRef(s); - cd = s->isClassDeclaration(); - baseType = cd->baseType; - cd->baseType = NULL; -} -#endif - -/********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - -int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) -{ - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - for (int i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - - if (b->base == this || isBaseOf2(b->base)) - return 1; - } - return 0; -} - -/******************************************* - * Determine if 'this' is a base class of cd. - */ - -int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - if (poffset) - *poffset = 0; - while (cd) - { - if (this == cd->baseClass) - return 1; - - /* cd->baseClass might not be set if cd is forward referenced. - */ - if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) - { - cd->error("base class is forward referenced by %s", toChars()); - } - - cd = cd->baseClass; - } - return 0; -} - -Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - Dsymbol *s; - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope) - { Scope *sc = scope; - sc->mustsemantic++; - semantic(sc); - sc->mustsemantic--; - } - - if (!members || !symtab || scope) - { - error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - s = ScopeDsymbol::search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - int i; - - for (i = 0; i < baseclasses.dim; i++) - { - BaseClass *b = (BaseClass *)baseclasses.data[i]; - - if (b->base) - { - if (!b->base->symtab) - error("base %s is forward referenced", b->base->ident->toChars()); - else - { - s = b->base->search(loc, ident, flags); - if (s == this) // happens if s is nested in this and derives from this - s = NULL; - else if (s) - break; - } - } - } - } - return s; -} - -/********************************************************** - * fd is in the vtbl[] for this class. - * Return 1 if function is hidden (not findable through search). - */ - -#if DMDV2 -int isf(void *param, FuncDeclaration *fd) -{ - //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); - return param == fd; -} - -int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) -{ - //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); - Dsymbol *s = search(0, fd->ident, 4|2); - if (!s) - { //printf("not found\n"); - /* Because, due to a hack, if there are multiple definitions - * of fd->ident, NULL is returned. - */ - return 0; - } - s = s->toAlias(); - OverloadSet *os = s->isOverloadSet(); - if (os) - { - for (int i = 0; i < os->a.dim; i++) - { Dsymbol *s = (Dsymbol *)os->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - if (f2 && overloadApply(getModule(), f2, &isf, fd)) - return 0; - } - return 1; - } - else - { - FuncDeclaration *fdstart = s->isFuncDeclaration(); - //printf("%s fdstart = %p\n", s->kind(), fdstart); - return !overloadApply(getModule(), fdstart, &isf, fd); - } -} -#endif - -/**************** - * Find virtual function matching identifier and type. - * Used to build virtual function tables for interface implementations. - */ - -FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) -{ - //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); - - ClassDeclaration *cd = this; - Array *vtbl = &cd->vtbl; - while (1) - { - for (size_t i = 0; i < vtbl->dim; i++) - { - FuncDeclaration *fd = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); - if (!fd) - continue; // the first entry might be a ClassInfo - - //printf("\t[%d] = %s\n", i, fd->toChars()); - if (ident == fd->ident && - //tf->equals(fd->type) - fd->type->covariant(tf) == 1 - ) - { //printf("\t\tfound\n"); - return fd; - } - //else printf("\t\t%d\n", fd->type->covariant(tf)); - } - if (!cd) - break; - vtbl = &cd->vtblFinal; - cd = cd->baseClass; - } - - return NULL; -} - -void ClassDeclaration::interfaceSemantic(Scope *sc) -{ - InterfaceDeclaration *id = isInterfaceDeclaration(); - - vtblInterfaces = new BaseClasses(); - vtblInterfaces->reserve(interfaces_dim); - - for (size_t i = 0; i < interfaces_dim; i++) - { - BaseClass *b = interfaces[i]; - - // If this is an interface, and it derives from a COM interface, - // then this is a COM interface too. - if (b->base->isCOMinterface()) - com = 1; - - if (b->base->isCPPinterface() && id) - id->cpp = 1; - - vtblInterfaces->push(b); - b->copyBaseInterfaces(vtblInterfaces); - } -} - -/**************************************** - */ - -int ClassDeclaration::isCOMclass() -{ - return com; -} - -int ClassDeclaration::isCOMinterface() -{ - return 0; -} - -#if DMDV2 -int ClassDeclaration::isCPPinterface() -{ - return 0; -} -#endif - - -/**************************************** - */ - -int ClassDeclaration::isAbstract() -{ - if (isabstract) - return TRUE; - for (int i = 1; i < vtbl.dim; i++) - { - FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the classinfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int ClassDeclaration::vtblOffset() -{ - return 1; -} - -/**************************************** - */ - -const char *ClassDeclaration::kind() -{ - return "class"; -} - -/**************************************** - */ - -void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - aclasses->push(this); -} - -/********************************* InterfaceDeclaration ****************************/ - -InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : ClassDeclaration(loc, id, baseclasses) -{ - com = 0; - cpp = 0; - if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces - { com = 1; - cpp = 1; // IUnknown is also a C++ interface - } -} - -Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) -{ - InterfaceDeclaration *id; - - if (s) - id = (InterfaceDeclaration *)s; - else - id = new InterfaceDeclaration(loc, ident, NULL); - - ClassDeclaration::syntaxCopy(id); - return id; -} - -void InterfaceDeclaration::semantic(Scope *sc) -{ int i; - - //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (inuse) - return; - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tinterface '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) // if already done - { if (!scope) - return; - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - if (sc->stc & STCdeprecated) - { - isdeprecated = 1; - } - - // Expand any tuples in baseclasses[] - for (i = 0; i < baseclasses.dim; ) - { BaseClass *b = (BaseClass *)baseclasses.data[0]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses.remove(i); - size_t dim = Argument::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *arg = Argument::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses.insert(i + j, b); - } - } - else - i++; - } - - if (!baseclasses.dim && sc->linkage == LINKcpp) - cpp = 1; - - // Check for errors, handle forward references - for (i = 0; i < baseclasses.dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = (BaseClass *)baseclasses.data[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses.remove(i); - continue; - } - else - { - // Check for duplicate interfaces - for (size_t j = 0; j < i; j++) - { - BaseClass *b2 = (BaseClass *)baseclasses.data[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (b->base == this || isBaseOf2(b->base)) - { - error("circular inheritance of interface"); - baseclasses.remove(i); - continue; - } - if (!b->base->symtab) - { // Try to resolve forward reference - if (sc->mustsemantic && b->base->scope) - b->base->semantic(NULL); - } - if (!b->base->symtab || b->base->scope || b->base->inuse) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } -#if 0 - // Inherit const/invariant from base class - storage_class |= b->base->storage_class & STC_TYPECTOR; -#endif - i++; - } - - interfaces_dim = baseclasses.dim; - interfaces = (BaseClass **)baseclasses.data; - - interfaceSemantic(sc); - - if (vtblOffset()) - vtbl.push(this); // leave room at vtbl[0] for classinfo - - // Cat together the vtbl[]'s from base interfaces - for (i = 0; i < interfaces_dim; i++) - { BaseClass *b = interfaces[i]; - - // Skip if b has already appeared - for (int k = 0; k < i; k++) - { - if (b == interfaces[i]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (int j = 1; j < d; j++) - vtbl.push(b->base->vtbl.data[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - protection = sc->protection; - storage_class |= sc->stc & STC_TYPECTOR; - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | - STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); - sc->stc |= storage_class & STC_TYPECTOR; - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - else if (isCPPinterface()) - sc->linkage = LINKcpp; - sc->structalign = 8; - structalign = sc->structalign; - sc->offset = PTRSIZE * 2; - inuse++; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc); - } - inuse--; - //members->print(); - sc->pop(); - //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - - -/******************************************* - * Determine if 'this' is a base class of cd. - * (Actually, if it is an interface supported by cd) - * Output: - * *poffset offset to start of class - * OFFSET_RUNTIME must determine offset at runtime - * Returns: - * 0 not a base - * 1 is a base - */ - -int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - unsigned j; - - //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); - assert(!baseClass); - for (j = 0; j < cd->interfaces_dim; j++) - { - BaseClass *b = cd->interfaces[j]; - - //printf("\tbase %s\n", b->base->toChars()); - if (this == b->base) - { - //printf("\tfound at offset %d\n", b->offset); - if (poffset) - { *poffset = b->offset; - if (j && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - - if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) - return 1; - - if (poffset) - *poffset = 0; - return 0; -} - - -int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) -{ - //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); - for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) - { - BaseClass *b = &bc->baseInterfaces[j]; - - if (this == b->base) - { - if (poffset) - { *poffset = b->offset; - if (j && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the ClassInfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int InterfaceDeclaration::vtblOffset() -{ - if (isCOMinterface() || isCPPinterface()) - return 0; - return 1; -} - -int InterfaceDeclaration::isCOMinterface() -{ - return com; -} - -#if DMDV2 -int InterfaceDeclaration::isCPPinterface() -{ - return cpp; -} -#endif - -/******************************************* - */ - -const char *InterfaceDeclaration::kind() -{ - return "interface"; -} - - -/******************************** BaseClass *****************************/ - -BaseClass::BaseClass() -{ - memset(this, 0, sizeof(BaseClass)); -} - -BaseClass::BaseClass(Type *type, enum PROT protection) -{ - //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); - this->type = type; - this->protection = protection; - base = NULL; - offset = 0; - - baseInterfaces_dim = 0; - baseInterfaces = NULL; -} - -/**************************************** - * Fill in vtbl[] for base class based on member functions of class cd. - * Input: - * vtbl if !=NULL, fill it in - * newinstance !=0 means all entries must be filled in by members - * of cd, not members of any base classes of cd. - * Returns: - * !=0 if any entries were filled in by members of cd (not exclusively - * by base classes) - */ - -int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) -{ - ClassDeclaration *id = base; - int j; - int result = 0; - - //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); - if (vtbl) - vtbl->setDim(base->vtbl.dim); - - // first entry is ClassInfo reference - for (j = base->vtblOffset(); j < base->vtbl.dim; j++) - { - FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); - FuncDeclaration *fd; - TypeFunction *tf; - - //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); - - assert(ifd); - // Find corresponding function in this class - tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; - fd = cd->findFunc(ifd->ident, tf); - if (fd && !fd->isAbstract()) - { - //printf(" found\n"); - // Check that calling conventions match - if (fd->linkage != ifd->linkage) - fd->error("linkage doesn't match interface function"); - - // Check that it is current - if (newinstance && - fd->toParent() != cd && - ifd->toParent() == base) - cd->error("interface function %s.%s is not implemented", - id->toChars(), ifd->ident->toChars()); - - if (fd->toParent() == cd) - result = 1; - } - else - { - //printf(" not found\n"); - // BUG: should mark this class as abstract? - if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); - fd = NULL; - } - if (vtbl) - vtbl->data[j] = fd; - } - - return result; -} - -void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) -{ - //printf("+copyBaseInterfaces(), %s\n", base->toChars()); -// if (baseInterfaces_dim) -// return; - - baseInterfaces_dim = base->interfaces_dim; - baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); - - //printf("%s.copyBaseInterfaces()\n", base->toChars()); - for (int i = 0; i < baseInterfaces_dim; i++) - { - BaseClass *b = &baseInterfaces[i]; - BaseClass *b2 = base->interfaces[i]; - - assert(b2->vtbl.dim == 0); // should not be filled yet - memcpy(b, b2, sizeof(BaseClass)); - - if (i) // single inheritance is i==0 - vtblInterfaces->push(b); // only need for M.I. - b->copyBaseInterfaces(vtblInterfaces); - } - //printf("-copyBaseInterfaces\n"); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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 +#include +#include + +#include "root.h" +#include "rmem.h" + +#include "enum.h" +#include "init.h" +#include "attrib.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" +#include "mtype.h" +#include "scope.h" +#include "module.h" +#include "expression.h" +#include "statement.h" + +/********************************* ClassDeclaration ****************************/ + +ClassDeclaration *ClassDeclaration::classinfo; +ClassDeclaration *ClassDeclaration::object; + +ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) + : AggregateDeclaration(loc, id) +{ + static char msg[] = "only object.d can define this reserved class name"; + + if (baseclasses) + // Actually, this is a transfer + this->baseclasses = baseclasses; + else + this->baseclasses = new BaseClasses(); + baseClass = NULL; + + interfaces_dim = 0; + interfaces = NULL; + + vtblInterfaces = NULL; + + //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim); + + // For forward references + type = new TypeClass(this); + handle = type; + + staticCtor = NULL; + staticDtor = NULL; + +#if IN_DMD + vtblsym = NULL; +#endif + vclassinfo = NULL; + + if (id) + { // Look for special class names + + if (id == Id::__sizeof || id == Id::__xalignof || id == Id::mangleof) + error("illegal class name"); + + // BUG: What if this is the wrong TypeInfo, i.e. it is nested? + if (id->toChars()[0] == 'T') + { + if (id == Id::TypeInfo) + { if (Type::typeinfo) + Type::typeinfo->error("%s", msg); + Type::typeinfo = this; + } + + if (id == Id::TypeInfo_Class) + { if (Type::typeinfoclass) + Type::typeinfoclass->error("%s", msg); + Type::typeinfoclass = this; + } + + if (id == Id::TypeInfo_Interface) + { if (Type::typeinfointerface) + Type::typeinfointerface->error("%s", msg); + Type::typeinfointerface = this; + } + + if (id == Id::TypeInfo_Struct) + { if (Type::typeinfostruct) + Type::typeinfostruct->error("%s", msg); + Type::typeinfostruct = this; + } + + if (id == Id::TypeInfo_Typedef) + { if (Type::typeinfotypedef) + Type::typeinfotypedef->error("%s", msg); + Type::typeinfotypedef = this; + } + + if (id == Id::TypeInfo_Pointer) + { if (Type::typeinfopointer) + Type::typeinfopointer->error("%s", msg); + Type::typeinfopointer = this; + } + + if (id == Id::TypeInfo_Array) + { if (Type::typeinfoarray) + Type::typeinfoarray->error("%s", msg); + Type::typeinfoarray = this; + } + + if (id == Id::TypeInfo_StaticArray) + { //if (Type::typeinfostaticarray) + //Type::typeinfostaticarray->error("%s", msg); + Type::typeinfostaticarray = this; + } + + if (id == Id::TypeInfo_AssociativeArray) + { if (Type::typeinfoassociativearray) + Type::typeinfoassociativearray->error("%s", msg); + Type::typeinfoassociativearray = this; + } + + if (id == Id::TypeInfo_Enum) + { if (Type::typeinfoenum) + Type::typeinfoenum->error("%s", msg); + Type::typeinfoenum = this; + } + + if (id == Id::TypeInfo_Function) + { if (Type::typeinfofunction) + Type::typeinfofunction->error("%s", msg); + Type::typeinfofunction = this; + } + + if (id == Id::TypeInfo_Delegate) + { if (Type::typeinfodelegate) + Type::typeinfodelegate->error("%s", msg); + Type::typeinfodelegate = this; + } + + if (id == Id::TypeInfo_Tuple) + { if (Type::typeinfotypelist) + Type::typeinfotypelist->error("%s", msg); + Type::typeinfotypelist = this; + } + +#if DMDV2 + if (id == Id::TypeInfo_Const) + { if (Type::typeinfoconst) + Type::typeinfoconst->error("%s", msg); + Type::typeinfoconst = this; + } + + if (id == Id::TypeInfo_Invariant) + { if (Type::typeinfoinvariant) + Type::typeinfoinvariant->error("%s", msg); + Type::typeinfoinvariant = this; + } + + if (id == Id::TypeInfo_Shared) + { if (Type::typeinfoshared) + Type::typeinfoshared->error("%s", msg); + Type::typeinfoshared = this; + } + + if (id == Id::TypeInfo_Wild) + { if (Type::typeinfowild) + Type::typeinfowild->error("%s", msg); + Type::typeinfowild = this; + } +#endif + } + + if (id == Id::Object) + { if (object) + object->error("%s", msg); + object = this; + } + + //if (id == Id::ClassInfo) + if (id == Id::TypeInfo_Class) + { if (classinfo) + classinfo->error("%s", msg); + classinfo = this; + } + + if (id == Id::ModuleInfo) + { if (Module::moduleinfo) + Module::moduleinfo->error("%s", msg); + Module::moduleinfo = this; + } + } + + com = 0; + isscope = 0; + isabstract = 0; + inuse = 0; +} + +Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) +{ + ClassDeclaration *cd; + + //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + cd = (ClassDeclaration *)s; + else + cd = new ClassDeclaration(loc, ident, NULL); + + cd->storage_class |= storage_class; + + cd->baseclasses->setDim(this->baseclasses->dim); + for (int i = 0; i < cd->baseclasses->dim; i++) + { + BaseClass *b = (BaseClass *)this->baseclasses->data[i]; + BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); + cd->baseclasses->data[i] = b2; + } + + ScopeDsymbol::syntaxCopy(cd); + return cd; +} + +void ClassDeclaration::semantic(Scope *sc) +{ int i; + unsigned offset; + + //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); + //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); + //printf("sc->stc = %x\n", sc->stc); + + //{ static int n; if (++n == 20) *(char*)0=0; } + + if (!ident) // if anonymous class + { const char *id = "__anonclass"; + + ident = Identifier::generateId(id); + } + + if (!sc) + sc = scope; + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; + + type = type->semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { //printf("\tclass '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) + { if (sizeok == 1 || !scope) + { //printf("\tsemantic for '%s' is already completed\n", toChars()); + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + unsigned dprogress_save = Module::dprogress; +#ifdef IN_GCC + methods.setDim(0); +#endif + + if (sc->stc & STCdeprecated) + { + isdeprecated = 1; + } + + if (sc->linkage == LINKcpp) + error("cannot create C++ classes"); + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses->dim; ) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; +//printf("test1 %s %s\n", toChars(), b->type->toChars()); + b->type = b->type->semantic(loc, sc); +//printf("test2\n"); + Type *tb = b->type->toBasetype(); + + if (tb->ty == Ttuple) + { TypeTuple *tup = (TypeTuple *)tb; + enum PROT protection = b->protection; + baseclasses->remove(i); + size_t dim = Parameter::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Parameter *arg = Parameter::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses->insert(i + j, b); + } + } + else + i++; + } + + // See if there's a base class as first in baseclasses[] + if (baseclasses->dim) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses->data[0]; + //b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty != Tclass) + { error("base type must be class or interface, not %s", b->type->toChars()); + baseclasses->remove(0); + } + else + { + tc = (TypeClass *)(tb); + + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + if (tc->sym->isInterfaceDeclaration()) + ; + else + { + for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) + { + if (cdb == this) + { + error("circular inheritance"); + baseclasses->remove(0); + goto L7; + } + } + if (!tc->sym->symtab || tc->sym->sizeok == 0) + { // Try to resolve forward reference + if (/*sc->mustsemantic &&*/ tc->sym->scope) + tc->sym->semantic(NULL); + } + if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) + { + //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base class, try again later + //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + if (tc->sym->scope) + tc->sym->scope->module->addDeferredSemantic(tc->sym); + scope->module->addDeferredSemantic(this); + return; + } + else + { baseClass = tc->sym; + b->base = baseClass; + } + L7: ; + } + } + } + + // Treat the remaining entries in baseclasses as interfaces + // Check for errors, handle forward references + for (i = (baseClass ? 1 : 0); i < baseclasses->dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses->data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses->remove(i); + continue; + } + else + { + if (tc->sym->isDeprecated()) + { + if (!isDeprecated()) + { + // Deriving from deprecated class makes this one deprecated too + isdeprecated = 1; + + tc->checkDeprecated(loc, sc); + } + } + + // Check for duplicate interfaces + for (size_t j = (baseClass ? 1 : 0); j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses->data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + if (!tc->sym->symtab) + { // Try to resolve forward reference + if (/*sc->mustsemantic &&*/ tc->sym->scope) + tc->sym->semantic(NULL); + } + + b->base = tc->sym; + if (!b->base->symtab || b->base->scope) + { + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + if (tc->sym->scope) + tc->sym->scope->module->addDeferredSemantic(tc->sym); + scope->module->addDeferredSemantic(this); + return; + } + } + i++; + } + + + // If no base class, and this is not an Object, use Object as base class + if (!baseClass && ident != Id::Object) + { + // BUG: what if Object is redefined in an inner scope? + Type *tbase = new TypeIdentifier(0, Id::Object); + BaseClass *b; + TypeClass *tc; + Type *bt; + + if (!object) + { + error("missing or corrupt object.d"); + fatal(); + } + bt = tbase->semantic(loc, sc)->toBasetype(); + b = new BaseClass(bt, PROTpublic); + baseclasses->shift(b); + assert(b->type->ty == Tclass); + tc = (TypeClass *)(b->type); + baseClass = tc->sym; + assert(!baseClass->isInterfaceDeclaration()); + b->base = baseClass; + } + + interfaces_dim = baseclasses->dim; + interfaces = (BaseClass **)baseclasses->data; + + + if (baseClass) + { + if (baseClass->storage_class & STCfinal) + error("cannot inherit from final class %s", baseClass->toChars()); + + interfaces_dim--; + interfaces++; + + // Copy vtbl[] from base class + vtbl.setDim(baseClass->vtbl.dim); + memcpy(vtbl.data, baseClass->vtbl.data, sizeof(void *) * vtbl.dim); + + // Inherit properties from base class + com = baseClass->isCOMclass(); + isscope = baseClass->isscope; + vthis = baseClass->vthis; + storage_class |= baseClass->storage_class & STC_TYPECTOR; + } + else + { + // No base class, so this is the root of the class hierarchy + vtbl.setDim(0); + vtbl.push(this); // leave room for classinfo as first member + } + + protection = sc->protection; + storage_class |= sc->stc; + + if (sizeok == 0) + { + interfaceSemantic(sc); + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + /* If this is a nested class, add the hidden 'this' + * member which is a pointer to the enclosing scope. + */ + if (vthis) // if inheriting from nested class + { // Use the base class's 'this' member + isnested = 1; + if (storage_class & STCstatic) + error("static class cannot inherit from nested class %s", baseClass->toChars()); + if (toParent2() != baseClass->toParent2()) + { + if (toParent2()) + { + error("is nested within %s, but super class %s is nested within %s", + toParent2()->toChars(), + baseClass->toChars(), + baseClass->toParent2()->toChars()); + } + else + { + error("is not nested, but super class %s is nested within %s", + baseClass->toChars(), + baseClass->toParent2()->toChars()); + } + isnested = 0; + } + } + else if (!(storage_class & STCstatic)) + { Dsymbol *s = toParent2(); + if (s) + { + AggregateDeclaration *ad = s->isClassDeclaration(); + FuncDeclaration *fd = s->isFuncDeclaration(); + + + if (ad || fd) + { isnested = 1; + Type *t; + if (ad) + t = ad->handle; + else if (fd) + { AggregateDeclaration *ad = fd->isMember2(); + if (ad) + t = ad->handle; + else + { + t = Type::tvoidptr; + } + } + else + assert(0); + if (t->ty == Tstruct) // ref to struct + t = Type::tvoidptr; + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + members->push(vthis); + } + } + } + } + + if (storage_class & STCauto) + error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); + if (storage_class & STCscope) + isscope = 1; + if (storage_class & STCabstract) + isabstract = 1; + if (storage_class & STCimmutable) + type = type->invariantOf(); + else if (storage_class & STCconst) + type = type->constOf(); + else if (storage_class & STCshared) + type = type->sharedOf(); + + sc = sc->push(this); + sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | + STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); + sc->stc |= storage_class & STC_TYPECTOR; + sc->parent = this; + sc->inunion = 0; + + if (isCOMclass()) + { +#if _WIN32 + sc->linkage = LINKwindows; +#else + /* This enables us to use COM objects under Linux and + * work with things like XPCOM + */ + sc->linkage = LINKc; +#endif + } + sc->protection = PROTpublic; + sc->explicitProtection = 0; + sc->structalign = 8; + structalign = sc->structalign; + if (baseClass) + { sc->offset = baseClass->structsize; + alignsize = baseClass->alignsize; +// if (isnested) +// sc->offset += PTRSIZE; // room for uplevel context pointer + } + else + { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor + alignsize = PTRSIZE; + } + structsize = sc->offset; + Scope scsave = *sc; + int members_dim = members->dim; + sizeok = 0; + + /* Set scope so if there are forward references, we still might be able to + * resolve individual members like enums. + */ + for (i = 0; i < members_dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + /* There are problems doing this in the general case because + * Scope keeps track of things like 'offset' + */ + if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) + { + //printf("setScope %s %s\n", s->kind(), s->toChars()); + s->setScope(sc); + } + } + + for (i = 0; i < members_dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + sc = sc->pop(); + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + + Module::dprogress = dprogress_save; + + //printf("\tsemantic('%s') failed due to forward references\n", toChars()); + return; + } + + //printf("\tsemantic('%s') successful\n", toChars()); + + structsize = sc->offset; + //members->print(); + + /* Look for special member functions. + * They must be in this class, not in a base class. + */ + ctor = (CtorDeclaration *)search(0, Id::ctor, 0); + if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) + ctor = NULL; + +// dtor = (DtorDeclaration *)search(Id::dtor, 0); +// if (dtor && dtor->toParent() != this) +// dtor = NULL; + +// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); +// if (inv && inv->toParent() != this) +// inv = NULL; + + // Can be in base class + aggNew = (NewDeclaration *)search(0, Id::classNew, 0); + aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + + // If this class has no constructor, but base class does, create + // a constructor: + // this() { } + if (!ctor && baseClass && baseClass->ctor) + { + //printf("Creating default this(){} for class %s\n", toChars()); + CtorDeclaration *ctor = new CtorDeclaration(loc, 0, NULL, 0, 0); + ctor->fbody = new CompoundStatement(0, new Statements()); + members->push(ctor); + ctor->addMember(sc, this, 1); + *sc = scsave; // why? What about sc->nofree? + sc->offset = structsize; + ctor->semantic(sc); + this->ctor = ctor; + defaultCtor = ctor; + } + +#if 0 + if (baseClass) + { if (!aggDelete) + aggDelete = baseClass->aggDelete; + if (!aggNew) + aggNew = baseClass->aggNew; + } +#endif + + // Allocate instance of each new interface + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + unsigned thissize = PTRSIZE; + + alignmember(structalign, thissize, &sc->offset); + assert(b->offset == 0); + b->offset = sc->offset; + + // Take care of single inheritance offsets + while (b->baseInterfaces_dim) + { + b = &b->baseInterfaces[0]; + b->offset = sc->offset; + } + + sc->offset += thissize; + if (alignsize < thissize) + alignsize = thissize; + } + structsize = sc->offset; + sizeok = 1; + Module::dprogress++; + + dtor = buildDtor(sc); + + sc->pop(); + +#if 0 // Do not call until toObjfile() because of forward references + // Fill in base class vtbl[]s + for (i = 0; i < vtblInterfaces->dim; i++) + { + BaseClass *b = (BaseClass *)vtblInterfaces->data[i]; + + //b->fillVtbl(this, &b->vtbl, 1); + } +#endif + //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + +void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (!isAnonymous()) + { + buf->printf("%s ", kind()); + buf->writestring(toChars()); + if (baseclasses->dim) + buf->writestring(" : "); + } + for (int i = 0; i < baseclasses->dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses->data[i]; + + if (i) + buf->writeByte(','); + //buf->writestring(b->base->ident->toChars()); + b->type->toCBuffer(buf, NULL, hgs); + } + if (members) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writestring("}"); + } + else + buf->writeByte(';'); + buf->writenl(); +} + +#if 0 +void ClassDeclaration::defineRef(Dsymbol *s) +{ + ClassDeclaration *cd; + + AggregateDeclaration::defineRef(s); + cd = s->isClassDeclaration(); + baseType = cd->baseType; + cd->baseType = NULL; +} +#endif + +/********************************************* + * Determine if 'this' is a base class of cd. + * This is used to detect circular inheritance only. + */ + +int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) +{ + if (!cd) + return 0; + //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + for (int i = 0; i < cd->baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses->data[i]; + + if (b->base == this || isBaseOf2(b->base)) + return 1; + } + return 0; +} + +/******************************************* + * Determine if 'this' is a base class of cd. + */ + +int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); + if (poffset) + *poffset = 0; + while (cd) + { + if (this == cd->baseClass) + return 1; + + /* cd->baseClass might not be set if cd is forward referenced. + */ + if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) + { + cd->error("base class is forward referenced by %s", toChars()); + } + + cd = cd->baseClass; + } + return 0; +} + +/********************************************* + * Determine if 'this' has complete base class information. + * This is used to detect forward references in covariant overloads. + */ + +int ClassDeclaration::isBaseInfoComplete() +{ + if (!baseClass) + return ident == Id::Object; + for (int i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; + if (!b->base || !b->base->isBaseInfoComplete()) + return 0; + } + return 1; +} + +Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) +{ + Dsymbol *s; + //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); + + if (scope) + { Scope *sc = scope; + sc->mustsemantic++; + semantic(sc); + sc->mustsemantic--; + } + + if (!members || !symtab || scope) + { + error("is forward referenced when looking for '%s'", ident->toChars()); + //*(char*)0=0; + return NULL; + } + + s = ScopeDsymbol::search(loc, ident, flags); + if (!s) + { + // Search bases classes in depth-first, left to right order + + int i; + + for (i = 0; i < baseclasses->dim; i++) + { + BaseClass *b = (BaseClass *)baseclasses->data[i]; + + if (b->base) + { + if (!b->base->symtab) + error("base %s is forward referenced", b->base->ident->toChars()); + else + { + s = b->base->search(loc, ident, flags); + if (s == this) // happens if s is nested in this and derives from this + s = NULL; + else if (s) + break; + } + } + } + } + return s; +} + +/********************************************************** + * fd is in the vtbl[] for this class. + * Return 1 if function is hidden (not findable through search). + */ + +#if DMDV2 +int isf(void *param, FuncDeclaration *fd) +{ + //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); + return param == fd; +} + +int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) +{ + //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); + Dsymbol *s = search(0, fd->ident, 4|2); + if (!s) + { //printf("not found\n"); + /* Because, due to a hack, if there are multiple definitions + * of fd->ident, NULL is returned. + */ + return 0; + } + s = s->toAlias(); + OverloadSet *os = s->isOverloadSet(); + if (os) + { + for (int i = 0; i < os->a.dim; i++) + { Dsymbol *s = (Dsymbol *)os->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + if (f2 && overloadApply(getModule(), f2, &isf, fd)) + return 0; + } + return 1; + } + else + { + FuncDeclaration *fdstart = s->isFuncDeclaration(); + //printf("%s fdstart = %p\n", s->kind(), fdstart); + return !overloadApply(getModule(), fdstart, &isf, fd); + } +} +#endif + +/**************** + * Find virtual function matching identifier and type. + * Used to build virtual function tables for interface implementations. + */ + +FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) +{ + //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); + + ClassDeclaration *cd = this; + Array *vtbl = &cd->vtbl; + while (1) + { + for (size_t i = 0; i < vtbl->dim; i++) + { + FuncDeclaration *fd = ((Dsymbol*)vtbl->data[i])->isFuncDeclaration(); + if (!fd) + continue; // the first entry might be a ClassInfo + + //printf("\t[%d] = %s\n", i, fd->toChars()); + if (ident == fd->ident && + //tf->equals(fd->type) + fd->type->covariant(tf) == 1 + ) + { //printf("\t\tfound\n"); + return fd; + } + //else printf("\t\t%d\n", fd->type->covariant(tf)); + } + if (!cd) + break; + vtbl = &cd->vtblFinal; + cd = cd->baseClass; + } + + return NULL; +} + +void ClassDeclaration::interfaceSemantic(Scope *sc) +{ + InterfaceDeclaration *id = isInterfaceDeclaration(); + + vtblInterfaces = new BaseClasses(); + vtblInterfaces->reserve(interfaces_dim); + + for (size_t i = 0; i < interfaces_dim; i++) + { + BaseClass *b = interfaces[i]; + + // If this is an interface, and it derives from a COM interface, + // then this is a COM interface too. + if (b->base->isCOMinterface()) + com = 1; + + if (b->base->isCPPinterface() && id) + id->cpp = 1; + + vtblInterfaces->push(b); + b->copyBaseInterfaces(vtblInterfaces); + } +} + +/**************************************** + */ + +int ClassDeclaration::isCOMclass() +{ + return com; +} + +int ClassDeclaration::isCOMinterface() +{ + return 0; +} + +#if DMDV2 +int ClassDeclaration::isCPPinterface() +{ + return 0; +} +#endif + + +/**************************************** + */ + +int ClassDeclaration::isAbstract() +{ + if (isabstract) + return TRUE; + for (int i = 1; i < vtbl.dim; i++) + { + FuncDeclaration *fd = ((Dsymbol *)vtbl.data[i])->isFuncDeclaration(); + + //printf("\tvtbl[%d] = %p\n", i, fd); + if (!fd || fd->isAbstract()) + { + isabstract |= 1; + return TRUE; + } + } + return FALSE; +} + + +/**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the classinfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + +int ClassDeclaration::vtblOffset() +{ + return 1; +} + +/**************************************** + */ + +const char *ClassDeclaration::kind() +{ + return "class"; +} + +/**************************************** + */ + +void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) +{ + aclasses->push(this); +} + +/********************************* InterfaceDeclaration ****************************/ + +InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) + : ClassDeclaration(loc, id, baseclasses) +{ + com = 0; + cpp = 0; + if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces + { com = 1; + cpp = 1; // IUnknown is also a C++ interface + } +} + +Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) +{ + InterfaceDeclaration *id; + + if (s) + id = (InterfaceDeclaration *)s; + else + id = new InterfaceDeclaration(loc, ident, NULL); + + ClassDeclaration::syntaxCopy(id); + return id; +} + +void InterfaceDeclaration::semantic(Scope *sc) +{ int i; + + //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); + if (inuse) + return; + + if (!sc) + sc = scope; + if (!parent && sc->parent && !sc->parent->isModule()) + parent = sc->parent; + + type = type->semantic(loc, sc); + handle = type; + + if (!members) // if forward reference + { //printf("\tinterface '%s' is forward referenced\n", toChars()); + return; + } + if (symtab) // if already done + { if (!scope) + return; + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + if (sc->stc & STCdeprecated) + { + isdeprecated = 1; + } + + // Expand any tuples in baseclasses[] + for (i = 0; i < baseclasses->dim; ) + { BaseClass *b = (BaseClass *)baseclasses->data[0]; + b->type = b->type->semantic(loc, sc); + Type *tb = b->type->toBasetype(); + + if (tb->ty == Ttuple) + { TypeTuple *tup = (TypeTuple *)tb; + enum PROT protection = b->protection; + baseclasses->remove(i); + size_t dim = Parameter::dim(tup->arguments); + for (size_t j = 0; j < dim; j++) + { Parameter *arg = Parameter::getNth(tup->arguments, j); + b = new BaseClass(arg->type, protection); + baseclasses->insert(i + j, b); + } + } + else + i++; + } + + if (!baseclasses->dim && sc->linkage == LINKcpp) + cpp = 1; + + // Check for errors, handle forward references + for (i = 0; i < baseclasses->dim; ) + { TypeClass *tc; + BaseClass *b; + Type *tb; + + b = (BaseClass *)baseclasses->data[i]; + b->type = b->type->semantic(loc, sc); + tb = b->type->toBasetype(); + if (tb->ty == Tclass) + tc = (TypeClass *)tb; + else + tc = NULL; + if (!tc || !tc->sym->isInterfaceDeclaration()) + { + error("base type must be interface, not %s", b->type->toChars()); + baseclasses->remove(i); + continue; + } + else + { + // Check for duplicate interfaces + for (size_t j = 0; j < i; j++) + { + BaseClass *b2 = (BaseClass *)baseclasses->data[j]; + if (b2->base == tc->sym) + error("inherits from duplicate interface %s", b2->base->toChars()); + } + + b->base = tc->sym; + if (b->base == this || isBaseOf2(b->base)) + { + error("circular inheritance of interface"); + baseclasses->remove(i); + continue; + } + if (!b->base->symtab) + { // Try to resolve forward reference + if (sc->mustsemantic && b->base->scope) + b->base->semantic(NULL); + } + if (!b->base->symtab || b->base->scope || b->base->inuse) + { + //error("forward reference of base class %s", baseClass->toChars()); + // Forward reference of base, try again later + //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + return; + } + } +#if 0 + // Inherit const/invariant from base class + storage_class |= b->base->storage_class & STC_TYPECTOR; +#endif + i++; + } + + interfaces_dim = baseclasses->dim; + interfaces = (BaseClass **)baseclasses->data; + + interfaceSemantic(sc); + + if (vtblOffset()) + vtbl.push(this); // leave room at vtbl[0] for classinfo + + // Cat together the vtbl[]'s from base interfaces + for (i = 0; i < interfaces_dim; i++) + { BaseClass *b = interfaces[i]; + + // Skip if b has already appeared + for (int k = 0; k < i; k++) + { + if (b == interfaces[k]) + goto Lcontinue; + } + + // Copy vtbl[] from base class + if (b->base->vtblOffset()) + { int d = b->base->vtbl.dim; + if (d > 1) + { + vtbl.reserve(d - 1); + for (int j = 1; j < d; j++) + vtbl.push(b->base->vtbl.data[j]); + } + } + else + { + vtbl.append(&b->base->vtbl); + } + + Lcontinue: + ; + } + + protection = sc->protection; + storage_class |= sc->stc & STC_TYPECTOR; + + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(sc, this, 1); + } + + sc = sc->push(this); + sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | + STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); + sc->stc |= storage_class & STC_TYPECTOR; + sc->parent = this; + if (isCOMinterface()) + sc->linkage = LINKwindows; + else if (isCPPinterface()) + sc->linkage = LINKcpp; + sc->structalign = 8; + structalign = sc->structalign; + sc->offset = PTRSIZE * 2; + inuse++; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc); + } + inuse--; + //members->print(); + sc->pop(); + //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); +} + + +/******************************************* + * Determine if 'this' is a base class of cd. + * (Actually, if it is an interface supported by cd) + * Output: + * *poffset offset to start of class + * OFFSET_RUNTIME must determine offset at runtime + * Returns: + * 0 not a base + * 1 is a base + */ + +int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) +{ + unsigned j; + + //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); + assert(!baseClass); + for (j = 0; j < cd->interfaces_dim; j++) + { + BaseClass *b = cd->interfaces[j]; + + //printf("\tbase %s\n", b->base->toChars()); + if (this == b->base) + { + //printf("\tfound at offset %d\n", b->offset); + if (poffset) + { *poffset = b->offset; + if (j && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return 1; + } + if (isBaseOf(b, poffset)) + { if (j && poffset && cd->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return 1; + } + } + + if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) + return 1; + + if (poffset) + *poffset = 0; + return 0; +} + + +int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) +{ + //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); + for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) + { + BaseClass *b = &bc->baseInterfaces[j]; + + if (this == b->base) + { + if (poffset) + { *poffset = b->offset; + if (j && bc->base->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + } + return 1; + } + if (isBaseOf(b, poffset)) + { if (j && poffset && bc->base->isInterfaceDeclaration()) + *poffset = OFFSET_RUNTIME; + return 1; + } + } + if (poffset) + *poffset = 0; + return 0; +} + +/********************************************* + * Determine if 'this' has clomplete base class information. + * This is used to detect forward references in covariant overloads. + */ + +int InterfaceDeclaration::isBaseInfoComplete() +{ + assert(!baseClass); + for (int i = 0; i < baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)baseclasses->data[i]; + if (!b->base || !b->base->isBaseInfoComplete ()) + return 0; + } + return 1; +} + +/**************************************** + * Determine if slot 0 of the vtbl[] is reserved for something else. + * For class objects, yes, this is where the ClassInfo ptr goes. + * For COM interfaces, no. + * For non-COM interfaces, yes, this is where the Interface ptr goes. + */ + +int InterfaceDeclaration::vtblOffset() +{ + if (isCOMinterface() || isCPPinterface()) + return 0; + return 1; +} + +int InterfaceDeclaration::isCOMinterface() +{ + return com; +} + +#if DMDV2 +int InterfaceDeclaration::isCPPinterface() +{ + return cpp; +} +#endif + +/******************************************* + */ + +const char *InterfaceDeclaration::kind() +{ + return "interface"; +} + + +/******************************** BaseClass *****************************/ + +BaseClass::BaseClass() +{ + memset(this, 0, sizeof(BaseClass)); +} + +BaseClass::BaseClass(Type *type, enum PROT protection) +{ + //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); + this->type = type; + this->protection = protection; + base = NULL; + offset = 0; + + baseInterfaces_dim = 0; + baseInterfaces = NULL; +} + +/**************************************** + * Fill in vtbl[] for base class based on member functions of class cd. + * Input: + * vtbl if !=NULL, fill it in + * newinstance !=0 means all entries must be filled in by members + * of cd, not members of any base classes of cd. + * Returns: + * !=0 if any entries were filled in by members of cd (not exclusively + * by base classes) + */ + +int BaseClass::fillVtbl(ClassDeclaration *cd, Array *vtbl, int newinstance) +{ + ClassDeclaration *id = base; + int j; + int result = 0; + + //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); + if (vtbl) + vtbl->setDim(base->vtbl.dim); + + // first entry is ClassInfo reference + for (j = base->vtblOffset(); j < base->vtbl.dim; j++) + { + FuncDeclaration *ifd = ((Dsymbol *)base->vtbl.data[j])->isFuncDeclaration(); + FuncDeclaration *fd; + TypeFunction *tf; + + //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); + + assert(ifd); + // Find corresponding function in this class + tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; + fd = cd->findFunc(ifd->ident, tf); + if (fd && !fd->isAbstract()) + { + //printf(" found\n"); + // Check that calling conventions match + if (fd->linkage != ifd->linkage) + fd->error("linkage doesn't match interface function"); + + // Check that it is current + if (newinstance && + fd->toParent() != cd && + ifd->toParent() == base) + cd->error("interface function %s.%s is not implemented", + id->toChars(), ifd->ident->toChars()); + + if (fd->toParent() == cd) + result = 1; + } + else + { + //printf(" not found\n"); + // BUG: should mark this class as abstract? + if (!cd->isAbstract()) + cd->error("interface function %s.%s isn't implemented", + id->toChars(), ifd->ident->toChars()); + fd = NULL; + } + if (vtbl) + vtbl->data[j] = fd; + } + + return result; +} + +void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) +{ + //printf("+copyBaseInterfaces(), %s\n", base->toChars()); +// if (baseInterfaces_dim) +// return; + + baseInterfaces_dim = base->interfaces_dim; + baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); + + //printf("%s.copyBaseInterfaces()\n", base->toChars()); + for (int i = 0; i < baseInterfaces_dim; i++) + { + BaseClass *b = &baseInterfaces[i]; + BaseClass *b2 = base->interfaces[i]; + + assert(b2->vtbl.dim == 0); // should not be filled yet + memcpy(b, b2, sizeof(BaseClass)); + + if (i) // single inheritance is i==0 + vtblInterfaces->push(b); // only need for M.I. + b->copyBaseInterfaces(vtblInterfaces); + } + //printf("-copyBaseInterfaces\n"); +} diff --git a/dmd2/clone.c b/dmd2/clone.c index 251e9366..2c9e2a02 100644 --- a/dmd2/clone.c +++ b/dmd2/clone.c @@ -1,443 +1,570 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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 -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "statement.h" -#include "init.h" - - -/******************************************* - * We need an opAssign for the struct if - * it has a destructor or a postblit. - * We need to generate one if a user-specified one does not exist. - */ - -int StructDeclaration::needOpAssign() -{ -#define X 0 - if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); - if (hasIdentityAssign) - goto Ldontneed; - - if (dtor || postblit) - goto Lneed; - - /* If any of the fields need an opAssign, then we - * need it too. - */ - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->needOpAssign()) - goto Lneed; - } - } -Ldontneed: - if (X) printf("\tdontneed\n"); - return 0; - -Lneed: - if (X) printf("\tneed\n"); - return 1; -#undef X -} - -/****************************************** - * Build opAssign for struct. - * S* opAssign(S s) { ... } - */ - -FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) -{ - if (!needOpAssign()) - return NULL; - - //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); - - FuncDeclaration *fop = NULL; - - Argument *param = new Argument(STCnodtor, type, Id::p, NULL); - Arguments *fparams = new Arguments; - fparams->push(param); - Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); -#if STRUCTTHISREF - ((TypeFunction *)ftype)->isref = 1; -#endif - - fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); - - Expression *e = NULL; - if (postblit) - { /* Swap: - * tmp = *this; *this = s; tmp.dtor(); - */ - //printf("\tswap copy\n"); - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp; - AssignExp *ec = NULL; - if (dtor) - { - tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); - tmp->noauto = 1; - e = new DeclarationExp(0, tmp); - ec = new AssignExp(0, - new VarExp(0, tmp), -#if STRUCTTHISREF - new ThisExp(0) -#else - new PtrExp(0, new ThisExp(0)) -#endif - ); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - ec = new AssignExp(0, -#if STRUCTTHISREF - new ThisExp(0), -#else - new PtrExp(0, new ThisExp(0)), -#endif - new IdentifierExp(0, Id::p)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - if (dtor) - { - /* Instead of running the destructor on s, run it - * on tmp. This avoids needing to copy tmp back in to s. - */ - Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); - ec = new CallExp(0, ec); - e = Expression::combine(e, ec); - } - } - else - { /* Do memberwise copy - */ - //printf("\tmemberwise copy\n"); - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - // this.v = s.v; - AssignExp *ec = new AssignExp(0, - new DotVarExp(0, new ThisExp(0), v, 0), - new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - } - Statement *s1 = new ExpStatement(0, e); - - /* Add: - * return this; - */ - e = new ThisExp(0); - Statement *s2 = new ReturnStatement(0, e); - - fop->fbody = new CompoundStatement(0, s1, s2); - - members->push(fop); - fop->addMember(sc, this, 1); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fop->semantic(sc); - - sc->pop(); - - //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); - - return fop; -} - -/******************************************* - * Build copy constructor for struct. - * Copy constructors are compiler generated only, and are only - * callable from the compiler. They are not user accessible. - * A copy constructor is: - * void cpctpr(ref S s) - * { - * *this = s; - * this.postBlit(); - * } - * This is done so: - * - postBlit() never sees uninitialized data - * - memcpy can be much more efficient than memberwise copy - * - no fields are overlooked - */ - -FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) -{ - //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); - FuncDeclaration *fcp = NULL; - - /* Copy constructor is only necessary if there is a postblit function, - * otherwise the code generator will just do a bit copy. - */ - if (postblit) - { - //printf("generating cpctor\n"); - - Argument *param = new Argument(STCref, type, Id::p, NULL); - Arguments *fparams = new Arguments; - fparams->push(param); - Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); - - fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); - - // Build *this = p; - Expression *e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif - AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p)); - ea->op = TOKblit; - Statement *s = new ExpStatement(0, ea); - - // Build postBlit(); - e = new VarExp(0, postblit, 0); - e = new CallExp(0, e); - - s = new CompoundStatement(0, s, new ExpStatement(0, e)); - fcp->fbody = s; - - members->push(fcp); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fcp->semantic(sc); - - sc->pop(); - } - - return fcp; -} - -/***************************************** - * Create inclusive postblit for struct by aggregating - * all the postblits in postblits[] with the postblits for - * all the members. - * Note the close similarity with AggregateDeclaration::buildDtor(), - * and the ordering changes (runs forward instead of backwards). - */ - -#if DMDV2 -FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) -{ - //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); - Expression *e = NULL; - - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - size_t dim = 1; - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->postblit) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.postblit() - ex = new DotVarExp(0, ex, sd->postblit, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.postblit(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::postblit); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(e, ex); // combine in forward order - } - } - } - - /* Build our own "postblit" which executes e - */ - if (e) - { //printf("Building __fieldPostBlit()\n"); - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); - dd->fbody = new ExpStatement(0, e); - postblits.shift(dd); - members->push(dd); - dd->semantic(sc); - } - - switch (postblits.dim) - { - case 0: - return NULL; - - case 1: - return (FuncDeclaration *)postblits.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < postblits.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(e, ex); - } - PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - -#endif - -/***************************************** - * Create inclusive destructor for struct/class by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - * Note the close similarity with StructDeclaration::buildPostBlit(), - * and the ordering changes (runs backward instead of forwards). - */ - -FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) -{ - //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); - Expression *e = NULL; - -#if DMDV2 - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - size_t dim = 1; - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 1) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->dtor, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.destroy(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::destroy); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(ex, e); // combine in reverse order - } - } - } - - /* Build our own "destructor" which executes e - */ - if (e) - { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); - dd->fbody = new ExpStatement(0, e); - dtors.shift(dd); - members->push(dd); - dd->semantic(sc); - } -#endif - - switch (dtors.dim) - { - case 0: - return NULL; - - case 1: - return (FuncDeclaration *)dtors.data[0]; - - default: - e = NULL; - for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(ex, e); - } - DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "statement.h" +#include "init.h" + + +/******************************************* + * We need an opAssign for the struct if + * it has a destructor or a postblit. + * We need to generate one if a user-specified one does not exist. + */ + +int StructDeclaration::needOpAssign() +{ +#define X 0 + if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); + if (hasIdentityAssign) + goto Ldontneed; + + if (dtor || postblit) + goto Lneed; + + /* If any of the fields need an opAssign, then we + * need it too. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->needOpAssign()) + goto Lneed; + } + } +Ldontneed: + if (X) printf("\tdontneed\n"); + return 0; + +Lneed: + if (X) printf("\tneed\n"); + return 1; +#undef X +} + +/******************************************* + * We need an opEquals for the struct if + * any fields has an opEquals. + * Generate one if a user-specified one does not exist. + */ + +int StructDeclaration::needOpEquals() +{ +#define X 0 + if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars()); + + /* If any of the fields has an opEquals, then we + * need it too. + */ + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->eq) + goto Lneed; + } + } +Ldontneed: + if (X) printf("\tdontneed\n"); + return 0; + +Lneed: + if (X) printf("\tneed\n"); + return 1; +#undef X +} + +/****************************************** + * Build opAssign for struct. + * S* opAssign(S s) { ... } + * + * Note that s will be constructed onto the stack, probably copy-constructed. + * Then, the body is: + * S tmp = *this; // bit copy + * *this = s; // bit copy + * tmp.dtor(); + * Instead of running the destructor on s, run it on tmp instead. + */ + +FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) +{ + if (!needOpAssign()) + return NULL; + + //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); + + FuncDeclaration *fop = NULL; + + Parameter *param = new Parameter(STCnodtor, type, Id::p, NULL); + Parameters *fparams = new Parameters; + fparams->push(param); + Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); +#if STRUCTTHISREF + ((TypeFunction *)ftype)->isref = 1; +#endif + + fop = new FuncDeclaration(0, 0, Id::assign, STCundefined, ftype); + + Expression *e = NULL; + if (postblit) + { /* Swap: + * tmp = *this; *this = s; tmp.dtor(); + */ + //printf("\tswap copy\n"); + Identifier *idtmp = Lexer::uniqueId("__tmp"); + VarDeclaration *tmp; + AssignExp *ec = NULL; + if (dtor) + { + tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); + tmp->noscope = 1; + tmp->storage_class |= STCctfe; + e = new DeclarationExp(0, tmp); + ec = new AssignExp(0, + new VarExp(0, tmp), +#if STRUCTTHISREF + new ThisExp(0) +#else + new PtrExp(0, new ThisExp(0)) +#endif + ); + ec->op = TOKblit; + e = Expression::combine(e, ec); + } + ec = new AssignExp(0, +#if STRUCTTHISREF + new ThisExp(0), +#else + new PtrExp(0, new ThisExp(0)), +#endif + new IdentifierExp(0, Id::p)); + ec->op = TOKblit; + e = Expression::combine(e, ec); + if (dtor) + { + /* Instead of running the destructor on s, run it + * on tmp. This avoids needing to copy tmp back in to s. + */ + Expression *ec = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); + ec = new CallExp(0, ec); + e = Expression::combine(e, ec); + } + } + else + { /* Do memberwise copy + */ + //printf("\tmemberwise copy\n"); + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + // this.v = s.v; + AssignExp *ec = new AssignExp(0, + new DotVarExp(0, new ThisExp(0), v, 0), + new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); + ec->op = TOKblit; + e = Expression::combine(e, ec); + } + } + Statement *s1 = new ExpStatement(0, e); + + /* Add: + * return this; + */ + e = new ThisExp(0); + Statement *s2 = new ReturnStatement(0, e); + + fop->fbody = new CompoundStatement(0, s1, s2); + + members->push(fop); + fop->addMember(sc, this, 1); + + sc = sc->push(); + sc->stc = 0; + sc->linkage = LINKd; + + fop->semantic(sc); + + sc->pop(); + + //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); + + return fop; +} + +/****************************************** + * Build opEquals for struct. + * const bool opEquals(const ref S s) { ... } + */ + +FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc) +{ + if (!needOpEquals()) + return NULL; + //printf("StructDeclaration::buildOpEquals() %s\n", toChars()); + Loc loc = this->loc; + + Parameters *parameters = new Parameters; +#if STRUCTTHISREF + // bool opEquals(ref const T) const; + Parameter *param = new Parameter(STCref, type->constOf(), Id::p, NULL); +#else + // bool opEquals(const T*) const; + Parameter *param = new Parameter(STCin, type->pointerTo(), Id::p, NULL); +#endif + + parameters->push(param); + TypeFunction *ftype = new TypeFunction(parameters, Type::tbool, 0, LINKd); + ftype->mod = MODconst; + ftype = (TypeFunction *)ftype->semantic(loc, sc); + + FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, ftype); + + Expression *e = NULL; + /* Do memberwise compare + */ + //printf("\tmemberwise compare\n"); + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + assert(0); // what should we do with this? + // this.v == s.v; + EqualExp *ec = new EqualExp(TOKequal, loc, + new DotVarExp(loc, new ThisExp(loc), v, 0), + new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0)); + if (e) + e = new AndAndExp(loc, e, ec); + else + e = ec; + } + if (!e) + e = new IntegerExp(loc, 1, Type::tbool); + fop->fbody = new ReturnStatement(loc, e); + + members->push(fop); + fop->addMember(sc, this, 1); + + sc = sc->push(); + sc->stc = 0; + sc->linkage = LINKd; + + fop->semantic(sc); + + sc->pop(); + + //printf("-StructDeclaration::buildOpEquals() %s\n", toChars()); + + return fop; +} + + +/******************************************* + * Build copy constructor for struct. + * Copy constructors are compiler generated only, and are only + * callable from the compiler. They are not user accessible. + * A copy constructor is: + * void cpctpr(ref S s) + * { + * *this = s; + * this.postBlit(); + * } + * This is done so: + * - postBlit() never sees uninitialized data + * - memcpy can be much more efficient than memberwise copy + * - no fields are overlooked + */ + +FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) +{ + //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); + FuncDeclaration *fcp = NULL; + + /* Copy constructor is only necessary if there is a postblit function, + * otherwise the code generator will just do a bit copy. + */ + if (postblit) + { + //printf("generating cpctor\n"); + + Parameter *param = new Parameter(STCref, type, Id::p, NULL); + Parameters *fparams = new Parameters; + fparams->push(param); + Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd); + + fcp = new FuncDeclaration(0, 0, Id::cpctor, STCundefined, ftype); + fcp->storage_class |= postblit->storage_class & STCdisable; + + // Build *this = p; + Expression *e = new ThisExp(0); +#if !STRUCTTHISREF + e = new PtrExp(0, e); +#endif + AssignExp *ea = new AssignExp(0, e, new IdentifierExp(0, Id::p)); + ea->op = TOKblit; + Statement *s = new ExpStatement(0, ea); + + // Build postBlit(); + e = new VarExp(0, postblit, 0); + e = new CallExp(0, e); + + s = new CompoundStatement(0, s, new ExpStatement(0, e)); + fcp->fbody = s; + + members->push(fcp); + + sc = sc->push(); + sc->stc = 0; + sc->linkage = LINKd; + + fcp->semantic(sc); + + sc->pop(); + } + + return fcp; +} + +/***************************************** + * Create inclusive postblit for struct by aggregating + * all the postblits in postblits[] with the postblits for + * all the members. + * Note the close similarity with AggregateDeclaration::buildDtor(), + * and the ordering changes (runs forward instead of backwards). + */ + +#if DMDV2 +FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) +{ + //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); + Expression *e = NULL; + StorageClass stc = 0; + + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->postblit) + { Expression *ex; + + stc |= sd->postblit->storage_class & STCdisable; + + // this.v + ex = new ThisExp(0); + ex = new DotVarExp(0, ex, v, 0); + + if (dim == 1) + { // this.v.postblit() + ex = new DotVarExp(0, ex, sd->postblit, 0); + ex = new CallExp(0, ex); + } + else + { + // Typeinfo.postblit(cast(void*)&this.v); + Expression *ea = new AddrExp(0, ex); + ea = new CastExp(0, ea, Type::tvoid->pointerTo()); + + Expression *et = v->type->getTypeInfo(sc); + et = new DotIdExp(0, et, Id::postblit); + + ex = new CallExp(0, et, ea); + } + e = Expression::combine(e, ex); // combine in forward order + } + } + } + + /* Build our own "postblit" which executes e + */ + if (e) + { //printf("Building __fieldPostBlit()\n"); + PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__fieldPostBlit")); + dd->storage_class |= stc; + dd->fbody = new ExpStatement(0, e); + postblits.shift(dd); + members->push(dd); + dd->semantic(sc); + } + + switch (postblits.dim) + { + case 0: + return NULL; + + case 1: + return (FuncDeclaration *)postblits.data[0]; + + default: + e = NULL; + for (size_t i = 0; i < postblits.dim; i++) + { FuncDeclaration *fd = (FuncDeclaration *)postblits.data[i]; + stc |= fd->storage_class & STCdisable; + Expression *ex = new ThisExp(0); + ex = new DotVarExp(0, ex, fd, 0); + ex = new CallExp(0, ex); + e = Expression::combine(e, ex); + } + PostBlitDeclaration *dd = new PostBlitDeclaration(0, 0, Lexer::idPool("__aggrPostBlit")); + dd->storage_class |= stc; + dd->fbody = new ExpStatement(0, e); + members->push(dd); + dd->semantic(sc); + return dd; + } +} + +#endif + +/***************************************** + * Create inclusive destructor for struct/class by aggregating + * all the destructors in dtors[] with the destructors for + * all the members. + * Note the close similarity with StructDeclaration::buildPostBlit(), + * and the ordering changes (runs backward instead of forwards). + */ + +FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) +{ + //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); + Expression *e = NULL; + +#if DMDV2 + for (size_t i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); + if (v->storage_class & STCref) + continue; + Type *tv = v->type->toBasetype(); + size_t dim = 1; + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + dim *= ((TypeSArray *)tv)->dim->toInteger(); + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { Expression *ex; + + // this.v + ex = new ThisExp(0); + ex = new DotVarExp(0, ex, v, 0); + + if (dim == 1) + { // this.v.dtor() + ex = new DotVarExp(0, ex, sd->dtor, 0); + ex = new CallExp(0, ex); + } + else + { + // Typeinfo.destroy(cast(void*)&this.v); + Expression *ea = new AddrExp(0, ex); + ea = new CastExp(0, ea, Type::tvoid->pointerTo()); + + Expression *et = v->type->getTypeInfo(sc); + et = new DotIdExp(0, et, Id::destroy); + + ex = new CallExp(0, et, ea); + } + e = Expression::combine(ex, e); // combine in reverse order + } + } + } + + /* Build our own "destructor" which executes e + */ + if (e) + { //printf("Building __fieldDtor()\n"); + DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__fieldDtor")); + dd->fbody = new ExpStatement(0, e); + dtors.shift(dd); + members->push(dd); + dd->semantic(sc); + } +#endif + + switch (dtors.dim) + { + case 0: + return NULL; + + case 1: + return (FuncDeclaration *)dtors.data[0]; + + default: + e = NULL; + for (size_t i = 0; i < dtors.dim; i++) + { FuncDeclaration *fd = (FuncDeclaration *)dtors.data[i]; + Expression *ex = new ThisExp(0); + ex = new DotVarExp(0, ex, fd, 0); + ex = new CallExp(0, ex); + e = Expression::combine(ex, e); + } + DtorDeclaration *dd = new DtorDeclaration(0, 0, Lexer::idPool("__aggrDtor")); + dd->fbody = new ExpStatement(0, e); + members->push(dd); + dd->semantic(sc); + return dd; + } +} + + diff --git a/dmd2/complex_t.h b/dmd2/complex_t.h index ad895b8a..a1b4f4ed 100644 --- a/dmd2/complex_t.h +++ b/dmd2/complex_t.h @@ -1,74 +1,74 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright and Burton Radons -// 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. - -#ifndef DMD_COMPLEX_T_H -#define DMD_COMPLEX_T_H - -/* Roll our own complex type for compilers that don't support complex - */ - -struct complex_t -{ - long double re; - long double im; - - complex_t() { this->re = 0; this->im = 0; } - complex_t(long double re) { this->re = re; this->im = 0; } - complex_t(long double re, long double im) { this->re = re; this->im = im; } - - complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; } - complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; } - complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; } - complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } - - complex_t operator / (complex_t y) - { - long double abs_y_re = y.re < 0 ? -y.re : y.re; - long double abs_y_im = y.im < 0 ? -y.im : y.im; - long double r, den; - - if (abs_y_re < abs_y_im) - { - r = y.re / y.im; - den = y.im + r * y.re; - return complex_t((re * r + im) / den, - (im * r - re) / den); - } - else - { - r = y.im / y.re; - den = y.re + r * y.im; - return complex_t((re + r * im) / den, - (im - r * re) / den); - } - } - - operator bool () { return re || im; } - - int operator == (complex_t y) { return re == y.re && im == y.im; } - int operator != (complex_t y) { return re != y.re || im != y.im; } -}; - -inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); } - - -inline long double creall(complex_t x) -{ - return x.re; -} - -inline long double cimagl(complex_t x) -{ - return x.im; -} - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright and Burton Radons +// 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. + +#ifndef DMD_COMPLEX_T_H +#define DMD_COMPLEX_T_H + +/* Roll our own complex type for compilers that don't support complex + */ + +struct complex_t +{ + long double re; + long double im; + + complex_t() { this->re = 0; this->im = 0; } + complex_t(long double re) { this->re = re; this->im = 0; } + complex_t(long double re, long double im) { this->re = re; this->im = im; } + + complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; } + complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; } + complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; } + complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } + + complex_t operator / (complex_t y) + { + long double abs_y_re = y.re < 0 ? -y.re : y.re; + long double abs_y_im = y.im < 0 ? -y.im : y.im; + long double r, den; + + if (abs_y_re < abs_y_im) + { + r = y.re / y.im; + den = y.im + r * y.re; + return complex_t((re * r + im) / den, + (im * r - re) / den); + } + else + { + r = y.im / y.re; + den = y.re + r * y.im; + return complex_t((re + r * im) / den, + (im - r * re) / den); + } + } + + operator bool () { return re || im; } + + int operator == (complex_t y) { return re == y.re && im == y.im; } + int operator != (complex_t y) { return re != y.re || im != y.im; } +}; + +inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; } +inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); } +inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); } + + +inline long double creall(complex_t x) +{ + return x.re; +} + +inline long double cimagl(complex_t x) +{ + return x.im; +} + +#endif diff --git a/dmd2/cond.c b/dmd2/cond.c index 33f600ed..831a10d6 100644 --- a/dmd2/cond.c +++ b/dmd2/cond.c @@ -1,406 +1,406 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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 -#include - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "identifier.h" -#include "expression.h" -#include "cond.h" -#include "module.h" -#include "template.h" -#include "lexer.h" -#ifdef _DH -#include "mtype.h" -#include "scope.h" -#endif - -int findCondition(Array *ids, Identifier *ident) -{ - if (ids) - { - for (int i = 0; i < ids->dim; i++) - { - const char *id = (const char *)ids->data[i]; - - if (strcmp(id, ident->toChars()) == 0) - return TRUE; - } - } - - return FALSE; -} - -/* ============================================================ */ - -Condition::Condition(Loc loc) -{ - this->loc = loc; - inc = 0; -} - -/* ============================================================ */ - -DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) - : Condition(0) -{ - this->mod = mod; - this->level = level; - this->ident = ident; -} - -Condition *DVCondition::syntaxCopy() -{ - return this; // don't need to copy -} - -/* ============================================================ */ - -void DebugCondition::setGlobalLevel(unsigned level) -{ - global.params.debuglevel = level; -} - -void DebugCondition::addGlobalIdent(const char *ident) -{ - if (!global.params.debugids) - global.params.debugids = new Array(); - global.params.debugids->push((void *)ident); -} - - -DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int DebugCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->debugids, ident)) - inc = 1; - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { if (!mod->debugidsNot) - mod->debugidsNot = new Array(); - mod->debugidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod->debuglevel) - inc = 1; - } - return (inc == 1); -} - -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - -/* ============================================================ */ - -void VersionCondition::setGlobalLevel(unsigned level) -{ - global.params.versionlevel = level; -} - -void VersionCondition::checkPredefined(Loc loc, const char *ident) -{ - static const char* reserved[] = - { - "DigitalMars", "X86", "X86_64", - "Windows", "Win32", "Win64", - "linux", -#if DMDV2 - /* Although Posix is predefined by D1, disallowing its - * redefinition breaks makefiles and older builds. - */ - "Posix", - "D_NET", -#endif - "OSX", "FreeBSD", - "Solaris", - "LittleEndian", "BigEndian", - "all", - "none", - -#if IN_LLVM - "LLVM", "LDC", "LLVM64", - "PPC", "PPC64", - "darwin","solaris","freebsd" -#endif - }; - - for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) - { - if (strcmp(ident, reserved[i]) == 0) - goto Lerror; - } - - if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); -} - -void VersionCondition::addGlobalIdent(const char *ident) -{ - checkPredefined(0, ident); - addPredefinedGlobalIdent(ident); -} - -void VersionCondition::addPredefinedGlobalIdent(const char *ident) -{ - if (!global.params.versionids) - global.params.versionids = new Array(); - global.params.versionids->push((void *)ident); -} - - -VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int VersionCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident->toChars()); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->versionids, ident)) - inc = 1; - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod->versionidsNot) - mod->versionidsNot = new Array(); - mod->versionidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod->versionlevel) - inc = 1; - } - return (inc == 1); -} - -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - -/**************************** StaticIfCondition *******************************/ - -StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) - : Condition(loc) -{ - this->exp = exp; -} - -Condition *StaticIfCondition::syntaxCopy() -{ - return new StaticIfCondition(loc, exp->syntaxCopy()); -} - -int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) -{ -#if 0 - printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - inc = 1; - else if (e->isBool(FALSE)) - inc = 2; - else - { - e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; - } - } - return (inc == 1); -} - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} - - -/**************************** IftypeCondition *******************************/ - -IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) - : Condition(loc) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; -} - -Condition *IftypeCondition::syntaxCopy() -{ - return new IftypeCondition(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL); -} - -int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("IftypeCondition::include()\n"); - if (inc == 0) - { - if (!sc) - { - error(loc, "iftype conditional cannot be at global scope"); - inc = 2; - return 0; - } - Type *t = targ->trySemantic(loc, sc); - if (t) - targ = t; - else - inc = 2; // condition is false - - if (!t) - { - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.data[0] = (void *)&tp; - - Objects dedtypes; - dedtypes.setDim(1); - - m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - inc = 2; - else - { - inc = 1; - Type *tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - Dsymbol *s = new AliasDeclaration(loc, id, targ); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - inc = 1; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - inc = 1; - else - inc = 2; - } - else /* == */ - { if (targ->equals(tspec)) - inc = 1; - else - inc = 2; - } - } - else - inc = 1; - //printf("inc = %d\n", inc); - } - return (inc == 1); -} - -void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("iftype("); - targ->toCBuffer(buf, id, hgs); - if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } - buf->writeByte(')'); -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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 +#include + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "identifier.h" +#include "expression.h" +#include "cond.h" +#include "module.h" +#include "template.h" +#include "lexer.h" +#ifdef _DH +#include "mtype.h" +#include "scope.h" +#endif + +int findCondition(Array *ids, Identifier *ident) +{ + if (ids) + { + for (int i = 0; i < ids->dim; i++) + { + const char *id = (const char *)ids->data[i]; + + if (strcmp(id, ident->toChars()) == 0) + return TRUE; + } + } + + return FALSE; +} + +/* ============================================================ */ + +Condition::Condition(Loc loc) +{ + this->loc = loc; + inc = 0; +} + +/* ============================================================ */ + +DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) + : Condition(0) +{ + this->mod = mod; + this->level = level; + this->ident = ident; +} + +Condition *DVCondition::syntaxCopy() +{ + return this; // don't need to copy +} + +/* ============================================================ */ + +void DebugCondition::setGlobalLevel(unsigned level) +{ + global.params.debuglevel = level; +} + +void DebugCondition::addGlobalIdent(const char *ident) +{ + if (!global.params.debugids) + global.params.debugids = new Array(); + global.params.debugids->push((void *)ident); +} + + +DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int DebugCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->debugids, ident)) + inc = 1; + else if (findCondition(global.params.debugids, ident)) + inc = 1; + else + { if (!mod->debugidsNot) + mod->debugidsNot = new Array(); + mod->debugidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.debuglevel || level <= mod->debuglevel) + inc = 1; + } + return (inc == 1); +} + +void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("debug (%s)", ident->toChars()); + else + buf->printf("debug (%u)", level); +} + +/* ============================================================ */ + +void VersionCondition::setGlobalLevel(unsigned level) +{ + global.params.versionlevel = level; +} + +void VersionCondition::checkPredefined(Loc loc, const char *ident) +{ + static const char* reserved[] = + { + "DigitalMars", "X86", "X86_64", + "Windows", "Win32", "Win64", + "linux", +#if DMDV2 + /* Although Posix is predefined by D1, disallowing its + * redefinition breaks makefiles and older builds. + */ + "Posix", + "D_NET", +#endif + "OSX", "FreeBSD", + "Solaris", + "LittleEndian", "BigEndian", + "all", + "none", + +#if IN_LLVM + "LLVM", "LDC", "LLVM64", + "PPC", "PPC64", + "darwin","solaris","freebsd" +#endif + }; + + for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) + { + if (strcmp(ident, reserved[i]) == 0) + goto Lerror; + } + + if (ident[0] == 'D' && ident[1] == '_') + goto Lerror; + + return; + + Lerror: + error(loc, "version identifier '%s' is reserved and cannot be set", ident); +} + +void VersionCondition::addGlobalIdent(const char *ident) +{ + checkPredefined(0, ident); + addPredefinedGlobalIdent(ident); +} + +void VersionCondition::addPredefinedGlobalIdent(const char *ident) +{ + if (!global.params.versionids) + global.params.versionids = new Array(); + global.params.versionids->push((void *)ident); +} + + +VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) + : DVCondition(mod, level, ident) +{ +} + +int VersionCondition::include(Scope *sc, ScopeDsymbol *s) +{ + //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); + //if (ident) printf("\tident = '%s'\n", ident->toChars()); + if (inc == 0) + { + inc = 2; + if (ident) + { + if (findCondition(mod->versionids, ident)) + inc = 1; + else if (findCondition(global.params.versionids, ident)) + inc = 1; + else + { + if (!mod->versionidsNot) + mod->versionidsNot = new Array(); + mod->versionidsNot->push(ident->toChars()); + } + } + else if (level <= global.params.versionlevel || level <= mod->versionlevel) + inc = 1; + } + return (inc == 1); +} + +void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (ident) + buf->printf("version (%s)", ident->toChars()); + else + buf->printf("version (%u)", level); +} + + +/**************************** StaticIfCondition *******************************/ + +StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) + : Condition(loc) +{ + this->exp = exp; +} + +Condition *StaticIfCondition::syntaxCopy() +{ + return new StaticIfCondition(loc, exp->syntaxCopy()); +} + +int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) +{ +#if 0 + printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); + if (s) + { + printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); + } +#endif + if (inc == 0) + { + if (!sc) + { + error(loc, "static if conditional cannot be at global scope"); + inc = 2; + return 0; + } + + sc = sc->push(sc->scopesym); + sc->sd = s; // s gets any addMember() + sc->flags |= SCOPEstaticif; + Expression *e = exp->semantic(sc); + sc->pop(); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(TRUE)) + inc = 1; + else if (e->isBool(FALSE)) + inc = 2; + else + { + e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); + inc = 2; + } + } + return (inc == 1); +} + +void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("static if("); + exp->toCBuffer(buf, hgs); + buf->writeByte(')'); +} + + +/**************************** IftypeCondition *******************************/ + +IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) + : Condition(loc) +{ + this->targ = targ; + this->id = id; + this->tok = tok; + this->tspec = tspec; +} + +Condition *IftypeCondition::syntaxCopy() +{ + return new IftypeCondition(loc, + targ->syntaxCopy(), + id, + tok, + tspec ? tspec->syntaxCopy() : NULL); +} + +int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) +{ + //printf("IftypeCondition::include()\n"); + if (inc == 0) + { + if (!sc) + { + error(loc, "iftype conditional cannot be at global scope"); + inc = 2; + return 0; + } + Type *t = targ->trySemantic(loc, sc); + if (t) + targ = t; + else + inc = 2; // condition is false + + if (!t) + { + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + MATCH m; + TemplateTypeParameter tp(loc, id, NULL, NULL); + + TemplateParameters parameters; + parameters.setDim(1); + parameters.data[0] = (void *)&tp; + + Objects dedtypes; + dedtypes.setDim(1); + + m = targ->deduceType(NULL, tspec, ¶meters, &dedtypes); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + inc = 2; + else + { + inc = 1; + Type *tded = (Type *)dedtypes.data[0]; + if (!tded) + tded = targ; + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to TRUE + */ + Dsymbol *s = new AliasDeclaration(loc, id, targ); + s->semantic(sc); + sc->insert(s); + if (sd) + s->addMember(sc, sd, 1); + inc = 1; + } + else if (tspec) + { + /* Evaluate to TRUE if targ matches tspec + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s\n", targ->toChars()); + //printf("tspec = %s\n", tspec->toChars()); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + inc = 1; + else + inc = 2; + } + else /* == */ + { if (targ->equals(tspec)) + inc = 1; + else + inc = 2; + } + } + else + inc = 1; + //printf("inc = %d\n", inc); + } + return (inc == 1); +} + +void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("iftype("); + targ->toCBuffer(buf, id, hgs); + if (tspec) + { + if (tok == TOKcolon) + buf->writestring(" : "); + else + buf->writestring(" == "); + tspec->toCBuffer(buf, NULL, hgs); + } + buf->writeByte(')'); +} + + diff --git a/dmd2/cond.h b/dmd2/cond.h index c5554e83..5d6fb94d 100644 --- a/dmd2/cond.h +++ b/dmd2/cond.h @@ -30,9 +30,9 @@ int findCondition(Array *ids, Identifier *ident); struct Condition { Loc loc; - int inc; // 0: not computed yet - // 1: include - // 2: do not include + int inc; // 0: not computed yet + // 1: include + // 2: do not include Condition(Loc loc); @@ -92,9 +92,9 @@ struct IftypeCondition : Condition /* iftype (targ id tok tspec) */ Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL + Identifier *id; // can be NULL + enum TOK tok; // ':' or '==' + Type *tspec; // can be NULL IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec); Condition *syntaxCopy(); diff --git a/dmd2/constfold.c b/dmd2/constfold.c index 3e412011..cc4a1f9f 100644 --- a/dmd2/constfold.c +++ b/dmd2/constfold.c @@ -1,1607 +1,1641 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "rmem.h" -#include "root.h" -#include "port.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.h" - -#if __FreeBSD__ -#define fmodl fmod // hack for now, fix later -#endif - -#define LOG 0 - -Expression *expType(Type *type, Expression *e) -{ - if (type != e->type) - { - e = e->copy(); - e->type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ - -int Expression::isConst() -{ - //printf("Expression::isConst(): %s\n", toChars()); - return 0; -} - -int IntegerExp::isConst() -{ - return 1; -} - -int RealExp::isConst() -{ - return 1; -} - -int ComplexExp::isConst() -{ - return 1; -} - -int NullExp::isConst() -{ - return 0; -} - -int SymOffExp::isConst() -{ - return 2; -} - -/* =============================== constFold() ============================== */ - -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ - -/* ========================================================================== */ - -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->type->isreal()) - { - e = new RealExp(loc, -e1->toReal(), type); - } - else if (e1->type->isimaginary()) - { - e = new RealExp(loc, -e1->toImaginary(), type); - } - else if (e1->type->iscomplex()) - { - e = new ComplexExp(loc, -e1->toComplex(), type); - } - else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; -} - -Expression *Com(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, ~e1->toInteger(), type); - return e; -} - -Expression *Not(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(0), type); - return e; -} - -Expression *Bool(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(1), type); - return e; -} - -Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - -#if LOG - printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); -#endif - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() + e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 + r2); break; - case 0+1: v = r1 + i2 * I; break; - case 0+2: v = r1 + c2; break; - case 3+0: v = i1 * I + r2; break; - case 3+1: v = (complex_t) ((i1 + i2) * I); break; - case 3+2: v = i1 * I + c2; break; - case 6+0: v = c1 + r2; break; - case 6+1: v = c1 + i2 * I; break; - case 6+2: v = c1 + c2; break; -#else - case 0+0: v = complex_t(r1 + r2, 0); break; - case 0+1: v = complex_t(r1, i2); break; - case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; - case 3+0: v = complex_t(r2, i1); break; - case 3+1: v = complex_t(0, i1 + i2); break; - case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; - case 6+2: v = c1 + c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); - e->type = type; - } - else if (e2->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e2; - e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); - e->type = type; - } - else - e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); - return e; -} - - -Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() - e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 - r2); break; - case 0+1: v = r1 - i2 * I; break; - case 0+2: v = r1 - c2; break; - case 3+0: v = i1 * I - r2; break; - case 3+1: v = (complex_t) ((i1 - i2) * I); break; - case 3+2: v = i1 * I - c2; break; - case 6+0: v = c1 - r2; break; - case 6+1: v = c1 - i2 * I; break; - case 6+2: v = c1 - c2; break; -#else - case 0+0: v = complex_t(r1 - r2, 0); break; - case 0+1: v = complex_t(r1, -i2); break; - case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; - case 3+0: v = complex_t(-r2, i1); break; - case 3+1: v = complex_t(0, i1 - i2); break; - case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; - case 6+2: v = c1 - c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); - e->type = type; - } - else - { - e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); - } - return e; -} - -Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - if (e1->type->isreal()) - { -#if __DMC__ - c = e1->toReal() * e2->toComplex(); -#else - r = e1->toReal(); - c = e2->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e1->type->isimaginary()) - { -#if __DMC__ - c = e1->toImaginary() * I * e2->toComplex(); -#else - r = e1->toImaginary(); - c = e2->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else if (e2->type->isreal()) - { -#if __DMC__ - c = e2->toReal() * e1->toComplex(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - c = e1->toComplex() * e2->toImaginary() * I; -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else - c = e1->toComplex() * e2->toComplex(); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { - e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); - } - return e; -} - -Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - //e1->type->print(); - //e2->type->print(); - if (e2->type->isreal()) - { - if (e1->type->isreal()) - { - e = new RealExp(loc, e1->toReal() / e2->toReal(), type); - return e; - } -#if __DMC__ - //r = e2->toReal(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / e2->toReal(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - //r = e2->toImaginary(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / (e2->toImaginary() * I); -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); -#endif - } - else - { - c = e1->toComplex() / e2->toComplex(); - } - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) / ((d_uns64) n2); - else - n = n1 / n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { - complex_t c; - - if (e2->type->isreal()) - { real_t r2 = e2->toReal(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); -#else - c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); -#endif - } - else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); - -#ifdef __DMC__ - c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); -#else - c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); -#endif - } - else - assert(0); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) % ((d_uns64) n2); - else - n = n1 % n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); - return e; -} - -Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - dinteger_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - value = (d_int8)(value) >> count; - break; - - case Tuns8: - value = (d_uns8)(value) >> count; - break; - - case Tint16: - value = (d_int16)(value) >> count; - break; - - case Tuns16: - value = (d_uns16)(value) >> count; - break; - - case Tint32: - value = (d_int32)(value) >> count; - break; - - case Tuns32: - value = (d_uns32)(value) >> count; - break; - - case Tint64: - value = (d_int64)(value) >> count; - break; - - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - unsigned count; - dinteger_t value; - - value = e1->toInteger(); - count = e2->toInteger(); - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - assert(0); // no way to trigger this - value = (value & 0xFF) >> count; - break; - - case Tint16: - case Tuns16: - assert(0); // no way to trigger this - value = (value & 0xFFFF) >> count; - break; - - case Tint32: - case Tuns32: - value = (value & 0xFFFFFFFF) >> count; - break; - - case Tint64: - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - default: - assert(0); - } - e = new IntegerExp(loc, value, type); - return e; -} - -Expression *And(Type *type, Expression *e1, Expression *e2) -{ - Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - real_t r1; - real_t r2; - - //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - assert(op == TOKequal || op == TOKnotequal); - - if (e1->op == TOKnull) - { - if (e2->op == TOKnull) - cmp = 1; - else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; - cmp = (0 == es2->len); - } - else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - cmp = !es2->elements || (0 == es2->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e2->op == TOKnull) - { - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - cmp = (0 == es1->len); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - cmp = !es1->elements || (0 == es1->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - - if (es1->sz != es2->sz) - { - assert(global.errors); - return EXP_CANT_INTERPRET; - } - if (es1->len == es2->len && - memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { // Swap operands and use common code - Expression *e = e1; - e1 = e2; - e2 = e; - goto Lsa; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral) - { - Lsa: - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t dim1 = es1->len; - size_t dim2 = es2->elements ? es2->elements->dim : 0; - if (dim1 != dim2) - cmp = 0; - else - { - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1->charAt(i); - Expression *ee2 = (Expression *)es2->elements->data[i]; - if (ee2->isConst() != 1) - return EXP_CANT_INTERPRET; - cmp = (c == ee2->toInteger()); - if (cmp == 0) - break; - } - } - } - else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) - { StructLiteralExp *es1 = (StructLiteralExp *)e1; - StructLiteralExp *es2 = (StructLiteralExp *)e2; - - if (es1->sd != es2->sd) - cmp = 0; - else if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - cmp = 1; - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (Expression *)es1->elements->data[i]; - Expression *ee2 = (Expression *)es2->elements->data[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { cmp = 0; - break; - } - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } -#if 0 // Should handle this - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { - } -#endif - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - cmp = (r1 == r2); -#else - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - cmp = e1->toComplex() == e2->toComplex(); - } - else if (e1->type->isintegral()) - { - cmp = (e1->toInteger() == e2->toInteger()); - } - else - return EXP_CANT_INTERPRET; - if (op == TOKnotequal) - cmp ^= 1; - e = new IntegerExp(loc, cmp, type); - return e; -} - -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - - if (e1->op == TOKnull) - { - cmp = (e2->op == TOKnull); - } - else if (e2->op == TOKnull) - { - cmp = 0; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else if (e1->isConst() == 1 && e2->isConst() == 1) - return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, - type, e1, e2); - else - assert(0); - if (op == TOKnotidentity) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - - -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - dinteger_t n; - real_t r1; - real_t r2; - - //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - size_t sz = es1->sz; - assert(sz == es2->sz); - - size_t len = es1->len; - if (es2->len < len) - len = es2->len; - - int cmp = memcmp(es1->string, es2->string, sz * len); - if (cmp == 0) - cmp = es1->len - es2->len; - - switch (op) - { - case TOKlt: n = cmp < 0; break; - case TOKle: n = cmp <= 0; break; - case TOKgt: n = cmp > 0; break; - case TOKge: n = cmp >= 0; break; - - case TOKleg: n = 1; break; - case TOKlg: n = cmp != 0; break; - case TOKunord: n = 0; break; - case TOKue: n = cmp == 0; break; - case TOKug: n = cmp > 0; break; - case TOKuge: n = cmp >= 0; break; - case TOKul: n = cmp < 0; break; - case TOKule: n = cmp <= 0; break; - - default: - assert(0); - } - } - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - // DMC is the only compiler I know of that handles NAN arguments - // correctly in comparisons. - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = r1 <>= r2; break; - case TOKlg: n = r1 <> r2; break; - case TOKunord: n = r1 !<>= r2; break; - case TOKue: n = r1 !<> r2; break; - case TOKug: n = r1 !<= r2; break; - case TOKuge: n = r1 !< r2; break; - case TOKul: n = r1 !>= r2; break; - case TOKule: n = r1 !> r2; break; - - default: - assert(0); - } -#else - // Don't rely on compiler, handle NAN arguments separately - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - switch (op) - { - case TOKlt: n = 0; break; - case TOKle: n = 0; break; - case TOKgt: n = 0; break; - case TOKge: n = 0; break; - - case TOKleg: n = 0; break; - case TOKlg: n = 0; break; - case TOKunord: n = 1; break; - case TOKue: n = 1; break; - case TOKug: n = 1; break; - case TOKuge: n = 1; break; - case TOKul: n = 1; break; - case TOKule: n = 1; break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = r1 != r2; break; - case TOKunord: n = 0; break; - case TOKue: n = r1 == r2; break; - case TOKug: n = r1 > r2; break; - case TOKuge: n = r1 >= r2; break; - case TOKul: n = r1 < r2; break; - case TOKule: n = r1 <= r2; break; - - default: - assert(0); - } - } -#endif - } - else if (e1->type->iscomplex()) - { - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (e1->type->isunsigned() || e2->type->isunsigned()) - { - switch (op) - { - case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - - case TOKleg: n = 1; break; - case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; - case TOKunord: n = 0; break; - case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; - case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = n1 < n2; break; - case TOKle: n = n1 <= n2; break; - case TOKgt: n = n1 > n2; break; - case TOKge: n = n1 >= n2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = n1 != n2; break; - case TOKunord: n = 0; break; - case TOKue: n = n1 == n2; break; - case TOKug: n = n1 > n2; break; - case TOKuge: n = n1 >= n2; break; - case TOKul: n = n1 < n2; break; - case TOKule: n = n1 <= n2; break; - - default: - assert(0); - } - } - } - e = new IntegerExp(loc, n, type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ - -Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("\te1->type = %s\n", e1->type->toChars()); - if (e1->type->equals(type) && type->equals(to)) - return e1; - if (e1->type->implicitConvTo(to) >= MATCHconst || - to->implicitConvTo(e1->type) >= MATCHconst) - return expType(to, e1); - - Type *tb = to->toBasetype(); - Type *typeb = type->toBasetype(); - - /* Allow casting from one string type to another - */ - if (e1->op == TOKstring) - { - if (tb->ty == Tarray && typeb->ty == Tarray && - tb->nextOf()->size() == typeb->nextOf()->size()) - { - return expType(to, e1); - } - } - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { dinteger_t result; - real_t r = e1->toReal(); - - switch (typeb->ty) - { - case Tint8: result = (d_int8)r; break; - case Tchar: - case Tuns8: result = (d_uns8)r; break; - case Tint16: result = (d_int16)r; break; - case Twchar: - case Tuns16: result = (d_uns16)r; break; - case Tint32: result = (d_int32)r; break; - case Tdchar: - case Tuns32: result = (d_uns32)r; break; - case Tint64: result = (d_int64)r; break; - case Tuns64: result = (d_uns64)r; break; - default: - assert(0); - } - - e = new IntegerExp(loc, result, type); - } - else if (type->isunsigned()) - e = new IntegerExp(loc, e1->toUInteger(), type); - else - e = new IntegerExp(loc, e1->toInteger(), type); - } - else if (tb->isreal()) - { real_t value = e1->toReal(); - - e = new RealExp(loc, value, type); - } - else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); - - e = new RealExp(loc, value, type); - } - else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); - - e = new ComplexExp(loc, value, type); - } - else if (tb->isscalar()) - e = new IntegerExp(loc, e1->toInteger(), type); - else if (tb->ty == Tvoid) - e = EXP_CANT_INTERPRET; - else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; - StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); - assert(sd); - Expressions *elements = new Expressions; - for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - Expression *exp = new IntegerExp(0); - exp = Cast(v->type, v->type, exp); - if (exp == EXP_CANT_INTERPRET) - return exp; - elements->push(exp); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = type; - } - else - { - error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); - e = new IntegerExp(loc, 0, Type::tint32); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); - else - { unsigned value = es1->charAt(i); - e = new IntegerExp(loc, value, type); - } - } - else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) - { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); - uinteger_t length = tsa->dim->toInteger(); - uinteger_t i = e2->toInteger(); - - if (i >= length) - { e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); - } - else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) - { - uinteger_t i = e2->toInteger(); - - if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (i >= ale->elements->dim) - { e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); - } - else - { e = (Expression *)ale->elements->data[i]; - e->type = type; - } - } - } - else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = (Expression *)ae->keys->data[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = (Expression *)ae->values->data[i]; - e->type = type; - break; - } - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - -#if LOG - printf("Slice()\n"); - if (lwr) - { printf("\te1 = %s\n", e1->toChars()); - printf("\tlwr = %s\n", lwr->toChars()); - printf("\tupr = %s\n", upr->toChars()); - } -#endif - if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->len || ilwr > iupr) - e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); - else - { dinteger_t value; - void *s; - size_t len = iupr - ilwr; - int sz = es1->sz; - StringExp *es; - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len, es1->postfix); - es->sz = sz; - es->committed = 1; - es->type = type; - e = es; - } - } - else if (e1->op == TOKarrayliteral && - lwr->op == TOKint64 && upr->op == TOKint64 && - !e1->checkSideEffect(2)) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->elements->dim || ilwr > iupr) - e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); - else - { - Expressions *elements = new Expressions(); - elements->setDim(iupr - ilwr); - memcpy(elements->data, - es1->elements->data + ilwr, - (iupr - ilwr) * sizeof(es1->elements->data[0])); - e = new ArrayLiteralExp(e1->loc, elements); - e->type = type; - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - Type *t; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - //printf("\tt1 = %s, t2 = %s\n", t1->toChars(), t2->toChars()); - - if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; - goto L2; - } - else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; - L2: - Type *tn = e->type->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { - // Create a StringExp - void *s; - StringExp *es; - size_t len = 1; - int sz = tn->size(); - dinteger_t v = e->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 1; - e = es; - } - else - { // Create an ArrayLiteralExp - Expressions *elements = new Expressions(); - elements->push(e); - e = new ArrayLiteralExp(e->loc, elements); - } - e->type = type; - return e; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = es1->len + es2->len; - int sz = es1->sz; - - if (sz != es2->sz) - { - /* Can happen with: - * auto s = "foo"d ~ "bar"c; - */ - assert(global.errors); - return e; - } - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed | es2->committed; - if (es1->committed) - t = es1->type; - else - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKstring && e2->op == TOKint64) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es; - Type *t; - size_t len = es1->len + 1; - int sz = es1->sz; - dinteger_t v = e2->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, &v, sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed; - t = es1->type; - es->type = type; - e = es; - } - else if (e1->op == TOKint64 && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - Type *t; - size_t len = 1 + es2->len; - int sz = es2->sz; - dinteger_t v = e1->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es2->committed; - t = es2->type; - es->type = type; - e = es; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKnull && - t1->nextOf()->equals(t2->nextOf())) - { - e = e1; - goto L3; - } - else if (e1->op == TOKnull && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - e = e2; - L3: - // Concatenate the array with null - ArrayLiteralExp *es = (ArrayLiteralExp *)e; - - es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); - e = es; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1; - if (e1->op == TOKarrayliteral) - { es1 = (ArrayLiteralExp *)e1; - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - } - else - { - es1 = new ArrayLiteralExp(e1->loc, e2); - } - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e2->op == TOKarrayliteral && - e2->type->toBasetype()->nextOf()->equals(e1->type)) - { - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); - es2->elements->shift(e1); - e = es2; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKnull && e2->op == TOKstring) - { - t = e1->type; - e = e2; - goto L1; - } - else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; - t = e2->type; - L1: - Type *tb = t->toBasetype(); - if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); - expressions->push(e); - e = new ArrayLiteralExp(loc, expressions); - e->type = t; - } - if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); - e = se->castTo(NULL, type); - } - } - return e; -} - -Expression *Ptr(Type *type, Expression *e1) -{ - //printf("Ptr(e1 = %s)\n", e1->toChars()); - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; - unsigned offset = ae->e2->toInteger(); - Expression *e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - return EXP_CANT_INTERPRET; -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include +#include + +#if __DMC__ +#include +#endif + +#include "rmem.h" +#include "root.h" +#include "port.h" + +#include "mtype.h" +#include "expression.h" +#include "aggregate.h" +#include "declaration.h" + +#if __FreeBSD__ +#define fmodl fmod // hack for now, fix later +#endif + +#define LOG 0 + +Expression *expType(Type *type, Expression *e) +{ + if (type != e->type) + { + e = e->copy(); + e->type = type; + } + return e; +} + +/* ================================== isConst() ============================== */ + +int Expression::isConst() +{ + //printf("Expression::isConst(): %s\n", toChars()); + return 0; +} + +int IntegerExp::isConst() +{ + return 1; +} + +int RealExp::isConst() +{ + return 1; +} + +int ComplexExp::isConst() +{ + return 1; +} + +int NullExp::isConst() +{ + return 0; +} + +int SymOffExp::isConst() +{ + return 2; +} + +/* =============================== constFold() ============================== */ + +/* The constFold() functions were redundant with the optimize() ones, + * and so have been folded in with them. + */ + +/* ========================================================================== */ + +Expression *Neg(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->type->isreal()) + { + e = new RealExp(loc, -e1->toReal(), type); + } + else if (e1->type->isimaginary()) + { + e = new RealExp(loc, -e1->toImaginary(), type); + } + else if (e1->type->iscomplex()) + { + e = new ComplexExp(loc, -e1->toComplex(), type); + } + else + e = new IntegerExp(loc, -e1->toInteger(), type); + return e; +} + +Expression *Com(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, ~e1->toInteger(), type); + return e; +} + +Expression *Not(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(0), type); + return e; +} + +Expression *Bool(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->isBool(1), type); + return e; +} + +Expression *Add(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + +#if LOG + printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); +#endif + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() + e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 + r2); break; + case 0+1: v = r1 + i2 * I; break; + case 0+2: v = r1 + c2; break; + case 3+0: v = i1 * I + r2; break; + case 3+1: v = (complex_t) ((i1 + i2) * I); break; + case 3+2: v = i1 * I + c2; break; + case 6+0: v = c1 + r2; break; + case 6+1: v = c1 + i2 * I; break; + case 6+2: v = c1 + c2; break; +#else + case 0+0: v = complex_t(r1 + r2, 0); break; + case 0+1: v = complex_t(r1, i2); break; + case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; + case 3+0: v = complex_t(r2, i1); break; + case 3+1: v = complex_t(0, i1 + i2); break; + case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; + case 6+2: v = c1 + c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); + e->type = type; + } + else if (e2->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e2; + e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); + e->type = type; + } + else + e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); + return e; +} + + +Expression *Min(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isreal()) + { + e = new RealExp(loc, e1->toReal() - e2->toReal(), type); + } + else if (type->isimaginary()) + { + e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); + } + else if (type->iscomplex()) + { + // This rigamarole is necessary so that -0.0 doesn't get + // converted to +0.0 by doing an extraneous add with +0.0 + complex_t c1; + real_t r1; + real_t i1; + + complex_t c2; + real_t r2; + real_t i2; + + complex_t v; + int x; + + if (e1->type->isreal()) + { r1 = e1->toReal(); + x = 0; + } + else if (e1->type->isimaginary()) + { i1 = e1->toImaginary(); + x = 3; + } + else + { c1 = e1->toComplex(); + x = 6; + } + + if (e2->type->isreal()) + { r2 = e2->toReal(); + } + else if (e2->type->isimaginary()) + { i2 = e2->toImaginary(); + x += 1; + } + else + { c2 = e2->toComplex(); + x += 2; + } + + switch (x) + { +#if __DMC__ + case 0+0: v = (complex_t) (r1 - r2); break; + case 0+1: v = r1 - i2 * I; break; + case 0+2: v = r1 - c2; break; + case 3+0: v = i1 * I - r2; break; + case 3+1: v = (complex_t) ((i1 - i2) * I); break; + case 3+2: v = i1 * I - c2; break; + case 6+0: v = c1 - r2; break; + case 6+1: v = c1 - i2 * I; break; + case 6+2: v = c1 - c2; break; +#else + case 0+0: v = complex_t(r1 - r2, 0); break; + case 0+1: v = complex_t(r1, -i2); break; + case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; + case 3+0: v = complex_t(-r2, i1); break; + case 3+1: v = complex_t(0, i1 - i2); break; + case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; + case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; + case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; + case 6+2: v = c1 - c2; break; +#endif + default: assert(0); + } + e = new ComplexExp(loc, v, type); + } + else if (e1->op == TOKsymoff) + { + SymOffExp *soe = (SymOffExp *)e1; + e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); + e->type = type; + } + else + { + e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); + } + return e; +} + +Expression *Mul(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + if (e1->type->isreal()) + { +#if __DMC__ + c = e1->toReal() * e2->toComplex(); +#else + r = e1->toReal(); + c = e2->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e1->type->isimaginary()) + { +#if __DMC__ + c = e1->toImaginary() * I * e2->toComplex(); +#else + r = e1->toImaginary(); + c = e2->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else if (e2->type->isreal()) + { +#if __DMC__ + c = e2->toReal() * e1->toComplex(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(r * creall(c), r * cimagl(c)); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + c = e1->toComplex() * e2->toImaginary() * I; +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(-r * cimagl(c), r * creall(c)); +#endif + } + else + c = e1->toComplex() * e2->toComplex(); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { + e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); + } + return e; +} + +Expression *Div(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { complex_t c; +#ifdef IN_GCC + real_t r; +#else + d_float80 r; +#endif + + //e1->type->print(); + //e2->type->print(); + if (e2->type->isreal()) + { + if (e1->type->isreal()) + { + e = new RealExp(loc, e1->toReal() / e2->toReal(), type); + return e; + } +#if __DMC__ + //r = e2->toReal(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / e2->toReal(); +#else + r = e2->toReal(); + c = e1->toComplex(); + c = complex_t(creall(c) / r, cimagl(c) / r); +#endif + } + else if (e2->type->isimaginary()) + { +#if __DMC__ + //r = e2->toImaginary(); + //c = e1->toComplex(); + //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); + + c = e1->toComplex() / (e2->toImaginary() * I); +#else + r = e2->toImaginary(); + c = e1->toComplex(); + c = complex_t(cimagl(c) / r, -creall(c) / r); +#endif + } + else + { + c = e1->toComplex() / e2->toComplex(); + } + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) / ((d_uns64) n2); + else + n = n1 / n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Mod(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + if (type->isfloating()) + { + complex_t c; + + if (e2->type->isreal()) + { real_t r2 = e2->toReal(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), r2) + fmodl(e1->toImaginary(), r2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); +#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) + // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! + // arm also doesn't like fmodl + c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); +#else + c = complex_t(fmodl(e1->toReal(), r2), fmodl(e1->toImaginary(), r2)); +#endif + } + else if (e2->type->isimaginary()) + { real_t i2 = e2->toImaginary(); + +#ifdef __DMC__ + c = fmodl(e1->toReal(), i2) + fmodl(e1->toImaginary(), i2) * I; +#elif defined(IN_GCC) + c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); +#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) + // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! + // arm also doesn't like fmodl + c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); +#else + c = complex_t(fmodl(e1->toReal(), i2), fmodl(e1->toImaginary(), i2)); +#endif + } + else + assert(0); + + if (type->isreal()) + e = new RealExp(loc, creall(c), type); + else if (type->isimaginary()) + e = new RealExp(loc, cimagl(c), type); + else if (type->iscomplex()) + e = new ComplexExp(loc, c, type); + else + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + sinteger_t n; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (n2 == 0) + { e2->error("divide by 0"); + e2 = new IntegerExp(loc, 1, e2->type); + n2 = 1; + } + if (e1->type->isunsigned() || e2->type->isunsigned()) + n = ((d_uns64) n1) % ((d_uns64) n2); + else + n = n1 % n2; + e = new IntegerExp(loc, n, type); + } + return e; +} + +Expression *Shl(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); + return e; +} + +Expression *Shr(Type *type, Expression *e1, Expression *e2) +{ + Loc loc = e1->loc; + + dinteger_t value = e1->toInteger(); + unsigned count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + value = (d_int8)(value) >> count; + break; + + case Tuns8: + value = (d_uns8)(value) >> count; + break; + + case Tint16: + value = (d_int16)(value) >> count; + break; + + case Tuns16: + value = (d_uns16)(value) >> count; + break; + + case Tint32: + value = (d_int32)(value) >> count; + break; + + case Tuns32: + value = (d_uns32)(value) >> count; + break; + + case Tint64: + value = (d_int64)(value) >> count; + break; + + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + case Terror: + return e1; + + default: + assert(0); + } + Expression *e = new IntegerExp(loc, value, type); + return e; +} + +Expression *Ushr(Type *type, Expression *e1, Expression *e2) +{ + Loc loc = e1->loc; + + dinteger_t value = e1->toInteger(); + unsigned count = e2->toInteger(); + switch (e1->type->toBasetype()->ty) + { + case Tint8: + case Tuns8: + assert(0); // no way to trigger this + value = (value & 0xFF) >> count; + break; + + case Tint16: + case Tuns16: + assert(0); // no way to trigger this + value = (value & 0xFFFF) >> count; + break; + + case Tint32: + case Tuns32: + value = (value & 0xFFFFFFFF) >> count; + break; + + case Tint64: + case Tuns64: + value = (d_uns64)(value) >> count; + break; + + case Terror: + return e1; + + default: + assert(0); + } + Expression *e = new IntegerExp(loc, value, type); + return e; +} + +Expression *And(Type *type, Expression *e1, Expression *e2) +{ + Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); + return e; +} + +Expression *Or(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); + return e; +} + +Expression *Xor(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + */ +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + int cmp; + real_t r1; + real_t r2; + + //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + assert(op == TOKequal || op == TOKnotequal); + + if (e1->op == TOKnull) + { + if (e2->op == TOKnull) + cmp = 1; + else if (e2->op == TOKstring) + { StringExp *es2 = (StringExp *)e2; + cmp = (0 == es2->len); + } + else if (e2->op == TOKarrayliteral) + { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + cmp = !es2->elements || (0 == es2->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e2->op == TOKnull) + { + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + cmp = (0 == es1->len); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + cmp = !es1->elements || (0 == es1->elements->dim); + } + else + return EXP_CANT_INTERPRET; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + + if (es1->sz != es2->sz) + { + assert(global.errors); + return EXP_CANT_INTERPRET; + } + if (es1->len == es2->len && + memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) + cmp = 1; + else + cmp = 0; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { // Swap operands and use common code + Expression *e = e1; + e1 = e2; + e2 = e; + goto Lsa; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral) + { + Lsa: + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t dim1 = es1->len; + size_t dim2 = es2->elements ? es2->elements->dim : 0; + if (dim1 != dim2) + cmp = 0; + else + { + for (size_t i = 0; i < dim1; i++) + { + uinteger_t c = es1->charAt(i); + Expression *ee2 = (Expression *)es2->elements->data[i]; + if (ee2->isConst() != 1) + return EXP_CANT_INTERPRET; + cmp = (c == ee2->toInteger()); + if (cmp == 0) + break; + } + } + } + else if (e1->op == TOKstructliteral && e2->op == TOKstructliteral) + { StructLiteralExp *es1 = (StructLiteralExp *)e1; + StructLiteralExp *es2 = (StructLiteralExp *)e2; + + if (es1->sd != es2->sd) + cmp = 0; + else if ((!es1->elements || !es1->elements->dim) && + (!es2->elements || !es2->elements->dim)) + cmp = 1; // both arrays are empty + else if (!es1->elements || !es2->elements) + cmp = 0; + else if (es1->elements->dim != es2->elements->dim) + cmp = 0; + else + { + cmp = 1; + for (size_t i = 0; i < es1->elements->dim; i++) + { Expression *ee1 = (Expression *)es1->elements->data[i]; + Expression *ee2 = (Expression *)es2->elements->data[i]; + + if (ee1 == ee2) + continue; + if (!ee1 || !ee2) + { cmp = 0; + break; + } + Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); + if (v == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + cmp = v->toInteger(); + if (cmp == 0) + break; + } + } + } +#if 0 // Should handle this + else if (e1->op == TOKarrayliteral && e2->op == TOKstring) + { + } +#endif + else if (e1->isConst() != 1 || e2->isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + cmp = (r1 == r2); +#else + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + cmp = 0; + } + else + { + cmp = (r1 == r2); + } +#endif + } + else if (e1->type->iscomplex()) + { + cmp = e1->toComplex() == e2->toComplex(); + } + else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer) + { + cmp = (e1->toInteger() == e2->toInteger()); + } + else + return EXP_CANT_INTERPRET; + if (op == TOKnotequal) + cmp ^= 1; + e = new IntegerExp(loc, cmp, type); + return e; +} + +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ + Loc loc = e1->loc; + int cmp; + + if (e1->op == TOKnull) + { + cmp = (e2->op == TOKnull); + } + else if (e2->op == TOKnull) + { + cmp = 0; + } + else if (e1->op == TOKsymoff && e2->op == TOKsymoff) + { + SymOffExp *es1 = (SymOffExp *)e1; + SymOffExp *es2 = (SymOffExp *)e2; + + cmp = (es1->var == es2->var && es1->offset == es2->offset); + } + else if (e1->isConst() == 1 && e2->isConst() == 1) + return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, + type, e1, e2); + else + assert(0); + if (op == TOKnotidentity) + cmp ^= 1; + return new IntegerExp(loc, cmp, type); +} + + +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + dinteger_t n; + real_t r1; + real_t r2; + + //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + + if (e1->op == TOKstring && e2->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + size_t sz = es1->sz; + assert(sz == es2->sz); + + size_t len = es1->len; + if (es2->len < len) + len = es2->len; + + int cmp = memcmp(es1->string, es2->string, sz * len); + if (cmp == 0) + cmp = es1->len - es2->len; + + switch (op) + { + case TOKlt: n = cmp < 0; break; + case TOKle: n = cmp <= 0; break; + case TOKgt: n = cmp > 0; break; + case TOKge: n = cmp >= 0; break; + + case TOKleg: n = 1; break; + case TOKlg: n = cmp != 0; break; + case TOKunord: n = 0; break; + case TOKue: n = cmp == 0; break; + case TOKug: n = cmp > 0; break; + case TOKuge: n = cmp >= 0; break; + case TOKul: n = cmp < 0; break; + case TOKule: n = cmp <= 0; break; + + default: + assert(0); + } + } + else if (e1->isConst() != 1 || e2->isConst() != 1) + return EXP_CANT_INTERPRET; + else if (e1->type->isreal()) + { + r1 = e1->toReal(); + r2 = e2->toReal(); + goto L1; + } + else if (e1->type->isimaginary()) + { + r1 = e1->toImaginary(); + r2 = e2->toImaginary(); + L1: +#if __DMC__ + // DMC is the only compiler I know of that handles NAN arguments + // correctly in comparisons. + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = r1 <>= r2; break; + case TOKlg: n = r1 <> r2; break; + case TOKunord: n = r1 !<>= r2; break; + case TOKue: n = r1 !<> r2; break; + case TOKug: n = r1 !<= r2; break; + case TOKuge: n = r1 !< r2; break; + case TOKul: n = r1 !>= r2; break; + case TOKule: n = r1 !> r2; break; + + default: + assert(0); + } +#else + // Don't rely on compiler, handle NAN arguments separately + if (Port::isNan(r1) || Port::isNan(r2)) // if unordered + { + switch (op) + { + case TOKlt: n = 0; break; + case TOKle: n = 0; break; + case TOKgt: n = 0; break; + case TOKge: n = 0; break; + + case TOKleg: n = 0; break; + case TOKlg: n = 0; break; + case TOKunord: n = 1; break; + case TOKue: n = 1; break; + case TOKug: n = 1; break; + case TOKuge: n = 1; break; + case TOKul: n = 1; break; + case TOKule: n = 1; break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = r1 < r2; break; + case TOKle: n = r1 <= r2; break; + case TOKgt: n = r1 > r2; break; + case TOKge: n = r1 >= r2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = r1 != r2; break; + case TOKunord: n = 0; break; + case TOKue: n = r1 == r2; break; + case TOKug: n = r1 > r2; break; + case TOKuge: n = r1 >= r2; break; + case TOKul: n = r1 < r2; break; + case TOKule: n = r1 <= r2; break; + + default: + assert(0); + } + } +#endif + } + else if (e1->type->iscomplex()) + { + assert(0); + } + else + { sinteger_t n1; + sinteger_t n2; + + n1 = e1->toInteger(); + n2 = e2->toInteger(); + if (e1->type->isunsigned() || e2->type->isunsigned()) + { + switch (op) + { + case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + + case TOKleg: n = 1; break; + case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; + case TOKunord: n = 0; break; + case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; + case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; + case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; + case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; + case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; + + default: + assert(0); + } + } + else + { + switch (op) + { + case TOKlt: n = n1 < n2; break; + case TOKle: n = n1 <= n2; break; + case TOKgt: n = n1 > n2; break; + case TOKge: n = n1 >= n2; break; + + case TOKleg: n = 1; break; + case TOKlg: n = n1 != n2; break; + case TOKunord: n = 0; break; + case TOKue: n = n1 == n2; break; + case TOKug: n = n1 > n2; break; + case TOKuge: n = n1 >= n2; break; + case TOKul: n = n1 < n2; break; + case TOKule: n = n1 <= n2; break; + + default: + assert(0); + } + } + } + e = new IntegerExp(loc, n, type); + return e; +} + +/* Also returns EXP_CANT_INTERPRET if cannot be computed. + * to: type to cast to + * type: type to paint the result + */ + +Expression *Cast(Type *type, Type *to, Expression *e1) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); + //printf("\te1->type = %s\n", e1->type->toChars()); + if (e1->type->equals(type) && type->equals(to)) + return e1; + if (e1->type->implicitConvTo(to) >= MATCHconst || + to->implicitConvTo(e1->type) >= MATCHconst) + return expType(to, e1); + + Type *tb = to->toBasetype(); + Type *typeb = type->toBasetype(); + + /* Allow casting from one string type to another + */ + if (e1->op == TOKstring) + { + if (tb->ty == Tarray && typeb->ty == Tarray && + tb->nextOf()->size() == typeb->nextOf()->size()) + { + return expType(to, e1); + } + } + + if (e1->op == TOKarrayliteral && typeb == tb) + return e1; + + if (e1->isConst() != 1) + return EXP_CANT_INTERPRET; + + if (tb->ty == Tbool) + e = new IntegerExp(loc, e1->toInteger() != 0, type); + else if (type->isintegral()) + { + if (e1->type->isfloating()) + { dinteger_t result; + real_t r = e1->toReal(); + + switch (typeb->ty) + { + case Tint8: result = (d_int8)r; break; + case Tchar: + case Tuns8: result = (d_uns8)r; break; + case Tint16: result = (d_int16)r; break; + case Twchar: + case Tuns16: result = (d_uns16)r; break; + case Tint32: result = (d_int32)r; break; + case Tdchar: + case Tuns32: result = (d_uns32)r; break; + case Tint64: result = (d_int64)r; break; + case Tuns64: result = (d_uns64)r; break; + default: + assert(0); + } + + e = new IntegerExp(loc, result, type); + } + else if (type->isunsigned()) + e = new IntegerExp(loc, e1->toUInteger(), type); + else + e = new IntegerExp(loc, e1->toInteger(), type); + } + else if (tb->isreal()) + { real_t value = e1->toReal(); + + e = new RealExp(loc, value, type); + } + else if (tb->isimaginary()) + { real_t value = e1->toImaginary(); + + e = new RealExp(loc, value, type); + } + else if (tb->iscomplex()) + { complex_t value = e1->toComplex(); + + e = new ComplexExp(loc, value, type); + } + else if (tb->isscalar()) + e = new IntegerExp(loc, e1->toInteger(), type); + else if (tb->ty == Tvoid) + e = EXP_CANT_INTERPRET; + else if (tb->ty == Tstruct && e1->op == TOKint64) + { // Struct = 0; + StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); + assert(sd); + Expressions *elements = new Expressions; + for (size_t i = 0; i < sd->fields.dim; i++) + { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + + Expression *exp = new IntegerExp(0); + exp = Cast(v->type, v->type, exp); + if (exp == EXP_CANT_INTERPRET) + return exp; + elements->push(exp); + } + e = new StructLiteralExp(loc, sd, elements); + e->type = type; + } + else + { + if (type != Type::terror) + error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); + e = new ErrorExp(); + } + return e; +} + + +Expression *ArrayLength(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + + e = new IntegerExp(loc, es1->len, type); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + size_t dim; + + dim = ale->elements ? ale->elements->dim : 0; + e = new IntegerExp(loc, dim, type); + } + else if (e1->op == TOKassocarrayliteral) + { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; + size_t dim = ale->keys->dim; + + e = new IntegerExp(loc, dim, type); + } + else + e = EXP_CANT_INTERPRET; + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Index(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + assert(e1->type); + if (e1->op == TOKstring && e2->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t i = e2->toInteger(); + + if (i >= es1->len) + e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); + else + { unsigned value = es1->charAt(i); + e = new IntegerExp(loc, value, type); + } + } + else if (e1->type->toBasetype()->ty == Tsarray && e2->op == TOKint64) + { TypeSArray *tsa = (TypeSArray *)e1->type->toBasetype(); + uinteger_t length = tsa->dim->toInteger(); + uinteger_t i = e2->toInteger(); + + if (i >= length) + { e2->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); + } + else if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) + { + uinteger_t i = e2->toInteger(); + + if (e1->op == TOKarrayliteral && !e1->checkSideEffect(2)) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + if (i >= ale->elements->dim) + { e2->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); + } + else + { e = (Expression *)ale->elements->data[i]; + e->type = type; + } + } + } + else if (e1->op == TOKassocarrayliteral && !e1->checkSideEffect(2)) + { + AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e1; + /* Search the keys backwards, in case there are duplicate keys + */ + for (size_t i = ae->keys->dim; i;) + { + i--; + Expression *ekey = (Expression *)ae->keys->data[i]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); + if (ex == EXP_CANT_INTERPRET) + return ex; + if (ex->isBool(TRUE)) + { e = (Expression *)ae->values->data[i]; + e->type = type; + break; + } + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + +#if LOG + printf("Slice()\n"); + if (lwr) + { printf("\te1 = %s\n", e1->toChars()); + printf("\tlwr = %s\n", lwr->toChars()); + printf("\tupr = %s\n", upr->toChars()); + } +#endif + if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->len || ilwr > iupr) + e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { dinteger_t value; + void *s; + size_t len = iupr - ilwr; + int sz = es1->sz; + StringExp *es; + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, (unsigned char *)es1->string + ilwr * sz, len * sz); + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len, es1->postfix); + es->sz = sz; + es->committed = 1; + es->type = type; + e = es; + } + } + else if (e1->op == TOKarrayliteral && + lwr->op == TOKint64 && upr->op == TOKint64 && + !e1->checkSideEffect(2)) + { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + uinteger_t ilwr = lwr->toInteger(); + uinteger_t iupr = upr->toInteger(); + + if (iupr > es1->elements->dim || ilwr > iupr) + e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); + else + { + Expressions *elements = new Expressions(); + elements->setDim(iupr - ilwr); + memcpy(elements->data, + es1->elements->data + ilwr, + (iupr - ilwr) * sizeof(es1->elements->data[0])); + e = new ArrayLiteralExp(e1->loc, elements); + e->type = type; + } + } + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Cat(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + Type *t; + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + + //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars()); + + if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) + { e = e2; + goto L2; + } + else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) + { e = e1; + L2: + Type *tn = e->type->toBasetype(); + if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) + { + // Create a StringExp + void *s; + StringExp *es; + size_t len = 1; + int sz = tn->size(); + dinteger_t v = e->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 1; + e = es; + } + else + { // Create an ArrayLiteralExp + Expressions *elements = new Expressions(); + elements->push(e); + e = new ArrayLiteralExp(e->loc, elements); + } + e->type = type; + return e; + } + else if (e1->op == TOKstring && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = es1->len + es2->len; + int sz = es1->sz; + + if (sz != es2->sz) + { + /* Can happen with: + * auto s = "foo"d ~ "bar"c; + */ + assert(global.errors); + return e; + } + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed | es2->committed; + if (es1->committed) + t = es1->type; + else + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKstring && e2->op == TOKarrayliteral && + t2->nextOf()->isintegral()) + { + // Concatenate the strings + StringExp *es1 = (StringExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + size_t len = es1->len + es2->elements->dim; + int sz = es1->sz; + + void *s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + for (int i = 0; i < es2->elements->dim; i++) + { Expression *es2e = (Expression *)es2->elements->data[i]; + if (es2e->op != TOKint64) + return EXP_CANT_INTERPRET; + dinteger_t v = es2e->toInteger(); + memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); + } + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + StringExp *es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = 0; //es1->committed; + es->type = type; + e = es; + } + else if (e1->op == TOKstring && e2->op == TOKint64) + { + // Concatenate the strings + void *s; + StringExp *es1 = (StringExp *)e1; + StringExp *es; + Type *t; + size_t len = es1->len + 1; + int sz = es1->sz; + dinteger_t v = e2->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy(s, es1->string, es1->len * sz); + memcpy((unsigned char *)s + es1->len * sz, &v, sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es1->committed; + t = es1->type; + es->type = type; + e = es; + } + else if (e1->op == TOKint64 && e2->op == TOKstring) + { + // Concatenate the strings + void *s; + StringExp *es2 = (StringExp *)e2; + StringExp *es; + Type *t; + size_t len = 1 + es2->len; + int sz = es2->sz; + dinteger_t v = e1->toInteger(); + + s = mem.malloc((len + 1) * sz); + memcpy((unsigned char *)s, &v, sz); + memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); + + // Add terminating 0 + memset((unsigned char *)s + len * sz, 0, sz); + + es = new StringExp(loc, s, len); + es->sz = sz; + es->committed = es2->committed; + t = es2->type; + es->type = type; + e = es; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + // Concatenate the arrays + ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->insert(es1->elements->dim, es2->elements); + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e1->op == TOKarrayliteral && e2->op == TOKnull && + t1->nextOf()->equals(t2->nextOf())) + { + e = e1; + goto L3; + } + else if (e1->op == TOKnull && e2->op == TOKarrayliteral && + t1->nextOf()->equals(t2->nextOf())) + { + e = e2; + L3: + // Concatenate the array with null + ArrayLiteralExp *es = (ArrayLiteralExp *)e; + + es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); + e = es; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && + e1->type->toBasetype()->nextOf()->equals(e2->type)) + { + ArrayLiteralExp *es1; + if (e1->op == TOKarrayliteral) + { es1 = (ArrayLiteralExp *)e1; + es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); + es1->elements->push(e2); + } + else + { + es1 = new ArrayLiteralExp(e1->loc, e2); + } + e = es1; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e2->op == TOKarrayliteral && + e2->type->toBasetype()->nextOf()->equals(e1->type)) + { + ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; + + es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); + es2->elements->shift(e1); + e = es2; + + if (type->toBasetype()->ty == Tsarray) + { + e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); + e->type = e->type->semantic(loc, NULL); + } + else + e->type = type; + } + else if (e1->op == TOKnull && e2->op == TOKstring) + { + t = e1->type; + e = e2; + goto L1; + } + else if (e1->op == TOKstring && e2->op == TOKnull) + { e = e1; + t = e2->type; + L1: + Type *tb = t->toBasetype(); + if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) + { Expressions *expressions = new Expressions(); + expressions->push(e); + e = new ArrayLiteralExp(loc, expressions); + e->type = t; + } + if (!e->type->equals(type)) + { StringExp *se = (StringExp *)e->copy(); + e = se->castTo(NULL, type); + } + } + return e; +} + +Expression *Ptr(Type *type, Expression *e1) +{ + //printf("Ptr(e1 = %s)\n", e1->toChars()); + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + if (ade->e1->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ade->e1; + unsigned offset = ae->e2->toInteger(); + Expression *e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + return EXP_CANT_INTERPRET; +} + diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c index d2755593..cd34c708 100644 --- a/dmd2/cppmangle.c +++ b/dmd2/cppmangle.c @@ -1,381 +1,389 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "mars.h" -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" - -#if CPP_MANGLE - -/* Do mangling for C++ linkage. - * Follows Itanium C++ ABI 1.86 - * No attempt is made to support mangling of templates, operator - * overloading, or special functions. - * - * So why don't we use the C++ ABI for D name mangling? - * Because D supports a lot of things (like modules) that the C++ - * ABI has no concept of. These affect every D mangled name, - * so nothing would be compatible anyway. - */ - -struct CppMangleState -{ - static Array components; - - int substitute(OutBuffer *buf, void *p); -}; - -Array CppMangleState::components; - - -void writeBase36(OutBuffer *buf, unsigned i) -{ - if (i >= 36) - { - writeBase36(buf, i / 36); - i %= 36; - } - if (i < 10) - buf->writeByte(i + '0'); - else if (i < 36) - buf->writeByte(i - 10 + 'A'); - else - assert(0); -} - -int CppMangleState::substitute(OutBuffer *buf, void *p) -{ - for (size_t i = 0; i < components.dim; i++) - { - if (p == components.data[i]) - { - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf->writeByte('S'); - if (i) - writeBase36(buf, i - 1); - buf->writeByte('_'); - return 1; - } - } - components.push(p); - return 0; -} - -void source_name(OutBuffer *buf, Dsymbol *s) -{ - char *name = s->ident->toChars(); - buf->printf("%d%s", strlen(name), name); -} - -void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) -{ - if (!cms->substitute(buf, s)) - { - Dsymbol *p = s->toParent(); - if (p && !p->isModule()) - { - prefix_name(buf, cms, p); - } - source_name(buf, s); - } -} - -void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) -{ - Dsymbol *p = s->toParent(); - if (p && !p->isModule()) - { - buf->writeByte('N'); - - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd->isConst()) - buf->writeByte('K'); - - prefix_name(buf, cms, p); - source_name(buf, s); - - buf->writeByte('E'); - } - else - source_name(buf, s); -} - - -char *cpp_mangle(Dsymbol *s) -{ - /* - * ::= _Z - * ::= - * ::= - * ::= - */ - - CppMangleState cms; - memset(&cms, 0, sizeof(cms)); - cms.components.setDim(0); - - OutBuffer buf; -#if MACHOBJ - buf.writestring("__Z"); -#else - buf.writestring("_Z"); -#endif - - cpp_mangle_name(&buf, &cms, s); - - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { // add - TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - Argument::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs); - } - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ============= Type Encodings ============================================= */ - -void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - /* Make this the 'vendor extended type' when there is no - * C++ analog. - * u - */ - if (!cms->substitute(buf, this)) - { assert(deco); - buf->printf("u%d%s", strlen(deco), deco); - } -} - -void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ char c; - char p = 0; - - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short - * t unsigned short - * i int - * j unsigned int - * l long - * m unsigned long - * x long long, __int64 - * y unsigned long long, __int64 - * n __int128 - * o unsigned __int128 - * f float - * d double - * e long double, __float80 - * g __float128 - * z ellipsis - * u # vendor extended type - */ - - switch (ty) - { - case Tvoid: c = 'v'; break; - case Tint8: c = 'a'; break; - case Tuns8: c = 'h'; break; - case Tint16: c = 's'; break; - case Tuns16: c = 't'; break; - case Tint32: c = 'i'; break; - case Tuns32: c = 'j'; break; - case Tfloat32: c = 'f'; break; - case Tint64: c = 'x'; break; - case Tuns64: c = 'y'; break; - case Tfloat64: c = 'd'; break; - case Tfloat80: c = 'e'; break; - case Tbool: c = 'b'; break; - case Tchar: c = 'c'; break; - case Twchar: c = 't'; break; - case Tdchar: c = 'w'; break; - - case Timaginary32: p = 'G'; c = 'f'; break; - case Timaginary64: p = 'G'; c = 'd'; break; - case Timaginary80: p = 'G'; c = 'e'; break; - case Tcomplex32: p = 'C'; c = 'f'; break; - case Tcomplex64: p = 'C'; c = 'd'; break; - case Tcomplex80: p = 'C'; c = 'e'; break; - - default: assert(0); - } - if (p) - { - if (cms->substitute(buf, this)) - return; - buf->writeByte(p); - } - buf->writeByte(c); -} - - -void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->printf("A%ju_", dim ? dim->toInteger() : 0); - next->toCppMangle(buf, cms); - } -} - -void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->writeByte('P'); - next->toCppMangle(buf, cms); - } -} - - -void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->writeByte('R'); - next->toCppMangle(buf, cms); - } -} - - -void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ /* - * ::= F [Y] E - * ::= + - * # types are possible return type, then parameter types - */ - - /* ABI says: - "The type of a non-static member function is considered to be different, - for the purposes of substitution, from the type of a namespace-scope or - static member function whose type appears similar. The types of two - non-static member functions are considered to be different, for the - purposes of substitution, if the functions are members of different - classes. In other words, for the purposes of substitution, the class of - which the function is a member is considered part of the type of - function." - - BUG: Right now, types of functions are never merged, so our simplistic - component matcher always finds them to be different. - We should use Type::equals on these, and use different - TypeFunctions for non-static member functions, and non-static - member functions of different classes. - */ - if (!cms->substitute(buf, this)) - { - buf->writeByte('F'); - if (linkage == LINKc) - buf->writeByte('Y'); - next->toCppMangle(buf, cms); - Argument::argsCppMangle(buf, cms, parameters, varargs); - buf->writeByte('E'); - } -} - - -void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); -} - - -void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); -} - - -void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->writeByte('P'); - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); - } -} - - - -void Argument::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Arguments *arguments, int varargs) -{ int n = 0; - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - Type *t = arg->type; - if (arg->storageClass & (STCout | STCref)) - t = t->referenceTo(); - else if (arg->storageClass & STClazy) - { // Mangle as delegate - Type *td = new TypeFunction(NULL, t, 0, LINKd); - td = new TypeDelegate(td); - t = t->merge(); - } - if (t->ty == Tsarray) - { // Mangle static arrays as pointers - t = t->pointerTo(); - } - t->toCppMangle(buf, cms); - - n++; - } - } - if (varargs) - buf->writestring("z"); - else if (!n) - buf->writeByte('v'); // encode ( ) arguments -} - - -#endif - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include + +#include "mars.h" +#include "dsymbol.h" +#include "mtype.h" +#include "scope.h" +#include "init.h" +#include "expression.h" +#include "attrib.h" +#include "declaration.h" +#include "template.h" +#include "id.h" +#include "enum.h" +#include "import.h" +#include "aggregate.h" + +#if CPP_MANGLE + +/* Do mangling for C++ linkage. + * Follows Itanium C++ ABI 1.86 + * No attempt is made to support mangling of templates, operator + * overloading, or special functions. + * + * So why don't we use the C++ ABI for D name mangling? + * Because D supports a lot of things (like modules) that the C++ + * ABI has no concept of. These affect every D mangled name, + * so nothing would be compatible anyway. + */ + +struct CppMangleState +{ + static Array components; + + int substitute(OutBuffer *buf, void *p); +}; + +Array CppMangleState::components; + + +void writeBase36(OutBuffer *buf, unsigned i) +{ + if (i >= 36) + { + writeBase36(buf, i / 36); + i %= 36; + } + if (i < 10) + buf->writeByte(i + '0'); + else if (i < 36) + buf->writeByte(i - 10 + 'A'); + else + assert(0); +} + +int CppMangleState::substitute(OutBuffer *buf, void *p) +{ + for (size_t i = 0; i < components.dim; i++) + { + if (p == components.data[i]) + { + /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... + */ + buf->writeByte('S'); + if (i) + writeBase36(buf, i - 1); + buf->writeByte('_'); + return 1; + } + } + components.push(p); + return 0; +} + +void source_name(OutBuffer *buf, Dsymbol *s) +{ + char *name = s->ident->toChars(); + buf->printf("%d%s", strlen(name), name); +} + +void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) +{ + if (!cms->substitute(buf, s)) + { + Dsymbol *p = s->toParent(); + if (p && !p->isModule()) + { + prefix_name(buf, cms, p); + } + source_name(buf, s); + } +} + +void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) +{ + Dsymbol *p = s->toParent(); + if (p && !p->isModule()) + { + buf->writeByte('N'); + + FuncDeclaration *fd = s->isFuncDeclaration(); + if (!fd) + { + s->error("C++ static variables not supported"); + } + else + if (fd->isConst()) + buf->writeByte('K'); + + prefix_name(buf, cms, p); + source_name(buf, s); + + buf->writeByte('E'); + } + else + source_name(buf, s); +} + + +char *cpp_mangle(Dsymbol *s) +{ + /* + * ::= _Z + * ::= + * ::= + * ::= + */ + + CppMangleState cms; + memset(&cms, 0, sizeof(cms)); + cms.components.setDim(0); + + OutBuffer buf; +#if MACHOBJ + buf.writestring("__Z"); +#else + buf.writestring("_Z"); +#endif + + cpp_mangle_name(&buf, &cms, s); + + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { // add + TypeFunction *tf = (TypeFunction *)fd->type; + assert(tf->ty == Tfunction); + Parameter::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs); + } + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* ============= Type Encodings ============================================= */ + +void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + /* Make this the 'vendor extended type' when there is no + * C++ analog. + * u + */ + if (!cms->substitute(buf, this)) + { assert(deco); + buf->printf("u%d%s", strlen(deco), deco); + } +} + +void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ char c; + char p = 0; + + /* ABI spec says: + * v void + * w wchar_t + * b bool + * c char + * a signed char + * h unsigned char + * s short + * t unsigned short + * i int + * j unsigned int + * l long + * m unsigned long + * x long long, __int64 + * y unsigned long long, __int64 + * n __int128 + * o unsigned __int128 + * f float + * d double + * e long double, __float80 + * g __float128 + * z ellipsis + * u # vendor extended type + */ + + if (isConst()) + buf->writeByte('K'); + + switch (ty) + { + case Tvoid: c = 'v'; break; + case Tint8: c = 'a'; break; + case Tuns8: c = 'h'; break; + case Tint16: c = 's'; break; + case Tuns16: c = 't'; break; + case Tint32: c = 'i'; break; + case Tuns32: c = 'j'; break; + case Tfloat32: c = 'f'; break; + case Tint64: c = 'x'; break; + case Tuns64: c = 'y'; break; + case Tfloat64: c = 'd'; break; + case Tfloat80: c = 'e'; break; + case Tbool: c = 'b'; break; + case Tchar: c = 'c'; break; + case Twchar: c = 't'; break; + case Tdchar: c = 'w'; break; + + case Timaginary32: p = 'G'; c = 'f'; break; + case Timaginary64: p = 'G'; c = 'd'; break; + case Timaginary80: p = 'G'; c = 'e'; break; + case Tcomplex32: p = 'C'; c = 'f'; break; + case Tcomplex64: p = 'C'; c = 'd'; break; + case Tcomplex80: p = 'C'; c = 'e'; break; + + default: assert(0); + } + if (p) + { + if (cms->substitute(buf, this)) + return; + buf->writeByte(p); + } + buf->writeByte(c); +} + + +void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->printf("A%ju_", dim ? dim->toInteger() : 0); + next->toCppMangle(buf, cms); + } +} + +void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('P'); + next->toCppMangle(buf, cms); + } +} + + +void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('R'); + next->toCppMangle(buf, cms); + } +} + + +void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ /* + * ::= F [Y] E + * ::= + + * # types are possible return type, then parameter types + */ + + /* ABI says: + "The type of a non-static member function is considered to be different, + for the purposes of substitution, from the type of a namespace-scope or + static member function whose type appears similar. The types of two + non-static member functions are considered to be different, for the + purposes of substitution, if the functions are members of different + classes. In other words, for the purposes of substitution, the class of + which the function is a member is considered part of the type of + function." + + BUG: Right now, types of functions are never merged, so our simplistic + component matcher always finds them to be different. + We should use Type::equals on these, and use different + TypeFunctions for non-static member functions, and non-static + member functions of different classes. + */ + if (!cms->substitute(buf, this)) + { + buf->writeByte('F'); + if (linkage == LINKc) + buf->writeByte('Y'); + next->toCppMangle(buf, cms); + Parameter::argsCppMangle(buf, cms, parameters, varargs); + buf->writeByte('E'); + } +} + + +void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); +} + + +void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); +} + + +void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + Type::toCppMangle(buf, cms); +} + + +void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms) +{ + if (!cms->substitute(buf, this)) + { buf->writeByte('P'); + if (!cms->substitute(buf, sym)) + cpp_mangle_name(buf, cms, sym); + } +} + + + +void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs) +{ int n = 0; + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Parameter *arg = (Parameter *)arguments->data[i]; + Type *t = arg->type; + if (arg->storageClass & (STCout | STCref)) + t = t->referenceTo(); + else if (arg->storageClass & STClazy) + { // Mangle as delegate + Type *td = new TypeFunction(NULL, t, 0, LINKd); + td = new TypeDelegate(td); + t = t->merge(); + } + if (t->ty == Tsarray) + { // Mangle static arrays as pointers + t = t->pointerTo(); + } + t->toCppMangle(buf, cms); + + n++; + } + } + if (varargs) + buf->writestring("z"); + else if (!n) + buf->writeByte('v'); // encode ( ) arguments +} + + +#endif + diff --git a/dmd2/declaration.c b/dmd2/declaration.c index 31ad8d64..1afbc35c 100644 --- a/dmd2/declaration.c +++ b/dmd2/declaration.c @@ -1,1754 +1,1953 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; - inuse = 0; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isStaticConstructor() -{ - return FALSE; -} - -int Declaration::isStaticDestructor() -{ - return FALSE; -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isThreadlocal() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (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() && storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && - fd->toParent() == toParent() - ) - { - VarDeclaration *v = isVarDeclaration(); - assert(v); - v->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else - { - const char *p = isStatic() ? "static " : ""; - error(loc, "can only initialize %sconst %s inside %sconstructor", - p, toChars(), p); - } - } - break; - } - } - else - { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign == 0) - { - const char *p = NULL; - if (isConst()) - p = "const"; - else if (isInvariant()) - p = "immutable"; - else if (storage_class & STCmanifest) - p = "enum"; - else if (!t->isAssignable()) - p = "struct with immutable members"; - if (p) - { error(loc, "cannot modify %s", p); - } - } - } -} -#endif - - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -const char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Arguments *args = new Arguments(); - args->setDim(objects->dim); - OutBuffer buf; - for (size_t i = 0; i < objects->dim; i++) - { Type *t = (Type *)objects->data[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Argument *arg = new Argument(STCin, t, id, NULL); -#else - Argument *arg = new Argument(0, t, NULL, NULL); -#endif - args->data[i] = (void *)arg; - } - - tupletype = new TypeTuple(args); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hbasetype = NULL; -#endif - this->sem = 0; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); -#endif - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == 0) - { sem = 1; - basetype = basetype->semantic(loc, sc); - sem = 2; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - storage_class |= sc->stc & STCdeprecated; - } - else if (sem == 1) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == 2) - { sem = 3; - if (init) - { - init = init->semantic(sc, basetype); - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - this->importprot = PROTundefined; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; -#ifdef _DH - this->htype = NULL; - this->haliassym = NULL; -#endif - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("AliasDeclaration::syntaxCopy()\n"); - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); -#endif - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - - if (storage_class & STCconst) - error("cannot be const"); - - storage_class |= sc->stc & STCdeprecated; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s && ((s->getType() && type->equals(s->getType())) || s->isEnumMember())) - goto L2; // it's a symbolic alias - -#if DMDV2 - if (storage_class & STCref) - { // For 'ref' to be attached to function types, and picked - // up by Type::resolve(), it has to go into sc. - sc = sc->push(); - sc->stc |= STCref; - type->resolve(loc, sc, &e, &t, &s); - sc = sc->pop(); - } - else -#endif - type->resolve(loc, sc, &e, &t, &s); - if (s) - { - goto L2; - } - else if (e) - { - // Try to convert Expression to Dsymbol - s = getDsymbol(e); - if (s) - goto L2; - - error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - else if (t) - { - type = t; - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); -#if IN_LLVM - fa->importprot = importprot; -#endif - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, s, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - } - //printf("setting aliassym %p to %p\n", this, s); - aliassym = s; - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (overnext == NULL) - { overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -const char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 10) *(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); - aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); - } - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 && _DH - if (hgs->hdrgen) - { - if (haliassym) - { - buf->writestring(haliassym->toChars()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { - aliassym->toCBuffer(buf, hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; -#ifdef _DH - this->htype = NULL; - this->hinit = NULL; -#endif - this->loc = loc; - offset = 0; - noauto = 0; -#if DMDV1 - nestedref = 0; -#endif - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - value = NULL; - rundtor = NULL; -#if IN_LLVM - aggrIndex = 0; - - // LDC - anonDecl = NULL; - offset2 = 0; - - nakedUse = false; - - availableExternally = true; // assume this unless proven otherwise -#endif -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } -#ifdef _DH - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); -#endif - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ -#if 0 - printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - printf(" type = %s\n", type ? type->toChars() : "null"); - printf(" stc = x%x\n", sc->stc); - printf(" storage_class = x%x\n", storage_class); - printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); -#endif - - storage_class |= sc->stc; - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - type = init->inferType(sc); - inuse--; - inferred = 1; - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - -#if DMDV2 - if (storage_class & STCgshared && global.params.safe && !sc->module->safe) - { - error("__gshared not allowed in safe mode; use shared"); - } -#endif - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Argument::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - Expression *ie = init ? init->toExpression() : NULL; - - for (size_t i = 0; i < nelems; i++) - { Argument *arg = Argument::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - -/* -// removed for LDC since TupleDeclaration::toObj already creates the fields; -// adding them to the scope again leads to duplicates - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } -*/ - Expression *e = new DsymbolExp(loc, v); - exps->data[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - -Lagain: - /* Storage class can modify the type - */ - type = type->addStorageClass(storage_class); - - /* Adjust storage class to reflect type - */ - if (type->isConst()) - { storage_class |= STCconst; - if (type->isShared()) - storage_class |= STCshared; - } - else if (type->isInvariant()) - storage_class |= STCimmutable; - else if (type->isShared()) - storage_class |= STCshared; - - if (isSynchronized()) - { - error("variable %s cannot be synchronized", toChars()); - } - else if (isOverride()) - { - error("override cannot be applied to variable"); - } - else if (isAbstract()) - { - error("abstract cannot be applied to variable"); - } - else if (storage_class & STCfinal) - { - error("final cannot be applied to variable"); - } - - if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared)) - { - } - else - { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); - if (aad) - { -#if DMDV2 - assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); - - if (storage_class & (STCconst | STCimmutable) && init) - { - if (!type->toBasetype()->isTypeBasic()) - storage_class |= STCstatic; - } - else -#endif - aad->addField(sc, this); - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - /* Templates cannot add fields to aggregates - */ - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad = ti->tempdecl->isMember(); - if (ad && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad->toChars()); - } - } - } - -#if DMDV2 - if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && - ident != Id::This) - { - error("only parameters or foreach declarations can be ref"); - } -#endif - - if (type->isauto() && !noauto) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd) - { - error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); - } - - if (!(storage_class & (STCauto | STCscope))) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - if ((isConst() || isInvariant()) && !init && !fd) - { // Initialize by constructor only - storage_class |= STCctorinit; - } - - if (init) - storage_class |= STCinit; // remember we had an explicit initializer - else if (storage_class & STCmanifest) - error("manifest constants must have initializers"); - - enum TOK op = TOKconstruct; - if (!init && !sc->inunion && !isStatic() && fd && - (!(storage_class & (STCfield | STCin | STCforeach | STCparameter)) || (storage_class & STCout)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new AssignExp(loc, e1, e); - e->op = TOKconstruct; - e->type = e1->type; // don't type check this, it would fail - init = new ExpInitializer(loc, e); - return; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - // Default initializer is always a blit - op = TOKblit; - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - init = ai->toAssocArrayInitializer(); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - // See if initializer is a NewExp that can be allocated on the stack - if (ei && isScope() && ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && - !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) && - !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type); - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - int dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); -#if DMDV2 - /* Look to see if initializer is a call to the constructor - */ - StructDeclaration *sd = ((TypeStruct *)t)->sym; - if (sd->ctor && // there are constructors - ei->exp->type->ty == Tstruct && // rvalue is the same struct - ((TypeStruct *)ei->exp->type)->sym == sd && - ei->exp->op == TOKstar) - { - /* Look for form of constructor call which is: - * *__ctmp.ctor(arguments...) - */ - PtrExp *pe = (PtrExp *)ei->exp; - if (pe->e1->op == TOKcall) - { CallExp *ce = (CallExp *)pe->e1; - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { /* It's a constructor call, currently constructing - * a temporary __ctmp. - */ - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; - e->type = t; - ei->exp = new CommaExp(loc, e, ei->exp); - - /* Replace __ctmp being constructed with e1 - */ - dve->e1 = e1; - return; - } - } - } - } -#endif - if (!ei->exp->implicitConvTo(type)) - { Type *ti = ei->exp->type->toBasetype(); - // Don't cast away invariant or mutability in initializer - if (!(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) - ei->exp = new CastExp(loc, ei->exp, type); - } - } - ei->exp = new AssignExp(loc, e1, ei->exp); - ei->exp->op = op; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type); - } - } - else if (storage_class & (STCconst | STCimmutable | STCmanifest) || - type->isConst() || type->isInvariant()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.errors; - global.gag++; - //printf("+gag\n"); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type); - } - inuse--; - global.gag--; - //printf("-gag\n"); - if (errors != global.errors) // if errors happened - { - if (global.gag == 0) - global.errors = errors; // act as if nothing happened -#if DMDV2 - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); -#endif - } - else if (ei) - { - if (isDataseg()) - /* static const/invariant does CTFE - */ - e = e->optimize(WANTvalue | WANTinterpret); - else - e = e->optimize(WANTvalue); - if (e->op == TOKint64 || e->op == TOKstring || e->op == TOKfloat64) - { - ei->exp = e; // no errors, keep result - } -#if DMDV2 - else - { - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); - } -#endif - } - else - init = i2; // no errors, keep result - } - } - sc = sc->pop(); - } -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type); - inuse--; - } -} - -void VarDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - // Preserve call chain - Declaration::semantic3(sc); -} - -const char *VarDeclaration::kind() -{ - return "variable"; -} - -Dsymbol *VarDeclaration::toAlias() -{ - //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); - assert(this != aliassym); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - - /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() - * too. - */ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && - (storage_class & STCstatic || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ -#if 0 /* doesn't work if more than one static ctor */ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -#endif -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - if (parent && !isDataseg() && parent != sc->parent && - !(storage_class & STCmanifest)) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis && fdv != fdthis) - { - if (loc.filename) - fdthis->getLevel(loc, fdv); - - for (int i = 0; i < nestedrefs.dim; i++) - { FuncDeclaration *f = (FuncDeclaration *)nestedrefs.data[i]; - if (f == fdthis) - goto L1; - } - nestedrefs.push(fdthis); - L1: ; - - - for (int i = 0; i < fdv->closureVars.dim; i++) - { Dsymbol *s = (Dsymbol *)fdv->closureVars.data[i]; - if (s == this) - goto L2; - } - - fdv->closureVars.push(this); - L2: ; - - //printf("fdthis is %s\n", fdthis->toChars()); - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - } - } -} - -/**************************** - * Get ExpInitializer for a variable, if there is one. - */ - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(loc); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -/******************************************* - * If variable has a constant expression initializer, get it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::getConstInitializer() -{ - if ((isConst() || isInvariant() || storage_class & STCmanifest) && - storage_class & STCinit) - { - ExpInitializer *ei = getExpInitializer(); - if (ei) - return ei->exp; - } - - return NULL; -} - -/************************************* - * Return !=0 if we can take the address of this variable. - */ - -int VarDeclaration::canTakeAddressOf() -{ -#if 0 - /* Global variables and struct/class fields of the form: - * const int x = 3; - * are not stored and hence cannot have their address taken. - */ - if ((isConst() || isInvariant()) && - storage_class & STCinit && - (!(storage_class & (STCstatic | STCextern)) || (storage_class & STCfield)) && - (!parent || toParent()->isModule() || toParent()->isTemplateInstance()) && - type->toBasetype()->isTypeBasic() - ) - { - return 0; - } -#else - if (storage_class & STCmanifest) - return 0; -#endif - return 1; -} - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%x, %p, %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - if (storage_class & STCmanifest) - return 0; - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & STCstatic)) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return canTakeAddressOf() && - (storage_class & (STCstatic | STCextern | STCtls | STCgshared) || - toParent()->isModule() || - toParent()->isTemplateInstance()); -} - -/************************************ - * Does symbol go into thread local storage? - */ - -int VarDeclaration::isThreadlocal() -{ - //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); -#if 0 || TARGET_OSX - /* To be thread-local, must use the __thread storage class. - * BUG: OSX doesn't support thread local yet. - */ - return isDataseg() && - (storage_class & (STCtls | STCconst | STCimmutable | STCshared | STCgshared)) == STCtls; -#else - /* Data defaults to being thread-local. It is not thread-local - * if it is immutable, const or shared. - */ - int i = isDataseg() && - !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared)); - //printf("\treturn %d\n", i); - return i; -#endif -} - -int VarDeclaration::hasPointers() -{ - //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); - return (!isDataseg() && type->hasPointers()); -} - -/****************************************** - * Return TRUE if variable needs to call the destructor. - */ - -int VarDeclaration::needsAutoDtor() -{ - //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); - - if (noauto || storage_class & STCnodtor) - return FALSE; - - // Destructors for structs and arrays of structs - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - return TRUE; - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - if (type->isClassHandle()) - return TRUE; - } - return FALSE; -} - - -/****************************************** - * If a variable has an auto destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callAutoDtor(Scope *sc) -{ Expression *e = NULL; - - //printf("VarDeclaration::callAutoDtor() %s\n", toChars()); - - if (noauto || storage_class & STCnodtor) - return NULL; - - // Destructors for structs and arrays of structs - bool array = false; - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - array = true; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { - if (array) - { - // Typeinfo.destroy(cast(void*)&v); - Expression *ea = new SymOffExp(loc, this, 0, 0); - ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); - Expressions *args = new Expressions(); - args->push(ea); - - Expression *et = type->getTypeInfo(sc); - et = new DotIdExp(loc, et, Id::destroy); - - e = new CallExp(loc, et, args); - } - else - { - e = new VarExp(loc, this); - e = new DotVarExp(loc, e, sd->dtor, 0); - e = new CallExp(loc, e); - } - return e; - } - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd->isInterfaceDeclaration()) - //error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic | STCgshared; -} - -Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ClassInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic | STCgshared; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* TypeInfoDeclaration ****************************/ - -TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) -{ - this->tinfo = tinfo; - storage_class = STCstatic | STCgshared; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoSharedDeclaration **********************/ - -#if DMDV2 -TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Loc loc, Type *t) - : VarDeclaration(loc, t, Id::This, NULL) -{ - noauto = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -/********************** StaticStructInitDeclaration ***************************/ - -StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) - : Declaration(new Identifier("", TOKidentifier)) -{ - this->loc = loc; - this->dsym = dsym; - storage_class |= STCconst; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include + +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "mtype.h" +#include "template.h" +#include "scope.h" +#include "aggregate.h" +#include "module.h" +#include "id.h" +#include "expression.h" +#include "hdrgen.h" + +/********************************* Declaration ****************************/ + +Declaration::Declaration(Identifier *id) + : Dsymbol(id) +{ + type = NULL; + originalType = NULL; + storage_class = STCundefined; + protection = PROTundefined; + linkage = LINKdefault; + inuse = 0; + sem = SemanticStart; +} + +void Declaration::semantic(Scope *sc) +{ +} + +const char *Declaration::kind() +{ + return "declaration"; +} + +unsigned Declaration::size(Loc loc) +{ + assert(type); + return type->size(); +} + +int Declaration::isDelete() +{ + return FALSE; +} + +int Declaration::isDataseg() +{ + return FALSE; +} + +int Declaration::isThreadlocal() +{ + return FALSE; +} + +int Declaration::isCodeseg() +{ + return FALSE; +} + +enum PROT Declaration::prot() +{ + return protection; +} + +/************************************* + * Check to see if declaration can be modified in this context (sc). + * Issue error if not. + */ + +#if DMDV2 +void Declaration::checkModify(Loc loc, Scope *sc, Type *t) +{ + if (sc->incontract && isParameter()) + error(loc, "cannot modify parameter '%s' in contract", toChars()); + + if (sc->incontract && isResult()) + error(loc, "cannot modify result '%s' in contract", toChars()); + + if (isCtorinit() && !t->isMutable()) + { // 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() && storage_class & STCfield) || + (fd->isStaticCtorDeclaration() && !(storage_class & STCfield))) && + fd->toParent() == toParent() + ) + { + VarDeclaration *v = isVarDeclaration(); + assert(v); + v->ctorinit = 1; + //printf("setting ctorinit\n"); + } + else + { + if (s) + { s = s->toParent2(); + continue; + } + else + { + const char *p = isStatic() ? "static " : ""; + error(loc, "can only initialize %sconst %s inside %sconstructor", + p, toChars(), p); + } + } + break; + } + } + else + { + VarDeclaration *v = isVarDeclaration(); + if (v && v->canassign == 0) + { + const char *p = NULL; + if (isConst()) + p = "const"; + else if (isImmutable()) + p = "immutable"; + else if (storage_class & STCmanifest) + p = "enum"; + else if (!t->isAssignable()) + p = "struct with immutable members"; + if (p) + { error(loc, "cannot modify %s", p); + } + } + } +} +#endif + + +/********************************* TupleDeclaration ****************************/ + +TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) + : Declaration(id) +{ + this->type = NULL; + this->objects = objects; + this->isexp = 0; + this->tupletype = NULL; +} + +Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); + return NULL; +} + +const char *TupleDeclaration::kind() +{ + return "tuple"; +} + +Type *TupleDeclaration::getType() +{ + /* If this tuple represents a type, return that type + */ + + //printf("TupleDeclaration::getType() %s\n", toChars()); + if (isexp) + return NULL; + if (!tupletype) + { + /* It's only a type tuple if all the Object's are types + */ + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + + if (o->dyncast() != DYNCAST_TYPE) + { + //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); + return NULL; + } + } + + /* We know it's a type tuple, so build the TypeTuple + */ + Parameters *args = new Parameters(); + args->setDim(objects->dim); + OutBuffer buf; + int hasdeco = 1; + for (size_t i = 0; i < objects->dim; i++) + { Type *t = (Type *)objects->data[i]; + + //printf("type = %s\n", t->toChars()); +#if 0 + buf.printf("_%s_%d", ident->toChars(), i); + char *name = (char *)buf.extractData(); + Identifier *id = new Identifier(name, TOKidentifier); + Parameter *arg = new Parameter(STCin, t, id, NULL); +#else + Parameter *arg = new Parameter(0, t, NULL, NULL); +#endif + args->data[i] = (void *)arg; + if (!t->deco) + hasdeco = 0; + } + + tupletype = new TypeTuple(args); + if (hasdeco) + return tupletype->semantic(0, NULL); + } + + return tupletype; +} + +int TupleDeclaration::needThis() +{ + //printf("TupleDeclaration::needThis(%s)\n", toChars()); + for (size_t i = 0; i < objects->dim; i++) + { Object *o = (Object *)objects->data[i]; + if (o->dyncast() == DYNCAST_EXPRESSION) + { Expression *e = (Expression *)o; + if (e->op == TOKdsymbol) + { DsymbolExp *ve = (DsymbolExp *)e; + Declaration *d = ve->s->isDeclaration(); + if (d && d->needThis()) + { + return 1; + } + } + } + } + return 0; +} + +/********************************* TypedefDeclaration ****************************/ + +TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) + : Declaration(id) +{ + this->type = new TypeTypedef(this); + this->basetype = basetype->toBasetype(); + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hbasetype = NULL; +#endif + this->loc = loc; +#if IN_DMD + this->sinit = NULL; +#endif +} + +Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) +{ + Type *basetype = this->basetype->syntaxCopy(); + + Initializer *init = NULL; + if (this->init) + init = this->init->syntaxCopy(); + + assert(!s); + TypedefDeclaration *st; + st = new TypedefDeclaration(loc, ident, basetype, init); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + st->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + st->htype = htype->syntaxCopy(); + if (!hbasetype) + { if (basetype) + { hbasetype = basetype->syntaxCopy(); + st->hbasetype = basetype->syntaxCopy(); + } + } + else + st->hbasetype = hbasetype->syntaxCopy(); +#endif + return st; +} + +void TypedefDeclaration::semantic(Scope *sc) +{ + //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); + if (sem == SemanticStart) + { sem = SemanticIn; + basetype = basetype->semantic(loc, sc); + sem = SemanticDone; +#if DMDV2 + type = type->addStorageClass(storage_class); +#endif + type = type->semantic(loc, sc); + if (sc->parent->isFuncDeclaration() && init) + semantic2(sc); + storage_class |= sc->stc & STCdeprecated; + } + else if (sem == SemanticIn) + { + error("circular definition"); + } +} + +void TypedefDeclaration::semantic2(Scope *sc) +{ + //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); + if (sem == SemanticDone) + { sem = Semantic2Done; + if (init) + { + init = init->semantic(sc, basetype); + + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + { + if (ie->exp->type == basetype) + ie->exp->type = type; + } + } + } +} + +const char *TypedefDeclaration::kind() +{ + return "typedef"; +} + +Type *TypedefDeclaration::getType() +{ + return type; +} + +void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typedef "); + basetype->toCBuffer(buf, ident, hgs); + if (init) + { + buf->writestring(" = "); + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* AliasDeclaration ****************************/ + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("type = '%s'\n", type->toChars()); + this->loc = loc; + this->type = type; + this->aliassym = NULL; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + this->importprot = PROTundefined; + assert(type); +} + +AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) + : Declaration(id) +{ + //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); + assert(s != this); + this->loc = loc; + this->type = NULL; + this->aliassym = s; +#ifdef _DH + this->htype = NULL; + this->haliassym = NULL; +#endif + this->overnext = NULL; + this->inSemantic = 0; + assert(s); +} + +Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("AliasDeclaration::syntaxCopy()\n"); + assert(!s); + AliasDeclaration *sa; + if (type) + sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); + else + sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sa->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sa->htype = htype->syntaxCopy(); + if (!haliassym) + { if (aliassym) + { haliassym = aliassym->syntaxCopy(s); + sa->haliassym = aliassym->syntaxCopy(s); + } + } + else + sa->haliassym = haliassym->syntaxCopy(s); +#endif + return sa; +} + +void AliasDeclaration::semantic(Scope *sc) +{ + //printf("AliasDeclaration::semantic() %s\n", toChars()); + if (aliassym) + { + if (aliassym->isTemplateInstance()) + aliassym->semantic(sc); + return; + } + this->inSemantic = 1; + +#if DMDV1 // don't really know why this is here + if (storage_class & STCconst) + error("cannot be const"); +#endif + + storage_class |= sc->stc & STCdeprecated; + + // Given: + // alias foo.bar.abc def; + // it is not knowable from the syntax whether this is an alias + // for a type or an alias for a symbol. It is up to the semantic() + // pass to distinguish. + // If it is a type, then type is set and getType() will return that + // type. If it is a symbol, then aliassym is set and type is NULL - + // toAlias() will return aliasssym. + + Dsymbol *s; + Type *t; + Expression *e; + + /* This section is needed because resolve() will: + * const x = 3; + * alias x y; + * try to alias y to 3. + */ + s = type->toDsymbol(sc); + if (s +#if DMDV2 + && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) +#endif + ) + goto L2; // it's a symbolic alias + +#if DMDV2 + type = type->addStorageClass(storage_class); + if (storage_class & (STCref | STCnothrow | STCpure | STCdisable)) + { // For 'ref' to be attached to function types, and picked + // up by Type::resolve(), it has to go into sc. + sc = sc->push(); + sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared | STCdisable); + type->resolve(loc, sc, &e, &t, &s); + sc = sc->pop(); + } + else +#endif + type->resolve(loc, sc, &e, &t, &s); + if (s) + { + goto L2; + } + else if (e) + { + // Try to convert Expression to Dsymbol + s = getDsymbol(e); + if (s) + goto L2; + + error("cannot alias an expression %s", e->toChars()); + t = e->type; + } + else if (t) + { + type = t; + //printf("\talias resolved to type %s\n", type->toChars()); + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, this, overnext); + this->inSemantic = 0; + return; + + L2: + //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); + type = NULL; + VarDeclaration *v = s->isVarDeclaration(); + if (0 && v && v->linkage == LINKdefault) + { + error("forward reference of %s", v->toChars()); + s = NULL; + } + else + { + FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); + if (f) + { + if (overnext) + { + FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); +#if IN_LLVM + fa->importprot = importprot; +#endif + if (!fa->overloadInsert(overnext)) + ScopeDsymbol::multiplyDefined(0, f, overnext); + overnext = NULL; + s = fa; + s->parent = sc->parent; + } + } + if (overnext) + ScopeDsymbol::multiplyDefined(0, s, overnext); + if (s == this) + { + assert(global.errors); + s = NULL; + } + } + //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); + aliassym = s; + this->inSemantic = 0; +} + +int AliasDeclaration::overloadInsert(Dsymbol *s) +{ + /* Don't know yet what the aliased symbol is, so assume it can + * be overloaded and check later for correctness. + */ + + //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); + if (aliassym) // see test/test56.d + { + Dsymbol *a = aliassym->toAlias(); + FuncDeclaration *f = a->isFuncDeclaration(); + if (f) // BUG: what if it's a template? + { + FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); + aliassym = fa; + return fa->overloadInsert(s); + } + } + + if (overnext == NULL) + { + if (s == this) + { + return TRUE; + } + overnext = s; + return TRUE; + } + else + { + return overnext->overloadInsert(s); + } +} + +const char *AliasDeclaration::kind() +{ + return "alias"; +} + +Type *AliasDeclaration::getType() +{ + return type; +} + +Dsymbol *AliasDeclaration::toAlias() +{ + //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); + assert(this != aliassym); + //static int count; if (++count == 10) *(char*)0=0; + if (inSemantic) + { error("recursive alias declaration"); + aliassym = new TypedefDeclaration(loc, ident, Type::terror, NULL); + } + else if (!aliassym && scope) + semantic(scope); + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); +#if 0 && _DH + if (hgs->hdrgen) + { + if (haliassym) + { + buf->writestring(haliassym->toChars()); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + htype->toCBuffer(buf, ident, hgs); + } + else +#endif + { + if (aliassym) + { + aliassym->toCBuffer(buf, hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + } + else + type->toCBuffer(buf, ident, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +/********************************* VarDeclaration ****************************/ + +VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) + : Declaration(id) +{ + //printf("VarDeclaration('%s')\n", id->toChars()); +#ifdef DEBUG + if (!type && !init) + { printf("VarDeclaration('%s')\n", id->toChars()); + //*(char*)0=0; + } +#endif + assert(type || init); + this->type = type; + this->init = init; +#ifdef _DH + this->htype = NULL; + this->hinit = NULL; +#endif + this->loc = loc; + offset = 0; + noscope = 0; +#if DMDV2 + isargptr = FALSE; +#endif +#if DMDV1 + nestedref = 0; +#endif + ctorinit = 0; + aliassym = NULL; + onstack = 0; + canassign = 0; + value = NULL; + rundtor = NULL; +#if IN_LLVM + aggrIndex = 0; + + // LDC + anonDecl = NULL; + offset2 = 0; + + nakedUse = false; + + availableExternally = true; // assume this unless proven otherwise +#endif +} + +Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) +{ + //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); + + VarDeclaration *sv; + if (s) + { sv = (VarDeclaration *)s; + } + else + { + Initializer *init = NULL; + if (this->init) + { init = this->init->syntaxCopy(); + //init->isExpInitializer()->exp->print(); + //init->isExpInitializer()->exp->dump(0); + } + + sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); + sv->storage_class = storage_class; + } +#ifdef _DH + // Syntax copy for header file + if (!htype) // Don't overwrite original + { if (type) // Make copy for both old and new instances + { htype = type->syntaxCopy(); + sv->htype = type->syntaxCopy(); + } + } + else // Make copy of original for new instance + sv->htype = htype->syntaxCopy(); + if (!hinit) + { if (init) + { hinit = init->syntaxCopy(); + sv->hinit = init->syntaxCopy(); + } + } + else + sv->hinit = hinit->syntaxCopy(); +#endif + return sv; +} + +void VarDeclaration::semantic(Scope *sc) +{ +#if 0 + printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); + printf(" type = %s\n", type ? type->toChars() : "null"); + printf(" stc = x%x\n", sc->stc); + printf(" storage_class = x%x\n", storage_class); + printf("linkage = %d\n", sc->linkage); + //if (strcmp(toChars(), "mul") == 0) halt(); +#endif + +// if (sem > SemanticStart) +// return; +// sem = SemanticIn; + + if (scope) + { sc = scope; + scope = NULL; + } + + /* Pick up storage classes from context, but skip synchronized + */ + storage_class |= (sc->stc & ~STCsynchronized); + if (storage_class & STCextern && init) + error("extern symbols cannot have initializers"); + + /* If auto type inference, do the inference + */ + int inferred = 0; + if (!type) + { inuse++; + + ArrayInitializer *ai = init->isArrayInitializer(); + if (ai) + { Expression *e; + if (ai->isAssociativeArray()) + e = ai->toAssocArrayLiteral(); + else + e = init->toExpression(); + init = new ExpInitializer(e->loc, e); + type = init->inferType(sc); + if (type->ty == Tsarray) + type = type->nextOf()->arrayOf(); + } + else + type = init->inferType(sc); + +//printf("test2: %s, %s, %s\n", toChars(), type->toChars(), type->deco); +// type = type->semantic(loc, sc); + + inuse--; + inferred = 1; + + if (init->isArrayInitializer() && type->toBasetype()->ty == Tsarray) + { // Prefer array literals to give a T[] type rather than a T[dim] + type = type->toBasetype()->nextOf()->arrayOf(); + } + + /* This is a kludge to support the existing syntax for RAII + * declarations. + */ + storage_class &= ~STCauto; + originalType = type; + } + else + { if (!originalType) + originalType = type; + type = type->semantic(loc, sc); + } + //printf(" semantic type = %s\n", type ? type->toChars() : "null"); + + type->checkDeprecated(loc, sc); + linkage = sc->linkage; + this->parent = sc->parent; + //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); + protection = sc->protection; + //printf("sc->stc = %x\n", sc->stc); + //printf("storage_class = x%x\n", storage_class); + +#if DMDV2 +#if 1 + if (storage_class & STCgshared && sc->func && sc->func->isSafe()) + { + error("__gshared not allowed in safe functions; use shared"); + } +#else + if (storage_class & STCgshared && global.params.safe && !sc->module->safe) + { + error("__gshared not allowed in safe mode; use shared"); + } +#endif +#endif + + Dsymbol *parent = toParent(); + FuncDeclaration *fd = parent->isFuncDeclaration(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tvoid && !(storage_class & STClazy)) + { error("voids have no value"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tfunction) + { error("cannot be declared to be a function"); + type = Type::terror; + tb = type; + } + if (tb->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tb; + + if (!ts->sym->members) + { + error("no definition of struct %s", ts->toChars()); + } + } + if ((storage_class & STCauto) && !inferred) + error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); + + if (tb->ty == Ttuple) + { /* Instead, declare variables for each of the tuple elements + * and add those. + */ + TypeTuple *tt = (TypeTuple *)tb; + size_t nelems = Parameter::dim(tt->arguments); + Objects *exps = new Objects(); + exps->setDim(nelems); + Expression *ie = init ? init->toExpression() : NULL; + + for (size_t i = 0; i < nelems; i++) + { Parameter *arg = Parameter::getNth(tt->arguments, i); + + OutBuffer buf; + buf.printf("_%s_field_%zu", ident->toChars(), i); + buf.writeByte(0); + const char *name = (const char *)buf.extractData(); + Identifier *id = Lexer::idPool(name); + + Expression *einit = ie; + if (ie && ie->op == TOKtuple) + { einit = (Expression *)((TupleExp *)ie)->exps->data[i]; + } + Initializer *ti = init; + if (einit) + { ti = new ExpInitializer(einit->loc, einit); + } + + VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); + //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); + v->semantic(sc); + +/* +// removed for LDC since TupleDeclaration::toObj already creates the fields; +// adding them to the scope again leads to duplicates + if (sc->scopesym) + { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); + if (sc->scopesym->members) + sc->scopesym->members->push(v); + } +*/ + Expression *e = new DsymbolExp(loc, v); + exps->data[i] = e; + } + TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); + v2->isexp = 1; + aliassym = v2; + return; + } + +Lagain: + /* Storage class can modify the type + */ + type = type->addStorageClass(storage_class); + + /* Adjust storage class to reflect type + */ + if (type->isConst()) + { storage_class |= STCconst; + if (type->isShared()) + storage_class |= STCshared; + } + else if (type->isImmutable()) + storage_class |= STCimmutable; + else if (type->isShared()) + storage_class |= STCshared; + else if (type->isWild()) + storage_class |= STCwild; + + if (isSynchronized()) + { + error("variable %s cannot be synchronized", toChars()); + } + else if (isOverride()) + { + error("override cannot be applied to variable"); + } + else if (isAbstract()) + { + error("abstract cannot be applied to variable"); + } + else if (storage_class & STCfinal) + { + error("final cannot be applied to variable"); + } + + if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe)) + { + } + else + { + AggregateDeclaration *aad = sc->anonAgg; + if (!aad) + aad = parent->isAggregateDeclaration(); + if (aad) + { +#if DMDV2 + assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); + + if (storage_class & (STCconst | STCimmutable) && init) + { + if (!type->toBasetype()->isTypeBasic()) + storage_class |= STCstatic; + } + else +#endif + aad->addField(sc, this); + } + + InterfaceDeclaration *id = parent->isInterfaceDeclaration(); + if (id) + { + error("field not allowed in interface"); + } + + /* Templates cannot add fields to aggregates + */ + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + AggregateDeclaration *ad = ti->tempdecl->isMember(); + if (ad && storage_class != STCundefined) + { + error("cannot use template to add field to aggregate '%s'", ad->toChars()); + } + } + } + +#if DMDV2 + if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && + ident != Id::This) + { + error("only parameters or foreach declarations can be ref"); + } + + if ((storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest) || + isDataseg()) && + type->hasWild()) + { + error("only fields, parameters or stack based variables can be inout"); + } +#endif + + if (type->isscope() && !noscope) + { + if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd) + { + error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); + } + + if (!(storage_class & STCscope)) + { + if (!(storage_class & STCparameter) && ident != Id::withSym) + error("reference to scope class must be scope"); + } + } + + if (!init && !fd) + { // If not mutable, initializable by constructor only + storage_class |= STCctorinit; + } + + if (init) + storage_class |= STCinit; // remember we had an explicit initializer + else if (storage_class & STCmanifest) + error("manifest constants must have initializers"); + + enum TOK op = TOKconstruct; + if (!init && !sc->inunion && !isStatic() && fd && + (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult)) + || (storage_class & STCout)) && + type->size() != 0) + { + // Provide a default initializer + //printf("Providing default initializer for '%s'\n", toChars()); + if (type->ty == Tstruct && + ((TypeStruct *)type)->sym->zeroInit == 1) + { /* If a struct is all zeros, as a special case + * set it's initializer to the integer 0. + * In AssignExp::toElem(), we check for this and issue + * a memset() to initialize the struct. + * Must do same check in interpreter. + */ + Expression *e = new IntegerExp(loc, 0, Type::tint32); + Expression *e1; + e1 = new VarExp(loc, this); + e = new ConstructExp(loc, e1, e); + e->type = e1->type; // don't type check this, it would fail + init = new ExpInitializer(loc, e); + return; + } + else if (type->ty == Ttypedef) + { TypeTypedef *td = (TypeTypedef *)type; + if (td->sym->init) + { init = td->sym->init; + ExpInitializer *ie = init->isExpInitializer(); + if (ie) + // Make copy so we can modify it + init = new ExpInitializer(ie->loc, ie->exp); + } + else + init = getExpInitializer(); + } + else + { + init = getExpInitializer(); + } + // Default initializer is always a blit + op = TOKblit; + } + + if (init) + { + sc = sc->push(); + sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref | STCdisable); + + ArrayInitializer *ai = init->isArrayInitializer(); + if (ai && tb->ty == Taarray) + { + Expression *e = ai->toAssocArrayLiteral(); + init = new ExpInitializer(e->loc, e); + } + + StructInitializer *si = init->isStructInitializer(); + ExpInitializer *ei = init->isExpInitializer(); + + // See if initializer is a NewExp that can be allocated on the stack + if (ei && isScope() && ei->exp->op == TOKnew) + { NewExp *ne = (NewExp *)ei->exp; + if (!(ne->newargs && ne->newargs->dim)) + { ne->onstack = 1; + onstack = 1; + if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) + onstack = 2; + } + } + + // If inside function, there is no semantic3() call + if (sc->func) + { + // If local variable, use AssignExp to handle all the various + // possibilities. + if (fd && + !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) && + !init->isVoidInitializer()) + { + //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); + if (!ei) + { + Expression *e = init->toExpression(); + if (!e) + { + init = init->semantic(sc, type); + e = init->toExpression(); + if (!e) + { error("is not a static and cannot have static initializer"); + return; + } + } + ei = new ExpInitializer(init->loc, e); + init = ei; + } + + Expression *e1 = new VarExp(loc, this); + + Type *t = type->toBasetype(); + if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) + { + ei->exp = ei->exp->semantic(sc); + if (!ei->exp->implicitConvTo(type)) + { + int dim = ((TypeSArray *)t)->dim->toInteger(); + // If multidimensional static array, treat as one large array + while (1) + { + t = t->nextOf()->toBasetype(); + if (t->ty != Tsarray) + break; + dim *= ((TypeSArray *)t)->dim->toInteger(); + e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); + } + } + e1 = new SliceExp(loc, e1, NULL, NULL); + } + else if (t->ty == Tstruct) + { + ei->exp = ei->exp->semantic(sc); + ei->exp = resolveProperties(sc, ei->exp); + StructDeclaration *sd = ((TypeStruct *)t)->sym; +#if DMDV2 + /* Look to see if initializer is a call to the constructor + */ + if (sd->ctor && // there are constructors + ei->exp->type->ty == Tstruct && // rvalue is the same struct + ((TypeStruct *)ei->exp->type)->sym == sd && + ei->exp->op == TOKstar) + { + /* Look for form of constructor call which is: + * *__ctmp.ctor(arguments...) + */ + PtrExp *pe = (PtrExp *)ei->exp; + if (pe->e1->op == TOKcall) + { CallExp *ce = (CallExp *)pe->e1; + if (ce->e1->op == TOKdotvar) + { DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + { /* It's a constructor call, currently constructing + * a temporary __ctmp. + */ + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + Expression *e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); + e->op = TOKblit; + e->type = t; + ei->exp = new CommaExp(loc, e, ei->exp); + + /* Replace __ctmp being constructed with e1 + */ + dve->e1 = e1; + return; + } + } + } + } +#endif + if (!ei->exp->implicitConvTo(type)) + { + Type *ti = ei->exp->type->toBasetype(); + // Look for constructor first + if (sd->ctor && + /* Initializing with the same type is done differently + */ + !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) + { + // Rewrite as e1.ctor(arguments) + Expression *ector = new DotIdExp(loc, e1, Id::ctor); + ei->exp = new CallExp(loc, ector, ei->exp); + /* Before calling the constructor, initialize + * variable with a bit copy of the default + * initializer + */ + Expression *e = new AssignExp(loc, e1, t->defaultInit(loc)); + e->op = TOKblit; + e->type = t; + ei->exp = new CommaExp(loc, e, ei->exp); + } + else + /* Look for opCall + * See bugzilla 2702 for more discussion + */ + // Don't cast away invariant or mutability in initializer + if (search_function(sd, Id::call) && + /* Initializing with the same type is done differently + */ + !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) + { // Rewrite as e1.call(arguments) + Expression * eCall = new DotIdExp(loc, e1, Id::call); + ei->exp = new CallExp(loc, eCall, ei->exp); + } + } + } + ei->exp = new AssignExp(loc, e1, ei->exp); + ei->exp->op = op; + canassign++; + ei->exp = ei->exp->semantic(sc); + canassign--; + ei->exp->optimize(WANTvalue); + } + else + { + init = init->semantic(sc, type); + } + } + else if (storage_class & (STCconst | STCimmutable | STCmanifest) || + type->isConst() || type->isImmutable() || + parent->isAggregateDeclaration()) + { + /* Because we may need the results of a const declaration in a + * subsequent type, such as an array dimension, before semantic2() + * gets ordinarily run, try to run semantic2() now. + * Ignore failure. + */ + + if (!global.errors && !inferred) + { + unsigned errors = global.errors; + global.gag++; + //printf("+gag\n"); + Expression *e; + Initializer *i2 = init; + inuse++; + if (ei) + { + e = ei->exp->syntaxCopy(); + e = e->semantic(sc); + e = resolveProperties(sc, e); +#if DMDV2 + /* The problem is the following code: + * struct CopyTest { + * double x; + * this(double a) { x = a * 10.0;} + * this(this) { x += 2.0; } + * } + * const CopyTest z = CopyTest(5.3); // ok + * const CopyTest w = z; // not ok, postblit not run + * static assert(w.x == 55.0); + * because the postblit doesn't get run on the initialization of w. + */ + + Type *tb = e->type->toBasetype(); + if (tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + Type *typeb = type->toBasetype(); + /* Look to see if initializer involves a copy constructor + * (which implies a postblit) + */ + if (sd->cpctor && // there is a copy constructor + typeb->equals(tb)) // rvalue is the same struct + { + // The only allowable initializer is a (non-copy) constructor + if (e->op == TOKcall) + { + CallExp *ce = (CallExp *)e; + if (ce->e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)ce->e1; + if (dve->var->isCtorDeclaration()) + goto LNoCopyConstruction; + } + } + global.gag--; + error("of type struct %s uses this(this), which is not allowed in static initialization", typeb->toChars()); + global.gag++; + + LNoCopyConstruction: + ; + } + } +#endif + e = e->implicitCastTo(sc, type); + } + else if (si || ai) + { i2 = init->syntaxCopy(); + i2 = i2->semantic(sc, type); + } + inuse--; + global.gag--; + //printf("-gag\n"); + if (errors != global.errors) // if errors happened + { + if (global.gag == 0) + global.errors = errors; // act as if nothing happened +#if DMDV2 + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); +#endif + } + else if (ei) + { + if (isDataseg()) + /* static const/invariant does CTFE + */ + e = e->optimize(WANTvalue | WANTinterpret); + else + e = e->optimize(WANTvalue); + if (e->op == TOKint64 || e->op == TOKstring || e->op == TOKfloat64) + { + ei->exp = e; // no errors, keep result + } +#if DMDV2 + else + { + /* Save scope for later use, to try again + */ + scope = new Scope(*sc); + scope->setNoFree(); + } +#endif + } + else + init = i2; // no errors, keep result + } + } + sc = sc->pop(); + } + sem = SemanticDone; +} + +void VarDeclaration::semantic2(Scope *sc) +{ + //printf("VarDeclaration::semantic2('%s')\n", toChars()); + if (init && !toParent()->isFuncDeclaration()) + { inuse++; +#if 0 + ExpInitializer *ei = init->isExpInitializer(); + if (ei) + { + ei->exp->dump(0); + printf("type = %p\n", ei->exp->type); + } +#endif + init = init->semantic(sc, type); + inuse--; + } + sem = Semantic2Done; +} + +void VarDeclaration::semantic3(Scope *sc) +{ + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + // Preserve call chain + Declaration::semantic3(sc); +} + +const char *VarDeclaration::kind() +{ + return "variable"; +} + +Dsymbol *VarDeclaration::toAlias() +{ + //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); + assert(this != aliassym); + Dsymbol *s = aliassym ? aliassym->toAlias() : this; + return s; +} + +void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + StorageClassDeclaration::stcToCBuffer(buf, storage_class); + + /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() + * too. + */ + if (type) + type->toCBuffer(buf, ident, hgs); + else + buf->writestring(ident->toChars()); + if (init) + { buf->writestring(" = "); +#if DMDV2 + ExpInitializer *ie = init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); + else +#endif + init->toCBuffer(buf, hgs); + } + buf->writeByte(';'); + buf->writenl(); +} + +int VarDeclaration::needThis() +{ + //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); + return storage_class & STCfield; +} + +int VarDeclaration::isImportedSymbol() +{ + if (protection == PROTexport && !init && + (storage_class & STCstatic || parent->isModule())) + return TRUE; + return FALSE; +} + +void VarDeclaration::checkCtorConstInit() +{ +#if 0 /* doesn't work if more than one static ctor */ + if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) + error("missing initializer in static constructor for const variable"); +#endif +} + +/************************************ + * Check to see if this variable is actually in an enclosing function + * rather than the current one. + */ + +void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) +{ + //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); + if (parent && !isDataseg() && parent != sc->parent && + !(storage_class & STCmanifest)) + { + // The function that this variable is in + FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + // The current function + FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); + + if (fdv && fdthis && fdv != fdthis) + { + if (loc.filename) + fdthis->getLevel(loc, fdv); + + for (int i = 0; i < nestedrefs.dim; i++) + { FuncDeclaration *f = (FuncDeclaration *)nestedrefs.data[i]; + if (f == fdthis) + goto L1; + } + nestedrefs.push(fdthis); + L1: ; + + + for (int i = 0; i < fdv->closureVars.dim; i++) + { Dsymbol *s = (Dsymbol *)fdv->closureVars.data[i]; + if (s == this) + goto L2; + } + + fdv->closureVars.push(this); + L2: ; + + //printf("fdthis is %s\n", fdthis->toChars()); + //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); + // __dollar creates problems because it isn't a real variable Bugzilla 3326 + if (ident == Id::dollar) + ::error(loc, "cannnot use $ inside a function literal"); + } + } +} + +/**************************** + * Get ExpInitializer for a variable, if there is one. + */ + +ExpInitializer *VarDeclaration::getExpInitializer() +{ + ExpInitializer *ei; + + if (init) + ei = init->isExpInitializer(); + else + { + Expression *e = type->defaultInit(loc); + if (e) + ei = new ExpInitializer(loc, e); + else + ei = NULL; + } + return ei; +} + +/******************************************* + * If variable has a constant expression initializer, get it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::getConstInitializer() +{ + if ((isConst() || isImmutable() || storage_class & STCmanifest) && + storage_class & STCinit) + { + ExpInitializer *ei = getExpInitializer(); + if (ei) + return ei->exp; + } + + return NULL; +} + +/************************************* + * Return !=0 if we can take the address of this variable. + */ + +int VarDeclaration::canTakeAddressOf() +{ +#if 0 + /* Global variables and struct/class fields of the form: + * const int x = 3; + * are not stored and hence cannot have their address taken. + */ + if ((isConst() || isImmutable()) && + storage_class & STCinit && + (!(storage_class & (STCstatic | STCextern)) || (storage_class & STCfield)) && + (!parent || toParent()->isModule() || toParent()->isTemplateInstance()) && + type->toBasetype()->isTypeBasic() + ) + { + return 0; + } +#else + if (storage_class & STCmanifest) + return 0; +#endif + return 1; +} + +/******************************* + * Does symbol go into data segment? + * Includes extern variables. + */ + +int VarDeclaration::isDataseg() +{ +#if 0 + printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); + printf("%llx, isModule: %p, isTemplateInstance: %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); + printf("parent = '%s'\n", parent->toChars()); +#endif + if (storage_class & STCmanifest) + return 0; + Dsymbol *parent = this->toParent(); + if (!parent && !(storage_class & STCstatic)) + { error("forward referenced"); + type = Type::terror; + return 0; + } + return canTakeAddressOf() && + (storage_class & (STCstatic | STCextern | STCtls | STCgshared) || + toParent()->isModule() || + toParent()->isTemplateInstance()); +} + +/************************************ + * Does symbol go into thread local storage? + */ + +int VarDeclaration::isThreadlocal() +{ + //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); +#if 0 //|| TARGET_OSX + /* To be thread-local, must use the __thread storage class. + * BUG: OSX doesn't support thread local yet. + */ + return isDataseg() && + (storage_class & (STCtls | STCconst | STCimmutable | STCshared | STCgshared)) == STCtls; +#else + /* Data defaults to being thread-local. It is not thread-local + * if it is immutable, const or shared. + */ + int i = isDataseg() && + !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared)); + //printf("\treturn %d\n", i); + return i; +#endif +} + +/******************************************** + * Can variable be read and written by CTFE? + */ + +int VarDeclaration::isCTFE() +{ + return (storage_class & STCctfe) != 0; // || !isDataseg(); +} + +int VarDeclaration::hasPointers() +{ + //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); + return (!isDataseg() && type->hasPointers()); +} + +/****************************************** + * Return TRUE if variable needs to call the destructor. + */ + +int VarDeclaration::needsAutoDtor() +{ + //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); + + if (noscope || storage_class & STCnodtor) + return FALSE; + + // Destructors for structs and arrays of structs + Type *tv = type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + return TRUE; + } + + // Destructors for classes + if (storage_class & (STCauto | STCscope)) + { + if (type->isClassHandle()) + return TRUE; + } + return FALSE; +} + + +/****************************************** + * If a variable has a scope destructor call, return call for it. + * Otherwise, return NULL. + */ + +Expression *VarDeclaration::callScopeDtor(Scope *sc) +{ Expression *e = NULL; + + //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); + + if (noscope || storage_class & STCnodtor) + return NULL; + + // Destructors for structs and arrays of structs + bool array = false; + Type *tv = type->toBasetype(); + while (tv->ty == Tsarray) + { TypeSArray *ta = (TypeSArray *)tv; + array = true; + tv = tv->nextOf()->toBasetype(); + } + if (tv->ty == Tstruct) + { TypeStruct *ts = (TypeStruct *)tv; + StructDeclaration *sd = ts->sym; + if (sd->dtor) + { + if (array) + { + // Typeinfo.destroy(cast(void*)&v); + Expression *ea = new SymOffExp(loc, this, 0, 0); + ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); + Expressions *args = new Expressions(); + args->push(ea); + + Expression *et = type->getTypeInfo(sc); + et = new DotIdExp(loc, et, Id::destroy); + + e = new CallExp(loc, et, args); + } + else + { + e = new VarExp(loc, this); + e = new DotVarExp(loc, e, sd->dtor, 0); + e = new CallExp(loc, e); + } + return e; + } + } + + // Destructors for classes + if (storage_class & (STCauto | STCscope)) + { + for (ClassDeclaration *cd = type->isClassHandle(); + cd; + cd = cd->baseClass) + { + /* We can do better if there's a way with onstack + * classes to determine if there's no way the monitor + * could be set. + */ + //if (cd->isInterfaceDeclaration()) + //error("interface %s cannot be scope", cd->toChars()); + if (1 || onstack || cd->dtors.dim) // if any destructors + { + // delete this; + Expression *ec; + + ec = new VarExp(loc, this); + e = new DeleteExp(loc, ec); + e->type = Type::tvoid; + break; + } + } + } + return e; +} + + +/********************************* ClassInfoDeclaration ****************************/ + +ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) + : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) +{ + this->cd = cd; + storage_class = STCstatic | STCgshared; +} + +Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ClassInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* ModuleInfoDeclaration ****************************/ + +ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) + : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) +{ + this->mod = mod; + storage_class = STCstatic | STCgshared; +} + +Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void ModuleInfoDeclaration::semantic(Scope *sc) +{ +} + +/********************************* TypeInfoDeclaration ****************************/ + +TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) + : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) +{ + this->tinfo = tinfo; + storage_class = STCstatic | STCgshared; + protection = PROTpublic; + linkage = LINKc; +} + +Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +void TypeInfoDeclaration::semantic(Scope *sc) +{ + assert(linkage == LINKc); +#if IN_LLVM + if (!global.params.useAvailableExternally) + availableExternally = false; +#endif +} + +/***************************** TypeInfoConstDeclaration **********************/ + +#if DMDV2 +TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoconst->type; +} +#endif + +/***************************** TypeInfoInvariantDeclaration **********************/ + +#if DMDV2 +TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoinvariant->type; +} +#endif + +/***************************** TypeInfoSharedDeclaration **********************/ + +#if DMDV2 +TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoshared->type; +} +#endif + +/***************************** TypeInfoWildDeclaration **********************/ + +#if DMDV2 +TypeInfoWildDeclaration::TypeInfoWildDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfowild->type; +} +#endif + +/***************************** TypeInfoStructDeclaration **********************/ + +TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfostruct->type; +} + +/***************************** TypeInfoClassDeclaration ***********************/ + +TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoclass->type; +} + +/***************************** TypeInfoInterfaceDeclaration *******************/ + +TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfointerface->type; +} + +/***************************** TypeInfoTypedefDeclaration *********************/ + +TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfotypedef->type; +} + +/***************************** TypeInfoPointerDeclaration *********************/ + +TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfopointer->type; +} + +/***************************** TypeInfoArrayDeclaration ***********************/ + +TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoarray->type; +} + +/***************************** TypeInfoStaticArrayDeclaration *****************/ + +TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfostaticarray->type; +} + +/***************************** TypeInfoAssociativeArrayDeclaration ************/ + +TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoassociativearray->type; +} + +/***************************** TypeInfoEnumDeclaration ***********************/ + +TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfoenum->type; +} + +/***************************** TypeInfoFunctionDeclaration ********************/ + +TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfofunction->type; +} + +/***************************** TypeInfoDelegateDeclaration ********************/ + +TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfodelegate->type; +} + +/***************************** TypeInfoTupleDeclaration **********************/ + +TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) + : TypeInfoDeclaration(tinfo, 0) +{ + type = Type::typeinfotypelist->type; +} + +/********************************* ThisDeclaration ****************************/ + +// For the "this" parameter to member functions + +ThisDeclaration::ThisDeclaration(Loc loc, Type *t) + : VarDeclaration(loc, t, Id::This, NULL) +{ + noscope = 1; +} + +Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(0); // should never be produced by syntax + return NULL; +} + +/********************** StaticStructInitDeclaration ***************************/ + +StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) + : Declaration(new Identifier("", TOKidentifier)) +{ + this->loc = loc; + this->dsym = dsym; + storage_class |= STCconst; +} diff --git a/dmd2/declaration.h b/dmd2/declaration.h index e7c8789c..d52b07f1 100644 --- a/dmd2/declaration.h +++ b/dmd2/declaration.h @@ -1,992 +1,1050 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#if IN_LLVM -#include -#include -#include -#endif - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -#if IN_LLVM -struct LabelStatement; -#endif -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -#if IN_LLVM -struct AnonDeclaration; -#endif - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; - -enum STC -{ - STCundefined = 0, - STCstatic = 1, - STCextern = 2, - STCconst = 4, - STCfinal = 8, - STCabstract = 0x10, - STCparameter = 0x20, - STCfield = 0x40, - STCoverride = 0x80, - STCauto = 0x100, - STCsynchronized = 0x200, - STCdeprecated = 0x400, - STCin = 0x800, // in parameter - STCout = 0x1000, // out parameter - STClazy = 0x2000, // lazy parameter - STCforeach = 0x4000, // variable for foreach loop - STCcomdat = 0x8000, // should go into COMDAT record - STCvariadic = 0x10000, // variadic function argument - STCctorinit = 0x20000, // can only be set inside constructor - STCtemplateparameter = 0x40000, // template parameter - STCscope = 0x80000, // template parameter - STCinvariant = 0x100000, - STCimmutable = 0x100000, - STCref = 0x200000, - STCinit = 0x400000, // has explicit initializer - STCmanifest = 0x800000, // manifest constant - STCnodtor = 0x1000000, // don't run destructor - STCnothrow = 0x2000000, // never throws exceptions - STCpure = 0x4000000, // pure function - STCtls = 0x8000000, // thread local - STCalias = 0x10000000, // alias parameter - STCshared = 0x20000000, // accessible from multiple threads - STCgshared = 0x40000000, // accessible from multiple threads - // but not typed as "shared" - STC_TYPECTOR = (STCconst | STCimmutable | STCshared), -}; - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, - Expression *ethis, Expressions *arguments, Module* from); -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - unsigned storage_class; - enum PROT protection; - enum LINK linkage; - int inuse; // used to detect cycles - - Declaration(Identifier *id); - void semantic(Scope *sc); - const char *kind(); - unsigned size(Loc loc); - void checkModify(Loc loc, Scope *sc, Type *t); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isStaticConstructor(); - virtual int isStaticDestructor(); - virtual int isDelete(); - virtual int isDataseg(); - virtual int isThreadlocal(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isInvariant() { return storage_class & STCinvariant; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & (STCscope | STCauto); } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - int sem; // 0: semantic() has not been run - // 1: semantic() is in progress - // 2: semantic() has been run - // 3: semantic2() has been run - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Type *hbasetype; -#endif - - void toDocBuffer(OutBuffer *buf); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); -#endif - - TypedefDeclaration *isTypedefDeclaration() { return this; } - -#if IN_DMD - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - PROT importprot; // if generated by import, store its protection - - AliasDeclaration(Loc loc, Identifier *ident, Type *type); - AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - const char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Dsymbol *haliassym; -#endif - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noauto; // no auto semantics -#if DMDV2 - FuncDeclarations nestedrefs; // referenced by these lexically nested functions -#else - int nestedref; // referenced by a lexically nested function -#endif - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - Expression *value; // when interpreting, this is the value - // (NULL if value not determinable) -#if DMDV2 - VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see - // if the destructor should be run. Used to prevent - // dtor calls on postblitted vars -#endif - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#ifdef _DH - Type *htype; - Initializer *hinit; -#endif - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int isThreadlocal(); - int hasPointers(); -#if DMDV2 - int canTakeAddressOf(); - int needsAutoDtor(); -#endif - Expression *callAutoDtor(Scope *sc); - ExpInitializer *getExpInitializer(); - Expression *getConstInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - int cvMember(unsigned char *p); -#endif - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - /// Index into parent aggregate. - /// Set during type generation. - unsigned aggrIndex; - - /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - /// Override added to set above flag. - void semantic3(Scope *sc); - - // FIXME: we're not using these anymore! - AnonDeclaration* anonDecl; - unsigned offset2; - - /// This var is used by a naked function. - bool nakedUse; -#endif -}; - -/**************************************************************/ - -// LDC uses this to denote static struct initializers - -struct StaticStructInitDeclaration : Declaration -{ - StructDeclaration *dsym; - - StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - // Eliminate need for dynamic_cast - StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - virtual void toDt(dt_t **pdt); -#endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); - virtual void llvmDefine(); -#endif -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoSharedDeclaration : TypeInfoDeclaration -{ - TypeInfoSharedDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif -}; -#endif - -/**************************************************************/ - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Loc loc, Type *t); - Dsymbol *syntaxCopy(Dsymbol *); - ThisDeclaration *isThisDeclaration() { return this; } -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ -#if DMDV2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs -}; - -Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); - -#else -enum BUILTIN { }; -#endif - -struct FuncDeclaration : Declaration -{ - Array *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - Dsymbols *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - int inlineAsm; // !=0 if has inline assembler - ILS inlineStatus; - int inlineNest; // !=0 if nested inline - int cantInterpret; // !=0 if cannot interpret function - int semanticRun; // 1 semantic() run - // 2 semantic2() run - // 3 semantic3() started - // 4 semantic3() done - // 5 toObjFile() run - // this function's frame ptr - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden -#if IN_DMD - Symbol *shidden; // hidden pointer passed to function -#endif - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - Dsymbols closureVars; // local variables in this function - // which are referenced by nested - // functions -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - // called from semantic3 - void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int findVtblIndex(Array *vtbl, int dim); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t, Module* from); - FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags = 0, Module* from=NULL); - MATCH leastAsSpecialized(FuncDeclaration *g); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - const char *toPrettyChars(); - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - int isPure(); - virtual int isNested(); - int needThis(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); - void inlineScan(); - int canInline(int hasthis, int hdrscan = 0); - Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); - const char *kind(); - void toDocBuffer(OutBuffer *buf); - FuncDeclaration *isUnique(); - int needsClosure(); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Arguments *args, Type *treturn, Identifier *id); - -#if IN_DMD - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - void buildClosure(IRState *irs); // Should this be inside or outside the #if IN_DMD? -#endif - FuncDeclaration *isFuncDeclaration() { return this; } - -#if IN_LLVM - // LDC stuff - - /// Codegen traversal - void codegen(Ir* ir); - - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - - std::string intrinsicName; - - bool isIntrinsic(); - bool isVaIntrinsic(); - - // we keep our own table of label statements as LabelDsymbolS - // don't always carry their corresponding statement along ... - typedef std::map LabelMap; - LabelMap labmap; - - // if this is an array operation it gets a little special attention - bool isArrayOp; - - // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - - // true if overridden with the pragma(allow_inline); stmt - bool allowInlining; -#endif -}; - -#if DMDV2 -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags); -#endif - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - PROT importprot; // if generated by import, store its protection - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toDocBuffer(OutBuffer *buf); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticConstructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable - - StaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isStaticDestructor(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Arguments *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Arguments *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); -#ifdef _DH - DeleteDeclaration *isDeleteDeclaration() { return this; } -#endif -}; - -#endif /* DMD_DECLARATION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_DECLARATION_H +#define DMD_DECLARATION_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#if IN_LLVM +#include +#include +#include +#endif + +#include "dsymbol.h" +#include "lexer.h" +#include "mtype.h" + +struct Expression; +struct Statement; +struct LabelDsymbol; +#if IN_LLVM +struct LabelStatement; +#endif +struct Initializer; +struct Module; +struct InlineScanState; +struct ForeachStatement; +struct FuncDeclaration; +struct ExpInitializer; +struct StructDeclaration; +struct TupleType; +struct InterState; +struct IRState; +#if IN_LLVM +struct AnonDeclaration; +#endif + +enum PROT; +enum LINK; +enum TOK; +enum MATCH; + +#define STCundefined 0LL +#define STCstatic 1LL +#define STCextern 2LL +#define STCconst 4LL +#define STCfinal 8LL +#define STCabstract 0x10LL +#define STCparameter 0x20LL +#define STCfield 0x40LL +#define STCoverride 0x80LL +#define STCauto 0x100LL +#define STCsynchronized 0x200LL +#define STCdeprecated 0x400LL +#define STCin 0x800LL // in parameter +#define STCout 0x1000LL // out parameter +#define STClazy 0x2000LL // lazy parameter +#define STCforeach 0x4000LL // variable for foreach loop +#define STCcomdat 0x8000LL // should go into COMDAT record +#define STCvariadic 0x10000LL // variadic function argument +#define STCctorinit 0x20000LL // can only be set inside constructor +#define STCtemplateparameter 0x40000LL // template parameter +#define STCscope 0x80000LL // template parameter +#define STCimmutable 0x100000LL +#define STCref 0x200000LL +#define STCinit 0x400000LL // has explicit initializer +#define STCmanifest 0x800000LL // manifest constant +#define STCnodtor 0x1000000LL // don't run destructor +#define STCnothrow 0x2000000LL // never throws exceptions +#define STCpure 0x4000000LL // pure function +#define STCtls 0x8000000LL // thread local +#define STCalias 0x10000000LL // alias parameter +#define STCshared 0x20000000LL // accessible from multiple threads +#define STCgshared 0x40000000LL // accessible from multiple threads + // but not typed as "shared" +#define STCwild 0x80000000LL // for "wild" type constructor +#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild) + +#define STCproperty 0x100000000LL +#define STCsafe 0x200000000LL +#define STCtrusted 0x400000000LL +#define STCsystem 0x800000000LL +#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static +#define STCdisable 0x2000000000LL // for functions that are not callable +#define STCresult 0x4000000000LL // for result variables passed to out contracts + +struct Match +{ + int count; // number of matches found + MATCH last; // match level of lastf + FuncDeclaration *lastf; // last matching function we found + FuncDeclaration *nextf; // current matching function + FuncDeclaration *anyf; // pick a func, any func, to use for error recovery +}; + +void overloadResolveX(Match *m, FuncDeclaration *f, + Expression *ethis, Expressions *arguments, Module* from); +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param); + +enum Semantic +{ + SemanticStart, // semantic has not been run + SemanticIn, // semantic() is in progress + SemanticDone, // semantic() has been run + Semantic2Done, // semantic2() has been run +}; + +/**************************************************************/ + +struct Declaration : Dsymbol +{ + Type *type; + Type *originalType; // before semantic analysis + StorageClass storage_class; + enum PROT protection; + enum LINK linkage; + int inuse; // used to detect cycles + + enum Semantic sem; + + Declaration(Identifier *id); + void semantic(Scope *sc); + const char *kind(); + unsigned size(Loc loc); + void checkModify(Loc loc, Scope *sc, Type *t); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + char *mangle(); + int isStatic() { return storage_class & STCstatic; } + virtual int isDelete(); + virtual int isDataseg(); + virtual int isThreadlocal(); + virtual int isCodeseg(); + int isCtorinit() { return storage_class & STCctorinit; } + int isFinal() { return storage_class & STCfinal; } + int isAbstract() { return storage_class & STCabstract; } + int isConst() { return storage_class & STCconst; } + int isImmutable() { return storage_class & STCimmutable; } + int isAuto() { return storage_class & STCauto; } + int isScope() { return storage_class & STCscope; } + int isSynchronized() { return storage_class & STCsynchronized; } + int isParameter() { return storage_class & STCparameter; } + int isDeprecated() { return storage_class & STCdeprecated; } + int isOverride() { return storage_class & STCoverride; } + int isResult() { return storage_class & STCresult; } + + int isIn() { return storage_class & STCin; } + int isOut() { return storage_class & STCout; } + int isRef() { return storage_class & STCref; } + + enum PROT prot(); + + Declaration *isDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TupleDeclaration : Declaration +{ + Objects *objects; + int isexp; // 1: expression tuple + + TypeTuple *tupletype; // !=NULL if this is a type tuple + + TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); + Dsymbol *syntaxCopy(Dsymbol *); + const char *kind(); + Type *getType(); + int needThis(); + + TupleDeclaration *isTupleDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct TypedefDeclaration : Declaration +{ + Type *basetype; + Initializer *init; + + TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + char *mangle(); + const char *kind(); + Type *getType(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Type *hbasetype; +#endif + + void toDocBuffer(OutBuffer *buf); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); +#endif + + TypedefDeclaration *isTypedefDeclaration() { return this; } + +#if IN_DMD + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); +#endif +}; + +/**************************************************************/ + +struct AliasDeclaration : Declaration +{ + Dsymbol *aliassym; + Dsymbol *overnext; // next in overload list + int inSemantic; + PROT importprot; // if generated by import, store its protection + + AliasDeclaration(Loc loc, Identifier *ident, Type *type); + AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int overloadInsert(Dsymbol *s); + const char *kind(); + Type *getType(); + Dsymbol *toAlias(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Dsymbol *haliassym; +#endif + + void toDocBuffer(OutBuffer *buf); + + AliasDeclaration *isAliasDeclaration() { return this; } +}; + +/**************************************************************/ + +struct VarDeclaration : Declaration +{ + Initializer *init; + unsigned offset; + int noscope; // no auto semantics +#if DMDV2 + FuncDeclarations nestedrefs; // referenced by these lexically nested functions + bool isargptr; // if parameter that _argptr points to +#else + int nestedref; // referenced by a lexically nested function +#endif + int ctorinit; // it has been initialized in a ctor + int onstack; // 1: it has been allocated on the stack + // 2: on stack, run destructor anyway + int canassign; // it can be assigned to + Dsymbol *aliassym; // if redone as alias to another symbol + Expression *value; // when interpreting, this is the value + // (NULL if value not determinable) +#if DMDV2 + VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see + // if the destructor should be run. Used to prevent + // dtor calls on postblitted vars +#endif + + VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#ifdef _DH + Type *htype; + Initializer *hinit; +#endif + int needThis(); + int isImportedSymbol(); + int isDataseg(); + int isThreadlocal(); + int isCTFE(); + int hasPointers(); +#if DMDV2 + int canTakeAddressOf(); + int needsAutoDtor(); +#endif + Expression *callScopeDtor(Scope *sc); + ExpInitializer *getExpInitializer(); + Expression *getConstInitializer(); + void checkCtorConstInit(); + void checkNestedReference(Scope *sc, Loc loc); + Dsymbol *toAlias(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + int cvMember(unsigned char *p); +#endif + + // Eliminate need for dynamic_cast + VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } + +#if IN_LLVM + /// Codegen traversal + virtual void codegen(Ir* ir); + + /// Index into parent aggregate. + /// Set during type generation. + unsigned aggrIndex; + + /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + /// Override added to set above flag. + void semantic3(Scope *sc); + + // FIXME: we're not using these anymore! + AnonDeclaration* anonDecl; + unsigned offset2; + + /// This var is used by a naked function. + bool nakedUse; +#endif +}; + +/**************************************************************/ + +// LDC uses this to denote static struct initializers + +struct StaticStructInitDeclaration : Declaration +{ + StructDeclaration *dsym; + + StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + // Eliminate need for dynamic_cast + StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } +}; + +struct ClassInfoDeclaration : VarDeclaration +{ + ClassDeclaration *cd; + + ClassInfoDeclaration(ClassDeclaration *cd); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + Symbol *toSymbol(); +#endif + + ClassInfoDeclaration* isClassInfoDeclaration() { return this; } +}; + +struct ModuleInfoDeclaration : VarDeclaration +{ + Module *mod; + + ModuleInfoDeclaration(Module *mod); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct TypeInfoDeclaration : VarDeclaration +{ + Type *tinfo; + + TypeInfoDeclaration(Type *tinfo, int internal); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + Symbol *toSymbol(); + virtual void toDt(dt_t **pdt); +#endif + + virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } + +#if IN_LLVM + /// Codegen traversal + void codegen(Ir* ir); + virtual void llvmDefine(); +#endif +}; + +struct TypeInfoStructDeclaration : TypeInfoDeclaration +{ + TypeInfoStructDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoClassDeclaration : TypeInfoDeclaration +{ + TypeInfoClassDeclaration(Type *tinfo); + +#if IN_DMD + Symbol *toSymbol(); + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration +{ + TypeInfoInterfaceDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTypedefDeclaration : TypeInfoDeclaration +{ + TypeInfoTypedefDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoPointerDeclaration : TypeInfoDeclaration +{ + TypeInfoPointerDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoStaticArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration +{ + TypeInfoAssociativeArrayDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoEnumDeclaration : TypeInfoDeclaration +{ + TypeInfoEnumDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoFunctionDeclaration : TypeInfoDeclaration +{ + TypeInfoFunctionDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoDelegateDeclaration : TypeInfoDeclaration +{ + TypeInfoDelegateDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoTupleDeclaration : TypeInfoDeclaration +{ + TypeInfoTupleDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +#if DMDV2 +struct TypeInfoConstDeclaration : TypeInfoDeclaration +{ + TypeInfoConstDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoInvariantDeclaration : TypeInfoDeclaration +{ + TypeInfoInvariantDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif + +#if IN_LLVM + void llvmDefine(); +#endif +}; + +struct TypeInfoSharedDeclaration : TypeInfoDeclaration +{ + TypeInfoSharedDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif +}; + +struct TypeInfoWildDeclaration : TypeInfoDeclaration +{ + TypeInfoWildDeclaration(Type *tinfo); + +#if IN_DMD + void toDt(dt_t **pdt); +#endif +}; +#endif + +/**************************************************************/ + +struct ThisDeclaration : VarDeclaration +{ + ThisDeclaration(Loc loc, Type *t); + Dsymbol *syntaxCopy(Dsymbol *); + ThisDeclaration *isThisDeclaration() { return this; } +}; + +enum ILS +{ + ILSuninitialized, // not computed yet + ILSno, // cannot inline + ILSyes, // can inline +}; + +/**************************************************************/ +#if DMDV2 + +enum BUILTIN +{ + BUILTINunknown = -1, // not known if this is a builtin + BUILTINnot, // this is not a builtin + BUILTINsin, // std.math.sin + BUILTINcos, // std.math.cos + BUILTINtan, // std.math.tan + BUILTINsqrt, // std.math.sqrt + BUILTINfabs, // std.math.fabs +}; + +Expression *eval_builtin(enum BUILTIN builtin, Expressions *arguments); + +#else +enum BUILTIN { }; +#endif + +struct FuncDeclaration : Declaration +{ + Array *fthrows; // Array of Type's of exceptions (not used) + Statement *frequire; + Statement *fensure; + Statement *fbody; + + FuncDeclarations foverrides; // functions this function overrides + FuncDeclaration *fdrequire; // function that does the in contract + FuncDeclaration *fdensure; // function that does the out contract + + Identifier *outId; // identifier for out statement + VarDeclaration *vresult; // variable corresponding to outId + LabelDsymbol *returnLabel; // where the return goes + + DsymbolTable *localsymtab; // used to prevent symbols in different + // scopes from having the same name + VarDeclaration *vthis; // 'this' parameter (member and nested) + VarDeclaration *v_arguments; // '_arguments' parameter +#if IN_GCC + VarDeclaration *v_argptr; // '_argptr' variable +#endif + Dsymbols *parameters; // Array of VarDeclaration's for parameters + DsymbolTable *labtab; // statement label symbol table + Declaration *overnext; // next in overload list + Loc endloc; // location of closing curly bracket + int vtblIndex; // for member functions, index into vtbl[] + int naked; // !=0 if naked + int inlineAsm; // !=0 if has inline assembler + ILS inlineStatus; + int inlineNest; // !=0 if nested inline + int cantInterpret; // !=0 if cannot interpret function + enum PASS semanticRun; + // this function's frame ptr + ForeachStatement *fes; // if foreach body, this is the foreach + int introducing; // !=0 if 'introducing' function + Type *tintro; // if !=NULL, then this is the type + // of the 'introducing' function + // this one is overriding + int inferRetType; // !=0 if return type is to be inferred + + // Things that should really go into Scope + int hasReturnExp; // 1 if there's a return exp; statement + // 2 if there's a throw statement + // 4 if there's an assert(0) + // 8 if there's inline asm + + // Support for NRVO (named return value optimization) + int nrvo_can; // !=0 means we can do it + VarDeclaration *nrvo_var; // variable to replace with shidden +#if IN_DMD + Symbol *shidden; // hidden pointer passed to function +#endif + +#if DMDV2 + enum BUILTIN builtin; // set if this is a known, builtin + // function we can evaluate at compile + // time + + int tookAddressOf; // set if someone took the address of + // this function + Dsymbols closureVars; // local variables in this function + // which are referenced by nested + // functions +#else + int nestedFrameRef; // !=0 if nested variables referenced +#endif + + FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + // called from semantic3 + void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); + int overrides(FuncDeclaration *fd); + int findVtblIndex(Array *vtbl, int dim); + int overloadInsert(Dsymbol *s); + FuncDeclaration *overloadExactMatch(Type *t, Module* from); + FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags = 0, Module* from=NULL); + MATCH leastAsSpecialized(FuncDeclaration *g); + LabelDsymbol *searchLabel(Identifier *ident); + AggregateDeclaration *isThis(); + AggregateDeclaration *isMember2(); + int getLevel(Loc loc, FuncDeclaration *fd); // lexical nesting level difference + void appendExp(Expression *e); + void appendState(Statement *s); + char *mangle(); + const char *toPrettyChars(); + int isMain(); + int isWinMain(); + int isDllMain(); + enum BUILTIN isBuiltin(); + int isExport(); + int isImportedSymbol(); + int isAbstract(); + int isCodeseg(); + int isOverloadable(); + int isPure(); + int isSafe(); + int isTrusted(); + virtual int isNested(); + int needThis(); + virtual int isVirtual(); + virtual int isFinal(); + virtual int addPreInvariant(); + virtual int addPostInvariant(); + Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); + void inlineScan(); + int canInline(int hasthis, int hdrscan = 0); + Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); + const char *kind(); + void toDocBuffer(OutBuffer *buf); + FuncDeclaration *isUnique(); + int needsClosure(); + Statement *mergeFrequire(Statement *); + Statement *mergeFensure(Statement *); + Parameters *getParameters(int *pvarargs); + +// LDC: give argument types to runtime functions + static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name); + static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id); + +#if IN_DMD + Symbol *toSymbol(); + Symbol *toThunkSymbol(int offset); // thunk version + void toObjFile(int multiobj); // compile to .obj file + int cvMember(unsigned char *p); + void buildClosure(IRState *irs); // Should this be inside or outside the #if IN_DMD? +#endif + FuncDeclaration *isFuncDeclaration() { return this; } + +#if IN_LLVM + // LDC stuff + + /// Codegen traversal + void codegen(Ir* ir); + + // vars declared in this function that nested funcs reference + // is this is not empty, nestedFrameRef is set and these VarDecls + // probably have nestedref set too, see VarDeclaration::checkNestedReference + std::set nestedVars; + + std::string intrinsicName; + + bool isIntrinsic(); + bool isVaIntrinsic(); + + // we keep our own table of label statements as LabelDsymbolS + // don't always carry their corresponding statement along ... + typedef std::map LabelMap; + LabelMap labmap; + + // if this is an array operation it gets a little special attention + bool isArrayOp; + + // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. + bool availableExternally; + + // true if overridden with the pragma(allow_inline); stmt + bool allowInlining; +#endif +}; + +#if DMDV2 +FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, + Objects *tiargs, + Expression *ethis, + Expressions *arguments, + int flags); +#endif + +struct FuncAliasDeclaration : FuncDeclaration +{ + FuncDeclaration *funcalias; + PROT importprot; // if generated by import, store its protection + + FuncAliasDeclaration(FuncDeclaration *funcalias); + + FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } + const char *kind(); +#if IN_DMD + Symbol *toSymbol(); +#endif +}; + +struct FuncLiteralDeclaration : FuncDeclaration +{ + enum TOK tok; // TOKfunction or TOKdelegate + + FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, + ForeachStatement *fes); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Dsymbol *syntaxCopy(Dsymbol *); + int isNested(); + int isVirtual(); + + FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } + const char *kind(); +}; + +struct CtorDeclaration : FuncDeclaration +{ Parameters *arguments; + int varargs; + + CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs, StorageClass stc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toDocBuffer(OutBuffer *buf); + + CtorDeclaration *isCtorDeclaration() { return this; } +}; + +#if DMDV2 +struct PostBlitDeclaration : FuncDeclaration +{ + PostBlitDeclaration(Loc loc, Loc endloc); + PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + + PostBlitDeclaration *isPostBlitDeclaration() { return this; } +}; +#endif + +struct DtorDeclaration : FuncDeclaration +{ + DtorDeclaration(Loc loc, Loc endloc); + DtorDeclaration(Loc loc, Loc endloc, Identifier *id); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + int overloadInsert(Dsymbol *s); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + + DtorDeclaration *isDtorDeclaration() { return this; } +}; + +struct StaticCtorDeclaration : FuncDeclaration +{ + StaticCtorDeclaration(Loc loc, Loc endloc); + StaticCtorDeclaration(Loc loc, Loc endloc, const char *name); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } +}; + +#if DMDV2 +struct SharedStaticCtorDeclaration : StaticCtorDeclaration +{ + SharedStaticCtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } +}; +#endif + +struct StaticDtorDeclaration : FuncDeclaration +{ VarDeclaration *vgate; // 'gate' variable + + StaticDtorDeclaration(Loc loc, Loc endloc); + StaticDtorDeclaration(Loc loc, Loc endloc, const char *name); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } +}; + +#if DMDV2 +struct SharedStaticDtorDeclaration : StaticDtorDeclaration +{ + SharedStaticDtorDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } +}; +#endif + +struct InvariantDeclaration : FuncDeclaration +{ + InvariantDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + InvariantDeclaration *isInvariantDeclaration() { return this; } +}; + +struct UnitTestDeclaration : FuncDeclaration +{ + UnitTestDeclaration(Loc loc, Loc endloc); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + AggregateDeclaration *isThis(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + + UnitTestDeclaration *isUnitTestDeclaration() { return this; } +}; + +struct NewDeclaration : FuncDeclaration +{ Parameters *arguments; + int varargs; + + NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); + + NewDeclaration *isNewDeclaration() { return this; } +}; + + +struct DeleteDeclaration : FuncDeclaration +{ Parameters *arguments; + + DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + int isDelete(); + int isVirtual(); + int addPreInvariant(); + int addPostInvariant(); +#ifdef _DH + DeleteDeclaration *isDeleteDeclaration() { return this; } +#endif +}; + +#endif /* DMD_DECLARATION_H */ diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c index da38f2a7..3f5b7257 100644 --- a/dmd2/delegatize.c +++ b/dmd2/delegatize.c @@ -1,214 +1,214 @@ - -// 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 -#include - -#include "mars.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" - -/******************************************** - * Convert from expression to delegate that returns the expression, - * i.e. convert: - * expr - * to: - * t delegate() { return expr; } - */ - -Expression *Expression::toDelegate(Scope *sc, Type *t) -{ - //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); - TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd); - FuncLiteralDeclaration *fld = - new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); - Expression *e; -#if 1 - sc = sc->push(); - sc->parent = fld; // set current function to be the delegate - e = this; - e->scanForNestedRef(sc); - sc = sc->pop(); -#else - e = this->syntaxCopy(); -#endif - Statement *s = new ReturnStatement(loc, e); - fld->fbody = s; - e = new FuncExp(loc, fld); - e = e->semantic(sc); - return e; -} - -/****************************** - * Perform scanForNestedRef() on an array of Expressions. - */ - -void arrayExpressionScanForNestedRef(Scope *sc, Expressions *a) -{ - //printf("arrayExpressionScanForNestedRef(%p)\n", a); - if (a) - { - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; - - if (e) - { - e->scanForNestedRef(sc); - } - } - } -} - -void Expression::scanForNestedRef(Scope *sc) -{ - //printf("Expression::scanForNestedRef(%s)\n", toChars()); -} - -void SymOffExp::scanForNestedRef(Scope *sc) -{ - //printf("SymOffExp::scanForNestedRef(%s)\n", toChars()); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); -} - -void VarExp::scanForNestedRef(Scope *sc) -{ - //printf("VarExp::scanForNestedRef(%s)\n", toChars()); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); -} - -void ThisExp::scanForNestedRef(Scope *sc) -{ - assert(var); - var->isVarDeclaration()->checkNestedReference(sc, 0); -} - -void SuperExp::scanForNestedRef(Scope *sc) -{ - ThisExp::scanForNestedRef(sc); -} - -void FuncExp::scanForNestedRef(Scope *sc) -{ - //printf("FuncExp::scanForNestedRef(%s)\n", toChars()); - //fd->parent = sc->parent; -} - -void DeclarationExp::scanForNestedRef(Scope *sc) -{ - //printf("DeclarationExp::scanForNestedRef() %s\n", toChars()); - declaration->parent = sc->parent; -} - -void NewExp::scanForNestedRef(Scope *sc) -{ - //printf("NewExp::scanForNestedRef(Scope *sc): %s\n", toChars()); - - if (thisexp) - thisexp->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, newargs); - arrayExpressionScanForNestedRef(sc, arguments); -} - -void UnaExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); -} - -void BinExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - e2->scanForNestedRef(sc); -} - -void CallExp::scanForNestedRef(Scope *sc) -{ - //printf("CallExp::scanForNestedRef(Scope *sc): %s\n", toChars()); - e1->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, arguments); -} - - -void IndexExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - - if (lengthVar) - { //printf("lengthVar\n"); - lengthVar->parent = sc->parent; - } - e2->scanForNestedRef(sc); -} - - -void SliceExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - - if (lengthVar) - { //printf("lengthVar\n"); - lengthVar->parent = sc->parent; - } - if (lwr) - lwr->scanForNestedRef(sc); - if (upr) - upr->scanForNestedRef(sc); -} - - -void ArrayLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, elements); -} - - -void AssocArrayLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, keys); - arrayExpressionScanForNestedRef(sc, values); -} - - -void StructLiteralExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, elements); -} - - -void TupleExp::scanForNestedRef(Scope *sc) -{ - arrayExpressionScanForNestedRef(sc, exps); -} - - -void ArrayExp::scanForNestedRef(Scope *sc) -{ - e1->scanForNestedRef(sc); - arrayExpressionScanForNestedRef(sc, arguments); -} - - -void CondExp::scanForNestedRef(Scope *sc) -{ - econd->scanForNestedRef(sc); - e1->scanForNestedRef(sc); - e2->scanForNestedRef(sc); -} - - - + +// 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 +#include + +#include "mars.h" +#include "expression.h" +#include "statement.h" +#include "mtype.h" +#include "utf.h" +#include "declaration.h" +#include "aggregate.h" +#include "scope.h" + +/******************************************** + * Convert from expression to delegate that returns the expression, + * i.e. convert: + * expr + * to: + * t delegate() { return expr; } + */ + +Expression *Expression::toDelegate(Scope *sc, Type *t) +{ + //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); + TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd); + FuncLiteralDeclaration *fld = + new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); + Expression *e; +#if 1 + sc = sc->push(); + sc->parent = fld; // set current function to be the delegate + e = this; + e->scanForNestedRef(sc); + sc = sc->pop(); +#else + e = this->syntaxCopy(); +#endif + Statement *s = new ReturnStatement(loc, e); + fld->fbody = s; + e = new FuncExp(loc, fld); + e = e->semantic(sc); + return e; +} + +/****************************** + * Perform scanForNestedRef() on an array of Expressions. + */ + +void arrayExpressionScanForNestedRef(Scope *sc, Expressions *a) +{ + //printf("arrayExpressionScanForNestedRef(%p)\n", a); + if (a) + { + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)a->data[i]; + + if (e) + { + e->scanForNestedRef(sc); + } + } + } +} + +void Expression::scanForNestedRef(Scope *sc) +{ + //printf("Expression::scanForNestedRef(%s)\n", toChars()); +} + +void SymOffExp::scanForNestedRef(Scope *sc) +{ + //printf("SymOffExp::scanForNestedRef(%s)\n", toChars()); + VarDeclaration *v = var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, 0); +} + +void VarExp::scanForNestedRef(Scope *sc) +{ + //printf("VarExp::scanForNestedRef(%s)\n", toChars()); + VarDeclaration *v = var->isVarDeclaration(); + if (v) + v->checkNestedReference(sc, 0); +} + +void ThisExp::scanForNestedRef(Scope *sc) +{ + assert(var); + var->isVarDeclaration()->checkNestedReference(sc, 0); +} + +void SuperExp::scanForNestedRef(Scope *sc) +{ + ThisExp::scanForNestedRef(sc); +} + +void FuncExp::scanForNestedRef(Scope *sc) +{ + //printf("FuncExp::scanForNestedRef(%s)\n", toChars()); + //fd->parent = sc->parent; +} + +void DeclarationExp::scanForNestedRef(Scope *sc) +{ + //printf("DeclarationExp::scanForNestedRef() %s\n", toChars()); + declaration->parent = sc->parent; +} + +void NewExp::scanForNestedRef(Scope *sc) +{ + //printf("NewExp::scanForNestedRef(Scope *sc): %s\n", toChars()); + + if (thisexp) + thisexp->scanForNestedRef(sc); + arrayExpressionScanForNestedRef(sc, newargs); + arrayExpressionScanForNestedRef(sc, arguments); +} + +void UnaExp::scanForNestedRef(Scope *sc) +{ + e1->scanForNestedRef(sc); +} + +void BinExp::scanForNestedRef(Scope *sc) +{ + e1->scanForNestedRef(sc); + e2->scanForNestedRef(sc); +} + +void CallExp::scanForNestedRef(Scope *sc) +{ + //printf("CallExp::scanForNestedRef(Scope *sc): %s\n", toChars()); + e1->scanForNestedRef(sc); + arrayExpressionScanForNestedRef(sc, arguments); +} + + +void IndexExp::scanForNestedRef(Scope *sc) +{ + e1->scanForNestedRef(sc); + + if (lengthVar) + { //printf("lengthVar\n"); + lengthVar->parent = sc->parent; + } + e2->scanForNestedRef(sc); +} + + +void SliceExp::scanForNestedRef(Scope *sc) +{ + e1->scanForNestedRef(sc); + + if (lengthVar) + { //printf("lengthVar\n"); + lengthVar->parent = sc->parent; + } + if (lwr) + lwr->scanForNestedRef(sc); + if (upr) + upr->scanForNestedRef(sc); +} + + +void ArrayLiteralExp::scanForNestedRef(Scope *sc) +{ + arrayExpressionScanForNestedRef(sc, elements); +} + + +void AssocArrayLiteralExp::scanForNestedRef(Scope *sc) +{ + arrayExpressionScanForNestedRef(sc, keys); + arrayExpressionScanForNestedRef(sc, values); +} + + +void StructLiteralExp::scanForNestedRef(Scope *sc) +{ + arrayExpressionScanForNestedRef(sc, elements); +} + + +void TupleExp::scanForNestedRef(Scope *sc) +{ + arrayExpressionScanForNestedRef(sc, exps); +} + + +void ArrayExp::scanForNestedRef(Scope *sc) +{ + e1->scanForNestedRef(sc); + arrayExpressionScanForNestedRef(sc, arguments); +} + + +void CondExp::scanForNestedRef(Scope *sc) +{ + econd->scanForNestedRef(sc); + e1->scanForNestedRef(sc); + e2->scanForNestedRef(sc); +} + + + diff --git a/dmd2/doc.c b/dmd2/doc.c index 4f5ac765..2a373744 100644 --- a/dmd2/doc.c +++ b/dmd2/doc.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -33,6 +33,7 @@ #include "hdrgen.h" #include "doc.h" #include "mtype.h" +#include "utf.h" struct Escape { @@ -66,7 +67,7 @@ struct MacroSection : Section struct DocComment { - Array sections; // Section*[] + Array sections; // Section*[] Section *summary; Section *copyright; @@ -89,57 +90,61 @@ int cmp(const char *stringz, void *s, size_t slen); int icmp(const char *stringz, void *s, size_t slen); int isDitto(unsigned char *comment); unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, unsigned i); -unsigned skippastident(OutBuffer *buf, unsigned i); -unsigned skippastURL(OutBuffer *buf, unsigned i); +unsigned skiptoident(OutBuffer *buf, size_t i); +unsigned skippastident(OutBuffer *buf, size_t i); +unsigned skippastURL(OutBuffer *buf, size_t i); void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); + +int isIdStart(unsigned char *p); +int isIdTail(unsigned char *p); +int utfStride(unsigned char *p); static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

\n\ - $(BODY)\n\ -
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ - \n\ +DDOC = \n\ + \n\ + $(TITLE)\n\ + \n\ +

$(TITLE)

\n\ + $(BODY)\n\ +
$(SMALL Page generated by $(LINK2 http://www.digitalmars.com/d/2.0/ddoc.html, Ddoc). $(COPYRIGHT))\n\ + \n\ \n\ -B = $0\n\ -I = $0\n\ -U = $0\n\ -P =

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ +B = $0\n\ +I = $0\n\ +U = $0\n\ +P =

    $0

    \n\ +DL =
    $0
    \n\ +DT =
    $0
    \n\ +DD =
    $0
    \n\ +TABLE = $0
    \n\ +TR = $0\n\ +TH = $0\n\ +TD = $0\n\ +OL =
      $0
    \n\ +UL =
      $0
    \n\ +LI =
  • $0
  • \n\ +BIG = $0\n\ +SMALL = $0\n\ +BR =
    \n\ +LINK = $0\n\ +LINK2 = $+\n\ \n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ +RED = $0\n\ +BLUE = $0\n\ +GREEN = $0\n\ YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ +BLACK = $0\n\ +WHITE = $0\n\ \n\ D_CODE =
    $0
    \n\ D_COMMENT = $(GREEN $0)\n\ D_STRING = $(RED $0)\n\ D_KEYWORD = $(BLUE $0)\n\ D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ +D_PARAM = $(I $0)\n\ \n\ DDOC_COMMENT = \n\ DDOC_DECL = $(DT $(BIG $0))\n\ @@ -173,15 +178,15 @@ DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ DDOC_PARAM_ROW = $(TR $0)\n\ DDOC_PARAM_ID = $(TD $0)\n\ DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ +DDOC_BLANKLINE = $(BR)$(BR)\n\ \n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ +DDOC_PSYMBOL = $(U $0)\n\ +DDOC_KEYWORD = $(B $0)\n\ +DDOC_PARAM = $(I $0)\n\ \n\ ESCAPES = //>/\n\ - /&/&/\n\ + />/>/\n\ + /&/&/\n\ "; static char ddoc_decl_s[] = "$(DDOC_DECL "; @@ -203,32 +208,32 @@ void Module::gendocfile() //printf("Module::gendocfile()\n"); - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; + if (!mbuf_done) // if not already read the ddoc files + { mbuf_done = 1; - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); + // Use our internal default + mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); + // Override with DDOCFILE specified in the sc.ini file + char *p = getenv("DDOCFILE"); + if (p) + global.params.ddocfiles->shift(p); - // Override with the ddoc macro files from the command line - for (int i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f((char *)global.params.ddocfiles->data[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use + // Override with the ddoc macro files from the command line + for (int i = 0; i < global.params.ddocfiles->dim; i++) + { + FileName f((char *)global.params.ddocfiles->data[i], 0); + File file(&f); + file.readv(); + // BUG: convert file contents to UTF-8 before use - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } + //printf("file: '%.*s'\n", file.len, file.buffer); + mbuf.write(file.buffer, file.len); + } } DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - Scope *sc = Scope::createGlobal(this); // create root scope + Scope *sc = Scope::createGlobal(this); // create root scope sc->docbuf = &buf; DocComment *dc = DocComment::parse(sc, this, comment); @@ -238,8 +243,8 @@ void Module::gendocfile() // Generate predefined macros // Set the title to be the name of the module - { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); + { const char *p = toPrettyChars(); + Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); } time_t t; @@ -254,26 +259,26 @@ void Module::gendocfile() if (dc->copyright) { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); + dc->copyright->nooutput = 1; + Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); } buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); if (isDocFile) { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); + size_t commentlen = strlen((char *)comment); + if (dc->macros) + { + commentlen = dc->macros->name - comment; + dc->macros->write(dc, sc, this, sc->docbuf); + } + sc->docbuf->write(comment, commentlen); + highlightText(NULL, this, sc->docbuf, 0); } else { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); + dc->writeSections(sc, this, sc->docbuf); + emitMemberComments(sc); } //printf("BODY= '%.*s'\n", buf.offset, buf.data); @@ -289,30 +294,30 @@ void Module::gendocfile() * and make CR-LF the newline. */ { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } + buf.setsize(0); + buf.reserve(buf2.offset); + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + unsigned char c = p[j]; + if (c == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + if (c == '\n') + buf.writeByte('\r'); + else if (c == '\r') + { + buf.writestring("\r\n"); + if (j + 1 < buf2.offset && p[j + 1] == '\n') + { + j++; + } + continue; + } + buf.writeByte(c); + } } // Transfer image to file @@ -321,25 +326,25 @@ void Module::gendocfile() docfile->ref = 1; char *pt = FileName::path(docfile->toChars()); if (*pt) - FileName::ensurePathExists(pt); + FileName::ensurePathExists(pt); mem.free(pt); docfile->writev(); #else /* Remove all the escape sequences from buf2 */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); + { unsigned i = 0; + unsigned char *p = buf2.data; + for (unsigned j = 0; j < buf2.offset; j++) + { + if (p[j] == 0xFF && j + 1 < buf2.offset) + { + j++; + continue; + } + p[i] = p[j]; + i++; + } + buf2.setsize(i); } // Transfer image to file @@ -347,12 +352,84 @@ void Module::gendocfile() docfile->ref = 1; char *pt = FileName::path(docfile->toChars()); if (*pt) - FileName::ensurePathExists(pt); + FileName::ensurePathExists(pt); mem.free(pt); docfile->writev(); #endif } +/**************************************************** + * Having unmatched parentheses can hose the output of Ddoc, + * as the macros depend on properly nested parentheses. + * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). + */ +void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) +{ + unsigned par_open = 0; + + for (unsigned u = start; u < buf->offset; u++) + { + unsigned char c = buf->data[u]; + switch(c) + { + case '(': + par_open++; + break; + + case ')': + if (par_open == 0) + { + //stray ')' + if (global.params.warnings) + warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." + " Use $(RPAREN) instead for unpaired right parentheses."); + buf->remove(u, 1); //remove the ) + buf->insert(u, "$(RPAREN)", 9); //insert this instead + u += 8; //skip over newly inserted macro + } + else + par_open--; + break; +#if 0 + // For this to work, loc must be set to the beginning of the passed + // text which is currently not possible + // (loc is set to the Loc of the Dsymbol) + case '\n': + loc.linnum++; + break; +#endif + } + } + + if (par_open) // if any unmatched lparens + { par_open = 0; + for (unsigned u = buf->offset; u > start;) + { u--; + unsigned char c = buf->data[u]; + switch(c) + { + case ')': + par_open++; + break; + + case '(': + if (par_open == 0) + { + //stray '(' + if (global.params.warnings) + warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." + " Use $(LPAREN) instead for unpaired left parentheses."); + buf->remove(u, 1); //remove the ( + buf->insert(u, "$(LPAREN)", 9); //insert this instead + } + else + par_open--; + break; + } + } + } +} + /******************************* emitComment **********************************/ /* @@ -367,20 +444,20 @@ void Dsymbol::emitDitto(Scope *sc) OutBuffer b; b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); + o = b.offset; + toDocBuffer(&b); + //printf("b: '%.*s'\n", b.offset, b.data); + /* If 'this' is a function template, then highlightCode() was + * already run by FuncDeclaration::toDocbuffer(). + */ + TemplateDeclaration *td; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { + } + else + highlightCode(sc, this, &b, o); b.writeByte(')'); buf->spread(sc->lastoffset, b.offset); memcpy(buf->data + sc->lastoffset, b.data, b.offset); @@ -393,38 +470,38 @@ void ScopeDsymbol::emitMemberComments(Scope *sc) OutBuffer *buf = sc->docbuf; if (members) - { const char *m = "$(DDOC_MEMBERS \n"; + { const char *m = "$(DDOC_MEMBERS \n"; - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; + if (isModule()) + m = "$(DDOC_MODULE_MEMBERS \n"; + else if (isClassDeclaration()) + m = "$(DDOC_CLASS_MEMBERS \n"; + else if (isStructDeclaration()) + m = "$(DDOC_STRUCT_MEMBERS \n"; + else if (isEnumDeclaration()) + m = "$(DDOC_ENUM_MEMBERS \n"; + else if (isTemplateDeclaration()) + m = "$(DDOC_TEMPLATE_MEMBERS \n"; - unsigned offset1 = buf->offset; // save starting offset - buf->writestring(m); - unsigned offset2 = buf->offset; // to see if we write anything - sc = sc->push(this); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); + unsigned offset1 = buf->offset; // save starting offset + buf->writestring(m); + unsigned offset2 = buf->offset; // to see if we write anything + sc = sc->push(this); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("\ts = '%s'\n", s->toChars()); + s->emitComment(sc); + } + sc->pop(); + if (buf->offset == offset2) + { + /* Didn't write out any members, so back out last write + */ + buf->offset = offset1; + } + else + buf->writestring(")\n"); } } @@ -434,21 +511,21 @@ void emitProtection(OutBuffer *buf, PROT prot) switch (prot) { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; + case PROTpackage: p = "package"; break; + case PROTprotected: p = "protected"; break; + case PROTexport: p = "export"; break; + default: p = NULL; break; } if (p) - buf->printf("%s ", p); + buf->printf("%s ", p); } -void Dsymbol::emitComment(Scope *sc) { } +void Dsymbol::emitComment(Scope *sc) { } void InvariantDeclaration::emitComment(Scope *sc) { } #if DMDV2 void PostBlitDeclaration::emitComment(Scope *sc) { } #endif -void DtorDeclaration::emitComment(Scope *sc) { } +void DtorDeclaration::emitComment(Scope *sc) { } void StaticCtorDeclaration::emitComment(Scope *sc) { } void StaticDtorDeclaration::emitComment(Scope *sc) { } void ClassInfoDeclaration::emitComment(Scope *sc) { } @@ -462,10 +539,10 @@ void Declaration::emitComment(Scope *sc) //printf("type = %p\n", type); if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; + (!type && !isCtorDeclaration() && !isAliasDeclaration())) + return; if (!comment) - return; + return; OutBuffer *buf = sc->docbuf; DocComment *dc = DocComment::parse(sc, this, comment); @@ -473,16 +550,16 @@ void Declaration::emitComment(Scope *sc) if (!dc) { - emitDitto(sc); - return; + emitDitto(sc); + return; } dc->pmacrotable = &sc->module->macrotable; buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; buf->writestring(ddoc_decl_e); buf->writestring(ddoc_decl_dd_s); @@ -494,17 +571,17 @@ void AggregateDeclaration::emitComment(Scope *sc) { //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); if (prot() == PROTprivate) - return; + return; if (!comment) - return; + return; OutBuffer *buf = sc->docbuf; DocComment *dc = DocComment::parse(sc, this, comment); if (!dc) { - emitDitto(sc); - return; + emitDitto(sc); + return; } dc->pmacrotable = &sc->module->macrotable; @@ -523,7 +600,7 @@ void TemplateDeclaration::emitComment(Scope *sc) { //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); if (prot() == PROTprivate) - return; + return; unsigned char *com = comment; int hasmembers = 1; @@ -532,22 +609,22 @@ void TemplateDeclaration::emitComment(Scope *sc) if (onemember) { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } + ss = onemember->isAggregateDeclaration(); + if (!ss) + { + ss = onemember->isFuncDeclaration(); + if (ss) + { hasmembers = 0; + if (com != ss->comment) + com = Lexer::combineComments(com, ss->comment); + } + else + ss = this; + } } if (!com) - return; + return; OutBuffer *buf = sc->docbuf; DocComment *dc = DocComment::parse(sc, this, com); @@ -555,59 +632,59 @@ void TemplateDeclaration::emitComment(Scope *sc) if (!dc) { - ss->emitDitto(sc); - return; + ss->emitDitto(sc); + return; } dc->pmacrotable = &sc->module->macrotable; buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; + o = buf->offset; + ss->toDocBuffer(buf); + if (ss == this) + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; buf->writestring(ddoc_decl_e); buf->writestring(ddoc_decl_dd_s); dc->writeSections(sc, this, buf); if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); + ((ScopeDsymbol *)ss)->emitMemberComments(sc); buf->writestring(ddoc_decl_dd_e); } void EnumDeclaration::emitComment(Scope *sc) { if (prot() == PROTprivate) - return; + return; // if (!comment) - { if (isAnonymous() && members) - { - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->emitComment(sc); - } - return; - } + { if (isAnonymous() && members) + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->emitComment(sc); + } + return; + } } if (!comment) - return; + return; if (isAnonymous()) - return; + return; OutBuffer *buf = sc->docbuf; DocComment *dc = DocComment::parse(sc, this, comment); if (!dc) { - emitDitto(sc); - return; + emitDitto(sc); + return; } dc->pmacrotable = &sc->module->macrotable; buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; + toDocBuffer(buf); + sc->lastoffset = buf->offset; buf->writestring(ddoc_decl_e); buf->writestring(ddoc_decl_dd_s); @@ -620,9 +697,9 @@ void EnumMember::emitComment(Scope *sc) { //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); if (prot() == PROTprivate) - return; + return; if (!comment) - return; + return; OutBuffer *buf = sc->docbuf; DocComment *dc = DocComment::parse(sc, this, comment); @@ -630,16 +707,16 @@ void EnumMember::emitComment(Scope *sc) if (!dc) { - emitDitto(sc); - return; + emitDitto(sc); + return; } dc->pmacrotable = &sc->module->macrotable; buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; + o = buf->offset; + toDocBuffer(buf); + highlightCode(sc, this, buf, o); + sc->lastoffset = buf->offset; buf->writestring(ddoc_decl_e); buf->writestring(ddoc_decl_dd_s); @@ -661,25 +738,25 @@ void Dsymbol::toDocBuffer(OutBuffer *buf) void prefix(OutBuffer *buf, Dsymbol *s) { if (s->isDeprecated()) - buf->writestring("deprecated "); + buf->writestring("deprecated "); Declaration *d = s->isDeclaration(); if (d) { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); + emitProtection(buf, d->protection); + if (d->isAbstract()) + buf->writestring("abstract "); + if (d->isStatic()) + buf->writestring("static "); + if (d->isConst()) + buf->writestring("const "); #if DMDV2 - if (d->isInvariant()) - buf->writestring("invariant "); + if (d->isImmutable()) + buf->writestring("immutable "); #endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); + if (d->isFinal()) + buf->writestring("final "); + if (d->isSynchronized()) + buf->writestring("synchronized "); } } @@ -688,21 +765,21 @@ void Declaration::toDocBuffer(OutBuffer *buf) //printf("Declaration::toDocbuffer() %s, originalType = %p\n", toChars(), originalType); if (ident) { - prefix(buf, this); + prefix(buf, this); - if (type) - { HdrGenState hgs; - hgs.ddoc = 1; - if (originalType) - { //originalType->print(); - originalType->toCBuffer(buf, ident, &hgs); - } - else - type->toCBuffer(buf, ident, &hgs); - } - else - buf->writestring(ident->toChars()); - buf->writestring(";\n"); + if (type) + { HdrGenState hgs; + hgs.ddoc = 1; + if (originalType) + { //originalType->print(); + originalType->toCBuffer(buf, ident, &hgs); + } + else + type->toCBuffer(buf, ident, &hgs); + } + else + buf->writestring(ident->toChars()); + buf->writestring(";\n"); } } @@ -712,13 +789,13 @@ void AliasDeclaration::toDocBuffer(OutBuffer *buf) //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); if (ident) { - if (isDeprecated()) - buf->writestring("deprecated "); + if (isDeprecated()) + buf->writestring("deprecated "); - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); + emitProtection(buf, protection); + buf->writestring("alias "); + buf->writestring(toChars()); + buf->writestring(";\n"); } } @@ -727,13 +804,13 @@ void TypedefDeclaration::toDocBuffer(OutBuffer *buf) { if (ident) { - if (isDeprecated()) - buf->writestring("deprecated "); + if (isDeprecated()) + buf->writestring("deprecated "); - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); + emitProtection(buf, protection); + buf->writestring("typedef "); + buf->writestring(toChars()); + buf->writestring(";\n"); } } @@ -743,40 +820,40 @@ void FuncDeclaration::toDocBuffer(OutBuffer *buf) //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); if (ident) { - TemplateDeclaration *td; + TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - HdrGenState hgs; - unsigned o = buf->offset; - TypeFunction *tf = (TypeFunction *)type; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { /* It's a function template + */ + HdrGenState hgs; + unsigned o = buf->offset; + TypeFunction *tf = (TypeFunction *)type; - hgs.ddoc = 1; - prefix(buf, td); - tf->next->toCBuffer(buf, NULL, &hgs); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (int i = 0; i < td->origParameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, &hgs); - } - buf->writeByte(')'); - Argument::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); - buf->writestring(";\n"); + hgs.ddoc = 1; + prefix(buf, td); + tf->next->toCBuffer(buf, NULL, &hgs); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + buf->writeByte('('); + for (int i = 0; i < td->origParameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)td->origParameters->data[i]; + if (i) + buf->writestring(", "); + tp->toCBuffer(buf, &hgs); + } + buf->writeByte(')'); + Parameter::argsToCBuffer(buf, &hgs, tf->parameters, tf->varargs); + buf->writestring(";\n"); - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } + highlightCode(NULL, this, buf, o); + } + else + { + Declaration::toDocBuffer(buf); + } } } @@ -785,7 +862,7 @@ void CtorDeclaration::toDocBuffer(OutBuffer *buf) HdrGenState hgs; buf->writestring("this"); - Argument::argsToCBuffer(buf, &hgs, arguments, varargs); + Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); buf->writestring(";\n"); } @@ -795,10 +872,10 @@ void AggregateDeclaration::toDocBuffer(OutBuffer *buf) if (ident) { #if 0 - emitProtection(buf, protection); + emitProtection(buf, protection); #endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); } } @@ -808,22 +885,22 @@ void StructDeclaration::toDocBuffer(OutBuffer *buf) if (ident) { #if 0 - emitProtection(buf, protection); + emitProtection(buf, protection); #endif - TemplateDeclaration *td; + TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + buf->writestring(";\n"); } } @@ -833,50 +910,50 @@ void ClassDeclaration::toDocBuffer(OutBuffer *buf) if (ident) { #if 0 - emitProtection(buf, protection); + emitProtection(buf, protection); #endif - TemplateDeclaration *td; + TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - if (isAbstract()) - buf->writestring("abstract "); - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (int i = 0; i < baseclasses.dim; i++) - { BaseClass *bc = (BaseClass *)baseclasses.data[i]; + if (parent && + (td = parent->isTemplateDeclaration()) != NULL && + td->onemember == this) + { unsigned o = buf->offset; + td->toDocBuffer(buf); + highlightCode(NULL, this, buf, o); + } + else + { + if (isAbstract()) + buf->writestring("abstract "); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + } + int any = 0; + for (int i = 0; i < baseclasses->dim; i++) + { BaseClass *bc = (BaseClass *)baseclasses->data[i]; - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; + if (bc->protection == PROTprivate) + continue; + if (bc->base && bc->base->ident == Id::Object) + continue; - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); + if (any) + buf->writestring(", "); + else + { buf->writestring(": "); + any = 1; + } + emitProtection(buf, bc->protection); + if (bc->base) + { + buf->writestring(bc->base->toPrettyChars()); + } + else + { + HdrGenState hgs; + bc->type->toCBuffer(buf, NULL, &hgs); + } + } + buf->writestring(";\n"); } } @@ -885,8 +962,8 @@ void EnumDeclaration::toDocBuffer(OutBuffer *buf) { if (ident) { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); + buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); + buf->writestring(";\n"); } } @@ -894,7 +971,7 @@ void EnumMember::toDocBuffer(OutBuffer *buf) { if (ident) { - buf->writestring(toChars()); + buf->writestring(toChars()); } } @@ -911,25 +988,25 @@ DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) //printf("parse(%s): '%s'\n", s->toChars(), comment); if (sc->lastdc && isDitto(comment)) - return NULL; + return NULL; DocComment *dc = new DocComment(); if (!comment) - return dc; + return dc; dc->parseSections(comment); for (int i = 0; i < dc->sections.dim; i++) - { Section *s = (Section *)dc->sections.data[i]; + { Section *s = (Section *)dc->sections.data[i]; - if (icmp("copyright", s->name, s->namelen) == 0) - { - dc->copyright = s; - } - if (icmp("macros", s->name, s->namelen) == 0) - { - dc->macros = s; - } + if (icmp("copyright", s->name, s->namelen) == 0) + { + dc->copyright = s; + } + if (icmp("macros", s->name, s->namelen) == 0) + { + dc->macros = s; + } } sc->lastdc = dc; @@ -948,7 +1025,6 @@ void DocComment::parseSections(unsigned char *comment) { unsigned char *p; unsigned char *pstart; unsigned char *pend; - unsigned char *q; unsigned char *idstart; unsigned idlen; @@ -959,87 +1035,103 @@ void DocComment::parseSections(unsigned char *comment) p = comment; while (*p) { - p = skipwhitespace(p); - pstart = p; + p = skipwhitespace(p); + pstart = p; + pend = p; - /* Find end of section, which is ended by one of: - * 'identifier:' - * '\0' - */ - idlen = 0; - while (1) - { - if (isalpha(*p) || *p == '_') - { - q = p + 1; - while (isalnum(*q) || *q == '_') - q++; - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - { pend = p; - goto L1; - } - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - } - p = skipwhitespace(p); - } + /* Find end of section, which is ended by one of: + * 'identifier:' (but not inside a code section) + * '\0' + */ + idlen = 0; + int inCode = 0; + while (1) + { + // Check for start/end of a code section + if (*p == '-') + { + int numdash = 0; + while (*p == '-') + { + ++numdash; + p++; + } + // BUG: handle UTF PS and LS too + if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) + inCode ^= 1; + pend = p; + } + + if (!inCode && isIdStart(p)) + { + unsigned char *q = p + utfStride(p); + while (isIdTail(q)) + q += utfStride(q); + if (*q == ':') // identifier: ends it + { idlen = q - p; + idstart = p; + for (pend = p; pend > pstart; pend--) + { if (pend[-1] == '\n') + break; + } + p = q + 1; + break; + } + } + while (1) + { + if (!*p) + goto L1; + if (*p == '\n') + { p++; + if (*p == '\n' && !summary && !namelen) + { + pend = p; + p++; + goto L1; + } + break; + } + p++; + pend = p; + } + p = skipwhitespace(p); + } L1: - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; + if (namelen || pstart < pend) + { + Section *s; + if (icmp("Params", name, namelen) == 0) + s = new ParamSection(); + else if (icmp("Macros", name, namelen) == 0) + s = new MacroSection(); + else + s = new Section(); + s->name = name; + s->namelen = namelen; + s->body = pstart; + s->bodylen = pend - pstart; + s->nooutput = 0; - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); + //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - sections.push(s); + sections.push(s); - if (!summary && !namelen) - summary = s; - } + if (!summary && !namelen) + summary = s; + } - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } + if (idlen) + { name = idstart; + namelen = idlen; + } + else + { name = NULL; + namelen = 0; + if (!*p) + break; + } } } @@ -1048,29 +1140,30 @@ void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) //printf("DocComment::writeSections()\n"); if (sections.dim) { - buf->writestring("$(DDOC_SECTIONS \n"); - for (int i = 0; i < sections.dim; i++) - { Section *sec = (Section *)sections.data[i]; + buf->writestring("$(DDOC_SECTIONS \n"); + for (int i = 0; i < sections.dim; i++) + { Section *sec = (Section *)sections.data[i]; - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); + if (sec->nooutput) + continue; + //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); + if (sec->namelen || i) + sec->write(this, sc, s, buf); + else + { + buf->writestring("$(DDOC_SUMMARY "); + unsigned o = buf->offset; + buf->write(sec->body, sec->bodylen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")\n"); + } + } + buf->writestring(")\n"); } else { - buf->writestring("$(DDOC_BLANKLINE)\n"); + buf->writestring("$(DDOC_BLANKLINE)\n"); } } @@ -1081,37 +1174,40 @@ void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) { if (namelen) { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; + static const char *table[] = + { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", + "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", + "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", + "VERSION" }; - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (icmp(table[i], name, namelen) == 0) + { + buf->printf("$(DDOC_%s ", table[i]); + goto L1; + } + } - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - buf->writestring(":)\n"); + buf->writestring("$(DDOC_SECTION "); + // Replace _ characters with spaces + buf->writestring("$(DDOC_SECTION_H "); + unsigned o = buf->offset; + for (unsigned u = 0; u < namelen; u++) + { unsigned char c = name[u]; + buf->writeByte((c == '_') ? ' ' : c); + } + escapeStrayParenthesis(buf, o, s->loc); + buf->writestring(":)\n"); } else { - buf->writestring("$(DDOC_DESCRIPTION "); + buf->writestring("$(DDOC_DESCRIPTION "); } L1: unsigned o = buf->offset; buf->write(body, bodylen); + escapeStrayParenthesis(buf, o, s->loc); highlightText(sc, s, buf, o); buf->writestring(")\n"); } @@ -1129,108 +1225,109 @@ void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) unsigned templen; unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation + unsigned namelen = 0; // !=0 if line continuation unsigned char *textstart; unsigned textlen; unsigned o; - Argument *arg; + Parameter *arg; buf->writestring("$(DDOC_PARAMS \n"); while (p < pend) { - // Skip to start of macro - for (; 1; p++) - { - switch (*p) - { - case ' ': - case '\t': - continue; + // Skip to start of macro + while (1) + { + switch (*p) + { + case ' ': + case '\t': + p++; + continue; - case '\n': - p++; - goto Lcont; + case '\n': + p++; + goto Lcont; - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; - while (isalnum(*p) || *p == '_') - p++; - templen = p - tempstart; + while (isIdTail(p)) + p += utfStride(p); + templen = p - tempstart; - while (*p == ' ' || *p == '\t') - p++; + while (*p == ' ' || *p == '\t') + p++; - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; - if (namelen) - { // Output existing param + if (namelen) + { // Output existing param - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); + L1: + //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + HdrGenState hgs; + buf->writestring("$(DDOC_PARAM_ROW "); + buf->writestring("$(DDOC_PARAM_ID "); + o = buf->offset; + arg = isFunctionParameter(s, namestart, namelen); + if (arg && arg->type && arg->ident) + arg->type->toCBuffer(buf, arg->ident, &hgs); + else + buf->write(namestart, namelen); + escapeStrayParenthesis(buf, o, s->loc); + highlightCode(sc, s, buf, o); + buf->writestring(")\n"); - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } + buf->writestring("$(DDOC_PARAM_DESC "); + o = buf->offset; + buf->write(textstart, textlen); + escapeStrayParenthesis(buf, o, s->loc); + highlightText(sc, s, buf, o); + buf->writestring(")"); + buf->writestring(")\n"); + namelen = 0; + if (p >= pend) + break; + } - namestart = tempstart; - namelen = templen; + namestart = tempstart; + namelen = templen; - while (*p == ' ' || *p == '\t') - p++; - textstart = p; + while (*p == ' ' || *p == '\t') + p++; + textstart = p; Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; + while (*p != '\n') + p++; + textlen = p - textstart; + p++; Lcont: - continue; + continue; Lskipline: - // Ignore this line - while (*p++ != '\n') - ; + // Ignore this line + while (*p++ != '\n') + ; } if (namelen) - goto L1; // write out last one + goto L1; // write out last one buf->writestring(")\n"); } @@ -1246,9 +1343,9 @@ void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) /************************************************ * Parse macros out of Macros: section. * Macros are of the form: - * name1 = value1 + * name1 = value1 * - * name2 = value2 + * name2 = value2 */ void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) @@ -1261,117 +1358,116 @@ void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigne unsigned templen; unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation + unsigned namelen = 0; // !=0 if line continuation unsigned char *textstart; unsigned textlen; while (p < pend) { - // Skip to start of macro - for (; 1; p++) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - continue; + // Skip to start of macro + while (1) + { + if (p >= pend) + goto Ldone; + switch (*p) + { + case ' ': + case '\t': + p++; + continue; - case '\n': - p++; - goto Lcont; + case '\n': + p++; + goto Lcont; - default: - if (!(isalpha(*p) || *p == '_')) - { - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - break; - } - tempstart = p; + default: + if (isIdStart(p)) + break; + if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + break; + } + tempstart = p; - while (1) - { - if (p >= pend) - goto Ldone; - if (!(isalnum(*p) || *p == '_')) - break; - p++; - } - templen = p - tempstart; + while (1) + { + if (p >= pend) + goto Ldone; + if (!isIdTail(p)) + break; + p += utfStride(p); + } + templen = p - tempstart; - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } + while (1) + { + if (p >= pend) + goto Ldone; + if (!(*p == ' ' || *p == '\t')) + break; + p++; + } - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; + if (*p != '=') + { if (namelen) + goto Ltext; // continuation of prev macro + goto Lskipline; + } + p++; + if (p >= pend) + goto Ldone; - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } + if (namelen) + { // Output existing macro + L1: + //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); + if (icmp("ESCAPES", namestart, namelen) == 0) + parseEscapes(pescapetable, textstart, textlen); + else + Macro::define(pmacrotable, namestart, namelen, textstart, textlen); + namelen = 0; + if (p >= pend) + break; + } - namestart = tempstart; - namelen = templen; + namestart = tempstart; + namelen = templen; - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; + while (p < pend && (*p == ' ' || *p == '\t')) + p++; + textstart = p; Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; + while (p < pend && *p != '\n') + p++; + textlen = p - textstart; - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; + // Remove trailing \r if there is one + if (p > m && p[-1] == '\r') + textlen--; - p++; - //printf("p = %p, pend = %p\n", p, pend); + p++; + //printf("p = %p, pend = %p\n", p, pend); Lcont: - continue; + continue; Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; + // Ignore this line + while (p < pend && *p++ != '\n') + ; } Ldone: if (namelen) - goto L1; // write out last one + goto L1; // write out last one } /************************************** * Parse escapes of the form: - * /c/string/ + * /c/string/ * where c is a single character. * Multiple escapes can be separated * by whitespace and/or commas. @@ -1381,41 +1477,41 @@ void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, u { Escape *escapetable = *pescapetable; if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; + { escapetable = new Escape; + *pescapetable = escapetable; } unsigned char *p = textstart; unsigned char *pend = p + textlen; while (1) { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; + while (1) + { + if (p + 4 >= pend) + return; + if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) + break; + p++; + } + if (p[0] != '/' || p[2] != '/') + return; + unsigned char c = p[1]; + p += 3; + unsigned char *start = p; + while (1) + { + if (p >= pend) + return; + if (*p == '/') + break; + p++; + } + size_t len = p - start; + char *s = (char *)memcpy(mem.malloc(len + 1), start, len); + s[len] = 0; + escapetable->strings[c] = s; + //printf("%c = '%s'\n", c, s); + p++; } } @@ -1430,7 +1526,7 @@ int cmp(const char *stringz, void *s, size_t slen) size_t len1 = strlen(stringz); if (len1 != slen) - return len1 - slen; + return len1 - slen; return memcmp(stringz, s, slen); } @@ -1439,7 +1535,7 @@ int icmp(const char *stringz, void *s, size_t slen) size_t len1 = strlen(stringz); if (len1 != slen) - return len1 - slen; + return len1 - slen; return memicmp(stringz, (char *)s, slen); } @@ -1451,10 +1547,10 @@ int isDitto(unsigned char *comment) { if (comment) { - unsigned char *p = skipwhitespace(comment); + unsigned char *p = skipwhitespace(comment); - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; + if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) + return 1; } return 0; } @@ -1466,14 +1562,14 @@ int isDitto(unsigned char *comment) unsigned char *skipwhitespace(unsigned char *p) { for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; + { switch (*p) + { + case ' ': + case '\t': + case '\n': + continue; + } + break; } return p; } @@ -1481,21 +1577,30 @@ unsigned char *skipwhitespace(unsigned char *p) /************************************************ * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf + * start of identifier + * beginning of next line + * end of buf */ -unsigned skiptoident(OutBuffer *buf, unsigned i) +unsigned skiptoident(OutBuffer *buf, size_t i) { - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (isalpha(c) || c == '_') - break; - if (c == '\n') - break; + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (!isUniAlpha(c)) + continue; + } + else if (!(isalpha(c) || c == '_' || c == '\n')) + continue; + i = oi; + break; } return i; } @@ -1504,14 +1609,25 @@ unsigned skiptoident(OutBuffer *buf, unsigned i) * Scan forward past end of identifier. */ -unsigned skippastident(OutBuffer *buf, unsigned i) +unsigned skippastident(OutBuffer *buf, size_t i) { - for (; i < buf->offset; i++) - { - // BUG: handle unicode alpha's - unsigned char c = buf->data[i]; - if (!(isalnum(c) || c == '_')) - break; + while (i < buf->offset) + { dchar_t c; + + size_t oi = i; + if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) + /* Ignore UTF errors, but still consume input + */ + break; + if (c >= 0x80) + { + if (isUniAlpha(c)) + continue; + } + else if (isalnum(c) || c == '_') + continue; + i = oi; + break; } return i; } @@ -1521,11 +1637,11 @@ unsigned skippastident(OutBuffer *buf, unsigned i) * Scan forward past URL starting at i. * We don't want to highlight parts of a URL. * Returns: - * i if not a URL - * index just past it if it is a URL + * i if not a URL + * index just past it if it is a URL */ -unsigned skippastURL(OutBuffer *buf, unsigned i) +unsigned skippastURL(OutBuffer *buf, size_t i) { unsigned length = buf->offset - i; unsigned char *p = &buf->data[i]; unsigned j; @@ -1533,19 +1649,19 @@ unsigned skippastURL(OutBuffer *buf, unsigned i) if (length > 7 && memicmp((char *)p, "http://", 7) == 0) { - j = 7; + j = 7; } else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) { - j = 8; + j = 8; } else - goto Lno; + goto Lno; for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; + { unsigned char c = p[j]; + if (isalnum(c)) + continue; if (c == '-' || c == '_' || c == '?' || c == '=' || c == '%' || c == '&' || c == '/' || c == '+' || c == '#' || @@ -1559,7 +1675,7 @@ unsigned skippastURL(OutBuffer *buf, unsigned i) break; } if (sawdot) - return i + j; + return i + j; Lno: return i; @@ -1575,8 +1691,8 @@ int isKeyword(unsigned char *p, unsigned len) for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) { - if (cmp(table[i], p, len) == 0) - return 1; + if (cmp(table[i], p, len) == 0) + return 1; } return 0; } @@ -1584,7 +1700,7 @@ int isKeyword(unsigned char *p, unsigned len) /**************************************************** */ -Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) +Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) { FuncDeclaration *f = s->isFuncDeclaration(); @@ -1592,25 +1708,25 @@ Argument *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) */ if (f && f->type) { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; + TypeFunction *tf; + if (f->originalType) + { + tf = (TypeFunction *)f->originalType; + } + else + tf = (TypeFunction *)f->type; - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Argument *arg = (Argument *)tf->parameters->data[k]; + if (tf->parameters) + { + for (size_t k = 0; k < tf->parameters->dim; k++) + { Parameter *arg = (Parameter *)tf->parameters->data[k]; - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } + if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) + { + return arg; + } + } + } } return NULL; } @@ -1629,233 +1745,242 @@ void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) int leadingBlank = 1; int inCode = 0; - int inComment = 0; // in comment - unsigned iCodeStart; // start of code section + int inComment = 0; // in comment + unsigned iCodeStart; // start of code section unsigned iLineStart = offset; for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; + { unsigned char c = buf->data[i]; Lcont: - switch (c) - { - case ' ': - case '\t': - break; + switch (c) + { + case ' ': + case '\t': + break; - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; + case '\n': + if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" + { + static char blankline[] = "$(DDOC_BLANKLINE)\n"; - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; + i = buf->insert(i, blankline, sizeof(blankline) - 1); + } + leadingBlank = 1; + iLineStart = i + 1; + break; - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; + case '<': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } + // Skip over comments + if (p[1] == '!' && p[2] == '-' && p[3] == '-') + { unsigned j = i + 4; + p += 4; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '-' && p[1] == '-' && p[2] == '>') + { + i = j + 2; // place on closing '>' + break; + } + j++; + p++; + } + break; + } - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } + // Skip over HTML tag + if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) + { unsigned j = i + 2; + p += 2; + while (1) + { + if (j == buf->offset) + goto L1; + if (p[0] == '>') + { + i = j; // place on closing '>' + break; + } + j++; + p++; + } + break; + } - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; + L1: + // Replace '<' with '<' character entity + se = Escape::escapeChar('<'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; + case '>': + leadingBlank = 0; + if (inCode) + break; + // Replace '>' with '>' character entity + se = Escape::escapeChar('>'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; + case '&': + leadingBlank = 0; + if (inCode) + break; + p = &buf->data[i]; + if (p[1] == '#' || isalpha(p[1])) + break; // already a character entity + // Replace '&' with '&' character entity + se = Escape::escapeChar('&'); + if (se) + { size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + break; - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; + case '-': + /* A line beginning with --- delimits a code section. + * inCode tells us if it is start or end of a code section. + */ + if (leadingBlank) + { int istart = i; + int eollen = 0; - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; + leadingBlank = 0; + while (1) + { + ++i; + if (i >= buf->offset) + break; + c = buf->data[i]; + if (c == '\n') + { eollen = 1; + break; + } + if (c == '\r') + { + eollen = 1; + if (i + 1 >= buf->offset) + break; + if (buf->data[i + 1] == '\n') + { eollen = 2; + break; + } + } + // BUG: handle UTF PS and LS too + if (c != '-') + goto Lcont; + } + if (i - istart < 3) + goto Lcont; - // We have the start/end of a code section + // We have the start/end of a code section - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; + // Remove the entire --- line, including blanks and \n + buf->remove(iLineStart, i - iLineStart + eollen); + i = iLineStart; - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; + if (inCode && (i <= iCodeStart)) + { // Empty code section, just remove it completely. + inCode = 0; + break; + } - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; + if (inCode) + { + inCode = 0; + // The code section is from iCodeStart to i + OutBuffer codebuf; - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - } - } - break; + codebuf.write(buf->data + iCodeStart, i - iCodeStart); + codebuf.writeByte(0); + highlightCode2(sc, s, &codebuf, 0); + buf->remove(iCodeStart, i - iCodeStart); + i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); + i = buf->insert(i, ")\n", 2); + i--; + } + else + { static char pre[] = "$(D_CODE \n"; - default: - leadingBlank = 0; - if (sc && !inCode && (isalpha(c) || c == '_')) - { unsigned j; + inCode = 1; + i = buf->insert(i, pre, sizeof(pre) - 1); + iCodeStart = i; + i--; // place i on > + leadingBlank = true; + } + } + break; - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } + default: + leadingBlank = 0; + if (sc && !inCode && isIdStart(&buf->data[i])) + { unsigned j; - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } + j = skippastident(buf, i); + if (j > i) + { + unsigned k = skippastURL(buf, i); + if (k > i) + { i = k - 1; + break; + } + + if (buf->data[i] == '_') // leading '_' means no highlight + { + buf->remove(i, 1); + i = j - 1; + } + else + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + break; + } + else if (isKeyword(buf->data + i, j - i)) + { + i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; + break; + } + else + { + if (f && isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + break; + } + } + i = j - 1; + } + } + } + break; + } } Ldone: + if (inCode) + s->error("unmatched --- in DDoc comment"); ; } @@ -1870,40 +1995,40 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; + { unsigned char c = buf->data[i]; + const char *se; - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isalpha(c) || c == '_') - { unsigned j; + se = Escape::escapeChar(c); + if (se) + { + size_t len = strlen(se); + buf->remove(i, 1); + i = buf->insert(i, se, len); + i--; // point to ';' + } + else if (isIdStart(&buf->data[i])) + { unsigned j; - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } + j = skippastident(buf, i); + if (j > i) + { + if (cmp(sid, buf->data + i, j - i) == 0) + { + i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; + continue; + } + else if (f) + { + if (isFunctionParameter(f, buf->data + i, j - i)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; + continue; + } + } + i = j - 1; + } + } } } @@ -1913,11 +2038,11 @@ void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) { for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); + { const char *s = Escape::escapeChar(*p); + if (s) + buf->writestring(s); + else + buf->writeByte(*p); } } @@ -1941,51 +2066,51 @@ void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) res.reserve(buf->offset); while (1) { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; + lex.scan(&tok); + highlightCode3(&res, lastp, tok.ptr); + highlight = NULL; + switch (tok.value) + { + case TOKidentifier: + if (!sc) + break; + if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) + { + highlight = "$(D_PSYMBOL "; + break; + } + else if (f) + { + if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) + { + //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); + highlight = "$(D_PARAM "; + break; + } + } + break; - case TOKcomment: - highlight = "$(D_COMMENT "; - break; + case TOKcomment: + highlight = "$(D_COMMENT "; + break; - case TOKstring: - highlight = "$(D_STRING "; - break; + case TOKstring: + highlight = "$(D_STRING "; + break; - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; + default: + if (tok.isKeyword()) + highlight = "$(D_KEYWORD "; + break; + } + if (highlight) + res.writestring(highlight); + highlightCode3(&res, tok.ptr, lex.p); + if (highlight) + res.writeByte(')'); + if (tok.value == TOKeof) + break; + lastp = lex.p; } buf->setsize(offset); buf->write(&res); @@ -2001,19 +2126,70 @@ const char *Escape::escapeChar(unsigned c) switch (c) { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; + case '<': + s = "<"; + break; + case '>': + s = ">"; + break; + case '&': + s = "&"; + break; + default: + s = NULL; + break; } return s; } +/**************************************** + * Determine if p points to the start of an identifier. + */ + +int isIdStart(unsigned char *p) +{ + unsigned c = *p; + if (isalpha(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/**************************************** + * Determine if p points to the rest of an identifier. + */ + +int isIdTail(unsigned char *p) +{ + unsigned c = *p; + if (isalnum(c) || c == '_') + return 1; + if (c >= 0x80) + { size_t i = 0; + if (utf_decodeChar(p, 4, &i, &c)) + return 0; // ignore errors + if (isUniAlpha(c)) + return 1; + } + return 0; +} + +/***************************************** + * Return number of bytes in UTF character. + */ + +int utfStride(unsigned char *p) +{ + unsigned c = *p; + if (c < 0x80) + return 1; + size_t i = 0; + utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input + return i; +} diff --git a/dmd2/doc.h b/dmd2/doc.h index 30b74b21..c74ab4f7 100644 --- a/dmd2/doc.h +++ b/dmd2/doc.h @@ -1,19 +1,19 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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. - -#ifndef DMD_DOC_H -#define DMD_DOC_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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. + +#ifndef DMD_DOC_H +#define DMD_DOC_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + + +#endif diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c index 98eedf20..43c20571 100644 --- a/dmd2/dsymbol.c +++ b/dmd2/dsymbol.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -13,6 +13,8 @@ #include #include "rmem.h" +#include "speller.h" +#include "aav.h" #include "mars.h" #include "dsymbol.h" @@ -80,10 +82,10 @@ int Dsymbol::equals(Object *o) { Dsymbol *s; if (this == o) - return TRUE; + return TRUE; s = (Dsymbol *)(o); if (s && ident->equals(s->ident)) - return TRUE; + return TRUE; return FALSE; } @@ -104,9 +106,9 @@ Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) /************************************** * Determine if this symbol is only one. * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol + * FALSE, *ps = NULL: There are 2 or more symbols + * TRUE, *ps = NULL: There are zero symbols + * TRUE, *ps = symbol: The one and only one symbol */ int Dsymbol::oneMember(Dsymbol **ps) @@ -127,29 +129,29 @@ int Dsymbol::oneMembers(Array *members, Dsymbol **ps) if (members) { - for (int i = 0; i < members->dim; i++) - { Dsymbol *sx = (Dsymbol *)members->data[i]; + for (int i = 0; i < members->dim; i++) + { Dsymbol *sx = (Dsymbol *)members->data[i]; - int x = sx->oneMember(ps); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } + int x = sx->oneMember(ps); + //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); + if (!x) + { + //printf("\tfalse 1\n"); + assert(*ps == NULL); + return FALSE; + } + if (*ps) + { + if (s) // more than one symbol + { *ps = NULL; + //printf("\tfalse 2\n"); + return FALSE; + } + s = *ps; + } + } } - *ps = s; // s is the one symbol, NULL if none + *ps = s; // s is the one symbol, NULL if none //printf("\ttrue\n"); return TRUE; } @@ -177,24 +179,24 @@ const char *Dsymbol::toPrettyChars() //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); if (!parent) - return toChars(); + return toChars(); len = 0; for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; + len += strlen(p->toChars()) + 1; s = (char *)mem.malloc(len); q = s + len - 1; *q = 0; for (p = this; p; p = p->parent) { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; + char *t = p->toChars(); + len = strlen(t); + q -= len; + memcpy(q, t, len); + if (q == s) + break; + q--; #if TARGET_NET if (AggregateDeclaration* ad = p->isAggregateDeclaration()) { @@ -205,7 +207,7 @@ const char *Dsymbol::toPrettyChars() } } #endif - *q = '.'; + *q = '.'; } return s; } @@ -218,7 +220,7 @@ char *Dsymbol::locToChars() Module *m = getModule(); if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); + loc.filename = m->srcfile->toChars(); return loc.toChars(); } @@ -248,7 +250,7 @@ Dsymbol *Dsymbol::pastMixin() //printf("Dsymbol::pastMixin() %s\n", toChars()); while (s && s->isTemplateMixin()) - s = s->parent; + s = s->parent; return s; } @@ -261,7 +263,7 @@ Dsymbol *Dsymbol::toParent2() { Dsymbol *s = parent; while (s && s->isTemplateInstance()) - s = s->parent; + s = s->parent; return s; } @@ -269,9 +271,9 @@ TemplateInstance *Dsymbol::inTemplateInstance() { for (Dsymbol *parent = this->parent; parent; parent = parent->parent) { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - return ti; + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; } return NULL; } @@ -290,14 +292,22 @@ void Dsymbol::setScope(Scope *sc) { //printf("Dsymbol::setScope() %p %s\n", this, toChars()); if (!sc->nofree) - sc->setNoFree(); // may need it even after semantic() finishes + sc->setNoFree(); // may need it even after semantic() finishes scope = sc; } +void Dsymbol::importAll(Scope *sc) +{ +} + /************************************* * Does semantic analysis on the public face of declarations. */ +void Dsymbol::semantic0(Scope *sc) +{ +} + void Dsymbol::semantic(Scope *sc) { error("%p has no semantic routine", this); @@ -333,11 +343,11 @@ void Dsymbol::inlineScan() /********************************************* * Search for ident as member of s. * Input: - * flags: 1 don't find private members - * 2 don't give error messages - * 4 return NULL if ambiguous + * flags: 1 don't find private members + * 2 don't give error messages + * 4 return NULL if ambiguous * Returns: - * NULL if not found + * NULL if not found */ Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) @@ -346,11 +356,32 @@ Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) return NULL; } +/*************************************************** + * Search for symbol with correct spelling. + */ + +void *symbol_search_fp(void *arg, const char *seed) +{ + Dsymbol *s = (Dsymbol *)arg; + Identifier id(seed, 0); + Module::clearCache(); + s = s->search(0, &id, 4|2); + return s; +} + +Dsymbol *Dsymbol::search_correct(Identifier *ident) +{ + if (global.gag) + return NULL; // don't do it for speculative compiles; too time consuming + + return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); +} + /*************************************** * Search for identifier id as a member of 'this'. * id may be a template instance. * Returns: - * symbol found, NULL if not + * symbol found, NULL if not */ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) @@ -361,38 +392,38 @@ Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) switch (id->dyncast()) { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; + case DYNCAST_IDENTIFIER: + sm = s->search(loc, id, 0); + break; - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { error("template identifier %s is not a member of %s %s", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticRun) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } + case DYNCAST_DSYMBOL: + { // It's a template instance + //printf("\ttemplate instance id\n"); + Dsymbol *st = (Dsymbol *)id; + TemplateInstance *ti = st->isTemplateInstance(); + id = ti->name; + sm = s->search(loc, id, 0); + if (!sm) + { error("template identifier %s is not a member of %s %s", + id->toChars(), s->kind(), s->toChars()); + return NULL; + } + sm = sm->toAlias(); + TemplateDeclaration *td = sm->isTemplateDeclaration(); + if (!td) + { + error("%s is not a template, it is a %s", id->toChars(), sm->kind()); + return NULL; + } + ti->tempdecl = td; + if (!ti->semanticRun) + ti->semantic(sc); + sm = ti->toAlias(); + break; + } - default: - assert(0); + default: + assert(0); } return sm; } @@ -424,11 +455,11 @@ AggregateDeclaration *Dsymbol::isThis() return NULL; } -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? +ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? { Dsymbol *parent = toParent(); if (parent && parent->isClassDeclaration()) - return (ClassDeclaration *)parent; + return (ClassDeclaration *)parent; return NULL; } @@ -459,12 +490,12 @@ int Dsymbol::isOverloadable() } #endif -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? +LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? { return NULL; } -AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? +AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? { //printf("Dsymbol::isMember() %s\n", toChars()); Dsymbol *parent = toParent(); @@ -488,24 +519,24 @@ int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table + if (!isAnonymous()) // no name, so can't add it to symbol table { - if (!sd->symtab->insert(this)) // if name is already defined - { - Dsymbol *s2; + if (!sd->symtabInsert(this)) // if name is already defined + { + Dsymbol *s2; - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::alignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; + s2 = sd->symtab->lookup(ident); + if (!s2->overloadInsert(this)) + { + sd->multiplyDefined(0, this, s2); + } + } + if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) + { + if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) + error(".%s property cannot be redefined", ident->toChars()); + } + return 1; } return 0; } @@ -515,25 +546,25 @@ void Dsymbol::error(const char *format, ...) //printf("Dsymbol::error()\n"); if (!global.gag) { - char *p = locToChars(); + char *p = locToChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); - fprintf(stdmsg, "Error: "); - if (isAnonymous()) - fprintf(stdmsg, "%s ", kind()); - else - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + fprintf(stdmsg, "Error: "); + if (isAnonymous()) + fprintf(stdmsg, "%s ", kind()); + else + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); - fprintf(stdmsg, "\n"); - fflush(stdmsg); + fprintf(stdmsg, "\n"); + fflush(stdmsg); } global.errors++; @@ -544,24 +575,24 @@ void Dsymbol::error(Loc loc, const char *format, ...) { if (!global.gag) { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); + char *p = loc.toChars(); + if (!*p) + p = locToChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); + fprintf(stdmsg, "Error: "); + fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); - fprintf(stdmsg, "\n"); - fflush(stdmsg); + fprintf(stdmsg, "\n"); + fflush(stdmsg); } global.errors++; @@ -573,23 +604,36 @@ void Dsymbol::checkDeprecated(Loc loc, Scope *sc) { if (!global.params.useDeprecated && isDeprecated()) { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - return; - } + // Don't complain if we're inside a deprecated symbol's scope + for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) + { if (sp->isDeprecated()) + goto L1; + } - for (; sc; sc = sc->enclosing) - { - if (sc->scopesym && sc->scopesym->isDeprecated()) - return; + for (; sc; sc = sc->enclosing) + { + if (sc->scopesym && sc->scopesym->isDeprecated()) + goto L1; - // If inside a StorageClassDeclaration that is deprecated - if (sc->stc & STCdeprecated) - return; - } + // If inside a StorageClassDeclaration that is deprecated + if (sc->stc & STCdeprecated) + goto L1; + } - error(loc, "is deprecated"); + error(loc, "is deprecated"); + } + + L1: + Declaration *d = isDeclaration(); + if (d && d->storage_class & STCdisable) + { + if (!(sc->func && sc->func->storage_class & STCdisable)) + { + if (d->ident == Id::cpctor && d->toParent()) + d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); + else + error(loc, "is not callable because it is annotated with @disable"); + } } } @@ -606,11 +650,11 @@ Module *Dsymbol::getModule() s = this; while (s) { - //printf("\ts = '%s'\n", s->toChars()); - m = s->isModule(); - if (m) - return m; - s = s->parent; + //printf("\ts = '%s'\n", s->toChars()); + m = s->isModule(); + if (m) + return m; + s = s->parent; } return NULL; } @@ -656,20 +700,20 @@ enum PROT Dsymbol::prot() */ -Array *Dsymbol::arraySyntaxCopy(Array *a) +Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) { - Array *b = NULL; + Dsymbols *b = NULL; if (a) { - b = a->copy(); - for (int i = 0; i < b->dim; i++) - { - Dsymbol *s = (Dsymbol *)b->data[i]; + b = (Dsymbols *)a->copy(); + for (int i = 0; i < b->dim; i++) + { + Dsymbol *s = (Dsymbol *)b->data[i]; - s = s->syntaxCopy(NULL); - b->data[i] = (void *)s; - } + s = s->syntaxCopy(NULL); + b->data[i] = (void *)s; + } } return b; } @@ -683,14 +727,14 @@ Array *Dsymbol::arraySyntaxCopy(Array *a) void Dsymbol::addComment(unsigned char *comment) { //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); + //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); if (!this->comment) - this->comment = comment; + this->comment = comment; #if 1 else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); + { // Concatenate the two + this->comment = Lexer::combineComments(this->comment, comment); } #endif } @@ -741,9 +785,9 @@ Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) ScopeDsymbol *sd; if (s) - sd = (ScopeDsymbol *)s; + sd = (ScopeDsymbol *)s; else - sd = new ScopeDsymbol(ident); + sd = new ScopeDsymbol(ident); sd->members = arraySyntaxCopy(members); return sd; } @@ -755,7 +799,7 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) // Look in symbols declared in this module Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - + //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); // hide the aliases generated by selective or renamed private imports if (s && flags & 1) if (AliasDeclaration* ad = s->isAliasDeclaration()) @@ -766,100 +810,100 @@ Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) if (s) { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); + //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); } else if (imports) { - OverloadSet *a = NULL; + OverloadSet *a = NULL; - // Look in imported modules - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; - Dsymbol *s2; + // Look in imported modules + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; + Dsymbol *s2; - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; + // If private import, don't search it + if (flags & 1 && prots[i] == PROTprivate) + continue; - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same symbol, - * so it's not an ambiguity. - * But if one alias is deprecated, prefer the other. - */ - if (s->isDeprecated()) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - if (s2->isOverloadable() && (a || s->isOverloadable())) - { if (!a) - a = new OverloadSet(); - /* Don't add to a[] if s2 is alias of previous sym - */ - for (int j = 0; j < a->a.dim; j++) - { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; - if (s2->toAlias() == s3->toAlias()) - { - if (s3->isDeprecated()) - a->a.data[j] = (void *)s2; - goto Lcontinue; - } - } - a->push(s2); - Lcontinue: - continue; - } - if (flags & 4) // if return NULL on ambiguity - return NULL; - if (!(flags & 2)) - ss->multiplyDefined(loc, s, s2); - break; - } - } - } - } + //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); + /* Don't find private members if ss is a module + */ + s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); + if (!s) + s = s2; + else if (s2 && s != s2) + { + if (s->toAlias() == s2->toAlias()) + { + /* After following aliases, we found the same symbol, + * so it's not an ambiguity. + * But if one alias is deprecated, prefer the other. + */ + if (s->isDeprecated()) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import *i1 = s->isImport(); + Import *i2 = s2->isImport(); + if (!(i1 && i2 && + (i1->mod == i2->mod || + (!i1->parent->isImport() && !i2->parent->isImport() && + i1->ident->equals(i2->ident)) + ) + ) + ) + { + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + if (s2->isOverloadable() && (a || s->isOverloadable())) + { if (!a) + a = new OverloadSet(); + /* Don't add to a[] if s2 is alias of previous sym + */ + for (int j = 0; j < a->a.dim; j++) + { Dsymbol *s3 = (Dsymbol *)a->a.data[j]; + if (s2->toAlias() == s3->toAlias()) + { + if (s3->isDeprecated()) + a->a.data[j] = (void *)s2; + goto Lcontinue; + } + } + a->push(s2); + Lcontinue: + continue; + } + if (flags & 4) // if return NULL on ambiguity + return NULL; + if (!(flags & 2)) + ss->multiplyDefined(loc, s, s2); + break; + } + } + } + } - /* Build special symbol if we had multiple finds - */ - if (a) - { assert(s); - a->push(s); - s = a; - } + /* Build special symbol if we had multiple finds + */ + if (a) + { assert(s); + a->push(s); + s = a; + } - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin() && - !(flags & 2)) - error("%s is private", d->toPrettyChars()); - } + if (s) + { + Declaration *d = s->isDeclaration(); + if (d && d->protection == PROTprivate && + !d->parent->isTemplateMixin() && + !(flags & 2)) + error(loc, "%s is private", d->toPrettyChars()); + } } return s; } @@ -871,25 +915,25 @@ void ScopeDsymbol::importScope(ScopeDsymbol *s, enum PROT protection) // No circular or redundant import's if (s != this) { - if (!imports) - imports = new Array(); - else - { - for (int i = 0; i < imports->dim; i++) - { ScopeDsymbol *ss; + if (!imports) + imports = new Array(); + else + { + for (int i = 0; i < imports->dim; i++) + { ScopeDsymbol *ss; - ss = (ScopeDsymbol *) imports->data[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; + ss = (ScopeDsymbol *) imports->data[i]; + if (ss == s) // if already imported + { + if (protection > prots[i]) + prots[i] = protection; // upgrade access + return; + } + } + } + imports->push(s); + prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); + prots[imports->dim - 1] = protection; } } @@ -915,18 +959,18 @@ void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); #endif if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); + { ::error(loc, "%s at %s conflicts with %s at %s", + s1->toPrettyChars(), + s1->locToChars(), + s2->toPrettyChars(), + s2->locToChars()); } else { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); + s1->error(loc, "conflicts with %s %s at %s", + s2->kind(), + s2->toPrettyChars(), + s2->locToChars()); } } @@ -938,15 +982,15 @@ Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) sprev = symtab->lookup(s->ident); assert(sprev); - if (s->equals(sprev)) // if the same symbol + if (s->equals(sprev)) // if the same symbol { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } + if (s->isforwardRef()) // if second declaration is a forward reference + return sprev; + if (sprev->isforwardRef()) + { + sprev->defineRef(s); // copy data from s into sprev + return sprev; + } } multiplyDefined(0, s, sprev); return sprev; @@ -957,69 +1001,77 @@ const char *ScopeDsymbol::kind() return "ScopeDsymbol"; } +Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) +{ + return symtab->insert(s); +} /*************************************** * Determine number of Dsymbols, folding in AttribDeclaration members. */ +#if DMDV2 size_t ScopeDsymbol::dim(Array *members) { size_t n = 0; if (members) { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - AttribDeclaration *a = s->isAttribDeclaration(); + for (size_t i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + AttribDeclaration *a = s->isAttribDeclaration(); - if (a) - { - n += dim(a->decl); - } - else - n++; - } + if (a) + { + n += dim(a->decl); + } + else + n++; + } } return n; } +#endif /*************************************** * Get nth Dsymbol, folding in AttribDeclaration members. * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols + * Dsymbol* nth Dsymbol + * NULL not found, *pn gets incremented by the number + * of Dsymbols */ +#if DMDV2 Dsymbol *ScopeDsymbol::getNth(Array *members, size_t nth, size_t *pn) { if (!members) - return NULL; + return NULL; size_t n = 0; for (size_t i = 0; i < members->dim; i++) { Dsymbol *s = (Dsymbol *)members->data[i]; - AttribDeclaration *a = s->isAttribDeclaration(); + AttribDeclaration *a = s->isAttribDeclaration(); - if (a) - { - s = getNth(a->decl, nth - n, &n); - if (s) - return s; - } - else if (n == nth) - return s; - else - n++; + if (a) + { + s = getNth(a->decl, nth - n, &n); + if (s) + return s; + } + else if (n == nth) + return s; + else + n++; } if (pn) - *pn += n; + *pn += n; return NULL; } +#endif /******************************************* * Look for member of the form: - * const(MemberInfo)[] getMembers(string); + * const(MemberInfo)[] getMembers(string); * Returns NULL if not found */ @@ -1034,20 +1086,20 @@ FuncDeclaration *ScopeDsymbol::findGetMembers() if (!tfgetmembers) { - Scope sc; - Arguments *arguments = new Arguments; - Arguments *arg = new Argument(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); + Scope sc; + Parameters *arguments = new Parameters; + Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); + arguments->push(arg); - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); + Type *tret = NULL; + tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); + tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); } if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); + fdx = fdx->overloadExactMatch(tfgetmembers); #endif if (fdx && fdx->isVirtual()) - fdx = NULL; + fdx = NULL; return fdx; } @@ -1102,109 +1154,112 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) { //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; + { VarDeclaration **pvar; + Expression *ce; + + if (ident == Id::length && !global.params.useDeprecated) + error("using 'length' inside [ ] is deprecated, use '$' instead"); L1: - if (td) - { /* $ gives the number of elements in the tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } + if (td) + { /* $ gives the number of elements in the tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } - if (type) - { /* $ gives the number of type entries in the type tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } + if (type) + { /* $ gives the number of type entries in the type tuple + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + v->semantic(sc); + return v; + } - if (exp->op == TOKindex) - { /* array[index] where index is some function of $ - */ - IndexExp *ie = (IndexExp *)exp; + if (exp->op == TOKindex) + { /* array[index] where index is some function of $ + */ + IndexExp *ie = (IndexExp *)exp; - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { /* array[lwr .. upr] where lwr or upr is some function of $ - */ - SliceExp *se = (SliceExp *)exp; + pvar = &ie->lengthVar; + ce = ie->e1; + } + else if (exp->op == TOKslice) + { /* array[lwr .. upr] where lwr or upr is some function of $ + */ + SliceExp *se = (SliceExp *)exp; - pvar = &se->lengthVar; - ce = se->e1; - } - else - /* Didn't find $, look in enclosing scope(s). - */ - return NULL; + pvar = &se->lengthVar; + ce = se->e1; + } + else + /* Didn't find $, look in enclosing scope(s). + */ + return NULL; - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (ce->op == TOKtype) + { + Type *t = ((TypeExp *)ce)->type; + if (t->ty == Ttuple) + { type = (TypeTuple *)t; + goto L1; + } + } - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $, - * which will be a constant. - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { /* Create variable v and set it to the value of $, + * which will be a constant. + */ + VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - if (ce->op == TOKvar) - { // if ce is const, get its initializer - ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); - } + if (ce->op == TOKvar) + { // if ce is const, get its initializer + ce = fromConstInitializer(WANTvalue | WANTinterpret, ce); + } - if (ce->op == TOKstring) - { /* It is for a string literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKarrayliteral) - { /* It is for an array literal, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - *pvar = v; - } - (*pvar)->semantic(sc); - return (*pvar); + if (ce->op == TOKstring) + { /* It is for a string literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((StringExp *)ce)->len, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKarrayliteral) + { /* It is for an array literal, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((ArrayLiteralExp *)ce)->elements->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + else if (ce->op == TOKtuple) + { /* It is for an expression tuple, so the + * length will be a const. + */ + Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); + v->init = new ExpInitializer(0, e); + v->storage_class |= STCstatic | STCconst; + } + *pvar = v; + } + (*pvar)->semantic(sc); + return (*pvar); } return NULL; } @@ -1214,60 +1269,89 @@ Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) DsymbolTable::DsymbolTable() { +#if STRINGTABLE tab = new StringTable; +#else + tab = NULL; +#endif } DsymbolTable::~DsymbolTable() { +#if STRINGTABLE delete tab; +#endif } Dsymbol *DsymbolTable::lookup(Identifier *ident) { +#if STRINGTABLE #ifdef DEBUG assert(ident); assert(tab); #endif + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); StringValue *sv = tab->lookup((char*)ident->string, ident->len); return (Dsymbol *)(sv ? sv->ptrvalue : NULL); +#else + //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); + return (Dsymbol *)_aaGetRvalue(tab, ident); +#endif } Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - +{ //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - ident = s->ident; + Identifier *ident = s->ident; +#if STRINGTABLE #ifdef DEBUG assert(ident); assert(tab); #endif - sv = tab->insert(ident->toChars(), ident->len); + StringValue *sv = tab->insert(ident->toChars(), ident->len); if (!sv) - return NULL; // already in table + return NULL; // already in table sv->ptrvalue = s; return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif } Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ StringValue *sv; - +{ //printf("DsymbolTable::insert()\n"); - sv = tab->insert(ident->toChars(), ident->len); +#if STRINGTABLE + StringValue *sv = tab->insert(ident->toChars(), ident->len); if (!sv) - return NULL; // already in table + return NULL; // already in table sv->ptrvalue = s; return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + if (*ps) + return NULL; // already in table + *ps = s; + return s; +#endif } Dsymbol *DsymbolTable::update(Dsymbol *s) -{ StringValue *sv; - Identifier *ident; - - ident = s->ident; - sv = tab->update(ident->toChars(), ident->len); +{ + Identifier *ident = s->ident; +#if STRINGTABLE + StringValue *sv = tab->update(ident->toChars(), ident->len); sv->ptrvalue = s; return s; +#else + Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); + *ps = s; + return s; +#endif } diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h index 3bcd25be..f6319935 100644 --- a/dmd2/dsymbol.h +++ b/dmd2/dsymbol.h @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -47,6 +47,8 @@ struct PostBlitDeclaration; struct DtorDeclaration; struct StaticCtorDeclaration; struct StaticDtorDeclaration; +struct SharedStaticCtorDeclaration; +struct SharedStaticDtorDeclaration; struct InvariantDeclaration; struct UnitTestDeclaration; struct NewDeclaration; @@ -75,6 +77,7 @@ struct Expression; struct DeleteDeclaration; struct HdrGenState; struct OverloadSet; +struct AA; #if TARGET_NET struct PragmaScope; #endif @@ -106,7 +109,7 @@ struct Classsym; enum PROT { PROTundefined, - PROTnone, // no access + PROTnone, // no access PROTprivate, PROTpackage, PROTprotected, @@ -114,6 +117,18 @@ enum PROT PROTexport, }; +/* State of symbol in winding its way through the passes of the compiler + */ +enum PASS +{ + PASSinit, // initial state + PASSsemantic, // semantic() started + PASSsemanticdone, // semantic() done + PASSsemantic2, // semantic2() run + PASSsemantic3, // semantic3() started + PASSsemantic3done, // semantic3() done + PASSobj, // toObjFile() run +}; struct Dsymbol : Object { @@ -121,12 +136,12 @@ struct Dsymbol : Object Identifier *c_ident; Dsymbol *parent; #if IN_DMD - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym + Symbol *csym; // symbol for code generator + Symbol *isym; // import version of csym #endif - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - Scope *scope; // !=NULL means context to use for semantic() + unsigned char *comment; // documentation comment for this Dsymbol + Loc loc; // where defined + Scope *scope; // !=NULL means context to use for semantic() Dsymbol(); Dsymbol(Identifier *); @@ -144,20 +159,23 @@ struct Dsymbol : Object Dsymbol *toParent2(); TemplateInstance *inTemplateInstance(); - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() + int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - static Array *arraySyntaxCopy(Array *a); + static Dsymbols *arraySyntaxCopy(Dsymbols *a); virtual const char *toPrettyChars(); virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol + virtual Dsymbol *toAlias(); // resolve real symbol virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); virtual void setScope(Scope *sc); + virtual void importAll(Scope *sc); + virtual void semantic0(Scope *sc); virtual void semantic(Scope *sc); virtual void semantic2(Scope *sc); virtual void semantic3(Scope *sc); virtual void inlineScan(); virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); + Dsymbol *search_correct(Identifier *id); Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); virtual int overloadInsert(Dsymbol *s); #ifdef _DH @@ -166,24 +184,25 @@ struct Dsymbol : Object #endif virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); virtual void toDocBuffer(OutBuffer *buf); + virtual void toJsonBuffer(OutBuffer *buf); virtual unsigned size(Loc loc); virtual int isforwardRef(); virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - virtual ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? + virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member + virtual ClassDeclaration *isClassMember(); // are we a member of a class? + virtual int isExport(); // is Dsymbol exported? + virtual int isImportedSymbol(); // is Dsymbol imported? + virtual int isDeprecated(); // is Dsymbol deprecated? #if DMDV2 virtual int isOverloadable(); #endif - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? + virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? + virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? + virtual Type *getType(); // is this a type? virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? + virtual int needThis(); // need a 'this' pointer? virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees virtual int oneMember(Dsymbol **ps); static int oneMembers(Array *members, Dsymbol **ps); virtual int hasPointers(); @@ -197,14 +216,14 @@ struct Dsymbol : Object #if IN_DMD // Backend - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member + virtual Symbol *toSymbol(); // to backend symbol + virtual void toObjFile(int multiobj); // compile to .obj file + virtual int cvMember(unsigned char *p); // emit cv debug info for member - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol + Symbol *toImport(); // to backend import symbol + static Symbol *toImport(Symbol *s); // to backend import symbol - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper + Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper #endif // Eliminate need for dynamic_cast @@ -228,6 +247,8 @@ struct Dsymbol : Object virtual DtorDeclaration *isDtorDeclaration() { return NULL; } virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } + virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } + virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } virtual NewDeclaration *isNewDeclaration() { return NULL; } @@ -268,11 +289,11 @@ struct Dsymbol : Object struct ScopeDsymbol : Dsymbol { - Array *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table + Dsymbols *members; // all Dsymbol's in this scope + DsymbolTable *symtab; // members[] sorted into table - Array *imports; // imported ScopeDsymbol's - unsigned char *prots; // array of PROT, one for each import + Array *imports; // imported ScopeDsymbol's + unsigned char *prots; // array of PROT, one for each import ScopeDsymbol(); ScopeDsymbol(Identifier *id); @@ -285,6 +306,7 @@ struct ScopeDsymbol : Dsymbol Dsymbol *nameCollision(Dsymbol *s); const char *kind(); FuncDeclaration *findGetMembers(); + virtual Dsymbol *symtabInsert(Dsymbol *s); void emitMemberComments(Scope *sc); @@ -310,9 +332,9 @@ struct WithScopeSymbol : ScopeDsymbol struct ArrayScopeSymbol : ScopeDsymbol { - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects + Expression *exp; // IndexExp or SliceExp + TypeTuple *type; // for tuple[length] + TupleDeclaration *td; // for tuples of objects Scope *sc; ArrayScopeSymbol(Scope *sc, Expression *e); @@ -328,7 +350,7 @@ struct ArrayScopeSymbol : ScopeDsymbol #if DMDV2 struct OverloadSet : Dsymbol { - Dsymbols a; // array of Dsymbols + Dsymbols a; // array of Dsymbols OverloadSet(); void push(Dsymbol *s); @@ -341,7 +363,11 @@ struct OverloadSet : Dsymbol struct DsymbolTable : Object { +#if STRINGTABLE StringTable *tab; +#else + AA *tab; +#endif DsymbolTable(); ~DsymbolTable(); @@ -354,7 +380,7 @@ struct DsymbolTable : Object // Look for Dsymbol in table. If there, return it. If not, insert s and return that. Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same + Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same }; #endif /* DMD_DSYMBOL_H */ diff --git a/dmd2/dump.c b/dmd2/dump.c index 1f6fecd1..d1468264 100644 --- a/dmd2/dump.c +++ b/dmd2/dump.c @@ -1,144 +1,144 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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 -#include -#include - -#include "mars.h" -#include "mtype.h" -#include "declaration.h" -#include "expression.h" -#include "template.h" - -static void indent(int indent) -{ - int i; - - for (i = 0; i < indent; i++) - printf(" "); -} - -static char *type_print(Type *type) -{ - return type ? type->toChars() : (char *) "null"; -} - -void dumpExpressions(int i, Expressions *exps) -{ - for (size_t j = 0; j < exps->dim; j++) - { Expression *e = (Expression *)exps->data[j]; - indent(i); - printf("(\n"); - e->dump(i + 2); - indent(i); - printf(")\n"); - } -} - -void Expression::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type)); -} - -void IntegerExp::dump(int i) -{ - indent(i); - printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); -} - -void IdentifierExp::dump(int i) -{ - indent(i); - printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type)); -} - -void DsymbolExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, s->toChars(), type_print(type)); -} - -void VarExp::dump(int i) -{ - indent(i); - printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type)); -} - -void UnaExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void CallExp::dump(int i) -{ - UnaExp::dump(i); - dumpExpressions(i, arguments); -} - -void SliceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); - if (lwr) - lwr->dump(i + 2); - if (upr) - upr->dump(i + 2); -} - -void DotIdExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotVarExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotTemplateInstanceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DelegateExp::dump(int i) -{ - indent(i); - printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void BinExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2); - if (e1) - e1->dump(i + 2); - if (e2) - e2->dump(i + 2); -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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 +#include +#include + +#include "mars.h" +#include "mtype.h" +#include "declaration.h" +#include "expression.h" +#include "template.h" + +static void indent(int indent) +{ + int i; + + for (i = 0; i < indent; i++) + printf(" "); +} + +static char *type_print(Type *type) +{ + return type ? type->toChars() : (char *) "null"; +} + +void dumpExpressions(int i, Expressions *exps) +{ + for (size_t j = 0; j < exps->dim; j++) + { Expression *e = (Expression *)exps->data[j]; + indent(i); + printf("(\n"); + e->dump(i + 2); + indent(i); + printf(")\n"); + } +} + +void Expression::dump(int i) +{ + indent(i); + printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type)); +} + +void IntegerExp::dump(int i) +{ + indent(i); + printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); +} + +void IdentifierExp::dump(int i) +{ + indent(i); + printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type)); +} + +void DsymbolExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s\n", this, s->toChars(), type_print(type)); +} + +void VarExp::dump(int i) +{ + indent(i); + printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type)); +} + +void UnaExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); + if (e1) + e1->dump(i + 2); +} + +void CallExp::dump(int i) +{ + UnaExp::dump(i); + dumpExpressions(i, arguments); +} + +void SliceExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); + if (e1) + e1->dump(i + 2); + if (lwr) + lwr->dump(i + 2); + if (upr) + upr->dump(i + 2); +} + +void DotIdExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1); + if (e1) + e1->dump(i + 2); +} + +void DotVarExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1); + if (e1) + e1->dump(i + 2); +} + +void DotTemplateInstanceExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1); + if (e1) + e1->dump(i + 2); +} + +void DelegateExp::dump(int i) +{ + indent(i); + printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1); + if (e1) + e1->dump(i + 2); +} + +void BinExp::dump(int i) +{ + indent(i); + printf("%p %s type=%s e1=%p e2=%p\n", this, Token::toChars(op), type_print(type), e1, e2); + if (e1) + e1->dump(i + 2); + if (e2) + e2->dump(i + 2); +} + + diff --git a/dmd2/entity.c b/dmd2/entity.c index 1b5cc3c7..110128e4 100644 --- a/dmd2/entity.c +++ b/dmd2/entity.c @@ -13,8 +13,8 @@ /********************************************* * Convert from named entity to its encoding. * For reference: - * http://www.htmlhelp.com/reference/html40/entities/ - * http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html + * http://www.htmlhelp.com/reference/html40/entities/ + * http://www.w3.org/TR/1999/REC-html401-19991224/sgml/entities.html */ struct NameId @@ -25,1060 +25,1060 @@ struct NameId #if IN_GCC static NameId namesA[]={ - "Aacgr", 0x0386, - "aacgr", 0x03AC, - "Aacute", 0x00C1, - "aacute", 0x00E1, - "Abreve", 0x0102, - "abreve", 0x0103, - "Acirc", 0x00C2, - "acirc", 0x00E2, - "acute", 0x00B4, - "Acy", 0x0410, - "acy", 0x0430, - "AElig", 0x00C6, - "aelig", 0x00E6, - "Agr", 0x0391, - "agr", 0x03B1, - "Agrave", 0x00C0, - "agrave", 0x00E0, - "aleph", 0x2135, - "alpha", 0x03B1, - "Amacr", 0x0100, - "amacr", 0x0101, - "amalg", 0x2210, - "amp", 0x0026, - "and", 0x2227, - "ang", 0x2220, - "ang90", 0x221F, - "angmsd", 0x2221, - "angsph", 0x2222, - "angst", 0x212B, - "Aogon", 0x0104, - "aogon", 0x0105, - "ap", 0x2248, - "ape", 0x224A, - "apos", 0x0027, - "Aring", 0x00C5, - "aring", 0x00E5, - "ast", 0x002A, - "asymp", 0x224D, - "Atilde", 0x00C3, - "atilde", 0x00E3, - "Auml", 0x00C4, - "auml", 0x00E4, - NULL, 0 + "Aacgr", 0x0386, + "aacgr", 0x03AC, + "Aacute", 0x00C1, + "aacute", 0x00E1, + "Abreve", 0x0102, + "abreve", 0x0103, + "Acirc", 0x00C2, + "acirc", 0x00E2, + "acute", 0x00B4, + "Acy", 0x0410, + "acy", 0x0430, + "AElig", 0x00C6, + "aelig", 0x00E6, + "Agr", 0x0391, + "agr", 0x03B1, + "Agrave", 0x00C0, + "agrave", 0x00E0, + "aleph", 0x2135, + "alpha", 0x03B1, + "Amacr", 0x0100, + "amacr", 0x0101, + "amalg", 0x2210, + "amp", 0x0026, + "and", 0x2227, + "ang", 0x2220, + "ang90", 0x221F, + "angmsd", 0x2221, + "angsph", 0x2222, + "angst", 0x212B, + "Aogon", 0x0104, + "aogon", 0x0105, + "ap", 0x2248, + "ape", 0x224A, + "apos", 0x0027, + "Aring", 0x00C5, + "aring", 0x00E5, + "ast", 0x002A, + "asymp", 0x224D, + "Atilde", 0x00C3, + "atilde", 0x00E3, + "Auml", 0x00C4, + "auml", 0x00E4, + NULL, 0 }; static NameId namesB[]={ - "barwed", 0x22BC, - "Barwed", 0x2306, - "bcong", 0x224C, - "Bcy", 0x0411, - "bcy", 0x0431, - "becaus", 0x2235, - "bepsi", 0x220D, - "bernou", 0x212C, - "beta", 0x03B2, - "beth", 0x2136, - "Bgr", 0x0392, - "bgr", 0x03B2, - "blank", 0x2423, - "blk12", 0x2592, - "blk14", 0x2591, - "blk34", 0x2593, - "block", 0x2588, - "bottom", 0x22A5, - "bowtie", 0x22C8, - "boxdl", 0x2510, - "boxDL", 0x2555, - "boxdL", 0x2556, - "boxDl", 0x2557, - "boxdr", 0x250C, - "boxDR", 0x2552, - "boxDr", 0x2553, - "boxdR", 0x2554, - "boxh", 0x2500, - "boxH", 0x2550, - "boxhd", 0x252C, - "boxhD", 0x2564, - "boxHD", 0x2565, - "boxHd", 0x2566, - "boxhu", 0x2534, - "boxhU", 0x2567, - "boxHU", 0x2568, - "boxHu", 0x2569, - "boxul", 0x2518, - "boxUL", 0x255B, - "boxUl", 0x255C, - "boxuL", 0x255D, - "boxur", 0x2514, - "boxUR", 0x2558, - "boxuR", 0x2559, - "boxUr", 0x255A, - "boxv", 0x2502, - "boxV", 0x2551, - "boxvh", 0x253C, - "boxvH", 0x256A, - "boxVH", 0x256B, - "boxVh", 0x256C, - "boxvl", 0x2524, - "boxvL", 0x2561, - "boxVL", 0x2562, - "boxVl", 0x2563, - "boxvr", 0x251C, - "boxvR", 0x255E, - "boxVR", 0x255F, - "boxVr", 0x2560, - "bprime", 0x2035, - "breve", 0x02D8, - "brvbar", 0x00A6, - "bsim", 0x223D, - "bsime", 0x22CD, - "bsol", 0x005C, - "bull", 0x2022, - "bump", 0x224E, - "bumpe", 0x224F, - NULL, 0 + "barwed", 0x22BC, + "Barwed", 0x2306, + "bcong", 0x224C, + "Bcy", 0x0411, + "bcy", 0x0431, + "becaus", 0x2235, + "bepsi", 0x220D, + "bernou", 0x212C, + "beta", 0x03B2, + "beth", 0x2136, + "Bgr", 0x0392, + "bgr", 0x03B2, + "blank", 0x2423, + "blk12", 0x2592, + "blk14", 0x2591, + "blk34", 0x2593, + "block", 0x2588, + "bottom", 0x22A5, + "bowtie", 0x22C8, + "boxdl", 0x2510, + "boxDL", 0x2555, + "boxdL", 0x2556, + "boxDl", 0x2557, + "boxdr", 0x250C, + "boxDR", 0x2552, + "boxDr", 0x2553, + "boxdR", 0x2554, + "boxh", 0x2500, + "boxH", 0x2550, + "boxhd", 0x252C, + "boxhD", 0x2564, + "boxHD", 0x2565, + "boxHd", 0x2566, + "boxhu", 0x2534, + "boxhU", 0x2567, + "boxHU", 0x2568, + "boxHu", 0x2569, + "boxul", 0x2518, + "boxUL", 0x255B, + "boxUl", 0x255C, + "boxuL", 0x255D, + "boxur", 0x2514, + "boxUR", 0x2558, + "boxuR", 0x2559, + "boxUr", 0x255A, + "boxv", 0x2502, + "boxV", 0x2551, + "boxvh", 0x253C, + "boxvH", 0x256A, + "boxVH", 0x256B, + "boxVh", 0x256C, + "boxvl", 0x2524, + "boxvL", 0x2561, + "boxVL", 0x2562, + "boxVl", 0x2563, + "boxvr", 0x251C, + "boxvR", 0x255E, + "boxVR", 0x255F, + "boxVr", 0x2560, + "bprime", 0x2035, + "breve", 0x02D8, + "brvbar", 0x00A6, + "bsim", 0x223D, + "bsime", 0x22CD, + "bsol", 0x005C, + "bull", 0x2022, + "bump", 0x224E, + "bumpe", 0x224F, + NULL, 0 }; static NameId namesC[]={ - "Cacute", 0x0106, - "cacute", 0x0107, - "cap", 0x2229, - "Cap", 0x22D2, - "caret", 0x2041, - "caron", 0x02C7, - "Ccaron", 0x010C, - "ccaron", 0x010D, - "Ccedil", 0x00C7, - "ccedil", 0x00E7, - "Ccirc", 0x0108, - "ccirc", 0x0109, - "Cdot", 0x010A, - "cdot", 0x010B, - "cedil", 0x00B8, - "cent", 0x00A2, - "CHcy", 0x0427, - "chcy", 0x0447, - "check", 0x2713, - "chi", 0x03C7, - "cir", 0x25CB, - "circ", 0x005E, - "cire", 0x2257, - "clubs", 0x2663, - "colon", 0x003A, - "colone", 0x2254, - "comma", 0x002C, - "commat", 0x0040, - "comp", 0x2201, - "compfn", 0x2218, - "cong", 0x2245, - "conint", 0x222E, - "coprod", 0x2210, - "copy", 0x00A9, - "copysr", 0x2117, - "cross", 0x2717, - "cuepr", 0x22DE, - "cuesc", 0x22DF, - "cularr", 0x21B6, - "cup", 0x222A, - "Cup", 0x22D3, - "cupre", 0x227C, - "curarr", 0x21B7, - "curren", 0x00A4, - "cuvee", 0x22CE, - "cuwed", 0x22CF, - NULL, 0 + "Cacute", 0x0106, + "cacute", 0x0107, + "cap", 0x2229, + "Cap", 0x22D2, + "caret", 0x2041, + "caron", 0x02C7, + "Ccaron", 0x010C, + "ccaron", 0x010D, + "Ccedil", 0x00C7, + "ccedil", 0x00E7, + "Ccirc", 0x0108, + "ccirc", 0x0109, + "Cdot", 0x010A, + "cdot", 0x010B, + "cedil", 0x00B8, + "cent", 0x00A2, + "CHcy", 0x0427, + "chcy", 0x0447, + "check", 0x2713, + "chi", 0x03C7, + "cir", 0x25CB, + "circ", 0x005E, + "cire", 0x2257, + "clubs", 0x2663, + "colon", 0x003A, + "colone", 0x2254, + "comma", 0x002C, + "commat", 0x0040, + "comp", 0x2201, + "compfn", 0x2218, + "cong", 0x2245, + "conint", 0x222E, + "coprod", 0x2210, + "copy", 0x00A9, + "copysr", 0x2117, + "cross", 0x2717, + "cuepr", 0x22DE, + "cuesc", 0x22DF, + "cularr", 0x21B6, + "cup", 0x222A, + "Cup", 0x22D3, + "cupre", 0x227C, + "curarr", 0x21B7, + "curren", 0x00A4, + "cuvee", 0x22CE, + "cuwed", 0x22CF, + NULL, 0 }; static NameId namesD[]={ - "dagger", 0x2020, - "Dagger", 0x2021, - "daleth", 0x2138, - "darr", 0x2193, - "dArr", 0x21D3, - "darr2", 0x21CA, - "dash", 0x2010, - "dashv", 0x22A3, - "dblac", 0x02DD, - "Dcaron", 0x010E, - "dcaron", 0x010F, - "Dcy", 0x0414, - "dcy", 0x0434, - "deg", 0x00B0, - "Delta", 0x0394, - "delta", 0x03B4, - "Dgr", 0x0394, - "dgr", 0x03B4, - "dharl", 0x21C3, - "dharr", 0x21C2, - "diam", 0x22C4, - "diams", 0x2666, - "die", 0x00A8, - "divide", 0x00F7, - "divonx", 0x22C7, - "DJcy", 0x0402, - "djcy", 0x0452, - "dlarr", 0x2199, - "dlcorn", 0x231E, - "dlcrop", 0x230D, - "dollar", 0x0024, - "Dot", 0x00A8, - "dot", 0x02D9, - "DotDot", 0x20DC, - "drarr", 0x2198, - "drcorn", 0x231F, - "drcrop", 0x230C, - "DScy", 0x0405, - "dscy", 0x0455, - "Dstrok", 0x0110, - "dstrok", 0x0111, - "dtri", 0x25BF, - "dtrif", 0x25BE, - "DZcy", 0x040F, - "dzcy", 0x045F, - NULL, 0 + "dagger", 0x2020, + "Dagger", 0x2021, + "daleth", 0x2138, + "darr", 0x2193, + "dArr", 0x21D3, + "darr2", 0x21CA, + "dash", 0x2010, + "dashv", 0x22A3, + "dblac", 0x02DD, + "Dcaron", 0x010E, + "dcaron", 0x010F, + "Dcy", 0x0414, + "dcy", 0x0434, + "deg", 0x00B0, + "Delta", 0x0394, + "delta", 0x03B4, + "Dgr", 0x0394, + "dgr", 0x03B4, + "dharl", 0x21C3, + "dharr", 0x21C2, + "diam", 0x22C4, + "diams", 0x2666, + "die", 0x00A8, + "divide", 0x00F7, + "divonx", 0x22C7, + "DJcy", 0x0402, + "djcy", 0x0452, + "dlarr", 0x2199, + "dlcorn", 0x231E, + "dlcrop", 0x230D, + "dollar", 0x0024, + "Dot", 0x00A8, + "dot", 0x02D9, + "DotDot", 0x20DC, + "drarr", 0x2198, + "drcorn", 0x231F, + "drcrop", 0x230C, + "DScy", 0x0405, + "dscy", 0x0455, + "Dstrok", 0x0110, + "dstrok", 0x0111, + "dtri", 0x25BF, + "dtrif", 0x25BE, + "DZcy", 0x040F, + "dzcy", 0x045F, + NULL, 0 }; static NameId namesE[]={ - "Eacgr", 0x0388, - "eacgr", 0x03AD, - "Eacute", 0x00C9, - "eacute", 0x00E9, - "Ecaron", 0x011A, - "ecaron", 0x011B, - "ecir", 0x2256, - "Ecirc", 0x00CA, - "ecirc", 0x00EA, - "ecolon", 0x2255, - "Ecy", 0x042D, - "ecy", 0x044D, - "Edot", 0x0116, - "edot", 0x0117, - "eDot", 0x2251, - "EEacgr", 0x0389, - "eeacgr", 0x03AE, - "EEgr", 0x0397, - "eegr", 0x03B7, - "efDot", 0x2252, - "Egr", 0x0395, - "egr", 0x03B5, - "Egrave", 0x00C8, - "egrave", 0x00E8, - "egs", 0x22DD, - "ell", 0x2113, - "els", 0x22DC, - "Emacr", 0x0112, - "emacr", 0x0113, - "empty", 0x2205, - "emsp", 0x2003, - "emsp13", 0x2004, - "emsp14", 0x2005, - "ENG", 0x014A, - "eng", 0x014B, - "ensp", 0x2002, - "Eogon", 0x0118, - "eogon", 0x0119, - "epsi", 0x220A, - "epsis", 0x220A, - "epsiv", 0x03B5, - "equals", 0x003D, - "equiv", 0x2261, - "erDot", 0x2253, - "esdot", 0x2250, - "eta", 0x03B7, - "ETH", 0x00D0, - "eth", 0x00F0, - "Euml", 0x00CB, - "euml", 0x00EB, - "excl", 0x0021, - "exist", 0x2203, - NULL, 0 + "Eacgr", 0x0388, + "eacgr", 0x03AD, + "Eacute", 0x00C9, + "eacute", 0x00E9, + "Ecaron", 0x011A, + "ecaron", 0x011B, + "ecir", 0x2256, + "Ecirc", 0x00CA, + "ecirc", 0x00EA, + "ecolon", 0x2255, + "Ecy", 0x042D, + "ecy", 0x044D, + "Edot", 0x0116, + "edot", 0x0117, + "eDot", 0x2251, + "EEacgr", 0x0389, + "eeacgr", 0x03AE, + "EEgr", 0x0397, + "eegr", 0x03B7, + "efDot", 0x2252, + "Egr", 0x0395, + "egr", 0x03B5, + "Egrave", 0x00C8, + "egrave", 0x00E8, + "egs", 0x22DD, + "ell", 0x2113, + "els", 0x22DC, + "Emacr", 0x0112, + "emacr", 0x0113, + "empty", 0x2205, + "emsp", 0x2003, + "emsp13", 0x2004, + "emsp14", 0x2005, + "ENG", 0x014A, + "eng", 0x014B, + "ensp", 0x2002, + "Eogon", 0x0118, + "eogon", 0x0119, + "epsi", 0x220A, + "epsis", 0x220A, + "epsiv", 0x03B5, + "equals", 0x003D, + "equiv", 0x2261, + "erDot", 0x2253, + "esdot", 0x2250, + "eta", 0x03B7, + "ETH", 0x00D0, + "eth", 0x00F0, + "Euml", 0x00CB, + "euml", 0x00EB, + "excl", 0x0021, + "exist", 0x2203, + NULL, 0 }; static NameId namesF[]={ - "Fcy", 0x0424, - "fcy", 0x0444, - "female", 0x2640, - "ffilig", 0xFB03, - "fflig", 0xFB00, - "ffllig", 0xFB04, - "filig", 0xFB01, - "flat", 0x266D, - "fllig", 0xFB02, - "fnof", 0x0192, - "forall", 0x2200, - "fork", 0x22D4, - "frac12", 0x00BD, - "frac13", 0x2153, - "frac14", 0x00BC, - "frac15", 0x2155, - "frac16", 0x2159, - "frac18", 0x215B, - "frac23", 0x2154, - "frac25", 0x2156, - "frac34", 0x00BE, - "frac35", 0x2157, - "frac38", 0x215C, - "frac45", 0x2158, - "frac56", 0x215A, - "frac58", 0x215D, - "frac78", 0x215E, - "frown", 0x2322, - NULL, 0 + "Fcy", 0x0424, + "fcy", 0x0444, + "female", 0x2640, + "ffilig", 0xFB03, + "fflig", 0xFB00, + "ffllig", 0xFB04, + "filig", 0xFB01, + "flat", 0x266D, + "fllig", 0xFB02, + "fnof", 0x0192, + "forall", 0x2200, + "fork", 0x22D4, + "frac12", 0x00BD, + "frac13", 0x2153, + "frac14", 0x00BC, + "frac15", 0x2155, + "frac16", 0x2159, + "frac18", 0x215B, + "frac23", 0x2154, + "frac25", 0x2156, + "frac34", 0x00BE, + "frac35", 0x2157, + "frac38", 0x215C, + "frac45", 0x2158, + "frac56", 0x215A, + "frac58", 0x215D, + "frac78", 0x215E, + "frown", 0x2322, + NULL, 0 }; static NameId namesG[]={ - "gacute", 0x01F5, - "Gamma", 0x0393, - "gamma", 0x03B3, - "gammad", 0x03DC, - "gap", 0x2273, - "Gbreve", 0x011E, - "gbreve", 0x011F, - "Gcedil", 0x0122, - "Gcirc", 0x011C, - "gcirc", 0x011D, - "Gcy", 0x0413, - "gcy", 0x0433, - "Gdot", 0x0120, - "gdot", 0x0121, - "ge", 0x2265, - "gE", 0x2267, - "gel", 0x22DB, - "gEl", 0x22DB, - "ges", 0x2265, - "Gg", 0x22D9, - "Ggr", 0x0393, - "ggr", 0x03B3, - "gimel", 0x2137, - "GJcy", 0x0403, - "gjcy", 0x0453, - "gl", 0x2277, - "gnap", 0xE411, - "gne", 0x2269, - "gnE", 0x2269, - "gnsim", 0x22E7, - "grave", 0x0060, - "gsdot", 0x22D7, - "gsim", 0x2273, - "gt", 0x003E, - "Gt", 0x226B, - "gvnE", 0x2269, - NULL, 0 + "gacute", 0x01F5, + "Gamma", 0x0393, + "gamma", 0x03B3, + "gammad", 0x03DC, + "gap", 0x2273, + "Gbreve", 0x011E, + "gbreve", 0x011F, + "Gcedil", 0x0122, + "Gcirc", 0x011C, + "gcirc", 0x011D, + "Gcy", 0x0413, + "gcy", 0x0433, + "Gdot", 0x0120, + "gdot", 0x0121, + "ge", 0x2265, + "gE", 0x2267, + "gel", 0x22DB, + "gEl", 0x22DB, + "ges", 0x2265, + "Gg", 0x22D9, + "Ggr", 0x0393, + "ggr", 0x03B3, + "gimel", 0x2137, + "GJcy", 0x0403, + "gjcy", 0x0453, + "gl", 0x2277, + "gnap", 0xE411, + "gne", 0x2269, + "gnE", 0x2269, + "gnsim", 0x22E7, + "grave", 0x0060, + "gsdot", 0x22D7, + "gsim", 0x2273, + "gt", 0x003E, + "Gt", 0x226B, + "gvnE", 0x2269, + NULL, 0 }; static NameId namesH[]={ - "hairsp", 0x200A, - "half", 0x00BD, - "hamilt", 0x210B, - "HARDcy", 0x042A, - "hardcy", 0x044A, - "harr", 0x2194, - "hArr", 0x21D4, - "harrw", 0x21AD, - "Hcirc", 0x0124, - "hcirc", 0x0125, - "hearts", 0x2665, - "hellip", 0x2026, - "horbar", 0x2015, - "Hstrok", 0x0126, - "hstrok", 0x0127, - "hybull", 0x2043, - "hyphen", 0x002D, - NULL, 0 + "hairsp", 0x200A, + "half", 0x00BD, + "hamilt", 0x210B, + "HARDcy", 0x042A, + "hardcy", 0x044A, + "harr", 0x2194, + "hArr", 0x21D4, + "harrw", 0x21AD, + "Hcirc", 0x0124, + "hcirc", 0x0125, + "hearts", 0x2665, + "hellip", 0x2026, + "horbar", 0x2015, + "Hstrok", 0x0126, + "hstrok", 0x0127, + "hybull", 0x2043, + "hyphen", 0x002D, + NULL, 0 }; static NameId namesI[]={ - "Iacgr", 0x038A, - "iacgr", 0x03AF, - "Iacute", 0x00CD, - "iacute", 0x00ED, - "Icirc", 0x00CE, - "icirc", 0x00EE, - "Icy", 0x0418, - "icy", 0x0438, - "idiagr", 0x0390, - "Idigr", 0x03AA, - "idigr", 0x03CA, - "Idot", 0x0130, - "IEcy", 0x0415, - "iecy", 0x0435, - "iexcl", 0x00A1, - "iff", 0x21D4, - "Igr", 0x0399, - "igr", 0x03B9, - "Igrave", 0x00CC, - "igrave", 0x00EC, - "IJlig", 0x0132, - "ijlig", 0x0133, - "Imacr", 0x012A, - "imacr", 0x012B, - "image", 0x2111, - "incare", 0x2105, - "infin", 0x221E, - "inodot", 0x0131, - "int", 0x222B, - "intcal", 0x22BA, - "IOcy", 0x0401, - "iocy", 0x0451, - "Iogon", 0x012E, - "iogon", 0x012F, - "iota", 0x03B9, - "iquest", 0x00BF, - "isin", 0x220A, - "Itilde", 0x0128, - "itilde", 0x0129, - "Iukcy", 0x0406, - "iukcy", 0x0456, - "Iuml", 0x00CF, - "iuml", 0x00EF, - NULL, 0 + "Iacgr", 0x038A, + "iacgr", 0x03AF, + "Iacute", 0x00CD, + "iacute", 0x00ED, + "Icirc", 0x00CE, + "icirc", 0x00EE, + "Icy", 0x0418, + "icy", 0x0438, + "idiagr", 0x0390, + "Idigr", 0x03AA, + "idigr", 0x03CA, + "Idot", 0x0130, + "IEcy", 0x0415, + "iecy", 0x0435, + "iexcl", 0x00A1, + "iff", 0x21D4, + "Igr", 0x0399, + "igr", 0x03B9, + "Igrave", 0x00CC, + "igrave", 0x00EC, + "IJlig", 0x0132, + "ijlig", 0x0133, + "Imacr", 0x012A, + "imacr", 0x012B, + "image", 0x2111, + "incare", 0x2105, + "infin", 0x221E, + "inodot", 0x0131, + "int", 0x222B, + "intcal", 0x22BA, + "IOcy", 0x0401, + "iocy", 0x0451, + "Iogon", 0x012E, + "iogon", 0x012F, + "iota", 0x03B9, + "iquest", 0x00BF, + "isin", 0x220A, + "Itilde", 0x0128, + "itilde", 0x0129, + "Iukcy", 0x0406, + "iukcy", 0x0456, + "Iuml", 0x00CF, + "iuml", 0x00EF, + NULL, 0 }; static NameId namesJ[]={ - "Jcirc", 0x0134, - "jcirc", 0x0135, - "Jcy", 0x0419, - "jcy", 0x0439, - "Jsercy", 0x0408, - "jsercy", 0x0458, - "Jukcy", 0x0404, - "jukcy", 0x0454, - NULL, 0 + "Jcirc", 0x0134, + "jcirc", 0x0135, + "Jcy", 0x0419, + "jcy", 0x0439, + "Jsercy", 0x0408, + "jsercy", 0x0458, + "Jukcy", 0x0404, + "jukcy", 0x0454, + NULL, 0 }; static NameId namesK[]={ - "kappa", 0x03BA, - "kappav", 0x03F0, - "Kcedil", 0x0136, - "kcedil", 0x0137, - "Kcy", 0x041A, - "kcy", 0x043A, - "Kgr", 0x039A, - "kgr", 0x03BA, - "kgreen", 0x0138, - "KHcy", 0x0425, - "khcy", 0x0445, - "KHgr", 0x03A7, - "khgr", 0x03C7, - "KJcy", 0x040C, - "kjcy", 0x045C, - NULL, 0 + "kappa", 0x03BA, + "kappav", 0x03F0, + "Kcedil", 0x0136, + "kcedil", 0x0137, + "Kcy", 0x041A, + "kcy", 0x043A, + "Kgr", 0x039A, + "kgr", 0x03BA, + "kgreen", 0x0138, + "KHcy", 0x0425, + "khcy", 0x0445, + "KHgr", 0x03A7, + "khgr", 0x03C7, + "KJcy", 0x040C, + "kjcy", 0x045C, + NULL, 0 }; static NameId namesL[]={ - "lAarr", 0x21DA, - "Lacute", 0x0139, - "lacute", 0x013A, - "lagran", 0x2112, - "Lambda", 0x039B, - "lambda", 0x03BB, - "lang", 0x3008, - "lap", 0x2272, - "laquo", 0x00AB, - "larr", 0x2190, - "Larr", 0x219E, - "lArr", 0x21D0, - "larr2", 0x21C7, - "larrhk", 0x21A9, - "larrlp", 0x21AB, - "larrtl", 0x21A2, - "Lcaron", 0x013D, - "lcaron", 0x013E, - "Lcedil", 0x013B, - "lcedil", 0x013C, - "lceil", 0x2308, - "lcub", 0x007B, - "Lcy", 0x041B, - "lcy", 0x043B, - "ldot", 0x22D6, - "ldquo", 0x201C, - "ldquor", 0x201E, - "le", 0x2264, - "lE", 0x2266, - "leg", 0x22DA, - "lEg", 0x22DA, - "les", 0x2264, - "lfloor", 0x230A, - "lg", 0x2276, - "Lgr", 0x039B, - "lgr", 0x03BB, - "lhard", 0x21BD, - "lharu", 0x21BC, - "lhblk", 0x2584, - "LJcy", 0x0409, - "ljcy", 0x0459, - "Ll", 0x22D8, - "Lmidot", 0x013F, - "lmidot", 0x0140, - "lnap", 0xE2A2, - "lne", 0x2268, - "lnE", 0x2268, - "lnsim", 0x22E6, - "lowast", 0x2217, - "lowbar", 0x005F, - "loz", 0x25CA, - "lozf", 0x2726, - "lpar", 0x0028, - "lrarr2", 0x21C6, - "lrhar2", 0x21CB, - "lsh", 0x21B0, - "lsim", 0x2272, - "lsqb", 0x005B, - "lsquo", 0x2018, - "lsquor", 0x201A, - "Lstrok", 0x0141, - "lstrok", 0x0142, - "lt", 0x003C, - "Lt", 0x226A, - "lthree", 0x22CB, - "ltimes", 0x22C9, - "ltri", 0x25C3, - "ltrie", 0x22B4, - "ltrif", 0x25C2, - "lvnE", 0x2268, - NULL, 0 + "lAarr", 0x21DA, + "Lacute", 0x0139, + "lacute", 0x013A, + "lagran", 0x2112, + "Lambda", 0x039B, + "lambda", 0x03BB, + "lang", 0x3008, + "lap", 0x2272, + "laquo", 0x00AB, + "larr", 0x2190, + "Larr", 0x219E, + "lArr", 0x21D0, + "larr2", 0x21C7, + "larrhk", 0x21A9, + "larrlp", 0x21AB, + "larrtl", 0x21A2, + "Lcaron", 0x013D, + "lcaron", 0x013E, + "Lcedil", 0x013B, + "lcedil", 0x013C, + "lceil", 0x2308, + "lcub", 0x007B, + "Lcy", 0x041B, + "lcy", 0x043B, + "ldot", 0x22D6, + "ldquo", 0x201C, + "ldquor", 0x201E, + "le", 0x2264, + "lE", 0x2266, + "leg", 0x22DA, + "lEg", 0x22DA, + "les", 0x2264, + "lfloor", 0x230A, + "lg", 0x2276, + "Lgr", 0x039B, + "lgr", 0x03BB, + "lhard", 0x21BD, + "lharu", 0x21BC, + "lhblk", 0x2584, + "LJcy", 0x0409, + "ljcy", 0x0459, + "Ll", 0x22D8, + "Lmidot", 0x013F, + "lmidot", 0x0140, + "lnap", 0xE2A2, + "lne", 0x2268, + "lnE", 0x2268, + "lnsim", 0x22E6, + "lowast", 0x2217, + "lowbar", 0x005F, + "loz", 0x25CA, + "lozf", 0x2726, + "lpar", 0x0028, + "lrarr2", 0x21C6, + "lrhar2", 0x21CB, + "lsh", 0x21B0, + "lsim", 0x2272, + "lsqb", 0x005B, + "lsquo", 0x2018, + "lsquor", 0x201A, + "Lstrok", 0x0141, + "lstrok", 0x0142, + "lt", 0x003C, + "Lt", 0x226A, + "lthree", 0x22CB, + "ltimes", 0x22C9, + "ltri", 0x25C3, + "ltrie", 0x22B4, + "ltrif", 0x25C2, + "lvnE", 0x2268, + NULL, 0 }; static NameId namesM[]={ - "macr", 0x00AF, - "male", 0x2642, - "malt", 0x2720, - "map", 0x21A6, - "marker", 0x25AE, - "Mcy", 0x041C, - "mcy", 0x043C, - "mdash", 0x2014, - "Mgr", 0x039C, - "mgr", 0x03BC, - "micro", 0x00B5, - "mid", 0x2223, - "middot", 0x00B7, - "minus", 0x2212, - "minusb", 0x229F, - "mldr", 0x2026, - "mnplus", 0x2213, - "models", 0x22A7, - "mu", 0x03BC, - "mumap", 0x22B8, - NULL, 0 + "macr", 0x00AF, + "male", 0x2642, + "malt", 0x2720, + "map", 0x21A6, + "marker", 0x25AE, + "Mcy", 0x041C, + "mcy", 0x043C, + "mdash", 0x2014, + "Mgr", 0x039C, + "mgr", 0x03BC, + "micro", 0x00B5, + "mid", 0x2223, + "middot", 0x00B7, + "minus", 0x2212, + "minusb", 0x229F, + "mldr", 0x2026, + "mnplus", 0x2213, + "models", 0x22A7, + "mu", 0x03BC, + "mumap", 0x22B8, + NULL, 0 }; static NameId namesN[]={ - "nabla", 0x2207, - "Nacute", 0x0143, - "nacute", 0x0144, - "nap", 0x2249, - "napos", 0x0149, - "natur", 0x266E, -// "nbsp", 0x00A0, - "nbsp", 32, // make non-breaking space appear as space - "Ncaron", 0x0147, - "ncaron", 0x0148, - "Ncedil", 0x0145, - "ncedil", 0x0146, - "ncong", 0x2247, - "Ncy", 0x041D, - "ncy", 0x043D, - "ndash", 0x2013, - "ne", 0x2260, - "nearr", 0x2197, - "nequiv", 0x2262, - "nexist", 0x2204, - "nge", 0x2271, - "ngE", 0x2271, - "nges", 0x2271, - "Ngr", 0x039D, - "ngr", 0x03BD, - "ngt", 0x226F, - "nharr", 0x21AE, - "nhArr", 0x21CE, - "ni", 0x220D, - "NJcy", 0x040A, - "njcy", 0x045A, - "nlarr", 0x219A, - "nlArr", 0x21CD, - "nldr", 0x2025, - "nle", 0x2270, - "nlE", 0x2270, - "nles", 0x2270, - "nlt", 0x226E, - "nltri", 0x22EA, - "nltrie", 0x22EC, - "nmid", 0x2224, - "not", 0x00AC, - "notin", 0x2209, - "npar", 0x2226, - "npr", 0x2280, - "npre", 0x22E0, - "nrarr", 0x219B, - "nrArr", 0x21CF, - "nrtri", 0x22EB, - "nrtrie", 0x22ED, - "nsc", 0x2281, - "nsce", 0x22E1, - "nsim", 0x2241, - "nsime", 0x2244, - "nsmid", 0xE2AA, - "nspar", 0x2226, - "nsub", 0x2284, - "nsube", 0x2288, - "nsubE", 0x2288, - "nsup", 0x2285, - "nsupe", 0x2289, - "nsupE", 0x2289, - "Ntilde", 0x00D1, - "ntilde", 0x00F1, - "nu", 0x03BD, - "num", 0x0023, - "numero", 0x2116, - "numsp", 0x2007, - "nvdash", 0x22AC, - "nvDash", 0x22AD, - "nVdash", 0x22AE, - "nVDash", 0x22AF, - "nwarr", 0x2196, - NULL, 0 + "nabla", 0x2207, + "Nacute", 0x0143, + "nacute", 0x0144, + "nap", 0x2249, + "napos", 0x0149, + "natur", 0x266E, +// "nbsp", 0x00A0, + "nbsp", 32, // make non-breaking space appear as space + "Ncaron", 0x0147, + "ncaron", 0x0148, + "Ncedil", 0x0145, + "ncedil", 0x0146, + "ncong", 0x2247, + "Ncy", 0x041D, + "ncy", 0x043D, + "ndash", 0x2013, + "ne", 0x2260, + "nearr", 0x2197, + "nequiv", 0x2262, + "nexist", 0x2204, + "nge", 0x2271, + "ngE", 0x2271, + "nges", 0x2271, + "Ngr", 0x039D, + "ngr", 0x03BD, + "ngt", 0x226F, + "nharr", 0x21AE, + "nhArr", 0x21CE, + "ni", 0x220D, + "NJcy", 0x040A, + "njcy", 0x045A, + "nlarr", 0x219A, + "nlArr", 0x21CD, + "nldr", 0x2025, + "nle", 0x2270, + "nlE", 0x2270, + "nles", 0x2270, + "nlt", 0x226E, + "nltri", 0x22EA, + "nltrie", 0x22EC, + "nmid", 0x2224, + "not", 0x00AC, + "notin", 0x2209, + "npar", 0x2226, + "npr", 0x2280, + "npre", 0x22E0, + "nrarr", 0x219B, + "nrArr", 0x21CF, + "nrtri", 0x22EB, + "nrtrie", 0x22ED, + "nsc", 0x2281, + "nsce", 0x22E1, + "nsim", 0x2241, + "nsime", 0x2244, + "nsmid", 0xE2AA, + "nspar", 0x2226, + "nsub", 0x2284, + "nsube", 0x2288, + "nsubE", 0x2288, + "nsup", 0x2285, + "nsupe", 0x2289, + "nsupE", 0x2289, + "Ntilde", 0x00D1, + "ntilde", 0x00F1, + "nu", 0x03BD, + "num", 0x0023, + "numero", 0x2116, + "numsp", 0x2007, + "nvdash", 0x22AC, + "nvDash", 0x22AD, + "nVdash", 0x22AE, + "nVDash", 0x22AF, + "nwarr", 0x2196, + NULL, 0 }; static NameId namesO[]={ - "Oacgr", 0x038C, - "oacgr", 0x03CC, - "Oacute", 0x00D3, - "oacute", 0x00F3, - "oast", 0x229B, - "ocir", 0x229A, - "Ocirc", 0x00D4, - "ocirc", 0x00F4, - "Ocy", 0x041E, - "ocy", 0x043E, - "odash", 0x229D, - "Odblac", 0x0150, - "odblac", 0x0151, - "odot", 0x2299, - "OElig", 0x0152, - "oelig", 0x0153, - "ogon", 0x02DB, - "Ogr", 0x039F, - "ogr", 0x03BF, - "Ograve", 0x00D2, - "ograve", 0x00F2, - "OHacgr", 0x038F, - "ohacgr", 0x03CE, - "OHgr", 0x03A9, - "ohgr", 0x03C9, - "ohm", 0x2126, - "olarr", 0x21BA, - "Omacr", 0x014C, - "omacr", 0x014D, - "Omega", 0x03A9, - "omega", 0x03C9, - "ominus", 0x2296, - "oplus", 0x2295, - "or", 0x2228, - "orarr", 0x21BB, - "order", 0x2134, - "ordf", 0x00AA, - "ordm", 0x00BA, - "oS", 0x24C8, - "Oslash", 0x00D8, - "oslash", 0x00F8, - "osol", 0x2298, - "Otilde", 0x00D5, - "otilde", 0x00F5, - "otimes", 0x2297, - "Ouml", 0x00D6, - "ouml", 0x00F6, - NULL, 0 + "Oacgr", 0x038C, + "oacgr", 0x03CC, + "Oacute", 0x00D3, + "oacute", 0x00F3, + "oast", 0x229B, + "ocir", 0x229A, + "Ocirc", 0x00D4, + "ocirc", 0x00F4, + "Ocy", 0x041E, + "ocy", 0x043E, + "odash", 0x229D, + "Odblac", 0x0150, + "odblac", 0x0151, + "odot", 0x2299, + "OElig", 0x0152, + "oelig", 0x0153, + "ogon", 0x02DB, + "Ogr", 0x039F, + "ogr", 0x03BF, + "Ograve", 0x00D2, + "ograve", 0x00F2, + "OHacgr", 0x038F, + "ohacgr", 0x03CE, + "OHgr", 0x03A9, + "ohgr", 0x03C9, + "ohm", 0x2126, + "olarr", 0x21BA, + "Omacr", 0x014C, + "omacr", 0x014D, + "Omega", 0x03A9, + "omega", 0x03C9, + "ominus", 0x2296, + "oplus", 0x2295, + "or", 0x2228, + "orarr", 0x21BB, + "order", 0x2134, + "ordf", 0x00AA, + "ordm", 0x00BA, + "oS", 0x24C8, + "Oslash", 0x00D8, + "oslash", 0x00F8, + "osol", 0x2298, + "Otilde", 0x00D5, + "otilde", 0x00F5, + "otimes", 0x2297, + "Ouml", 0x00D6, + "ouml", 0x00F6, + NULL, 0 }; static NameId namesP[]={ - "par", 0x2225, - "para", 0x00B6, - "part", 0x2202, - "Pcy", 0x041F, - "pcy", 0x043F, - "percnt", 0x0025, - "period", 0x002E, - "permil", 0x2030, - "perp", 0x22A5, - "Pgr", 0x03A0, - "pgr", 0x03C0, - "PHgr", 0x03A6, - "phgr", 0x03C6, - "Phi", 0x03A6, - "phis", 0x03C6, - "phiv", 0x03D5, - "phmmat", 0x2133, - "phone", 0x260E, - "Pi", 0x03A0, - "pi", 0x03C0, - "piv", 0x03D6, - "planck", 0x210F, - "plus", 0x002B, - "plusb", 0x229E, - "plusdo", 0x2214, - "plusmn", 0x00B1, - "pound", 0x00A3, - "pr", 0x227A, - "prap", 0x227E, - "pre", 0x227C, - "prime", 0x2032, - "Prime", 0x2033, - "prnap", 0x22E8, - "prnE", 0xE2B3, - "prnsim", 0x22E8, - "prod", 0x220F, - "prop", 0x221D, - "prsim", 0x227E, - "PSgr", 0x03A8, - "psgr", 0x03C8, - "Psi", 0x03A8, - "psi", 0x03C8, - "puncsp", 0x2008, - NULL, 0 + "par", 0x2225, + "para", 0x00B6, + "part", 0x2202, + "Pcy", 0x041F, + "pcy", 0x043F, + "percnt", 0x0025, + "period", 0x002E, + "permil", 0x2030, + "perp", 0x22A5, + "Pgr", 0x03A0, + "pgr", 0x03C0, + "PHgr", 0x03A6, + "phgr", 0x03C6, + "Phi", 0x03A6, + "phis", 0x03C6, + "phiv", 0x03D5, + "phmmat", 0x2133, + "phone", 0x260E, + "Pi", 0x03A0, + "pi", 0x03C0, + "piv", 0x03D6, + "planck", 0x210F, + "plus", 0x002B, + "plusb", 0x229E, + "plusdo", 0x2214, + "plusmn", 0x00B1, + "pound", 0x00A3, + "pr", 0x227A, + "prap", 0x227E, + "pre", 0x227C, + "prime", 0x2032, + "Prime", 0x2033, + "prnap", 0x22E8, + "prnE", 0xE2B3, + "prnsim", 0x22E8, + "prod", 0x220F, + "prop", 0x221D, + "prsim", 0x227E, + "PSgr", 0x03A8, + "psgr", 0x03C8, + "Psi", 0x03A8, + "psi", 0x03C8, + "puncsp", 0x2008, + NULL, 0 }; static NameId namesQ[]={ - "quest", 0x003F, - "quot", 0x0022, - NULL, 0 + "quest", 0x003F, + "quot", 0x0022, + NULL, 0 }; static NameId namesR[]={ - "rAarr", 0x21DB, - "Racute", 0x0154, - "racute", 0x0155, - "radic", 0x221A, - "rang", 0x3009, - "raquo", 0x00BB, - "rarr", 0x2192, - "Rarr", 0x21A0, - "rArr", 0x21D2, - "rarr2", 0x21C9, - "rarrhk", 0x21AA, - "rarrlp", 0x21AC, - "rarrtl", 0x21A3, - "rarrw", 0x219D, - "Rcaron", 0x0158, - "rcaron", 0x0159, - "Rcedil", 0x0156, - "rcedil", 0x0157, - "rceil", 0x2309, - "rcub", 0x007D, - "Rcy", 0x0420, - "rcy", 0x0440, - "rdquo", 0x201D, - "rdquor", 0x201C, - "real", 0x211C, - "rect", 0x25AD, - "reg", 0x00AE, - "rfloor", 0x230B, - "Rgr", 0x03A1, - "rgr", 0x03C1, - "rhard", 0x21C1, - "rharu", 0x21C0, - "rho", 0x03C1, - "rhov", 0x03F1, - "ring", 0x02DA, - "rlarr2", 0x21C4, - "rlhar2", 0x21CC, - "rpar", 0x0029, - "rpargt", 0xE291, - "rsh", 0x21B1, - "rsqb", 0x005D, - "rsquo", 0x2019, - "rsquor", 0x2018, - "rthree", 0x22CC, - "rtimes", 0x22CA, - "rtri", 0x25B9, - "rtrie", 0x22B5, - "rtrif", 0x25B8, - "rx", 0x211E, - NULL, 0 + "rAarr", 0x21DB, + "Racute", 0x0154, + "racute", 0x0155, + "radic", 0x221A, + "rang", 0x3009, + "raquo", 0x00BB, + "rarr", 0x2192, + "Rarr", 0x21A0, + "rArr", 0x21D2, + "rarr2", 0x21C9, + "rarrhk", 0x21AA, + "rarrlp", 0x21AC, + "rarrtl", 0x21A3, + "rarrw", 0x219D, + "Rcaron", 0x0158, + "rcaron", 0x0159, + "Rcedil", 0x0156, + "rcedil", 0x0157, + "rceil", 0x2309, + "rcub", 0x007D, + "Rcy", 0x0420, + "rcy", 0x0440, + "rdquo", 0x201D, + "rdquor", 0x201C, + "real", 0x211C, + "rect", 0x25AD, + "reg", 0x00AE, + "rfloor", 0x230B, + "Rgr", 0x03A1, + "rgr", 0x03C1, + "rhard", 0x21C1, + "rharu", 0x21C0, + "rho", 0x03C1, + "rhov", 0x03F1, + "ring", 0x02DA, + "rlarr2", 0x21C4, + "rlhar2", 0x21CC, + "rpar", 0x0029, + "rpargt", 0xE291, + "rsh", 0x21B1, + "rsqb", 0x005D, + "rsquo", 0x2019, + "rsquor", 0x2018, + "rthree", 0x22CC, + "rtimes", 0x22CA, + "rtri", 0x25B9, + "rtrie", 0x22B5, + "rtrif", 0x25B8, + "rx", 0x211E, + NULL, 0 }; static NameId namesS[]={ - "Sacute", 0x015A, - "sacute", 0x015B, - "samalg", 0x2210, - "sbsol", 0xFE68, - "sc", 0x227B, - "scap", 0x227F, - "Scaron", 0x0160, - "scaron", 0x0161, - "sccue", 0x227D, - "sce", 0x227D, - "Scedil", 0x015E, - "scedil", 0x015F, - "Scirc", 0x015C, - "scirc", 0x015D, - "scnap", 0x22E9, - "scnE", 0xE2B5, - "scnsim", 0x22E9, - "scsim", 0x227F, - "Scy", 0x0421, - "scy", 0x0441, - "sdot", 0x22C5, - "sdotb", 0x22A1, - "sect", 0x00A7, - "semi", 0x003B, - "setmn", 0x2216, - "sext", 0x2736, - "sfgr", 0x03C2, - "sfrown", 0x2322, - "Sgr", 0x03A3, - "sgr", 0x03C3, - "sharp", 0x266F, - "SHCHcy", 0x0429, - "shchcy", 0x0449, - "SHcy", 0x0428, - "shcy", 0x0448, - "shy", 0x00AD, - "Sigma", 0x03A3, - "sigma", 0x03C3, - "sigmav", 0x03C2, - "sim", 0x223C, - "sime", 0x2243, - "smid", 0xE301, - "smile", 0x2323, - "SOFTcy", 0x042C, - "softcy", 0x044C, - "sol", 0x002F, - "spades", 0x2660, - "spar", 0x2225, - "sqcap", 0x2293, - "sqcup", 0x2294, - "sqsub", 0x228F, - "sqsube", 0x2291, - "sqsup", 0x2290, - "sqsupe", 0x2292, - "squ", 0x25A1, - "square", 0x25A1, - "squf", 0x25AA, - "ssetmn", 0x2216, - "ssmile", 0x2323, - "sstarf", 0x22C6, - "star", 0x22C6, - "starf", 0x2605, - "sub", 0x2282, - "Sub", 0x22D0, - "sube", 0x2286, - "subE", 0x2286, - "subne", 0x228A, - "subnE", 0x228A, - "sum", 0x2211, - "sung", 0x2669, - "sup", 0x2283, - "Sup", 0x22D1, - "sup1", 0x00B9, - "sup2", 0x00B2, - "sup3", 0x00B3, - "supe", 0x2287, - "supE", 0x2287, - "supne", 0x228B, - "supnE", 0x228B, - "szlig", 0x00DF, - NULL, 0 + "Sacute", 0x015A, + "sacute", 0x015B, + "samalg", 0x2210, + "sbsol", 0xFE68, + "sc", 0x227B, + "scap", 0x227F, + "Scaron", 0x0160, + "scaron", 0x0161, + "sccue", 0x227D, + "sce", 0x227D, + "Scedil", 0x015E, + "scedil", 0x015F, + "Scirc", 0x015C, + "scirc", 0x015D, + "scnap", 0x22E9, + "scnE", 0xE2B5, + "scnsim", 0x22E9, + "scsim", 0x227F, + "Scy", 0x0421, + "scy", 0x0441, + "sdot", 0x22C5, + "sdotb", 0x22A1, + "sect", 0x00A7, + "semi", 0x003B, + "setmn", 0x2216, + "sext", 0x2736, + "sfgr", 0x03C2, + "sfrown", 0x2322, + "Sgr", 0x03A3, + "sgr", 0x03C3, + "sharp", 0x266F, + "SHCHcy", 0x0429, + "shchcy", 0x0449, + "SHcy", 0x0428, + "shcy", 0x0448, + "shy", 0x00AD, + "Sigma", 0x03A3, + "sigma", 0x03C3, + "sigmav", 0x03C2, + "sim", 0x223C, + "sime", 0x2243, + "smid", 0xE301, + "smile", 0x2323, + "SOFTcy", 0x042C, + "softcy", 0x044C, + "sol", 0x002F, + "spades", 0x2660, + "spar", 0x2225, + "sqcap", 0x2293, + "sqcup", 0x2294, + "sqsub", 0x228F, + "sqsube", 0x2291, + "sqsup", 0x2290, + "sqsupe", 0x2292, + "squ", 0x25A1, + "square", 0x25A1, + "squf", 0x25AA, + "ssetmn", 0x2216, + "ssmile", 0x2323, + "sstarf", 0x22C6, + "star", 0x22C6, + "starf", 0x2605, + "sub", 0x2282, + "Sub", 0x22D0, + "sube", 0x2286, + "subE", 0x2286, + "subne", 0x228A, + "subnE", 0x228A, + "sum", 0x2211, + "sung", 0x2669, + "sup", 0x2283, + "Sup", 0x22D1, + "sup1", 0x00B9, + "sup2", 0x00B2, + "sup3", 0x00B3, + "supe", 0x2287, + "supE", 0x2287, + "supne", 0x228B, + "supnE", 0x228B, + "szlig", 0x00DF, + NULL, 0 }; static NameId namesT[]={ - "target", 0x2316, - "tau", 0x03C4, - "Tcaron", 0x0164, - "tcaron", 0x0165, - "Tcedil", 0x0162, - "tcedil", 0x0163, - "Tcy", 0x0422, - "tcy", 0x0442, - "tdot", 0x20DB, - "telrec", 0x2315, - "Tgr", 0x03A4, - "tgr", 0x03C4, - "there4", 0x2234, - "Theta", 0x0398, - "thetas", 0x03B8, - "thetav", 0x03D1, - "THgr", 0x0398, - "thgr", 0x03B8, - "thinsp", 0x2009, - "thkap", 0x2248, - "thksim", 0x223C, - "THORN", 0x00DE, - "thorn", 0x00FE, - "tilde", 0x02DC, - "times", 0x00D7, - "timesb", 0x22A0, - "top", 0x22A4, - "tprime", 0x2034, - "trade", 0x2122, - "trie", 0x225C, - "TScy", 0x0426, - "tscy", 0x0446, - "TSHcy", 0x040B, - "tshcy", 0x045B, - "Tstrok", 0x0166, - "tstrok", 0x0167, - "twixt", 0x226C, - NULL, 0 + "target", 0x2316, + "tau", 0x03C4, + "Tcaron", 0x0164, + "tcaron", 0x0165, + "Tcedil", 0x0162, + "tcedil", 0x0163, + "Tcy", 0x0422, + "tcy", 0x0442, + "tdot", 0x20DB, + "telrec", 0x2315, + "Tgr", 0x03A4, + "tgr", 0x03C4, + "there4", 0x2234, + "Theta", 0x0398, + "thetas", 0x03B8, + "thetav", 0x03D1, + "THgr", 0x0398, + "thgr", 0x03B8, + "thinsp", 0x2009, + "thkap", 0x2248, + "thksim", 0x223C, + "THORN", 0x00DE, + "thorn", 0x00FE, + "tilde", 0x02DC, + "times", 0x00D7, + "timesb", 0x22A0, + "top", 0x22A4, + "tprime", 0x2034, + "trade", 0x2122, + "trie", 0x225C, + "TScy", 0x0426, + "tscy", 0x0446, + "TSHcy", 0x040B, + "tshcy", 0x045B, + "Tstrok", 0x0166, + "tstrok", 0x0167, + "twixt", 0x226C, + NULL, 0 }; static NameId namesU[]={ - "Uacgr", 0x038E, - "uacgr", 0x03CD, - "Uacute", 0x00DA, - "uacute", 0x00FA, - "uarr", 0x2191, - "uArr", 0x21D1, - "uarr2", 0x21C8, - "Ubrcy", 0x040E, - "ubrcy", 0x045E, - "Ubreve", 0x016C, - "ubreve", 0x016D, - "Ucirc", 0x00DB, - "ucirc", 0x00FB, - "Ucy", 0x0423, - "ucy", 0x0443, - "Udblac", 0x0170, - "udblac", 0x0171, - "udiagr", 0x03B0, - "Udigr", 0x03AB, - "udigr", 0x03CB, - "Ugr", 0x03A5, - "ugr", 0x03C5, - "Ugrave", 0x00D9, - "ugrave", 0x00F9, - "uharl", 0x21BF, - "uharr", 0x21BE, - "uhblk", 0x2580, - "ulcorn", 0x231C, - "ulcrop", 0x230F, - "Umacr", 0x016A, - "umacr", 0x016B, - "uml", 0x00A8, - "Uogon", 0x0172, - "uogon", 0x0173, - "uplus", 0x228E, - "upsi", 0x03C5, - "Upsi", 0x03D2, - "urcorn", 0x231D, - "urcrop", 0x230E, - "Uring", 0x016E, - "uring", 0x016F, - "Utilde", 0x0168, - "utilde", 0x0169, - "utri", 0x25B5, - "utrif", 0x25B4, - "Uuml", 0x00DC, - "uuml", 0x00FC, - NULL, 0 + "Uacgr", 0x038E, + "uacgr", 0x03CD, + "Uacute", 0x00DA, + "uacute", 0x00FA, + "uarr", 0x2191, + "uArr", 0x21D1, + "uarr2", 0x21C8, + "Ubrcy", 0x040E, + "ubrcy", 0x045E, + "Ubreve", 0x016C, + "ubreve", 0x016D, + "Ucirc", 0x00DB, + "ucirc", 0x00FB, + "Ucy", 0x0423, + "ucy", 0x0443, + "Udblac", 0x0170, + "udblac", 0x0171, + "udiagr", 0x03B0, + "Udigr", 0x03AB, + "udigr", 0x03CB, + "Ugr", 0x03A5, + "ugr", 0x03C5, + "Ugrave", 0x00D9, + "ugrave", 0x00F9, + "uharl", 0x21BF, + "uharr", 0x21BE, + "uhblk", 0x2580, + "ulcorn", 0x231C, + "ulcrop", 0x230F, + "Umacr", 0x016A, + "umacr", 0x016B, + "uml", 0x00A8, + "Uogon", 0x0172, + "uogon", 0x0173, + "uplus", 0x228E, + "upsi", 0x03C5, + "Upsi", 0x03D2, + "urcorn", 0x231D, + "urcrop", 0x230E, + "Uring", 0x016E, + "uring", 0x016F, + "Utilde", 0x0168, + "utilde", 0x0169, + "utri", 0x25B5, + "utrif", 0x25B4, + "Uuml", 0x00DC, + "uuml", 0x00FC, + NULL, 0 }; static NameId namesV[]={ - "varr", 0x2195, - "vArr", 0x21D5, - "Vcy", 0x0412, - "vcy", 0x0432, - "vdash", 0x22A2, - "vDash", 0x22A8, - "Vdash", 0x22A9, - "veebar", 0x22BB, - "vellip", 0x22EE, - "verbar", 0x007C, - "Verbar", 0x2016, - "vltri", 0x22B2, - "vprime", 0x2032, - "vprop", 0x221D, - "vrtri", 0x22B3, - "vsubne", 0x228A, - "vsubnE", 0xE2B8, - "vsupne", 0x228B, - "vsupnE", 0x228B, - "Vvdash", 0x22AA, - NULL, 0 + "varr", 0x2195, + "vArr", 0x21D5, + "Vcy", 0x0412, + "vcy", 0x0432, + "vdash", 0x22A2, + "vDash", 0x22A8, + "Vdash", 0x22A9, + "veebar", 0x22BB, + "vellip", 0x22EE, + "verbar", 0x007C, + "Verbar", 0x2016, + "vltri", 0x22B2, + "vprime", 0x2032, + "vprop", 0x221D, + "vrtri", 0x22B3, + "vsubne", 0x228A, + "vsubnE", 0xE2B8, + "vsupne", 0x228B, + "vsupnE", 0x228B, + "Vvdash", 0x22AA, + NULL, 0 }; static NameId namesW[]={ - "Wcirc", 0x0174, - "wcirc", 0x0175, - "wedgeq", 0x2259, - "weierp", 0x2118, - "wreath", 0x2240, - NULL, 0 + "Wcirc", 0x0174, + "wcirc", 0x0175, + "wedgeq", 0x2259, + "weierp", 0x2118, + "wreath", 0x2240, + NULL, 0 }; static NameId namesX[]={ - "xcirc", 0x25CB, - "xdtri", 0x25BD, - "Xgr", 0x039E, - "xgr", 0x03BE, - "xharr", 0x2194, - "xhArr", 0x2194, - "Xi", 0x039E, - "xi", 0x03BE, - "xlArr", 0x21D0, - "xrArr", 0x21D2, - "xutri", 0x25B3, - NULL, 0 + "xcirc", 0x25CB, + "xdtri", 0x25BD, + "Xgr", 0x039E, + "xgr", 0x03BE, + "xharr", 0x2194, + "xhArr", 0x2194, + "Xi", 0x039E, + "xi", 0x03BE, + "xlArr", 0x21D0, + "xrArr", 0x21D2, + "xutri", 0x25B3, + NULL, 0 }; static NameId namesY[]={ - "Yacute", 0x00DD, - "yacute", 0x00FD, - "YAcy", 0x042F, - "yacy", 0x044F, - "Ycirc", 0x0176, - "ycirc", 0x0177, - "Ycy", 0x042B, - "ycy", 0x044B, - "yen", 0x00A5, - "YIcy", 0x0407, - "yicy", 0x0457, - "YUcy", 0x042E, - "yucy", 0x044E, - "yuml", 0x00FF, - "Yuml", 0x0178, - NULL, 0 + "Yacute", 0x00DD, + "yacute", 0x00FD, + "YAcy", 0x042F, + "yacy", 0x044F, + "Ycirc", 0x0176, + "ycirc", 0x0177, + "Ycy", 0x042B, + "ycy", 0x044B, + "yen", 0x00A5, + "YIcy", 0x0407, + "yicy", 0x0457, + "YUcy", 0x042E, + "yucy", 0x044E, + "yuml", 0x00FF, + "Yuml", 0x0178, + NULL, 0 }; static NameId namesZ[]={ - "Zacute", 0x0179, - "zacute", 0x017A, - "Zcaron", 0x017D, - "zcaron", 0x017E, - "Zcy", 0x0417, - "zcy", 0x0437, - "Zdot", 0x017B, - "zdot", 0x017C, - "zeta", 0x03B6, - "Zgr", 0x0396, - "zgr", 0x03B6, - "ZHcy", 0x0416, - "zhcy", 0x0436, - NULL, 0 + "Zacute", 0x0179, + "zacute", 0x017A, + "Zcaron", 0x017D, + "zcaron", 0x017E, + "Zcy", 0x0417, + "zcy", 0x0437, + "Zdot", 0x017B, + "zdot", 0x017C, + "zeta", 0x03B6, + "Zgr", 0x0396, + "zgr", 0x03B6, + "ZHcy", 0x0416, + "zhcy", 0x0436, + NULL, 0 }; // @todo@ order namesTable and names? by frequency -static NameId* namesTable[] = { - namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI, - namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR, - namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL +static NameId* namesTable[] = { + namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI, + namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR, + namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL }; int HtmlNamedEntity(unsigned char *p, int length) { int tableIndex = tolower(*p) - 'a'; if (tableIndex >= 0 && tableIndex < 26) { - NameId* names = namesTable[tableIndex]; - int i; + NameId* names = namesTable[tableIndex]; + int i; - for (i = 0; names[i].name; i++){ - if (strncmp(names[i].name, (char *)p, length) == 0){ - return names[i].value; - } - } + for (i = 0; names[i].name; i++){ + if (strncmp(names[i].name, (char *)p, length) == 0){ + return names[i].value; + } + } } error("unrecognized character entity \"%.*s\"", length, p); return -1; @@ -1089,263 +1089,263 @@ int HtmlNamedEntity(unsigned char *p, int length) static NameId names[] = { // Entities - "quot", 34, - "amp", 38, - "lt", 60, - "gt", 62, + "quot", 34, + "amp", 38, + "lt", 60, + "gt", 62, - "OElig", 338, - "oelig", 339, - "Scaron", 352, - "scaron", 353, - "Yuml", 376, - "circ", 710, - "tilde", 732, - "ensp", 8194, - "emsp", 8195, - "thinsp", 8201, - "zwnj", 8204, - "zwj", 8205, - "lrm", 8206, - "rlm", 8207, - "ndash", 8211, - "mdash", 8212, - "lsquo", 8216, - "rsquo", 8217, - "sbquo", 8218, - "ldquo", 8220, - "rdquo", 8221, - "bdquo", 8222, - "dagger", 8224, - "Dagger", 8225, - "permil", 8240, - "lsaquo", 8249, - "rsaquo", 8250, - "euro", 8364, + "OElig", 338, + "oelig", 339, + "Scaron", 352, + "scaron", 353, + "Yuml", 376, + "circ", 710, + "tilde", 732, + "ensp", 8194, + "emsp", 8195, + "thinsp", 8201, + "zwnj", 8204, + "zwj", 8205, + "lrm", 8206, + "rlm", 8207, + "ndash", 8211, + "mdash", 8212, + "lsquo", 8216, + "rsquo", 8217, + "sbquo", 8218, + "ldquo", 8220, + "rdquo", 8221, + "bdquo", 8222, + "dagger", 8224, + "Dagger", 8225, + "permil", 8240, + "lsaquo", 8249, + "rsaquo", 8250, + "euro", 8364, // Latin-1 (ISO-8859-1) Entities - "nbsp", 160, - "iexcl", 161, - "cent", 162, - "pound", 163, - "curren", 164, - "yen", 165, - "brvbar", 166, - "sect", 167, - "uml", 168, - "copy", 169, - "ordf", 170, - "laquo", 171, - "not", 172, - "shy", 173, - "reg", 174, - "macr", 175, - "deg", 176, - "plusmn", 177, - "sup2", 178, - "sup3", 179, - "acute", 180, - "micro", 181, - "para", 182, - "middot", 183, - "cedil", 184, - "sup1", 185, - "ordm", 186, - "raquo", 187, - "frac14", 188, - "frac12", 189, - "frac34", 190, - "iquest", 191, - "Agrave", 192, - "Aacute", 193, - "Acirc", 194, - "Atilde", 195, - "Auml", 196, - "Aring", 197, - "AElig", 198, - "Ccedil", 199, - "Egrave", 200, - "Eacute", 201, - "Ecirc", 202, - "Euml", 203, - "Igrave", 204, - "Iacute", 205, - "Icirc", 206, - "Iuml", 207, - "ETH", 208, - "Ntilde", 209, - "Ograve", 210, - "Oacute", 211, - "Ocirc", 212, - "Otilde", 213, - "Ouml", 214, - "times", 215, - "Oslash", 216, - "Ugrave", 217, - "Uacute", 218, - "Ucirc", 219, - "Uuml", 220, - "Yacute", 221, - "THORN", 222, - "szlig", 223, - "agrave", 224, - "aacute", 225, - "acirc", 226, - "atilde", 227, - "auml", 228, - "aring", 229, - "aelig", 230, - "ccedil", 231, - "egrave", 232, - "eacute", 233, - "ecirc", 234, - "euml", 235, - "igrave", 236, - "iacute", 237, - "icirc", 238, - "iuml", 239, - "eth", 240, - "ntilde", 241, - "ograve", 242, - "oacute", 243, - "ocirc", 244, - "otilde", 245, - "ouml", 246, - "divide", 247, - "oslash", 248, - "ugrave", 249, - "uacute", 250, - "ucirc", 251, - "uuml", 252, - "yacute", 253, - "thorn", 254, - "yuml", 255, + "nbsp", 160, + "iexcl", 161, + "cent", 162, + "pound", 163, + "curren", 164, + "yen", 165, + "brvbar", 166, + "sect", 167, + "uml", 168, + "copy", 169, + "ordf", 170, + "laquo", 171, + "not", 172, + "shy", 173, + "reg", 174, + "macr", 175, + "deg", 176, + "plusmn", 177, + "sup2", 178, + "sup3", 179, + "acute", 180, + "micro", 181, + "para", 182, + "middot", 183, + "cedil", 184, + "sup1", 185, + "ordm", 186, + "raquo", 187, + "frac14", 188, + "frac12", 189, + "frac34", 190, + "iquest", 191, + "Agrave", 192, + "Aacute", 193, + "Acirc", 194, + "Atilde", 195, + "Auml", 196, + "Aring", 197, + "AElig", 198, + "Ccedil", 199, + "Egrave", 200, + "Eacute", 201, + "Ecirc", 202, + "Euml", 203, + "Igrave", 204, + "Iacute", 205, + "Icirc", 206, + "Iuml", 207, + "ETH", 208, + "Ntilde", 209, + "Ograve", 210, + "Oacute", 211, + "Ocirc", 212, + "Otilde", 213, + "Ouml", 214, + "times", 215, + "Oslash", 216, + "Ugrave", 217, + "Uacute", 218, + "Ucirc", 219, + "Uuml", 220, + "Yacute", 221, + "THORN", 222, + "szlig", 223, + "agrave", 224, + "aacute", 225, + "acirc", 226, + "atilde", 227, + "auml", 228, + "aring", 229, + "aelig", 230, + "ccedil", 231, + "egrave", 232, + "eacute", 233, + "ecirc", 234, + "euml", 235, + "igrave", 236, + "iacute", 237, + "icirc", 238, + "iuml", 239, + "eth", 240, + "ntilde", 241, + "ograve", 242, + "oacute", 243, + "ocirc", 244, + "otilde", 245, + "ouml", 246, + "divide", 247, + "oslash", 248, + "ugrave", 249, + "uacute", 250, + "ucirc", 251, + "uuml", 252, + "yacute", 253, + "thorn", 254, + "yuml", 255, - // Symbols and Greek letter entities - "fnof", 402, - "Alpha", 913, - "Beta", 914, - "Gamma", 915, - "Delta", 916, - "Epsilon", 917, - "Zeta", 918, - "Eta", 919, - "Theta", 920, - "Iota", 921, - "Kappa", 922, - "Lambda", 923, - "Mu", 924, - "Nu", 925, - "Xi", 926, - "Omicron", 927, - "Pi", 928, - "Rho", 929, - "Sigma", 931, - "Tau", 932, - "Upsilon", 933, - "Phi", 934, - "Chi", 935, - "Psi", 936, - "Omega", 937, - "alpha", 945, - "beta", 946, - "gamma", 947, - "delta", 948, - "epsilon", 949, - "zeta", 950, - "eta", 951, - "theta", 952, - "iota", 953, - "kappa", 954, - "lambda", 955, - "mu", 956, - "nu", 957, - "xi", 958, - "omicron", 959, - "pi", 960, - "rho", 961, - "sigmaf", 962, - "sigma", 963, - "tau", 964, - "upsilon", 965, - "phi", 966, - "chi", 967, - "psi", 968, - "omega", 969, - "thetasym", 977, - "upsih", 978, - "piv", 982, - "bull", 8226, - "hellip", 8230, - "prime", 8242, - "Prime", 8243, - "oline", 8254, - "frasl", 8260, - "weierp", 8472, - "image", 8465, - "real", 8476, - "trade", 8482, - "alefsym", 8501, - "larr", 8592, - "uarr", 8593, - "rarr", 8594, - "darr", 8595, - "harr", 8596, - "crarr", 8629, - "lArr", 8656, - "uArr", 8657, - "rArr", 8658, - "dArr", 8659, - "hArr", 8660, - "forall", 8704, - "part", 8706, - "exist", 8707, - "empty", 8709, - "nabla", 8711, - "isin", 8712, - "notin", 8713, - "ni", 8715, - "prod", 8719, - "sum", 8721, - "minus", 8722, - "lowast", 8727, - "radic", 8730, - "prop", 8733, - "infin", 8734, - "ang", 8736, - "and", 8743, - "or", 8744, - "cap", 8745, - "cup", 8746, - "int", 8747, - "there4", 8756, - "sim", 8764, - "cong", 8773, - "asymp", 8776, - "ne", 8800, - "equiv", 8801, - "le", 8804, - "ge", 8805, - "sub", 8834, - "sup", 8835, - "nsub", 8836, - "sube", 8838, - "supe", 8839, - "oplus", 8853, - "otimes", 8855, - "perp", 8869, - "sdot", 8901, - "lceil", 8968, - "rceil", 8969, - "lfloor", 8970, - "rfloor", 8971, - "lang", 9001, - "rang", 9002, - "loz", 9674, - "spades", 9824, - "clubs", 9827, - "hearts", 9829, - "diams", 9830, + // Symbols and Greek letter entities + "fnof", 402, + "Alpha", 913, + "Beta", 914, + "Gamma", 915, + "Delta", 916, + "Epsilon", 917, + "Zeta", 918, + "Eta", 919, + "Theta", 920, + "Iota", 921, + "Kappa", 922, + "Lambda", 923, + "Mu", 924, + "Nu", 925, + "Xi", 926, + "Omicron", 927, + "Pi", 928, + "Rho", 929, + "Sigma", 931, + "Tau", 932, + "Upsilon", 933, + "Phi", 934, + "Chi", 935, + "Psi", 936, + "Omega", 937, + "alpha", 945, + "beta", 946, + "gamma", 947, + "delta", 948, + "epsilon", 949, + "zeta", 950, + "eta", 951, + "theta", 952, + "iota", 953, + "kappa", 954, + "lambda", 955, + "mu", 956, + "nu", 957, + "xi", 958, + "omicron", 959, + "pi", 960, + "rho", 961, + "sigmaf", 962, + "sigma", 963, + "tau", 964, + "upsilon", 965, + "phi", 966, + "chi", 967, + "psi", 968, + "omega", 969, + "thetasym", 977, + "upsih", 978, + "piv", 982, + "bull", 8226, + "hellip", 8230, + "prime", 8242, + "Prime", 8243, + "oline", 8254, + "frasl", 8260, + "weierp", 8472, + "image", 8465, + "real", 8476, + "trade", 8482, + "alefsym", 8501, + "larr", 8592, + "uarr", 8593, + "rarr", 8594, + "darr", 8595, + "harr", 8596, + "crarr", 8629, + "lArr", 8656, + "uArr", 8657, + "rArr", 8658, + "dArr", 8659, + "hArr", 8660, + "forall", 8704, + "part", 8706, + "exist", 8707, + "empty", 8709, + "nabla", 8711, + "isin", 8712, + "notin", 8713, + "ni", 8715, + "prod", 8719, + "sum", 8721, + "minus", 8722, + "lowast", 8727, + "radic", 8730, + "prop", 8733, + "infin", 8734, + "ang", 8736, + "and", 8743, + "or", 8744, + "cap", 8745, + "cup", 8746, + "int", 8747, + "there4", 8756, + "sim", 8764, + "cong", 8773, + "asymp", 8776, + "ne", 8800, + "equiv", 8801, + "le", 8804, + "ge", 8805, + "sub", 8834, + "sup", 8835, + "nsub", 8836, + "sube", 8838, + "supe", 8839, + "oplus", 8853, + "otimes", 8855, + "perp", 8869, + "sdot", 8901, + "lceil", 8968, + "rceil", 8969, + "lfloor", 8970, + "rfloor", 8971, + "lang", 9001, + "rang", 9002, + "loz", 9674, + "spades", 9824, + "clubs", 9827, + "hearts", 9829, + "diams", 9830, }; int HtmlNamedEntity(unsigned char *p, int length) @@ -1355,10 +1355,10 @@ int HtmlNamedEntity(unsigned char *p, int length) // BUG: this is a dumb, slow linear search for (i = 0; i < sizeof(names) / sizeof(names[0]); i++) { - // Entries are case sensitive - if (memcmp(names[i].name, (char *)p, length) == 0 && - !names[i].name[length]) - return names[i].value; + // Entries are case sensitive + if (memcmp(names[i].name, (char *)p, length) == 0 && + !names[i].name[length]) + return names[i].value; } return -1; } diff --git a/dmd2/enum.c b/dmd2/enum.c index b9465c15..1fa4ad71 100644 --- a/dmd2/enum.c +++ b/dmd2/enum.c @@ -1,393 +1,428 @@ - -// Copyright (c) 1999-2008 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 -#include - -#include "root.h" -#include "enum.h" -#include "mtype.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "module.h" -#include "declaration.h" - -/********************************* EnumDeclaration ****************************/ - -EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) - : ScopeDsymbol(id) -{ - this->loc = loc; - type = new TypeEnum(this); - this->memtype = memtype; - maxval = NULL; - minval = NULL; - defaultval = NULL; -#if IN_DMD - sinit = NULL; -#endif - isdeprecated = 0; -} - -Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *t = NULL; - if (memtype) - t = memtype->syntaxCopy(); - - EnumDeclaration *ed; - if (s) - { ed = (EnumDeclaration *)s; - ed->memtype = t; - } - else - ed = new EnumDeclaration(loc, ident, t); - ScopeDsymbol::syntaxCopy(ed); - return ed; -} - -void EnumDeclaration::semantic(Scope *sc) -{ - Type *t; - Scope *sce; - - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); - //printf("EnumDeclaration::semantic() %s\n", toChars()); - if (!members) // enum ident; - return; - - if (!memtype && !isAnonymous()) - { // Set memtype if we can to reduce fwd reference errors - memtype = Type::tint32; // case 1) enum ident { ... } - } - - if (symtab) // if already done - { if (!scope) - return; // semantic() already completed - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - if (sc->stc & STCdeprecated) - isdeprecated = 1; - - parent = sc->parent; - - /* The separate, and distinct, cases are: - * 1. enum { ... } - * 2. enum : memtype { ... } - * 3. enum ident { ... } - * 4. enum ident : memtype { ... } - */ - - if (memtype) - { - memtype = memtype->semantic(loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (memtype->ty == Tenum) - { EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc); - if (!sym->memtype || !sym->members || !sym->symtab || sym->scope) - { // memtype is forward referenced, so try again later - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - printf("\tdeferring %s\n", toChars()); - return; - } - } -#if 0 // Decided to abandon this restriction for D 2.0 - if (!memtype->isintegral()) - { error("base type must be of integral type, not %s", memtype->toChars()); - memtype = Type::tint32; - } -#endif - } - - type = type->semantic(loc, sc); - if (isAnonymous()) - sce = sc; - else - { sce = sc->push(this); - sce->parent = this; - } - if (members->dim == 0) - error("enum %s must have at least one member", toChars()); - int first = 1; - Expression *elast = NULL; - for (int i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - Expression *e; - - if (!em) - /* The e->semantic(sce) can insert other symbols, such as - * template instances and function literals. - */ - continue; - - //printf(" Enum member '%s'\n",em->toChars()); - if (em->type) - em->type = em->type->semantic(em->loc, sce); - e = em->value; - if (e) - { - assert(e->dyncast() == DYNCAST_EXPRESSION); - e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); - if (memtype) - { - e = e->implicitCastTo(sce, memtype); - e = e->optimize(WANTvalue | WANTinterpret); - if (!isAnonymous()) - e = e->castTo(sce, type); - t = memtype; - } - else if (em->type) - { - e = e->implicitCastTo(sce, em->type); - e = e->optimize(WANTvalue | WANTinterpret); - assert(isAnonymous()); - t = e->type; - } - else - t = e->type; - } - else if (first) - { - if (memtype) - t = memtype; - else if (em->type) - t = em->type; - else - t = Type::tint32; - e = new IntegerExp(em->loc, 0, Type::tint32); - e = e->implicitCastTo(sce, t); - e = e->optimize(WANTvalue | WANTinterpret); - if (!isAnonymous()) - e = e->castTo(sce, type); - } - else - { - // Set value to (elast + 1). - // But first check that (elast != t.max) - assert(elast); - e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); - e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->toInteger()) - error("overflow of enum value %s", elast->toChars()); - - // Now set e to (elast + 1) - e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); - e = e->semantic(sce); - e = e->castTo(sce, elast->type); - e = e->optimize(WANTvalue | WANTinterpret); - } - elast = e; - em->value = e; - - // Add to symbol table only after evaluating 'value' - if (isAnonymous()) - { - /* Anonymous enum members get added to enclosing scope. - */ - for (Scope *scx = sce; scx; scx = scx->enclosing) - { - if (scx->scopesym) - { - if (!scx->scopesym->symtab) - scx->scopesym->symtab = new DsymbolTable(); - em->addMember(sce, scx->scopesym, 1); - break; - } - } - } - else - em->addMember(sc, this, 1); - - /* Compute .min, .max and .default values. - * If enum doesn't have a name, we can never identify the enum type, - * so there is no purpose for a .min, .max or .default - */ - if (!isAnonymous()) - { - if (first) - { defaultval = e; - minval = e; - maxval = e; - } - else - { Expression *ec; - - /* In order to work successfully with UDTs, - * build expressions to do the comparisons, - * and let the semantic analyzer and constant - * folder give us the result. - */ - - // Compute if(e < minval) - ec = new CmpExp(TOKlt, em->loc, e, minval); - ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); - if (ec->toInteger()) - minval = e; - - ec = new CmpExp(TOKgt, em->loc, e, maxval); - ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); - if (ec->toInteger()) - maxval = e; - } - } - first = 0; - } - //printf("defaultval = %lld\n", defaultval); - - //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); - if (sc != sce) - sce->pop(); - //members->print(); -} - -int EnumDeclaration::oneMember(Dsymbol **ps) -{ - if (isAnonymous()) - return Dsymbol::oneMembers(members, ps); - return Dsymbol::oneMember(ps); -} - -void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - buf->writestring("enum "); - if (ident) - { buf->writestring(ident->toChars()); - buf->writeByte(' '); - } - if (memtype) - { - buf->writestring(": "); - memtype->toCBuffer(buf, NULL, hgs); - } - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (i = 0; i < members->dim; i++) - { - EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); - if (!em) - continue; - //buf->writestring(" "); - em->toCBuffer(buf, hgs); - buf->writeByte(','); - buf->writenl(); - } - buf->writeByte('}'); - buf->writenl(); -} - -Type *EnumDeclaration::getType() -{ - return type; -} - -const char *EnumDeclaration::kind() -{ - return "enum"; -} - -int EnumDeclaration::isDeprecated() -{ - return isdeprecated; -} - -Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) - // Try one last time to resolve this enum - semantic(scope); - - if (!members || !symtab || scope) - { error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - Dsymbol *s = ScopeDsymbol::search(loc, ident, flags); - return s; -} - -/********************************* EnumMember ****************************/ - -EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type) - : Dsymbol(id) -{ - this->value = value; - this->type = type; - this->loc = loc; -} - -Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) -{ - Expression *e = NULL; - if (value) - e = value->syntaxCopy(); - - Type *t = NULL; - if (type) - t = type->syntaxCopy(); - - EnumMember *em; - if (s) - { em = (EnumMember *)s; - em->loc = loc; - em->value = e; - em->type = t; - } - else - em = new EnumMember(loc, ident, e, t); - return em; -} - -void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (value) - { - buf->writestring(" = "); - value->toCBuffer(buf, hgs); - } -} - -const char *EnumMember::kind() -{ - return "enum member"; -} - - + +// Copyright (c) 1999-2010 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 +#include + +#include "root.h" +#include "enum.h" +#include "mtype.h" +#include "scope.h" +#include "id.h" +#include "expression.h" +#include "module.h" +#include "declaration.h" + +/********************************* EnumDeclaration ****************************/ + +EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) + : ScopeDsymbol(id) +{ + this->loc = loc; + type = new TypeEnum(this); + this->memtype = memtype; + maxval = NULL; + minval = NULL; + defaultval = NULL; +#if IN_DMD + sinit = NULL; +#endif + isdeprecated = 0; + isdone = 0; +} + +Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) +{ + Type *t = NULL; + if (memtype) + t = memtype->syntaxCopy(); + + EnumDeclaration *ed; + if (s) + { ed = (EnumDeclaration *)s; + ed->memtype = t; + } + else + ed = new EnumDeclaration(loc, ident, t); + ScopeDsymbol::syntaxCopy(ed); + return ed; +} + +void EnumDeclaration::semantic0(Scope *sc) +{ + /* This function is a hack to get around a significant problem. + * The members of anonymous enums, like: + * enum { A, B, C } + * don't get installed into the symbol table until after they are + * semantically analyzed, yet they're supposed to go into the enclosing + * scope's table. Hence, when forward referenced, they come out as + * 'undefined'. The real fix is to add them in at addSymbol() time. + * But to get code to compile, we'll just do this quick hack at the moment + * to compile it if it doesn't depend on anything else. + */ + + if (isdone || !scope) + return; + if (!isAnonymous() || memtype) + return; + for (int i = 0; i < members->dim; i++) + { + EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); + if (em && (em->type || em->value)) + return; + } + + // Can do it + semantic(sc); +} + +void EnumDeclaration::semantic(Scope *sc) +{ + Type *t; + Scope *sce; + + //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); + //printf("EnumDeclaration::semantic() %s\n", toChars()); + if (!members) // enum ident; + return; + + if (!memtype && !isAnonymous()) + { // Set memtype if we can to reduce fwd reference errors + memtype = Type::tint32; // case 1) enum ident { ... } + } + + if (symtab) // if already done + { if (isdone || !scope) + return; // semantic() already completed + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + unsigned dprogress_save = Module::dprogress; + + if (sc->stc & STCdeprecated) + isdeprecated = 1; + + parent = sc->parent; + + /* The separate, and distinct, cases are: + * 1. enum { ... } + * 2. enum : memtype { ... } + * 3. enum ident { ... } + * 4. enum ident : memtype { ... } + */ + + if (memtype) + { + memtype = memtype->semantic(loc, sc); + + /* Check to see if memtype is forward referenced + */ + if (memtype->ty == Tenum) + { EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc); + if (!sym->memtype || !sym->members || !sym->symtab || sym->scope) + { // memtype is forward referenced, so try again later + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + Module::dprogress = dprogress_save; + //printf("\tdeferring %s\n", toChars()); + return; + } + } +#if 0 // Decided to abandon this restriction for D 2.0 + if (!memtype->isintegral()) + { error("base type must be of integral type, not %s", memtype->toChars()); + memtype = Type::tint32; + } +#endif + } + + isdone = 1; + Module::dprogress++; + + type = type->semantic(loc, sc); + if (isAnonymous()) + sce = sc; + else + { sce = sc->push(this); + sce->parent = this; + } + if (members->dim == 0) + error("enum %s must have at least one member", toChars()); + int first = 1; + Expression *elast = NULL; + for (int i = 0; i < members->dim; i++) + { + EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); + Expression *e; + + if (!em) + /* The e->semantic(sce) can insert other symbols, such as + * template instances and function literals. + */ + continue; + + //printf(" Enum member '%s'\n",em->toChars()); + if (em->type) + em->type = em->type->semantic(em->loc, sce); + e = em->value; + if (e) + { + assert(e->dyncast() == DYNCAST_EXPRESSION); + e = e->semantic(sce); + e = e->optimize(WANTvalue | WANTinterpret); + if (memtype) + { + e = e->implicitCastTo(sce, memtype); + e = e->optimize(WANTvalue | WANTinterpret); + if (!isAnonymous()) + e = e->castTo(sce, type); + t = memtype; + } + else if (em->type) + { + e = e->implicitCastTo(sce, em->type); + e = e->optimize(WANTvalue | WANTinterpret); + assert(isAnonymous()); + t = e->type; + } + else + t = e->type; + } + else if (first) + { + if (memtype) + t = memtype; + else if (em->type) + t = em->type; + else + t = Type::tint32; + e = new IntegerExp(em->loc, 0, Type::tint32); + e = e->implicitCastTo(sce, t); + e = e->optimize(WANTvalue | WANTinterpret); + if (!isAnonymous()) + e = e->castTo(sce, type); + } + else + { + // Set value to (elast + 1). + // But first check that (elast != t.max) + assert(elast); + e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); + e = e->semantic(sce); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->toInteger()) + error("overflow of enum value %s", elast->toChars()); + + // Now set e to (elast + 1) + e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); + e = e->semantic(sce); + e = e->castTo(sce, elast->type); + e = e->optimize(WANTvalue | WANTinterpret); + } + elast = e; + em->value = e; + + // Add to symbol table only after evaluating 'value' + if (isAnonymous()) + { + /* Anonymous enum members get added to enclosing scope. + */ + for (Scope *scx = sce; scx; scx = scx->enclosing) + { + if (scx->scopesym) + { + if (!scx->scopesym->symtab) + scx->scopesym->symtab = new DsymbolTable(); + em->addMember(sce, scx->scopesym, 1); + break; + } + } + } + else + em->addMember(sc, this, 1); + + /* Compute .min, .max and .default values. + * If enum doesn't have a name, we can never identify the enum type, + * so there is no purpose for a .min, .max or .default + */ + if (!isAnonymous()) + { + if (first) + { defaultval = e; + minval = e; + maxval = e; + } + else + { Expression *ec; + + /* In order to work successfully with UDTs, + * build expressions to do the comparisons, + * and let the semantic analyzer and constant + * folder give us the result. + */ + + // Compute if(e < minval) + ec = new CmpExp(TOKlt, em->loc, e, minval); + ec = ec->semantic(sce); + ec = ec->optimize(WANTvalue | WANTinterpret); + if (ec->toInteger()) + minval = e; + + ec = new CmpExp(TOKgt, em->loc, e, maxval); + ec = ec->semantic(sce); + ec = ec->optimize(WANTvalue | WANTinterpret); + if (ec->toInteger()) + maxval = e; + } + } + first = 0; + } + //printf("defaultval = %lld\n", defaultval); + + //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); + if (sc != sce) + sce->pop(); + //members->print(); +} + +int EnumDeclaration::oneMember(Dsymbol **ps) +{ + if (isAnonymous()) + return Dsymbol::oneMembers(members, ps); + return Dsymbol::oneMember(ps); +} + +void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + buf->writestring("enum "); + if (ident) + { buf->writestring(ident->toChars()); + buf->writeByte(' '); + } + if (memtype) + { + buf->writestring(": "); + memtype->toCBuffer(buf, NULL, hgs); + } + if (!members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (i = 0; i < members->dim; i++) + { + EnumMember *em = ((Dsymbol *)members->data[i])->isEnumMember(); + if (!em) + continue; + //buf->writestring(" "); + em->toCBuffer(buf, hgs); + buf->writeByte(','); + buf->writenl(); + } + buf->writeByte('}'); + buf->writenl(); +} + +Type *EnumDeclaration::getType() +{ + return type; +} + +const char *EnumDeclaration::kind() +{ + return "enum"; +} + +int EnumDeclaration::isDeprecated() +{ + return isdeprecated; +} + +Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); + if (scope) + // Try one last time to resolve this enum + semantic(scope); + + if (!members || !symtab || scope) + { error("is forward referenced when looking for '%s'", ident->toChars()); + //*(char*)0=0; + return NULL; + } + + Dsymbol *s = ScopeDsymbol::search(loc, ident, flags); + return s; +} + +/********************************* EnumMember ****************************/ + +EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type) + : Dsymbol(id) +{ + this->value = value; + this->type = type; + this->loc = loc; +} + +Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) +{ + Expression *e = NULL; + if (value) + e = value->syntaxCopy(); + + Type *t = NULL; + if (type) + t = type->syntaxCopy(); + + EnumMember *em; + if (s) + { em = (EnumMember *)s; + em->loc = loc; + em->value = e; + em->type = t; + } + else + em = new EnumMember(loc, ident, e, t); + return em; +} + +void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (type) + type->toCBuffer(buf, ident, hgs); + else + buf->writestring(ident->toChars()); + if (value) + { + buf->writestring(" = "); + value->toCBuffer(buf, hgs); + } +} + +const char *EnumMember::kind() +{ + return "enum member"; +} + + diff --git a/dmd2/enum.h b/dmd2/enum.h index 94b62ef0..70e69536 100644 --- a/dmd2/enum.h +++ b/dmd2/enum.h @@ -1,94 +1,99 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_ENUM_H -#define DMD_ENUM_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct Identifier; -struct Type; -struct Expression; -#ifdef _DH -struct HdrGenState; -#endif - - -struct EnumDeclaration : ScopeDsymbol -{ /* enum ident : memtype { ... } - */ - Type *type; // the TypeEnum - Type *memtype; // type of the members - -#if DMDV1 - dinteger_t maxval; - dinteger_t minval; - dinteger_t defaultval; // default initializer -#else - Expression *maxval; - Expression *minval; - Expression *defaultval; // default initializer -#endif - int isdeprecated; - - EnumDeclaration(Loc loc, Identifier *id, Type *memtype); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *getType(); - const char *kind(); -#if DMDV2 - Dsymbol *search(Loc, Identifier *ident, int flags); -#endif - int isDeprecated(); // is Dsymbol deprecated? - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumDeclaration *isEnumDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - - -struct EnumMember : Dsymbol -{ - Expression *value; - Type *type; - - EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); - Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - - void emitComment(Scope *sc); - void toDocBuffer(OutBuffer *buf); - - EnumMember *isEnumMember() { return this; } -}; - -#endif /* DMD_ENUM_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +#ifndef DMD_ENUM_H +#define DMD_ENUM_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +struct Identifier; +struct Type; +struct Expression; +#ifdef _DH +struct HdrGenState; +#endif + + +struct EnumDeclaration : ScopeDsymbol +{ /* enum ident : memtype { ... } + */ + Type *type; // the TypeEnum + Type *memtype; // type of the members + +#if DMDV1 + dinteger_t maxval; + dinteger_t minval; + dinteger_t defaultval; // default initializer +#else + Expression *maxval; + Expression *minval; + Expression *defaultval; // default initializer +#endif + int isdeprecated; + int isdone; // 0: not done + // 1: semantic() successfully completed + + EnumDeclaration(Loc loc, Identifier *id, Type *memtype); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic0(Scope *sc); + void semantic(Scope *sc); + int oneMember(Dsymbol **ps); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Type *getType(); + const char *kind(); +#if DMDV2 + Dsymbol *search(Loc, Identifier *ident, int flags); +#endif + int isDeprecated(); // is Dsymbol deprecated? + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + EnumDeclaration *isEnumDeclaration() { return this; } + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file + void toDebug(); + int cvMember(unsigned char *p); + + Symbol *sinit; + Symbol *toInitializer(); +#endif + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + + +struct EnumMember : Dsymbol +{ + Expression *value; + Type *type; + + EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); + Dsymbol *syntaxCopy(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); + void toDocBuffer(OutBuffer *buf); + + EnumMember *isEnumMember() { return this; } +}; + +#endif /* DMD_ENUM_H */ diff --git a/dmd2/expression.c b/dmd2/expression.c index 899a855a..730677c1 100644 --- a/dmd2/expression.c +++ b/dmd2/expression.c @@ -1,10261 +1,11241 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include -#include -#if _MSC_VER -#include -#else -#if IN_DMD -#include -#endif -#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" -#if IN_DMD -#include "port.h" -#endif -#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" - -#if IN_DMD -Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); -#endif -Expression *expandVar(int result, VarDeclaration *v); - -#define LOGSEMANTIC 0 - -/********************************** - * Set operator precedence for each operator. - */ - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_unary, - PREC_primary, -}; - -enum PREC precedence[TOKMAX]; - -void initPrecedence() -{ - precedence[TOKdotvar] = PREC_primary; - precedence[TOKimport] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; -#if DMDV2 - precedence[TOKdefault] = PREC_primary; -#endif - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdot] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtobool] = PREC_add; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKcast] = PREC_unary; - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - -#if 0 - precedence[TOKequal] = PREC_equal; - precedence[TOKnotequal] = PREC_equal; - precedence[TOKidentity] = PREC_equal; - precedence[TOKnotidentity] = PREC_equal; -#else - /* Note that we changed precedence, so that < and != have the same - * precedence. This change is in the parser, too. - */ - precedence[TOKequal] = PREC_rel; - precedence[TOKnotequal] = PREC_rel; - precedence[TOKidentity] = PREC_rel; - precedence[TOKnotidentity] = PREC_rel; -#endif - - precedence[TOKand] = PREC_and; - - precedence[TOKxor] = PREC_xor; - - precedence[TOKor] = PREC_or; - - precedence[TOKandand] = PREC_andand; - - precedence[TOKoror] = PREC_oror; - - precedence[TOKquestion] = PREC_cond; - - precedence[TOKassign] = PREC_assign; - precedence[TOKconstruct] = PREC_assign; - precedence[TOKblit] = PREC_assign; - precedence[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; -} - -/************************************************************* - * 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->nestedrefs = 1; - - e1 = new VarExp(loc, f->vthis); - } - } - 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()); - } - } - 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 (parent) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - parent = ti->parent; - else - break; - } - - fd = 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"); - } - - } - else if (e->op == TOKdottd) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - return e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -void arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - exps->data[i] = (void *)e; - } - } -} - - -/****************************** - * 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]; - } - } - } -} - -/**************************************** - * Preprocess arguments to function. - */ - -void preFunctionArguments(Loc loc, Scope *sc, Expressions *exps) -{ - if (exps) - { - expandTuples(exps); - - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (Expression *)exps->data[i]; - - if (!arg->type) - { -#ifdef DEBUG - if (!global.gag) - printf("1: \n"); -#endif - arg->error("%s is not an expression", arg->toChars()); - arg = new IntegerExp(arg->loc, 0, Type::tint32); - } - - arg = resolveProperties(sc, arg); - exps->data[i] = (void *) arg; - - //arg->rvalue(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - exps->data[i] = (void *) 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)); - 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 - * 5. call copy constructor for struct value arguments - */ - -void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) -{ - unsigned n; - - //printf("functionArguments()\n"); - assert(arguments); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Argument::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()); - - 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 = (Expression *)arguments->data[i]; - else - arg = NULL; - Type *tb; - - if (i < nparams) - { - Argument *p = Argument::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); - break; - } - arg = p->defaultArg; -#if DMDV2 - if (arg->op == TOKdefault) - { DefaultInitExp *de = (DefaultInitExp *)arg; - arg = de->resolve(loc, sc); - } - else -#endif - arg = arg->copy(); - arguments->push(arg); - nargs++; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - if (arg->implicitConvTo(p->type)) - { - if (nargs != nparams) - error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - 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->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 = (Expression *)arguments->data[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 DMDV2 - ae->op = TOKconstruct; -#endif - 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()); - arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); - } - } - if (p->storageClass & STCref) - { - arg = arg->toLvalue(sc, arg); - } - else if (p->storageClass & STCout) - { - arg = arg->modifiableLvalue(sc, arg); - } - - tb = arg->type->toBasetype(); -// LDC we don't want this! -#if !IN_LLVM - // Convert static arrays to pointers - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } -#endif -#if DMDV2 - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) - { - arg = callCpCtor(loc, sc, arg); - } -#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)) - { - /* Function literals can only appear once, so if this - * appearance was scoped, there cannot be any others. - */ - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - 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 (arg->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)arg; - 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 - 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); - arg->type = ta; - } - else - arg = arg->castTo(sc, ta); - } -#if DMDV2 - if (tb->ty == Tstruct) - { - arg = callCpCtor(loc, sc, arg); - } - - // Give error for overloaded function addresses - 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) - { - Expression *e; - - 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) -{ - //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr || - /* Despite precedence, we don't allow aop] == 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) -{ - unsigned errors = global.errors; - global.gag++; - Expression *e = semantic(sc); - global.gag--; - if (errors != global.errors) - { - global.errors = errors; - e = NULL; - } - 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, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Expression::warning(const char *format, ...) -{ - if (global.params.warnings && !global.gag) - { - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); - } -} - -void Expression::rvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - { error("expression %s is void and has no value", toChars()); -#if 0 - dump(0); - halt(); -#endif - type = Type::terror; - } -} - -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 0; -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 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; -#endif -} - -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::checkScalar() -{ - if (!type->isscalar()) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); - rvalue(); -} - -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(); - } - rvalue(); - return this; -} - -Expression *Expression::checkArithmetic() -{ - if (!type->isintegral() && !type->isfloating()) - { error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - rvalue(); - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -#if DMDV2 -void Expression::checkPurity(Scope *sc, FuncDeclaration *f) -{ -#if 1 - if (sc->func) - { - FuncDeclaration *outerfunc=sc->func; - while (outerfunc->toParent2() && outerfunc->toParent2()->isFuncDeclaration()) - { - outerfunc = outerfunc->toParent2()->isFuncDeclaration(); - } - if (outerfunc->isPure() && !sc->intypeof && (!f->isNested() && !f->isPure())) - error("pure function '%s' cannot call impure function '%s'\n", - sc->func->toChars(), f->toChars()); - } -#else - 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 -} -#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; - - //printf("Expression::addressOf()\n"); - e = toLvalue(sc, NULL); - e = new AddrExp(loc, e); - e->type = type->pointerTo(); - return e; -} - -/****************************** - * If this is a reference, dereference it. - */ - -Expression *Expression::deref() -{ - //printf("Expression::deref()\n"); - if (type->ty == Treference) - { Expression *e; - - 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 (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - 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); - 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->toHeadMutable()->equals(ne->type->toHeadMutable())) && - 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 (real_t)(d_uns64)value; - else - return (real_t)(d_int64)value; -} - -real_t IntegerExp::toImaginary() -{ - return (real_t) 0; -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - return result ? value != 0 : value == 0; -} - -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: - if (v == '\'') - buf->writestring("'\\''"); - else if (isprint(v) && v != '\\') - buf->printf("'%c'", (int)v); - else - buf->printf("'\\x%02x'", (int)v); - 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 - 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) -{ -} - -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 : 0; -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? 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) -{ -//#if 1 -// return (Port::isNan(x1) && Port::isNan(x2)) || -//#elif __APPLE__ -#if __APPLE__ - return (__inline_isnan(x1) && __inline_isnan(x2)) || -#else - return // special case nans - (isnan(x1) && isnan(x2)) || -#endif - // and zero, in order to distinguish +0 from -0 - (x1 == 0 && x2 == 0 && 1./x1 == 1./x2) || - // otherwise just compare - (x1 != 0. && x1 == x2); -} - -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - 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 - buf->printf("%La", value); // ensure exact duplication - - 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 1 -// if (Port::isNan(value)) -//#elif __APPLE__ -#if __APPLE__ - if (__inline_isnan(value)) -#else - if (isnan(value)) -#endif - 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->toHeadMutable()->equals(ne->type->toHeadMutable())) && - 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) - { -#if DMDV2 - /* Disallow shadowing - */ - // First find the scope of the with - Scope *scwith = sc; - while (scwith->scopesym != scopesym) - { scwith = scwith->enclosing; - assert(scwith); - } - // Look at enclosing scopes for symbols with the same name, - // in the same function - for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars()); - } - } -#endif - 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 f is really a function template, - * then replace f with the function template declaration. - */ - 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) - { - TemplateDeclaration *tempdecl = ti->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; - } - } - // Haven't done overload resolution yet, so pass 1 - e = new DsymbolExp(loc, s, 1); - } - return e->semantic(sc); - } - error("undefined identifier %s", ident->toChars()); - type = Type::terror; - return this; -} - -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, int hasOverloads) - : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) -{ - this->s = s; - this->hasOverloads = hasOverloads; -} - -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; - OverloadSet *o; - Declaration *d; - 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); - s = s->toAlias(); - //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (!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; - 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) - { type = v->type; - if (!v->type) - { error("forward reference of %s %s", v->kind(), v->toChars()); - type = Type::terror; - } - } - 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->type->deco) - { - error("forward reference to %s", toChars()); - } - return new VarExp(loc, f, hasOverloads); - } - o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } - 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 this; - } - 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) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !global.errors) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->inst->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; - } - -Lerr: - error("%s '%s' is not a variable", s->kind(), s->toChars()); - type = Type::terror; - return this; -} - -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) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - int nested = 0; - -#if LOGSEMANTIC - printf("ThisExp::semantic()\n"); -#endif - if (type) - { //assert(global.errors || var); - return this; - } - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 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; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); // fd is the uplevel function with the 'this' variable - 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()); - type = Type::terror; - return this; -} - -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) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - ClassDeclaration *cd; - Dsymbol *s; - -#if LOGSEMANTIC - printf("SuperExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (sc->intypeof) - { - // Find enclosing class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - - if (!s) - { - error("%s is not in a class scope", toChars()); - goto Lerr; - } - 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; - } - } - } - - fdthis = sc->parent->isFuncDeclaration(); - fd = hasThis(sc); - 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; - } - - 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"); - type = Type::tint32; - return this; -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; -} - -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; -} - -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; -} - -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; -} - -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; -} - -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - -int StringExp::equals(Object *o) -{ - //printf("StringExp::equals('%s')\n", o->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); - break; - } - 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)); - type = new TypeDArray(Type::tdchar->invariantOf()); - committed = 1; - break; - - case 'w': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - break; - } - 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)); - type = new TypeDArray(Type::twchar->invariantOf()); - committed = 1; - break; - - case 'c': - committed = 1; - default: - //type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::tchar->invariantOf()); - break; - } - type = type->semantic(loc, sc); - //type = type->invariantOf(); - //printf("type = %s\n", type->toChars()); - } - 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); - break; - } - 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); - break; - } - else - result++; - } - break; - - case 4: - result = len; - break; - - default: - assert(0); - } - return result; -} - -/**************************************** - * 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) -{ - // 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; - - if (len1 == len2) - { - switch (sz) - { - case 1: - return strcmp((char *)string, (char *)se2->string); - - 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; -} - -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('"'); - 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; - } - } - 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->writeByte(m); - buf->printf("%d_", qlen); - for (size_t i = 0; i < qlen; i++) - buf->printf("%02x", q[i]); -} - -/************************ ArrayLiteralExp ************************************/ - -// [ e1, e2, e3, ... ] - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - this->elements = elements; -} - -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 (int i = 0; i < elements->dim; i++) - { e = (Expression *)elements->data[i]; - e = e->semantic(sc); - assert(e->type); - elements->data[i] = (void *)e; - } - expandTuples(elements); - for (int 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); - return this; -} - -int ArrayLiteralExp::checkSideEffect(int flag) -{ int f = 0; - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - f |= e->checkSideEffect(2); - } - 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 - -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%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = (Expression *)elements->data[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; -} - -Expression *AssocArrayLiteralExp::syntaxCopy() -{ - return new AssocArrayLiteralExp(loc, - arraySyntaxCopy(keys), arraySyntaxCopy(values)); -} - -Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ Expression *e; - Type *tkey = NULL; - Type *tvalue = NULL; - -#if LOGSEMANTIC - printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - // Run semantic() on each element - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - key = key->semantic(sc); - value = value->semantic(sc); - - keys->data[i] = (void *)key; - values->data[i] = (void *)value; - } - 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); - keys->setDim(0); - values->setDim(0); - } - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = (Expression *)keys->data[i]; - Expression *value = (Expression *)values->data[i]; - - if (!key->type) - error("%s has no value", key->toChars()); - if (!value->type) - error("%s has no value", value->toChars()); - key = resolveProperties(sc, key); - value = resolveProperties(sc, value); - - if (!tkey) - tkey = key->type; - else - key = key->implicitCastTo(sc, tkey); - keys->data[i] = (void *)key; - - if (!tvalue) - tvalue = value->type; - else - value = value->implicitCastTo(sc, tvalue); - values->data[i] = (void *)value; - } - - if (!tkey) - tkey = Type::tvoid; - if (!tvalue) - tvalue = Type::tvoid; - 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->checkSideEffect(2); - f |= value->checkSideEffect(2); - } - 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%zu", 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) - : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) -{ - this->sd = sd; - this->elements = elements; -#if IN_DMD - this->sym = NULL; -#endif - this->soffset = 0; - this->fillHoles = 1; -} - -Expression *StructLiteralExp::syntaxCopy() -{ - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements)); -} - -Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - int nfields = sd->fields.dim - sd->isnested; - -#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()); - e = resolveProperties(sc, e); - if (i >= nfields) - { error("more initializers than fields of %s", sd->toChars()); - return new ErrorExp(); - } - 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 < nfields; i++) - { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - assert(!v->isThisDeclaration()); - - if (v->offset < offset) - { e = NULL; - sd->hasUnions = 1; - } - else - { - if (v->init) - { e = v->init->toExpression(); - if (!e) - error("cannot make expression out of initializer for %s", v->toChars()); - } - else - { e = v->type->defaultInit(); - e->loc = loc; - } - offset = v->offset + v->type->size(); - } - elements->push(e); - } - - type = 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) - { - 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 - -/* -Removed in LDC. See declaration. -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->checkSideEffect(2); - } - 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%zu", 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::rvalue() -{ - error("type %s has no value", toChars()); -} - -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 && !global.errors) - { Dsymbol *s; - if (!ti->semanticRun) - ti->semantic(sc); - 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()); - } - else - { - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - //printf("\tparent = '%s'\n", sds->parent->toChars()); - sds->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 - { - 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()); -} - -void TemplateExp::rvalue() -{ - error("template %s has no value", toChars()); -} - -/********************** 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) -{ int i; - 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()); - type = newtype->semantic(loc, sc); - } - } - 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); - preFunctionArguments(loc, sc, newargs); - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (thisexp && tb->ty != Tclass) - error("e.new is only for allocating nested classes, not %s", tb->toChars()); - - 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()); - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (int i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[i])->isFuncDeclaration(); - if (fd && fd->isAbstract()) - error("function %s is abstract", fd->toChars()); - } - } - 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()); - break; - } - 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()); - } -#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()); - break; - } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } -#if 1 - else if (thisexp) - error("e.new is only for allocating nested classes"); - 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()); - break; - } - } - } -#else - else if (fdn) - { /* The nested class cd is nested inside a function, - * we'll let getEthis() look for errors. - */ - //printf("nested class %s is nested inside function %s, we're in %s\n", cd->toChars(), fdn->toChars(), sc->func->toChars()); - if (thisexp) - // Because thisexp cannot be a function frame pointer - error("e.new is only for allocating nested classes"); - } -#endif - else - assert(0); - } - else if (thisexp) - error("e.new is only for allocating nested classes"); - - FuncDeclaration *f = NULL; - if (cd->ctor) - f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); - if (f) - { - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - cd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - } - else - { - if (arguments && arguments->dim) - error("no constructor for %s", cd->toChars()); - } - - 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); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); - } - else - { - if (newargs && newargs->dim) - error("no allocator for %s", cd->toChars()); - } - } - else if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - TypeFunction *tf; - - FuncDeclaration *f = NULL; - if (sd->ctor) - f = resolveFuncCall(sc, loc, sd->ctor, NULL, NULL, arguments, 0); - if (f) - { - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - sd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; -// type = tf->next; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - } - else - { - if (arguments && arguments->dim) - error("no constructor for %s", sd->toChars()); - } - - - if (sd->aggNew) - { - // Prepend the uint size argument to newargs[] - Expression *e = new IntegerExp(loc, sd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = sd->aggNew->overloadResolve(loc, NULL, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - functionArguments(loc, sc, tf, newargs); -#if 0 - e = new VarExp(loc, f); - e = new CallExp(loc, e, newargs); - e = e->semantic(sc); - e->type = type->pointerTo(); - return e; -#endif - } - else - { - if (newargs && newargs->dim) - error("no allocator for %s", sd->toChars()); - } - - 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"); - arguments->dim = i; - break; - } - - Expression *arg = (Expression *)arguments->data[i]; - arg = resolveProperties(sc, arg); - arg = arg->implicitCastTo(sc, Type::tsize_t); - arg = arg->optimize(WANTvalue); - if (arg->op == TOKint64 && (long long)arg->toInteger() < 0) - error("negative array index %s", arg->toChars()); - arguments->data[i] = (void *) arg; - tb = ((TypeDArray *)tb)->next->toBasetype(); - } - } - else if (tb->isscalar()) - { - if (arguments && arguments->dim) - error("no constructor for %s", type->toChars()); - - type = type->pointerTo(); - } - else - { - error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - type = type->pointerTo(); - } - -//printf("NewExp: '%s'\n", toChars()); -//printf("NewExp:type '%s'\n", type->toChars()); - - return this; -} - -int NewExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int NewExp::canThrow() -{ - return 1; -} -#endif - -void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - 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) -{ int i; - - 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, int hasOverloads) - : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) -{ - 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()) - error("escaping reference to local variable %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, int hasOverloads) - : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) -{ - //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); - //if (strcmp(var->ident->toChars(), "func") == 0) halt(); - this->type = var->type; -} - -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - var == ne->var)) - return 1; - return 0; -} - -Expression *VarExp::semantic(Scope *sc) -{ FuncLiteralDeclaration *fd; - -#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 - } - - /* 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 0 - if ((v->isConst() || v->isInvariant()) && - type->toBasetype()->ty != Tsarray && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - //ei->exp->implicitCastTo(sc, type)->print(); - return ei->exp->implicitCastTo(sc, type); - } - } -#endif - v->checkNestedReference(sc, loc); -#if DMDV2 -#if 1 - if (sc->func) - { - /* Determine if sc->func is pure or if any function that - * encloses it is also pure. - */ - bool hasPureParent = false; - for (FuncDeclaration *outerfunc = sc->func; outerfunc;) - { - if (outerfunc->isPure()) - { - hasPureParent = true; - break; - } - Dsymbol *parent = outerfunc->toParent2(); - if (!parent) - break; - outerfunc = parent->isFuncDeclaration(); - } - - /* If ANY of its enclosing functions are pure, - * it cannot do anything impure. - * If it is pure, it cannot access any mutable variables other - * than those inside itself - */ - if (hasPureParent && !sc->intypeof && v->isDataseg() && - !v->isInvariant()) - { - error("pure function '%s' cannot access mutable static data '%s'", - sc->func->toChars(), v->toChars()); - } - else if (sc->func->isPure() && sc->parent != v->parent && - !sc->intypeof && !v->isInvariant() && - !(v->storage_class & STCmanifest)) - { - error("pure nested function '%s' cannot access mutable data '%s'", - sc->func->toChars(), v->toChars()); - if (v->isEnumDeclaration()) - error("enum"); - } - } -#else - if (sc->func && sc->func->isPure() && !sc->intypeof) - { - if (v->isDataseg() && !v->isInvariant()) - error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); - } -#endif -#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->isAuto() || v->isScope()) && !v->noauto) - error("escaping reference to scope local %s", v->toChars()); - else if (v->storage_class & STCvariadic) - error("escaping reference to variadic parameter %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 (type && type->toBasetype()->ty == Tsarray) - error("cannot change reference to static array '%s'", var->toChars()); - - var->checkModify(loc, sc, type); - - // 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 = (Object *)tup->objects->data[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) -{ TupleExp *ne; - - if (this == o) - return 1; - if (((Expression *)o)->op == TOKtuple) - { - TupleExp *te = (TupleExp *)o; - if (exps->dim != te->exps->dim) - return 0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (Expression *)exps->data[i]; - Expression *e2 = (Expression *)te->exps->data[i]; - - if (!e1->equals(e2)) - return 0; - } - return 1; - } - return 0; -} - -Expression *TupleExp::syntaxCopy() -{ - return new TupleExp(loc, arraySyntaxCopy(exps)); -} - -Expression *TupleExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("+TupleExp::semantic(%s)\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each argument - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - e->type = Type::terror; - } - exps->data[i] = (void *)e; - } - - expandTuples(exps); - if (0 && exps->dim == 1) - { - return (Expression *)exps->data[0]; - } - type = new TypeTuple(exps); - type = type->semantic(loc, sc); - //printf("-TupleExp::semantic(%s)\n", toChars()); - return this; -} - -void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("tuple("); - argsToCBuffer(buf, exps, hgs); - buf->writeByte(')'); -} - -int TupleExp::checkSideEffect(int flag) -{ int f = 0; - - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - f |= e->checkSideEffect(2); - } - if (flag == 0 && f == 0) - Expression::checkSideEffect(0); - return f; -} - -#if DMDV2 -int TupleExp::canThrow() -{ - return arrayExpressionCanThrow(exps); -} -#endif - -void TupleExp::checkEscape() -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - e->checkEscape(); - } -} - -/******************************** FuncExp *********************************/ - -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type) - { - fd->semantic(sc); - //fd->parent = sc->parent; - if (global.errors) - { - } - else - { - fd->semantic2(sc); - if (!global.errors || - // need to infer return type - (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) - { - fd->semantic3(sc); - - if (!global.errors && global.params.useInline) - fd->inlineScan(); - } - } - - // need to infer return type - if (global.errors && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) - ((TypeFunction *)fd->type)->next = Type::terror; - - // Type is a "delegate to" or "pointer to" the function literal - if (fd->isNested()) - { - type = new TypeDelegate(fd->type); - type = type->semantic(loc, sc); - } - else - { - type = fd->type->pointerTo(); - } - fd->tookAddressOf++; - } - return this; -} - -char *FuncExp::toChars() -{ - return fd->toChars(); -} - -void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - fd->toCBuffer(buf, hgs); - //buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - /* This is here to support extern(linkage) declaration, - * where the extern(linkage) winds up being an AttribDeclaration - * wrapper. - */ - Dsymbol *s = declaration; - - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad) - { - if (ad->decl && ad->decl->dim == 1) - s = (Dsymbol *)ad->decl->data[0]; - } - - if (s->isVarDeclaration()) - { // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - declaration->semantic(sc); - s->parent = sc->parent; - } - - //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); - // Insert into both local scope and function scope. - // Must be unique in both. - if (s->ident) - { - if (!sc->insert(s)) - error("declaration %s is already defined", s->toPrettyChars()); - else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); - if (s->isFuncDeclaration() && - !sc->func->localsymtab->insert(s)) - error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - declaration->semantic(sc); - s->parent = sc->parent; - } - if (!global.errors) - { - declaration->semantic2(sc); - if (!global.errors) - { - declaration->semantic3(sc); - - if (!global.errors && global.params.useInline) - declaration->inlineScan(); - } - } - - type = Type::tvoid; - return this; -} - -int DeclarationExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int DeclarationExp::canThrow() -{ - VarDeclaration *v = declaration->isVarDeclaration(); - if (v && v->init) - { ExpInitializer *ie = v->init->isExpInitializer(); - return ie && ie->exp->canThrow(); - } - return 0; -} -#endif - -void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - declaration->toCBuffer(buf, hgs); -} - - -/************************ TypeidExp ************************************/ - -/* - * typeid(int) - */ - -TypeidExp::TypeidExp(Loc loc, Type *typeidType) - : Expression(loc, TOKtypeid, sizeof(TypeidExp)) -{ - this->typeidType = typeidType; -} - - -Expression *TypeidExp::syntaxCopy() -{ - return new TypeidExp(loc, typeidType->syntaxCopy()); -} - - -Expression *TypeidExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeidExp::semantic()\n"); -#endif - typeidType = typeidType->semantic(loc, sc); - e = typeidType->getTypeInfo(sc); - if (e->loc.linnum == 0) - e->loc = loc; // so there's at least some line number info - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - typeidType->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); -} - -/************************ TraitsExp ************************************/ -#if DMDV2 -/* - * __traits(identifier, args...) - */ - -TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) - : Expression(loc, TOKtraits, sizeof(TraitsExp)) -{ - this->ident = ident; - this->args = args; -} - - -Expression *TraitsExp::syntaxCopy() -{ - return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); -} - - -void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__traits("); - buf->writestring(ident->toChars()); - if (args) - { - for (int i = 0; i < args->dim; i++) - { - buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - } - buf->writeByte(')'); -} -#endif - -/************************************************************/ - -HaltExp::HaltExp(Loc loc) - : Expression(loc, TOKhalt, sizeof(HaltExp)) -{ -} - -Expression *HaltExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("HaltExp::semantic()\n"); -#endif - type = Type::tvoid; - return this; -} - -int HaltExp::checkSideEffect(int flag) -{ - return 1; -} - -void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("halt"); -} - -/************************************************************/ - -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2, TemplateParameters *parameters) - : Expression(loc, TOKis, sizeof(IsExp)) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; - this->tok2 = tok2; - this->parameters = parameters; -} - -Expression *IsExp::syntaxCopy() -{ - // This section is identical to that in TemplateDeclaration::syntaxCopy() - TemplateParameters *p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (int i = 0; i < p->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - p->data[i] = (void *)tp->syntaxCopy(); - } - } - - return new IsExp(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL, - tok2, - p); -} - -Expression *IsExp::semantic(Scope *sc) -{ Type *tded; - - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - - //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & SCOPEstaticif)) - error("can only declare type aliases within static if conditionals"); - - Type *t = targ->trySemantic(loc, sc); - if (!t) - goto Lno; // errors, so condition is false - targ = t; - if (tok2 != TOKreserved) - { - switch (tok2) - { - case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; - - case TOKstruct: - if (targ->ty != Tstruct) - goto Lno; - if (((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKunion: - if (targ->ty != Tstruct) - goto Lno; - if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKclass: - if (targ->ty != Tclass) - goto Lno; - if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKinterface: - if (targ->ty != Tclass) - goto Lno; - if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; -#if DMDV2 - case TOKconst: - if (!targ->isConst()) - goto Lno; - tded = targ; - break; - - case TOKinvariant: - case TOKimmutable: - if (!targ->isInvariant()) - goto Lno; - tded = targ; - break; - - case TOKshared: - if (!targ->isShared()) - goto Lno; - tded = targ; - break; -#endif - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Arguments *args = new Arguments; - args->reserve(cd->baseclasses.dim); - for (size_t i = 0; i < cd->baseclasses.dim; i++) - { BaseClass *b = (BaseClass *)cd->baseclasses.data[i]; - args->push(new Argument(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = ((TypeDelegate *)targ)->next; // the underlying function type - break; - - case TOKfunction: - { - if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Arguments *params = ((TypeFunction *)tded)->parameters; - size_t dim = Argument::dim(params); - Arguments *args = new Arguments; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(params, i); - assert(arg && arg->type); - args->push(new Argument(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = ((TypeFunction *)targ)->next; - else if (targ->ty == Tdelegate) - { tded = ((TypeDelegate *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else if (targ->ty == Tpointer && - ((TypePointer *)targ)->next->ty == Tfunction) - { tded = ((TypePointer *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else - goto Lno; - break; - - default: - assert(0); - } - goto Lyes; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - assert(parameters && parameters->dim); - - Objects dedtypes; - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - m = targ->deduceType(NULL, tspec, parameters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - { - goto Lno; - } - else - { - tded = (Type *)dedtypes.data[0]; - if (!tded) - tded = targ; - - Objects tiargs; - tiargs.setDim(1); - tiargs.data[0] = (void *)targ; - - /* Declare trailing parameters - */ - for (int i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Declaration *s = NULL; - - m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); - if (m == MATCHnomatch) - goto Lno; - s->semantic(sc); - if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); -#if 0 - Object *o = (Object *)dedtypes.data[i]; - Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); -#endif - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } - - goto Lyes; - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - tded = targ; - goto Lyes; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - * is(targ == tspec) - * is(targ : tspec) - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - goto Lyes; - else - goto Lno; - } - else /* == */ - { if (targ->equals(tspec)) - goto Lyes; - else - goto Lno; - } - } - -Lyes: - if (id) - { - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } -//printf("Lyes\n"); - return new IntegerExp(loc, 1, Type::tbool); - -Lno: -//printf("Lno\n"); - return new IntegerExp(loc, 0, Type::tbool); -} - -void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("is("); - targ->toCBuffer(buf, id, hgs); - if (tok2 != TOKreserved) - { - buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); - } - else if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } -#if DMDV2 - if (parameters) - { // First parameter is already output, so start with second - for (int i = 1; i < parameters->dim; i++) - { - buf->writeByte(','); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ UnaExp *e; - - e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -#if DMDV2 -int UnaExp::canThrow() -{ - return e1->canThrow(); -} -#endif - -void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : Expression(loc, op, size) -{ - this->e1 = e1; - this->e2 = e2; -} - -Expression *BinExp::syntaxCopy() -{ BinExp *e; - - e = (BinExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - e->e2 = e->e2->syntaxCopy(); - return e; -} - -Expression *BinExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("BinExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); - if (!e1->type && - !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 - { - error("%s has no value", e1->toChars()); - e1->type = Type::terror; - } - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - return this; -} - -Expression *BinExp::semanticp(Scope *sc) -{ - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e2 = resolveProperties(sc, e2); - return this; -} - -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ - -Expression *BinExp::commonSemanticAssign(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - error("operator not allowed on bool expression %s", toChars()); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass && e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - } - return this; -} - -Expression *BinExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] op= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - e2 = e2->implicitCastTo(sc, type); - } - - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - return this; -} - -int BinExp::checkSideEffect(int flag) -{ - if (op == TOKplusplus || - op == TOKminusminus || - op == TOKassign || - op == TOKconstruct || - op == TOKblit || - op == TOKaddass || - op == TOKminass || - op == TOKcatass || - op == TOKmulass || - op == TOKdivass || - op == TOKmodass || - op == TOKshlass || - op == TOKshrass || - op == TOKushrass || - op == TOKandass || - op == TOKorass || - op == TOKxorass || - op == TOKin || - op == TOKremove) - return 1; - return Expression::checkSideEffect(flag); -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -#if DMDV2 -int BinExp::canThrow() -{ - return e1->canThrow() || e2->canThrow(); -} -#endif - -void BinExp::incompatibleTypes() -{ - error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); -} - -/************************************************************/ - -CompileExp::CompileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) -{ -} - -Expression *CompileExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CompileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); - if (e1->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", e1->toChars()); - type = Type::terror; - return this; - } - StringExp *se = (StringExp *)e1; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - //printf("p.loc.linnum = %d\n", p.loc.linnum); - Expression *e = p.parseExpression(); - if (p.token.value != TOKeof) - error("incomplete mixin expression (%s)", se->toChars()); - return e->semantic(sc); -} - -void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -FileExp::FileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(FileExp), e) -{ -} - -Expression *FileExp::semantic(Scope *sc) -{ char *name; - StringExp *se; - -#if LOGSEMANTIC - printf("FileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue); - if (e1->op != TOKstring) - { error("file name argument must be a string, not (%s)", e1->toChars()); - goto Lerror; - } - se = (StringExp *)e1; - se = se->toUTF8(sc); - name = (char *)se->string; - - if (!global.params.fileImppath) - { error("need -Jpath switch to import text file %s", name); - goto Lerror; - } - - if (name != FileName::name(name)) - { error("use -Jpath switch to provide path for filename %s", name); - goto Lerror; - } - - name = FileName::searchPath(global.filePath, name, 0); - if (!name) - { error("file %s cannot be found, check -Jpath", se->toChars()); - goto Lerror; - } - - if (global.params.verbose) - printf("file %s\t(%s)\n", (char *)se->string, name); - - { File f(name); - if (f.read()) - { error("cannot read file %s", f.toChars()); - goto Lerror; - } - else - { - f.ref = 1; - se = new StringExp(loc, f.buffer, f.len); - } - } - Lret: - return se->semantic(sc); - - Lerror: - se = new StringExp(loc, (char *)""); - goto Lret; -} - -void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("import("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) - : UnaExp(loc, TOKassert, sizeof(AssertExp), e) -{ - this->msg = msg; -} - -Expression *AssertExp::syntaxCopy() -{ - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; -} - -Expression *AssertExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssertExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - // BUG: see if we can do compile time elimination of the Assert - e1 = e1->optimize(WANTvalue); - e1 = e1->checkToBoolean(); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf()); - msg = msg->optimize(WANTvalue); - } - if (e1->isBool(FALSE)) - { - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 4; - - if (!global.params.useAssert) - { Expression *e = new HaltExp(loc); - e = e->semantic(sc); - return e; - } - } - type = Type::tvoid; - return this; -} - -int AssertExp::checkSideEffect(int flag) -{ - return 1; -} - -#if DMDV2 -int AssertExp::canThrow() -{ - /* assert()s are non-recoverable errors, so functions that - * use them can be considered "nothrow" - */ - return 0; //(global.params.useAssert != 0); -} -#endif - -void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("assert("); - expToCBuffer(buf, hgs, e1, PREC_assign); - if (msg) - { - buf->writeByte(','); - expToCBuffer(buf, hgs, msg, PREC_assign); - } - buf->writeByte(')'); -} - -/************************************************************/ - -DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) - : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) -{ - this->ident = ident; -} - -Expression *DotIdExp::semantic(Scope *sc) -{ Expression *e; - Expression *eleft; - Expression *eright; - -#if LOGSEMANTIC - printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); -#endif - -//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } - -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - - /* Special case: rewrite this.id and super.id - * to be classtype.id and baseclasstype.id - * if we have no this pointer. - */ - if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) - { ClassDeclaration *cd; - StructDeclaration *sd; - AggregateDeclaration *ad; - - ad = sc->getStructClassScope(); - if (ad) - { - cd = ad->isClassDeclaration(); - if (cd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = typeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { - e1 = resolveProperties(sc, e1); - eleft = NULL; - eright = e1; - } -#if DMDV2 - if (e1->op == TOKtuple && ident == Id::offsetof) - { /* 'distribute' the .offsetof to each of the tuple elements. - */ - TupleExp *te = (TupleExp *)e1; - Expressions *exps = new Expressions(); - exps->setDim(te->exps->dim); - for (int i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)te->exps->data[i]; - e = e->semantic(sc); - e = new DotIdExp(e->loc, e, Id::offsetof); - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - if (e1->op == TOKdottd) - { - error("template %s does not have property %s", e1->toChars(), ident->toChars()); - return e1; - } - - if (!e1->type) - { - error("expression %s does not have property %s", e1->toChars(), ident->toChars()); - return e1; - } - - Type *t1b = e1->type->toBasetype(); - - if (eright->op == TOKimport) // also used for template alias's - { - ScopeExp *ie = (ScopeExp *)eright; - - /* Disable access to another module's private imports. - * The check for 'is sds our current module' is because - * the current module should have access to its own imports. - */ - Dsymbol *s = ie->sds->search(loc, ident, - (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); - if (s) - { - s = s->toAlias(); - checkDeprecated(sc, s); - - EnumMember *em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - type = Type::tint32; - return this; - } - type = v->type; - if (v->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, v); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = v->type; - } - } - return e->deref(); - } - - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - //printf("it's a function\n"); - if (f->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, f); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, f, 1); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = f->type; - } - } - return e; - } -#if DMDV2 - OverloadSet *o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } -#endif - - Type *t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - if (eleft) - error("cannot have e.tuple"); - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - ScopeDsymbol *sds = s->isScopeDsymbol(); - if (sds) - { - //printf("it's a ScopeDsymbol\n"); - e = new ScopeExp(loc, sds); - e = e->semantic(sc); - if (eleft) - e = new DotExp(loc, eleft, e); - return e; - } - - Import *imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - - // BUG: handle other cases like in IdentifierExp::semantic() -#ifdef DEBUG - printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - assert(0); - } - else if (ident == Id::stringof) - { char *s = ie->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - error("undefined identifier %s", toChars()); - type = Type::tvoid; - return this; - } - else if (t1b->ty == Tpointer && - ident != Id::init && ident != Id::__sizeof && - ident != Id::alignof && ident != Id::offsetof && - ident != Id::mangleof && ident != Id::stringof) - { /* Rewrite: - * p.ident - * as: - * (*p).ident - */ - e = new PtrExp(loc, e1); - e->type = ((TypePointer *)t1b)->next; - return e->type->dotExp(sc, e, ident); - } -#if DMDV2 - else if (t1b->ty == Tarray || - t1b->ty == Tsarray || - t1b->ty == Taarray) - { /* If ident is not a valid property, rewrite: - * e1.ident - * as: - * .ident(e1) - */ - unsigned errors = global.errors; - global.gag++; - e = e1->type->dotExp(sc, e1, ident); - global.gag--; - if (errors != global.errors) // if failed to find the property - { - global.errors = errors; - e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); - e = new CallExp(loc, e, e1); - } - e = e->semantic(sc); - return e; - } -#endif - else - { - e = e1->type->dotExp(sc, e1, ident); - e = e->semantic(sc); - return e; - } -} - -void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("DotIdExp::toCBuffer()\n"); - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/********************** DotTemplateExp ***********************************/ - -// Mainly just a placeholder - -DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) - : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) - -{ - this->td = td; -} - -void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(td->toChars()); -} - - -/************************************************************/ - -DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) - : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) -{ - //printf("DotVarExp()\n"); - this->var = v; - this->hasOverloads = hasOverloads; -} - -Expression *DotVarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotVarExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - var = var->toAlias()->isDeclaration(); - - TupleDeclaration *tup = var->isTupleDeclaration(); - if (tup) - { /* Replace: - * e1.tuple(a, b, c) - * with: - * tuple(e1.a, e1.b, e1.c) - */ - Expressions *exps = new Expressions; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = (Object *)tup->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - { - error("%s is not an expression", o->toChars()); - } - else - { - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - error("%s is not a member", e->toChars()); - else - { DsymbolExp *ve = (DsymbolExp *)e; - - e = new DotVarExp(loc, e1, ve->s->isDeclaration()); - exps->push(e); - } - } - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - - e1 = e1->semantic(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new ErrorExp(); - } - assert(type); - - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - Type *t1 = e1->type; - if (t1->ty == Tpointer) - t1 = t1->nextOf(); - - type = type->addMod(t1->mod); - - Dsymbol *vparent = var->toParent(); - AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; - e1 = getRightThis(loc, sc, ad, e1, var); - if (!sc->noaccesscheck) - accessCheck(loc, sc, e1, var); - - VarDeclaration *v = var->isVarDeclaration(); - Expression *e = expandVar(WANTvalue, v); - if (e) - return e; - } - } - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; -} - -#if DMDV2 -int DotVarExp::isLvalue() -{ - return 1; -} -#endif - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 0 - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1->type = %s\n", e1->type->toChars()); - printf("var->type = %s\n", var->type->toChars()); -#endif - - 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() && - e1->op == TOKthis - ) - { - 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 member %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } - } -#if DMDV2 - else - { - Type *t1 = e1->type->toBasetype(); - - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || - !var->type->isAssignable() || - var->storage_class & STCmanifest - ) - error("cannot modify const/immutable expression %s", toChars()); - } -#endif - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = ti; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - (TemplateInstance *)ti->syntaxCopy(NULL)); - return de; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ Dsymbol *s; - Dsymbol *s2; - TemplateDeclaration *td; - Expression *e; - Identifier *id; - Type *t1; - Expression *eleft = NULL; - Expression *eright; - -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - //e1->print(); - //print(); - e1 = e1->semantic(sc); - t1 = e1->type; - if (t1) - t1 = t1->toBasetype(); - //t1->print(); - - /* Extract the following from e1: - * s: the symbol which ti should be a member of - * eleft: if not NULL, it is the 'this' pointer for ti - */ - - if (e1->op == TOKdotexp) - { DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { eleft = NULL; - eright = e1; - } - if (eright->op == TOKimport) - { - s = ((ScopeExp *)eright)->sds; - } - else if (e1->op == TOKtype) - { - s = t1->isClassHandle(); - if (!s) - { if (t1->ty == Tstruct) - s = ((TypeStruct *)t1)->sym; - else - goto L1; - } - } - else if (t1 && (t1->ty == Tstruct || t1->ty == Tclass)) - { - s = t1->toDsymbol(sc); - eleft = e1; - } - else if (t1 && t1->ty == Tpointer) - { - t1 = ((TypePointer *)t1)->next->toBasetype(); - if (t1->ty != Tstruct) - goto L1; - s = t1->toDsymbol(sc); - eleft = e1; - } - else - { - L1: - error("template %s is not a member of %s", ti->toChars(), e1->toChars()); - goto Lerr; - } - - assert(s); - id = ti->name; - s2 = s->search(loc, id, 0); - if (!s2) - { - if (!s->ident) - error("template identifier %s is not a member of undefined %s", id->toChars(), s->kind()); - else - error("template identifier %s is not a member of %s %s", id->toChars(), s->kind(), s->ident->toChars()); - goto Lerr; - } - s = s2; - s->semantic(sc); - s = s->toAlias(); - td = s->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template", id->toChars()); - goto Lerr; - } - if (global.errors) - goto Lerr; - - ti->tempdecl = td; - - if (eleft) - { Declaration *v; - - ti->semantic(sc); - s = ti->inst->toAlias(); - v = s->isDeclaration(); - if (v) - { e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - } - - e = new ScopeExp(loc, ti); - if (eleft) - { - e = new DotExp(loc, eleft, e); - } - e = e->semantic(sc); - return e; - -Lerr: - return new ErrorExp(); -} - -void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - ti->toCBuffer(buf, hgs); -} - -/************************************************************/ - -DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) - : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) -{ - this->func = f; - this->hasOverloads = hasOverloads; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - e1 = e1->semantic(sc); - // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' - type = new TypeDelegate(func->type->syntaxCopy()); - type = type->semantic(loc, sc); - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - if (func->needThis()) - e1 = getRightThis(loc, sc, ad, e1, func); - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(1); - arguments->data[0] = (void *)earg1; - - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->data[0] = (void *)earg1; - arguments->data[1] = (void *)earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - FuncDeclaration *f; - int i; - Type *t1; - int istemp; - Objects *targsi = NULL; // initial list of template arguments - TemplateInstance *tierror = NULL; - -#if LOGSEMANTIC - printf("CallExp::semantic() %s\n", toChars()); -#endif - if (type) - return this; // semantic() already run -#if 0 - if (arguments && arguments->dim) - { - Expression *earg = (Expression *)arguments->data[0]; - earg->print(); - if (earg->type) earg->type->print(); - } -#endif - - if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - - e1 = new DotVarExp(de->loc, de->e1, de->func); - return semantic(sc); - } - - /* Transform: - * array.id(args) into .id(array,args) - * aa.remove(arg) into delete aa[arg] - */ - if (e1->op == TOKdot) - { - // BUG: we should handle array.a.b.c.e(args) too - - DotIdExp *dotid = (DotIdExp *)(e1); - dotid->e1 = dotid->e1->semantic(sc); - assert(dotid->e1); - if (dotid->e1->type) - { - TY e1ty = dotid->e1->type->toBasetype()->ty; - if (e1ty == Taarray && dotid->ident == Id::remove) - { - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - goto Lagain; - } - Expression *key = (Expression *)arguments->data[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - key->rvalue(); - - TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); - key = key->implicitCastTo(sc, taa->index); - - return new RemoveExp(loc, dotid->e1, key); - } - else if (e1ty == Tarray || e1ty == Tsarray || e1ty == Taarray) - { - if (!arguments) - arguments = new Expressions(); - arguments->shift(dotid->e1); -#if DMDV2 - e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); -#else - e1 = new IdentifierExp(dotid->loc, dotid->ident); -#endif - } - } - } - -#if 1 - /* This recognizes: - * foo!(tiargs)(funcargs) - */ - if (e1->op == TOKimport && !e1->type) - { ScopeExp *se = (ScopeExp *)e1; - TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - unsigned errors = global.errors; - global.gag++; - ti->semantic(sc); - global.gag--; - if (errors != global.errors) - { - /* Didn't work, go with partial explicit specialization - */ - global.errors = errors; - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new IdentifierExp(loc, ti->name); - } - } - } - - /* This recognizes: - * expr.foo!(tiargs)(funcargs) - */ - if (e1->op == TOKdotti && !e1->type) - { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; - TemplateInstance *ti = se->ti; - if (!ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - Expression *etmp = e1->trySemantic(sc); - if (etmp) - e1 = etmp; // it worked - else // didn't work - { - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new DotIdExp(loc, se->e1, ti->name); - } - } - } -#endif - - istemp = 0; -Lagain: - //printf("Lagain: %s\n", toChars()); - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - else - { - UnaExp::semantic(sc); - - /* Look for e1 being a lazy parameter - */ - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - - if (ve->var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if 1 // patch for #540 by Oskar Linde - else if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *) e1; - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - if (e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; -#if DMDV2 - // First look for constructor - if (ad->ctor && arguments && arguments->dim) - { - // Create variable that will get constructed - Identifier *idtmp = Lexer::uniqueId("__ctmp"); - VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); - Expression *av = new DeclarationExp(loc, tmp); - av = new CommaExp(loc, av, new VarExp(loc, tmp)); - - Expression *e; - CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); - if (cf) - e = new DotVarExp(loc, av, cf, 1); - else - { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); - assert(td); - e = new DotTemplateExp(loc, av, td); - } - e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif - e = e->semantic(sc); - return e; - } -#endif - // No constructor, look for overload of opCall - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - error("%s %s does not overload ()", ad->kind(), ad->toChars()); - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments); - e = e->semantic(sc); - e->type = e1->type; // in case e1->type was a typedef - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arrayExpressionSemantic(arguments, sc); - preFunctionArguments(loc, sc, arguments); - - if (e1->op == TOKdotvar && t1->ty == Tfunction || - e1->op == TOKdottd) - { - DotVarExp *dve; - DotTemplateExp *dte; - AggregateDeclaration *ad; - UnaExp *ue = (UnaExp *)(e1); - - if (e1->op == TOKdotvar) - { // Do overload resolution - dve = (DotVarExp *)(e1); - - f = dve->var->isFuncDeclaration(); - assert(f); - f = f->overloadResolve(loc, ue->e1, arguments); - - ad = f->toParent()->isAggregateDeclaration(); - } - else - { dte = (DotTemplateExp *)(e1); - TemplateDeclaration *td = dte->td; - assert(td); - if (!arguments) - // Should fix deduceFunctionTemplate() so it works on NULL argument - arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); - if (!f) - { type = Type::terror; - return this; - } - ad = td->toParent()->isAggregateDeclaration(); - } - if (f->needThis()) - { - ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); - } - - /* Cannot call public functions from inside invariant - * (because then the invariant would have infinite recursion) - */ - if (sc->func && sc->func->isInvariantDeclaration() && - ue->e1->op == TOKthis && - f->addPostInvariant() - ) - { - error("cannot call public/export function %s from invariant", f->toChars()); - } - - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); -#endif - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - e1 = new CommaExp(loc, ue->e1, ve); - e1->type = f->type; - } - else - { - if (e1->op == TOKdotvar) - dve->var = f; - else - e1 = new DotVarExp(loc, dte->e1, f); - e1->type = f->type; -#if 0 - printf("ue->e1 = %s\n", ue->e1->toChars()); - printf("f = %s\n", f->toChars()); - printf("t = %s\n", t->toChars()); - printf("e1 = %s\n", e1->toChars()); - printf("e1->type = %s\n", e1->type->toChars()); -#endif - // Const member function can take const/immutable/mutable this - if (!(f->type->isConst())) - { - // Check for const/immutable compatibility - Type *tthis = ue->e1->type->toBasetype(); - if (tthis->ty == Tpointer) - tthis = tthis->nextOf()->toBasetype(); -#if 0 // this checking should have been already done - if (f->type->isInvariant()) - { - if (tthis->mod != MODinvariant) - error("%s can only be called with an immutable object", e1->toChars()); - } - else if (f->type->isShared()) - { - if (tthis->mod != MODinvariant && - tthis->mod != MODshared && - tthis->mod != (MODshared | MODconst)) - error("shared %s can only be called with a shared or immutable object", e1->toChars()); - } - else - { - if (tthis->mod != 0) - { //printf("mod = %x\n", tthis->mod); - error("%s can only be called with a mutable object, not %s", e1->toChars(), tthis->toChars()); - } - } -#endif - /* Cannot call mutable method on a final struct - */ - if (tthis->ty == Tstruct && - ue->e1->op == TOKvar) - { VarExp *v = (VarExp *)ue->e1; - if (v->var->storage_class & STCfinal) - error("cannot call mutable method on final struct"); - } - } - - // See if we need to adjust the 'this' pointer - AggregateDeclaration *ad = f->isThis(); - ClassDeclaration *cd = ue->e1->type->isClassHandle(); - if (ad && cd && ad->isClassDeclaration() && ad != cd && - ue->e1->op != TOKsuper) - { - ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); - ue->e1 = ue->e1->semantic(sc); - } - } - t1 = e1->type; - } - else if (e1->op == TOKsuper) - { - // Base class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) - { - error("super class constructor call must be in a constructor"); - type = Type::terror; - return this; - } - else - { - if (!cd->baseClass->ctor) - { error("no super class constructor for %s", cd->baseClass->toChars()); - type = Type::terror; - return this; - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXsuper_ctor; - } - - f = resolveFuncCall(sc, loc, cd->baseClass->ctor, NULL, NULL, arguments, 0); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - } - } - } - else if (e1->op == TOKthis) - { - // same class constructor call - AggregateDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isAggregateDeclaration(); - if (!cd || !sc->func->isCtorDeclaration()) - { - error("constructor call must be in a constructor"); - type = Type::terror; - return this; - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXthis_ctor; - } - - f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - - // BUG: this should really be done by checking the static - // call graph - if (f == sc->func) - error("cyclic constructor call"); - } - } - else if (e1->op == TOKoverloadset) - { - OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (int i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = (Dsymbol *)eo->vars->a.data[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - if (f2) - { - f2 = f2->overloadResolve(loc, NULL, arguments, 1); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f2 = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments, 1); - } - if (f2) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } - if (!f) - { /* No overload matches, just set f and rely on error - * message being generated later. - */ - f = (FuncDeclaration *)eo->vars->a.data[0]; - } - e1 = new VarExp(loc, f); - goto Lagain; - } - else if (!t1) - { - error("function expected before (), not '%s'", e1->toChars()); - type = Type::terror; - return this; - } - else if (t1->ty != Tfunction) - { - if (t1->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)t1; - assert(td->next->ty == Tfunction); - tf = (TypeFunction *)(td->next); - if (sc->func && sc->func->isPure() && !tf->ispure) - { - error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); - } - goto Lcheckargs; - } - else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { Expression *e; - - e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->ispure) - { - error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); - } - e->type = t1; - e1 = e; - } - else if (e1->op == TOKtemplate) - { - TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!f) - { if (tierror) - tierror->error("errors instantiating template"); // give better error message - type = Type::terror; - return this; - } - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); - goto Lagain; - } - - e1 = new VarExp(loc, f); - goto Lagain; - } - else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - type = Type::terror; - return this; - } - } - else if (e1->op == TOKvar) - { - // Do overload resolution - VarExp *ve = (VarExp *)e1; - - f = ve->var->isFuncDeclaration(); - assert(f); - - if (ve->hasOverloads) - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); -#endif - - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotVarExp(loc, new ThisExp(loc), f); - goto Lagain; - } - - accessCheck(loc, sc, NULL, f); - - ve->var = f; -// ve->hasOverloads = 0; - ve->type = f->type; - t1 = f->type; - } - assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - functionArguments(loc, sc, tf, arguments); - - if (!type) - { - error("forward reference to inferred return type of function call %s", toChars()); - type = Type::terror; - } - - if (f && f->tintro) - { - Type *t = type; - int offset = 0; - TypeFunction *tf = (TypeFunction *)f->tintro; - - if (tf->next->isBaseOf(t, &offset) && offset) - { - type = tf->next; - return castTo(sc, t); - } - } - - return this; -} - -int CallExp::checkSideEffect(int flag) -{ -#if DMDV2 - if (flag != 2) - return 1; - - if (e1->checkSideEffect(2)) - return 1; - - /* If any of the arguments have side effects, this expression does - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e->checkSideEffect(2)) - return 1; - } - - /* If calling a function or delegate that is typed as pure, - * then this expression has no side effects. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) - return 0; -#endif - return 1; -} - -#if DMDV2 -int CallExp::canThrow() -{ - //printf("CallExp::canThrow() %s\n", toChars()); - if (e1->canThrow()) - return 1; - - /* If any of the arguments can throw, then this expression can throw - */ - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e && e->canThrow()) - return 1; - } - - if (global.errors && !e1->type) - return 0; // error recovery - - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type *t = e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) - return 0; - if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - return 0; - - return 1; -} -#endif - -#if DMDV2 -int CallExp::isLvalue() -{ -// if (type->toBasetype()->ty == Tstruct) -// return 1; - Type *tb = e1->type->toBasetype(); - if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) - return 1; // function returns a reference - return 0; -} -#endif - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ - if (isLvalue()) - return this; - return Expression::toLvalue(sc, e); -} - -void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); -} - - -/************************************************************/ - -AddrExp::AddrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) -{ -#if IN_LLVM - m = NULL; -#endif -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { -#if IN_LLVM - m = sc->module; -#endif - UnaExp::semantic(sc); - e1 = e1->toLvalue(sc, NULL); - if (!e1->type) - { - error("cannot take address of %s", e1->toChars()); - return new ErrorExp(); - } - if (!e1->type->deco) - { - /* No deco means semantic() was not run on the type. - * We have to run semantic() on the symbol to get the right type: - * auto x = &bar; - * pure: int bar() { return 1;} - * otherwise the 'pure' is missing from the type assigned to x. - */ - - error("forward reference to %s", e1->toChars()); - return new ErrorExp(); - } - -//printf("test3 deco = %p\n", e1->type->deco); - type = e1->type->pointerTo(); - - // See if this should really be a delegate - if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - - if (f) - { - if (!dve->hasOverloads) - f->tookAddressOf++; - Expression *e = new DelegateExp(loc, dve->e1, f, dve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - else if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->canTakeAddressOf()) - error("cannot take address of %s", e1->toChars()); - - FuncDeclaration *f = ve->var->isFuncDeclaration(); - - if (f) - { - if (!ve->hasOverloads || - /* Because nested functions cannot be overloaded, - * mark here that we took its address because castTo() - * may not be called with an exact match. - */ - f->toParent2()->isFuncDeclaration()) - f->tookAddressOf++; - if (f->isNested()) - { - Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - if (f->needThis() && hasThis(sc)) - { - /* Should probably supply 'this' after overload resolution, - * not before. - */ - Expression *ethis = new ThisExp(loc); - Expression *e = new DelegateExp(loc, ethis, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - } - return optimize(WANTvalue); - } - return this; -} - -/************************************************************/ - -PtrExp::PtrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ -// if (e->type) -// type = ((TypePointer *)e->type)->next; -} - -PtrExp::PtrExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - type = t; -} - -Expression *PtrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("PtrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (!e1->type) - printf("PtrExp::semantic('%s')\n", toChars()); - Expression *e = op_overload(sc); - if (e) - return e; - Type *tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = ((TypePointer *)tb)->next; - break; - - case Tsarray: - case Tarray: - type = ((TypeArray *)tb)->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - return new ErrorExp(); - } - rvalue(); - } - return this; -} - -#if DMDV2 -int PtrExp::isLvalue() -{ - return 1; -} -#endif - -Expression *PtrExp::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; -} - -#if DMDV2 -Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - se->var->checkModify(loc, sc, type); - //return toLvalue(sc, e); - } - - return Expression::modifiableLvalue(sc, e); -} -#endif - -void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('*'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -NegExp::NegExp(Loc loc, Expression *e) - : UnaExp(loc, TOKneg, sizeof(NegExp), e) -{ -} - -Expression *NegExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("NegExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (e1->op != TOKslice) - e1->checkArithmetic(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -UAddExp::UAddExp(Loc loc, Expression *e) - : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) -{ -} - -Expression *UAddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("UAddExp::semantic('%s')\n", toChars()); -#endif - assert(!type); - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - e1->checkNoBool(); - e1->checkArithmetic(); - return e1; -} - -/************************************************************/ - -ComExp::ComExp(Loc loc, Expression *e) - : UnaExp(loc, TOKtilde, sizeof(ComExp), e) -{ -} - -Expression *ComExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (e1->op != TOKslice) - e1 = e1->checkIntegral(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -NotExp::NotExp(Loc loc, Expression *e) - : UnaExp(loc, TOKnot, sizeof(NotExp), e) -{ -} - -Expression *NotExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(); - type = Type::tboolean; - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->toLvalue(sc, NULL); - type = Type::tvoid; - - tb = e1->type->toBasetype(); - switch (tb->ty) - { case Tclass: - { TypeClass *tc = (TypeClass *)tb; - ClassDeclaration *cd = tc->sym; - - if (cd->isCOMinterface()) - { /* Because COM classes are deleted by IUnknown.Release() - */ - error("cannot delete instance of COM interface %s", cd->toChars()); - } - break; - } - case Tpointer: - tb = ((TypePointer *)tb)->next->toBasetype(); - if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggDelete; - FuncDeclaration *fd = sd->dtor; - - if (!f && !fd) - break; - - /* Construct: - * ea = copy e1 to a tmp to do side effects only once - * eb = call destructor - * ec = call deallocator - */ - Expression *ea = NULL; - Expression *eb = NULL; - Expression *ec = NULL; - VarDeclaration *v; - - if (fd && f) - { Identifier *id = Lexer::idPool("__tmp"); - v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); - v->semantic(sc); - v->parent = sc->parent; - ea = new DeclarationExp(loc, v); - ea->type = v->type; - } - - if (fd) - { Expression *e = ea ? new VarExp(loc, v) : e1; - e = new DotVarExp(0, e, fd, 0); - eb = new CallExp(loc, e); - eb = eb->semantic(sc); - } - - if (f) - { - Type *tpv = Type::tvoid->pointerTo(); - Expression *e = ea ? new VarExp(loc, v) : e1->castTo(sc, tpv); - e = new CallExp(loc, new VarExp(loc, f), e); - ec = e->semantic(sc); - } - ea = combine(ea, eb); - ea = combine(ea, ec); - assert(ea); - return ea; - } - break; - - case Tarray: - /* BUG: look for deleting arrays of structs with dtors. - */ - break; - - default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } - error("cannot delete type %s", e1->type->toChars()); - break; - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - -int DeleteExp::checkSideEffect(int flag) -{ - return 1; -} - -Expression *DeleteExp::checkToBoolean() -{ - error("delete does not give a boolean result"); - return this; -} - -void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete "); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -CastExp::CastExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = t; - this->mod = ~0; -} - -#if DMDV2 -/* For cast(const) and cast(immutable) - */ -CastExp::CastExp(Loc loc, Expression *e, unsigned mod) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = NULL; - this->mod = mod; -} -#endif - -Expression *CastExp::syntaxCopy() -{ - return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()) - : new CastExp(loc, e1->syntaxCopy(), mod); -} - - -Expression *CastExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - -#if LOGSEMANTIC - printf("CastExp::semantic('%s')\n", toChars()); -#endif - -//static int x; assert(++x < 10); - - if (type) - return this; - UnaExp::semantic(sc); - if (e1->type) // if not a tuple - { - e1 = resolveProperties(sc, e1); - - if (!to) - { - /* Handle cast(const) and cast(immutable), etc. - */ - to = e1->type->castMod(mod); - } - else - to = to->semantic(loc, sc); - - if (!to->equals(e1->type)) - { - e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - } - - Type *t1b = e1->type->toBasetype(); - Type *tob = to->toBasetype(); - if (tob->ty == Tstruct && - !tob->equals(t1b) && - ((TypeStruct *)tob)->sym->search(0, Id::call, 0) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - e = new TypeExp(loc, to); - e = new DotIdExp(loc, e, Id::call); - e = new CallExp(loc, e, e1); - e = e->semantic(sc); - return e; - } - } - else if (!to) - { error("cannot cast tuple"); - to = Type::terror; - } - - if (global.params.safe && !sc->module->safe && !sc->intypeof) - { // Disallow unsafe casts - Type *tob = to->toBasetype(); - Type *t1b = e1->type->toBasetype(); - if (!t1b->isMutable() && tob->isMutable()) - { // Cast not mutable to mutable - Lunsafe: - error("cast from %s to %s not allowed in safe mode", e1->type->toChars(), to->toChars()); - } - else if (t1b->isShared() && !tob->isShared()) - // Cast away shared - goto Lunsafe; - else if (tob->ty == Tpointer) - { if (t1b->ty != Tpointer) - goto Lunsafe; - Type *tobn = tob->nextOf()->toBasetype(); - Type *t1bn = t1b->nextOf()->toBasetype(); - - if (!t1bn->isMutable() && tobn->isMutable()) - // Cast away pointer to not mutable - goto Lunsafe; - - if (t1bn->isShared() && !tobn->isShared()) - // Cast away pointer to shared - goto Lunsafe; - - if (tobn->isTypeBasic() && tobn->size() < t1bn->size()) - // Allow things like casting a long* to an int* - ; - else if (tobn->ty != Tvoid) - // Cast to a pointer other than void* - goto Lunsafe; - } - - // BUG: Check for casting array types, such as void[] to int*[] - } - - e = e1->castTo(sc, to); - return e; -} - -int CastExp::checkSideEffect(int flag) -{ - /* if not: - * cast(void) - * cast(classtype)func() - */ - if (!to->equals(Type::tvoid) && - !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) - return Expression::checkSideEffect(flag); - return 1; -} - -void CastExp::checkEscape() -{ Type *tb = type->toBasetype(); - if (tb->ty == Tarray && e1->op == TOKvar && - e1->type->toBasetype()->ty == Tsarray) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !v->isParameter()) - error("escaping reference to local %s", v->toChars()); - } - } -} - -void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); -#if DMDV1 - to->toCBuffer(buf, NULL, hgs); -#else - if (to) - to->toCBuffer(buf, NULL, hgs); - else - { - switch (mod) - { case 0: - break; - case MODconst: - buf->writestring(Token::tochars[TOKconst]); - break; - case MODinvariant: - buf->writestring(Token::tochars[TOKimmutable]); - break; - case MODshared: - buf->writestring(Token::tochars[TOKshared]); - break; - case MODshared | MODconst: - buf->writestring(Token::tochars[TOKshared]); - buf->writeByte(' '); - buf->writestring(Token::tochars[TOKconst]); - break; - default: - assert(0); - } - } -#endif - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - error("need upper and lower bound to slice pointer"); - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else - goto Lerror; - - { - Scope *sc2 = sc; - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - { - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc2 = sc->push(sym); - } - - if (lwr) - { lwr = lwr->semantic(sc2); - lwr = resolveProperties(sc2, lwr); - lwr = lwr->implicitCastTo(sc2, Type::tsize_t); - } - if (upr) - { upr = upr->semantic(sc2); - upr = resolveProperties(sc2, upr); - upr = upr->implicitCastTo(sc2, Type::tsize_t); - } - - if (sc2 != sc) - sc2->pop(); - } - - if (t->ty == Ttuple) - { - lwr = lwr->optimize(WANTvalue); - upr = upr->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Argument::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (Expression *)te->exps->data[j1 + i]; - exps->data[i] = (void *)e; - } - e = new TupleExp(loc, exps); - } - else - { Arguments *args = new Arguments; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Argument *arg = Argument::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); - e = new ErrorExp(); - } - return e; - } - - if (t->ty == Tarray) - { - type = e1->type; - } - else - type = t->nextOf()->arrayOf(); - return e; - -Lerror: - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); - e = new ErrorExp(); - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -#if DMDV2 -int SliceExp::isLvalue() -{ - return 1; -} -#endif - -Expression *SliceExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("slice expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('['); - if (upr || lwr) - { - if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); - else - buf->writeByte('0'); - buf->writestring(".."); - if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); - else - buf->writestring("length"); // BUG: should be array.length - } - buf->writeByte(']'); -} - -/********************** ArrayLength **************************************/ - -ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) - : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) -{ -} - -Expression *ArrayLengthExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("ArrayLengthExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - type = Type::tsize_t; - } - return this; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - t1 = e1->type->toBasetype(); - if (t1->ty != Tclass && t1->ty != Tstruct) - { // Convert to IndexExp - if (arguments->dim != 1) - error("only one index allowed to index %s", t1->toChars()); - e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); - return e->semantic(sc); - } - - // Run semantic() on each argument - for (size_t i = 0; i < arguments->dim; i++) - { e = (Expression *)arguments->data[i]; - - e = e->semantic(sc); - if (!e->type) - error("%s has no value", e->toChars()); - arguments->data[i] = (void *)e; - } - - expandTuples(arguments); - assert(arguments && arguments->dim); - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - e = e1; - } - return e; -} - -#if DMDV2 -int ArrayExp::isLvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - return 0; - return 1; -} -#endif - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -#if DMDV2 -int CommaExp::isLvalue() -{ - return e2->isLvalue(); -} -#endif - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - -int CommaExp::checkSideEffect(int flag) -{ - if (flag == 2) - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - else - { - // Don't check e1 until we cast(void) the a,b code generation - return e2->checkSideEffect(flag); - } -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - BinExp *b; - UnaExp *u; - Type *t1; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("IndexExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - if (!e1->type) - e1 = e1->semantic(sc); - assert(e1->type); // semantic() should already be run on it - e = this; - - // Note that unlike C we do not implement the int[ptr] - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - { // Create scope for 'length' variable - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - if (!e2->type) - { - error("%s has no value", e2->toChars()); - e2->type = Type::terror; - } - e2 = resolveProperties(sc, e2); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = ((TypeNext *)t1)->next; - break; - - case Tsarray: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - - TypeSArray *tsa = (TypeSArray *)t1; - -#if 0 // Don't do now, because it might be short-circuit evaluated - // Do compile time array bounds checking if possible - e2 = e2->optimize(WANTvalue); - if (e2->op == TOKint64) - { - dinteger_t index = e2->toInteger(); - dinteger_t length = tsa->dim->toInteger(); - if (index < 0 || index >= length) - error("array index [%lld] is outside array bounds [0 .. %lld]", - index, length); - } -#endif - e->type = t1->nextOf(); - break; - } - - case Taarray: - { TypeAArray *taa = (TypeAArray *)t1; - if (!arrayTypeCompatible(e2->loc, e2->type, taa->index)) - { - e2 = e2->implicitCastTo(sc, taa->index); // type checking - } - type = taa->next; - break; - } - - case Ttuple: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue | WANTinterpret); - uinteger_t index = e2->toUInteger(); - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) - { - tup = (TypeTuple *)t1; - length = Argument::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - e = (Expression *)te->exps->data[(size_t)index]; - else - e = new TypeExp(e1->loc, Argument::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); - e = e1; - } - break; - } - - default: - error("%s must be an array or pointer type, not %s", - e1->toChars(), e1->type->toChars()); - type = Type::tint32; - break; - } - return e; -} - -#if DMDV2 -int IndexExp::isLvalue() -{ - return 1; -} -#endif - -Expression *IndexExp::toLvalue(Scope *sc, Expression *e) -{ -// if (type && type->toBasetype()->ty == Tvoid) -// error("voids have no value"); - return this; -} - -Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); - modifiable = 1; - if (e1->op == TOKstring) - error("string literals are immutable"); - if (type && !type->isMutable()) - error("%s isn't mutable", e->toChars()); - if (e1->type->toBasetype()->ty == Taarray) - e1 = e1->modifiableLvalue(sc, e1); - return toLvalue(sc, e); -} - -void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writeByte(']'); -} - - -/************************* PostExp ***********************************/ - -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) - : BinExp(loc, op, sizeof(PostExp), e, - new IntegerExp(loc, 1, Type::tint32)) -{ -} - -Expression *PostExp::semantic(Scope *sc) -{ Expression *e = this; - - if (!type) - { - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e = this; - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer) - e = scaleFactor(sc); - else - e2 = e2->castTo(sc, e1->type); - e->type = e1->type; - } - return e; -} - -void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writestring((op == TOKplusplus) ? (char *)"++" : (char *)"--"); -} - -/************************************************************/ - -/* op can be TOKassign, TOKconstruct, or TOKblit */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); - - if (type) - return this; - - if (e2->op == TOKcomma) - { /* Rewrite to get rid of the comma from rvalue - */ - AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); - ea->op = op; - Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); - return e->semantic(sc); - } - - /* Look for operator overloading of a[i]=value. - * Do it before semantic() otherwise the a[i] will have been - * converted to a.opIndex() already. - */ - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - Type *t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - - e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); - e = e->semantic(sc); - return e; - } - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L2; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L2: - // Rewrite (a[i..j] = value) to (a.opIndexAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - } - - BinExp::semantic(sc); - - if (e1->op == TOKdottd) - { // Rewrite a.b=e2, when b is a template, as a.b(e2) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - e2 = resolveProperties(sc, e2); - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (int i = 0; i < dim; i++) - { Expression *ex1 = (Expression *)tup1->exps->data[i]; - Expression *ex2 = (Expression *)tup2->exps->data[i]; - exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - // Determine if this is an initialization of a reference - int refinit = 0; - if (op == TOKconstruct && e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->storage_class & (STCout | STCref)) - refinit = 1; - } - - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tfunction) - { // Rewrite f=value to f(value) - Expression *e = new CallExp(loc, e1, e2); - e = e->semantic(sc); - return e; - } - - /* If it is an assignment from a 'foreign' type, - * check for operator overloading. - */ - if (t1->ty == Tstruct) - { - StructDeclaration *sd = ((TypeStruct *)t1)->sym; - if (op == TOKassign) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - else if (op == TOKconstruct && !refinit) - { Type *t2 = e2->type->toBasetype(); - if (t2->ty == Tstruct && - sd == ((TypeStruct *)t2)->sym && - sd->cpctor) - { /* We have a copy constructor for this - */ - if (e2->op == TOKquestion) - { /* Write as: - * a ? e1 = b : e1 = c; - */ - CondExp *ec = (CondExp *)e2; - AssignExp *ea1 = new AssignExp(ec->e1->loc, e1, ec->e1); - ea1->op = op; - AssignExp *ea2 = new AssignExp(ec->e1->loc, e1, ec->e2); - ea2->op = op; - Expression *e = new CondExp(loc, ec->econd, ea1, ea2); - return e->semantic(sc); - } - else if (e2->op == TOKvar || - e2->op == TOKdotvar || - e2->op == TOKstar || - e2->op == TOKindex) - { /* Write as: - * e1.cpctor(e2); - */ - Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); - e = new CallExp(loc, e, e2); - return e->semantic(sc); - } - } - } - } - else if (t1->ty == Tclass) - { // Disallow assignment operator overloads for same type - if (!e2->type->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - if (t1->ty == Tsarray && !refinit) - { // Convert e1 to e1[] - Expression *e = new SliceExp(e1->loc, e1, NULL, NULL); - e1 = e->semantic(sc); - t1 = e1->type->toBasetype(); - } - - e2->rvalue(); - - if (e1->op == TOKarraylength) - { - // e1 is not an lvalue, but we let code generator handle it - ArrayLengthExp *ale = (ArrayLengthExp *)e1; - - ale->e1 = ale->e1->modifiableLvalue(sc, e1); - } - else if (e1->op == TOKslice) - { - Type *tn = e1->type->nextOf(); - if (tn && !tn->isMutable() && op != TOKconstruct) - error("slice %s is not mutable", e1->toChars()); - } - else - { // Try to do a decent error message with the expression - // before it got constant folded - if (e1->op != TOKvar) - e1 = e1->optimize(WANTvalue); - - if (op != TOKconstruct) - e1 = e1->modifiableLvalue(sc, e1old); - } - - Type *t2 = e2->type; - if (e1->op == TOKslice && - t1->nextOf() && - e2->implicitConvTo(t1->nextOf()) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, t1->nextOf()); - } - else if (t1->ty == Tsarray) - { - /* Should have already converted e1 => e1[] - */ - assert(op == TOKconstruct); - //error("cannot assign to static array %s", e1->toChars()); - } - else if (e1->op == TOKslice) - { - e2 = e2->implicitCastTo(sc, e1->type->constOf()); - } - else - { - e2 = e2->implicitCastTo(sc, e1->type); - } - - /* Look for array operations - */ - if (e1->op == TOKslice && !ismemset && - (e2->op == TOKadd || e2->op == TOKmin || - e2->op == TOKmul || e2->op == TOKdiv || - e2->op == TOKmod || e2->op == TOKxor || - e2->op == TOKand || e2->op == TOKor || - e2->op == TOKtilde || e2->op == TOKneg)) - { - type = e1->type; - return arrayOp(sc); - } - - type = e1->type; - assert(type); - return this; -} - -Expression *AssignExp::checkToBoolean() -{ - // Things like: - // if (a = b) ... - // are usually mistakes. - - error("'=' does not give a boolean result"); - return this; -} - -/************************************************************/ - -AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) -{ -} - -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKslice) - { - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - typeCombine(sc); - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbit || tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return e; -} - -/************************************************************/ - -CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) -{ -} - -Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - error("cannot append to static array %s", se->e1->type->toChars()); - } - - e1 = e1->modifiableLvalue(sc, e1); - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - e2->rvalue(); - - if ((tb1->ty == Tarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - (e2->implicitConvTo(e1->type) || - tb2->nextOf()->implicitConvTo(tb1->nextOf())) - ) - { // Append array - e2 = e2->castTo(sc, e1->type); - type = e1->type; - e = this; - } - else if ((tb1->ty == Tarray) && - e2->implicitConvTo(tb1->nextOf()) - ) - { // Append element - e2 = e2->castTo(sc, tb1->nextOf()); - type = e1->type; - e = this; - } - else - { - error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); - type = Type::tint32; - e = this; - } - return e; -} - -/************************************************************/ - -MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) -{ -} - -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isfloating()) - { Type *t1; - Type *t2; - - t1 = e1->type; - t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { // T[] -= ... - typeCombine(sc); - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - if (e2->type->isimaginary()) - { Type *t1; - Type *t2; - - t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssign(sc); -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -Expression *ShlAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlAssignExp::semantic()\n"); - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -Expression *ShrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -Expression *UshrAssignExp::semantic(Scope *sc) -{ Expression *e; - - BinExp::semantic(sc); - e2 = resolveProperties(sc, e2); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - -/************************************************************/ - -AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) -{ -} - -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) -{ -} - -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) -{ -} - -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ -} - -Expression *AddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("AddExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tpointer && tb2->ty == Tpointer) - { - incompatibleTypes(); - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if ((e1->type->isreal() && e2->type->isimaginary()) || - (e1->type->isimaginary() && e2->type->isreal())) - { - switch (type->toBasetype()->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - e = this; - } - return e; - } - return this; -} - -/************************************************************/ - -MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) -{ -} - -Expression *MinExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("MinExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - e = this; - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if (t1->ty == Tpointer) - { - if (t2->ty == Tpointer) - { // Need to divide the result by the stride - // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; - Expression *e; - - typeCombine(sc); // make sure pointer types are compatible - type = Type::tptrdiff_t; - stride = t2->nextOf()->size(); - if (stride == 0) - { - e = new IntegerExp(loc, 0, Type::tptrdiff_t); - } - else - { - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - } - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("incompatible types for minus"); - return new ErrorExp(); - } - } - else if (t2->ty == Tpointer) - { - type = e2->type; - error("can't subtract pointer from %s", e1->type->toChars()); - return new ErrorExp(); - } - else - { - typeCombine(sc); - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->isreal() && t2->isimaginary()) || - (t1->isimaginary() && t2->isreal())) - { - switch (type->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - } - return e; -} - -/************************* CatExp *****************************/ - -CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) -{ -} - -Expression *CatExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatExp::semantic() %s\n", toChars()); - if (!type) - { - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - - /* BUG: Should handle things like: - * char c; - * c ~ ' ' - * ' ' ~ c; - */ - -#if 0 - e1->type->print(); - e2->type->print(); -#endif - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->type->implicitConvTo(tb1->nextOf()) >= MATCHconst) - { - type = tb1->nextOf()->arrayOf(); - if (tb2->ty == Tarray) - { // Make e2 into [e2] - e2 = new ArrayLiteralExp(e2->loc, e2); - e2->type = type; - } - return this; - } - else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->type->implicitConvTo(tb2->nextOf()) >= MATCHconst) - { - type = tb2->nextOf()->arrayOf(); - if (tb1->ty == Tarray) - { // Make e1 into [e1] - e1 = new ArrayLiteralExp(e1->loc, e1); - e1->type = type; - } - return this; - } - - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - (tb2->ty == Tsarray || tb2->ty == Tarray) && - (tb1->nextOf()->mod || tb2->nextOf()->mod) && - (tb1->nextOf()->mod != tb2->nextOf()->mod) - ) - { - Type *t1 = tb1->nextOf()->mutableOf()->constOf()->arrayOf(); - Type *t2 = tb2->nextOf()->mutableOf()->constOf()->arrayOf(); - if (e1->op == TOKstring && !((StringExp *)e1)->committed) - e1->type = t1; - else - e1 = e1->castTo(sc, t1); - if (e2->op == TOKstring && !((StringExp *)e2)->committed) - e2->type = t2; - else - e2 = e2->castTo(sc, t2); - } - - typeCombine(sc); - type = type->toHeadMutable(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray) - type = tb->nextOf()->arrayOf(); - if (type->ty == Tarray && tb1->nextOf() && tb2->nextOf() && - tb1->nextOf()->mod != tb2->nextOf()->mod) - { - type = type->nextOf()->toHeadMutable()->arrayOf(); - } -#if 0 - e1->type->print(); - e2->type->print(); - type->print(); - print(); -#endif - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (e1->op == TOKstring && e2->op == TOKstring) - e = optimize(WANTvalue); - else if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - e = this; - } - else - { - //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); - error("Can only concatenate arrays, not (%s ~ %s)", - e1->type->toChars(), e2->type->toChars()); - type = Type::tint32; - e = this; - } - e->type = e->type->semantic(loc, sc); - return e; - } - return this; -} - -/************************************************************/ - -MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) -{ -} - -Expression *MulExp::semantic(Scope *sc) -{ Expression *e; - -#if 0 - printf("MulExp::semantic() %s\n", toChars()); -#endif - if (type) - { - return this; - } - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkArithmetic(); - e2->checkArithmetic(); - } - if (type->isfloating()) - { type = e1->type; - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - } - return this; -} - -/************************************************************/ - -ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) -{ -} - -Expression *ShlExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlExp::semantic(), type = %p\n", type); - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) -{ -} - -Expression *AndExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - -/************************************************************/ - -OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) -{ -} - -Expression *OrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - -/************************************************************/ - -XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) -{ -} - -Expression *XorExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (e1->op != TOKslice && e2->op != TOKslice) - { e1->checkIntegral(); - e2->checkIntegral(); - } - } - } - return this; -} - - -/************************************************************/ - -OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) -{ -} - -Expression *OrOrExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for AndAnd - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(TRUE)) - { - return new IntegerExp(loc, 1, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e2->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *OrOrExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - -int OrOrExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - type = Type::tboolean; - if (e2->type->ty == Tvoid) - type = Type::tvoid; - if (e2->op == TOKtype || e2->op == TOKimport) - error("%s is not an expression", e2->toChars()); - return this; -} - -Expression *AndAndExp::checkToBoolean() -{ - e2 = e2->checkToBoolean(); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - -int AndAndExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return e1->checkSideEffect(2) || e2->checkSideEffect(2); - } - else - { - e1->checkSideEffect(1); - return e2->checkSideEffect(flag); - } -} - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - if (t2b->ty != Taarray) - { - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - type = Type::terror; - } - else - { - TypeAArray *ta = (TypeAArray *)t2b; - - // Special handling for array keys - if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) - { - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - } - - // Return type is pointer to value - type = ta->nextOf()->pointerTo(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tvoid; -} - -/************************************************************/ - -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(CmpExp), e1, e2) -{ -} - -Expression *CmpExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - -#if LOGSEMANTIC - printf("CmpExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) - { - error("do not use null when comparing class types"); - } - - e = op_overload(sc); - if (e) - { - if (!e->type->isscalar() && e->type->equals(e1->type)) - { - error("recursive opCmp expansion"); - e = new ErrorExp(); - } - else - { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - } - return e; - } - - typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - error("array comparison type mismatch, %s vs %s", t1->nextOf()->toChars(), t2->nextOf()->toChars()); - e = this; - } - else if (t1->ty == Tstruct || t2->ty == Tstruct || - (t1->ty == Tclass && t2->ty == Tclass)) - { - if (t2->ty == Tstruct) - error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); - else - error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); - e = this; - } -#if 1 - else if (t1->iscomplex() || t2->iscomplex()) - { - error("compare not defined for complex operands"); - e = new ErrorExp(); - } -#endif - else - { e1->rvalue(); - e2->rvalue(); - e = this; - } - //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars()); - return e; -} - -int CmpExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(EqualExp), e1, e2) -{ - assert(op == TOKequal || op == TOKnotequal); -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - Type *t2; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - if (e1->type->toBasetype()->ty == Tclass && e2->op == TOKnull || - e2->type->toBasetype()->ty == Tclass && e1->op == TOKnull) - { - error("use '%s' instead of '%s' when comparing with null", - Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), - Token::toChars(op)); - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - e = typeCombine(sc); - type = Type::tboolean; - - // Special handling for array comparisons - if (!arrayTypeCompatible(loc, e1->type, e2->type)) - { - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - } - return e; -} - -int EqualExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(IdentityExp), e1, e2) -{ -} - -Expression *IdentityExp::semantic(Scope *sc) -{ - if (type) - return this; - - BinExp::semanticp(sc); - type = Type::tboolean; - typeCombine(sc); - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - return this; -} - -int IdentityExp::isBit() -{ - return TRUE; -} - - -/****************************************************************/ - -CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) - : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) -{ - this->econd = econd; -} - -Expression *CondExp::syntaxCopy() -{ - return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); -} - - -Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - -#if LOGSEMANTIC - printf("CondExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - econd = econd->semantic(sc); - econd = resolveProperties(sc, econd); - econd = econd->checkToPointer(); - econd = econd->checkToBoolean(); - -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - - cs0 = sc->callSuper; - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; - sc->callSuper = cs0; - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - sc->mergeCallSuper(loc, cs1); - - - // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; - if (t1->ty == Tvoid || t2->ty == Tvoid) - type = Type::tvoid; - else if (t1 == t2) - type = t1; - else - { - typeCombine(sc); - switch (e1->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e2 = e2->castTo(sc, e1->type); - break; - } - switch (e2->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e1 = e1->castTo(sc, e2->type); - break; - } - if (type->toBasetype()->ty == Tarray) - { - e1 = e1->castTo(sc, type); - e2 = e2->castTo(sc, type); - } - } -#if 0 - printf("res: %s\n", type->toChars()); - printf("e1 : %s\n", e1->type->toChars()); - printf("e2 : %s\n", e2->type->toChars()); -#endif - return this; -} - -#if DMDV2 -int CondExp::isLvalue() -{ - return e1->isLvalue() && e2->isLvalue(); -} -#endif - -Expression *CondExp::toLvalue(Scope *sc, Expression *ex) -{ - PtrExp *e; - - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - e = new PtrExp(loc, this, type); - - e1 = e1->addressOf(sc); - //e1 = e1->toLvalue(sc, NULL); - - e2 = e2->addressOf(sc); - //e2 = e2->toLvalue(sc, NULL); - - typeCombine(sc); - - type = e2->type; - return e; -} - -Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("conditional expression %s is not a modifiable lvalue", toChars()); - return this; -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - - -Expression *CondExp::checkToBoolean() -{ - e1 = e1->checkToBoolean(); - e2 = e2->checkToBoolean(); - return this; -} - -int CondExp::checkSideEffect(int flag) -{ - if (flag == 2) - { - return econd->checkSideEffect(2) || - e1->checkSideEffect(2) || - e2->checkSideEffect(2); - } - else - { - econd->checkSideEffect(1); - e1->checkSideEffect(flag); - return e2->checkSideEffect(flag); - } -} - -#if DMDV2 -int CondExp::canThrow() -{ - return econd->canThrow() || e1->canThrow() || e2->canThrow(); -} -#endif - -void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, econd, PREC_oror); - buf->writestring(" ? "); - expToCBuffer(buf, hgs, e1, PREC_expr); - buf->writestring(" : "); - expToCBuffer(buf, hgs, e2, PREC_cond); -} - -/************************************************************/ - -#if IN_LLVM - -// Strictly LDC specific stuff - -GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) - : UnaExp(loc, TOKgep, sizeof(GEPExp), e) -{ - index = idx; - ident = id; -} - -void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -Expression* GEPExp::toLvalue(Scope* sc, Expression* e) -{ - // GEP's are always lvalues, at least in the "LLVM sense" ... - return this; -} - -#endif - -/****************************************************************/ - -DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) - : Expression(loc, TOKdefault, size) -{ - this->subop = subop; -} - -void DefaultInitExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(subop)); -} - -/****************************************************************/ - -FileInitExp::FileInitExp(Loc loc) - : DefaultInitExp(loc, TOKfile, sizeof(FileInitExp)) -{ -} - -Expression *FileInitExp::semantic(Scope *sc) -{ - //printf("FileInitExp::semantic()\n"); - type = Type::tchar->invariantOf()->arrayOf(); - return this; -} - -Expression *FileInitExp::resolve(Loc loc, Scope *sc) -{ - //printf("FileInitExp::resolve() %s\n", toChars()); - const char *s = loc.filename ? loc.filename : sc->module->ident->toChars(); - Expression *e = new StringExp(loc, (char *)s); - e = e->semantic(sc); - e = e->castTo(sc, type); - return e; -} - -/****************************************************************/ - -LineInitExp::LineInitExp(Loc loc) - : DefaultInitExp(loc, TOKline, sizeof(LineInitExp)) -{ -} - -Expression *LineInitExp::semantic(Scope *sc) -{ - type = Type::tint32; - return this; -} - -Expression *LineInitExp::resolve(Loc loc, Scope *sc) -{ - Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32); - e = e->castTo(sc, type); - return e; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include +#include +#include +#if _MSC_VER +#include +#else +#if IN_DMD +#include +#endif +#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" +#if IN_DMD +#include "port.h" +#endif +#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" + +#if IN_DMD +Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); +#endif +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->nestedrefs = 1; + + e1 = new VarExp(loc, f->vthis); + } + } + 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 (parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + parent = ti->parent; + else + break; + } + + fd = 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) + { +#if 0 + if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty) + error(e->loc, "not a property %s\n", e->toChars()); +#endif + 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 = (Expression *)exps->data[i]; + + if (!e->type) + { error("%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->data[i] = (void *)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 = (Expression *)exps->data[i]; + + e = resolveProperties(sc, e); + if (!e->type) + { 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.semantic(sc); + exps->data[j0] = (void *)condexp.e1; + e = condexp.e2; + j0 = i; + e0 = e; + t0 = e0->type; + } + } + else + { j0 = i; + e0 = e; + t0 = e->type; + } + exps->data[i] = (void *)e; + } + + if (t0) + { + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e = e->implicitCastTo(sc, t0); + exps->data[i] = (void *)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 +} + +/**************************************** + * 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 = (Expression *)exps->data[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->data[i] = (void *) arg; + + //arg->rvalue(); +#if 0 + if (arg->type->ty == Tfunction) + { + arg = new AddrExp(arg->loc, arg); + arg = arg->semantic(sc); + exps->data[i] = (void *) 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 + * 5. call copy constructor for struct value arguments + * Returns: + * return type from function + */ + +Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, + Expressions *arguments, FuncDeclaration *fd) +{ + //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()); + + unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + + unsigned wildmatch = 0; + int done = 0; + for (size_t i = 0; i < n; i++) + { + Expression *arg; + + if (i < nargs) + arg = (Expression *)arguments->data[i]; + else + arg = NULL; + Type *tb; + + 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 tf->next; + } + 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()); + if (arg->implicitConvTo(p->type)) + { + if (nargs != nparams) + { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + return tf->next; + } + 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 = (Expression *)arguments->data[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)); + ConstructExp *ae = new ConstructExp(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 tf->next; + } + 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 = new ErrorExp(); + goto L3; + } + if (p->type->isWild() && tf->next->isWild()) + { Type *t = p->type; + MATCH m = arg->implicitConvTo(t); + if (m == MATCHnomatch) + { t = t->constOf(); + m = arg->implicitConvTo(t); + if (m == MATCHnomatch) + { t = t->sharedConstOf(); + m = arg->implicitConvTo(t); + } + wildmatch |= p->type->wildMatch(arg->type); + } + arg = arg->implicitCastTo(sc, t); + } + else + arg = arg->implicitCastTo(sc, p->type); + arg = arg->optimize(WANTvalue); + } + } + if (p->storageClass & STCref) + { + arg = arg->toLvalue(sc, arg); + } + else if (p->storageClass & STCout) + { + arg = arg->modifiableLvalue(sc, arg); + } + + tb = arg->type->toBasetype(); +// LDC we don't want this! +#if !IN_LLVM +#if !SARRAYVALUE + // Convert static arrays to pointers + if (tb->ty == Tsarray) + { + arg = arg->checkToPointer(); + } +#endif +#endif +#if DMDV2 + if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +#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)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + 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 (arg->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)arg; + 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 + 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 (arg->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)arg; + if ( +#if DMDV2 + se->hasOverloads && +#endif + !se->var->isFuncDeclaration()->isUnique()) + arg->error("function %s is overloaded", arg->toChars()); + } + arg->rvalue(); + } + arg = arg->optimize(WANTvalue); + L3: + 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 + // If inferring return type, and semantic3() needs to be run if not already run + if (!tf->next && fd->inferRetType) + fd->semantic3(fd->scope); + + Type *tret = tf->next; + if (wildmatch) + { /* Adjust function return type based on wildmatch + */ + //printf("wildmatch = x%x\n", wildmatch); + assert(tret->isWild()); + if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) + tret = tret->constOf(); + else if (wildmatch & MODimmutable) + tret = tret->invariantOf(); + else + { assert(wildmatch & MODmutable); + tret = tret->mutableOf(); + } + } + return tret; +} + +/************************************************** + * 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 aop] == 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; + this->parens = 0; + 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.errors; + global.gag++; + Expression *e = semantic(sc); + global.gag--; + if (errors != global.errors) + { + global.errors = 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 ); + } +} + +void Expression::rvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + { error("expression %s is void and has no value", toChars()); +#if 0 + dump(0); + halt(); +#endif + type = Type::terror; + } +} + +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 0; +} + +real_t Expression::toImaginary() +{ + error("Floating point constant expression expected instead of %s", toChars()); + return 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; +#endif +} + +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() && type->toBasetype() != Type::terror) + error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); + rvalue(); +} + +void Expression::checkNoBool() +{ + if (type->toBasetype()->ty == Tbool) + error("operation not allowed on bool '%s'", toChars()); +} + +Expression *Expression::checkIntegral() +{ + if (!type->isintegral()) + { if (type->toBasetype() != Type::terror) + error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); + return new ErrorExp(); + } + rvalue(); + 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(); + } + rvalue(); + return this; +} + +void Expression::checkDeprecated(Scope *sc, Dsymbol *s) +{ + s->checkDeprecated(loc, sc); +} + +#if DMDV2 +void Expression::checkPurity(Scope *sc, FuncDeclaration *f) +{ +#if 1 + if (sc->func) + { + /* Given: + * void f() + * { pure void g() + * { + * void h() + * { + * void i() { } + * } + * } + * } + * g() can call h() but not f() + * i() can call h() and g() but not f() + */ + FuncDeclaration *outerfunc = sc->func; + // Find the closest pure parent of the calling function + while (outerfunc->toParent2() && + !outerfunc->isPure() && + outerfunc->toParent2()->isFuncDeclaration()) + { + outerfunc = outerfunc->toParent2()->isFuncDeclaration(); + } + // Find the closest pure parent of the called function + FuncDeclaration *calledparent = f; + while (calledparent->toParent2() && !calledparent->isPure() + && calledparent->toParent2()->isFuncDeclaration() ) + { + calledparent = calledparent->toParent2()->isFuncDeclaration(); + } + // If the caller has a pure parent, then either the called func must be pure, + // OR, they must have the same pure parent. + if (outerfunc->isPure() && !sc->intypeof && + !(f->isPure() || (calledparent == outerfunc))) + { + error("pure function '%s' cannot call impure function '%s'", + outerfunc->toChars(), f->toChars()); + } + } +#else + if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) + error("pure function '%s' cannot call impure function '%s'", + sc->func->toChars(), f->toChars()); +#endif +} + +void Expression::checkSafety(Scope *sc, FuncDeclaration *f) +{ + if (sc->func && sc->func->isSafe() && !sc->intypeof && + !f->isSafe() && !f->isTrusted()) + error("safe function '%s' cannot call system function '%s'", + 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 == TOKerror) + { // Error should have already been printed + } + else 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(Scope *sc) +{ + // Default is 'yes' - do nothing + +#ifdef DEBUG + if (!type) + dump(0); +#endif + + // Structs can be converted to bool using opCast(bool)() + Type *tb = type->toBasetype(); + if (tb->ty == Tstruct) + { AggregateDeclaration *ad = ((TypeStruct *)tb)->sym; + /* Don't really need to check for opCast first, but by doing so we + * get better error messages if it isn't there. + */ + Dsymbol *fd = search_function(ad, Id::cast); + if (fd) + { + Expression *e = new CastExp(loc, this, Type::tbool); + e = e->semantic(sc); + return e; + } + } + + if (!type->checkBoolean()) + { if (type->toBasetype() != Type::terror) + error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); + return new ErrorExp(); + } + return this; +} + +/**************************** + */ + +Expression *Expression::checkToPointer() +{ + //printf("Expression::checkToPointer()\n"); + Expression *e = this; + +#if !SARRAYVALUE + // If C static array, convert to pointer + Type *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(); + } +#endif + return e; +} + +/****************************** + * Take address of expression. + */ + +Expression *Expression::addressOf(Scope *sc) +{ + Expression *e; + + //printf("Expression::addressOf()\n"); + e = toLvalue(sc, NULL); + e = new AddrExp(loc, e); + e->type = type->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 +} + +/**************************************** + * Resolve __LINE__ and __FILE__ to loc. + */ + +Expression *Expression::resolveLoc(Loc loc, Scope *sc) +{ + return this; +} + +Expressions *Expression::arraySyntaxCopy(Expressions *exps) +{ Expressions *a = NULL; + + if (exps) + { + a = new Expressions(); + a->setDim(exps->dim); + for (int 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->toHeadMutable()->equals(ne->type->toHeadMutable())) && + 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) + { + printf("e = %p, ty = %d\n", this, type->ty); + type->print(); + assert(0); + } + break; + } + break; + } + return value; +} + +real_t IntegerExp::toReal() +{ + Type *t; + + toInteger(); + t = type->toBasetype(); + if (t->ty == Tuns64) + return (real_t)(d_uns64)value; + else + return (real_t)(d_int64)value; +} + +real_t IntegerExp::toImaginary() +{ + return (real_t) 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: + if (v == '\'') + buf->writestring("'\\''"); + else if (isprint(v) && v != '\\') + buf->printf("'%c'", (int)v); + else + buf->printf("'\\x%02x'", (int)v); + 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; +} + +Expression *ErrorExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +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 : 0; +} + +real_t RealExp::toImaginary() +{ + return type->isreal() ? 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) +{ +//#if 1 +// return (Port::isNan(x1) && Port::isNan(x2)) || +//#elif __APPLE__ +#if __APPLE__ + return (__inline_isnan(x1) && __inline_isnan(x2)) || +#else + return // special case nans + (isnan(x1) && isnan(x2)) || +#endif + // and zero, in order to distinguish +0 from -0 + (x1 == 0 && x2 == 0 && 1./x1 == 1./x2) || + // otherwise just compare + (x1 != 0. && x1 == x2); +} + +int RealExp::equals(Object *o) +{ RealExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKfloat64 && + ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + 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 + buf->printf("%La", value); // ensure exact duplication + + 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 1 +// if (Port::isNan(value)) +//#elif __APPLE__ +#if __APPLE__ + if (__inline_isnan(value)) +#else + if (isnan(value)) +#endif + 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->toHeadMutable()->equals(ne->type->toHeadMutable())) && + 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) + { +#if DMDV2 + /* Disallow shadowing + */ + // First find the scope of the with + Scope *scwith = sc; + while (scwith->scopesym != scopesym) + { scwith = scwith->enclosing; + assert(scwith); + } + // Look at enclosing scopes for symbols with the same name, + // in the same function + for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing) + { Dsymbol *s2; + + if (scx->scopesym && scx->scopesym->symtab && + (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && + s != s2) + { + error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars()); + } + } +#endif + 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 f is really a function template, + * then replace f with the function template declaration. + */ + 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) + { + TemplateDeclaration *tempdecl = ti->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; + } + } + // Haven't done overload resolution yet, so pass 1 + e = new DsymbolExp(loc, s, 1); + } + 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, int hasOverloads) + : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) +{ + this->s = s; + this->hasOverloads = hasOverloads; +} + +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; + OverloadSet *o; + Declaration *d; + 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); + s = s->toAlias(); + //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); + if (!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; + 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->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->storage_class & STCmanifest) && v->init) + { + e = v->init->toExpression(); + if (!e) + { error("cannot make expression out of initializer for %s", v->toChars()); + return new ErrorExp(); + } + e = e->semantic(sc); + 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 + f->semantic(f->scope); + if (!f->type->deco) + { + error("forward reference to %s", toChars()); + return new ErrorExp(); + } + return new VarExp(loc, f, hasOverloads); + } + o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } + 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) + { + return new TypeExp(loc, t); + } + + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { + e = new TupleExp(loc, tup); + e = e->semantic(sc); + return e; + } + + TemplateInstance *ti = s->isTemplateInstance(); + if (ti && !global.errors) + { if (!ti->semanticRun) + ti->semantic(sc); + s = ti->inst->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; + } + +Lerr: + 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) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + int nested = 0; + +#if LOGSEMANTIC + printf("ThisExp::semantic()\n"); +#endif + if (type) + { //assert(global.errors || var); + return this; + } + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing struct or class + for (Dsymbol *s = sc->parent; 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; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); // fd is the uplevel function with the 'this' variable + 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) +{ FuncDeclaration *fd; + FuncDeclaration *fdthis; + ClassDeclaration *cd; + Dsymbol *s; + +#if LOGSEMANTIC + printf("SuperExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + /* Special case for typeof(this) and typeof(super) since both + * should work even if they are not inside a non-static member function + */ + if (sc->intypeof) + { + // Find enclosing class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + ClassDeclaration *cd; + + if (!s) + { + error("%s is not in a class scope", toChars()); + goto Lerr; + } + 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; + } + } + } + + fdthis = sc->parent->isFuncDeclaration(); + fd = hasThis(sc); + 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; + } + + 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; +} + +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; +} + +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; +} + +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; +} + +#if 0 +Expression *StringExp::syntaxCopy() +{ + printf("StringExp::syntaxCopy() %s\n", toChars()); + return copy(); +} +#endif + +int StringExp::equals(Object *o) +{ + //printf("StringExp::equals('%s')\n", o->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)); + type = new TypeDArray(Type::tdchar->invariantOf()); + 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)); + type = new TypeDArray(Type::twchar->invariantOf()); + committed = 1; + break; + + case 'c': + committed = 1; + default: + //type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); + type = new TypeDArray(Type::tchar->invariantOf()); + break; + } + type = type->semantic(loc, sc); + //type = type->invariantOf(); + //printf("type = %s\n", type->toChars()); + } + 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; +} + +/**************************************** + * 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) +{ + // 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; + + if (len1 == len2) + { + switch (sz) + { + case 1: + return strcmp((char *)string, (char *)se2->string); + + 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 + +Expression *StringExp::toLvalue(Scope *sc, Expression *e) +{ + //printf("StringExp::toLvalue(%s)\n", toChars()); + return this; +} + +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('"'); + 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; + } + } + 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->writeByte(m); + buf->printf("%d_", qlen); + for (size_t i = 0; i < qlen; i++) + buf->printf("%02x", q[i]); +} + +/************************ ArrayLiteralExp ************************************/ + +// [ e1, e2, e3, ... ] + +ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) + : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) +{ + this->elements = elements; +} + +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) +{ +#if LOGSEMANTIC + printf("ArrayLiteralExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + /* Perhaps an empty array literal [ ] should be rewritten as null? + */ + + arrayExpressionSemantic(elements, sc); // run semantic() on each element + expandTuples(elements); + + Type *t0; + elements = arrayExpressionToCommonType(sc, elements, &t0); + + type = t0->arrayOf(); + //type = new TypeSArray(t0, new IntegerExp(elements->dim)); + type = type->semantic(loc, sc); + return this; +} + +int ArrayLiteralExp::checkSideEffect(int flag) +{ int f = 0; + + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + + f |= e->checkSideEffect(2); + } + 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 + +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%zu", dim); + for (size_t i = 0; i < dim; i++) + { Expression *e = (Expression *)elements->data[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; +} + +Expression *AssocArrayLiteralExp::syntaxCopy() +{ + return new AssocArrayLiteralExp(loc, + arraySyntaxCopy(keys), arraySyntaxCopy(values)); +} + +Expression *AssocArrayLiteralExp::semantic(Scope *sc) +{ Expression *e; + +#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); + + 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->checkSideEffect(2); + f |= value->checkSideEffect(2); + } + 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%zu", 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; +} + +Expression *StructLiteralExp::syntaxCopy() +{ + return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), stype); +} + +Expression *StructLiteralExp::semantic(Scope *sc) +{ Expression *e; + int nfields = sd->fields.dim - sd->isnested; + +#if LOGSEMANTIC + printf("StructLiteralExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + elements = arrayExpressionSemantic(elements, sc); // run semantic() on each element + 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 >= nfields) + { error("more initializers than fields of %s", sd->toChars()); + return new ErrorExp(); + } + Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + if (v->offset < offset) + { error("overlapping initialization for %s", v->toChars()); + return new ErrorExp(); + } + offset = v->offset + v->type->size(); + + Type *telem = v->type; + if (stype) + telem = telem->addMod(stype->mod); + 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 < nfields; i++) + { Dsymbol *s = (Dsymbol *)sd->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v); + assert(!v->isThisDeclaration()); + + if (v->offset < offset) + { e = NULL; + sd->hasUnions = 1; + } + else + { + if (v->init) + { 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); + e = i2->toExpression(); + 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 + +/* +Removed in LDC. See declaration. +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->checkSideEffect(2); + } + 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%zu", 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::rvalue() +{ + error("type %s has no value", toChars()); +} + +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 && !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()); + } + } + else + { + //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); + //printf("\tparent = '%s'\n", sds->parent->toChars()); + sds->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 + { + 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()); +} + +void TemplateExp::rvalue() +{ + error("template %s has no value", toChars()); +} + +/********************** 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) +{ int i; + 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 (int i = 0; i < cd->vtbl.dim; i++) + { FuncDeclaration *fd = ((Dsymbol *)cd->vtbl.data[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 + } +#if 1 + 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 + else if (fdn) + { /* The nested class cd is nested inside a function, + * we'll let getEthis() look for errors. + */ + //printf("nested class %s is nested inside function %s, we're in %s\n", cd->toChars(), fdn->toChars(), sc->func->toChars()); + if (thisexp) + { // Because thisexp cannot be a function frame pointer + error("e.new is only for allocating nested classes"); + goto Lerr; + } + } +#endif + else + assert(0); + } + else if (thisexp) + { error("e.new is only for allocating nested classes"); + goto Lerr; + } + + FuncDeclaration *f = NULL; + if (cd->ctor) + f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f->isCtorDeclaration(); + assert(member); + + cd->accessCheck(loc, sc, member); + + tf = (TypeFunction *)f->type; + + if (!arguments) + arguments = new Expressions(); + functionParameters(loc, sc, tf, arguments, f); + + type = type->addMod(tf->nextOf()->mod); + } + 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); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionParameters(loc, sc, tf, newargs, f); + } + 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; + TypeFunction *tf; + + FuncDeclaration *f = NULL; + if (sd->ctor) + f = resolveFuncCall(sc, loc, sd->ctor, NULL, NULL, arguments, 0); + if (f) + { + checkDeprecated(sc, f); + member = f->isCtorDeclaration(); + assert(member); + + sd->accessCheck(loc, sc, member); + + tf = (TypeFunction *)f->type; + type = tf->next; + + if (!arguments) + arguments = new Expressions(); + functionParameters(loc, sc, tf, arguments, f); + } + else + { + if (arguments && arguments->dim) + { error("no constructor for %s", sd->toChars()); + goto Lerr; + } + } + + + if (sd->aggNew) + { + // Prepend the uint size argument to newargs[] + Expression *e = new IntegerExp(loc, sd->size(loc), Type::tuns32); + if (!newargs) + newargs = new Expressions(); + newargs->shift(e); + + f = sd->aggNew->overloadResolve(loc, NULL, newargs); + allocator = f->isNewDeclaration(); + assert(allocator); + + tf = (TypeFunction *)f->type; + functionParameters(loc, sc, tf, newargs, f); +#if 0 + e = new VarExp(loc, f); + e = new CallExp(loc, e, newargs); + e = e->semantic(sc); + e->type = type->pointerTo(); + return e; +#endif + } + else + { + if (newargs && newargs->dim) + { error("no allocator for %s", sd->toChars()); + goto Lerr; + } + } + + 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 = (Expression *)arguments->data[i]; + arg = resolveProperties(sc, arg); + arg = arg->implicitCastTo(sc, Type::tsize_t); + arg = arg->optimize(WANTvalue); + if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0) + { error("negative array index %s", arg->toChars()); + goto Lerr; + } + arguments->data[i] = (void *) 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() +{ + return 1; +} +#endif + +void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + 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) +{ int i; + + 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, int hasOverloads) + : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) +{ + 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, int hasOverloads) + : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) +{ + //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); + //if (strcmp(var->ident->toChars(), "func") == 0) halt(); + this->type = var->type; +} + +int VarExp::equals(Object *o) +{ VarExp *ne; + + if (this == o || + (((Expression *)o)->op == TOKvar && + ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && + var == ne->var)) + return 1; + return 0; +} + +Expression *VarExp::semantic(Scope *sc) +{ FuncLiteralDeclaration *fd; + +#if LOGSEMANTIC + printf("VarExp::semantic(%s)\n", toChars()); +#endif +// if (var->sem == SemanticStart && var->scope) // if forward referenced +// var->semantic(sc); + 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 + } + + /* 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 0 + if ((v->isConst() || v->isImmutable()) && + type->toBasetype()->ty != Tsarray && v->init) + { + ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + //ei->exp->implicitCastTo(sc, type)->print(); + return ei->exp->implicitCastTo(sc, type); + } + } +#endif + v->checkNestedReference(sc, loc); +#if DMDV2 +#if 1 + if (sc->func && !sc->intypeof) + { + /* Given: + * void f() + * { int fx; + * pure void g() + * { int gx; + * void h() + * { int hx; + * void i() { } + * } + * } + * } + * i() can modify hx and gx but not fx + */ + + /* Determine if sc->func is pure or if any function that + * encloses it is also pure. + */ + bool hasPureParent = false; + for (FuncDeclaration *outerfunc = sc->func; outerfunc;) + { + if (outerfunc->isPure()) + { + hasPureParent = true; + break; + } + Dsymbol *parent = outerfunc->toParent2(); + if (!parent) + break; + outerfunc = parent->isFuncDeclaration(); + } + + /* Magic variable __ctfe never violates pure or safe + */ + if (v->ident != Id::ctfe) + { + /* If ANY of its enclosing functions are pure, + * it cannot do anything impure. + * If it is pure, it cannot access any mutable variables other + * than those inside itself + */ + if (hasPureParent && v->isDataseg() && + !v->isImmutable()) + { + error("pure function '%s' cannot access mutable static data '%s'", + sc->func->toChars(), v->toChars()); + } + else if (sc->func->isPure() && + sc->parent->pastMixin() != v->parent->pastMixin() && + !v->isImmutable() && + !(v->storage_class & STCmanifest)) + { + error("pure nested function '%s' cannot access mutable data '%s'", + sc->func->toChars(), v->toChars()); + if (v->isEnumDeclaration()) + error("enum"); + } + } + + /* Do not allow safe functions to access __gshared data + */ + if (sc->func->isSafe() && v->storage_class & STCgshared) + error("safe function '%s' cannot access __gshared data '%s'", + sc->func->toChars(), v->toChars()); + } +#else + 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 +#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 scope 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 new ErrorExp(); + } + return this; +} + +Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); + //if (type && type->toBasetype()->ty == Tsarray) + //error("cannot change reference to static array '%s'", var->toChars()); + + var->checkModify(loc, sc, type); + + // 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 = (Object *)tup->objects->data[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) +{ TupleExp *ne; + + if (this == o) + return 1; + if (((Expression *)o)->op == TOKtuple) + { + TupleExp *te = (TupleExp *)o; + if (exps->dim != te->exps->dim) + return 0; + for (size_t i = 0; i < exps->dim; i++) + { Expression *e1 = (Expression *)exps->data[i]; + Expression *e2 = (Expression *)te->exps->data[i]; + + if (!e1->equals(e2)) + return 0; + } + return 1; + } + return 0; +} + +Expression *TupleExp::syntaxCopy() +{ + return new TupleExp(loc, arraySyntaxCopy(exps)); +} + +Expression *TupleExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("+TupleExp::semantic(%s)\n", toChars()); +#endif + if (type) + return this; + + // Run semantic() on each argument + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->semantic(sc); + if (!e->type) + { error("%s has no value", e->toChars()); + e = new ErrorExp(); + } + exps->data[i] = (void *)e; + } + + expandTuples(exps); + if (0 && exps->dim == 1) + { + return (Expression *)exps->data[0]; + } + type = new TypeTuple(exps); + type = type->semantic(loc, sc); + //printf("-TupleExp::semantic(%s)\n", toChars()); + return this; +} + +void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("tuple("); + argsToCBuffer(buf, exps, hgs); + buf->writeByte(')'); +} + +int TupleExp::checkSideEffect(int flag) +{ int f = 0; + + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + f |= e->checkSideEffect(2); + } + if (flag == 0 && f == 0) + Expression::checkSideEffect(0); + return f; +} + +#if DMDV2 +int TupleExp::canThrow() +{ + return arrayExpressionCanThrow(exps); +} +#endif + +void TupleExp::checkEscape() +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + e->checkEscape(); + } +} + +/******************************** FuncExp *********************************/ + +FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd) + : Expression(loc, TOKfunction, sizeof(FuncExp)) +{ + this->fd = fd; +} + +Expression *FuncExp::syntaxCopy() +{ + return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); +} + +Expression *FuncExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("FuncExp::semantic(%s)\n", toChars()); +#endif + if (!type) + { + fd->semantic(sc); + //fd->parent = sc->parent; + if (global.errors) + { + } + else + { + fd->semantic2(sc); + if (!global.errors || + // need to infer return type + (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) + { + fd->semantic3(sc); + + if (!global.errors && global.params.useInline) + fd->inlineScan(); + } + } + + // need to infer return type + if (global.errors && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) + ((TypeFunction *)fd->type)->next = Type::terror; + + // Type is a "delegate to" or "pointer to" the function literal + if (fd->isNested()) + { + type = new TypeDelegate(fd->type); + type = type->semantic(loc, sc); + } + else + { + type = fd->type->pointerTo(); + } + fd->tookAddressOf++; + } + return this; +} + +char *FuncExp::toChars() +{ + return fd->toChars(); +} + +void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + fd->toCBuffer(buf, hgs); + //buf->writestring(fd->toChars()); +} + + +/******************************** DeclarationExp **************************/ + +DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) + : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) +{ + this->declaration = declaration; +} + +Expression *DeclarationExp::syntaxCopy() +{ + return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); +} + +Expression *DeclarationExp::semantic(Scope *sc) +{ + if (type) + return this; + +#if LOGSEMANTIC + printf("DeclarationExp::semantic() %s\n", toChars()); +#endif + + /* This is here to support extern(linkage) declaration, + * where the extern(linkage) winds up being an AttribDeclaration + * wrapper. + */ + Dsymbol *s = declaration; + + AttribDeclaration *ad = declaration->isAttribDeclaration(); + if (ad) + { + if (ad->decl && ad->decl->dim == 1) + s = (Dsymbol *)ad->decl->data[0]; + } + + if (s->isVarDeclaration()) + { // Do semantic() on initializer first, so: + // int a = a; + // will be illegal. + declaration->semantic(sc); + s->parent = sc->parent; + } + + //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); + // Insert into both local scope and function scope. + // Must be unique in both. + if (s->ident) + { + if (!sc->insert(s)) + error("declaration %s is already defined", s->toPrettyChars()); + else if (sc->func) + { VarDeclaration *v = s->isVarDeclaration(); + if (s->isFuncDeclaration() && + !sc->func->localsymtab->insert(s)) + error("declaration %s is already defined in another scope in %s", s->toPrettyChars(), sc->func->toChars()); + else if (!global.params.useDeprecated) + { // Disallow shadowing + + for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) + { Dsymbol *s2; + + if (scx->scopesym && scx->scopesym->symtab && + (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && + s != s2) + { + error("shadowing declaration %s is deprecated", s->toPrettyChars()); + } + } + } + } + } + if (!s->isVarDeclaration()) + { + Scope *sc2 = sc; + if (sc2->stc & (STCpure | STCnothrow)) + sc2 = sc->push(); + sc2->stc &= ~(STCpure | STCnothrow); + declaration->semantic(sc2); + if (sc2 != sc) + sc2->pop(); + s->parent = sc->parent; + } + if (!global.errors) + { + declaration->semantic2(sc); + if (!global.errors) + { + declaration->semantic3(sc); + + if (!global.errors && global.params.useInline) + declaration->inlineScan(); + } + } + + type = Type::tvoid; + return this; +} + +int DeclarationExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int DeclarationExp::canThrow() +{ + VarDeclaration *v = declaration->isVarDeclaration(); + if (v && v->init) + { ExpInitializer *ie = v->init->isExpInitializer(); + return ie && ie->exp->canThrow(); + } + return 0; +} +#endif + +void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + declaration->toCBuffer(buf, hgs); +} + + +/************************ TypeidExp ************************************/ + +/* + * typeid(int) + */ + +TypeidExp::TypeidExp(Loc loc, Object *o) + : Expression(loc, TOKtypeid, sizeof(TypeidExp)) +{ + this->obj = o; +} + + +Expression *TypeidExp::syntaxCopy() +{ + return new TypeidExp(loc, objectSyntaxCopy(obj)); +} + + +Expression *TypeidExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("TypeidExp::semantic() %s\n", toChars()); +#endif + Type *ta = isType(obj); + Expression *ea = isExpression(obj); + Dsymbol *sa = isDsymbol(obj); + + //printf("ta %p ea %p sa %p\n", ta, ea, sa); + + if (ta) + { + ta->resolve(loc, sc, &ea, &ta, &sa); + } + + if (ea) + { + ea = ea->semantic(sc); + ea = resolveProperties(sc, ea); + ta = ea->type; + if (ea->op == TOKtype) + ea = NULL; + } + + if (!ta) + { + //printf("ta %p ea %p sa %p\n", ta, ea, sa); + error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : "")); + return new ErrorExp(); + } + + if (ea && ta->toBasetype()->ty == Tclass) + { /* Get the dynamic type, which is .classinfo + */ + e = new DotIdExp(ea->loc, ea, Id::classinfo); + e = e->semantic(sc); + } + else + { /* Get the static type + */ + e = ta->getTypeInfo(sc); + if (e->loc.linnum == 0) + e->loc = loc; // so there's at least some line number info + if (ea) + { + e = new CommaExp(loc, ea, e); // execute ea + e = e->semantic(sc); + } + } + return e; +} + +void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("typeid("); + ObjectToCBuffer(buf, hgs, obj); + buf->writeByte(')'); +} + +/************************ TraitsExp ************************************/ +#if DMDV2 +/* + * __traits(identifier, args...) + */ + +TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) + : Expression(loc, TOKtraits, sizeof(TraitsExp)) +{ + this->ident = ident; + this->args = args; +} + + +Expression *TraitsExp::syntaxCopy() +{ + return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); +} + + +void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("__traits("); + buf->writestring(ident->toChars()); + if (args) + { + for (int i = 0; i < args->dim; i++) + { + buf->writeByte(','); + Object *oarg = (Object *)args->data[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + } + buf->writeByte(')'); +} +#endif + +/************************************************************/ + +HaltExp::HaltExp(Loc loc) + : Expression(loc, TOKhalt, sizeof(HaltExp)) +{ +} + +Expression *HaltExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("HaltExp::semantic()\n"); +#endif + type = Type::tvoid; + return this; +} + +int HaltExp::checkSideEffect(int flag) +{ + return 1; +} + +void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("halt"); +} + +/************************************************************/ + +IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, + Type *tspec, enum TOK tok2, TemplateParameters *parameters) + : Expression(loc, TOKis, sizeof(IsExp)) +{ + this->targ = targ; + this->id = id; + this->tok = tok; + this->tspec = tspec; + this->tok2 = tok2; + this->parameters = parameters; +} + +Expression *IsExp::syntaxCopy() +{ + // This section is identical to that in TemplateDeclaration::syntaxCopy() + TemplateParameters *p = NULL; + if (parameters) + { + p = new TemplateParameters(); + p->setDim(parameters->dim); + for (int i = 0; i < p->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + p->data[i] = (void *)tp->syntaxCopy(); + } + } + + return new IsExp(loc, + targ->syntaxCopy(), + id, + tok, + tspec ? tspec->syntaxCopy() : NULL, + tok2, + p); +} + +Expression *IsExp::semantic(Scope *sc) +{ Type *tded; + + /* is(targ id tok tspec) + * is(targ id : tok2) + * is(targ id == tok2) + */ + + //printf("IsExp::semantic(%s)\n", toChars()); + if (id && !(sc->flags & SCOPEstaticif)) + { error("can only declare type aliases within static if conditionals"); + return new ErrorExp(); + } + + Type *t = targ->trySemantic(loc, sc); + if (!t) + goto Lno; // errors, so condition is false + targ = t; + if (tok2 != TOKreserved) + { + switch (tok2) + { + case TOKtypedef: + if (targ->ty != Ttypedef) + goto Lno; + tded = ((TypeTypedef *)targ)->sym->basetype; + break; + + case TOKstruct: + if (targ->ty != Tstruct) + goto Lno; + if (((TypeStruct *)targ)->sym->isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKunion: + if (targ->ty != Tstruct) + goto Lno; + if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKclass: + if (targ->ty != Tclass) + goto Lno; + if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; + + case TOKinterface: + if (targ->ty != Tclass) + goto Lno; + if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) + goto Lno; + tded = targ; + break; +#if DMDV2 + case TOKconst: + if (!targ->isConst()) + goto Lno; + tded = targ; + break; + + case TOKinvariant: + if (!global.params.useDeprecated) + error("use of 'invariant' rather than 'immutable' is deprecated"); + case TOKimmutable: + if (!targ->isImmutable()) + goto Lno; + tded = targ; + break; + + case TOKshared: + if (!targ->isShared()) + goto Lno; + tded = targ; + break; + + case TOKwild: + if (!targ->isWild()) + goto Lno; + tded = targ; + break; +#endif + + case TOKsuper: + // If class or interface, get the base class and interfaces + if (targ->ty != Tclass) + goto Lno; + else + { ClassDeclaration *cd = ((TypeClass *)targ)->sym; + Parameters *args = new Parameters; + args->reserve(cd->baseclasses->dim); + for (size_t i = 0; i < cd->baseclasses->dim; i++) + { BaseClass *b = (BaseClass *)cd->baseclasses->data[i]; + args->push(new Parameter(STCin, b->type, NULL, NULL)); + } + tded = new TypeTuple(args); + } + break; + + case TOKenum: + if (targ->ty != Tenum) + goto Lno; + tded = ((TypeEnum *)targ)->sym->memtype; + break; + + case TOKdelegate: + if (targ->ty != Tdelegate) + goto Lno; + tded = ((TypeDelegate *)targ)->next; // the underlying function type + break; + + case TOKfunction: + { + if (targ->ty != Tfunction) + goto Lno; + tded = targ; + + /* Generate tuple from function parameter types. + */ + assert(tded->ty == Tfunction); + Parameters *params = ((TypeFunction *)tded)->parameters; + size_t dim = Parameter::dim(params); + Parameters *args = new Parameters; + args->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Parameter *arg = Parameter::getNth(params, i); + assert(arg && arg->type); + args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); + } + tded = new TypeTuple(args); + break; + } + case TOKreturn: + /* Get the 'return type' for the function, + * delegate, or pointer to function. + */ + if (targ->ty == Tfunction) + tded = ((TypeFunction *)targ)->next; + else if (targ->ty == Tdelegate) + { tded = ((TypeDelegate *)targ)->next; + tded = ((TypeFunction *)tded)->next; + } + else if (targ->ty == Tpointer && + ((TypePointer *)targ)->next->ty == Tfunction) + { tded = ((TypePointer *)targ)->next; + tded = ((TypeFunction *)tded)->next; + } + else + goto Lno; + break; + + default: + assert(0); + } + goto Lyes; + } + else if (id && tspec) + { + /* Evaluate to TRUE if targ matches tspec. + * If TRUE, declare id as an alias for the specialized type. + */ + + assert(parameters && parameters->dim); + + Objects dedtypes; + dedtypes.setDim(parameters->dim); + dedtypes.zero(); + + MATCH m = targ->deduceType(NULL, tspec, parameters, &dedtypes); +//printf("targ: %s\n", targ->toChars()); +//printf("tspec: %s\n", tspec->toChars()); + if (m == MATCHnomatch || + (m != MATCHexact && tok == TOKequal)) + { + goto Lno; + } + else + { + tded = (Type *)dedtypes.data[0]; + if (!tded) + tded = targ; + + Objects tiargs; + tiargs.setDim(1); + tiargs.data[0] = (void *)targ; + + /* Declare trailing parameters + */ + for (int i = 1; i < parameters->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Declaration *s = NULL; + + m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); + if (m == MATCHnomatch) + goto Lno; + s->semantic(sc); + if (!sc->insert(s)) + error("declaration %s is already defined", s->toChars()); +#if 0 + Object *o = (Object *)dedtypes.data[i]; + Dsymbol *s = TemplateDeclaration::declareParameter(loc, sc, tp, o); +#endif + if (sc->sd) + s->addMember(sc, sc->sd, 1); + } + + goto Lyes; + } + } + else if (id) + { + /* Declare id as an alias for type targ. Evaluate to TRUE + */ + tded = targ; + goto Lyes; + } + else if (tspec) + { + /* Evaluate to TRUE if targ matches tspec + * is(targ == tspec) + * is(targ : tspec) + */ + tspec = tspec->semantic(loc, sc); + //printf("targ = %s, %s\n", targ->toChars(), targ->deco); + //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); + if (tok == TOKcolon) + { if (targ->implicitConvTo(tspec)) + goto Lyes; + else + goto Lno; + } + else /* == */ + { if (targ->equals(tspec)) + goto Lyes; + else + goto Lno; + } + } + +Lyes: + if (id) + { + Dsymbol *s = new AliasDeclaration(loc, id, tded); + s->semantic(sc); + if (!sc->insert(s)) + error("declaration %s is already defined", s->toChars()); + if (sc->sd) + s->addMember(sc, sc->sd, 1); + } + //printf("Lyes\n"); + return new IntegerExp(loc, 1, Type::tbool); + +Lno: + //printf("Lno\n"); + return new IntegerExp(loc, 0, Type::tbool); + +Lerr: + return new ErrorExp(); +} + +void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("is("); + targ->toCBuffer(buf, id, hgs); + if (tok2 != TOKreserved) + { + buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); + } + else if (tspec) + { + if (tok == TOKcolon) + buf->writestring(" : "); + else + buf->writestring(" == "); + tspec->toCBuffer(buf, NULL, hgs); + } +#if DMDV2 + if (parameters) + { // First parameter is already output, so start with second + for (int i = 1; i < parameters->dim; i++) + { + buf->writeByte(','); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + tp->toCBuffer(buf, hgs); + } + } +#endif + buf->writeByte(')'); +} + + +/************************************************************/ + +UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) + : Expression(loc, op, size) +{ + this->e1 = e1; +} + +Expression *UnaExp::syntaxCopy() +{ + UnaExp *e = (UnaExp *)copy(); + e->type = NULL; + e->e1 = e->e1->syntaxCopy(); + return e; +} + +Expression *UnaExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("UnaExp::semantic('%s')\n", toChars()); +#endif + e1 = e1->semantic(sc); +// if (!e1->type) +// error("%s has no value", e1->toChars()); + return this; +} + +#if DMDV2 +int UnaExp::canThrow() +{ + return e1->canThrow(); +} +#endif + +Expression *UnaExp::resolveLoc(Loc loc, Scope *sc) +{ + e1 = e1->resolveLoc(loc, sc); + return this; +} + +void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) + : Expression(loc, op, size) +{ + this->e1 = e1; + this->e2 = e2; +} + +Expression *BinExp::syntaxCopy() +{ + BinExp *e = (BinExp *)copy(); + e->type = NULL; + e->e1 = e->e1->syntaxCopy(); + e->e2 = e->e2->syntaxCopy(); + return e; +} + +Expression *BinExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("BinExp::semantic('%s')\n", toChars()); +#endif + e1 = e1->semantic(sc); + if (!e1->type && + !(op == TOKassign && e1->op == TOKdottd)) // a.template = e2 + { + error("%s has no value", e1->toChars()); + return new ErrorExp(); + } + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + return new ErrorExp(); + } + return this; +} + +Expression *BinExp::semanticp(Scope *sc) +{ + BinExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e2 = resolveProperties(sc, e2); + return this; +} + +int BinExp::checkSideEffect(int flag) +{ + if (op == TOKplusplus || + op == TOKminusminus || + op == TOKassign || + op == TOKconstruct || + op == TOKblit || + op == TOKaddass || + op == TOKminass || + op == TOKcatass || + op == TOKmulass || + op == TOKdivass || + op == TOKmodass || + op == TOKshlass || + op == TOKshrass || + op == TOKushrass || + op == TOKandass || + op == TOKorass || + op == TOKxorass || + op == TOKpowass || + op == TOKin || + op == TOKremove) + return 1; + return Expression::checkSideEffect(flag); +} + +// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary +void BinExp::checkComplexMulAssign() +{ + // Any multiplication by an imaginary or complex number yields a complex result. + // r *= c, i*=c, r*=i, i*=i are all forbidden operations. + const char *opstr = Token::toChars(op); + if ( e1->type->isreal() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.re ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if (e1->type->isimaginary() && e2->type->iscomplex()) + { + error("%s %s %s is undefined. Did you mean %s %s %s.im ?", + e1->type->toChars(), opstr, e2->type->toChars(), + e1->type->toChars(), opstr, e2->type->toChars()); + } + else if ((e1->type->isreal() || e1->type->isimaginary()) && + e2->type->isimaginary()) + { + error("%s %s %s is an undefined operation", e1->type->toChars(), + opstr, e2->type->toChars()); + } +} + +// generate an error if this is a nonsensical += or -=, eg real += imaginary +void BinExp::checkComplexAddAssign() +{ + // Addition or subtraction of a real and an imaginary is a complex result. + // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. + if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || + (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) + ) + { + error("%s %s %s is undefined (result is complex)", + e1->type->toChars(), Token::toChars(op), e2->type->toChars()); + } +} + +void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte(' '); + buf->writestring(Token::toChars(op)); + buf->writeByte(' '); + expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); +} + +int BinExp::isunsigned() +{ + return e1->type->isunsigned() || e2->type->isunsigned(); +} + +#if DMDV2 +int BinExp::canThrow() +{ + return e1->canThrow() || e2->canThrow(); +} +#endif + +void BinExp::incompatibleTypes() +{ + if (e1->type->toBasetype() != Type::terror && + e2->type->toBasetype() != Type::terror + ) + error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", + e1->toChars(), Token::toChars(op), e2->toChars(), + e1->type->toChars(), e2->type->toChars()); +} + +/********************** BinAssignExp **************************************/ + +/*************************** + * Common semantic routine for some xxxAssignExp's. + */ + +Expression *BinAssignExp::commonSemanticAssign(Scope *sc) +{ Expression *e; + + if (!type) + { + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + if (e1->op == TOKslice) + { // T[] op= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + type = e1->type; + if (type->toBasetype()->ty == Tbool) + { + error("operator not allowed on bool expression %s", toChars()); + return new ErrorExp(); + } + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + + if (op == TOKmodass && e2->type->iscomplex()) + { error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; +} + +Expression *BinAssignExp::commonSemanticAssignIntegral(Scope *sc) +{ Expression *e; + + if (!type) + { + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + if (e1->op == TOKslice) + { // T[] op= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + type = e1->type; + if (type->toBasetype()->ty == Tbool) + { + e2 = e2->implicitCastTo(sc, type); + } + + typeCombine(sc); + e1->checkIntegral(); + e2->checkIntegral(); + } + return this; +} + +#if DMDV2 +int BinAssignExp::isLvalue() +{ + return 1; +} + +Expression *BinAssignExp::toLvalue(Scope *sc, Expression *ex) +{ Expression *e; + + if (e1->op == TOKvar) + { + /* Convert (e1 op= e2) to + * e1 op= e2; + * e1 + */ + e = e1->copy(); + e = new CommaExp(loc, this, e); + e = e->semantic(sc); + } + else + { + /* Convert (e1 op= e2) to + * ref v = e1; + * v op= e2; + * v + */ + + // ref v = e1; + Identifier *id = Lexer::uniqueId("__assignop"); + ExpInitializer *ei = new ExpInitializer(loc, e1); + VarDeclaration *v = new VarDeclaration(loc, e1->type, id, ei); + v->storage_class |= STCref | STCforeach; + Expression *de = new DeclarationExp(loc, v); + + // v op= e2 + e1 = new VarExp(e1->loc, v); + + e = new CommaExp(loc, de, this); + e = new CommaExp(loc, e, new VarExp(loc, v)); + e = e->semantic(sc); + } + return e; +} + +Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *e) +{ + return toLvalue(sc, this); +} + +#endif + +/************************************************************/ + +CompileExp::CompileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) +{ +} + +Expression *CompileExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("CompileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue | WANTinterpret); + if (e1->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", e1->toChars()); + return new ErrorExp(); + } + StringExp *se = (StringExp *)e1; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + //printf("p.loc.linnum = %d\n", p.loc.linnum); + Expression *e = p.parseExpression(); + if (p.token.value != TOKeof) + { error("incomplete mixin expression (%s)", se->toChars()); + return new ErrorExp(); + } + return e->semantic(sc); +} + +void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +FileExp::FileExp(Loc loc, Expression *e) + : UnaExp(loc, TOKmixin, sizeof(FileExp), e) +{ +} + +Expression *FileExp::semantic(Scope *sc) +{ char *name; + StringExp *se; + +#if LOGSEMANTIC + printf("FileExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->optimize(WANTvalue); + if (e1->op != TOKstring) + { error("file name argument must be a string, not (%s)", e1->toChars()); + goto Lerror; + } + se = (StringExp *)e1; + se = se->toUTF8(sc); + name = (char *)se->string; + + if (!global.params.fileImppath) + { error("need -Jpath switch to import text file %s", name); + goto Lerror; + } + + /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory + * ('Path Traversal') attacks. + * http://cwe.mitre.org/data/definitions/22.html + */ + + name = FileName::safeSearchPath(global.filePath, name); + if (!name) + { error("file %s cannot be found or not in a path specified with -J", se->toChars()); + goto Lerror; + } + + if (global.params.verbose) + printf("file %s\t(%s)\n", (char *)se->string, name); + + { File f(name); + if (f.read()) + { error("cannot read file %s", f.toChars()); + goto Lerror; + } + else + { + f.ref = 1; + se = new StringExp(loc, f.buffer, f.len); + } + } + Lret: + return se->semantic(sc); + + Lerror: + return new ErrorExp(); +} + +void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("import("); + expToCBuffer(buf, hgs, e1, PREC_assign); + buf->writeByte(')'); +} + +/************************************************************/ + +AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) + : UnaExp(loc, TOKassert, sizeof(AssertExp), e) +{ + this->msg = msg; +} + +Expression *AssertExp::syntaxCopy() +{ + AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), + msg ? msg->syntaxCopy() : NULL); + return ae; +} + +Expression *AssertExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AssertExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + // BUG: see if we can do compile time elimination of the Assert + e1 = e1->optimize(WANTvalue); + e1 = e1->checkToBoolean(sc); + if (msg) + { + msg = msg->semantic(sc); + msg = resolveProperties(sc, msg); + msg = msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf()); + msg = msg->optimize(WANTvalue); + } + if (e1->isBool(FALSE)) + { + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 4; + + if (!global.params.useAssert) + { Expression *e = new HaltExp(loc); + e = e->semantic(sc); + return e; + } + } + type = Type::tvoid; + return this; +} + +int AssertExp::checkSideEffect(int flag) +{ + return 1; +} + +#if DMDV2 +int AssertExp::canThrow() +{ + /* assert()s are non-recoverable errors, so functions that + * use them can be considered "nothrow" + */ + return 0; //(global.params.useAssert != 0); +} +#endif + +void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("assert("); + expToCBuffer(buf, hgs, e1, PREC_assign); + if (msg) + { + buf->writeByte(','); + expToCBuffer(buf, hgs, msg, PREC_assign); + } + buf->writeByte(')'); +} + +/************************************************************/ + +DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) + : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) +{ + this->ident = ident; +} + +Expression *DotIdExp::semantic(Scope *sc) +{ + // Indicate we didn't come from CallExp::semantic() + return semantic(sc, 0); +} + +Expression *DotIdExp::semantic(Scope *sc, int flag) +{ Expression *e; + Expression *eleft; + Expression *eright; + +#if LOGSEMANTIC + printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); + //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); +#endif + +//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } + +#if 0 + /* Don't do semantic analysis if we'll be converting + * it to a string. + */ + if (ident == Id::stringof) + { char *s = e1->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } +#endif + + /* Special case: rewrite this.id and super.id + * to be classtype.id and baseclasstype.id + * if we have no this pointer. + */ + if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) + { ClassDeclaration *cd; + StructDeclaration *sd; + AggregateDeclaration *ad; + + ad = sc->getStructClassScope(); + if (ad) + { + cd = ad->isClassDeclaration(); + if (cd) + { + if (e1->op == TOKthis) + { + e = typeDotIdExp(loc, cd->type, ident); + return e->semantic(sc); + } + else if (cd->baseClass && e1->op == TOKsuper) + { + e = typeDotIdExp(loc, cd->baseClass->type, ident); + return e->semantic(sc); + } + } + else + { + sd = ad->isStructDeclaration(); + if (sd) + { + if (e1->op == TOKthis) + { + e = typeDotIdExp(loc, sd->type, ident); + return e->semantic(sc); + } + } + } + } + } + + UnaExp::semantic(sc); + + if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *)e1; + eleft = de->e1; + eright = de->e2; + } + else + { + e1 = resolveProperties(sc, e1); + eleft = NULL; + eright = e1; + } +#if DMDV2 + if (e1->op == TOKtuple && ident == Id::offsetof) + { /* 'distribute' the .offsetof to each of the tuple elements. + */ + TupleExp *te = (TupleExp *)e1; + Expressions *exps = new Expressions(); + exps->setDim(te->exps->dim); + for (int i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)te->exps->data[i]; + e = e->semantic(sc); + e = new DotIdExp(e->loc, e, Id::offsetof); + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } +#endif + + if (e1->op == TOKtuple && ident == Id::length) + { + TupleExp *te = (TupleExp *)e1; + e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); + return e; + } + + if (e1->op == TOKdottd) + { + error("template %s does not have property %s", e1->toChars(), ident->toChars()); + return new ErrorExp(); + } + + if (!e1->type) + { + error("expression %s does not have property %s", e1->toChars(), ident->toChars()); + return new ErrorExp(); + } + + Type *t1b = e1->type->toBasetype(); + + if (eright->op == TOKimport) // also used for template alias's + { + ScopeExp *ie = (ScopeExp *)eright; + + /* Disable access to another module's private imports. + * The check for 'is sds our current module' is because + * the current module should have access to its own imports. + */ + Dsymbol *s = ie->sds->search(loc, ident, + (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); + if (s) + { + s = s->toAlias(); + checkDeprecated(sc, s); + + EnumMember *em = s->isEnumMember(); + if (em) + { + e = em->value; + e = e->semantic(sc); + return e; + } + + VarDeclaration *v = s->isVarDeclaration(); + if (v) + { + //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); + if (v->inuse) + { + error("circular reference to '%s'", v->toChars()); + return new ErrorExp(); + } + type = v->type; + if (v->needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, v); + e = e->semantic(sc); + } + else + { + e = new VarExp(loc, v); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e->type = v->type; + } + } + return e->deref(); + } + + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + { + //printf("it's a function\n"); + if (f->needThis()) + { + if (!eleft) + eleft = new ThisExp(loc); + e = new DotVarExp(loc, eleft, f); + e = e->semantic(sc); + } + else + { + e = new VarExp(loc, f, 1); + if (eleft) + { e = new CommaExp(loc, eleft, e); + e->type = f->type; + } + } + return e; + } +#if DMDV2 + OverloadSet *o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } +#endif + + Type *t = s->getType(); + if (t) + { + return new TypeExp(loc, t); + } + + TupleDeclaration *tup = s->isTupleDeclaration(); + if (tup) + { + if (eleft) + { error("cannot have e.tuple"); + return new ErrorExp(); + } + e = new TupleExp(loc, tup); + e = e->semantic(sc); + return e; + } + + ScopeDsymbol *sds = s->isScopeDsymbol(); + if (sds) + { + //printf("it's a ScopeDsymbol\n"); + e = new ScopeExp(loc, sds); + e = e->semantic(sc); + if (eleft) + e = new DotExp(loc, eleft, e); + return e; + } + + Import *imp = s->isImport(); + if (imp) + { + ScopeExp *ie; + + ie = new ScopeExp(loc, imp->pkg); + return ie->semantic(sc); + } + + // BUG: handle other cases like in IdentifierExp::semantic() +#ifdef DEBUG + printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + assert(0); + } + else if (ident == Id::stringof) + { char *s = ie->toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + e = e->semantic(sc); + return e; + } + error("undefined identifier %s", toChars()); + return new ErrorExp(); + } + else if (t1b->ty == Tpointer && + ident != Id::init && ident != Id::__sizeof && + ident != Id::__xalignof && ident != Id::offsetof && + ident != Id::mangleof && ident != Id::stringof) + { /* Rewrite: + * p.ident + * as: + * (*p).ident + */ + e = new PtrExp(loc, e1); + e->type = ((TypePointer *)t1b)->next; + return e->type->dotExp(sc, e, ident); + } +#if DMDV2 + else if (t1b->ty == Tarray || + t1b->ty == Tsarray || + t1b->ty == Taarray) + { /* If ident is not a valid property, rewrite: + * e1.ident + * as: + * .ident(e1) + */ + unsigned errors = global.errors; + global.gag++; + Type *t1 = e1->type; + e = e1->type->dotExp(sc, e1, ident); + global.gag--; + if (errors != global.errors) // if failed to find the property + { + global.errors = errors; + e1->type = t1; // kludge to restore type + e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); + e = new CallExp(loc, e, e1); + } + e = e->semantic(sc); + return e; + } +#endif + else + { + e = e1->type->dotExp(sc, e1, ident); + if (!(flag && e->op == TOKdotti)) // let CallExp::semantic() handle this + e = e->semantic(sc); + return e; + } +} + +void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("DotIdExp::toCBuffer()\n"); + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(ident->toChars()); +} + +/********************** DotTemplateExp ***********************************/ + +// Mainly just a placeholder + +DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) + : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) + +{ + this->td = td; +} + +void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(td->toChars()); +} + + +/************************************************************/ + +DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) + : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) +{ + //printf("DotVarExp()\n"); + this->var = v; + this->hasOverloads = hasOverloads; +} + +Expression *DotVarExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotVarExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + var = var->toAlias()->isDeclaration(); + + TupleDeclaration *tup = var->isTupleDeclaration(); + if (tup) + { /* Replace: + * e1.tuple(a, b, c) + * with: + * tuple(e1.a, e1.b, e1.c) + */ + Expressions *exps = new Expressions; + + exps->reserve(tup->objects->dim); + for (size_t i = 0; i < tup->objects->dim; i++) + { Object *o = (Object *)tup->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + { + error("%s is not an expression", o->toChars()); + goto Lerr; + } + else + { + Expression *e = (Expression *)o; + if (e->op != TOKdsymbol) + { error("%s is not a member", e->toChars()); + goto Lerr; + } + else + { DsymbolExp *ve = (DsymbolExp *)e; + + e = new DotVarExp(loc, e1, ve->s->isDeclaration()); + exps->push(e); + } + } + } + Expression *e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + + e1 = e1->semantic(sc); + type = var->type; + if (!type && global.errors) + { // var is goofed up, just return 0 + return new ErrorExp(); + } + assert(type); + + if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution + { + Type *t1 = e1->type; + if (t1->ty == Tpointer) + t1 = t1->nextOf(); + + type = type->addMod(t1->mod); + + Dsymbol *vparent = var->toParent(); + AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; + e1 = getRightThis(loc, sc, ad, e1, var); + if (!sc->noaccesscheck) + accessCheck(loc, sc, e1, var); + + VarDeclaration *v = var->isVarDeclaration(); + Expression *e = expandVar(WANTvalue, v); + if (e) + return e; + } + } + //printf("-DotVarExp::semantic('%s')\n", toChars()); + return this; + +Lerr: + return new ErrorExp(); +} + +#if DMDV2 +int DotVarExp::isLvalue() +{ + return 1; +} +#endif + +Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) +{ + //printf("DotVarExp::toLvalue(%s)\n", toChars()); + return this; +} + +Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) +{ +#if 0 + printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); + printf("e1->type = %s\n", e1->type->toChars()); + printf("var->type = %s\n", var->type->toChars()); +#endif + + Type *t1 = e1->type->toBasetype(); + + if (!t1->isMutable() || + (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || + !var->type->isMutable() || + !var->type->isAssignable() || + var->storage_class & STCmanifest + ) + { + 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() && + e1->op == TOKthis + ) + { + 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 member %s inside %sconstructor", + p, var->toChars(), p); + } + } + break; + } + } + else + { + error("cannot modify const/immutable/inout expression %s", toChars()); + } + } + return this; +} + +void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(var->toChars()); +} + +/************************************************************/ + +/* Things like: + * foo.bar!(args) + */ + +DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs) + : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) +{ + //printf("DotTemplateInstanceExp()\n"); + this->ti = new TemplateInstance(loc, name); + this->ti->tiargs = tiargs; +} + +Expression *DotTemplateInstanceExp::syntaxCopy() +{ + DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, + e1->syntaxCopy(), + ti->name, + TemplateInstance::arraySyntaxCopy(ti->tiargs)); + return de; +} + +TemplateDeclaration *DotTemplateInstanceExp::getTempdecl(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotTemplateInstanceExp::getTempdecl('%s')\n", toChars()); +#endif + if (!ti->tempdecl) + { + Expression *e = new DotIdExp(loc, e1, ti->name); + e = e->semantic(sc); + if (e->op == TOKdottd) + { + DotTemplateExp *dte = (DotTemplateExp *)e; + ti->tempdecl = dte->td; + } + else if (e->op == TOKimport) + { ScopeExp *se = (ScopeExp *)e; + ti->tempdecl = se->sds->isTemplateDeclaration(); + } + } + return ti->tempdecl; +} + +Expression *DotTemplateInstanceExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); +#endif + Expression *eleft; + Expression *e = new DotIdExp(loc, e1, ti->name); +L1: + e = e->semantic(sc); + if (e->op == TOKdottd) + { + if (global.errors) + return new ErrorExp(); // TemplateInstance::semantic() will fail anyway + DotTemplateExp *dte = (DotTemplateExp *)e; + TemplateDeclaration *td = dte->td; + eleft = dte->e1; + ti->tempdecl = td; + ti->semantic(sc); + if (!ti->inst) // if template failed to expand + return new ErrorExp(); + Dsymbol *s = ti->inst->toAlias(); + Declaration *v = s->isDeclaration(); + if (v) + { + /* Fix for Bugzilla 4003 + * The problem is a class template member function v returning a reference to the same + * type as the enclosing template instantiation. This results in a nested instantiation, + * which of course gets short circuited. The return type then gets set to + * the template instance type before instantiation, rather than after. + * We can detect this by the deco not being set. If so, go ahead and retry + * the return type semantic. + * The offending code is the return type from std.typecons.Tuple.slice: + * ref Tuple!(Types[from .. to]) slice(uint from, uint to)() + * { + * return *cast(typeof(return) *) &(field[from]); + * } + * and this line from the following unittest: + * auto s = a.slice!(1, 3); + * where s's type wound up not having semantic() run on it. + */ + if (v->type && !v->type->deco) + v->type = v->type->semantic(v->loc, sc); + + e = new DotVarExp(loc, eleft, v); + e = e->semantic(sc); + return e; + } + e = new ScopeExp(loc, ti); + e = new DotExp(loc, eleft, e); + e = e->semantic(sc); + return e; + } + else if (e->op == TOKimport) + { ScopeExp *se = (ScopeExp *)e; + TemplateDeclaration *td = se->sds->isTemplateDeclaration(); + if (!td) + { error("%s is not a template", e->toChars()); + return new ErrorExp(); + } + ti->tempdecl = td; + e = new ScopeExp(loc, ti); + e = e->semantic(sc); + return e; + } + else if (e->op == TOKdotexp) + { DotExp *de = (DotExp *)e; + + if (de->e2->op == TOKimport) + { // This should *really* be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)de->e2; + de->e2 = new DsymbolExp(loc, se->sds); + de->e2 = de->e2->semantic(sc); + } + + if (de->e2->op == TOKtemplate) + { TemplateExp *te = (TemplateExp *) de->e2; + e = new DotTemplateExp(loc,de->e1,te->td); + } + goto L1; + } + error("%s isn't a template", e->toChars()); + return new ErrorExp(); +} + +void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + ti->toCBuffer(buf, hgs); +} + +/************************************************************/ + +DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) + : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) +{ + this->func = f; + this->hasOverloads = hasOverloads; +} + +Expression *DelegateExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DelegateExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + m = sc->module; + e1 = e1->semantic(sc); + // LDC we need a copy as we store the LLVM tpye in TypeFunction, and delegate/members have different types for 'this' + type = new TypeDelegate(func->type->syntaxCopy()); + type = type->semantic(loc, sc); + AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); + if (func->needThis()) + e1 = getRightThis(loc, sc, ad, e1, func); + if (ad && ad->isClassDeclaration() && ad->type != e1->type) + { // A downcast is required for interfaces, see Bugzilla 3706 + e1 = new CastExp(loc, e1, ad->type); + e1 = e1->semantic(sc); + } + } + return this; +} + +void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('&'); + if (!func->isNested()) + { + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + } + buf->writestring(func->toChars()); +} + +/************************************************************/ + +DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) + : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) +{ + this->sym = s; + this->type = s->getType(); +} + +Expression *DotTypeExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotTypeExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + return this; +} + +void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(sym->toChars()); +} + +/************************************************************/ + +CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = exps; +} + +CallExp::CallExp(Loc loc, Expression *e) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + this->arguments = NULL; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + if (earg1) + { arguments->setDim(1); + arguments->data[0] = (void *)earg1; + } + this->arguments = arguments; +} + +CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) + : UnaExp(loc, TOKcall, sizeof(CallExp), e) +{ + Expressions *arguments = new Expressions(); + arguments->setDim(2); + arguments->data[0] = (void *)earg1; + arguments->data[1] = (void *)earg2; + + this->arguments = arguments; +} + +Expression *CallExp::syntaxCopy() +{ + return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + + +Expression *CallExp::semantic(Scope *sc) +{ + TypeFunction *tf; + FuncDeclaration *f; + int i; + Type *t1; + int istemp; + Objects *targsi = NULL; // initial list of template arguments + TemplateInstance *tierror = NULL; + +#if LOGSEMANTIC + printf("CallExp::semantic() %s\n", toChars()); +#endif + if (type) + return this; // semantic() already run +#if 0 + if (arguments && arguments->dim) + { + Expression *earg = (Expression *)arguments->data[0]; + earg->print(); + if (earg->type) earg->type->print(); + } +#endif + + if (e1->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)e1; + + e1 = new DotVarExp(de->loc, de->e1, de->func); + return semantic(sc); + } + + /* Transform: + * array.id(args) into .id(array,args) + * aa.remove(arg) into delete aa[arg] + */ + if (e1->op == TOKdot) + { + // BUG: we should handle array.a.b.c.e(args) too + + DotIdExp *dotid = (DotIdExp *)(e1); + dotid->e1 = dotid->e1->semantic(sc); + assert(dotid->e1); + if (dotid->e1->type) + { + TY e1ty = dotid->e1->type->toBasetype()->ty; + if (e1ty == Taarray && dotid->ident == Id::remove) + { + if (!arguments || arguments->dim != 1) + { error("expected key as argument to aa.remove()"); + return new ErrorExp(); + } + Expression *key = (Expression *)arguments->data[0]; + key = key->semantic(sc); + key = resolveProperties(sc, key); + key->rvalue(); + + TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); + key = key->implicitCastTo(sc, taa->index); + + return new RemoveExp(loc, dotid->e1, key); + } + else if (e1ty == Tarray || e1ty == Tsarray || + (e1ty == Taarray && dotid->ident != Id::apply && dotid->ident != Id::applyReverse)) + { + if (e1ty == Taarray) + { TypeAArray *taa = (TypeAArray *)dotid->e1->type->toBasetype(); + assert(taa->ty == Taarray); + StructDeclaration *sd = taa->getImpl(); + Dsymbol *s = sd->search(0, dotid->ident, 2); + if (s) + goto L2; + } + if (!arguments) + arguments = new Expressions(); + arguments->shift(dotid->e1); +#if DMDV2 + e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); +#else + e1 = new IdentifierExp(dotid->loc, dotid->ident); +#endif + } + + L2: + ; + } + } + +#if 1 + /* This recognizes: + * foo!(tiargs)(funcargs) + */ + if (e1->op == TOKimport && !e1->type) + { ScopeExp *se = (ScopeExp *)e1; + TemplateInstance *ti = se->sds->isTemplateInstance(); + if (ti && !ti->semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti->semanticTiargs(sc); + if (ti->needsTypeInference(sc)) + { + /* Go with partial explicit specialization + */ + targsi = ti->tiargs; + tierror = ti; // for error reporting + e1 = new IdentifierExp(loc, ti->name); + } + else + { + ti->semantic(sc); + } + } + } + + /* This recognizes: + * expr.foo!(tiargs)(funcargs) + */ +Ldotti: + if (e1->op == TOKdotti && !e1->type) + { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; + TemplateInstance *ti = se->ti; + if (!ti->semanticRun) + { + /* Attempt to instantiate ti. If that works, go with it. + * If not, go with partial explicit specialization. + */ + ti->semanticTiargs(sc); +#if 0 + Expression *etmp = e1->trySemantic(sc); + if (etmp) + e1 = etmp; // it worked + else // didn't work + { + targsi = ti->tiargs; + tierror = ti; // for error reporting + e1 = new DotIdExp(loc, se->e1, ti->name); + } +#else + if (!ti->tempdecl) + { + se->getTempdecl(sc); + } + if (ti->tempdecl && ti->needsTypeInference(sc)) + { + /* Go with partial explicit specialization + */ + targsi = ti->tiargs; + tierror = ti; // for error reporting + e1 = new DotIdExp(loc, se->e1, ti->name); + } + else + { + e1 = e1->semantic(sc); + } +#endif + } + } +#endif + + istemp = 0; +Lagain: + //printf("Lagain: %s\n", toChars()); + f = NULL; + if (e1->op == TOKthis || e1->op == TOKsuper) + { + // semantic() run later for these + } + else + { + if (e1->op == TOKdot) + { DotIdExp *die = (DotIdExp *)e1; + e1 = die->semantic(sc, 1); + /* Look for e1 having been rewritten to expr.opDispatch!(string) + * We handle such earlier, so go back. + * Note that in the rewrite, we carefully did not run semantic() on e1 + */ + if (e1->op == TOKdotti && !e1->type) + { + goto Ldotti; + } + } + else + UnaExp::semantic(sc); + + + /* Look for e1 being a lazy parameter + */ + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + + if (ve->var->storage_class & STClazy) + { + TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd); + TypeDelegate *t = new TypeDelegate(tf); + ve->type = t->semantic(loc, sc); + } + } + + if (e1->op == TOKimport) + { // Perhaps this should be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)e1; + e1 = new DsymbolExp(loc, se->sds); + e1 = e1->semantic(sc); + } +#if 1 // patch for #540 by Oskar Linde + else if (e1->op == TOKdotexp) + { + DotExp *de = (DotExp *) e1; + + if (de->e2->op == TOKimport) + { // This should *really* be moved to ScopeExp::semantic() + ScopeExp *se = (ScopeExp *)de->e2; + de->e2 = new DsymbolExp(loc, se->sds); + de->e2 = de->e2->semantic(sc); + } + + if (de->e2->op == TOKtemplate) + { TemplateExp *te = (TemplateExp *) de->e2; + e1 = new DotTemplateExp(loc,de->e1,te->td); + } + } +#endif + } + + if (e1->op == TOKcomma) + { + CommaExp *ce = (CommaExp *)e1; + + e1 = ce->e2; + e1->type = ce->type; + ce->e2 = this; + ce->type = NULL; + return ce->semantic(sc); + } + + t1 = NULL; + if (e1->type) + t1 = e1->type->toBasetype(); + + // Check for call operator overload + if (t1) + { AggregateDeclaration *ad; + + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; +#if DMDV2 + // First look for constructor + if (ad->ctor && arguments && arguments->dim) + { + // Create variable that will get constructed + Identifier *idtmp = Lexer::uniqueId("__ctmp"); + VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); + tmp->storage_class |= STCctfe; + Expression *av = new DeclarationExp(loc, tmp); + av = new CommaExp(loc, av, new VarExp(loc, tmp)); + + Expression *e; + CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); + if (cf) + e = new DotVarExp(loc, av, cf, 1); + else + { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); + assert(td); + e = new DotTemplateExp(loc, av, td); + } + e = new CallExp(loc, e, arguments); +#if !STRUCTTHISREF + /* Constructors return a pointer to the instance + */ + e = new PtrExp(loc, e); +#endif + e = e->semantic(sc); + return e; + } +#endif + // No constructor, look for overload of opCall + if (search_function(ad, Id::call)) + goto L1; // overload of opCall, therefore it's a call + + if (e1->op != TOKtype) + { error("%s %s does not overload ()", ad->kind(), ad->toChars()); + return new ErrorExp(); + } + + /* It's a struct literal + */ + Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments, e1->type); + e = e->semantic(sc); + return e; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + goto L1; + L1: + // Rewrite as e1.call(arguments) + Expression *e = new DotIdExp(loc, e1, Id::call); + e = new CallExp(loc, e, arguments); + e = e->semantic(sc); + return e; + } + } + + arguments = arrayExpressionSemantic(arguments, sc); + + preFunctionParameters(loc, sc, arguments); + + // If there was an error processing any argument, or the call, + // return an error without trying to resolve the function call. + if (arguments && arguments->dim) + { + for (int k = 0; k < arguments->dim; k++) + { Expression *checkarg = (Expression *)arguments->data[k]; + if (checkarg->op == TOKerror) + return checkarg; + } + } + if (e1->op == TOKerror) + return e1; + + if (e1->op == TOKdotvar && t1->ty == Tfunction || + e1->op == TOKdottd) + { + DotVarExp *dve; + DotTemplateExp *dte; + AggregateDeclaration *ad; + UnaExp *ue = (UnaExp *)(e1); + + if (e1->op == TOKdotvar) + { // Do overload resolution + dve = (DotVarExp *)(e1); + + f = dve->var->isFuncDeclaration(); + assert(f); + f = f->overloadResolve(loc, ue->e1, arguments); + + ad = f->toParent()->isAggregateDeclaration(); + } + else + { dte = (DotTemplateExp *)(e1); + TemplateDeclaration *td = dte->td; + assert(td); + if (!arguments) + // Should fix deduceFunctionTemplate() so it works on NULL argument + arguments = new Expressions(); + f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); + if (!f) + { type = Type::terror; + return this; + } + ad = td->toParent()->isAggregateDeclaration(); + } + if (f->needThis()) + { + ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); + } + + /* Cannot call public functions from inside invariant + * (because then the invariant would have infinite recursion) + */ + if (sc->func && sc->func->isInvariantDeclaration() && + ue->e1->op == TOKthis && + f->addPostInvariant() + ) + { + error("cannot call public/export function %s from invariant", f->toChars()); + return new ErrorExp(); + } + + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif + accessCheck(loc, sc, ue->e1, f); + if (!f->needThis()) + { + VarExp *ve = new VarExp(loc, f); + e1 = new CommaExp(loc, ue->e1, ve); + e1->type = f->type; + } + else + { + if (e1->op == TOKdotvar) + dve->var = f; + else + e1 = new DotVarExp(loc, dte->e1, f); + e1->type = f->type; +#if 0 + printf("ue->e1 = %s\n", ue->e1->toChars()); + printf("f = %s\n", f->toChars()); + printf("t = %s\n", t->toChars()); + printf("e1 = %s\n", e1->toChars()); + printf("e1->type = %s\n", e1->type->toChars()); +#endif + // Const member function can take const/immutable/mutable/inout this + if (!(f->type->isConst())) + { + // Check for const/immutable compatibility + Type *tthis = ue->e1->type->toBasetype(); + if (tthis->ty == Tpointer) + tthis = tthis->nextOf()->toBasetype(); +#if 0 // this checking should have been already done + if (f->type->isImmutable()) + { + if (tthis->mod != MODimmutable) + error("%s can only be called with an immutable object", e1->toChars()); + } + else if (f->type->isShared()) + { + if (tthis->mod != MODimmutable && + tthis->mod != MODshared && + tthis->mod != (MODshared | MODconst)) + error("shared %s can only be called with a shared or immutable object", e1->toChars()); + } + else + { + if (tthis->mod != 0) + { //printf("mod = %x\n", tthis->mod); + error("%s can only be called with a mutable object, not %s", e1->toChars(), tthis->toChars()); + } + } +#endif + /* Cannot call mutable method on a final struct + */ + if (tthis->ty == Tstruct && + ue->e1->op == TOKvar) + { VarExp *v = (VarExp *)ue->e1; + if (v->var->storage_class & STCfinal) + error("cannot call mutable method on final struct"); + } + } + + // See if we need to adjust the 'this' pointer + AggregateDeclaration *ad = f->isThis(); + ClassDeclaration *cd = ue->e1->type->isClassHandle(); + if (ad && cd && ad->isClassDeclaration() && ad != cd && + ue->e1->op != TOKsuper) + { + ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); + ue->e1 = ue->e1->semantic(sc); + } + } + t1 = e1->type; + } + else if (e1->op == TOKsuper) + { + // Base class constructor call + ClassDeclaration *cd = NULL; + + if (sc->func) + cd = sc->func->toParent()->isClassDeclaration(); + if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) + { + error("super class constructor call must be in a constructor"); + return new ErrorExp(); + } + else + { + if (!cd->baseClass->ctor) + { error("no super class constructor for %s", cd->baseClass->toChars()); + return new ErrorExp(); + } + else + { + if (!sc->intypeof) + { +#if 0 + if (sc->callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +#endif + if (sc->noctor || sc->callSuper & CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) + error("multiple constructor calls"); + sc->callSuper |= CSXany_ctor | CSXsuper_ctor; + } + + f = resolveFuncCall(sc, loc, cd->baseClass->ctor, NULL, NULL, arguments, 0); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif + e1 = new DotVarExp(e1->loc, e1, f); + e1 = e1->semantic(sc); + t1 = e1->type; + } + } + } + else if (e1->op == TOKthis) + { + // same class constructor call + AggregateDeclaration *cd = NULL; + + if (sc->func) + cd = sc->func->toParent()->isAggregateDeclaration(); + if (!cd || !sc->func->isCtorDeclaration()) + { + error("constructor call must be in a constructor"); + return new ErrorExp(); + } + else + { + if (!sc->intypeof) + { +#if 0 + if (sc->callSuper & (CSXthis | CSXsuper)) + error("reference to this before super()"); +#endif + if (sc->noctor || sc->callSuper & CSXlabel) + error("constructor calls not allowed in loops or after labels"); + if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) + error("multiple constructor calls"); + sc->callSuper |= CSXany_ctor | CSXthis_ctor; + } + + f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif + e1 = new DotVarExp(e1->loc, e1, f); + e1 = e1->semantic(sc); + t1 = e1->type; + + // BUG: this should really be done by checking the static + // call graph + if (f == sc->func) + { error("cyclic constructor call"); + return new ErrorExp(); + } + } + } + else if (e1->op == TOKoverloadset) + { + OverExp *eo = (OverExp *)e1; + FuncDeclaration *f = NULL; + Dsymbol *s = NULL; + for (int i = 0; i < eo->vars->a.dim; i++) + { s = (Dsymbol *)eo->vars->a.data[i]; + FuncDeclaration *f2 = s->isFuncDeclaration(); + if (f2) + { + f2 = f2->overloadResolve(loc, NULL, arguments, 1); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + assert(td); + f2 = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments, 1); + } + if (f2) + { if (f) + /* Error if match in more than one overload set, + * even if one is a 'better' match than the other. + */ + ScopeDsymbol::multiplyDefined(loc, f, f2); + else + f = f2; + } + } + if (!f) + { /* No overload matches + */ + error("no overload matches for %s", s->toChars()); + return new ErrorExp(); + } + e1 = new VarExp(loc, f); + goto Lagain; + } + else if (!t1) + { + error("function expected before (), not '%s'", e1->toChars()); + return new ErrorExp(); + } + else if (t1->ty != Tfunction) + { + if (t1->ty == Tdelegate) + { TypeDelegate *td = (TypeDelegate *)t1; + assert(td->next->ty == Tfunction); + tf = (TypeFunction *)(td->next); + if (sc->func && sc->func->isPure() && !tf->ispure) + { + error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); + } + if (sc->func && sc->func->isSafe() && tf->trust <= TRUSTsystem) + { + error("safe function '%s' cannot call system delegate '%s'", sc->func->toChars(), e1->toChars()); + } + goto Lcheckargs; + } + else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) + { + Expression *e = new PtrExp(loc, e1); + t1 = ((TypePointer *)t1)->next; + if (sc->func && sc->func->isPure() && !((TypeFunction *)t1)->ispure) + { + error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); + } + if (sc->func && sc->func->isSafe() && !((TypeFunction *)t1)->trust <= TRUSTsystem) + { + error("safe function '%s' cannot call system function pointer '%s'", sc->func->toChars(), e1->toChars()); + } + e->type = t1; + e1 = e; + } + else if (e1->op == TOKtemplate) + { + TemplateExp *te = (TemplateExp *)e1; + f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); + if (!f) + { if (tierror) + tierror->error("errors instantiating template"); // give better error message + return new ErrorExp(); + } + if (f->needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); + goto Lagain; + } + + e1 = new VarExp(loc, f); + goto Lagain; + } + else + { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); + return new ErrorExp(); + } + } + else if (e1->op == TOKvar) + { + // Do overload resolution + VarExp *ve = (VarExp *)e1; + + f = ve->var->isFuncDeclaration(); + assert(f); + + if (ve->hasOverloads) + f = f->overloadResolve(loc, NULL, arguments); + checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); + checkSafety(sc, f); +#endif + + if (f->needThis() && hasThis(sc)) + { + // Supply an implicit 'this', as in + // this.ident + + e1 = new DotVarExp(loc, new ThisExp(loc), f); + goto Lagain; + } + + accessCheck(loc, sc, NULL, f); + + ve->var = f; +// ve->hasOverloads = 0; + ve->type = f->type; + t1 = f->type; + } + assert(t1->ty == Tfunction); + tf = (TypeFunction *)(t1); + +Lcheckargs: + assert(tf->ty == Tfunction); + + if (!arguments) + arguments = new Expressions(); + type = functionParameters(loc, sc, tf, arguments, f); + + if (!type) + { + error("forward reference to inferred return type of function call %s", toChars()); + return new ErrorExp(); + } + + if (f && f->tintro) + { + Type *t = type; + int offset = 0; + TypeFunction *tf = (TypeFunction *)f->tintro; + + if (tf->next->isBaseOf(t, &offset) && offset) + { + type = tf->next; + return castTo(sc, t); + } + } + + return this; +} + +int CallExp::checkSideEffect(int flag) +{ +#if DMDV2 + if (flag != 2) + return 1; + + if (e1->checkSideEffect(2)) + return 1; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->checkSideEffect(2)) + return 1; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) + return 0; +#endif + return 1; +} + +#if DMDV2 +int CallExp::canThrow() +{ + //printf("CallExp::canThrow() %s\n", toChars()); + if (e1->canThrow()) + return 1; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e && e->canThrow()) + return 1; + } + + if (global.errors && !e1->type) + return 0; // error recovery + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + return 0; + + return 1; +} +#endif + +#if DMDV2 +int CallExp::isLvalue() +{ +// if (type->toBasetype()->ty == Tstruct) +// return 1; + Type *tb = e1->type->toBasetype(); + if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + return 1; // function returns a reference + return 0; +} +#endif + +Expression *CallExp::toLvalue(Scope *sc, Expression *e) +{ + if (isLvalue()) + return this; + return Expression::toLvalue(sc, e); +} + +void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (e1->op == TOKtype) + /* Avoid parens around type to prevent forbidden cast syntax: + * (sometype)(arg1) + * This is ok since types in constructor calls + * can never depend on parens anyway + */ + e1->toCBuffer(buf, hgs); + else + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('('); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(')'); +} + + +/************************************************************/ + +AddrExp::AddrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) +{ +#if IN_LLVM + m = NULL; +#endif +} + +Expression *AddrExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("AddrExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { +#if IN_LLVM + m = sc->module; +#endif + UnaExp::semantic(sc); + e1 = e1->toLvalue(sc, NULL); + if (!e1->type) + { + error("cannot take address of %s", e1->toChars()); + return new ErrorExp(); + } + if (!e1->type->deco) + { + /* No deco means semantic() was not run on the type. + * We have to run semantic() on the symbol to get the right type: + * auto x = &bar; + * pure: int bar() { return 1;} + * otherwise the 'pure' is missing from the type assigned to x. + */ + + error("forward reference to %s", e1->toChars()); + return new ErrorExp(); + } + + type = e1->type->pointerTo(); + + // See if this should really be a delegate + if (e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *f = dve->var->isFuncDeclaration(); + + if (f) + { + if (!dve->hasOverloads) + f->tookAddressOf++; + Expression *e = new DelegateExp(loc, dve->e1, f, dve->hasOverloads); + e = e->semantic(sc); + return e; + } + } + else if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && !v->canTakeAddressOf()) + { error("cannot take address of %s", e1->toChars()); + return new ErrorExp(); + } + + FuncDeclaration *f = ve->var->isFuncDeclaration(); + + if (f) + { + if (!ve->hasOverloads || + /* Because nested functions cannot be overloaded, + * mark here that we took its address because castTo() + * may not be called with an exact match. + */ + f->toParent2()->isFuncDeclaration()) + f->tookAddressOf++; + if (f->isNested()) + { + Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); + e = e->semantic(sc); + return e; + } + if (f->needThis() && hasThis(sc)) + { + /* Should probably supply 'this' after overload resolution, + * not before. + */ + Expression *ethis = new ThisExp(loc); + Expression *e = new DelegateExp(loc, ethis, f, ve->hasOverloads); + e = e->semantic(sc); + return e; + } + } + } + return optimize(WANTvalue); + } + return this; +} + +void AddrExp::checkEscape() +{ + e1->checkEscapeRef(); +} + +/************************************************************/ + +PtrExp::PtrExp(Loc loc, Expression *e) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ +// if (e->type) +// type = ((TypePointer *)e->type)->next; +} + +PtrExp::PtrExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKstar, sizeof(PtrExp), e) +{ + type = t; +} + +Expression *PtrExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("PtrExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + Expression *e = op_overload(sc); + if (e) + return e; + Type *tb = e1->type->toBasetype(); + switch (tb->ty) + { + case Tpointer: + type = ((TypePointer *)tb)->next; + break; + + case Tsarray: + case Tarray: + type = ((TypeArray *)tb)->next; + e1 = e1->castTo(sc, type->pointerTo()); + break; + + default: + error("can only * a pointer, not a '%s'", e1->type->toChars()); + case Terror: + return new ErrorExp(); + } + rvalue(); + } + return this; +} + +#if DMDV2 +int PtrExp::isLvalue() +{ + return 1; +} +#endif + +void PtrExp::checkEscapeRef() +{ + e1->checkEscape(); +} + +Expression *PtrExp::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; +} + +#if DMDV2 +Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); + + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + se->var->checkModify(loc, sc, type); + //return toLvalue(sc, e); + } + + return Expression::modifiableLvalue(sc, e); +} +#endif + +void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('*'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +NegExp::NegExp(Loc loc, Expression *e) + : UnaExp(loc, TOKneg, sizeof(NegExp), e) +{ +} + +Expression *NegExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("NegExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + e = op_overload(sc); + if (e) + return e; + + e1->checkNoBool(); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + type = e1->type; + } + return this; +} + +/************************************************************/ + +UAddExp::UAddExp(Loc loc, Expression *e) + : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) +{ +} + +Expression *UAddExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("UAddExp::semantic('%s')\n", toChars()); +#endif + assert(!type); + e = op_overload(sc); + if (e) + return e; + e1->checkNoBool(); + e1->checkArithmetic(); + return e1; +} + +/************************************************************/ + +ComExp::ComExp(Loc loc, Expression *e) + : UnaExp(loc, TOKtilde, sizeof(ComExp), e) +{ +} + +Expression *ComExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { + e = op_overload(sc); + if (e) + return e; + + e1->checkNoBool(); + if (!e1->isArrayOperand()) + e1 = e1->checkIntegral(); + type = e1->type; + } + return this; +} + +/************************************************************/ + +NotExp::NotExp(Loc loc, Expression *e) + : UnaExp(loc, TOKnot, sizeof(NotExp), e) +{ +} + +Expression *NotExp::semantic(Scope *sc) +{ + if (!type) + { // Note there is no operator overload + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(sc); + type = Type::tboolean; + } + return this; +} + +int NotExp::isBit() +{ + return TRUE; +} + + + +/************************************************************/ + +BoolExp::BoolExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) +{ + type = t; +} + +Expression *BoolExp::semantic(Scope *sc) +{ + if (!type) + { // Note there is no operator overload + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToBoolean(sc); + type = Type::tboolean; + } + return this; +} + +int BoolExp::isBit() +{ + return TRUE; +} + +/************************************************************/ + +DeleteExp::DeleteExp(Loc loc, Expression *e) + : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) +{ +} + +Expression *DeleteExp::semantic(Scope *sc) +{ + Type *tb; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->toLvalue(sc, NULL); + type = Type::tvoid; + + tb = e1->type->toBasetype(); + switch (tb->ty) + { case Tclass: + { TypeClass *tc = (TypeClass *)tb; + ClassDeclaration *cd = tc->sym; + + if (cd->isCOMinterface()) + { /* Because COM classes are deleted by IUnknown.Release() + */ + error("cannot delete instance of COM interface %s", cd->toChars()); + } + break; + } + case Tpointer: + tb = ((TypePointer *)tb)->next->toBasetype(); + if (tb->ty == Tstruct) + { + TypeStruct *ts = (TypeStruct *)tb; + StructDeclaration *sd = ts->sym; + FuncDeclaration *f = sd->aggDelete; + FuncDeclaration *fd = sd->dtor; + + if (!f && !fd) + break; + + /* Construct: + * ea = copy e1 to a tmp to do side effects only once + * eb = call destructor + * ec = call deallocator + */ + Expression *ea = NULL; + Expression *eb = NULL; + Expression *ec = NULL; + VarDeclaration *v; + + if (fd && f) + { Identifier *id = Lexer::idPool("__tmp"); + v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); + v->semantic(sc); + v->parent = sc->parent; + ea = new DeclarationExp(loc, v); + ea->type = v->type; + } + + if (fd) + { Expression *e = ea ? new VarExp(loc, v) : e1; + e = new DotVarExp(0, e, fd, 0); + eb = new CallExp(loc, e); + eb = eb->semantic(sc); + } + + if (f) + { + Type *tpv = Type::tvoid->pointerTo(); + Expression *e = ea ? new VarExp(loc, v) : e1->castTo(sc, tpv); + e = new CallExp(loc, new VarExp(loc, f), e); + ec = e->semantic(sc); + } + ea = combine(ea, eb); + ea = combine(ea, ec); + assert(ea); + return ea; + } + break; + + case Tarray: + /* BUG: look for deleting arrays of structs with dtors. + */ + break; + + default: + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + Type *tb1 = ae->e1->type->toBasetype(); + if (tb1->ty == Taarray) + break; + } + error("cannot delete type %s", e1->type->toChars()); + return new ErrorExp(); + } + + if (e1->op == TOKindex) + { + IndexExp *ae = (IndexExp *)(e1); + Type *tb1 = ae->e1->type->toBasetype(); + if (tb1->ty == Taarray) + { if (!global.params.useDeprecated) + error("delete aa[key] deprecated, use aa.remove(key)"); + } + } + + return this; +} + +int DeleteExp::checkSideEffect(int flag) +{ + return 1; +} + +Expression *DeleteExp::checkToBoolean(Scope *sc) +{ + error("delete does not give a boolean result"); + return new ErrorExp(); +} + +void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete "); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +CastExp::CastExp(Loc loc, Expression *e, Type *t) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = t; + this->mod = ~0; +} + +#if DMDV2 +/* For cast(const) and cast(immutable) + */ +CastExp::CastExp(Loc loc, Expression *e, unsigned mod) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = NULL; + this->mod = mod; +} +#endif + +Expression *CastExp::syntaxCopy() +{ + return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()) + : new CastExp(loc, e1->syntaxCopy(), mod); +} + + +Expression *CastExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + +#if LOGSEMANTIC + printf("CastExp::semantic('%s')\n", toChars()); +#endif + +//static int x; assert(++x < 10); + + if (type) + return this; + UnaExp::semantic(sc); + if (e1->type) // if not a tuple + { + e1 = resolveProperties(sc, e1); + + if (!to) + { + /* Handle cast(const) and cast(immutable), etc. + */ + to = e1->type->castMod(mod); + } + else + to = to->semantic(loc, sc); + + if (!to->equals(e1->type)) + { + e = op_overload(sc); + if (e) + { + return e->implicitCastTo(sc, to); + } + } + + if (e1->op == TOKtemplate) + { + error("cannot cast template %s to type %s", e1->toChars(), to->toChars()); + return new ErrorExp(); + } + + Type *t1b = e1->type->toBasetype(); + Type *tob = to->toBasetype(); + if (tob->ty == Tstruct && + !tob->equals(t1b) && + ((TypeStruct *)tob)->sym->search(0, Id::call, 0) + ) + { + /* Look to replace: + * cast(S)t + * with: + * S(t) + */ + + // Rewrite as to.call(e1) + e = new TypeExp(loc, to); + e = new DotIdExp(loc, e, Id::call); + e = new CallExp(loc, e, e1); + e = e->semantic(sc); + return e; + } + + // Struct casts are possible only when the sizes match + if (tob->ty == Tstruct || t1b->ty == Tstruct) + { + size_t fromsize = t1b->size(loc); + size_t tosize = tob->size(loc); + if (fromsize != tosize) + { + error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); + return new ErrorExp(); + } + } + } + else if (!to) + { error("cannot cast tuple"); + return new ErrorExp(); + } + + if (!e1->type) + { error("cannot cast %s", e1->toChars()); + return new ErrorExp(); + } + +#if 1 + if (sc->func && sc->func->isSafe() && !sc->intypeof) +#else + if (global.params.safe && !sc->module->safe && !sc->intypeof) +#endif + { // Disallow unsafe casts + Type *tob = to->toBasetype(); + Type *t1b = e1->type->toBasetype(); + if (!t1b->isMutable() && tob->isMutable()) + { // Cast not mutable to mutable + Lunsafe: + error("cast from %s to %s not allowed in safe code", e1->type->toChars(), to->toChars()); + return new ErrorExp(); + } + else if (t1b->isShared() && !tob->isShared()) + // Cast away shared + goto Lunsafe; + else if (tob->ty == Tpointer) + { if (t1b->ty != Tpointer) + goto Lunsafe; + Type *tobn = tob->nextOf()->toBasetype(); + Type *t1bn = t1b->nextOf()->toBasetype(); + + if (!t1bn->isMutable() && tobn->isMutable()) + // Cast away pointer to not mutable + goto Lunsafe; + + if (t1bn->isShared() && !tobn->isShared()) + // Cast away pointer to shared + goto Lunsafe; + + if (t1bn->isWild() && !tobn->isConst() && !tobn->isWild()) + // Cast wild to anything but const | wild + goto Lunsafe; + + if (tobn->isTypeBasic() && tobn->size() < t1bn->size()) + // Allow things like casting a long* to an int* + ; + else if (tobn->ty != Tvoid) + // Cast to a pointer other than void* + goto Lunsafe; + } + + // BUG: Check for casting array types, such as void[] to int*[] + } + + e = e1->castTo(sc, to); + return e; +} + +int CastExp::checkSideEffect(int flag) +{ + /* if not: + * cast(void) + * cast(classtype)func() + */ + if (!to->equals(Type::tvoid) && + !(to->ty == Tclass && e1->op == TOKcall && e1->type->ty == Tclass)) + return Expression::checkSideEffect(flag); + return 1; +} + +void CastExp::checkEscape() +{ Type *tb = type->toBasetype(); + if (tb->ty == Tarray && e1->op == TOKvar && + e1->type->toBasetype()->ty == Tsarray) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v) + { + if (!v->isDataseg() && !v->isParameter()) + error("escaping reference to local %s", v->toChars()); + } + } +} + +void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("cast("); +#if DMDV1 + to->toCBuffer(buf, NULL, hgs); +#else + if (to) + to->toCBuffer(buf, NULL, hgs); + else + { + MODtoBuffer(buf, mod); + } +#endif + buf->writeByte(')'); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + + +/************************************************************/ + +SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) + : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) +{ + this->upr = upr; + this->lwr = lwr; + lengthVar = NULL; +} + +Expression *SliceExp::syntaxCopy() +{ + Expression *lwr = NULL; + if (this->lwr) + lwr = this->lwr->syntaxCopy(); + + Expression *upr = NULL; + if (this->upr) + upr = this->upr->syntaxCopy(); + + return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); +} + +Expression *SliceExp::semantic(Scope *sc) +{ Expression *e; + AggregateDeclaration *ad; + //FuncDeclaration *fd; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("SliceExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + e = this; + + Type *t = e1->type->toBasetype(); + if (t->ty == Tpointer) + { + if (!lwr || !upr) + { error("need upper and lower bound to slice pointer"); + return new ErrorExp(); + } + } + else if (t->ty == Tarray) + { + } + else if (t->ty == Tsarray) + { + } + else if (t->ty == Tclass) + { + ad = ((TypeClass *)t)->sym; + goto L1; + } + else if (t->ty == Tstruct) + { + ad = ((TypeStruct *)t)->sym; + + L1: + if (search_function(ad, Id::slice)) + { + // Rewrite as e1.slice(lwr, upr) + e = new DotIdExp(loc, e1, Id::slice); + + if (lwr) + { + assert(upr); + e = new CallExp(loc, e, lwr, upr); + } + else + { assert(!upr); + e = new CallExp(loc, e); + } + e = e->semantic(sc); + return e; + } + goto Lerror; + } + else if (t->ty == Ttuple) + { + if (!lwr && !upr) + return e1; + if (!lwr || !upr) + { error("need upper and lower bound to slice tuple"); + goto Lerror; + } + } + else + goto Lerror; + + { + Scope *sc2 = sc; + if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) + { + sym = new ArrayScopeSymbol(sc, this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc2 = sc->push(sym); + } + + if (lwr) + { lwr = lwr->semantic(sc2); + lwr = resolveProperties(sc2, lwr); + lwr = lwr->implicitCastTo(sc2, Type::tsize_t); + if (lwr->type == Type::terror) + goto Lerr; + } + if (upr) + { upr = upr->semantic(sc2); + upr = resolveProperties(sc2, upr); + upr = upr->implicitCastTo(sc2, Type::tsize_t); + if (upr->type == Type::terror) + goto Lerr; + } + + if (sc2 != sc) + sc2->pop(); + } + + if (t->ty == Ttuple) + { + lwr = lwr->optimize(WANTvalue); + upr = upr->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); + uinteger_t i2 = upr->toUInteger(); + + size_t length; + TupleExp *te; + TypeTuple *tup; + + if (e1->op == TOKtuple) // slicing an expression tuple + { te = (TupleExp *)e1; + length = te->exps->dim; + } + else if (e1->op == TOKtype) // slicing a type tuple + { tup = (TypeTuple *)t; + length = Parameter::dim(tup->arguments); + } + else + assert(0); + + if (i1 <= i2 && i2 <= length) + { size_t j1 = (size_t) i1; + size_t j2 = (size_t) i2; + + if (e1->op == TOKtuple) + { Expressions *exps = new Expressions; + exps->setDim(j2 - j1); + for (size_t i = 0; i < j2 - j1; i++) + { Expression *e = (Expression *)te->exps->data[j1 + i]; + exps->data[i] = (void *)e; + } + e = new TupleExp(loc, exps); + } + else + { Parameters *args = new Parameters; + args->reserve(j2 - j1); + for (size_t i = j1; i < j2; i++) + { Parameter *arg = Parameter::getNth(tup->arguments, i); + args->push(arg); + } + e = new TypeExp(e1->loc, new TypeTuple(args)); + } + e = e->semantic(sc); + } + else + { + error("string slice [%ju .. %ju] is out of bounds", i1, i2); + goto Lerr; + } + return e; + } + + if (t->ty == Tarray) + { + type = e1->type; + } + else + type = t->nextOf()->arrayOf(); + return e; + +Lerror: + if (e1->op == TOKerror) + return e1; + char *s; + if (t->ty == Tvoid) + s = e1->toChars(); + else + s = t->toChars(); + error("%s cannot be sliced with []", s); +Lerr: + e = new ErrorExp(); + return e; +} + +void SliceExp::checkEscape() +{ + e1->checkEscape(); +} + +void SliceExp::checkEscapeRef() +{ + e1->checkEscapeRef(); +} + +#if DMDV2 +int SliceExp::isLvalue() +{ + return 1; +} +#endif + +Expression *SliceExp::toLvalue(Scope *sc, Expression *e) +{ + return this; +} + +Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) +{ + error("slice expression %s is not a modifiable lvalue", toChars()); + return this; +} + +void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writeByte('['); + if (upr || lwr) + { + if (lwr) + expToCBuffer(buf, hgs, lwr, PREC_assign); + else + buf->writeByte('0'); + buf->writestring(".."); + if (upr) + expToCBuffer(buf, hgs, upr, PREC_assign); + else + buf->writestring("length"); // BUG: should be array.length + } + buf->writeByte(']'); +} + +/********************** ArrayLength **************************************/ + +ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) + : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) +{ +} + +Expression *ArrayLengthExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("ArrayLengthExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + type = Type::tsize_t; + } + return this; +} + +Expression *opAssignToOp(Loc loc, enum TOK op, Expression *e1, Expression *e2) +{ Expression *e; + + switch (op) + { + case TOKaddass: e = new AddExp(loc, e1, e2); break; + case TOKminass: e = new MinExp(loc, e1, e2); break; + case TOKmulass: e = new MulExp(loc, e1, e2); break; + case TOKdivass: e = new DivExp(loc, e1, e2); break; + case TOKmodass: e = new ModExp(loc, e1, e2); break; + case TOKandass: e = new AndExp(loc, e1, e2); break; + case TOKorass: e = new OrExp (loc, e1, e2); break; + case TOKxorass: e = new XorExp(loc, e1, e2); break; + case TOKshlass: e = new ShlExp(loc, e1, e2); break; + case TOKshrass: e = new ShrExp(loc, e1, e2); break; + case TOKushrass: e = new UshrExp(loc, e1, e2); break; + default: assert(0); + } + return e; +} + +/********************* + * Rewrite: + * array.length op= e2 + * as: + * array.length = array.length op e2 + * or: + * auto tmp = &array; + * (*tmp).length = (*tmp).length op e2 + */ + +Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp) +{ Expression *e; + + assert(exp->e1->op == TOKarraylength); + ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1; + if (ale->e1->op == TOKvar) + { e = opAssignToOp(exp->loc, exp->op, ale, exp->e2); + e = new AssignExp(exp->loc, ale->syntaxCopy(), e); + } + else + { + /* auto tmp = &array; + * (*tmp).length = (*tmp).length op e2 + */ + Identifier *id = Lexer::uniqueId("__arraylength"); + ExpInitializer *ei = new ExpInitializer(ale->loc, new AddrExp(ale->loc, ale->e1)); + VarDeclaration *tmp = new VarDeclaration(ale->loc, ale->e1->type->pointerTo(), id, ei); + + Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp))); + Expression *elvalue = e1->syntaxCopy(); + e = opAssignToOp(exp->loc, exp->op, e1, exp->e2); + e = new AssignExp(exp->loc, elvalue, e); + e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e); + } + return e; +} + +void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writestring(".length"); +} + +/*********************** ArrayExp *************************************/ + +// e1 [ i1, i2, i3, ... ] + +ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) + : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) +{ + arguments = args; +} + +Expression *ArrayExp::syntaxCopy() +{ + return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); +} + +Expression *ArrayExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + +#if LOGSEMANTIC + printf("ArrayExp::semantic('%s')\n", toChars()); +#endif + UnaExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + t1 = e1->type->toBasetype(); + if (t1->ty != Tclass && t1->ty != Tstruct) + { // Convert to IndexExp + if (arguments->dim != 1) + { error("only one index allowed to index %s", t1->toChars()); + goto Lerr; + } + e = new IndexExp(loc, e1, (Expression *)arguments->data[0]); + return e->semantic(sc); + } + + // Run semantic() on each argument + for (size_t i = 0; i < arguments->dim; i++) + { e = (Expression *)arguments->data[i]; + + e = e->semantic(sc); + if (!e->type) + { error("%s has no value", e->toChars()); + goto Lerr; + } + else if (e->type == Type::terror) + goto Lerr; + arguments->data[i] = (void *)e; + } + + expandTuples(arguments); + assert(arguments && arguments->dim); + + e = op_overload(sc); + if (!e) + { error("no [] operator overload for type %s", e1->type->toChars()); + goto Lerr; + } + return e; + +Lerr: + return new ErrorExp(); +} + +#if DMDV2 +int ArrayExp::isLvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + return 0; + return 1; +} +#endif + +Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) +{ + if (type && type->toBasetype()->ty == Tvoid) + error("voids have no value"); + return this; +} + + +void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('['); + argsToCBuffer(buf, arguments, hgs); + buf->writeByte(']'); +} + +/************************* DotExp ***********************************/ + +DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) +{ +} + +Expression *DotExp::semantic(Scope *sc) +{ +#if LOGSEMANTIC + printf("DotExp::semantic('%s')\n", toChars()); + if (type) printf("\ttype = %s\n", type->toChars()); +#endif + e1 = e1->semantic(sc); + e2 = e2->semantic(sc); + if (e2->op == TOKimport) + { + ScopeExp *se = (ScopeExp *)e2; + TemplateDeclaration *td = se->sds->isTemplateDeclaration(); + if (td) + { Expression *e = new DotTemplateExp(loc, e1, td); + e = e->semantic(sc); + return e; + } + } + if (!type) + type = e2->type; + return this; +} + +void DotExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + expToCBuffer(buf, hgs, e2, PREC_primary); +} + +/************************* CommaExp ***********************************/ + +CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) +{ +} + +Expression *CommaExp::semantic(Scope *sc) +{ + if (!type) + { BinExp::semanticp(sc); + type = e2->type; + } + return this; +} + +void CommaExp::checkEscape() +{ + e2->checkEscape(); +} + +void CommaExp::checkEscapeRef() +{ + e2->checkEscapeRef(); +} + +#if DMDV2 +int CommaExp::isLvalue() +{ + return e2->isLvalue(); +} +#endif + +Expression *CommaExp::toLvalue(Scope *sc, Expression *e) +{ + e2 = e2->toLvalue(sc, NULL); + return this; +} + +Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) +{ + e2 = e2->modifiableLvalue(sc, e); + return this; +} + +int CommaExp::isBool(int result) +{ + return e2->isBool(result); +} + +int CommaExp::checkSideEffect(int flag) +{ + /* Check for compiler-generated code of the form auto __tmp, e, __tmp; + * In such cases, only check e for side effect (it's OK for __tmp to have + * no side effect). + * See Bugzilla 4231 for discussion + */ + CommaExp* firstComma = this; + while (firstComma->e1->op == TOKcomma) + firstComma = (CommaExp *)firstComma->e1; + if (firstComma->e1->op == TOKdeclaration && + e2->op == TOKvar && + ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)e2)->var) + { + return e1->checkSideEffect(flag); + } + + if (flag == 2) + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + else + { + // Don't check e1 until we cast(void) the a,b code generation + return e2->checkSideEffect(flag); + } +} + +/************************** IndexExp **********************************/ + +// e1 [ e2 ] + +IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) +{ + //printf("IndexExp::IndexExp('%s')\n", toChars()); + lengthVar = NULL; + modifiable = 0; // assume it is an rvalue +} + +Expression *IndexExp::semantic(Scope *sc) +{ Expression *e; + BinExp *b; + UnaExp *u; + Type *t1; + ScopeDsymbol *sym; + +#if LOGSEMANTIC + printf("IndexExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + if (!e1->type) + e1 = e1->semantic(sc); + assert(e1->type); // semantic() should already be run on it + e = this; + + // Note that unlike C we do not implement the int[ptr] + + t1 = e1->type->toBasetype(); + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + { // Create scope for 'length' variable + sym = new ArrayScopeSymbol(sc, this); + sym->loc = loc; + sym->parent = sc->scopesym; + sc = sc->push(sym); + } + + e2 = e2->semantic(sc); + if (!e2->type) + { + error("%s has no value", e2->toChars()); + goto Lerr; + } + e2 = resolveProperties(sc, e2); + if (e2->type == Type::terror) + goto Lerr; + + if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) + sc = sc->pop(); + + switch (t1->ty) + { + case Tpointer: + case Tarray: + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e->type = ((TypeNext *)t1)->next; + break; + + case Tsarray: + { + e2 = e2->implicitCastTo(sc, Type::tsize_t); + + TypeSArray *tsa = (TypeSArray *)t1; + +#if 0 // Don't do now, because it might be short-circuit evaluated + // Do compile time array bounds checking if possible + e2 = e2->optimize(WANTvalue); + if (e2->op == TOKint64) + { + dinteger_t index = e2->toInteger(); + dinteger_t length = tsa->dim->toInteger(); + if (index < 0 || index >= length) + error("array index [%lld] is outside array bounds [0 .. %lld]", + index, length); + } +#endif + e->type = t1->nextOf(); + break; + } + + case Taarray: + { TypeAArray *taa = (TypeAArray *)t1; + if (!arrayTypeCompatible(e2->loc, e2->type, taa->index)) + { + e2 = e2->implicitCastTo(sc, taa->index); // type checking + } + type = taa->next; + break; + } + + case Ttuple: + { + e2 = e2->implicitCastTo(sc, Type::tsize_t); + e2 = e2->optimize(WANTvalue | WANTinterpret); + uinteger_t index = e2->toUInteger(); + size_t length; + TupleExp *te; + TypeTuple *tup; + + if (e1->op == TOKtuple) + { te = (TupleExp *)e1; + length = te->exps->dim; + } + else if (e1->op == TOKtype) + { + tup = (TypeTuple *)t1; + length = Parameter::dim(tup->arguments); + } + else + assert(0); + + if (index < length) + { + + if (e1->op == TOKtuple) + e = (Expression *)te->exps->data[(size_t)index]; + else + e = new TypeExp(e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type); + } + else + { + error("array index [%ju] is outside array bounds [0 .. %zu]", + index, length); + e = e1; + } + break; + } + + default: + error("%s must be an array or pointer type, not %s", + e1->toChars(), e1->type->toChars()); + case Terror: + goto Lerr; + } + return e; + +Lerr: + return new ErrorExp(); +} + +#if DMDV2 +int IndexExp::isLvalue() +{ + return 1; +} +#endif + +Expression *IndexExp::toLvalue(Scope *sc, Expression *e) +{ +// if (type && type->toBasetype()->ty == Tvoid) +// error("voids have no value"); + return this; +} + +Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); + modifiable = 1; + if (e1->op == TOKstring) + error("string literals are immutable"); + if (type && !type->isMutable()) + error("%s isn't mutable", e->toChars()); + if (e1->type->toBasetype()->ty == Taarray) + e1 = e1->modifiableLvalue(sc, e1); + return toLvalue(sc, e); +} + +void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('['); + expToCBuffer(buf, hgs, e2, PREC_assign); + buf->writeByte(']'); +} + + +/************************* PostExp ***********************************/ + +PostExp::PostExp(enum TOK op, Loc loc, Expression *e) + : BinExp(loc, op, sizeof(PostExp), e, + new IntegerExp(loc, 1, Type::tint32)) +{ +} + +Expression *PostExp::semantic(Scope *sc) +{ Expression *e = this; + + if (!type) + { + BinExp::semantic(sc); + e1 = resolveProperties(sc, e1); + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + + Type *t1 = e1->type->toBasetype(); + if (t1->ty == Tclass || t1->ty == Tstruct) + { /* Check for operator overloading, + * but rewrite in terms of ++e instead of e++ + */ + + /* If e1 is not trivial, take a reference to it + */ + Expression *de = NULL; + if (e1->op != TOKvar) + { + // ref v = e1; + Identifier *id = Lexer::uniqueId("__postref"); + ExpInitializer *ei = new ExpInitializer(loc, e1); + VarDeclaration *v = new VarDeclaration(loc, e1->type, id, ei); + v->storage_class |= STCref | STCforeach; + de = new DeclarationExp(loc, v); + e1 = new VarExp(e1->loc, v); + } + + /* Rewrite as: + * auto tmp = e1; ++e1; tmp + */ + Identifier *id = Lexer::uniqueId("__tmp"); + ExpInitializer *ei = new ExpInitializer(loc, e1); + VarDeclaration *tmp = new VarDeclaration(loc, e1->type, id, ei); + Expression *ea = new DeclarationExp(loc, tmp); + + Expression *eb = e1->syntaxCopy(); + eb = new PreExp(op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, loc, eb); + + Expression *ec = new VarExp(loc, tmp); + + // Combine de,ea,eb,ec + if (de) + ea = new CommaExp(loc, de, ea); + e = new CommaExp(loc, ea, eb); + e = new CommaExp(loc, e, ec); + e = e->semantic(sc); + return e; + } + + e = this; + e1->checkScalar(); + e1->checkNoBool(); + if (e1->type->ty == Tpointer) + e = scaleFactor(sc); + else + e2 = e2->castTo(sc, e1->type); + e->type = e1->type; + } + return e; +} + +void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, precedence[op]); + buf->writestring(Token::toChars(op)); +} + +/************************* PreExp ***********************************/ + +PreExp::PreExp(enum TOK op, Loc loc, Expression *e) + : UnaExp(loc, op, sizeof(PreExp), e) +{ +} + +Expression *PreExp::semantic(Scope *sc) +{ + Expression *e; + + e = op_overload(sc); + if (e) + return e; + + // Rewrite as e1+=1 or e1-=1 + if (op == TOKpreplusplus) + e = new AddAssignExp(loc, e1, new IntegerExp(loc, 1, Type::tint32)); + else + e = new MinAssignExp(loc, e1, new IntegerExp(loc, 1, Type::tint32)); + return e->semantic(sc); +} + +void PreExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + expToCBuffer(buf, hgs, e1, precedence[op]); +} + +/************************************************************/ + +/* op can be TOKassign, TOKconstruct, or TOKblit */ + +AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) +{ + ismemset = 0; +} + +Expression *AssignExp::semantic(Scope *sc) +{ + Expression *e1old = e1; + +#if LOGSEMANTIC + printf("AssignExp::semantic('%s')\n", toChars()); +#endif + //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); + //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); + + if (type) + return this; + + if (e2->op == TOKcomma) + { /* Rewrite to get rid of the comma from rvalue + */ + AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); + ea->op = op; + Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); + return e->semantic(sc); + } + + /* Look for operator overloading of a[i]=value. + * Do it before semantic() otherwise the a[i] will have been + * converted to a.opIndex() already. + */ + if (e1->op == TOKarray) + { + ArrayExp *ae = (ArrayExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + Type *t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L1; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L1: + // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) + if (search_function(ad, Id::indexass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); + Expressions *a = (Expressions *)ae->arguments->copy(); + + a->insert(0, e2); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + else + { + // Rewrite (a[i] = value) to (a.opIndex(i, value)) + if (search_function(ad, id)) + { Expression *e = new DotIdExp(loc, ae->e1, id); + + if (1 || !global.params.useDeprecated) + { error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); + return new ErrorExp(); + } + + e = new CallExp(loc, e, (Expression *)ae->arguments->data[0], e2); + e = e->semantic(sc); + return e; + } + } + } + } + /* Look for operator overloading of a[i..j]=value. + * Do it before semantic() otherwise the a[i..j] will have been + * converted to a.opSlice() already. + */ + if (e1->op == TOKslice) + { Type *t1; + SliceExp *ae = (SliceExp *)e1; + AggregateDeclaration *ad; + Identifier *id = Id::index; + + ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); + t1 = ae->e1->type->toBasetype(); + if (t1->ty == Tstruct) + { + ad = ((TypeStruct *)t1)->sym; + goto L2; + } + else if (t1->ty == Tclass) + { + ad = ((TypeClass *)t1)->sym; + L2: + // Rewrite (a[i..j] = value) to (a.opSliceAssign(value, i, j)) + if (search_function(ad, Id::sliceass)) + { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); + Expressions *a = new Expressions(); + + a->push(e2); + if (ae->lwr) + { a->push(ae->lwr); + assert(ae->upr); + a->push(ae->upr); + } + else + assert(!ae->upr); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + } + } + + BinExp::semantic(sc); + + if (e1->op == TOKdottd) + { // Rewrite a.b=e2, when b is a template, as a.b(e2) + Expression *e = new CallExp(loc, e1, e2); + e = e->semantic(sc); + return e; + } + + e2 = resolveProperties(sc, e2); + assert(e1->type); + + /* Rewrite tuple assignment as a tuple of assignments. + */ + if (e1->op == TOKtuple && e2->op == TOKtuple) + { TupleExp *tup1 = (TupleExp *)e1; + TupleExp *tup2 = (TupleExp *)e2; + size_t dim = tup1->exps->dim; + if (dim != tup2->exps->dim) + { + error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); + return new ErrorExp(); + } + else + { Expressions *exps = new Expressions; + exps->setDim(dim); + + for (int i = 0; i < dim; i++) + { Expression *ex1 = (Expression *)tup1->exps->data[i]; + Expression *ex2 = (Expression *)tup2->exps->data[i]; + exps->data[i] = (void *) new AssignExp(loc, ex1, ex2); + } + Expression *e = new TupleExp(loc, exps); + e = e->semantic(sc); + return e; + } + } + + // Determine if this is an initialization of a reference + int refinit = 0; + if (op == TOKconstruct && e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v->storage_class & (STCout | STCref)) + refinit = 1; + } + + Type *t1 = e1->type->toBasetype(); + + if (t1->ty == Tfunction) + { // Rewrite f=value to f(value) + Expression *e = new CallExp(loc, e1, e2); + e = e->semantic(sc); + return e; + } + + /* If it is an assignment from a 'foreign' type, + * check for operator overloading. + */ + if (t1->ty == Tstruct) + { + StructDeclaration *sd = ((TypeStruct *)t1)->sym; + if (op == TOKassign) + { + Expression *e = op_overload(sc); + if (e) + return e; + } + else if (op == TOKconstruct && !refinit) + { Type *t2 = e2->type->toBasetype(); + if (t2->ty == Tstruct && + sd == ((TypeStruct *)t2)->sym && + sd->cpctor) + { /* We have a copy constructor for this + */ + if (e2->op == TOKquestion) + { /* Write as: + * a ? e1 = b : e1 = c; + */ + CondExp *ec = (CondExp *)e2; + AssignExp *ea1 = new AssignExp(ec->e1->loc, e1, ec->e1); + ea1->op = op; + AssignExp *ea2 = new AssignExp(ec->e1->loc, e1, ec->e2); + ea2->op = op; + Expression *e = new CondExp(loc, ec->econd, ea1, ea2); + return e->semantic(sc); + } + else if (e2->op == TOKvar || + e2->op == TOKdotvar || + e2->op == TOKstar || + e2->op == TOKthis || + e2->op == TOKindex) + { /* Write as: + * e1.cpctor(e2); + */ + Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); + e = new CallExp(loc, e, e2); + return e->semantic(sc); + } + } + } + } + else if (t1->ty == Tclass) + { // Disallow assignment operator overloads for same type + if (!e2->type->implicitConvTo(e1->type)) + { + Expression *e = op_overload(sc); + if (e) + return e; + } + } + + if (t1->ty == Tsarray && !refinit) + { // Convert e1 to e1[] + Expression *e = new SliceExp(e1->loc, e1, NULL, NULL); + e1 = e->semantic(sc); + t1 = e1->type->toBasetype(); + } + + e2->rvalue(); + + if (e1->op == TOKarraylength) + { + // e1 is not an lvalue, but we let code generator handle it + ArrayLengthExp *ale = (ArrayLengthExp *)e1; + + ale->e1 = ale->e1->modifiableLvalue(sc, e1); + } + else if (e1->op == TOKslice) + { + Type *tn = e1->type->nextOf(); + if (tn && !tn->isMutable() && op != TOKconstruct) + { error("slice %s is not mutable", e1->toChars()); + return new ErrorExp(); + } + } + else + { // Try to do a decent error message with the expression + // before it got constant folded + if (e1->op != TOKvar) + e1 = e1->optimize(WANTvalue); + + if (op != TOKconstruct) + e1 = e1->modifiableLvalue(sc, e1old); + } + + Type *t2 = e2->type; + if (e1->op == TOKslice && + t1->nextOf() && + e2->implicitConvTo(t1->nextOf()) + ) + { // memset + ismemset = 1; // make it easy for back end to tell what this is + e2 = e2->implicitCastTo(sc, t1->nextOf()); + } + else if (t1->ty == Tsarray) + { + /* Should have already converted e1 => e1[] + */ + assert(op == TOKconstruct); + //error("cannot assign to static array %s", e1->toChars()); + } + else if (e1->op == TOKslice) + { + e2 = e2->implicitCastTo(sc, e1->type->constOf()); + } + else + { + e2 = e2->implicitCastTo(sc, e1->type); + } + + /* Look for array operations + */ + if (e1->op == TOKslice && !ismemset && + (e2->op == TOKadd || e2->op == TOKmin || + e2->op == TOKmul || e2->op == TOKdiv || + e2->op == TOKmod || e2->op == TOKxor || + e2->op == TOKand || e2->op == TOKor || + e2->op == TOKtilde || e2->op == TOKneg)) + { + type = e1->type; + return arrayOp(sc); + } + + type = e1->type; + assert(type); + return this; +} + +Expression *AssignExp::checkToBoolean(Scope *sc) +{ + // Things like: + // if (a = b) ... + // are usually mistakes. + + error("'=' does not give a boolean result"); + return new ErrorExp(); +} + +/************************************************************/ + +ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2) + : AssignExp(loc, e1, e2) +{ + op = TOKconstruct; +} + +/************************************************************/ + +AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) +{ +} + +Expression *AddAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + if (e1->op == TOKslice) + { + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + else + { + e1 = e1->modifiableLvalue(sc, e1); + } + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1->nextOf()->equals(tb2->nextOf()) + ) + { + type = e1->type; + typeCombine(sc); + e = this; + } + else + { + e1->checkScalar(); + e1->checkNoBool(); + if (tb1->ty == Tpointer && tb2->isintegral()) + e = scaleFactor(sc); + else if (tb1->ty == Tbit || tb1->ty == Tbool) + { +#if 0 + // Need to rethink this + if (e1->op != TOKvar) + { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 + VarDeclaration *v; + Expression *ea; + Expression *ex; + + Identifier *id = Lexer::uniqueId("__name"); + + v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + + ea = new AddrExp(loc, e1); + ea = new AssignExp(loc, new VarExp(loc, v), ea); + + ex = new VarExp(loc, v); + ex = new PtrExp(loc, ex); + e = new AddExp(loc, ex, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, ex->syntaxCopy(), e); + + e = new CommaExp(loc, ea, e); + } + else +#endif + { // Rewrite e1+=e2 to e1=e1+e2 + // BUG: doesn't account for side effects in e1 + // BUG: other assignment operators for bits aren't handled at all + e = new AddExp(loc, e1, e2); + e = new CastExp(loc, e, e1->type); + e = new AssignExp(loc, e1->syntaxCopy(), e); + } + e = e->semantic(sc); + } + else + { + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + checkComplexAddAssign(); + if (type->isreal() || type->isimaginary()) + { + assert(global.errors || e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + } + return e; +} + +/************************************************************/ + +MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) +{ +} + +Expression *MinAssignExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + if (e1->type->ty == Tpointer && e2->type->isintegral()) + e = scaleFactor(sc); + else + { + e1 = e1->checkArithmetic(); + e2 = e2->checkArithmetic(); + checkComplexAddAssign(); + type = e1->type; + typeCombine(sc); + if (type->isreal() || type->isimaginary()) + { + assert(e2->type->isfloating()); + e2 = e2->castTo(sc, e1->type); + } + e = this; + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + return e; +} + +/************************************************************/ + +CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) +{ +} + +Expression *CatAssignExp::semantic(Scope *sc) +{ Expression *e; + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKslice) + { SliceExp *se = (SliceExp *)e1; + + if (se->e1->type->toBasetype()->ty == Tsarray) + { error("cannot append to static array %s", se->e1->type->toChars()); + return new ErrorExp(); + } + } + + e1 = e1->modifiableLvalue(sc, e1); + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + e2->rvalue(); + + Type *tb1next = tb1->nextOf(); + + if ((tb1->ty == Tarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + (e2->implicitConvTo(e1->type) +#if DMDV2 + || tb2->nextOf()->implicitConvTo(tb1next) +#endif + ) + ) + { // Append array + e2 = e2->castTo(sc, e1->type); + type = e1->type; + e = this; + } + else if ((tb1->ty == Tarray) && + e2->implicitConvTo(tb1next) + ) + { // Append element + e2 = e2->castTo(sc, tb1next); + type = e1->type; + e = this; + } + else if (tb1->ty == Tarray && + (tb1next->ty == Tchar || tb1next->ty == Twchar) && + e2->implicitConvTo(Type::tdchar) + ) + { // Append dchar to char[] or wchar[] + e2 = e2->castTo(sc, Type::tdchar); + type = e1->type; + e = this; + + /* Do not allow appending wchar to char[] because if wchar happens + * to be a surrogate pair, nothing good can result. + */ + } + else + { + if (tb1 != Type::terror && tb2 != Type::terror) + error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); + e = new ErrorExp(); + } + return e; +} + +/************************************************************/ + +MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) +{ +} + +Expression *MulAssignExp::semantic(Scope *sc) +{ Expression *e; + + e = op_overload(sc); + if (e) + return e; + +#if DMDV2 + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } +#endif + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + checkComplexMulAssign(); + if (e2->type->isfloating()) + { Type *t1; + Type *t2; + + t1 = e1->type; + t2 = e2->type; + if (t1->isreal()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + e2 = e2->castTo(sc, t1); + } + } + else if (t1->isimaginary()) + { + if (t2->isimaginary() || t2->iscomplex()) + { + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + } + } + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + } + return this; +} + +/************************************************************/ + +DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) +{ +} + +Expression *DivAssignExp::semantic(Scope *sc) +{ Expression *e; + + e = op_overload(sc); + if (e) + return e; + +#if DMDV2 + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } +#endif + + if (e1->op == TOKslice) + { // T[] -= ... + typeCombine(sc); + type = e1->type; + return arrayOp(sc); + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkArithmetic(); + e2->checkArithmetic(); + checkComplexMulAssign(); + if (e2->type->isimaginary()) + { Type *t1; + Type *t2; + + t1 = e1->type; + if (t1->isreal()) + { // x/iv = i(-x/v) + // Therefore, the result is 0 + e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); + e2->type = t1; + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + else if (t1->isimaginary()) + { Expression *e; + + switch (t1->ty) + { + case Timaginary32: t2 = Type::tfloat32; break; + case Timaginary64: t2 = Type::tfloat64; break; + case Timaginary80: t2 = Type::tfloat80; break; + default: + assert(0); + } + e2 = e2->castTo(sc, t2); + e = new AssignExp(loc, e1, e2); + e->type = t1; + return e; + } + } + + if (e2->type->iscomplex() && !type->iscomplex()) + error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); + + return this; +} + +/************************************************************/ + +ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) +{ +} + +Expression *ModAssignExp::semantic(Scope *sc) +{ + if (!type) + { + Expression *e = op_overload(sc); + if (e) + return e; + + checkComplexMulAssign(); + return commonSemanticAssign(sc); + } + return this; +} + +/************************************************************/ + +ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) +{ +} + +Expression *ShlAssignExp::semantic(Scope *sc) +{ Expression *e; + + //printf("ShlAssignExp::semantic()\n"); + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); +#if IN_DMD + e2 = e2->castTo(sc, Type::tshiftcnt); +#elif IN_LLVM + e2 = e2->castTo(sc, e1->type); +#endif + return this; +} + +/************************************************************/ + +ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) +{ +} + +Expression *ShrAssignExp::semantic(Scope *sc) +{ Expression *e; + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); +#if IN_DMD + e2 = e2->castTo(sc, Type::tshiftcnt); +#elif IN_LLVM + e2 = e2->castTo(sc, e1->type); +#endif + return this; +} + +/************************************************************/ + +UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) +{ +} + +Expression *UshrAssignExp::semantic(Scope *sc) +{ Expression *e; + + e = op_overload(sc); + if (e) + return e; + + if (e1->op == TOKarraylength) + { + e = ArrayLengthExp::rewriteOpAssign(this); + e = e->semantic(sc); + return e; + } + + e1 = e1->modifiableLvalue(sc, e1); + e1->checkScalar(); + e1->checkNoBool(); + type = e1->type; + typeCombine(sc); + e1->checkIntegral(); + e2 = e2->checkIntegral(); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + return this; +} + +/************************************************************/ + +AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) +{ +} + +Expression *AndAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) +{ +} + +Expression *OrAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/************************************************************/ + +XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) +{ +} + +Expression *XorAssignExp::semantic(Scope *sc) +{ + return commonSemanticAssignIntegral(sc); +} + +/***************** PowAssignExp *******************************************/ + +PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2) + : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2) +{ +} + +Expression *PowAssignExp::semantic(Scope *sc) +{ + Expression *e; + + if (type) + return this; + + e = op_overload(sc); + if (e) + return e; + + e1 = e1->modifiableLvalue(sc, e1); + assert(e1->type && e2->type); + + if ( (e1->type->isintegral() || e1->type->isfloating()) && + (e2->type->isintegral() || e2->type->isfloating())) + { + if (e1->op == TOKvar) + { // Rewrite: e1 = e1 ^^ e2 + e = new PowExp(loc, e1->syntaxCopy(), e2); + e = new AssignExp(loc, e1, e); + } + else + { // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 + Identifier *id = Lexer::uniqueId("__powtmp"); + VarDeclaration *v = new VarDeclaration(e1->loc, e1->type, id, new ExpInitializer(loc, e1)); + v->storage_class |= STCref | STCforeach; + Expression *de = new DeclarationExp(e1->loc, v); + VarExp *ve = new VarExp(e1->loc, v); + e = new PowExp(loc, ve, e2); + e = new AssignExp(loc, new VarExp(e1->loc, v), e); + e = new CommaExp(loc, de, e); + } + e = e->semantic(sc); + return e; + } + incompatibleTypes(); + return new ErrorExp(); +} + + +/************************* AddExp *****************************/ + +AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) +{ +} + +Expression *AddExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("AddExp::semantic('%s')\n", toChars()); +#endif + if (!type) + { + BinExp::semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + if ((tb1->ty == Tarray || tb1->ty == Tsarray) && + (tb2->ty == Tarray || tb2->ty == Tsarray) && + tb1->nextOf()->equals(tb2->nextOf()) + ) + { + type = e1->type; + e = this; + } + else if (tb1->ty == Tpointer && e2->type->isintegral() || + tb2->ty == Tpointer && e1->type->isintegral()) + e = scaleFactor(sc); + else if (tb1->ty == Tpointer && tb2->ty == Tpointer) + { + incompatibleTypes(); + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if ((e1->type->isreal() && e2->type->isimaginary()) || + (e1->type->isimaginary() && e2->type->isreal())) + { + switch (type->toBasetype()->ty) + { + case Tfloat32: + case Timaginary32: + type = Type::tcomplex32; + break; + + case Tfloat64: + case Timaginary64: + type = Type::tcomplex64; + break; + + case Tfloat80: + case Timaginary80: + type = Type::tcomplex80; + break; + + default: + assert(0); + } + } + e = this; + } + return e; + } + return this; +} + +/************************************************************/ + +MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) +{ +} + +Expression *MinExp::semantic(Scope *sc) +{ Expression *e; + Type *t1; + Type *t2; + +#if LOGSEMANTIC + printf("MinExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + BinExp::semanticp(sc); + + e = op_overload(sc); + if (e) + return e; + + e = this; + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if (t1->ty == Tpointer) + { + if (t2->ty == Tpointer) + { // Need to divide the result by the stride + // Replace (ptr - ptr) with (ptr - ptr) / stride + d_int64 stride; + Expression *e; + + typeCombine(sc); // make sure pointer types are compatible + type = Type::tptrdiff_t; + stride = t2->nextOf()->size(); + if (stride == 0) + { + e = new IntegerExp(loc, 0, Type::tptrdiff_t); + } + else + { + e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); + e->type = Type::tptrdiff_t; + } + return e; + } + else if (t2->isintegral()) + e = scaleFactor(sc); + else + { error("incompatible types for minus"); + return new ErrorExp(); + } + } + else if (t2->ty == Tpointer) + { + type = e2->type; + error("can't subtract pointer from %s", e1->type->toChars()); + return new ErrorExp(); + } + else + { + typeCombine(sc); + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if ((t1->isreal() && t2->isimaginary()) || + (t1->isimaginary() && t2->isreal())) + { + switch (type->ty) + { + case Tfloat32: + case Timaginary32: + type = Type::tcomplex32; + break; + + case Tfloat64: + case Timaginary64: + type = Type::tcomplex64; + break; + + case Tfloat80: + case Timaginary80: + type = Type::tcomplex80; + break; + + default: + assert(0); + } + } + } + return e; +} + +/************************* CatExp *****************************/ + +CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) +{ +} + +Expression *CatExp::semantic(Scope *sc) +{ Expression *e; + + //printf("CatExp::semantic() %s\n", toChars()); + if (!type) + { + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + Type *tb1 = e1->type->toBasetype(); + Type *tb2 = e2->type->toBasetype(); + + + /* BUG: Should handle things like: + * char c; + * c ~ ' ' + * ' ' ~ c; + */ + +#if 0 + e1->type->print(); + e2->type->print(); +#endif + Type *tb1next = tb1->nextOf(); + Type *tb2next = tb2->nextOf(); + + if ((tb1->ty == Tsarray || tb1->ty == Tarray) && + e2->implicitConvTo(tb1next) >= MATCHconvert) + { + e2 = e2->implicitCastTo(sc, tb1next); + type = tb1next->arrayOf(); + if (tb2->ty == Tarray) + { // Make e2 into [e2] + e2 = new ArrayLiteralExp(e2->loc, e2); + e2->type = type; + } + return this; + } + else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && + e1->implicitConvTo(tb2next) >= MATCHconvert) + { + e1 = e1->implicitCastTo(sc, tb2next); + type = tb2next->arrayOf(); + if (tb1->ty == Tarray) + { // Make e1 into [e1] + e1 = new ArrayLiteralExp(e1->loc, e1); + e1->type = type; + } + return this; + } + + if ((tb1->ty == Tsarray || tb1->ty == Tarray) && + (tb2->ty == Tsarray || tb2->ty == Tarray) && + (tb1next->mod || tb2next->mod) && + (tb1next->mod != tb2next->mod) + ) + { + Type *t1 = tb1next->mutableOf()->constOf()->arrayOf(); + Type *t2 = tb2next->mutableOf()->constOf()->arrayOf(); + if (e1->op == TOKstring && !((StringExp *)e1)->committed) + e1->type = t1; + else + e1 = e1->castTo(sc, t1); + if (e2->op == TOKstring && !((StringExp *)e2)->committed) + e2->type = t2; + else + e2 = e2->castTo(sc, t2); + } + + typeCombine(sc); + type = type->toHeadMutable(); + + Type *tb = type->toBasetype(); + if (tb->ty == Tsarray) + type = tb->nextOf()->arrayOf(); + if (type->ty == Tarray && tb1next && tb2next && + tb1next->mod != tb2next->mod) + { + type = type->nextOf()->toHeadMutable()->arrayOf(); + } +#if 0 + e1->type->print(); + e2->type->print(); + type->print(); + print(); +#endif + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (e1->op == TOKstring && e2->op == TOKstring) + e = optimize(WANTvalue); + else if ((t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { + e = this; + } + else + { + //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); + incompatibleTypes(); + return new ErrorExp(); + } + e->type = e->type->semantic(loc, sc); + return e; + } + return this; +} + +/************************************************************/ + +MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) +{ +} + +Expression *MulExp::semantic(Scope *sc) +{ Expression *e; + +#if 0 + printf("MulExp::semantic() %s\n", toChars()); +#endif + if (type) + { + return this; + } + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) + e2->checkArithmetic(); + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { Expression *e; + + switch (t1->toBasetype()->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + + // iy * iv = -yv + e1->type = type; + e2->type = type; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) +{ +} + +Expression *DivExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) + e2->checkArithmetic(); + if (type->isfloating()) + { Type *t1 = e1->type; + Type *t2 = e2->type; + + if (t1->isreal()) + { + type = t2; + if (t2->isimaginary()) + { Expression *e; + + // x/iv = i(-x/v) + e2->type = t1; + e = new NegExp(loc, this); + e = e->semantic(sc); + return e; + } + } + else if (t2->isreal()) + { + type = t1; + } + else if (t1->isimaginary()) + { + if (t2->isimaginary()) + { + switch (t1->toBasetype()->ty) + { + case Timaginary32: type = Type::tfloat32; break; + case Timaginary64: type = Type::tfloat64; break; + case Timaginary80: type = Type::tfloat80; break; + default: assert(0); + } + } + else + type = t2; // t2 is complex + } + else if (t2->isimaginary()) + { + type = t1; // t1 is complex + } + } + return this; +} + +/************************************************************/ + +ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) +{ +} + +Expression *ModExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkArithmetic(); + if (!e2->isArrayOperand()) + e2->checkArithmetic(); + if (type->isfloating()) + { type = e1->type; + if (e2->type->iscomplex()) + { error("cannot perform modulo complex arithmetic"); + return new ErrorExp(); + } + } + return this; +} + +PowExp::PowExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2) +{ +} + +Expression *PowExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + //printf("PowExp::semantic() %s\n", toChars()); + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + assert(e1->type && e2->type); + if ( (e1->type->isintegral() || e1->type->isfloating()) && + (e2->type->isintegral() || e2->type->isfloating())) + { + // For built-in numeric types, there are several cases. + // TODO: backend support, especially for e1 ^^ 2. + + bool wantSqrt = false; + e1 = e1->optimize(0); + e2 = e2->optimize(0); + + // Replace 1 ^^ x or 1.0^^x by (x, 1) + if ((e1->op == TOKint64 && e1->toInteger() == 1) || + (e1->op == TOKfloat64 && e1->toReal() == 1.0)) + { + typeCombine(sc); + e = new CommaExp(loc, e2, e1); + e = e->semantic(sc); + return e; + } + // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral + if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L) + { + typeCombine(sc); + Type* resultType = type; + e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type)); + e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType)); + e = e->semantic(sc); + return e; + } + // All other negative integral powers are illegal + if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0) + { + error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?", + e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars()); + return new ErrorExp(); + } + + // Determine if we're raising to an integer power. + sinteger_t intpow = 0; + if (e2->op == TOKint64 && ((sinteger_t)e2->toInteger() == 2 || (sinteger_t)e2->toInteger() == 3)) + intpow = e2->toInteger(); + else if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal()))) + intpow = (sinteger_t)(e2->toReal()); + + // Deal with x^^2, x^^3 immediately, since they are of practical importance. + if (intpow == 2 || intpow == 3) + { + typeCombine(sc); + // Replace x^^2 with (tmp = x, tmp*tmp) + // Replace x^^3 with (tmp = x, tmp*tmp*tmp) + Identifier *idtmp = Lexer::uniqueId("__tmp"); + VarDeclaration *tmp = new VarDeclaration(loc, e1->type->toBasetype(), idtmp, new ExpInitializer(0, e1)); + tmp->storage_class = STCctfe; + Expression *ve = new VarExp(loc, tmp); + Expression *ae = new DeclarationExp(loc, tmp); + /* Note that we're reusing ve. This should be ok. + */ + Expression *me = new MulExp(loc, ve, ve); + if (intpow == 3) + me = new MulExp(loc, me, ve); + e = new CommaExp(loc, ae, me); + e = e->semantic(sc); + return e; + } + + static int importMathChecked = 0; + if (!importMathChecked) + { + importMathChecked = 1; + for (int i = 0; i < Module::amodules.dim; i++) + { Module *mi = (Module *)Module::amodules.data[i]; + //printf("\t[%d] %s\n", i, mi->toChars()); + if (mi->ident == Id::math && + mi->parent->ident == Id::std && + !mi->parent->parent) + goto L1; + } + error("must import std.math to use ^^ operator"); + return new ErrorExp(); + + L1: ; + } + + e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::std); + e = new DotIdExp(loc, e, Id::math); + if (e2->op == TOKfloat64 && e2->toReal() == 0.5) + { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) + typeCombine(sc); + e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1); + } + else + { + // Replace e1 ^^ e2 with .std.math.pow(e1, e2) + // We don't combine the types if raising to an integer power (because + // integer powers are treated specially by std.math.pow). + if (!e2->type->isintegral()) + typeCombine(sc); + // In fact, if it *could* have been an integer, make it one. + if (e2->op == TOKfloat64 && intpow != 0) + e2 = new IntegerExp(loc, intpow, Type::tint64); + e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2); + } + e = e->semantic(sc); + // Always constant fold integer powers of literals. This will run the interpreter + // on .std.math.pow + if ((e1->op == TOKfloat64 || e1->op == TOKint64) && (e2->op == TOKint64)) + e = e->optimize(WANTvalue | WANTinterpret); + + return e; + } + incompatibleTypes(); + return new ErrorExp(); +} + +/************************************************************/ + +ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) +{ +} + +Expression *ShlExp::semantic(Scope *sc) +{ Expression *e; + + //printf("ShlExp::semantic(), type = %p\n", type); + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) +{ +} + +Expression *ShrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) +{ +} + +Expression *UshrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + e1 = e1->checkIntegral(); + e2 = e2->checkIntegral(); + e1 = e1->integralPromotions(sc); + //e2 = e2->castTo(sc, Type::tshiftcnt); + e2 = e2->castTo(sc, e1->type); // LDC + type = e1->type; + } + return this; +} + +/************************************************************/ + +AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) +{ +} + +Expression *AndExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) + e2->checkIntegral(); + } + } + return this; +} + +/************************************************************/ + +OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) +{ +} + +Expression *OrExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) + e2->checkIntegral(); + } + } + return this; +} + +/************************************************************/ + +XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) +{ +} + +Expression *XorExp::semantic(Scope *sc) +{ Expression *e; + + if (!type) + { BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + if (e1->type->toBasetype()->ty == Tbool && + e2->type->toBasetype()->ty == Tbool) + { + type = e1->type; + e = this; + } + else + { + typeCombine(sc); + if (!e1->isArrayOperand()) + e1->checkIntegral(); + if (!e2->isArrayOperand()) + e2->checkIntegral(); + } + } + return this; +} + + +/************************************************************/ + +OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) +{ +} + +Expression *OrOrExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for AndAnd + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(sc); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(TRUE)) + { + return new IntegerExp(loc, 1, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e2->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + { error("%s is not an expression", e2->toChars()); + return new ErrorExp(); + } + return this; +} + +Expression *OrOrExp::checkToBoolean(Scope *sc) +{ + e2 = e2->checkToBoolean(sc); + return this; +} + +int OrOrExp::isBit() +{ + return TRUE; +} + +int OrOrExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) +{ +} + +Expression *AndAndExp::semantic(Scope *sc) +{ + unsigned cs1; + + // same as for OrOr + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + e1 = e1->checkToPointer(); + e1 = e1->checkToBoolean(sc); + cs1 = sc->callSuper; + + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate e2 if we don't have to. + */ + e1 = e1->optimize(WANTflags); + if (e1->isBool(FALSE)) + { + return new IntegerExp(loc, 0, Type::tboolean); + } + } + + e2 = e2->semantic(sc); + sc->mergeCallSuper(loc, cs1); + e2 = resolveProperties(sc, e2); + e2 = e2->checkToPointer(); + + type = Type::tboolean; + if (e2->type->ty == Tvoid) + type = Type::tvoid; + if (e2->op == TOKtype || e2->op == TOKimport) + { error("%s is not an expression", e2->toChars()); + return new ErrorExp(); + } + return this; +} + +Expression *AndAndExp::checkToBoolean(Scope *sc) +{ + e2 = e2->checkToBoolean(sc); + return this; +} + +int AndAndExp::isBit() +{ + return TRUE; +} + +int AndAndExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return e1->checkSideEffect(2) || e2->checkSideEffect(2); + } + else + { + e1->checkSideEffect(1); + return e2->checkSideEffect(flag); + } +} + +/************************************************************/ + +InExp::InExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKin, sizeof(InExp), e1, e2) +{ +} + +Expression *InExp::semantic(Scope *sc) +{ Expression *e; + + if (type) + return this; + + BinExp::semanticp(sc); + e = op_overload(sc); + if (e) + return e; + + //type = Type::tboolean; + Type *t2b = e2->type->toBasetype(); + switch (t2b->ty) + { + case Taarray: + { + TypeAArray *ta = (TypeAArray *)t2b; + +#if DMDV2 + // Special handling for array keys + if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) +#endif + { + // Convert key to type of key + e1 = e1->implicitCastTo(sc, ta->index); + } + + // Return type is pointer to value + type = ta->nextOf()->pointerTo(); + break; + } + + default: + error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); + case Terror: + return new ErrorExp(); + } + return this; +} + +int InExp::isBit() +{ + return FALSE; +} + + +/************************************************************/ + +/* This deletes the key e1 from the associative array e2 + */ + +RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) +{ + type = Type::tvoid; +} + +/************************************************************/ + +CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(CmpExp), e1, e2) +{ +} + +Expression *CmpExp::semantic(Scope *sc) +{ Expression *e; + +#if LOGSEMANTIC + printf("CmpExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + BinExp::semanticp(sc); + + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (t1->ty == Tclass && e2->op == TOKnull || + t2->ty == Tclass && e1->op == TOKnull) + { + error("do not use null when comparing class types"); + return new ErrorExp(); + } + + e = op_overload(sc); + if (e) + { + if (!e->type->isscalar() && e->type->equals(e1->type)) + { + error("recursive opCmp expansion"); + e = new ErrorExp(); + } + else + { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); + e = e->semantic(sc); + } + return e; + } + + /* Disallow comparing T[]==T and T==T[] + */ + if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || + e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) + { + incompatibleTypes(); + return new ErrorExp(); + } + + typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + t1 = e1->type->toBasetype(); + t2 = e2->type->toBasetype(); + if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && + (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) + { + if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && + t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && + (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) + error("array comparison type mismatch, %s vs %s", t1->nextOf()->toChars(), t2->nextOf()->toChars()); + e = this; + } + else if (t1->ty == Tstruct || t2->ty == Tstruct || + (t1->ty == Tclass && t2->ty == Tclass)) + { + if (t2->ty == Tstruct) + error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); + else + error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); + e = new ErrorExp(); + } +#if 1 + else if (t1->iscomplex() || t2->iscomplex()) + { + error("compare not defined for complex operands"); + e = new ErrorExp(); + } +#endif + else + { e1->rvalue(); + e2->rvalue(); + e = this; + } + //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars()); + return e; +} + +int CmpExp::isBit() +{ + return TRUE; +} + + +/************************************************************/ + +EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(EqualExp), e1, e2) +{ + assert(op == TOKequal || op == TOKnotequal); +} + +Expression *EqualExp::semantic(Scope *sc) +{ Expression *e; + + //printf("EqualExp::semantic('%s')\n", toChars()); + if (type) + return this; + + BinExp::semanticp(sc); + + /* Before checking for operator overloading, check to see if we're + * comparing the addresses of two statics. If so, we can just see + * if they are the same symbol. + */ + if (e1->op == TOKaddress && e2->op == TOKaddress) + { AddrExp *ae1 = (AddrExp *)e1; + AddrExp *ae2 = (AddrExp *)e2; + + if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) + { VarExp *ve1 = (VarExp *)ae1->e1; + VarExp *ve2 = (VarExp *)ae2->e1; + + if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) + { + // They are the same, result is 'true' for ==, 'false' for != + e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); + return e; + } + } + } + + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (t1->ty == Tclass && e2->op == TOKnull || + t2->ty == Tclass && e1->op == TOKnull) + { + error("use '%s' instead of '%s' when comparing with null", + Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), + Token::toChars(op)); + return new ErrorExp(); + } + + if ((t1->ty == Tarray || t1->ty == Tsarray) && + (t2->ty == Tarray || t2->ty == Tsarray)) + { Type *t1n = t1->nextOf()->toBasetype(); + Type *t2n = t2->nextOf()->toBasetype(); + if (t1n->constOf() != t2n->constOf() && + !((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) && + (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) && + !(t1n->ty == Tvoid || t2n->ty == Tvoid) + ) + { /* Rewrite as: + * _ArrayEq(e1, e2) + */ + Expression *eq = new IdentifierExp(loc, Id::_ArrayEq); + Expressions *args = new Expressions(); + args->push(e1); + args->push(e2); + e = new CallExp(loc, eq, args); + if (op == TOKnotequal) + e = new NotExp(loc, e); + e = e->semantic(sc); + return e; + } + } + + //if (e2->op != TOKnull) + { + e = op_overload(sc); + if (e) + { + if (op == TOKnotequal) + { + e = new NotExp(e->loc, e); + e = e->semantic(sc); + } + return e; + } + } + + /* Disallow comparing T[]==T and T==T[] + */ + if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || + e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) + { + incompatibleTypes(); + return new ErrorExp(); + } + + e = typeCombine(sc); + type = Type::tboolean; + + // Special handling for array comparisons + if (!arrayTypeCompatible(loc, e1->type, e2->type)) + { + if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) + { + // Cast both to complex + e1 = e1->castTo(sc, Type::tcomplex80); + e2 = e2->castTo(sc, Type::tcomplex80); + } + } + return e; +} + +int EqualExp::isBit() +{ + return TRUE; +} + + + +/************************************************************/ + +IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) + : BinExp(loc, op, sizeof(IdentityExp), e1, e2) +{ +} + +Expression *IdentityExp::semantic(Scope *sc) +{ + if (type) + return this; + + BinExp::semanticp(sc); + type = Type::tboolean; + typeCombine(sc); + if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) + { + // Cast both to complex + e1 = e1->castTo(sc, Type::tcomplex80); + e2 = e2->castTo(sc, Type::tcomplex80); + } + return this; +} + +int IdentityExp::isBit() +{ + return TRUE; +} + + +/****************************************************************/ + +CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) + : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) +{ + this->econd = econd; +} + +Expression *CondExp::syntaxCopy() +{ + return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); +} + + +Expression *CondExp::semantic(Scope *sc) +{ Type *t1; + Type *t2; + unsigned cs0; + unsigned cs1; + +#if LOGSEMANTIC + printf("CondExp::semantic('%s')\n", toChars()); +#endif + if (type) + return this; + + econd = econd->semantic(sc); + econd = resolveProperties(sc, econd); + econd = econd->checkToPointer(); + econd = econd->checkToBoolean(sc); + +#if 0 /* this cannot work right because the types of e1 and e2 + * both contribute to the type of the result. + */ + if (sc->flags & SCOPEstaticif) + { + /* If in static if, don't evaluate what we don't have to. + */ + econd = econd->optimize(WANTflags); + if (econd->isBool(TRUE)) + { + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + return e1; + } + else if (econd->isBool(FALSE)) + { + e2 = e2->semantic(sc); + e2 = resolveProperties(sc, e2); + return e2; + } + } +#endif + + + cs0 = sc->callSuper; + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + cs1 = sc->callSuper; + sc->callSuper = cs0; + e2 = e2->semantic(sc); + e2 = resolveProperties(sc, e2); + sc->mergeCallSuper(loc, cs1); + + + // If either operand is void, the result is void + t1 = e1->type; + t2 = e2->type; + if (t1->ty == Tvoid || t2->ty == Tvoid) + type = Type::tvoid; + else if (t1 == t2) + type = t1; + else + { + typeCombine(sc); + switch (e1->type->toBasetype()->ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e2 = e2->castTo(sc, e1->type); + break; + } + switch (e2->type->toBasetype()->ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + e1 = e1->castTo(sc, e2->type); + break; + } + if (type->toBasetype()->ty == Tarray) + { + e1 = e1->castTo(sc, type); + e2 = e2->castTo(sc, type); + } + } +#if 0 + printf("res: %s\n", type->toChars()); + printf("e1 : %s\n", e1->type->toChars()); + printf("e2 : %s\n", e2->type->toChars()); +#endif + return this; +} + +#if DMDV2 +int CondExp::isLvalue() +{ + return e1->isLvalue() && e2->isLvalue(); +} +#endif + +Expression *CondExp::toLvalue(Scope *sc, Expression *ex) +{ + PtrExp *e; + + // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) + e = new PtrExp(loc, this, type); + + e1 = e1->addressOf(sc); + //e1 = e1->toLvalue(sc, NULL); + + e2 = e2->addressOf(sc); + //e2 = e2->toLvalue(sc, NULL); + + typeCombine(sc); + + type = e2->type; + return e; +} + +Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //error("conditional expression %s is not a modifiable lvalue", toChars()); + e1 = e1->modifiableLvalue(sc, e1); + e2 = e2->modifiableLvalue(sc, e1); + return toLvalue(sc, this); +} + +void CondExp::checkEscape() +{ + e1->checkEscape(); + e2->checkEscape(); +} + +void CondExp::checkEscapeRef() +{ + e1->checkEscapeRef(); + e2->checkEscapeRef(); +} + + +Expression *CondExp::checkToBoolean(Scope *sc) +{ + e1 = e1->checkToBoolean(sc); + e2 = e2->checkToBoolean(sc); + return this; +} + +int CondExp::checkSideEffect(int flag) +{ + if (flag == 2) + { + return econd->checkSideEffect(2) || + e1->checkSideEffect(2) || + e2->checkSideEffect(2); + } + else + { + econd->checkSideEffect(1); + e1->checkSideEffect(flag); + return e2->checkSideEffect(flag); + } +} + +#if DMDV2 +int CondExp::canThrow() +{ + return econd->canThrow() || e1->canThrow() || e2->canThrow(); +} +#endif + +void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, econd, PREC_oror); + buf->writestring(" ? "); + expToCBuffer(buf, hgs, e1, PREC_expr); + buf->writestring(" : "); + expToCBuffer(buf, hgs, e2, PREC_cond); +} + +/************************************************************/ + +#if IN_LLVM + +// Strictly LDC specific stuff + +GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) + : UnaExp(loc, TOKgep, sizeof(GEPExp), e) +{ + index = idx; + ident = id; +} + +void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + expToCBuffer(buf, hgs, e1, PREC_primary); + buf->writeByte('.'); + buf->writestring(ident->toChars()); +} + +Expression* GEPExp::toLvalue(Scope* sc, Expression* e) +{ + // GEP's are always lvalues, at least in the "LLVM sense" ... + return this; +} + +#endif + +/****************************************************************/ + +DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) + : Expression(loc, TOKdefault, size) +{ + this->subop = subop; +} + +void DefaultInitExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(subop)); +} + +/****************************************************************/ + +FileInitExp::FileInitExp(Loc loc) + : DefaultInitExp(loc, TOKfile, sizeof(FileInitExp)) +{ +} + +Expression *FileInitExp::semantic(Scope *sc) +{ + //printf("FileInitExp::semantic()\n"); + type = Type::tchar->invariantOf()->arrayOf(); + return this; +} + +Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc) +{ + //printf("FileInitExp::resolve() %s\n", toChars()); + const char *s = loc.filename ? loc.filename : sc->module->ident->toChars(); + Expression *e = new StringExp(loc, (char *)s); + e = e->semantic(sc); + e = e->castTo(sc, type); + return e; +} + +/****************************************************************/ + +LineInitExp::LineInitExp(Loc loc) + : DefaultInitExp(loc, TOKline, sizeof(LineInitExp)) +{ +} + +Expression *LineInitExp::semantic(Scope *sc) +{ + type = Type::tint32; + return this; +} + +Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc) +{ + Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32); + e = e->castTo(sc, type); + return e; +} + + diff --git a/dmd2/expression.h b/dmd2/expression.h index addf561a..0c9d22ba 100644 --- a/dmd2/expression.h +++ b/dmd2/expression.h @@ -1,2006 +1,2086 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct InterState; -#if IN_DMD -struct Symbol; // back end symbol -#endif -struct OverloadSet; -#if IN_LLVM -struct AssignExp; -#endif - -enum TOK; - -#if IN_DMD -// Back end -struct IRState; -struct dt_t; -#endif - -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#endif -#if IN_DMD -struct elem; -#endif - -#if IN_LLVM -struct IRState; -struct DValue; -namespace llvm { - class Constant; - class ConstantInt; -} -#endif - -void initPrecedence(); - -Expression *resolveProperties(Scope *sc, Expression *e); -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id); -Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); -void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr, Module *from); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void expandTuples(Expressions *exps); -FuncDeclaration *hasThis(Scope *sc); -Expression *fromConstInitializer(int result, Expression *e); -int arrayExpressionCanThrow(Expressions *exps); - -struct IntRange -{ uinteger_t imin; - uinteger_t imax; -}; - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - int size; // # of bytes in Expression so we can copy() it - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual Expression *semantic(Scope *sc); - Expression *trySemantic(Scope *sc); - - int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() - - void print(); - char *toChars(); - virtual void dump(int indent); - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void rvalue(); - - static Expression *combine(Expression *e1, Expression *e2); - static Expressions *arraySyntaxCopy(Expressions *exps); - - virtual dinteger_t toInteger(); - virtual uinteger_t toUInteger(); - virtual real_t toReal(); - virtual real_t toImaginary(); - virtual complex_t toComplex(); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toMangleBuffer(OutBuffer *buf); - virtual int isLvalue(); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - virtual Expression *implicitCastTo(Scope *sc, Type *t); - virtual MATCH implicitConvTo(Type *t); - virtual IntRange getIntRange(); - virtual Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - void checkScalar(); - void checkNoBool(); - Expression *checkIntegral(); - Expression *checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); - void checkPurity(Scope *sc, FuncDeclaration *f); - virtual Expression *checkToBoolean(); - Expression *checkToPointer(); - Expression *addressOf(Scope *sc); - Expression *deref(); - Expression *integralPromotions(Scope *sc); - - Expression *toDelegate(Scope *sc, Type *t); - virtual void scanForNestedRef(Scope *sc); - - virtual Expression *optimize(int result); - #define WANTflags 1 - #define WANTvalue 2 - #define WANTinterpret 4 - - virtual Expression *interpret(InterState *istate); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - virtual int checkSideEffect(int flag); - virtual int canThrow(); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Expression *inlineScan(InlineScanState *iss); - - // For operator overloading - virtual int isCommutative(); - virtual Identifier *opId(); - virtual Identifier *opId_r(); - - // For array ops - virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - virtual Expression *buildArrayLoop(Arguments *fparams); - -#if IN_DMD - // Back end - virtual elem *toElem(IRState *irs); - virtual dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - virtual DValue* toElem(IRState* irs); - virtual llvm::Constant *toConstElem(IRState *irs); - virtual void cacheLvalue(IRState* irs); - - llvm::Value* cachedLvalue; - - virtual AssignExp* isAssignExp() { return NULL; } -#endif -}; - -struct IntegerExp : Expression -{ - dinteger_t value; - - IntegerExp(Loc loc, dinteger_t value, Type *type); - IntegerExp(dinteger_t value); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - void dump(int indent); - IntRange getIntRange(); - dinteger_t toInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - int isConst(); - int isBool(int result); - MATCH implicitConvTo(Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *toLvalue(Scope *sc, Expression *e); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ErrorExp : IntegerExp -{ - ErrorExp(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct RealExp : Expression -{ - real_t value; - - RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ComplexExp : Expression -{ - complex_t value; - - ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#ifdef _DH - OutBuffer hexp; -#endif -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct IdentifierExp : Expression -{ - Identifier *ident; - Declaration *var; - - IdentifierExp(Loc loc, Identifier *ident); - IdentifierExp(Loc loc, Declaration *var); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct DollarExp : IdentifierExp -{ - DollarExp(Loc loc); -}; - -struct DsymbolExp : Expression -{ - Dsymbol *s; - int hasOverloads; - - DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct ThisExp : Expression -{ - Declaration *var; - - ThisExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct SuperExp : ThisExp -{ - SuperExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NullExp : Expression -{ - unsigned char committed; // !=0 if type is committed - - NullExp(Loc loc); - Expression *semantic(Scope *sc); - int isBool(int result); - int isConst(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StringExp : Expression -{ - void *string; // char, wchar, or dchar data - size_t len; // number of chars, wchars, or dchars - unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' - - StringExp(Loc loc, char *s); - StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); - //Expression *syntaxCopy(); - int equals(Object *o); - char *toChars(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - size_t length(); - StringExp *toUTF8(Scope *sc); - Expression *implicitCastTo(Scope *sc, Type *t); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - unsigned charAt(size_t i); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Tuple - -struct TupleExp : Expression -{ - Expressions *exps; - - TupleExp(Loc loc, Expressions *exps); - TupleExp(Loc loc, TupleDeclaration *tup); - Expression *syntaxCopy(); - int equals(Object *o); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - void checkEscape(); - int checkSideEffect(int flag); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *castTo(Scope *sc, Type *t); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ArrayLiteralExp : Expression -{ - Expressions *elements; - - ArrayLiteralExp(Loc loc, Expressions *elements); - ArrayLiteralExp(Loc loc, Expression *e); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct AssocArrayLiteralExp : Expression -{ - Expressions *keys; - Expressions *values; - - AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isBool(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StructLiteralExp : Expression -{ - StructDeclaration *sd; // which aggregate this is for - Expressions *elements; // parallels sd->fields[] with - // NULL entries for fields to skip - -#if IN_DMD - Symbol *sym; // back end symbol to initialize with literal -#endif - size_t soffset; // offset from start of s - int fillHoles; // fill alignment 'holes' with zero - - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *getField(Type *type, unsigned offset); - int getFieldIndex(Type *type, unsigned offset); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - void scanForNestedRef(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isLvalue(); - // LDC: struct literals aren't lvalues! Taking their address can lead to - // incorrect behavior, see LDC#218, DMD#2682 - // Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(); - MATCH implicitConvTo(Type *t); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident); -#if IN_DMD -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif - -struct TypeExp : Expression -{ - TypeExp(Loc loc, Type *type); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ScopeExp : Expression -{ - ScopeDsymbol *sds; - - ScopeExp(Loc loc, ScopeDsymbol *sds); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TemplateExp : Expression -{ - TemplateDeclaration *td; - - TemplateExp(Loc loc, TemplateDeclaration *td); - void rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct NewExp : Expression -{ - /* thisexp.new(newargs) newtype(arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - Type *newtype; - Expressions *arguments; // Array of Expression's - - CtorDeclaration *member; // constructor function - NewDeclaration *allocator; // allocator function - int onstack; // allocate on stack - - NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - int canThrow(); - - //int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NewAnonClassExp : Expression -{ - /* thisexp.new(newargs) class baseclasses { } (arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - ClassDeclaration *cd; // class being instantiated - Expressions *arguments; // Array of Expression's to call class constructor - - NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, - ClassDeclaration *cd, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int canThrow(); -}; - -struct SymbolExp : Expression -{ - Declaration *var; - int hasOverloads; - - SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// Offset from symbol - -struct SymOffExp : SymbolExp -{ - unsigned offset; - Module* m; // starting point for overload resolution - - SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); - Expression *semantic(Scope *sc); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isConst(); - int isBool(int result); - Expression *doInline(InlineDoState *ids); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// Variable - -struct VarExp : SymbolExp -{ - VarExp(Loc loc, Declaration *var, int hasOverloads = 0); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void dump(int indent); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - void scanForNestedRef(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -#if DMDV2 -// Overload Set - -struct OverExp : Expression -{ - OverloadSet *vars; - - OverExp(OverloadSet *s); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; -#endif - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void scanForNestedRef(Scope *sc); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - int inlineCost(InlineCostState *ics); - //Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Declaration of a symbol - -struct DeclarationExp : Expression -{ - Dsymbol *declaration; - - DeclarationExp(Loc loc, Dsymbol *declaration); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void scanForNestedRef(Scope *sc); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TypeidExp : Expression -{ - Type *typeidType; - - TypeidExp(Loc loc, Type *typeidType); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct TraitsExp : Expression -{ - Identifier *ident; - Objects *args; - - TraitsExp(Loc loc, Identifier *ident, Objects *args); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int checkSideEffect(int flag); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct IsExp : Expression -{ - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. - TemplateParameters *parameters; - - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, - enum TOK tok2, TemplateParameters *parameters); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/****************************************************************/ - -struct UnaExp : Expression -{ - Expression *e1; - - UnaExp(Loc loc, enum TOK op, int size, Expression *e1); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); // doesn't need to be virtual -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - void incompatibleTypes(); - void dump(int indent); - void scanForNestedRef(Scope *sc); - Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - int canThrow(); - Expression *arrayOp(Scope *sc); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - -#if IN_DMD - elem *toElemBin(IRState *irs, int op); -#endif -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - int checkSideEffect(int flag); -}; - -/****************************************************************/ - -struct CompileExp : UnaExp -{ - CompileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileExp : UnaExp -{ - FileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssertExp : UnaExp -{ - Expression *msg; - - AssertExp(Loc loc, Expression *e, Expression *msg = NULL); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - int canThrow(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotIdExp : UnaExp -{ - Identifier *ident; - - DotIdExp(Loc loc, Expression *e, Identifier *ident); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int i); -}; - -struct DotTemplateExp : UnaExp -{ - TemplateDeclaration *td; - - DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct DotVarExp : UnaExp -{ - Declaration *var; - int hasOverloads; - - DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct DotTemplateInstanceExp : UnaExp -{ - TemplateInstance *ti; - - DotTemplateInstanceExp(Loc loc, Expression *e, TemplateInstance *ti); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -}; - -struct DelegateExp : UnaExp -{ - FuncDeclaration *func; - Module* m; // starting point for overload resolution - int hasOverloads; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); - Expression *semantic(Scope *sc); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - - int inlineCost(InlineCostState *ics); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotTypeExp : UnaExp -{ - Dsymbol *sym; // symbol that represents a type - - DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CallExp : UnaExp -{ - Expressions *arguments; // function arguments - - CallExp(Loc loc, Expression *e, Expressions *exps); - CallExp(Loc loc, Expression *e); - CallExp(Loc loc, Expression *e, Expression *earg1); - CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); - - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void scanForNestedRef(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AddrExp : UnaExp -{ - Module* m; // starting point for overload resolution - - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct PtrExp : UnaExp -{ - PtrExp(Loc loc, Expression *e); - PtrExp(Loc loc, Expression *e, Type *t); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct NegExp : UnaExp -{ - NegExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UAddExp : UnaExp -{ - UAddExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); -}; - -struct ComExp : UnaExp -{ - ComExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NotExp : UnaExp -{ - NotExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct BoolExp : UnaExp -{ - BoolExp(Loc loc, Expression *e, Type *type); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DeleteExp : UnaExp -{ - DeleteExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CastExp : UnaExp -{ - // Possible to cast to one type while painting to another type - Type *to; // type to cast to - unsigned mod; // MODxxxxx - - CastExp(Loc loc, Expression *e, Type *t); - CastExp(Loc loc, Expression *e, unsigned mod); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - // For operator overloading - Identifier *opId(); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void scanForNestedRef(Scope *sc); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ArrayLengthExp : UnaExp -{ - ArrayLengthExp(Loc loc, Expression *e1); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scanForNestedRef(Scope *sc); - - // For operator overloading - Identifier *opId(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -/****************************************************************/ - -struct DotExp : BinExp -{ - DotExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); -}; - -struct CommaExp : BinExp -{ - CommaExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void checkEscape(); - IntRange getIntRange(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - int checkSideEffect(int flag); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - Expression *interpret(InterState *istate); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - Expression *doInline(InlineDoState *ids); - void scanForNestedRef(Scope *sc); - -#if IN_DMD - elem *toElem(IRState *irs); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -/* For both i++ and i-- - */ -struct PostExp : BinExp -{ - PostExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Identifier *opId(); // For operator overloading -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - Expression *interpret(InterState *istate); - Identifier *opId(); // For operator overloading - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - virtual AssignExp* isAssignExp() { return this; } -#endif -}; - -#if IN_DMD -#define ASSIGNEXP_TOELEM elem *toElem(IRState *irs); -#elif IN_LLVM -#define ASSIGNEXP_TOELEM DValue* toElem(IRState *irs); -#else -#define ASSIGNEXP_TOELEM -#endif - -#define ASSIGNEXP(op) \ -struct op##AssignExp : BinExp \ -{ \ - op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate); \ - X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ - X(Expression *buildArrayLoop(Arguments *fparams);) \ - \ - Identifier *opId(); /* For operator overloading */ \ - \ - ASSIGNEXP_TOELEM \ -}; - -#define X(a) a -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) -#undef X - -#define X(a) - -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -ASSIGNEXP(Cat) - -#undef X -#undef ASSIGNEXP -#undef ASSIGNEXP_TOELEM - -struct AddExp : BinExp -{ - AddExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct MinExp : BinExp -{ - MinExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CatExp : BinExp -{ - CatExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct MulExp : BinExp -{ - MulExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DivExp : BinExp -{ - DivExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ModExp : BinExp -{ - ModExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ShrExp : BinExp -{ - ShrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UshrExp : BinExp -{ - UshrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndExp : BinExp -{ - AndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrExp : BinExp -{ - OrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct XorExp : BinExp -{ - XorExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Arguments *fparams); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int checkSideEffect(int flag); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct RemoveExp : BinExp -{ - RemoveExp(Loc loc, Expression *e1, Expression *e2); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// == and != - -struct EqualExp : BinExp -{ - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// === and !=== - -struct IdentityExp : BinExp -{ - IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -/****************************************************************/ - -struct CondExp : BinExp -{ - Expression *econd; - - CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate); - void checkEscape(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *checkToBoolean(); - int checkSideEffect(int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void scanForNestedRef(Scope *sc); - int canThrow(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -/****************************************************************/ - -struct DefaultInitExp : Expression -{ - enum TOK subop; // which of the derived classes this is - - DefaultInitExp(Loc loc, enum TOK subop, int size); - virtual Expression *resolve(Loc loc, Scope *sc) = 0; - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileInitExp : DefaultInitExp -{ - FileInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; - -struct LineInitExp : DefaultInitExp -{ - LineInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolve(Loc loc, Scope *sc); -}; -#endif - -/****************************************************************/ - -#if IN_LLVM - -// this stuff is strictly LDC - -struct GEPExp : UnaExp -{ - unsigned index; - Identifier* ident; - - GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -}; - -#endif - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -#endif /* DMD_EXPRESSION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_EXPRESSION_H +#define DMD_EXPRESSION_H + +#include "mars.h" +#include "identifier.h" +#include "lexer.h" +#include "arraytypes.h" + +struct Type; +struct Scope; +struct TupleDeclaration; +struct VarDeclaration; +struct FuncDeclaration; +struct FuncLiteralDeclaration; +struct Declaration; +struct CtorDeclaration; +struct NewDeclaration; +struct Dsymbol; +struct Import; +struct Module; +struct ScopeDsymbol; +struct InlineCostState; +struct InlineDoState; +struct InlineScanState; +struct Expression; +struct Declaration; +struct AggregateDeclaration; +struct StructDeclaration; +struct TemplateInstance; +struct TemplateDeclaration; +struct ClassDeclaration; +struct HdrGenState; +struct BinExp; +struct InterState; +#if IN_DMD +struct Symbol; // back end symbol +#endif +struct OverloadSet; +#if IN_LLVM +struct AssignExp; +#endif + +enum TOK; + +#if IN_DMD +// Back end +struct IRState; +struct dt_t; +#endif + +#ifdef IN_GCC +union tree_node; typedef union tree_node elem; +#endif +#if IN_DMD +struct elem; +#endif + +#if IN_LLVM +struct IRState; +struct DValue; +namespace llvm { + class Constant; + class ConstantInt; +} +#endif + +void initPrecedence(); + +Expression *resolveProperties(Scope *sc, Expression *e); +void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); +Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id, Objects *targsi = NULL); +Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); +void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module *from); +void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); +void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); +void expandTuples(Expressions *exps); +FuncDeclaration *hasThis(Scope *sc); +Expression *fromConstInitializer(int result, Expression *e); +int arrayExpressionCanThrow(Expressions *exps); + +struct IntRange +{ uinteger_t imin; + uinteger_t imax; +}; + +struct Expression : Object +{ + Loc loc; // file location + enum TOK op; // handy to minimize use of dynamic_cast + Type *type; // !=NULL means that semantic() has been run + unsigned char size; // # of bytes in Expression so we can copy() it + unsigned char parens; // if this is a parenthesized expression + + Expression(Loc loc, enum TOK op, int size); + Expression *copy(); + virtual Expression *syntaxCopy(); + virtual Expression *semantic(Scope *sc); + Expression *trySemantic(Scope *sc); + + int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() + + void print(); + char *toChars(); + virtual void dump(int indent); + void error(const char *format, ...) IS_PRINTF(2); + void warning(const char *format, ...) IS_PRINTF(2); + virtual void rvalue(); + + static Expression *combine(Expression *e1, Expression *e2); + static Expressions *arraySyntaxCopy(Expressions *exps); + + virtual dinteger_t toInteger(); + virtual uinteger_t toUInteger(); + virtual real_t toReal(); + virtual real_t toImaginary(); + virtual complex_t toComplex(); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual void toMangleBuffer(OutBuffer *buf); + virtual int isLvalue(); + virtual Expression *toLvalue(Scope *sc, Expression *e); + virtual Expression *modifiableLvalue(Scope *sc, Expression *e); + virtual Expression *implicitCastTo(Scope *sc, Type *t); + virtual MATCH implicitConvTo(Type *t); + virtual IntRange getIntRange(); + virtual Expression *castTo(Scope *sc, Type *t); + virtual void checkEscape(); + virtual void checkEscapeRef(); + virtual Expression *resolveLoc(Loc loc, Scope *sc); + void checkScalar(); + void checkNoBool(); + Expression *checkIntegral(); + Expression *checkArithmetic(); + void checkDeprecated(Scope *sc, Dsymbol *s); + void checkPurity(Scope *sc, FuncDeclaration *f); + void checkSafety(Scope *sc, FuncDeclaration *f); + virtual Expression *checkToBoolean(Scope *sc); + Expression *checkToPointer(); + Expression *addressOf(Scope *sc); + Expression *deref(); + Expression *integralPromotions(Scope *sc); + + Expression *toDelegate(Scope *sc, Type *t); + virtual void scanForNestedRef(Scope *sc); + + virtual Expression *optimize(int result); + #define WANTflags 1 + #define WANTvalue 2 + #define WANTinterpret 4 + + virtual Expression *interpret(InterState *istate); + + virtual int isConst(); + virtual int isBool(int result); + virtual int isBit(); + virtual int checkSideEffect(int flag); + virtual int canThrow(); + + virtual int inlineCost(InlineCostState *ics); + virtual Expression *doInline(InlineDoState *ids); + virtual Expression *inlineScan(InlineScanState *iss); + Expression *inlineCopy(Scope *sc); + + // For operator overloading + virtual int isCommutative(); + virtual Identifier *opId(); + virtual Identifier *opId_r(); + + // For array ops + virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + virtual Expression *buildArrayLoop(Parameters *fparams); + int isArrayOperand(); + +#if IN_DMD + // Back end + virtual elem *toElem(IRState *irs); + virtual dt_t **toDt(dt_t **pdt); +#endif + +#if IN_LLVM + virtual DValue* toElem(IRState* irs); + virtual llvm::Constant *toConstElem(IRState *irs); + virtual void cacheLvalue(IRState* irs); + + llvm::Value* cachedLvalue; + + virtual AssignExp* isAssignExp() { return NULL; } +#endif +}; + +struct IntegerExp : Expression +{ + dinteger_t value; + + IntegerExp(Loc loc, dinteger_t value, Type *type); + IntegerExp(dinteger_t value); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + void dump(int indent); + IntRange getIntRange(); + dinteger_t toInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + int isConst(); + int isBool(int result); + MATCH implicitConvTo(Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + Expression *toLvalue(Scope *sc, Expression *e); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ErrorExp : IntegerExp +{ + ErrorExp(); + + Expression *implicitCastTo(Scope *sc, Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct RealExp : Expression +{ + real_t value; + + RealExp(Loc loc, real_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + dinteger_t toInteger(); + uinteger_t toUInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + Expression *castTo(Scope *sc, Type *t); + int isConst(); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ComplexExp : Expression +{ + complex_t value; + + ComplexExp(Loc loc, complex_t value, Type *type); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + char *toChars(); + dinteger_t toInteger(); + uinteger_t toUInteger(); + real_t toReal(); + real_t toImaginary(); + complex_t toComplex(); + Expression *castTo(Scope *sc, Type *t); + int isConst(); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#ifdef _DH + OutBuffer hexp; +#endif +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct IdentifierExp : Expression +{ + Identifier *ident; + Declaration *var; + + IdentifierExp(Loc loc, Identifier *ident); + IdentifierExp(Loc loc, Declaration *var); + Expression *semantic(Scope *sc); + char *toChars(); + void dump(int indent); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct DollarExp : IdentifierExp +{ + DollarExp(Loc loc); +}; + +struct DsymbolExp : Expression +{ + Dsymbol *s; + int hasOverloads; + + DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); + Expression *semantic(Scope *sc); + char *toChars(); + void dump(int indent); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; + +struct ThisExp : Expression +{ + Declaration *var; + + ThisExp(Loc loc); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int isBool(int result); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct SuperExp : ThisExp +{ + SuperExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); +}; + +struct NullExp : Expression +{ + unsigned char committed; // !=0 if type is committed + + NullExp(Loc loc, Type *t = NULL); + Expression *semantic(Scope *sc); + int isBool(int result); + int isConst(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct StringExp : Expression +{ + void *string; // char, wchar, or dchar data + size_t len; // number of chars, wchars, or dchars + unsigned char sz; // 1: char, 2: wchar, 4: dchar + unsigned char committed; // !=0 if type is committed + unsigned char postfix; // 'c', 'w', 'd' + + StringExp(Loc loc, char *s); + StringExp(Loc loc, void *s, size_t len); + StringExp(Loc loc, void *s, size_t len, unsigned char postfix); + //Expression *syntaxCopy(); + int equals(Object *o); + char *toChars(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + size_t length(); + StringExp *toUTF8(Scope *sc); + Expression *implicitCastTo(Scope *sc, Type *t); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int compare(Object *obj); + int isBool(int result); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + unsigned charAt(size_t i); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +// Tuple + +struct TupleExp : Expression +{ + Expressions *exps; + + TupleExp(Loc loc, Expressions *exps); + TupleExp(Loc loc, TupleDeclaration *tup); + Expression *syntaxCopy(); + int equals(Object *o); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + void checkEscape(); + int checkSideEffect(int flag); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *castTo(Scope *sc, Type *t); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ArrayLiteralExp : Expression +{ + Expressions *elements; + + ArrayLiteralExp(Loc loc, Expressions *elements); + ArrayLiteralExp(Loc loc, Expression *e); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct AssocArrayLiteralExp : Expression +{ + Expressions *keys; + Expressions *values; + + AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isBool(int result); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct StructLiteralExp : Expression +{ + StructDeclaration *sd; // which aggregate this is for + Expressions *elements; // parallels sd->fields[] with + // NULL entries for fields to skip + Type *stype; // final type of result (can be different from sd's type) + +#if IN_DMD + Symbol *sym; // back end symbol to initialize with literal +#endif + size_t soffset; // offset from start of s + int fillHoles; // fill alignment 'holes' with zero + + StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *getField(Type *type, unsigned offset); + int getFieldIndex(Type *type, unsigned offset); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toMangleBuffer(OutBuffer *buf); + void scanForNestedRef(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isLvalue(); + // LDC: struct literals aren't lvalues! Taking their address can lead to + // incorrect behavior, see LDC#218, DMD#2682 + // Expression *toLvalue(Scope *sc, Expression *e); + int canThrow(); + MATCH implicitConvTo(Type *t); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); + dt_t **toDt(dt_t **pdt); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident); +#if IN_DMD +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif + +struct TypeExp : Expression +{ + TypeExp(Loc loc, Type *type); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void rvalue(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ScopeExp : Expression +{ + ScopeDsymbol *sds; + + ScopeExp(Loc loc, ScopeDsymbol *sds); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct TemplateExp : Expression +{ + TemplateDeclaration *td; + + TemplateExp(Loc loc, TemplateDeclaration *td); + void rvalue(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct NewExp : Expression +{ + /* thisexp.new(newargs) newtype(arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + Type *newtype; + Expressions *arguments; // Array of Expression's + + CtorDeclaration *member; // constructor function + NewDeclaration *allocator; // allocator function + int onstack; // allocate on stack + + NewExp(Loc loc, Expression *thisexp, Expressions *newargs, + Type *newtype, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + Expression *optimize(int result); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + int canThrow(); + + //int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct NewAnonClassExp : Expression +{ + /* thisexp.new(newargs) class baseclasses { } (arguments) + */ + Expression *thisexp; // if !NULL, 'this' for class being allocated + Expressions *newargs; // Array of Expression's to call new operator + ClassDeclaration *cd; // class being instantiated + Expressions *arguments; // Array of Expression's to call class constructor + + NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, + ClassDeclaration *cd, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int canThrow(); +}; + +#if DMDV2 +struct SymbolExp : Expression +{ + Declaration *var; + int hasOverloads; + + SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; +#endif + +// Offset from symbol + +struct SymOffExp : SymbolExp +{ + unsigned offset; + Module* m; // starting point for overload resolution + + SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int isConst(); + int isBool(int result); + Expression *doInline(InlineDoState *ids); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// Variable + +struct VarExp : SymbolExp +{ + VarExp(Loc loc, Declaration *var, int hasOverloads = 0); + int equals(Object *o); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void dump(int indent); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void checkEscape(); + void checkEscapeRef(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + void scanForNestedRef(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); + void cacheLvalue(IRState* irs); +#endif +}; + +#if DMDV2 +// Overload Set + +struct OverExp : Expression +{ + OverloadSet *vars; + + OverExp(OverloadSet *s); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); +}; +#endif + +// Function/Delegate literal + +struct FuncExp : Expression +{ + FuncLiteralDeclaration *fd; + + FuncExp(Loc loc, FuncLiteralDeclaration *fd); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void scanForNestedRef(Scope *sc); + char *toChars(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + + int inlineCost(InlineCostState *ics); + //Expression *doInline(InlineDoState *ids); + //Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +// Declaration of a symbol + +struct DeclarationExp : Expression +{ + Dsymbol *declaration; + + DeclarationExp(Loc loc, Dsymbol *declaration); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct TypeidExp : Expression +{ + Object *obj; + + TypeidExp(Loc loc, Object *obj); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#if DMDV2 +struct TraitsExp : Expression +{ + Identifier *ident; + Objects *args; + + TraitsExp(Loc loc, Identifier *ident, Objects *args); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; +#endif + +struct HaltExp : Expression +{ + HaltExp(Loc loc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int checkSideEffect(int flag); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct IsExp : Expression +{ + /* is(targ id tok tspec) + * is(targ id == tok2) + */ + Type *targ; + Identifier *id; // can be NULL + enum TOK tok; // ':' or '==' + Type *tspec; // can be NULL + enum TOK tok2; // 'struct', 'union', 'typedef', etc. + TemplateParameters *parameters; + + IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, + enum TOK tok2, TemplateParameters *parameters); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +/****************************************************************/ + +struct UnaExp : Expression +{ + Expression *e1; + + UnaExp(Loc loc, enum TOK op, int size, Expression *e1); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)); + int canThrow(); + Expression *resolveLoc(Loc loc, Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + virtual Expression *op_overload(Scope *sc); +}; + +struct BinExp : Expression +{ + Expression *e1; + Expression *e2; + + BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *semanticp(Scope *sc); + int checkSideEffect(int flag); + void checkComplexMulAssign(); + void checkComplexAddAssign(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *scaleFactor(Scope *sc); + Expression *typeCombine(Scope *sc); + Expression *optimize(int result); + int isunsigned(); + void incompatibleTypes(); + void dump(int indent); + void scanForNestedRef(Scope *sc); + Expression *interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *)); + Expression *interpretCommon2(InterState *istate, Expression *(*fp)(TOK, Type *, Expression *, Expression *)); + Expression *interpretAssignCommon(InterState *istate, Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); + int canThrow(); + Expression *arrayOp(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + + Expression *op_overload(Scope *sc); + Expression *compare_overload(Scope *sc, Identifier *id); + +#if IN_DMD + elem *toElemBin(IRState *irs, int op); +#endif +}; + +struct BinAssignExp : BinExp +{ + BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) + : BinExp(loc, op, size, e1, e2) + { + } + + Expression *commonSemanticAssign(Scope *sc); + Expression *commonSemanticAssignIntegral(Scope *sc); + + Expression *op_overload(Scope *sc); + + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *ex); + Expression *modifiableLvalue(Scope *sc, Expression *e); +}; + +/****************************************************************/ + +struct CompileExp : UnaExp +{ + CompileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct FileExp : UnaExp +{ + FileExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AssertExp : UnaExp +{ + Expression *msg; + + AssertExp(Loc loc, Expression *e, Expression *msg = NULL); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + int canThrow(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DotIdExp : UnaExp +{ + Identifier *ident; + + DotIdExp(Loc loc, Expression *e, Identifier *ident); + Expression *semantic(Scope *sc); + Expression *semantic(Scope *sc, int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int i); +}; + +struct DotTemplateExp : UnaExp +{ + TemplateDeclaration *td; + + DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct DotVarExp : UnaExp +{ + Declaration *var; + int hasOverloads; + + DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); + void cacheLvalue(IRState* irs); +#endif +}; + +struct DotTemplateInstanceExp : UnaExp +{ + TemplateInstance *ti; + + DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs); + Expression *syntaxCopy(); + TemplateDeclaration *getTempdecl(Scope *sc); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +}; + +struct DelegateExp : UnaExp +{ + FuncDeclaration *func; + Module* m; // starting point for overload resolution + int hasOverloads; + + DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); + + int inlineCost(InlineCostState *ics); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DotTypeExp : UnaExp +{ + Dsymbol *sym; // symbol that represents a type + + DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CallExp : UnaExp +{ + Expressions *arguments; // function arguments + + CallExp(Loc loc, Expression *e, Expressions *exps); + CallExp(Loc loc, Expression *e); + CallExp(Loc loc, Expression *e, Expression *earg1); + CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); + + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AddrExp : UnaExp +{ + Module* m; // starting point for overload resolution + + AddrExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void checkEscape(); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *optimize(int result); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct PtrExp : UnaExp +{ + PtrExp(Loc loc, Expression *e); + PtrExp(Loc loc, Expression *e, Type *t); + Expression *semantic(Scope *sc); + int isLvalue(); + void checkEscapeRef(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + +#if IN_LLVM + DValue* toElem(IRState* irs); + void cacheLvalue(IRState* irs); +#endif +}; + +struct NegExp : UnaExp +{ + NegExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct UAddExp : UnaExp +{ + UAddExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + + // For operator overloading + Identifier *opId(); +}; + +struct ComExp : UnaExp +{ + ComExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + Identifier *opId(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct NotExp : UnaExp +{ + NotExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct BoolExp : UnaExp +{ + BoolExp(Loc loc, Expression *e, Type *type); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DeleteExp : UnaExp +{ + DeleteExp(Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CastExp : UnaExp +{ + // Possible to cast to one type while painting to another type + Type *to; // type to cast to + unsigned mod; // MODxxxxx + + CastExp(Loc loc, Expression *e, Type *t); + CastExp(Loc loc, Expression *e, unsigned mod); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + MATCH implicitConvTo(Type *t); + IntRange getIntRange(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); + void checkEscape(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + + // For operator overloading + Identifier *opId(); + Expression *op_overload(Scope *sc); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + + +struct SliceExp : UnaExp +{ + Expression *upr; // NULL if implicit 0 + Expression *lwr; // NULL if implicit [length - 1] + VarDeclaration *lengthVar; + + SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + void checkEscape(); + void checkEscapeRef(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void dump(int indent); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + void scanForNestedRef(Scope *sc); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +#endif +}; + +struct ArrayLengthExp : UnaExp +{ + ArrayLengthExp(Loc loc, Expression *e1); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + + static Expression *rewriteOpAssign(BinExp *exp); + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// e1[a0,a1,a2,a3,...] + +struct ArrayExp : UnaExp +{ + Expressions *arguments; // Array of Expression's + + ArrayExp(Loc loc, Expression *e1, Expressions *arguments); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scanForNestedRef(Scope *sc); + + // For operator overloading + Identifier *opId(); + Expression *op_overload(Scope *sc); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); +}; + +/****************************************************************/ + +struct DotExp : BinExp +{ + DotExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct CommaExp : BinExp +{ + CommaExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + void checkEscape(); + void checkEscapeRef(); + IntRange getIntRange(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + int isBool(int result); + int checkSideEffect(int flag); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + Expression *optimize(int result); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct IndexExp : BinExp +{ + VarDeclaration *lengthVar; + int modifiable; + + IndexExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + Expression *doInline(InlineDoState *ids); + void scanForNestedRef(Scope *sc); + +#if IN_DMD + elem *toElem(IRState *irs); +#elif IN_LLVM + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); + void cacheLvalue(IRState* irs); +#endif +}; + +/* For both i++ and i-- + */ +struct PostExp : BinExp +{ + PostExp(enum TOK op, Loc loc, Expression *e); + Expression *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Identifier *opId(); // For operator overloading +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +/* For both ++i and --i + */ +struct PreExp : UnaExp +{ + PreExp(enum TOK op, Loc loc, Expression *e); + Expression *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct AssignExp : BinExp +{ int ismemset; // !=0 if setting the contents of an array + + AssignExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(Scope *sc); + Expression *interpret(InterState *istate); + Identifier *opId(); // For operator overloading + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); + virtual AssignExp* isAssignExp() { return this; } +#endif +}; + +struct ConstructExp : AssignExp +{ + ConstructExp(Loc loc, Expression *e1, Expression *e2); +}; + +#if IN_DMD +#define ASSIGNEXP_TOELEM elem *toElem(IRState *irs); +#elif IN_LLVM +#define ASSIGNEXP_TOELEM DValue* toElem(IRState *irs); +#else +#define ASSIGNEXP_TOELEM +#endif + +#define ASSIGNEXP(op) \ +struct op##AssignExp : BinAssignExp \ +{ \ + op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ + Expression *semantic(Scope *sc); \ + Expression *interpret(InterState *istate); \ + X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ + X(Expression *buildArrayLoop(Parameters *fparams);) \ + \ + Identifier *opId(); /* For operator overloading */ \ + \ + ASSIGNEXP_TOELEM \ +}; + +#define X(a) a +ASSIGNEXP(Add) +ASSIGNEXP(Min) +ASSIGNEXP(Mul) +ASSIGNEXP(Div) +ASSIGNEXP(Mod) +ASSIGNEXP(And) +ASSIGNEXP(Or) +ASSIGNEXP(Xor) +#undef X + +#define X(a) + +ASSIGNEXP(Shl) +ASSIGNEXP(Shr) +ASSIGNEXP(Ushr) +ASSIGNEXP(Cat) + +#undef X +#undef ASSIGNEXP +#undef ASSIGNEXP_TOELEM + +// Only a reduced subset of operations for now. +struct PowAssignExp : BinAssignExp +{ + PowAssignExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + + // For operator overloading + Identifier *opId(); +}; + +struct AddExp : BinExp +{ + AddExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct MinExp : BinExp +{ + MinExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CatExp : BinExp +{ + CatExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct MulExp : BinExp +{ + MulExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct DivExp : BinExp +{ + DivExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + IntRange getIntRange(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ModExp : BinExp +{ + ModExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +#if DMDV2 +struct PowExp : BinExp +{ + PowExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); +}; +#endif + +struct ShlExp : BinExp +{ + ShlExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + IntRange getIntRange(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct ShrExp : BinExp +{ + ShrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + IntRange getIntRange(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct UshrExp : BinExp +{ + UshrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + IntRange getIntRange(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AndExp : BinExp +{ + AndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + IntRange getIntRange(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct OrExp : BinExp +{ + OrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + MATCH implicitConvTo(Type *t); + IntRange getIntRange(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct XorExp : BinExp +{ + XorExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void buildArrayIdent(OutBuffer *buf, Expressions *arguments); + Expression *buildArrayLoop(Parameters *fparams); + MATCH implicitConvTo(Type *t); + IntRange getIntRange(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct OrOrExp : BinExp +{ + OrOrExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(Scope *sc); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct AndAndExp : BinExp +{ + AndAndExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *checkToBoolean(Scope *sc); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int checkSideEffect(int flag); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct CmpExp : BinExp +{ + CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Expression *op_overload(Scope *sc); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct InExp : BinExp +{ + InExp(Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isBit(); + + // For operator overloading + Identifier *opId(); + Identifier *opId_r(); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +struct RemoveExp : BinExp +{ + RemoveExp(Loc loc, Expression *e1, Expression *e2); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// == and != + +struct EqualExp : BinExp +{ + EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + int isBit(); + + // For operator overloading + int isCommutative(); + Identifier *opId(); + Expression *op_overload(Scope *sc); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +// === and !=== + +struct IdentityExp : BinExp +{ + IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); + Expression *semantic(Scope *sc); + int isBit(); + Expression *optimize(int result); + Expression *interpret(InterState *istate); +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +/****************************************************************/ + +struct CondExp : BinExp +{ + Expression *econd; + + CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); + Expression *syntaxCopy(); + Expression *semantic(Scope *sc); + Expression *optimize(int result); + Expression *interpret(InterState *istate); + void checkEscape(); + void checkEscapeRef(); + int isLvalue(); + Expression *toLvalue(Scope *sc, Expression *e); + Expression *modifiableLvalue(Scope *sc, Expression *e); + Expression *checkToBoolean(Scope *sc); + int checkSideEffect(int flag); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + MATCH implicitConvTo(Type *t); + Expression *castTo(Scope *sc, Type *t); + void scanForNestedRef(Scope *sc); + int canThrow(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Expression *inlineScan(InlineScanState *iss); + +#if IN_DMD + elem *toElem(IRState *irs); +#endif + +#if IN_LLVM + DValue* toElem(IRState* irs); +#endif +}; + +#if DMDV2 +/****************************************************************/ + +struct DefaultInitExp : Expression +{ + enum TOK subop; // which of the derived classes this is + + DefaultInitExp(Loc loc, enum TOK subop, int size); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct FileInitExp : DefaultInitExp +{ + FileInitExp(Loc loc); + Expression *semantic(Scope *sc); + Expression *resolveLoc(Loc loc, Scope *sc); +}; + +struct LineInitExp : DefaultInitExp +{ + LineInitExp(Loc loc); + Expression *semantic(Scope *sc); + Expression *resolveLoc(Loc loc, Scope *sc); +}; +#endif + +/****************************************************************/ + +#if IN_LLVM + +// this stuff is strictly LDC + +struct GEPExp : UnaExp +{ + unsigned index; + Identifier* ident; + + GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Expression *toLvalue(Scope *sc, Expression *e); + + DValue* toElem(IRState* irs); + llvm::Constant *toConstElem(IRState *irs); +}; + +#endif + +/****************************************************************/ + +/* Special values used by the interpreter + */ +#define EXP_CANT_INTERPRET ((Expression *)1) +#define EXP_CONTINUE_INTERPRET ((Expression *)2) +#define EXP_BREAK_INTERPRET ((Expression *)3) +#define EXP_GOTO_INTERPRET ((Expression *)4) +#define EXP_VOID_INTERPRET ((Expression *)5) + +Expression *expType(Type *type, Expression *e); + +Expression *Neg(Type *type, Expression *e1); +Expression *Com(Type *type, Expression *e1); +Expression *Not(Type *type, Expression *e1); +Expression *Bool(Type *type, Expression *e1); +Expression *Cast(Type *type, Type *to, Expression *e1); +Expression *ArrayLength(Type *type, Expression *e1); +Expression *Ptr(Type *type, Expression *e1); + +Expression *Add(Type *type, Expression *e1, Expression *e2); +Expression *Min(Type *type, Expression *e1, Expression *e2); +Expression *Mul(Type *type, Expression *e1, Expression *e2); +Expression *Div(Type *type, Expression *e1, Expression *e2); +Expression *Mod(Type *type, Expression *e1, Expression *e2); +Expression *Shl(Type *type, Expression *e1, Expression *e2); +Expression *Shr(Type *type, Expression *e1, Expression *e2); +Expression *Ushr(Type *type, Expression *e1, Expression *e2); +Expression *And(Type *type, Expression *e1, Expression *e2); +Expression *Or(Type *type, Expression *e1, Expression *e2); +Expression *Xor(Type *type, Expression *e1, Expression *e2); +Expression *Index(Type *type, Expression *e1, Expression *e2); +Expression *Cat(Type *type, Expression *e1, Expression *e2); + +Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); +Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); + +Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); + +#endif /* DMD_EXPRESSION_H */ diff --git a/dmd2/func.c b/dmd2/func.c index d00d19be..e681f1b0 100644 --- a/dmd2/func.c +++ b/dmd2/func.c @@ -1,3413 +1,3809 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, enum STC storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("storage_class = x%x\n", storage_class); - this->storage_class = storage_class; - this->type = type; - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatus = ILSuninitialized; - inlineNest = 0; - inlineAsm = 0; - cantInterpret = 0; - semanticRun = 0; -#if DMDV1 - nestedFrameRef = 0; -#endif - fes = NULL; - introducing = 0; - tintro = NULL; - /* The type given for "infer the return type" is a TypeFunction with - * NULL for the return type. - */ - inferRetType = (type && type->nextOf() == NULL); - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; -#if IN_DMD - shidden = NULL; -#endif -#if DMDV2 - builtin = BUILTINunknown; - tookAddressOf = 0; -#endif -#if IN_LLVM - // LDC - isArrayOp = false; - allowInlining = false; - - availableExternally = true; // assume this unless proven otherwise - - // function types in ldc don't merge if the context parameter differs - // so we actually don't care about the function declaration, but only - // what kind of context parameter it has. - // however, this constructor is usually called from the parser, which - // unfortunately doesn't provide the information needed to get to the - // aggregate type. So we have to stick with the FuncDeclaration and - // just be sure we don't actually rely on the symbol it points to, - // but rather just the type of its context parameter. - // this means some function might have a function type pointing to - // another function declaration - - if (type) - { - assert(type->ty == Tfunction && "invalid function type"); - TypeFunction* tf = (TypeFunction*)type; - if (tf->funcdecl == NULL) - tf->funcdecl = this; - } -#endif -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, (enum STC) storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - -#if IN_LLVM - f->intrinsicName = intrinsicName; -#endif - - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - Dsymbol *pd; - -#if 0 - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); - if (isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); - printf("type: %p, %s\n", type, type->toChars()); -#endif - - if (semanticRun && isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - assert(semanticRun <= 1); - semanticRun = 1; - - storage_class |= sc->stc & ~STCref; - //printf("function storage_class = x%x\n", storage_class); - - if (!originalType) - originalType = type; - if (!type->deco) - { - /* Apply const and invariant storage class - * to the function type - */ - type = type->semantic(loc, sc); - unsigned stc = storage_class; - if (type->isInvariant()) - stc |= STCimmutable; - if (type->isConst()) - stc |= STCconst; - if (type->isShared() || storage_class & STCsynchronized) - stc |= STCshared; - switch (stc & STC_TYPECTOR) - { - case STCimmutable: - case STCimmutable | STCconst: - case STCimmutable | STCconst | STCshared: - case STCimmutable | STCshared: - // Don't use toInvariant(), as that will do a merge() - type = type->makeInvariant(); - type->deco = type->merge()->deco; - break; - - case STCconst: - type = type->makeConst(); - type->deco = type->merge()->deco; - break; - - case STCshared | STCconst: - type = type->makeSharedConst(); - type->deco = type->merge()->deco; - break; - - case STCshared: - type = type->makeShared(); - type->deco = type->merge()->deco; - break; - - case 0: - break; - - default: - assert(0); - } - } - //type->print(); - if (type->ty != Tfunction) - { - error("%s must be a function", toChars()); - return; - } - f = (TypeFunction *)(type); - - size_t nparams = Argument::dim(f->parameters); - - linkage = sc->linkage; -// if (!parent) - { - //parent = sc->scopesym; - parent = sc->parent; - } - protection = sc->protection; - Dsymbol *parent = toParent(); - - if (storage_class & STCscope) - error("functions cannot be scope"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - if ((f->isConst() || f->isInvariant()) && !isThis()) - error("without 'this' cannot be const/immutable"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - AggregateDeclaration *ad; - - ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - if (isCtorDeclaration()) - { - return; - } -#if 0 - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() - //||isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || -#if DMDV2 - isPostBlitDeclaration() || -#endif - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("special function not allowed in interface %s", id->toChars()); - if (fbody) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member function not allowed in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - return; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - - // Find index of existing function in vtbl[] to override - vi = findVtblIndex(&cd->vtbl, cd->baseClass ? cd->baseClass->vtbl.dim : 0); - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - if (isOverride()) - error("does not override any function"); - cd->vtblFinal.push(this); - } - else - { - // Append to end of vtbl[] - //printf("\tintroducing function\n"); - introducing = 1; - vi = cd->vtbl.dim; - cd->vtbl.push(this); - vtblIndex = vi; - } - break; - - case -2: // can't determine because of fwd refs - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->vtbl.data[vi]; - // This function is covariant with fdv - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - -#if DMDV2 - if (!isOverride()) - warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - if (fdv->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides - // the other. - if (fdv->parent->isClassDeclaration()) - break; - if (!this->parent->isClassDeclaration() -#if !BREAKABI - && !isDtorDeclaration() -#endif -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl.data[vi] = (void *)this; - vtblIndex = vi; - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { - BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); - switch (vi) - { - case -1: - break; - - case -2: - cd->sizeok = 2; // can't finish due to forward reference - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; - Type *ti = NULL; - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - ti = fdv->type; -#if 0 - if (offset) - ti = fdv->type; - else if (type->nextOf()->ty == Tclass) - { ClassDeclaration *cdn = ((TypeClass *)type->nextOf())->sym; - if (cdn && cdn->sizeok != 1) - ti = fdv->type; - } -#endif - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - } - } - - if (introducing && isOverride()) - { - error("does not override any function"); - } - - L2: ; - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(char[][] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Argument *arg0 = Argument::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Argument *arg1 = Argument::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - -Ldone: - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - if (sd) - { - sd->hasIdentityAssign = 1; // don't need to generate it - goto Ldone; - } - error("identity assignment operator overload is illegal"); -} - -void FuncDeclaration::semantic2(Scope *sc) -{ -} - -// Do the semantic analysis on the internals of the function. - -void FuncDeclaration::semantic3(Scope *sc) -{ TypeFunction *f; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - - if (!parent) - { - if (global.errors) - return; - //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); - //printf("storage class = x%x %x\n", sc->stc, storage_class); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun >= 3) - return; - semanticRun = 3; - - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - size_t nparams = Argument::dim(f->parameters); - - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = (Type *)fthrows->data[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } - - if (fbody || frequire) - { - /* Symbol table into which we place parameters and nested functions, - * solely to diagnose name collisions. - */ - localsymtab = new DsymbolTable(); - - // Establish function scope - ScopeDsymbol *ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - Scope *sc2 = sc->push(ss); - sc2->func = this; - sc2->parent = this; - sc2->callSuper = 0; - sc2->sbreak = NULL; - sc2->scontinue = NULL; - sc2->sw = NULL; - sc2->fes = fes; - sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = 8; - sc2->incontract = 0; -#if !IN_LLVM - sc2->tf = NULL; -#else - sc2->enclosingFinally = NULL; - sc2->enclosingScopeExit = NULL; -#endif - sc2->noctor = 0; - - // Declare 'this' - AggregateDeclaration *ad = isThis(); - if (ad) - { VarDeclaration *v; - - if (isFuncLiteralDeclaration() && isNested()) - { - error("literals cannot be class members"); - return; - } - else - { - assert(!isNested()); // can't be both member and nested - assert(ad->handle); - Type *thandle = ad->handle; -#if STRUCTTHISREF - thandle = thandle->addMod(type->mod); - thandle = thandle->addStorageClass(storage_class); - if (isPure()) - thandle = thandle->addMod(MODconst); -#else - if (storage_class & STCconst || type->isConst()) - { - assert(0); // BUG: shared not handled - if (thandle->ty == Tclass) - thandle = thandle->constOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->constOf()->pointerTo(); - } - } - else if (storage_class & STCimmutable || type->isInvariant()) - { - if (thandle->ty == Tclass) - thandle = thandle->invariantOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->invariantOf()->pointerTo(); - } - } - else if (storage_class & STCshared || type->isShared()) - { - assert(0); // not implemented - } -#endif - v = new ThisDeclaration(loc, thandle); - v->storage_class |= STCparameter; -#if STRUCTTHISREF - if (thandle->ty == Tstruct) - v->storage_class |= STCref; -#endif - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); - v->storage_class |= STCparameter; - v->semantic(sc2); - if (!sc2->insert(v)) - assert(0); - v->parent = this; - vthis = v; - } - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { -#if TARGET_NET - varArgs(sc2, f, argptr, _arguments); -#else - Type *t; - - if (f->linkage == LINKd) - { // Declare _arguments[] -#if BREAKABI - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - //t = Type::typeinfo->type->constOf()->arrayOf(); - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif - } - if (f->linkage == LINKd || (parameters && parameters->dim)) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } -#endif - } - -#if IN_LLVM - // LDC make sure argument type is semanticed. - // Turns TypeTuple!(int, int) into two int parameters, for instance. - if (f->parameters) - { - for (size_t i = 0; i < Argument::dim(f->parameters); i++) - { Argument *arg = (Argument *)Argument::getNth(f->parameters, i); - Type* nw = arg->type->semantic(0, sc); - if (arg->type != nw) { - arg->type = nw; - // Examine this index again. - // This is important if it turned into a tuple. - // In particular, the empty tuple should be handled or the - // next parameter will be skipped. - // FIXME: Maybe we only need to do this for tuples, - // and can add tuple.length after decrement? - i--; - } - } - // update nparams to include expanded tuples - nparams = Argument::dim(f->parameters); - } -#endif - - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } - - /* Declare all the function parameters as variables - * and install them in parameters[] - */ - size_t nparams = Argument::dim(f->parameters); - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new Dsymbols(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Argument *arg = Argument::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - /* Generate identifier for un-named parameter, - * because we need it later on. - */ - arg->ident = id = Identifier::generateId("_param_", i); - } - Type *vtype = arg->type; - if (isPure()) - vtype = vtype->addMod(MODconst); - VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); - //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); - v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == nparams) - v->storage_class |= STCvariadic; - v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Argument *arg = (Argument *)f->parameters->data[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Argument::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Argument *narg = Argument::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(v->loc, v); - exps->data[j] = (void *)e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); - //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - localsymtab->insert(v); - v->parent = this; - } - } - } - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; - - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - VarDeclaration *v; - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noauto = 1; -#if DMDV2 - if (f->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression* v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - ls->isReturnLabel = 1; - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { ClassDeclaration *cd = isClassMember(); - - /* If this is a class constructor - */ - if (isCtorDeclaration() && cd) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - if (!fbody) - fbody = new CompoundStatement(0, new Statements()); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - type = type->semantic(loc, sc); - } - f = (TypeFunction *)type; - } - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *ad = p->isScopeDsymbol(); - if (!ad) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (int i = 0; i < ad->members->dim; i++) - { Dsymbol *s = (Dsymbol *)ad->members->data[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && cd) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (int i = 0; i < cd->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; - - if (v->ctorinit == 0 && v->isCtorinit()) - error("missing initializer for final field %s", v->toChars()); - } - } - - if (!(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - e = e->trySemantic(sc2); - if (!e) - error("no match for implicit super() call in constructor"); - else - { - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("expected to return a value of type %s", type->nextOf()->toChars()); - else if (!inlineAsm) - { -#if DMDV2 - int blockexit = fbody ? fbody->blockExit() : BEfallthru; - if (f->isnothrow && blockexit & BEthrow) - error("'%s' is nothrow yet may throw", toChars()); - - int offend = blockexit & BEfallthru; -#endif - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else - { - if (offend) - { Expression *e; -#if DMDV1 - warning(loc, "no return exp; or assert(0); at end of function"); -#else - error("no return exp; or assert(0); at end of function"); -#endif - if (global.params.useAssert && - !global.params.useInline) - { /* Add an assert(0, msg); where the missing return - * should be. - */ - e = new AssertExp( - endloc, - new IntegerExp(0), - new StringExp(loc, (char *)"missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr to point past non-variadic arg -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Expression *e1; - Expression *e; - Type *t = argptr->type; - VarDeclaration *p; - unsigned offset; - - e1 = new VarExp(0, argptr); - if (parameters && parameters->dim) - p = (VarDeclaration *)parameters->data[parameters->dim - 1]; - else - p = v_arguments; // last parameter is _arguments[] - offset = p->type->size(); - offset = (offset + 3) & ~3; // assume stack aligns on 4 - e = new SymOffExp(0, p, offset); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); -#endif // IN_GCC - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new AssignExp(0, e1, e); - e->op = TOKconstruct; - e = e->semantic(sc2); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - -#ifdef _DH - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } -#else - if (frequire && global.params.useIn) - a->push(frequire); -#endif - - // Precondition invariant - if (addPreInvariant()) - { - Expression *e = NULL; - Expression *ee = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp* tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression *v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif -#if IN_LLVM - //e = new AssertExp(loc, v, NULL); - - // LDC: check for null this - //v = new ThisExp(0); - //v->type = vthis->type; - //v->var = vthis; // Error: Expression has no property var... in D1 typeof(v) == ThisExp - - //NullExp *nv = new NullExp(0); - //nv->type = v->type; - - //IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); - //ie->type = Type::tbool; -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); - se->type = Type::tchar->arrayOf(); -//#if IN_LLVM -// ee = new AssertExp(loc, ie, se); -//#else - e = new AssertExp(loc, v, se); -//#endif - } - if (ee) - { - ExpStatement *s = new ExpStatement(0, ee); - a->push(s); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } - } - - if (fbody) - a->push(fbody); - - if (fensure) - { - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid) - { - // Create: return vresult; - assert(vresult); - Expression *e = new VarExp(0, vresult); - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - - fbody = new CompoundStatement(0, a); - -#if 0 // This seems to have been added in with dmd 2.032, see below - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - error("synchronized function %s must be a member of a class", toChars()); - - Expression *sync; - if (isStatic()) - { - // static member functions synchronize on classinfo - sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); - } - else - { - // non-static member functions synchronize on this - sync = new VarExp(loc, vthis); - } - - // we do not want to rerun semantics on the whole function, so we - // manually adjust all labels in the function that currently don't - // have an enclosingScopeExit to use the new SynchronizedStatement - SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); - s->semantic(sc2); - s->body = fbody; - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = s; - - a = new Statements; - a->push(s); - fbody = new CompoundStatement(0, a); - } -#endif -#if DMDV2 - /* Append destructor calls for parameters as finally blocks. - */ - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - - if (v->storage_class & (STCref | STCout)) - continue; - - /* Don't do this for static arrays, since static - * arrays are called by reference. Remove this - * when we change them to call by value. - */ - if (v->type->toBasetype()->ty == Tsarray) - continue; - - Expression *e = v->callAutoDtor(sc); - if (e) - { Statement *s = new ExpStatement(0, e); - s = s->semantic(sc); - if (fbody->blockExit() == BEfallthru) - fbody = new CompoundStatement(0, fbody, s); - else - fbody = new TryFinallyStatement(0, fbody, s); - } - } - } -#endif - -#if 1 - if (isSynchronized()) - { /* Wrap the entire function body in a synchronized statement - */ - ClassDeclaration *cd = parent->isClassDeclaration(); - if (cd) - { -#if TARGET_WINDOS - if (/*config.flags2 & CFG2seh &&*/ // always on for WINDOS - !isStatic() && !fbody->usesEH()) - { - /* The back end uses the "jmonitor" hack for syncing; - * no need to do the sync at this level. - */ - } - else -#endif - { - Expression *vsync; - if (isStatic()) - { // The monitor is in the ClassInfo - vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id::classinfo); - } - else - { // 'this' is the monitor - vsync = new VarExp(loc, vthis); - } - fbody = new PeelStatement(fbody); // don't redo semantic() - fbody = new SynchronizedStatement(loc, vsync, fbody); - fbody = fbody->semantic(sc2); - } - } - else - { - error("synchronized function %s must be a member of a class", toChars()); - } - } -#endif - } - - sc2->callSuper = 0; - sc2->pop(); - } - semanticRun = 4; -} - -void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); - - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - - -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) -{ - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - switch (cov) - { - case 0: // types are distinct - break; - - case 1: - return vi; - - case 2: - //type->print(); - //fdv->type->print(); - //printf("%s %s\n", type->deco, fdv->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), fdv->toPrettyChars(), fdv->type->toChars()); - break; - - case 3: - return -2; // forward references - - default: - assert(0); - } - } - } - return -1; -} - -/**************************************************** - * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. - */ - -int FuncDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *f; - AliasDeclaration *a; - - //printf("FuncDeclaration::overloadInsert(%s)\n", s->toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - -#if 0 - /* Disable this check because: - * const void foo(); - * semantic() isn't run yet on foo(), so the const hasn't been - * applied yet. - */ - if (type) - { printf("type = %s\n", type->toChars()); - printf("f->type = %s\n", f->type->toChars()); - } - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - f->type->mod == type->mod && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } -#endif - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(Module* from, FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (fa->getModule() == from || fa->importprot != PROTprivate) - if (overloadApply(from, fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; -#if IN_LLVM - if (a->importprot == PROTprivate && a->getModule() != from) - if (FuncDeclaration* fd = next->isFuncDeclaration()) - next = fd->overnext; -#endif - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * If there are no overloads of function f, return that function, - * otherwise return NULL. - */ - -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - -FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; - - overloadApply(getModule(), this, &fpunique, &result); - return result; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, if it's just a const conversion - * of the return type - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(from, this, &fp1, &p); - return p.f; -} - - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; - Expression *ethis; - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - MATCH match; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - match = (MATCH) tf->callMatch(f->needThis() ? p->ethis : NULL, arguments); - //printf("match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = f->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(f); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto LfIsBetter; - if (c1 < c2) - goto LlastIsBetter; - } - - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - -void overloadResolveX(Match *m, FuncDeclaration *fstart, - Expression *ethis, Expressions *arguments, Module* from) -{ - Param2 p; - p.m = m; - p.ethis = ethis; - p.arguments = arguments; - overloadApply(from, fstart, &fp2, &p); -} - - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags, Module* from) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = (Expression *)arguments->data[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, ethis, arguments, from); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - buf.writeByte('('); - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - buf.writeByte(')'); - if (ethis) - ethis->type->modToBuffer(&buf); - } - else - buf.writeByte(')'); - - if (m.last == MATCHnomatch) - { - if (flags & 1) // if do not print error messages - return NULL; // no match - - tf = (TypeFunction *)type; - - OutBuffer buf2; - tf->modToBuffer(&buf2); - - //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); - error(loc, "%s%s is not callable using argument types %s", - Argument::argsTypesToChars(tf->parameters, tf->varargs), - buf2.toChars(), - buf.toChars()); - return m.anyf; // as long as it's not a FuncAliasDeclaration - } - else - { -#if 1 - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", - buf.toChars(), - m.lastf->toPrettyChars(), Argument::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Argument::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/************************************* - * Determine partial specialization order of 'this' vs g. - * This is very similar to TemplateDeclaration::leastAsSpecialized(). - * Returns: - * match 'this' is at least as specialized as g - * 0 g is more specialized than 'this' - */ - -MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) -{ -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); -#endif - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction *tf = (TypeFunction *)type; - TypeFunction *tg = (TypeFunction *)g->type; - size_t nfparams = Argument::dim(tf->parameters); - size_t ngparams = Argument::dim(tg->parameters); - MATCH match = MATCHexact; - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (needThis() && g->needThis()) - { - if (tf->mod != tg->mod) - { - if (tg->mod == MODconst) - match = MATCHconst; - else - return MATCHnomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - args.setDim(nfparams); - for (int u = 0; u < nfparams; u++) - { - Argument *p = Argument::getNth(tf->parameters, u); - Expression *e; - if (p->storageClass & (STCref | STCout)) - { - e = new IdentifierExp(0, p->ident); - e->type = p->type; - } - else - e = p->type->defaultInit(); - args.data[u] = e; - } - - MATCH m = (MATCH) tg->callMatch(NULL, &args); - if (m) - { - /* A variadic parameter list is less specialized than a - * non-variadic one. - */ - if (tf->varargs && !tg->varargs) - goto L1; // less specialized - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - -/******************************************* - * Given a symbol that could be either a FuncDeclaration or - * a function template, resolve it to a function symbol. - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags) -{ - if (!s) - return NULL; // no match - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - f = f->overloadResolve(loc, ethis, arguments); - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f = td->deduceFunctionTemplate(sc, loc, tiargs, NULL, arguments, flags); - } - return f; -} - -/******************************** - * Labels are in a separate scope, one per function. - */ - -LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) -{ Dsymbol *s; - - if (!labtab) - labtab = new DsymbolTable(); // guess we need one - - s = labtab->lookup(ident); - if (!s) - { - s = new LabelDsymbol(ident); - labtab->insert(s); - } - return (LabelDsymbol *)s; -} - -/**************************************** - * If non-static member function that has a 'this' pointer, - * return the aggregate it is a member of. - * Otherwise, return NULL. - */ - -AggregateDeclaration *FuncDeclaration::isThis() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); - ad = NULL; - if ((storage_class & STCstatic) == 0) - { - ad = isMember2(); - } - //printf("-FuncDeclaration::isThis() %p\n", ad); - return ad; -} - -AggregateDeclaration *FuncDeclaration::isMember2() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); - ad = NULL; - for (Dsymbol *s = this; s; s = s->parent) - { -//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); - ad = s->isMember(); - if (ad) -{ //printf("test4\n"); - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ //printf("test5\n"); - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = '%s'\n", s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - AggregateDeclaration *thiscd = s->isAggregateDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - error(loc, "cannot access frame of function %s", fd->toChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ - if (!fbody) - fbody = s; - else - { - CompoundStatement *cs = fbody->isCompoundStatement(); - if (cs) - { - if (!cs->statements) - fbody = s; - else - cs->statements->push(s); - } - else - fbody = new CompoundStatement(0, fbody, s); - } -} - -const char *FuncDeclaration::toPrettyChars() -{ - if (isMain()) - return "D main"; - else - return Dsymbol::toPrettyChars(); -} - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration()); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - toParent()->isClassDeclaration(); -} - -int FuncDeclaration::isFinal() -{ - ClassDeclaration *cd; -#if 0 - printf("FuncDeclaration::isFinal(%s)\n", toChars()); - printf("%p %d %d %d %d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -int FuncDeclaration::isOverloadable() -{ - return 1; // functions can be overloaded -} - -int FuncDeclaration::isPure() -{ - //printf("FuncDeclaration::isPure() '%s'\n", toChars()); - assert(type->ty == Tfunction); - return ((TypeFunction *)this->type)->ispure; -} - -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -/********************************** - * Generate a FuncDeclaration for a runtime library function. - */ - -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, const char *name) -{ - return genCfunc(args, treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Arguments *args, Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(args, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -const char *FuncDeclaration::kind() -{ - return "function"; -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - (enum STC)funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; -#if IN_LLVM - importprot = PROTundefined; -#endif -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Lexer::uniqueId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - f->ident = ident; // keep old identifier - } - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok == TOKdelegate); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - static Identifier *idfunc; - static Identifier *iddel; - - if (!idfunc) - idfunc = new Identifier("function", 0); - if (!iddel) - iddel = new Identifier("delegate", 0); - - type->toCBuffer(buf, ((tok == TOKdelegate) ? iddel : idfunc), hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::ctor, STCundefined, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f; - - f = new CtorDeclaration(loc, endloc, NULL, varargs); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - f->arguments = Argument::arraySyntaxCopy(arguments); - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - //printf("CtorDeclaration::semantic() %s\n", toChars()); - if (type) - return; - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - - parent = sc->parent; - Dsymbol *parent = toParent2(); - ad = parent->isAggregateDeclaration(); - if (!ad || parent->isUnionDeclaration()) - { - error("constructors are only for class or struct definitions"); - fatal(); - tret = Type::tvoid; - } - else - { tret = ad->handle; - assert(tret); - } - type = new TypeFunction(arguments, tret, varargs, LINKd); -#if STRUCTTHISREF - if (ad && ad->isStructDeclaration()) - ((TypeFunction *)type)->isref = 1; -#endif - if (!originalType) - originalType = type; - - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc->flags &= ~SCOPEctor; - - // Append: - // return this; - // to the function body - if (fbody) - { - Expression *e = new ThisExp(loc); - Statement *s = new ReturnStatement(loc, e); - fbody = new CompoundStatement(loc, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (ad && varargs == 0 && Argument::dim(arguments) == 0) - { if (ad->isStructDeclaration()) - error("default constructor not allowed for structs"); - else - ad->defaultCtor = this; - } -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - - -void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - -/********************************* PostBlitDeclaration ****************************/ - -#if DMDV2 -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) -{ -} - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void PostBlitDeclaration::semantic(Scope *sc) -{ - //printf("PostBlitDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - StructDeclaration *ad = parent->isStructDeclaration(); - if (!ad) - { - error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - } - else if (ident == Id::_postblit) - ad->postblits.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not static - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int PostBlitDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload postblits -} - -int PostBlitDeclaration::addPreInvariant() -{ - return FALSE; -} - -int PostBlitDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int PostBlitDeclaration::isVirtual() -{ - return FALSE; -} - -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("=this()"); - bodyToCBuffer(buf, hgs); -} -#endif - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - fatal(); - } - else if (ident == Id::dtor) - ad->dtors.push(this); - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -const char *DtorDeclaration::kind() -{ - return "destructor"; -} - -char *DtorDeclaration::toChars() -{ - return (char *)"~this"; -} - -int DtorDeclaration::isVirtual() -{ - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI - return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticCtorDeclaration *scd; - - assert(!s); - scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp(1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isStaticConstructor() -{ - return TRUE; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - { buf->writestring("static this();\n"); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticDtorDeclaration *sdd; - - assert(!s); - sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - cd = sc->scopesym->isClassDeclaration(); - if (!cd) - { - } - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance()) - { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = STCstatic; - Statements *sa = new Statements(); - Statement *s = new DeclarationStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - vgate = v; - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isStaticDestructor() -{ - return TRUE; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - AggregateDeclaration *ad; - Type *tret; - - parent = sc->parent; - Dsymbol *parent = toParent(); - ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants are only for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ - if (global.params.useUnitTests) - { - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - Scope *sc2 = sc->push(); - sc2->linkage = LINKd; - FuncDeclaration::semantic(sc2); - sc2->pop(); - } - - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - m->needmoduleinfo = 1; -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Arguments *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Type *tret; - - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - tret = Type::tvoid->pointerTo(); - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type size_t - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) < 1) - { - error("at least one argument of type size_t expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tsize_t)) - error("first argument must be type size_t, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Argument::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Arguments *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Argument::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd; - - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Argument::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Argument *a = Argument::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Argument::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include + +#include "mars.h" +#include "init.h" +#include "declaration.h" +#include "attrib.h" +#include "expression.h" +#include "scope.h" +#include "mtype.h" +#include "aggregate.h" +#include "identifier.h" +#include "id.h" +#include "module.h" +#include "statement.h" +#include "template.h" +#include "hdrgen.h" + +#ifdef IN_GCC +#include "d-dmd-gcc.h" +#endif + +/********************************* FuncDeclaration ****************************/ + +FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type) + : Declaration(id) +{ + //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); + //printf("storage_class = x%x\n", storage_class); + this->storage_class = storage_class; + this->type = type; + this->loc = loc; + this->endloc = endloc; + fthrows = NULL; + frequire = NULL; + fdrequire = NULL; + fdensure = NULL; + outId = NULL; + vresult = NULL; + returnLabel = NULL; + fensure = NULL; + fbody = NULL; + localsymtab = NULL; + vthis = NULL; + v_arguments = NULL; +#if IN_GCC + v_argptr = NULL; +#endif + parameters = NULL; + labtab = NULL; + overnext = NULL; + vtblIndex = -1; + hasReturnExp = 0; + naked = 0; + inlineStatus = ILSuninitialized; + inlineNest = 0; + inlineAsm = 0; + cantInterpret = 0; + semanticRun = PASSinit; +#if DMDV1 + nestedFrameRef = 0; +#endif + fes = NULL; + introducing = 0; + tintro = NULL; + /* The type given for "infer the return type" is a TypeFunction with + * NULL for the return type. + */ + inferRetType = (type && type->nextOf() == NULL); + hasReturnExp = 0; + nrvo_can = 1; + nrvo_var = NULL; +#if IN_DMD + shidden = NULL; +#endif +#if DMDV2 + builtin = BUILTINunknown; + tookAddressOf = 0; +#endif +#if IN_LLVM + // LDC + isArrayOp = false; + allowInlining = false; + + availableExternally = true; // assume this unless proven otherwise + + // function types in ldc don't merge if the context parameter differs + // so we actually don't care about the function declaration, but only + // what kind of context parameter it has. + // however, this constructor is usually called from the parser, which + // unfortunately doesn't provide the information needed to get to the + // aggregate type. So we have to stick with the FuncDeclaration and + // just be sure we don't actually rely on the symbol it points to, + // but rather just the type of its context parameter. + // this means some function might have a function type pointing to + // another function declaration + + if (type) + { + assert(type->ty == Tfunction && "invalid function type"); + TypeFunction* tf = (TypeFunction*)type; + if (tf->funcdecl == NULL) + tf->funcdecl = this; + } +#endif +} + +Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncDeclaration *f; + + //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncDeclaration *)s; + else + f = new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy()); + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + +#if IN_LLVM + f->intrinsicName = intrinsicName; +#endif + + return f; +} + + +// Do the semantic analysis on the external interface to the function. + +void FuncDeclaration::semantic(Scope *sc) +{ TypeFunction *f; + StructDeclaration *sd; + ClassDeclaration *cd; + InterfaceDeclaration *id; + Dsymbol *pd; + +#if 0 + printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); + if (isFuncLiteralDeclaration()) + printf("\tFuncLiteralDeclaration()\n"); + printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); + printf("type: %p, %s\n", type, type->toChars()); +#endif + + if (semanticRun != PASSinit && isFuncLiteralDeclaration()) + { + /* Member functions that have return types that are + * forward references can have semantic() run more than + * once on them. + * See test\interface2.d, test20 + */ + return; + } + + parent = sc->parent; + Dsymbol *parent = toParent(); + + if (semanticRun >= PASSsemanticdone) + { + if (!parent->isClassDeclaration()) + { + return; + } + // need to re-run semantic() in order to set the class's vtbl[] + } + else + { + assert(semanticRun <= PASSsemantic); + semanticRun = PASSsemantic; + } + + unsigned dprogress_save = Module::dprogress; + + foverrides.setDim(0); // reset in case semantic() is being retried for this function + + storage_class |= sc->stc & ~STCref; + //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal()); + + if (!originalType) + originalType = type; + if (!type->deco) + { + sc = sc->push(); + sc->stc |= storage_class & STCref; // forward to function type + if (isCtorDeclaration()) + sc->flags |= SCOPEctor; + type = type->semantic(loc, sc); + sc = sc->pop(); + + /* Apply const, immutable and shared storage class + * to the function type + */ + StorageClass stc = storage_class; + if (type->isImmutable()) + stc |= STCimmutable; + if (type->isConst()) + stc |= STCconst; + if (type->isShared() || storage_class & STCsynchronized) + stc |= STCshared; + if (type->isWild()) + stc |= STCwild; + switch (stc & STC_TYPECTOR) + { + case STCimmutable: + case STCimmutable | STCconst: + case STCimmutable | STCconst | STCshared: + case STCimmutable | STCshared: + case STCimmutable | STCwild: + case STCimmutable | STCconst | STCwild: + case STCimmutable | STCconst | STCshared | STCwild: + case STCimmutable | STCshared | STCwild: + // Don't use toInvariant(), as that will do a merge() + type = type->makeInvariant(); + goto Lmerge; + + case STCconst: + case STCconst | STCwild: + type = type->makeConst(); + goto Lmerge; + + case STCshared | STCconst: + case STCshared | STCconst | STCwild: + type = type->makeSharedConst(); + goto Lmerge; + + case STCshared: + type = type->makeShared(); + goto Lmerge; + + case STCwild: + type = type->makeWild(); + goto Lmerge; + + case STCshared | STCwild: + type = type->makeSharedWild(); + goto Lmerge; + + Lmerge: + if (!(type->ty == Tfunction && !type->nextOf())) + /* Can't do merge if return type is not known yet + */ + type->deco = type->merge()->deco; + break; + + case 0: + break; + + default: + assert(0); + } + } + storage_class &= ~STCref; + if (type->ty != Tfunction) + { + error("%s must be a function instead of %s", toChars(), type->toChars()); + return; + } + f = (TypeFunction *)(type); + size_t nparams = Parameter::dim(f->parameters); + + linkage = sc->linkage; + protection = sc->protection; + + if (storage_class & STCscope) + error("functions cannot be scope"); + + if (isAbstract() && !isVirtual()) + error("non-virtual functions cannot be abstract"); + + if ((f->isConst() || f->isImmutable()) && !isThis()) + error("without 'this' cannot be const/immutable"); + + if (isAbstract() && isFinal()) + error("cannot be both final and abstract"); +#if 0 + if (isAbstract() && fbody) + error("abstract functions cannot have bodies"); +#endif + +#if 0 + if (isStaticConstructor() || isStaticDestructor()) + { + if (!isStatic() || type->nextOf()->ty != Tvoid) + error("static constructors / destructors must be static void"); + if (f->arguments && f->arguments->dim) + error("static constructors / destructors must have empty parameter list"); + // BUG: check for invalid storage classes + } +#endif + +#ifdef IN_GCC + AggregateDeclaration *ad; + + ad = parent->isAggregateDeclaration(); + if (ad) + ad->methods.push(this); +#endif + sd = parent->isStructDeclaration(); + if (sd) + { + if (isCtorDeclaration()) + { + goto Ldone; + } +#if 0 + // Verify no constructors, destructors, etc. + if (isCtorDeclaration() + //||isDtorDeclaration() + //|| isInvariantDeclaration() + //|| isUnitTestDeclaration() + ) + { + error("special member functions not allowed for %ss", sd->kind()); + } + + if (!sd->inv) + sd->inv = isInvariantDeclaration(); + + if (!sd->aggNew) + sd->aggNew = isNewDeclaration(); + + if (isDelete()) + { + if (sd->aggDelete) + error("multiple delete's for struct %s", sd->toChars()); + sd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + } + + id = parent->isInterfaceDeclaration(); + if (id) + { + storage_class |= STCabstract; + + if (isCtorDeclaration() || +#if DMDV2 + isPostBlitDeclaration() || +#endif + isDtorDeclaration() || + isInvariantDeclaration() || + isUnitTestDeclaration() || isNewDeclaration() || isDelete()) + error("constructors, destructors, postblits, invariants, unittests, new and delete functions are not allowed in interface %s", id->toChars()); + if (fbody && isVirtual()) + error("function body is not abstract in interface %s", id->toChars()); + } + + /* Contracts can only appear without a body when they are virtual interface functions + */ + if (!fbody && (fensure || frequire) && !(id && isVirtual())) + error("in and out contracts require function body"); + + /* Template member functions aren't virtual: + * interface TestInterface { void tpl(T)(); } + * and so won't work in interfaces + */ + if ((pd = toParent()) != NULL && + pd->isTemplateInstance() && + (pd = toParent2()) != NULL && + (id = pd->isInterfaceDeclaration()) != NULL) + { + error("template member functions are not allowed in interface %s", id->toChars()); + } + + cd = parent->isClassDeclaration(); + if (cd) + { int vi; + CtorDeclaration *ctor; + DtorDeclaration *dtor; + InvariantDeclaration *inv; + + if (isCtorDeclaration()) + { +// ctor = (CtorDeclaration *)this; +// if (!cd->ctor) +// cd->ctor = ctor; + return; + } + +#if 0 + dtor = isDtorDeclaration(); + if (dtor) + { + if (cd->dtor) + error("multiple destructors for class %s", cd->toChars()); + cd->dtor = dtor; + } + + inv = isInvariantDeclaration(); + if (inv) + { + cd->inv = inv; + } + + if (isNewDeclaration()) + { + if (!cd->aggNew) + cd->aggNew = (NewDeclaration *)(this); + } + + if (isDelete()) + { + if (cd->aggDelete) + error("multiple delete's for class %s", cd->toChars()); + cd->aggDelete = (DeleteDeclaration *)(this); + } +#endif + + if (storage_class & STCabstract) + cd->isabstract = 1; + + // if static function, do not put in vtbl[] + if (!isVirtual()) + { + //printf("\tnot virtual\n"); + goto Ldone; + } + + /* Find index of existing function in base class's vtbl[] to override + * (the index will be the same as in cd's current vtbl[]) + */ + vi = cd->baseClass ? findVtblIndex(&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) + : -1; + + switch (vi) + { + case -1: + /* Didn't find one, so + * This is an 'introducing' function which gets a new + * slot in the vtbl[]. + */ + + // Verify this doesn't override previous final function + if (cd->baseClass) + { Dsymbol *s = cd->baseClass->search(loc, ident, 0); + if (s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + f = f->overloadExactMatch(type, getModule()); + if (f && f->isFinal() && f->prot() != PROTprivate) + error("cannot override final function %s", f->toPrettyChars()); + } + } + + if (isFinal()) + { + if (isOverride()) + error("is marked as override, but does not override any function"); + cd->vtblFinal.push(this); + } + else + { + // Append to end of vtbl[] + //printf("\tintroducing function\n"); + introducing = 1; + vi = cd->vtbl.dim; + cd->vtbl.push(this); + vtblIndex = vi; + } + break; + + case -2: // can't determine because of fwd refs + cd->sizeok = 2; // can't finish due to forward reference + Module::dprogress = dprogress_save; + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl.data[vi]; + // This function is covariant with fdv + if (fdv->isFinal()) + error("cannot override final function %s", fdv->toPrettyChars()); + +#if DMDV2 + if (!isOverride()) + warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); +#endif + + if (fdv->toParent() == parent) + { + // If both are mixins, then error. + // If either is not, the one that is not overrides + // the other. + if (fdv->parent->isClassDeclaration()) + break; + if (!this->parent->isClassDeclaration() +#if !BREAKABI + && !isDtorDeclaration() +#endif +#if DMDV2 + && !isPostBlitDeclaration() +#endif + ) + error("multiple overrides of same function"); + } + cd->vtbl.data[vi] = (void *)this; + vtblIndex = vi; + + /* Remember which functions this overrides + */ + foverrides.push(fdv); + + /* This works by whenever this function is called, + * it actually returns tintro, which gets dynamically + * cast to type. But we know that tintro is a base + * of type, so we could optimize it by not doing a + * dynamic cast, but just subtracting the isBaseOf() + * offset if the value is != null. + */ + + if (fdv->tintro) + tintro = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + int offset; + if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) + { + tintro = fdv->type; + } + } + break; + } + } + + /* Go through all the interface bases. + * If this function is covariant with any members of those interface + * functions, set the tintro. + */ + for (int i = 0; i < cd->interfaces_dim; i++) + { + BaseClass *b = cd->interfaces[i]; + vi = findVtblIndex(&b->base->vtbl, b->base->vtbl.dim); + switch (vi) + { + case -1: + break; + + case -2: + cd->sizeok = 2; // can't finish due to forward reference + Module::dprogress = dprogress_save; + return; + + default: + { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.data[vi]; + Type *ti = NULL; + + /* Remember which functions this overrides + */ + foverrides.push(fdv); + + if (fdv->tintro) + ti = fdv->tintro; + else if (!type->equals(fdv->type)) + { + /* Only need to have a tintro if the vptr + * offsets differ + */ + unsigned errors = global.errors; + global.gag++; // suppress printing of error messages + int offset; + int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset); + global.gag--; // suppress printing of error messages + if (errors != global.errors) + { + // any error in isBaseOf() is a forward reference error, so we bail out + global.errors = errors; + cd->sizeok = 2; // can't finish due to forward reference + Module::dprogress = dprogress_save; + return; + } + if (baseOf) + { + ti = fdv->type; + } + } + if (ti) + { + if (tintro && !tintro->equals(ti)) + { + error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); + } + tintro = ti; + } + goto L2; + } + } + } + + if (introducing && isOverride()) + { + error("does not override any function"); + } + + L2: ; + + /* Go through all the interface bases. + * Disallow overriding any final functions in the interface(s). + */ + for (int i = 0; i < cd->interfaces_dim; i++) + { + BaseClass *b = cd->interfaces[i]; + if (b->base) + { + Dsymbol *s = search_function(b->base, ident); + if (s) + { + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + { + f = f->overloadExactMatch(type, getModule()); + if (f && f->isFinal() && f->prot() != PROTprivate) + error("cannot override final function %s.%s", b->base->toChars(), f->toPrettyChars()); + } + } + } + } + } + else if (isOverride() && !parent->isTemplateInstance()) + error("override only applies to class member functions"); + + /* Do not allow template instances to add virtual functions + * to a class. + */ + if (isVirtual()) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + { + // Take care of nested templates + while (1) + { + TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); + if (!ti2) + break; + ti = ti2; + } + + // If it's a member template + ClassDeclaration *cd = ti->tempdecl->isClassMember(); + if (cd) + { + error("cannot use template to add virtual function to class '%s'", cd->toChars()); + } + } + } + + if (isMain()) + { + // Check parameters to see if they are either () or (char[][] args) + switch (nparams) + { + case 0: + break; + + case 1: + { + Parameter *arg0 = Parameter::getNth(f->parameters, 0); + if (arg0->type->ty != Tarray || + arg0->type->nextOf()->ty != Tarray || + arg0->type->nextOf()->nextOf()->ty != Tchar || + arg0->storageClass & (STCout | STCref | STClazy)) + goto Lmainerr; + break; + } + + default: + goto Lmainerr; + } + + if (!f->nextOf()) + error("must return int or void"); + else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) + error("must return int or void, not %s", f->nextOf()->toChars()); + if (f->varargs) + { + Lmainerr: + error("parameters must be main() or main(string[] args)"); + } + } + + if (ident == Id::assign && (sd || cd)) + { // Disallow identity assignment operator. + + // opAssign(...) + if (nparams == 0) + { if (f->varargs == 1) + goto Lassignerr; + } + else + { + Parameter *arg0 = Parameter::getNth(f->parameters, 0); + Type *t0 = arg0->type->toBasetype(); + Type *tb = sd ? sd->type : cd->type; + if (arg0->type->implicitConvTo(tb) || + (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) + ) + { + if (nparams == 1) + goto Lassignerr; + Parameter *arg1 = Parameter::getNth(f->parameters, 1); + if (arg1->defaultArg) + goto Lassignerr; + } + } + } + + if (isVirtual() && semanticRun != PASSsemanticdone) + { + /* Rewrite contracts as nested functions, then call them. + * Doing it as nested functions means that overriding functions + * can call them. + */ + if (frequire) + { /* in { ... } + * becomes: + * void __require() { ... } + * __require(); + */ + Loc loc = frequire->loc; + TypeFunction *tf = new TypeFunction(NULL, Type::tvoid, 0, LINKd); + FuncDeclaration *fd = new FuncDeclaration(loc, loc, + Id::require, STCundefined, tf); + fd->fbody = frequire; + Statement *s1 = new DeclarationStatement(loc, fd); + Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), (Expressions *)NULL); + Statement *s2 = new ExpStatement(loc, e); + frequire = new CompoundStatement(loc, s1, s2); + fdrequire = fd; + } + + if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) + outId = Id::result; // provide a default + + if (fensure) + { /* out (result) { ... } + * becomes: + * tret __ensure(ref tret result) { ... } + * __ensure(result); + */ + Loc loc = fensure->loc; + Parameters *arguments = new Parameters(); + Parameter *a = NULL; + if (outId) + { a = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL); + arguments->push(a); + } + TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + FuncDeclaration *fd = new FuncDeclaration(loc, loc, + Id::ensure, STCundefined, tf); + fd->fbody = fensure; + Statement *s1 = new DeclarationStatement(loc, fd); + Expression *eresult = NULL; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), eresult); + Statement *s2 = new ExpStatement(loc, e); + fensure = new CompoundStatement(loc, s1, s2); + fdensure = fd; + } + } + +Ldone: + Module::dprogress++; + semanticRun = PASSsemanticdone; + + /* Save scope for possible later use (if we need the + * function internals) + */ + scope = new Scope(*sc); + scope->setNoFree(); + return; + +Lassignerr: + if (sd) + { + sd->hasIdentityAssign = 1; // don't need to generate it + goto Ldone; + } + error("identity assignment operator overload is illegal"); +} + +void FuncDeclaration::semantic2(Scope *sc) +{ +} + +// Do the semantic analysis on the internals of the function. + +void FuncDeclaration::semantic3(Scope *sc) +{ TypeFunction *f; + VarDeclaration *argptr = NULL; + VarDeclaration *_arguments = NULL; + + if (!parent) + { + if (global.errors) + return; + //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); + assert(0); + } + //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); + //fflush(stdout); + //printf("storage class = x%x %x\n", sc->stc, storage_class); + //{ static int x; if (++x == 2) *(char*)0=0; } + //printf("\tlinkage = %d\n", sc->linkage); + + //printf(" sc->incontract = %d\n", sc->incontract); + if (semanticRun >= PASSsemantic3) + return; + semanticRun = PASSsemantic3; + + // LDC + if (!global.params.useAvailableExternally) + availableExternally = false; + + if (!type || type->ty != Tfunction) + return; + f = (TypeFunction *)(type); + size_t nparams = Parameter::dim(f->parameters); + +#if 0 + // Check the 'throws' clause + if (fthrows) + { + for (int i = 0; i < fthrows->dim; i++) + { + Type *t = (Type *)fthrows->data[i]; + + t = t->semantic(loc, sc); + if (!t->isClassHandle()) + error("can only throw classes, not %s", t->toChars()); + } + } +#endif + + frequire = mergeFrequire(frequire); + fensure = mergeFensure(fensure); + + if (fbody || frequire || fensure) + { + /* Symbol table into which we place parameters and nested functions, + * solely to diagnose name collisions. + */ + localsymtab = new DsymbolTable(); + + // Establish function scope + ScopeDsymbol *ss = new ScopeDsymbol(); + ss->parent = sc->scopesym; + Scope *sc2 = sc->push(ss); + sc2->func = this; + sc2->parent = this; + sc2->callSuper = 0; + sc2->sbreak = NULL; + sc2->scontinue = NULL; + sc2->sw = NULL; + sc2->fes = fes; + sc2->linkage = LINKd; + sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | + STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | + STCproperty | STCsafe | STCtrusted | STCsystem); + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + sc2->structalign = 8; + sc2->incontract = 0; +#if !IN_LLVM + sc2->tf = NULL; +#else + sc2->enclosingFinally = NULL; + sc2->enclosingScopeExit = NULL; +#endif + sc2->noctor = 0; + + // Declare 'this' + AggregateDeclaration *ad = isThis(); + if (ad) + { VarDeclaration *v; + + if (isFuncLiteralDeclaration() && isNested() && !sc->intypeof) + { + error("function literals cannot be class members"); + return; + } + else + { + assert(!isNested() || sc->intypeof); // can't be both member and nested + assert(ad->handle); + Type *thandle = ad->handle; +#if STRUCTTHISREF + thandle = thandle->addMod(type->mod); + thandle = thandle->addStorageClass(storage_class); + if (isPure()) + thandle = thandle->addMod(MODconst); +#else + if (storage_class & STCconst || type->isConst()) + { + assert(0); // BUG: shared not handled + if (thandle->ty == Tclass) + thandle = thandle->constOf(); + else + { assert(thandle->ty == Tpointer); + thandle = thandle->nextOf()->constOf()->pointerTo(); + } + } + else if (storage_class & STCimmutable || type->isImmutable()) + { + if (thandle->ty == Tclass) + thandle = thandle->invariantOf(); + else + { assert(thandle->ty == Tpointer); + thandle = thandle->nextOf()->invariantOf()->pointerTo(); + } + } + else if (storage_class & STCshared || type->isShared()) + { + assert(0); // not implemented + } +#endif + v = new ThisDeclaration(loc, thandle); + //v = new ThisDeclaration(loc, isCtorDeclaration() ? ad->handle : thandle); + v->storage_class |= STCparameter; +#if STRUCTTHISREF + if (thandle->ty == Tstruct) + v->storage_class |= STCref; +#endif + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + } + else if (isNested()) + { + /* The 'this' for a nested function is the link to the + * enclosing function's stack frame. + * Note that nested functions and member functions are disjoint. + */ + VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); + v->storage_class |= STCparameter; + v->semantic(sc2); + if (!sc2->insert(v)) + assert(0); + v->parent = this; + vthis = v; + } + + // Declare hidden variable _arguments[] and _argptr + if (f->varargs == 1) + { +#if TARGET_NET + varArgs(sc2, f, argptr, _arguments); +#else + Type *t; + + if (f->linkage == LINKd) + { // Declare _arguments[] +#if BREAKABI + v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); + v_arguments->storage_class = STCparameter; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; + + //t = Type::typeinfo->type->constOf()->arrayOf(); + t = Type::typeinfo->type->arrayOf(); + _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + _arguments->semantic(sc2); + sc2->insert(_arguments); + _arguments->parent = this; +#else + t = Type::typeinfo->type->arrayOf(); + v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); + v_arguments->storage_class = STCparameter | STCin; + v_arguments->semantic(sc2); + sc2->insert(v_arguments); + v_arguments->parent = this; +#endif + } + if (f->linkage == LINKd || (parameters && parameters->dim)) + { // Declare _argptr +#if IN_GCC + t = d_gcc_builtin_va_list_d_type; +#else + t = Type::tvoid->pointerTo(); +#endif + argptr = new VarDeclaration(0, t, Id::_argptr, NULL); + argptr->semantic(sc2); + sc2->insert(argptr); + argptr->parent = this; + } +#endif + } + +#if IN_LLVM + // LDC make sure argument type is semanticed. + // Turns TypeTuple!(int, int) into two int parameters, for instance. + if (f->parameters) + { + for (size_t i = 0; i < Parameter::dim(f->parameters); i++) + { Parameter *arg = (Parameter *)Parameter::getNth(f->parameters, i); + Type* nw = arg->type->semantic(0, sc); + if (arg->type != nw) { + arg->type = nw; + // Examine this index again. + // This is important if it turned into a tuple. + // In particular, the empty tuple should be handled or the + // next parameter will be skipped. + // FIXME: Maybe we only need to do this for tuples, + // and can add tuple.length after decrement? + i--; + } + } + // update nparams to include expanded tuples + nparams = Parameter::dim(f->parameters); + } +#endif + +#if 0 + // Propagate storage class from tuple parameters to their element-parameters. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Parameter *arg = (Parameter *)f->parameters->data[i]; + + //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Parameter::dim(t->arguments); + for (size_t j = 0; j < dim; j++) + { Parameter *narg = Parameter::getNth(t->arguments, j); + narg->storageClass = arg->storageClass; + } + } + } + } +#endif + + /* Declare all the function parameters as variables + * and install them in parameters[] + */ + size_t nparams = Parameter::dim(f->parameters); + if (nparams) + { /* parameters[] has all the tuples removed, as the back end + * doesn't know about tuples + */ + parameters = new Dsymbols(); + parameters->reserve(nparams); + for (size_t i = 0; i < nparams; i++) + { + Parameter *arg = Parameter::getNth(f->parameters, i); + Identifier *id = arg->ident; + if (!id) + { + /* Generate identifier for un-named parameter, + * because we need it later on. + */ + arg->ident = id = Identifier::generateId("_param_", i); + } + Type *vtype = arg->type; + if (isPure()) + vtype = vtype->addMod(MODconst); + VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); + //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); + v->storage_class |= STCparameter; + if (f->varargs == 2 && i + 1 == nparams) + v->storage_class |= STCvariadic; + v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); + v->semantic(sc2); + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + parameters->push(v); + localsymtab->insert(v); + v->parent = this; + } + } + + // Declare the tuple symbols and put them in the symbol table, + // but not in parameters[]. + if (f->parameters) + { + for (size_t i = 0; i < f->parameters->dim; i++) + { Parameter *arg = (Parameter *)f->parameters->data[i]; + + if (!arg->ident) + continue; // never used, so ignore + if (arg->type->ty == Ttuple) + { TypeTuple *t = (TypeTuple *)arg->type; + size_t dim = Parameter::dim(t->arguments); + Objects *exps = new Objects(); + exps->setDim(dim); + for (size_t j = 0; j < dim; j++) + { Parameter *narg = Parameter::getNth(t->arguments, j); + assert(narg->ident); + VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); + assert(v); + Expression *e = new VarExp(v->loc, v); + exps->data[j] = (void *)e; + } + assert(arg->ident); + TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); + //printf("declaring tuple %s\n", v->toChars()); + v->isexp = 1; + if (!sc2->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + localsymtab->insert(v); + v->parent = this; + } + } + } + + /* Do the semantic analysis on the [in] preconditions and + * [out] postconditions. + */ + sc2->incontract++; + + if (frequire) + { /* frequire is composed of the [in] contracts + */ + // BUG: need to error if accessing out parameters + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + // BUG: verify that all in and ref parameters are read + frequire = frequire->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (fensure || addPostInvariant()) + { /* fensure is composed of the [out] contracts + */ + if (!type->nextOf()) // if return type is inferred + { /* This case: + * auto fp = function() out { } body { }; + * Can fix by doing semantic() onf fbody first. + */ + error("post conditions are not supported if the return type is inferred"); + return; + } + + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc2->scopesym; + sc2 = sc2->push(sym); + + assert(type->nextOf()); + if (type->nextOf()->ty == Tvoid) + { + if (outId) + error("void functions have no result"); + } + else + { + if (!outId) + outId = Id::result; // provide a default + } + + if (outId) + { // Declare result variable + Loc loc = this->loc; + + if (fensure) + loc = fensure->loc; + + VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); + v->noscope = 1; + v->storage_class |= STCresult; +#if DMDV2 + if (!isVirtual()) + v->storage_class |= STCconst; + if (f->isref) + { + v->storage_class |= STCref | STCforeach; + } +#endif + sc2->incontract--; + v->semantic(sc2); + sc2->incontract++; + if (!sc2->insert(v)) + error("out result %s is already defined", v->toChars()); + v->parent = this; + vresult = v; + + // vresult gets initialized with the function return value + // in ReturnStatement::semantic() + } + + // BUG: need to treat parameters as const + // BUG: need to disallow returns and throws + if (fensure) + { fensure = fensure->semantic(sc2); + labtab = NULL; // so body can't refer to labels + } + + if (!global.params.useOut) + { fensure = NULL; // discard + vresult = NULL; + } + + // Postcondition invariant + if (addPostInvariant()) + { + Expression *e = NULL; + if (isCtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + ThisExp *tv = new ThisExp(0); + tv->type = vthis->type; + tv->var = vthis; + Expression* v = tv; + +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif + e = new AssertExp(0, v); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + if (fensure) + fensure = new CompoundStatement(0, s, fensure); + else + fensure = s; + } + } + + if (fensure) + { returnLabel = new LabelDsymbol(Id::returnLabel); + LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); + returnLabel->statement = ls; + } + sc2 = sc2->pop(); + } + + sc2->incontract--; + + if (fbody) + { ClassDeclaration *cd = isClassMember(); + + /* If this is a class constructor + */ + if (isCtorDeclaration() && cd) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + v->ctorinit = 0; + } + } + + if (inferRetType || f->retStyle() != RETstack) + nrvo_can = 0; + + fbody = fbody->semantic(sc2); + if (!fbody) + fbody = new CompoundStatement(0, new Statements()); + + if (inferRetType) + { // If no return type inferred yet, then infer a void + if (!type->nextOf()) + { + ((TypeFunction *)type)->next = Type::tvoid; + type = type->semantic(loc, sc); + } + f = (TypeFunction *)type; + } + + if (isStaticCtorDeclaration()) + { /* It's a static constructor. Ensure that all + * ctor consts were initialized. + */ + + Dsymbol *p = toParent(); + ScopeDsymbol *ad = p->isScopeDsymbol(); + if (!ad) + { + error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); + } + else + { + for (int i = 0; i < ad->members->dim; i++) + { Dsymbol *s = (Dsymbol *)ad->members->data[i]; + + s->checkCtorConstInit(); + } + } + } + + if (isCtorDeclaration() && cd) + { + //printf("callSuper = x%x\n", sc2->callSuper); + + // Verify that all the ctorinit fields got initialized + if (!(sc2->callSuper & CSXthis_ctor)) + { + for (int i = 0; i < cd->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)cd->fields.data[i]; + + if (v->ctorinit == 0 && v->isCtorinit() && !v->type->isMutable()) + error("missing initializer for final field %s", v->toChars()); + } + } + + if (!(sc2->callSuper & CSXany_ctor) && + cd->baseClass && cd->baseClass->ctor) + { + sc2->callSuper = 0; + + // Insert implicit super() at start of fbody + Expression *e1 = new SuperExp(0); + Expression *e = new CallExp(0, e1); + + e = e->trySemantic(sc2); + if (!e) + error("no match for implicit super() call in constructor"); + else + { + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, s, fbody); + } + } + } + else if (fes) + { // For foreach(){} body, append a return 0; + Expression *e = new IntegerExp(0); + Statement *s = new ReturnStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + assert(!returnLabel); + } + else if (!hasReturnExp && type->nextOf()->ty != Tvoid) + error("has no return statement, but is expected to return a value of type %s", type->nextOf()->toChars()); + else if (!inlineAsm) + { +#if DMDV2 + int blockexit = fbody ? fbody->blockExit() : BEfallthru; + if (f->isnothrow && blockexit & BEthrow) + error("'%s' is nothrow yet may throw", toChars()); + + int offend = blockexit & BEfallthru; +#endif + if (type->nextOf()->ty == Tvoid) + { + if (offend && isMain()) + { // Add a return 0; statement + Statement *s = new ReturnStatement(0, new IntegerExp(0)); + fbody = new CompoundStatement(0, fbody, s); + } + } + else + { + if (offend) + { Expression *e; +#if DMDV1 + warning(loc, "no return exp; or assert(0); at end of function"); +#else + error("no return exp; or assert(0); at end of function"); +#endif + if (global.params.useAssert && + !global.params.useInline) + { /* Add an assert(0, msg); where the missing return + * should be. + */ + e = new AssertExp( + endloc, + new IntegerExp(0), + new StringExp(loc, (char *)"missing return expression") + ); + } + else + e = new HaltExp(endloc); + e = new CommaExp(0, e, type->nextOf()->defaultInit()); + e = e->semantic(sc2); + Statement *s = new ExpStatement(0, e); + fbody = new CompoundStatement(0, fbody, s); + } + } + } + } + + { + Statements *a = new Statements(); + + // Merge in initialization of 'out' parameters + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->storage_class & STCout) + { + assert(v->init); + ExpInitializer *ie = v->init->isExpInitializer(); + assert(ie); + if (ie->exp->op == TOKconstruct) + ie->exp->op = TOKassign; // construction occured in parameter processing + a->push(new ExpStatement(0, ie->exp)); + } + } + } + +// we'll handle variadics ourselves +#if !IN_LLVM + if (argptr) + { // Initialize _argptr to point past non-variadic arg +#if IN_GCC + // Handled in FuncDeclaration::toObjFile + v_argptr = argptr; + v_argptr->init = new VoidInitializer(loc); +#else + Type *t = argptr->type; + VarDeclaration *p; + unsigned offset = 0; + + Expression *e1 = new VarExp(0, argptr); + // Find the last non-ref parameter + if (parameters && parameters->dim) + { + int lastNonref = parameters->dim -1; + p = (VarDeclaration *)parameters->data[lastNonref]; + /* The trouble with out and ref parameters is that taking + * the address of it doesn't work, because later processing + * adds in an extra level of indirection. So we skip over them. + */ + while (p->storage_class & (STCout | STCref)) + { + --lastNonref; + offset += PTRSIZE; + if (lastNonref < 0) + { + p = v_arguments; + break; + } + p = (VarDeclaration *)parameters->data[lastNonref]; + } + } + else + p = v_arguments; // last parameter is _arguments[] + if (p->storage_class & STClazy) + // If the last parameter is lazy, it's the size of a delegate + offset += PTRSIZE * 2; + else + offset += p->type->size(); + offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); // assume stack aligns on pointer size + Expression *e = new SymOffExp(0, p, offset); + e->type = Type::tvoidptr; + //e = e->semantic(sc); + e = new AssignExp(0, e1, e); + e->type = t; + a->push(new ExpStatement(0, e)); + p->isargptr = TRUE; +#endif + } + + if (_arguments) + { + /* Advance to elements[] member of TypeInfo_Tuple with: + * _arguments = v_arguments.elements; + */ + Expression *e = new VarExp(0, v_arguments); + e = new DotIdExp(0, e, Id::elements); + Expression *e1 = new VarExp(0, _arguments); + e = new ConstructExp(0, e1, e); + e = e->semantic(sc2); + a->push(new ExpStatement(0, e)); + } + +#endif // !IN_LLVM + + // Merge contracts together with body into one compound statement + +#ifdef _DH + if (frequire && global.params.useIn) + { frequire->incontract = 1; + a->push(frequire); + } +#else + if (frequire && global.params.useIn) + a->push(frequire); +#endif + + // Precondition invariant + if (addPreInvariant()) + { + Expression *e = NULL; + Expression *ee = NULL; + if (isDtorDeclaration()) + { + // Call invariant directly only if it exists + InvariantDeclaration *inv = ad->inv; + ClassDeclaration *cd = ad->isClassDeclaration(); + + while (!inv && cd) + { + cd = cd->baseClass; + if (!cd) + break; + inv = cd->inv; + } + if (inv) + { + e = new DsymbolExp(0, inv); + e = new CallExp(0, e); + e = e->semantic(sc2); + } + } + else + { // Call invariant virtually + ThisExp* tv = new ThisExp(0); + tv->type = vthis->type; + tv->var = vthis; + Expression *v = tv; + +#if STRUCTTHISREF + if (ad->isStructDeclaration()) + v = v->addressOf(sc); +#endif +#if IN_LLVM + //e = new AssertExp(loc, v, NULL); + + // LDC: check for null this + //v = new ThisExp(0); + //v->type = vthis->type; + //v->var = vthis; // Error: Expression has no property var... in D1 typeof(v) == ThisExp + + //NullExp *nv = new NullExp(0); + //nv->type = v->type; + + //IdentityExp *ie = new IdentityExp(TOKnotidentity, 0, v, nv); + //ie->type = Type::tbool; +#endif + Expression *se = new StringExp(0, (char *)"null this"); + se = se->semantic(sc); + se->type = Type::tchar->arrayOf(); +//#if IN_LLVM +// ee = new AssertExp(loc, ie, se); +//#else + e = new AssertExp(loc, v, se); +//#endif + } + if (ee) + { + ExpStatement *s = new ExpStatement(0, ee); + a->push(s); + } + if (e) + { + ExpStatement *s = new ExpStatement(0, e); + a->push(s); + } + } + + if (fbody) + a->push(fbody); + + if (fensure) + { + a->push(returnLabel->statement); + + if (type->nextOf()->ty != Tvoid) + { + // Create: return vresult; + assert(vresult); + Expression *e = new VarExp(0, vresult); + if (tintro) + { e = e->implicitCastTo(sc, tintro->nextOf()); + e = e->semantic(sc); + } + ReturnStatement *s = new ReturnStatement(0, e); + a->push(s); + } + } + + fbody = new CompoundStatement(0, a); + +#if 0 // This seems to have been added in with dmd 2.032, see below + // wrap body of synchronized functions in a synchronized statement + if (isSynchronized()) + { + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd) + error("synchronized function %s must be a member of a class", toChars()); + + Expression *sync; + if (isStatic()) + { + // static member functions synchronize on classinfo + sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); + } + else + { + // non-static member functions synchronize on this + sync = new VarExp(loc, vthis); + } + + // we do not want to rerun semantics on the whole function, so we + // manually adjust all labels in the function that currently don't + // have an enclosingScopeExit to use the new SynchronizedStatement + SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); + s->semantic(sc2); + s->body = fbody; + + // LDC + LabelMap::iterator it, end = labmap.end(); + for (it = labmap.begin(); it != end; ++it) + if (it->second->enclosingScopeExit == NULL) + it->second->enclosingScopeExit = s; + + a = new Statements; + a->push(s); + fbody = new CompoundStatement(0, a); + } +#endif +#if DMDV2 + /* Append destructor calls for parameters as finally blocks. + */ + if (parameters) + { for (size_t i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + + if (v->storage_class & (STCref | STCout)) + continue; + + /* Don't do this for static arrays, since static + * arrays are called by reference. Remove this + * when we change them to call by value. + */ + if (v->type->toBasetype()->ty == Tsarray) + continue; + + Expression *e = v->callScopeDtor(sc2); + if (e) + { Statement *s = new ExpStatement(0, e); + s = s->semantic(sc2); + if (fbody->blockExit() == BEfallthru) + fbody = new CompoundStatement(0, fbody, s); + else + fbody = new TryFinallyStatement(0, fbody, s); + } + } + } +#endif + +#if 1 + if (isSynchronized()) + { /* Wrap the entire function body in a synchronized statement + */ + ClassDeclaration *cd = parent->isClassDeclaration(); + if (cd) + { +#if TARGET_WINDOS + if (/*config.flags2 & CFG2seh &&*/ // always on for WINDOS + !isStatic() && !fbody->usesEH()) + { + /* The back end uses the "jmonitor" hack for syncing; + * no need to do the sync at this level. + */ + } + else +#endif + { + Expression *vsync; + if (isStatic()) + { // The monitor is in the ClassInfo + vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id::classinfo); + } + else + { // 'this' is the monitor + vsync = new VarExp(loc, vthis); + } + fbody = new PeelStatement(fbody); // don't redo semantic() + fbody = new SynchronizedStatement(loc, vsync, fbody); + fbody = fbody->semantic(sc2); + } + } + else + { + error("synchronized function %s must be a member of a class", toChars()); + } + } +#endif + } + + sc2->callSuper = 0; + sc2->pop(); + } + semanticRun = PASSsemantic3done; +} + +void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); + + StorageClassDeclaration::stcToCBuffer(buf, storage_class); + type->toCBuffer(buf, ident, hgs); + bodyToCBuffer(buf, hgs); +} + + +void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (fbody && + (!hgs->hdrgen || hgs->tpltMember || canInline(1,1)) + ) + { buf->writenl(); + + // in{} + if (frequire) + { buf->writestring("in"); + buf->writenl(); + frequire->toCBuffer(buf, hgs); + } + + // out{} + if (fensure) + { buf->writestring("out"); + if (outId) + { buf->writebyte('('); + buf->writestring(outId->toChars()); + buf->writebyte(')'); + } + buf->writenl(); + fensure->toCBuffer(buf, hgs); + } + + if (frequire || fensure) + { buf->writestring("body"); + buf->writenl(); + } + + buf->writebyte('{'); + buf->writenl(); + fbody->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { buf->writeByte(';'); + buf->writenl(); + } +} + +/**************************************************** + * Merge into this function the 'in' contracts of all it overrides. + * 'in's are OR'd together, i.e. only one of them needs to pass. + */ + +Statement *FuncDeclaration::mergeFrequire(Statement *sf) +{ + /* Implementing this is done by having the overriding function call + * nested functions (the fdrequire functions) nested inside the overridden + * function. This requires that the stack layout of the calling function's + * parameters and 'this' pointer be in the same place (as the nested + * function refers to them). + * This is easy for the parameters, as they are all on the stack in the same + * place by definition, since it's an overriding function. The problem is + * getting the 'this' pointer in the same place, since it is a local variable. + * We did some hacks in the code generator to make this happen: + * 1. always generate exception handler frame, or at least leave space for it + * in the frame (Windows 32 SEH only) + * 2. always generate an EBP style frame + * 3. since 'this' is passed in a register that is subsequently copied into + * a stack local, allocate that local immediately following the exception + * handler block, so it is always at the same offset from EBP. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + sf = fdv->mergeFrequire(sf); + if (fdv->fdrequire) + { + //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); + /* Make the call: + * try { __require(); } + * catch { frequire; } + */ + Expression *eresult = NULL; + Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), eresult); + Statement *s2 = new ExpStatement(loc, e); + + if (sf) + { Catch *c = new Catch(loc, NULL, NULL, sf); + Array *catches = new Array(); + catches->push(c); + sf = new TryCatchStatement(loc, s2, catches); + } + else + sf = s2; + } + } + return sf; +} + +/**************************************************** + * Merge into this function the 'out' contracts of all it overrides. + * 'out's are AND'd together, i.e. all of them need to pass. + */ + +Statement *FuncDeclaration::mergeFensure(Statement *sf) +{ + /* Same comments as for mergeFrequire(), except that we take care + * of generating a consistent reference to the 'result' local by + * explicitly passing 'result' to the nested function as a reference + * argument. + * This won't work for the 'this' parameter as it would require changing + * the semantic code for the nested function so that it looks on the parameter + * list for the 'this' pointer, something that would need an unknown amount + * of tweaking of various parts of the compiler that I'd rather leave alone. + */ + for (int i = 0; i < foverrides.dim; i++) + { + FuncDeclaration *fdv = (FuncDeclaration *)foverrides.data[i]; + sf = fdv->mergeFensure(sf); + if (fdv->fdensure) + { + //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); + // Make the call: __ensure(result) + Expression *eresult = NULL; + if (outId) + eresult = new IdentifierExp(loc, outId); + Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), eresult); + Statement *s2 = new ExpStatement(loc, e); + + if (sf) + { + sf = new CompoundStatement(fensure->loc, s2, sf); + } + else + sf = s2; + } + } + return sf; +} + +/**************************************************** + * Determine if 'this' overrides fd. + * Return !=0 if it does. + */ + +int FuncDeclaration::overrides(FuncDeclaration *fd) +{ int result = 0; + + if (fd->ident == ident) + { + int cov = type->covariant(fd->type); + if (cov) + { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); + ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); + + if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) + result = 1; + } + } + return result; +} + +/************************************************* + * Find index of function in vtbl[0..dim] that + * this function overrides. + * Prefer an exact match to a covariant one. + * Returns: + * -1 didn't find one + * -2 can't determine because of forward references + */ + +int FuncDeclaration::findVtblIndex(Array *vtbl, int dim) +{ + FuncDeclaration *mismatch = NULL; + int bestvi = -1; + for (int vi = 0; vi < dim; vi++) + { + FuncDeclaration *fdv = ((Dsymbol *)vtbl->data[vi])->isFuncDeclaration(); + if (fdv && fdv->ident == ident) + { + if (type->equals(fdv->type)) // if exact match + return vi; // no need to look further + + int cov = type->covariant(fdv->type); + //printf("\tbaseclass cov = %d\n", cov); + switch (cov) + { + case 0: // types are distinct + break; + + case 1: + bestvi = vi; // covariant, but not identical + break; // keep looking for an exact match + + case 2: + mismatch = fdv; // overrides, but is not covariant + break; // keep looking for an exact match + + case 3: + return -2; // forward references + + default: + assert(0); + } + } + } + if (bestvi == -1 && mismatch) + { + //type->print(); + //mismatch->type->print(); + //printf("%s %s\n", type->deco, mismatch->type->deco); + error("of type %s overrides but is not covariant with %s of type %s", + type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); + } + return bestvi; +} + +/**************************************************** + * Overload this FuncDeclaration with the new one f. + * Return !=0 if successful; i.e. no conflict. + */ + +int FuncDeclaration::overloadInsert(Dsymbol *s) +{ + FuncDeclaration *f; + AliasDeclaration *a; + + //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars()); + a = s->isAliasDeclaration(); + if (a) + { + if (overnext) + return overnext->overloadInsert(a); + if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) + { + //printf("\ta = '%s'\n", a->type->toChars()); + return FALSE; + } + overnext = a; + //printf("\ttrue: no conflict\n"); + return TRUE; + } + f = s->isFuncDeclaration(); + if (!f) + return FALSE; + +#if 0 + /* Disable this check because: + * const void foo(); + * semantic() isn't run yet on foo(), so the const hasn't been + * applied yet. + */ + if (type) + { printf("type = %s\n", type->toChars()); + printf("f->type = %s\n", f->type->toChars()); + } + if (type && f->type && // can be NULL for overloaded constructors + f->type->covariant(type) && + f->type->mod == type->mod && + !isFuncAliasDeclaration()) + { + //printf("\tfalse: conflict %s\n", kind()); + return FALSE; + } +#endif + + if (overnext) + return overnext->overloadInsert(f); + overnext = f; + //printf("\ttrue: no conflict\n"); + return TRUE; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +/*************************************************** + * Visit each overloaded function in turn, and call + * (*fp)(param, f) on it. + * Exit when no more, or (*fp)(param, f) returns 1. + * Returns: + * 0 continue + * 1 done + */ + +int overloadApply(Module* from, FuncDeclaration *fstart, + int (*fp)(void *, FuncDeclaration *), + void *param) +{ + FuncDeclaration *f; + Declaration *d; + Declaration *next; + + for (d = fstart; d; d = next) + { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); + + if (fa) + { + if (fa->getModule() == from || fa->importprot != PROTprivate) + if (overloadApply(from, fa->funcalias, fp, param)) + return 1; + next = fa->overnext; + } + else + { + AliasDeclaration *a = d->isAliasDeclaration(); + + if (a) + { + Dsymbol *s = a->toAlias(); + next = s->isDeclaration(); + if (next == a) + break; + if (next == fstart) + break; +#if IN_LLVM + if (a->importprot == PROTprivate && a->getModule() != from) + if (FuncDeclaration* fd = next->isFuncDeclaration()) + next = fd->overnext; +#endif + } + else + { + f = d->isFuncDeclaration(); + if (!f) + { d->error("is aliased to a function"); + break; // BUG: should print error message? + } + if ((*fp)(param, f)) + return 1; + + next = f->overnext; + } + } + } + return 0; +} + +/******************************************** + * If there are no overloads of function f, return that function, + * otherwise return NULL. + */ + +static int fpunique(void *param, FuncDeclaration *f) +{ FuncDeclaration **pf = (FuncDeclaration **)param; + + if (*pf) + { *pf = NULL; + return 1; // ambiguous, done + } + else + { *pf = f; + return 0; + } +} + +FuncDeclaration *FuncDeclaration::isUnique() +{ FuncDeclaration *result = NULL; + + overloadApply(getModule(), this, &fpunique, &result); + return result; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +struct Param1 +{ + Type *t; // type to match + FuncDeclaration *f; // return value +}; + +int fp1(void *param, FuncDeclaration *f) +{ Param1 *p = (Param1 *)param; + Type *t = p->t; + + if (t->equals(f->type)) + { p->f = f; + return 1; + } + +#if DMDV2 + /* Allow covariant matches, as long as the return type + * is just a const conversion. + * This allows things like pure functions to match with an impure function type. + */ + if (t->ty == Tfunction) + { TypeFunction *tf = (TypeFunction *)f->type; + if (tf->covariant(t) == 1 && + tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) + { + p->f = f; + return 1; + } + } +#endif + return 0; +} + +FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) +{ + Param1 p; + p.t = t; + p.f = NULL; + overloadApply(from, this, &fp1, &p); + return p.f; +} + + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match *m; +#if DMDV2 + Expression *ethis; + int property; // 0: unintialized + // 1: seen @property + // 2: not @property +#endif + Expressions *arguments; +}; + +int fp2(void *param, FuncDeclaration *f) +{ Param2 *p = (Param2 *)param; + Match *m = p->m; + Expressions *arguments = p->arguments; + MATCH match; + + if (f != m->lastf) // skip duplicates + { + m->anyf = f; + TypeFunction *tf = (TypeFunction *)f->type; + + int property = (tf->isproperty) ? 1 : 2; + if (p->property == 0) + p->property = property; + else if (p->property != property) + error(f->loc, "cannot overload both property and non-property functions"); + + /* For constructors, don't worry about the right type of ethis. It's a problem + * anyway, because the constructor attribute may not match the ethis attribute, + * but we don't care because the attribute on the ethis doesn't matter until + * after it's constructed. + */ + match = (MATCH) tf->callMatch(f->needThis() && !f->isCtorDeclaration() ? p->ethis : NULL, arguments); + //printf("test1: match = %d\n", match); + if (match != MATCHnomatch) + { + if (match > m->last) + goto LfIsBetter; + + if (match < m->last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m->lastf->overrides(f)) + goto LlastIsBetter; + else if (f->overrides(m->lastf)) + goto LfIsBetter; + +#if DMDV2 + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = f->leastAsSpecialized(m->lastf); + MATCH c2 = m->lastf->leastAsSpecialized(f); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) + goto LfIsBetter; + if (c1 < c2) + goto LlastIsBetter; + } +#endif + Lambiguous: + m->nextf = f; + m->count++; + return 0; + + LfIsBetter: + m->last = match; + m->lastf = f; + m->count = 1; + return 0; + + LlastIsBetter: + return 0; + } + } + return 0; +} + + +void overloadResolveX(Match *m, FuncDeclaration *fstart, + Expression *ethis, Expressions *arguments, Module* from) +{ + Param2 p; + p.m = m; + p.ethis = ethis; + p.property = 0; + p.arguments = arguments; + overloadApply(from, fstart, &fp2, &p); +} + + +FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags, Module* from) +{ + TypeFunction *tf; + Match m; + +#if 0 +printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); +if (arguments) +{ int i; + + for (i = 0; i < arguments->dim; i++) + { Expression *arg; + + arg = (Expression *)arguments->data[i]; + assert(arg->type); + printf("\t%s: ", arg->toChars()); + arg->type->print(); + } +} +#endif + + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + overloadResolveX(&m, this, ethis, arguments, from); + + if (m.count == 1) // exactly one match + { + return m.lastf; + } + else + { + OutBuffer buf; + + buf.writeByte('('); + if (arguments) + { + HdrGenState hgs; + + argExpTypesToCBuffer(&buf, arguments, &hgs); + buf.writeByte(')'); + if (ethis) + ethis->type->modToBuffer(&buf); + } + else + buf.writeByte(')'); + + if (m.last == MATCHnomatch) + { + if (flags & 1) // if do not print error messages + return NULL; // no match + + tf = (TypeFunction *)type; + + OutBuffer buf2; + tf->modToBuffer(&buf2); + + //printf("tf = %s, args = %s\n", tf->deco, ((Expression *)arguments->data[0])->type->deco); + error(loc, "%s%s is not callable using argument types %s", + Parameter::argsTypesToChars(tf->parameters, tf->varargs), + buf2.toChars(), + buf.toChars()); + return m.anyf; // as long as it's not a FuncAliasDeclaration + } + else + { +#if 1 + TypeFunction *t1 = (TypeFunction *)m.lastf->type; + TypeFunction *t2 = (TypeFunction *)m.nextf->type; + + error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", + buf.toChars(), + m.lastf->toPrettyChars(), Parameter::argsTypesToChars(t1->parameters, t1->varargs), + m.nextf->toPrettyChars(), Parameter::argsTypesToChars(t2->parameters, t2->varargs)); +#else + error(loc, "overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); +#endif + return m.lastf; + } + } +} + +/************************************* + * Determine partial specialization order of 'this' vs g. + * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Returns: + * match 'this' is at least as specialized as g + * 0 g is more specialized than 'this' + */ + +#if DMDV2 +MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) +{ +#define LOG_LEASTAS 0 + +#if LOG_LEASTAS + printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); + printf("%s, %s\n", type->toChars(), g->type->toChars()); +#endif + + /* This works by calling g() with f()'s parameters, and + * if that is possible, then f() is at least as specialized + * as g() is. + */ + + TypeFunction *tf = (TypeFunction *)type; + TypeFunction *tg = (TypeFunction *)g->type; + size_t nfparams = Parameter::dim(tf->parameters); + size_t ngparams = Parameter::dim(tg->parameters); + MATCH match = MATCHexact; + + /* If both functions have a 'this' pointer, and the mods are not + * the same and g's is not const, then this is less specialized. + */ + if (needThis() && g->needThis()) + { + if (tf->mod != tg->mod) + { + if (tg->mod == MODconst) + match = MATCHconst; + else + return MATCHnomatch; + } + } + + /* Create a dummy array of arguments out of the parameters to f() + */ + Expressions args; + args.setDim(nfparams); + for (int u = 0; u < nfparams; u++) + { + Parameter *p = Parameter::getNth(tf->parameters, u); + Expression *e; + if (p->storageClass & (STCref | STCout)) + { + e = new IdentifierExp(0, p->ident); + e->type = p->type; + } + else + e = p->type->defaultInit(); + args.data[u] = e; + } + + MATCH m = (MATCH) tg->callMatch(NULL, &args, 1); + if (m) + { + /* A variadic parameter list is less specialized than a + * non-variadic one. + */ + if (tf->varargs && !tg->varargs) + goto L1; // less specialized + +#if LOG_LEASTAS + printf(" matches %d, so is least as specialized\n", m); +#endif + return m; + } + L1: +#if LOG_LEASTAS + printf(" doesn't match, so is not as specialized\n"); +#endif + return MATCHnomatch; +} + +/******************************************* + * Given a symbol that could be either a FuncDeclaration or + * a function template, resolve it to a function symbol. + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL + */ + +FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, + Objects *tiargs, + Expression *ethis, + Expressions *arguments, + int flags) +{ + if (!s) + return NULL; // no match + FuncDeclaration *f = s->isFuncDeclaration(); + if (f) + f = f->overloadResolve(loc, ethis, arguments); + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + assert(td); + f = td->deduceFunctionTemplate(sc, loc, tiargs, NULL, arguments, flags); + } + return f; +} +#endif + +/******************************** + * Labels are in a separate scope, one per function. + */ + +LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) +{ Dsymbol *s; + + if (!labtab) + labtab = new DsymbolTable(); // guess we need one + + s = labtab->lookup(ident); + if (!s) + { + s = new LabelDsymbol(ident); + labtab->insert(s); + } + return (LabelDsymbol *)s; +} + +/**************************************** + * If non-static member function that has a 'this' pointer, + * return the aggregate it is a member of. + * Otherwise, return NULL. + */ + +AggregateDeclaration *FuncDeclaration::isThis() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); + ad = NULL; + if ((storage_class & STCstatic) == 0) + { + ad = isMember2(); + } + //printf("-FuncDeclaration::isThis() %p\n", ad); + return ad; +} + +AggregateDeclaration *FuncDeclaration::isMember2() +{ AggregateDeclaration *ad; + + //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); + ad = NULL; + for (Dsymbol *s = this; s; s = s->parent) + { +//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); + ad = s->isMember(); + if (ad) +{ + break; +} + if (!s->parent || + (!s->parent->isTemplateInstance())) +{ + break; +} + } + //printf("-FuncDeclaration::isMember2() %p\n", ad); + return ad; +} + +/***************************************** + * Determine lexical level difference from 'this' to nested function 'fd'. + * Error if this cannot call fd. + * Returns: + * 0 same level + * -1 increase nesting by 1 (fd is nested within 'this') + * >0 decrease nesting by number + */ + +int FuncDeclaration::getLevel(Loc loc, FuncDeclaration *fd) +{ int level; + Dsymbol *s; + Dsymbol *fdparent; + + //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); + fdparent = fd->toParent2(); + if (fdparent == this) + return -1; + s = this; + level = 0; + while (fd != s && fdparent != s->toParent2()) + { + //printf("\ts = %s, '%s'\n", s->kind(), s->toChars()); + FuncDeclaration *thisfd = s->isFuncDeclaration(); + if (thisfd) + { if (!thisfd->isNested() && !thisfd->vthis) + goto Lerr; + } + else + { + AggregateDeclaration *thiscd = s->isAggregateDeclaration(); + if (thiscd) + { if (!thiscd->isNested()) + goto Lerr; + } + else + goto Lerr; + } + + s = s->toParent2(); + assert(s); + level++; + } + return level; + +Lerr: + error(loc, "cannot access frame of function %s", fd->toPrettyChars()); + return 1; +} + +void FuncDeclaration::appendExp(Expression *e) +{ Statement *s; + + s = new ExpStatement(0, e); + appendState(s); +} + +void FuncDeclaration::appendState(Statement *s) +{ + if (!fbody) + fbody = s; + else + { + CompoundStatement *cs = fbody->isCompoundStatement(); + if (cs) + { + if (!cs->statements) + fbody = s; + else + cs->statements->push(s); + } + else + fbody = new CompoundStatement(0, fbody, s); + } +} + +const char *FuncDeclaration::toPrettyChars() +{ + if (isMain()) + return "D main"; + else + return Dsymbol::toPrettyChars(); +} + +int FuncDeclaration::isMain() +{ + return ident == Id::main && + linkage != LINKc && !isMember() && !isNested(); +} + +int FuncDeclaration::isWinMain() +{ + //printf("FuncDeclaration::isWinMain() %s\n", toChars()); +#if 0 + int x = ident == Id::WinMain && + linkage != LINKc && !isMember(); + printf("%s\n", x ? "yes" : "no"); + return x; +#else + return ident == Id::WinMain && + linkage != LINKc && !isMember(); +#endif +} + +int FuncDeclaration::isDllMain() +{ + return ident == Id::DllMain && + linkage != LINKc && !isMember(); +} + +int FuncDeclaration::isExport() +{ + return protection == PROTexport; +} + +int FuncDeclaration::isImportedSymbol() +{ + //printf("isImportedSymbol()\n"); + //printf("protection = %d\n", protection); + return (protection == PROTexport) && !fbody; +} + +// Determine if function goes into virtual function pointer table + +int FuncDeclaration::isVirtual() +{ +#if 0 + printf("FuncDeclaration::isVirtual(%s)\n", toChars()); + printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); + printf("result is %d\n", + isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + toParent()->isClassDeclaration()); +#endif + Dsymbol *p = toParent(); + return isMember() && + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + p->isClassDeclaration() && + !(p->isInterfaceDeclaration() && isFinal()); +} + +int FuncDeclaration::isFinal() +{ + ClassDeclaration *cd; +#if 0 + printf("FuncDeclaration::isFinal(%s), %x\n", toChars(), Declaration::isFinal()); + printf("%p %d %d %d\n", isMember(), isStatic(), Declaration::isFinal(), ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); + printf("result is %d\n", + isMember() && + (Declaration::isFinal() || + ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal))); + if (cd) + printf("\tmember of %s\n", cd->toChars()); +#if 0 + !(isStatic() || protection == PROTprivate || protection == PROTpackage) && + (cd = toParent()->isClassDeclaration()) != NULL && + cd->storage_class & STCfinal); +#endif +#endif + return isMember() && + (Declaration::isFinal() || + ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); +} + +int FuncDeclaration::isAbstract() +{ + return storage_class & STCabstract; +} + +int FuncDeclaration::isCodeseg() +{ + return TRUE; // functions are always in the code segment +} + +int FuncDeclaration::isOverloadable() +{ + return 1; // functions can be overloaded +} + +int FuncDeclaration::isPure() +{ + //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + assert(type->ty == Tfunction); + return ((TypeFunction *)this->type)->ispure; +} + +int FuncDeclaration::isSafe() +{ + assert(type->ty == Tfunction); + return ((TypeFunction *)type)->trust == TRUSTsafe; +} + +int FuncDeclaration::isTrusted() +{ + assert(type->ty == Tfunction); + return ((TypeFunction *)type)->trust == TRUSTtrusted; +} + +// Determine if function needs +// a static frame pointer to its lexically enclosing function + +int FuncDeclaration::isNested() +{ + //if (!toParent()) + //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); + //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); + return ((storage_class & STCstatic) == 0) && toParent2() && + (toParent2()->isFuncDeclaration() != NULL); +} + +int FuncDeclaration::needThis() +{ + //printf("FuncDeclaration::needThis() '%s'\n", toChars()); + int i = isThis() != NULL; + //printf("\t%d\n", i); + if (!i && isFuncAliasDeclaration()) + i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); + return i; +} + +int FuncDeclaration::addPreInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked && + ident != Id::cpctor); +} + +int FuncDeclaration::addPostInvariant() +{ + AggregateDeclaration *ad = isThis(); + return (ad && + ad->inv && + //ad->isClassDeclaration() && + global.params.useInvariants && + (protection == PROTpublic || protection == PROTexport) && + !naked && + ident != Id::cpctor); +} + +/********************************** + * Generate a FuncDeclaration for a runtime library function. + */ + +// +// LDC: Adjusted to give argument info to the runtime function decl. +// + +FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name) +{ + return genCfunc(args, treturn, Lexer::idPool(name)); +} + +FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id) +{ + FuncDeclaration *fd; + TypeFunction *tf; + Dsymbol *s; + static DsymbolTable *st = NULL; + + //printf("genCfunc(name = '%s')\n", id->toChars()); + //printf("treturn\n\t"); treturn->print(); + + // See if already in table + if (!st) + st = new DsymbolTable(); + s = st->lookup(id); + if (s) + { + fd = s->isFuncDeclaration(); + assert(fd); + assert(fd->type->nextOf()->equals(treturn)); + } + else + { + tf = new TypeFunction(NULL, treturn, 0, LINKc); + fd = new FuncDeclaration(0, 0, id, STCstatic, tf); + fd->protection = PROTpublic; + fd->linkage = LINKc; + + st->insert(fd); + } + return fd; +} + +const char *FuncDeclaration::kind() +{ + return "function"; +} + +/******************************* + * Look at all the variables in this function that are referenced + * by nested functions, and determine if a closure needs to be + * created for them. + */ + +#if DMDV2 +int FuncDeclaration::needsClosure() +{ + /* Need a closure for all the closureVars[] if any of the + * closureVars[] are accessed by a + * function that escapes the scope of this function. + * We take the conservative approach and decide that any function that: + * 1) is a virtual function + * 2) has its address taken + * 3) has a parent that escapes + * + * Note that since a non-virtual function can be called by + * a virtual one, if that non-virtual function accesses a closure + * var, the closure still has to be taken. Hence, we check for isThis() + * instead of isVirtual(). (thanks to David Friedman) + */ + + //printf("FuncDeclaration::needsClosure() %s\n", toChars()); + for (int i = 0; i < closureVars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)closureVars.data[i]; + assert(v->isVarDeclaration()); + //printf("\tv = %s\n", v->toChars()); + + for (int j = 0; j < v->nestedrefs.dim; j++) + { FuncDeclaration *f = (FuncDeclaration *)v->nestedrefs.data[j]; + assert(f != this); + + //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); + if (f->isThis() || f->tookAddressOf) + goto Lyes; // assume f escapes this function's scope + + // Look to see if any parents of f that are below this escape + for (Dsymbol *s = f->parent; s && s != this; s = s->parent) + { + f = s->isFuncDeclaration(); + if (f && (f->isThis() || f->tookAddressOf)) + goto Lyes; + } + } + } + return 0; + +Lyes: + //printf("\tneeds closure\n"); + return 1; +} +#endif + +/********************************************* + * Return the function's parameter list, and whether + * it is variadic or not. + */ + +Parameters *FuncDeclaration::getParameters(int *pvarargs) +{ Parameters *fparameters; + int fvarargs; + + if (type) + { + assert(type->ty == Tfunction); + TypeFunction *fdtype = (TypeFunction *)type; + fparameters = fdtype->parameters; + fvarargs = fdtype->varargs; + } + else // Constructors don't have type's + { CtorDeclaration *fctor = isCtorDeclaration(); + assert(fctor); + fparameters = fctor->arguments; + fvarargs = fctor->varargs; + } + if (pvarargs) + *pvarargs = fvarargs; + return fparameters; +} + + +/****************************** FuncAliasDeclaration ************************/ + +// Used as a way to import a set of functions from another scope into this one. + +FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) + : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, + funcalias->storage_class, funcalias->type) +{ + assert(funcalias != this); + this->funcalias = funcalias; +#if IN_LLVM + importprot = PROTundefined; +#endif +} + +const char *FuncAliasDeclaration::kind() +{ + return "function alias"; +} + + +/****************************** FuncLiteralDeclaration ************************/ + +FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, + enum TOK tok, ForeachStatement *fes) + : FuncDeclaration(loc, endloc, NULL, STCundefined, type) +{ + const char *id; + + if (fes) + id = "__foreachbody"; + else if (tok == TOKdelegate) + id = "__dgliteral"; + else + id = "__funcliteral"; + this->ident = Lexer::uniqueId(id); + this->tok = tok; + this->fes = fes; + //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); +} + +Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) +{ + FuncLiteralDeclaration *f; + + //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); + if (s) + f = (FuncLiteralDeclaration *)s; + else + { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); + f->ident = ident; // keep old identifier + } + FuncDeclaration::syntaxCopy(f); + return f; +} + +int FuncLiteralDeclaration::isNested() +{ + //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); + return (tok == TOKdelegate); +} + +int FuncLiteralDeclaration::isVirtual() +{ + return FALSE; +} + +const char *FuncLiteralDeclaration::kind() +{ + // GCC requires the (char*) casts + return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; +} + +void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(kind()); + buf->writeByte(' '); + type->toCBuffer(buf, NULL, hgs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* CtorDeclaration ****************************/ + +CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs, StorageClass stc) + : FuncDeclaration(loc, endloc, Id::ctor, stc, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; + //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); +} + +Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) +{ + CtorDeclaration *f = new CtorDeclaration(loc, endloc, NULL, varargs, storage_class); + + f->outId = outId; + f->frequire = frequire ? frequire->syntaxCopy() : NULL; + f->fensure = fensure ? fensure->syntaxCopy() : NULL; + f->fbody = fbody ? fbody->syntaxCopy() : NULL; + assert(!fthrows); // deprecated + + f->arguments = Parameter::arraySyntaxCopy(arguments); + return f; +} + + +void CtorDeclaration::semantic(Scope *sc) +{ + //printf("CtorDeclaration::semantic() %s\n", toChars()); + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static constructor + + parent = sc->parent; + Dsymbol *parent = toParent2(); + Type *tret; + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + if (!ad || parent->isUnionDeclaration()) + { + error("constructors are only for class or struct definitions"); + fatal(); + tret = Type::tvoid; + } + else + { tret = ad->handle; + assert(tret); + tret = tret->addStorageClass(storage_class | sc->stc); + } + if (!type) + type = new TypeFunction(arguments, tret, varargs, LINKd, storage_class | sc->stc); + +#if STRUCTTHISREF + if (ad && ad->isStructDeclaration()) + ((TypeFunction *)type)->isref = 1; +#endif + if (!originalType) + originalType = type; + + // Append: + // return this; + // to the function body + if (fbody && semanticRun < PASSsemantic) + { + Expression *e = new ThisExp(loc); + if (parent->isClassDeclaration()) + e->type = tret; + Statement *s = new ReturnStatement(loc, e); + fbody = new CompoundStatement(loc, fbody, s); + } + + FuncDeclaration::semantic(sc); + + sc->pop(); + + // See if it's the default constructor + if (ad && varargs == 0 && Parameter::dim(arguments) == 0) + { if (ad->isStructDeclaration()) + error("default constructor not allowed for structs"); + else + ad->defaultCtor = this; + } +} + +const char *CtorDeclaration::kind() +{ + return "constructor"; +} + +char *CtorDeclaration::toChars() +{ + return (char *)"this"; +} + +int CtorDeclaration::isVirtual() +{ + return FALSE; +} + +int CtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int CtorDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + + +void CtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this"); + Parameter::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + +/********************************* PostBlitDeclaration ****************************/ + +#if DMDV2 +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::_postblit, STCundefined, NULL) +{ +} + +PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void PostBlitDeclaration::semantic(Scope *sc) +{ + //printf("PostBlitDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + //printf("stc = x%llx\n", sc->stc); + parent = sc->parent; + Dsymbol *parent = toParent(); + StructDeclaration *ad = parent->isStructDeclaration(); + if (!ad) + { + error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + } + else if (ident == Id::_postblit && semanticRun < PASSsemantic) + ad->postblits.push(this); + + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not static + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int PostBlitDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload postblits +} + +int PostBlitDeclaration::addPreInvariant() +{ + return FALSE; +} + +int PostBlitDeclaration::addPostInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int PostBlitDeclaration::isVirtual() +{ + return FALSE; +} + +void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this(this)"); + bodyToCBuffer(buf, hgs); +} +#endif + +/********************************* DtorDeclaration ****************************/ + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) +{ +} + +DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) + : FuncDeclaration(loc, endloc, id, STCundefined, NULL) +{ +} + +Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); + return FuncDeclaration::syntaxCopy(dd); +} + + +void DtorDeclaration::semantic(Scope *sc) +{ + //printf("DtorDeclaration::semantic() %s\n", toChars()); + //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); + parent = sc->parent; + Dsymbol *parent = toParent(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); + fatal(); + } + else if (ident == Id::dtor && semanticRun < PASSsemantic) + ad->dtors.push(this); + + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static destructor + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int DtorDeclaration::overloadInsert(Dsymbol *s) +{ + return FALSE; // cannot overload destructors +} + +int DtorDeclaration::addPreInvariant() +{ + return (isThis() && vthis && global.params.useInvariants); +} + +int DtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +const char *DtorDeclaration::kind() +{ + return "destructor"; +} + +char *DtorDeclaration::toChars() +{ + return (char *)"~this"; +} + +int DtorDeclaration::isVirtual() +{ + /* This should be FALSE so that dtor's don't get put into the vtbl[], + * but doing so will require recompiling everything. + */ +#if BREAKABI + return FALSE; +#else + return FuncDeclaration::isVirtual(); +#endif +} + +void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* StaticCtorDeclaration ****************************/ + +StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticCtor"), STCstatic, NULL) +{ +} + +StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name) + : FuncDeclaration(loc, endloc, + Identifier::generateId(name), STCstatic, NULL) +{ +} + +Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(scd); +} + + +void StaticCtorDeclaration::semantic(Scope *sc) +{ + //printf("StaticCtorDeclaration::semantic()\n"); + + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance() && semanticRun < PASSsemantic) + { + /* Add this prefix to the function: + * static int gate; + * if (++gate != 1) return; + * Note that this is not thread safe; should not have threads + * during static construction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = isSharedStaticCtorDeclaration() ? STCstatic : STCtls; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp(1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; + //printf("module1 %s needs moduleinfo\n", m->toChars()); +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticCtorDeclaration::isThis() +{ + return NULL; +} + +int StaticCtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticCtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + { buf->writestring("static this();\n"); + return; + } + buf->writestring("static this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* SharedStaticCtorDeclaration ****************************/ + +SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc) + : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor") +{ +} + +Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(scd); +} + +void SharedStaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("shared "); + StaticCtorDeclaration::toCBuffer(buf, hgs); +} + +/********************************* StaticDtorDeclaration ****************************/ + +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, + Identifier::generateId("_staticDtor"), STCstatic, NULL) +{ + vgate = NULL; +} + +StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name) + : FuncDeclaration(loc, endloc, + Identifier::generateId(name), STCstatic, NULL) +{ + vgate = NULL; +} + +Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(sdd); +} + + +void StaticDtorDeclaration::semantic(Scope *sc) +{ + ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); + + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + /* If the static ctor appears within a template instantiation, + * it could get called multiple times by the module constructors + * for different modules. Thus, protect it with a gate. + */ + if (inTemplateInstance() && semanticRun < PASSsemantic) + { + /* Add this prefix to the function: + * static int gate; + * if (--gate != 0) return; + * Increment gate during constructor execution. + * Note that this is not thread safe; should not have threads + * during static destruction. + */ + Identifier *id = Lexer::idPool("__gate"); + VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); + v->storage_class = isSharedStaticDtorDeclaration() ? STCstatic : STCtls; + Statements *sa = new Statements(); + Statement *s = new DeclarationStatement(0, v); + sa->push(s); + Expression *e = new IdentifierExp(0, id); + e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); + e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); + s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); + sa->push(s); + if (fbody) + sa->push(fbody); + fbody = new CompoundStatement(0, sa); + vgate = v; + } + + FuncDeclaration::semantic(sc); + + // We're going to need ModuleInfo + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { m->needmoduleinfo = 1; + //printf("module2 %s needs moduleinfo\n", m->toChars()); +#ifdef IN_GCC + m->strictlyneedmoduleinfo = 1; +#endif + } +} + +AggregateDeclaration *StaticDtorDeclaration::isThis() +{ + return NULL; +} + +int StaticDtorDeclaration::isVirtual() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPreInvariant() +{ + return FALSE; +} + +int StaticDtorDeclaration::addPostInvariant() +{ + return FALSE; +} + +void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("static ~this()"); + bodyToCBuffer(buf, hgs); +} + +/********************************* SharedStaticDtorDeclaration ****************************/ + +SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc) + : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor") +{ +} + +Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s) +{ + assert(!s); + SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(sdd); +} + +void SharedStaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (!hgs->hdrgen) + { + buf->writestring("shared "); + StaticDtorDeclaration::toCBuffer(buf, hgs); + } +} + + +/********************************* InvariantDeclaration ****************************/ + +InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) +{ +} + +Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) +{ + InvariantDeclaration *id; + + assert(!s); + id = new InvariantDeclaration(loc, endloc); + FuncDeclaration::syntaxCopy(id); + return id; +} + + +void InvariantDeclaration::semantic(Scope *sc) +{ + parent = sc->parent; + Dsymbol *parent = toParent(); + AggregateDeclaration *ad = parent->isAggregateDeclaration(); + if (!ad) + { + error("invariants are only for struct/union/class definitions"); + return; + } + else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic) + { + error("more than one invariant for %s", ad->toChars()); + } + ad->inv = this; + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + + sc = sc->push(); + sc->stc &= ~STCstatic; // not a static invariant + sc->incontract++; + sc->linkage = LINKd; + + FuncDeclaration::semantic(sc); + + sc->pop(); +} + +int InvariantDeclaration::isVirtual() +{ + return FALSE; +} + +int InvariantDeclaration::addPreInvariant() +{ + return FALSE; +} + +int InvariantDeclaration::addPostInvariant() +{ + return FALSE; +} + +void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("invariant"); + bodyToCBuffer(buf, hgs); +} + + +/********************************* UnitTestDeclaration ****************************/ + +/******************************* + * Generate unique unittest function Id so we can have multiple + * instances per module. + */ + +static Identifier *unitTestId() +{ + return Lexer::uniqueId("__unittest"); +} + +UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) + : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) +{ +} + +Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) +{ + UnitTestDeclaration *utd; + + assert(!s); + utd = new UnitTestDeclaration(loc, endloc); + return FuncDeclaration::syntaxCopy(utd); +} + + +void UnitTestDeclaration::semantic(Scope *sc) +{ + if (global.params.useUnitTests) + { + if (!type) + type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); + Scope *sc2 = sc->push(); + sc2->linkage = LINKd; + FuncDeclaration::semantic(sc2); + sc2->pop(); + } + +#if 0 + // We're going to need ModuleInfo even if the unit tests are not + // compiled in, because other modules may import this module and refer + // to this ModuleInfo. + // (This doesn't make sense to me?) + Module *m = getModule(); + if (!m) + m = sc->module; + if (m) + { + //printf("module3 %s needs moduleinfo\n", m->toChars()); + m->needmoduleinfo = 1; + } +#endif +} + +AggregateDeclaration *UnitTestDeclaration::isThis() +{ + return NULL; +} + +int UnitTestDeclaration::isVirtual() +{ + return FALSE; +} + +int UnitTestDeclaration::addPreInvariant() +{ + return FALSE; +} + +int UnitTestDeclaration::addPostInvariant() +{ + return FALSE; +} + +void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen) + return; + buf->writestring("unittest"); + bodyToCBuffer(buf, hgs); +} + +/********************************* NewDeclaration ****************************/ + +NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) + : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) +{ + this->arguments = arguments; + this->varargs = varargs; +} + +Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) +{ + NewDeclaration *f; + + f = new NewDeclaration(loc, endloc, NULL, varargs); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Parameter::arraySyntaxCopy(arguments); + + return f; +} + + +void NewDeclaration::semantic(Scope *sc) +{ + //printf("NewDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + Type *tret = Type::tvoid->pointerTo(); + if (!type) + type = new TypeFunction(arguments, tret, varargs, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is at least one argument of type size_t + TypeFunction *tf = (TypeFunction *)type; + if (Parameter::dim(tf->parameters) < 1) + { + error("at least one argument of type size_t expected"); + } + else + { + Parameter *a = Parameter::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tsize_t)) + error("first argument must be type size_t, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *NewDeclaration::kind() +{ + return "allocator"; +} + +int NewDeclaration::isVirtual() +{ + return FALSE; +} + +int NewDeclaration::addPreInvariant() +{ + return FALSE; +} + +int NewDeclaration::addPostInvariant() +{ + return FALSE; +} + +void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("new"); + Parameter::argsToCBuffer(buf, hgs, arguments, varargs); + bodyToCBuffer(buf, hgs); +} + + +/********************************* DeleteDeclaration ****************************/ + +DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) + : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) +{ + this->arguments = arguments; +} + +Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) +{ + DeleteDeclaration *f; + + f = new DeleteDeclaration(loc, endloc, NULL); + + FuncDeclaration::syntaxCopy(f); + + f->arguments = Parameter::arraySyntaxCopy(arguments); + + return f; +} + + +void DeleteDeclaration::semantic(Scope *sc) +{ + //printf("DeleteDeclaration::semantic()\n"); + + parent = sc->parent; + Dsymbol *parent = toParent(); + ClassDeclaration *cd = parent->isClassDeclaration(); + if (!cd && !parent->isStructDeclaration()) + { + error("new allocators only are for class or struct definitions"); + } + if (!type) + type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); + + type = type->semantic(loc, sc); + assert(type->ty == Tfunction); + + // Check that there is only one argument of type void* + TypeFunction *tf = (TypeFunction *)type; + if (Parameter::dim(tf->parameters) != 1) + { + error("one argument of type void* expected"); + } + else + { + Parameter *a = Parameter::getNth(tf->parameters, 0); + if (!a->type->equals(Type::tvoid->pointerTo())) + error("one argument of type void* expected, not %s", a->type->toChars()); + } + + FuncDeclaration::semantic(sc); +} + +const char *DeleteDeclaration::kind() +{ + return "deallocator"; +} + +int DeleteDeclaration::isDelete() +{ + return TRUE; +} + +int DeleteDeclaration::isVirtual() +{ + return FALSE; +} + +int DeleteDeclaration::addPreInvariant() +{ + return FALSE; +} + +int DeleteDeclaration::addPostInvariant() +{ + return FALSE; +} + +void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("delete"); + Parameter::argsToCBuffer(buf, hgs, arguments, 0); + bodyToCBuffer(buf, hgs); +} + + + + diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c index b7a14fb6..63d70667 100644 --- a/dmd2/hdrgen.c +++ b/dmd2/hdrgen.c @@ -1,104 +1,104 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// Initial header generation implementation by Dave Fladebo -// 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. - -// Routines to emit header files - -#ifdef _DH - -#define PRETTY_PRINT -#define TEST_EMIT_ALL 0 // For Testing - -#define LOG 0 - -#include -#include -#include -#if __DMC__ -#include -#endif - -#include "rmem.h" - -#include "id.h" -#include "init.h" - -#include "attrib.h" -#include "cond.h" -#include "enum.h" -#include "import.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "staticassert.h" -#include "template.h" -#include "utf.h" -#include "version.h" - -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "hdrgen.h" - -void argsToCBuffer(OutBuffer *buf, Array *arguments, HdrGenState *hgs); - -void Module::genhdrfile() -{ - OutBuffer hdrbufr; - - hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); - hdrbufr.writenl(); - - HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - hgs.hdrgen = 1; - - toCBuffer(&hdrbufr, &hgs); - - // Transfer image to file - hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); - hdrbufr.data = NULL; - - char *pt = FileName::path(hdrfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - hdrfile->writev(); -} - - -void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (md) - { - buf->writestring("module "); - buf->writestring(md->toChars()); - buf->writebyte(';'); - buf->writenl(); - } - - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - - s->toHBuffer(buf, hgs); - } -} - - -void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - toCBuffer(buf, hgs); -} - - -/*************************************/ - -#endif // #ifdef _DH + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// Initial header generation implementation by Dave Fladebo +// 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. + +// Routines to emit header files + +#ifdef _DH + +#define PRETTY_PRINT +#define TEST_EMIT_ALL 0 // For Testing + +#define LOG 0 + +#include +#include +#include +#if __DMC__ +#include +#endif + +#include "rmem.h" + +#include "id.h" +#include "init.h" + +#include "attrib.h" +#include "cond.h" +#include "enum.h" +#include "import.h" +#include "module.h" +#include "mtype.h" +#include "scope.h" +#include "staticassert.h" +#include "template.h" +#include "utf.h" +#include "version.h" + +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "statement.h" +#include "mtype.h" +#include "hdrgen.h" + +void argsToCBuffer(OutBuffer *buf, Array *arguments, HdrGenState *hgs); + +void Module::genhdrfile() +{ + OutBuffer hdrbufr; + + hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); + hdrbufr.writenl(); + + HdrGenState hgs; + memset(&hgs, 0, sizeof(hgs)); + hgs.hdrgen = 1; + + toCBuffer(&hdrbufr, &hgs); + + // Transfer image to file + hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); + hdrbufr.data = NULL; + + char *pt = FileName::path(hdrfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + hdrfile->writev(); +} + + +void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (md) + { + buf->writestring("module "); + buf->writestring(md->toChars()); + buf->writebyte(';'); + buf->writenl(); + } + + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + + s->toHBuffer(buf, hgs); + } +} + + +void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + toCBuffer(buf, hgs); +} + + +/*************************************/ + +#endif // #ifdef _DH diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h index d4a21861..79cfb732 100644 --- a/dmd2/hdrgen.h +++ b/dmd2/hdrgen.h @@ -1,34 +1,34 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// initial header generation implementation by Dave Fladebo -// 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. - - -struct HdrGenState -{ - int hdrgen; // 1 if generating header file - int ddoc; // 1 if generating Ddoc file - int console; // 1 if writing to console - int tpltMember; - int inCallExp; - int inPtrExp; - int inSlcExp; - int inDotExp; - int inBinExp; - int inArrExp; - int emitInst; - struct - { - int init; - int decl; - } FLinit; - - HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } -}; - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// initial header generation implementation by Dave Fladebo +// 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. + + +struct HdrGenState +{ + int hdrgen; // 1 if generating header file + int ddoc; // 1 if generating Ddoc file + int console; // 1 if writing to console + int tpltMember; + int inCallExp; + int inPtrExp; + int inSlcExp; + int inDotExp; + int inBinExp; + int inArrExp; + int emitInst; + struct + { + int init; + int decl; + } FLinit; + + HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } +}; + + diff --git a/dmd2/html.c b/dmd2/html.c index 243df1c3..155999b9 100644 --- a/dmd2/html.c +++ b/dmd2/html.c @@ -1,720 +1,720 @@ - -// Copyright (c) 1999-2009 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. - - -/* HTML parser - */ - -#include -#include -#include -#include -#include -#include - -#include "mars.h" -#include "html.h" - -#include -#include "root.h" - -extern int HtmlNamedEntity(unsigned char *p, int length); - -static int isLineSeparator(const unsigned char* p); - -/********************************** - * Determine if beginning of tag identifier - * or a continuation of a tag identifier. - */ - -inline int istagstart(int c) -{ - return (isalpha(c) || c == '_'); -} - -inline int istag(int c) -{ - return (isalnum(c) || c == '_'); -} - -/********************************************** - */ - -Html::Html(const char *sourcename, unsigned char *base, unsigned length) -{ - //printf("Html::Html()\n"); - this->sourcename = sourcename; - this->base = base; - p = base; - end = base + length; - linnum = 1; - dbuf = NULL; - inCode = 0; -} - -/********************************************** - * Print error & quit. - */ - -void Html::error(const char *format, ...) -{ - if (!global.gag) - { - printf("%s(%d) : HTML Error: ", sourcename, linnum); - - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - - printf("\n"); - fflush(stdout); - } - - global.errors++; -} - -/********************************************** - * Extract all the code from an HTML file, - * concatenate it all together, and store in buf. - */ - -void Html::extractCode(OutBuffer *buf) -{ - //printf("Html::extractCode()\n"); - dbuf = buf; // save for other routines - buf->reserve(end - p); - inCode = 0; - while (1) - { - //printf("p = %p, *p = x%x\n", p, *p); - switch (*p) - { -#if 0 // strings are not recognized outside of tags - case '"': - case '\'': - skipString(); - continue; -#endif - case '<': - if (p[1] == '!' && isCommentStart()) - { // Comments start with - * Netscape: comments nest - * w3c: whitespace can appear between -- and > of comment close - */ - -void Html::scanComment() -{ - // Most of the complexity is dealing with the case that - // an arbitrary amount of whitespace can appear between - // the -- and the > of a comment close. - int scangt = 0; - - //printf("scanComment()\n"); - if (*p == '\n') - { linnum++; - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - } - while (1) - { - //scangt = 1; // IE 5.0 compatibility - p++; - switch (*p) - { - case '-': - if (p[1] == '-') - { - if (p[2] == '>') // optimize for most common case - { - p += 3; - break; - } - p++; - scangt = 1; - } - else - scangt = 0; - continue; - - case '>': - if (scangt) - { // found --> - p++; - break; - } - continue; - - case ' ': - case '\t': - case '\f': - case '\v': - // skip white space - continue; - - case '\r': - if (p[1] == '\n') - goto Ldefault; - case '\n': - linnum++; // remember to count lines - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - continue; - - case 0: - case 0x1a: - error("end of file before closing --> of comment"); - break; - - default: - Ldefault: - scangt = 0; // it's not --> - continue; - } - break; - } - //printf("*p = '%c'\n", *p); -} - -/******************************************** - * Determine if we are at the start of a comment. - * Input: - * p is on the opening '<' - * Returns: - * 0 if not start of a comment - * 1 if start of a comment, p is adjusted to point past -- - */ - -int Html::isCommentStart() -#ifdef __DMC__ - __out(result) - { - if (result == 0) - ; - else if (result == 1) - { - assert(p[-2] == '-' && p[-1] == '-'); - } - else - assert(0); - } - __body -#endif /* __DMC__ */ - { unsigned char *s; - - if (p[0] == '<' && p[1] == '!') - { - for (s = p + 2; 1; s++) - { - switch (*s) - { - case ' ': - case '\t': - case '\r': - case '\f': - case '\v': - // skip white space, even though spec says no - // white space is allowed - continue; - - case '-': - if (s[1] == '-') - { - p = s + 2; - return 1; - } - goto No; - - default: - goto No; - } - } - } - No: - return 0; - } - -int Html::isCDATAStart() -{ - const char * CDATA_START_MARKER = "0) - { - /* Always extract new lines, so that D lexer counts the lines - * right. - */ - linnum++; - dbuf->writeUTF8('\n'); - p += lineSepLength; - continue; - } - else if (p[0] == ']' && p[1] == ']' && p[2] == '>') - { - /* end of CDATA section */ - p += 3; - return; - } - else if (inCode) - { - /* this CDATA section contains D code */ - dbuf->writeByte(*p); - } - - p++; - } -} - - -/******************************************** - * Convert an HTML character entity into a character. - * Forms are: - * &name; named entity - * &#ddd; decimal - * &#xhhhh; hex - * Input: - * p is on the & - */ - -int Html::charEntity() -{ int c = 0; - int v; - int hex; - unsigned char *pstart = p; - - //printf("Html::charEntity('%c')\n", *p); - if (p[1] == '#') - { - p++; - if (p[1] == 'x' || p[1] == 'X') - { p++; - hex = 1; - } - else - hex = 0; - if (p[1] == ';') - goto Linvalid; - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - goto Lignore; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - break; - - case ';': - // Termination is explicit - p++; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - v = *p - '0'; - goto Lvalue; - - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - if (!hex) - goto Linvalid; - v = (*p - 'a') + 10; - goto Lvalue; - - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - if (!hex) - goto Linvalid; - v = (*p - 'A') + 10; - goto Lvalue; - - Lvalue: - if (hex) - c = (c << 4) + v; - else - c = (c * 10) + v; - if (c > 0x10FFFF) - { - error("character entity out of range"); - goto Lignore; - } - continue; - - default: - Linvalid: - error("invalid numeric character reference"); - goto Lignore; - } - break; - } - } - else - { - // It's a named entity; gather all characters until ; - unsigned char *idstart = p + 1; - - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - break; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - break; - - case ';': - // Termination is explicit - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - p++; - break; - - default: - continue; - } - break; - } - } - - // Kludge to convert non-breaking space to ascii space - if (c == 160) - c = ' '; - - return c; - -Lignore: - //printf("Lignore\n"); - p = pstart + 1; - return '&'; -} - -/** - * identify DOS, Linux, Mac, Next and Unicode line endings - * 0 if this is no line separator - * >0 the length of the separator - * Note: input has to be UTF-8 - */ -static int isLineSeparator(const unsigned char* p) -{ - // Linux - if( p[0]=='\n') - return 1; - - // Mac & Dos - if( p[0]=='\r') - return (p[1]=='\n') ? 2 : 1; - - // Unicode (line || paragraph sep.) - if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9)) - return 3; - - // Next - if( p[0]==0xC2 && p[1]==0x85) - return 2; - - return 0; -} - - + +// Copyright (c) 1999-2009 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. + + +/* HTML parser + */ + +#include +#include +#include +#include +#include +#include + +#include "mars.h" +#include "html.h" + +#include +#include "root.h" + +extern int HtmlNamedEntity(unsigned char *p, int length); + +static int isLineSeparator(const unsigned char* p); + +/********************************** + * Determine if beginning of tag identifier + * or a continuation of a tag identifier. + */ + +inline int istagstart(int c) +{ + return (isalpha(c) || c == '_'); +} + +inline int istag(int c) +{ + return (isalnum(c) || c == '_'); +} + +/********************************************** + */ + +Html::Html(const char *sourcename, unsigned char *base, unsigned length) +{ + //printf("Html::Html()\n"); + this->sourcename = sourcename; + this->base = base; + p = base; + end = base + length; + linnum = 1; + dbuf = NULL; + inCode = 0; +} + +/********************************************** + * Print error & quit. + */ + +void Html::error(const char *format, ...) +{ + if (!global.gag) + { + printf("%s(%d) : HTML Error: ", sourcename, linnum); + + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + + printf("\n"); + fflush(stdout); + } + + global.errors++; +} + +/********************************************** + * Extract all the code from an HTML file, + * concatenate it all together, and store in buf. + */ + +void Html::extractCode(OutBuffer *buf) +{ + //printf("Html::extractCode()\n"); + dbuf = buf; // save for other routines + buf->reserve(end - p); + inCode = 0; + while (1) + { + //printf("p = %p, *p = x%x\n", p, *p); + switch (*p) + { +#if 0 // strings are not recognized outside of tags + case '"': + case '\'': + skipString(); + continue; +#endif + case '<': + if (p[1] == '!' && isCommentStart()) + { // Comments start with + * Netscape: comments nest + * w3c: whitespace can appear between -- and > of comment close + */ + +void Html::scanComment() +{ + // Most of the complexity is dealing with the case that + // an arbitrary amount of whitespace can appear between + // the -- and the > of a comment close. + int scangt = 0; + + //printf("scanComment()\n"); + if (*p == '\n') + { linnum++; + // Always extract new lines, so that D lexer counts the + // lines right. + dbuf->writeByte(*p); + } + while (1) + { + //scangt = 1; // IE 5.0 compatibility + p++; + switch (*p) + { + case '-': + if (p[1] == '-') + { + if (p[2] == '>') // optimize for most common case + { + p += 3; + break; + } + p++; + scangt = 1; + } + else + scangt = 0; + continue; + + case '>': + if (scangt) + { // found --> + p++; + break; + } + continue; + + case ' ': + case '\t': + case '\f': + case '\v': + // skip white space + continue; + + case '\r': + if (p[1] == '\n') + goto Ldefault; + case '\n': + linnum++; // remember to count lines + // Always extract new lines, so that D lexer counts the + // lines right. + dbuf->writeByte(*p); + continue; + + case 0: + case 0x1a: + error("end of file before closing --> of comment"); + break; + + default: + Ldefault: + scangt = 0; // it's not --> + continue; + } + break; + } + //printf("*p = '%c'\n", *p); +} + +/******************************************** + * Determine if we are at the start of a comment. + * Input: + * p is on the opening '<' + * Returns: + * 0 if not start of a comment + * 1 if start of a comment, p is adjusted to point past -- + */ + +int Html::isCommentStart() +#ifdef __DMC__ + __out(result) + { + if (result == 0) + ; + else if (result == 1) + { + assert(p[-2] == '-' && p[-1] == '-'); + } + else + assert(0); + } + __body +#endif /* __DMC__ */ + { unsigned char *s; + + if (p[0] == '<' && p[1] == '!') + { + for (s = p + 2; 1; s++) + { + switch (*s) + { + case ' ': + case '\t': + case '\r': + case '\f': + case '\v': + // skip white space, even though spec says no + // white space is allowed + continue; + + case '-': + if (s[1] == '-') + { + p = s + 2; + return 1; + } + goto No; + + default: + goto No; + } + } + } + No: + return 0; + } + +int Html::isCDATAStart() +{ + const char * CDATA_START_MARKER = "0) + { + /* Always extract new lines, so that D lexer counts the lines + * right. + */ + linnum++; + dbuf->writeUTF8('\n'); + p += lineSepLength; + continue; + } + else if (p[0] == ']' && p[1] == ']' && p[2] == '>') + { + /* end of CDATA section */ + p += 3; + return; + } + else if (inCode) + { + /* this CDATA section contains D code */ + dbuf->writeByte(*p); + } + + p++; + } +} + + +/******************************************** + * Convert an HTML character entity into a character. + * Forms are: + * &name; named entity + * &#ddd; decimal + * &#xhhhh; hex + * Input: + * p is on the & + */ + +int Html::charEntity() +{ int c = 0; + int v; + int hex; + unsigned char *pstart = p; + + //printf("Html::charEntity('%c')\n", *p); + if (p[1] == '#') + { + p++; + if (p[1] == 'x' || p[1] == 'X') + { p++; + hex = 1; + } + else + hex = 0; + if (p[1] == ';') + goto Linvalid; + while (1) + { + p++; + switch (*p) + { + case 0: + case 0x1a: + error("end of file before end of character entity"); + goto Lignore; + + case '\n': + case '\r': + case '<': // tag start + // Termination is assumed + break; + + case ';': + // Termination is explicit + p++; + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + v = *p - '0'; + goto Lvalue; + + case 'a': case 'b': case 'c': + case 'd': case 'e': case 'f': + if (!hex) + goto Linvalid; + v = (*p - 'a') + 10; + goto Lvalue; + + case 'A': case 'B': case 'C': + case 'D': case 'E': case 'F': + if (!hex) + goto Linvalid; + v = (*p - 'A') + 10; + goto Lvalue; + + Lvalue: + if (hex) + c = (c << 4) + v; + else + c = (c * 10) + v; + if (c > 0x10FFFF) + { + error("character entity out of range"); + goto Lignore; + } + continue; + + default: + Linvalid: + error("invalid numeric character reference"); + goto Lignore; + } + break; + } + } + else + { + // It's a named entity; gather all characters until ; + unsigned char *idstart = p + 1; + + while (1) + { + p++; + switch (*p) + { + case 0: + case 0x1a: + error("end of file before end of character entity"); + break; + + case '\n': + case '\r': + case '<': // tag start + // Termination is assumed + c = HtmlNamedEntity(idstart, p - idstart); + if (c == -1) + goto Lignore; + break; + + case ';': + // Termination is explicit + c = HtmlNamedEntity(idstart, p - idstart); + if (c == -1) + goto Lignore; + p++; + break; + + default: + continue; + } + break; + } + } + + // Kludge to convert non-breaking space to ascii space + if (c == 160) + c = ' '; + + return c; + +Lignore: + //printf("Lignore\n"); + p = pstart + 1; + return '&'; +} + +/** + * identify DOS, Linux, Mac, Next and Unicode line endings + * 0 if this is no line separator + * >0 the length of the separator + * Note: input has to be UTF-8 + */ +static int isLineSeparator(const unsigned char* p) +{ + // Linux + if( p[0]=='\n') + return 1; + + // Mac & Dos + if( p[0]=='\r') + return (p[1]=='\n') ? 2 : 1; + + // Unicode (line || paragraph sep.) + if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9)) + return 3; + + // Next + if( p[0]==0xC2 && p[1]==0x85) + return 2; + + return 0; +} + + diff --git a/dmd2/html.h b/dmd2/html.h index 9dbdc8b5..feceab38 100644 --- a/dmd2/html.h +++ b/dmd2/html.h @@ -1,42 +1,42 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -#ifndef DMD_HTML_H -#define DMD_HTML_H 1 - -struct OutBuffer; - -struct Html -{ - const char *sourcename; - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - unsigned linnum; // current line number - OutBuffer *dbuf; // code source buffer - int inCode; // !=0 if in code - - - Html(const char *sourcename, unsigned char *base, unsigned length); - - void error(const char *format, ...) IS_PRINTF(2); - void extractCode(OutBuffer *buf); - void skipTag(); - void skipString(); - unsigned char *skipWhite(unsigned char *q); - void scanComment(); - int isCommentStart(); - void scanCDATA(); - int isCDATAStart(); - int charEntity(); - static int namedEntity(unsigned char *p, int length); -}; - -#endif + +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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. + +#ifndef DMD_HTML_H +#define DMD_HTML_H 1 + +struct OutBuffer; + +struct Html +{ + const char *sourcename; + + unsigned char *base; // pointer to start of buffer + unsigned char *end; // past end of buffer + unsigned char *p; // current character + unsigned linnum; // current line number + OutBuffer *dbuf; // code source buffer + int inCode; // !=0 if in code + + + Html(const char *sourcename, unsigned char *base, unsigned length); + + void error(const char *format, ...) IS_PRINTF(2); + void extractCode(OutBuffer *buf); + void skipTag(); + void skipString(); + unsigned char *skipWhite(unsigned char *q); + void scanComment(); + int isCommentStart(); + void scanCDATA(); + int isCDATAStart(); + int charEntity(); + static int namedEntity(unsigned char *p, int length); +}; + +#endif diff --git a/dmd2/id.c b/dmd2/id.c deleted file mode 100644 index 838a732d..00000000 --- a/dmd2/id.c +++ /dev/null @@ -1,473 +0,0 @@ -// File generated by idgen.c -#include "id.h" -#include "identifier.h" -#include "lexer.h" -Identifier *Id::IUnknown; -Identifier *Id::Object; -Identifier *Id::object; -Identifier *Id::max; -Identifier *Id::min; -Identifier *Id::This; -Identifier *Id::ctor; -Identifier *Id::dtor; -Identifier *Id::cpctor; -Identifier *Id::_postblit; -Identifier *Id::classInvariant; -Identifier *Id::unitTest; -Identifier *Id::init; -Identifier *Id::size; -Identifier *Id::__sizeof; -Identifier *Id::alignof; -Identifier *Id::mangleof; -Identifier *Id::stringof; -Identifier *Id::tupleof; -Identifier *Id::length; -Identifier *Id::remove; -Identifier *Id::ptr; -Identifier *Id::funcptr; -Identifier *Id::dollar; -Identifier *Id::offset; -Identifier *Id::offsetof; -Identifier *Id::ModuleInfo; -Identifier *Id::ClassInfo; -Identifier *Id::classinfo; -Identifier *Id::typeinfo; -Identifier *Id::outer; -Identifier *Id::Exception; -Identifier *Id::Throwable; -Identifier *Id::withSym; -Identifier *Id::result; -Identifier *Id::returnLabel; -Identifier *Id::delegate; -Identifier *Id::line; -Identifier *Id::empty; -Identifier *Id::p; -Identifier *Id::coverage; -Identifier *Id::__vptr; -Identifier *Id::__monitor; -Identifier *Id::system; -Identifier *Id::TypeInfo; -Identifier *Id::TypeInfo_Class; -Identifier *Id::TypeInfo_Interface; -Identifier *Id::TypeInfo_Struct; -Identifier *Id::TypeInfo_Enum; -Identifier *Id::TypeInfo_Typedef; -Identifier *Id::TypeInfo_Pointer; -Identifier *Id::TypeInfo_Array; -Identifier *Id::TypeInfo_StaticArray; -Identifier *Id::TypeInfo_AssociativeArray; -Identifier *Id::TypeInfo_Function; -Identifier *Id::TypeInfo_Delegate; -Identifier *Id::TypeInfo_Tuple; -Identifier *Id::TypeInfo_Const; -Identifier *Id::TypeInfo_Invariant; -Identifier *Id::TypeInfo_Shared; -Identifier *Id::elements; -Identifier *Id::_arguments_typeinfo; -Identifier *Id::_arguments; -Identifier *Id::_argptr; -Identifier *Id::_match; -Identifier *Id::destroy; -Identifier *Id::postblit; -Identifier *Id::LINE; -Identifier *Id::FILE; -Identifier *Id::DATE; -Identifier *Id::TIME; -Identifier *Id::TIMESTAMP; -Identifier *Id::VENDOR; -Identifier *Id::VERSIONX; -Identifier *Id::EOFX; -Identifier *Id::nan; -Identifier *Id::infinity; -Identifier *Id::dig; -Identifier *Id::epsilon; -Identifier *Id::mant_dig; -Identifier *Id::max_10_exp; -Identifier *Id::max_exp; -Identifier *Id::min_10_exp; -Identifier *Id::min_exp; -Identifier *Id::re; -Identifier *Id::im; -Identifier *Id::C; -Identifier *Id::D; -Identifier *Id::Windows; -Identifier *Id::Pascal; -Identifier *Id::System; -Identifier *Id::exit; -Identifier *Id::success; -Identifier *Id::failure; -Identifier *Id::keys; -Identifier *Id::values; -Identifier *Id::rehash; -Identifier *Id::sort; -Identifier *Id::reverse; -Identifier *Id::dup; -Identifier *Id::idup; -Identifier *Id::property; -Identifier *Id::___out; -Identifier *Id::___in; -Identifier *Id::__int; -Identifier *Id::__dollar; -Identifier *Id::__LOCAL_SIZE; -Identifier *Id::uadd; -Identifier *Id::neg; -Identifier *Id::com; -Identifier *Id::add; -Identifier *Id::add_r; -Identifier *Id::sub; -Identifier *Id::sub_r; -Identifier *Id::mul; -Identifier *Id::mul_r; -Identifier *Id::div; -Identifier *Id::div_r; -Identifier *Id::mod; -Identifier *Id::mod_r; -Identifier *Id::eq; -Identifier *Id::cmp; -Identifier *Id::iand; -Identifier *Id::iand_r; -Identifier *Id::ior; -Identifier *Id::ior_r; -Identifier *Id::ixor; -Identifier *Id::ixor_r; -Identifier *Id::shl; -Identifier *Id::shl_r; -Identifier *Id::shr; -Identifier *Id::shr_r; -Identifier *Id::ushr; -Identifier *Id::ushr_r; -Identifier *Id::cat; -Identifier *Id::cat_r; -Identifier *Id::assign; -Identifier *Id::addass; -Identifier *Id::subass; -Identifier *Id::mulass; -Identifier *Id::divass; -Identifier *Id::modass; -Identifier *Id::andass; -Identifier *Id::orass; -Identifier *Id::xorass; -Identifier *Id::shlass; -Identifier *Id::shrass; -Identifier *Id::ushrass; -Identifier *Id::catass; -Identifier *Id::postinc; -Identifier *Id::postdec; -Identifier *Id::index; -Identifier *Id::indexass; -Identifier *Id::slice; -Identifier *Id::sliceass; -Identifier *Id::call; -Identifier *Id::cast; -Identifier *Id::match; -Identifier *Id::next; -Identifier *Id::opIn; -Identifier *Id::opIn_r; -Identifier *Id::opStar; -Identifier *Id::opDot; -Identifier *Id::opImplicitCast; -Identifier *Id::classNew; -Identifier *Id::classDelete; -Identifier *Id::apply; -Identifier *Id::applyReverse; -Identifier *Id::Fempty; -Identifier *Id::Fhead; -Identifier *Id::Ftoe; -Identifier *Id::Fnext; -Identifier *Id::Fretreat; -Identifier *Id::adDup; -Identifier *Id::adReverse; -Identifier *Id::aaLen; -Identifier *Id::aaKeys; -Identifier *Id::aaValues; -Identifier *Id::aaRehash; -Identifier *Id::monitorenter; -Identifier *Id::monitorexit; -Identifier *Id::criticalenter; -Identifier *Id::criticalexit; -Identifier *Id::GNU_asm; -Identifier *Id::lib; -Identifier *Id::msg; -Identifier *Id::startaddress; -Identifier *Id::intrinsic; -Identifier *Id::va_intrinsic; -Identifier *Id::no_typeinfo; -Identifier *Id::no_moduleinfo; -Identifier *Id::Alloca; -Identifier *Id::vastart; -Identifier *Id::vacopy; -Identifier *Id::vaend; -Identifier *Id::vaarg; -Identifier *Id::ldc; -Identifier *Id::allow_inline; -Identifier *Id::llvm_inline_asm; -Identifier *Id::tohash; -Identifier *Id::tostring; -Identifier *Id::getmembers; -Identifier *Id::main; -Identifier *Id::WinMain; -Identifier *Id::DllMain; -Identifier *Id::tls_get_addr; -Identifier *Id::std; -Identifier *Id::math; -Identifier *Id::sin; -Identifier *Id::cos; -Identifier *Id::tan; -Identifier *Id::_sqrt; -Identifier *Id::fabs; -Identifier *Id::isAbstractClass; -Identifier *Id::isArithmetic; -Identifier *Id::isAssociativeArray; -Identifier *Id::isFinalClass; -Identifier *Id::isFloating; -Identifier *Id::isIntegral; -Identifier *Id::isScalar; -Identifier *Id::isStaticArray; -Identifier *Id::isUnsigned; -Identifier *Id::isVirtualFunction; -Identifier *Id::isAbstractFunction; -Identifier *Id::isFinalFunction; -Identifier *Id::hasMember; -Identifier *Id::getMember; -Identifier *Id::getVirtualFunctions; -Identifier *Id::classInstanceSize; -Identifier *Id::allMembers; -Identifier *Id::derivedMembers; -Identifier *Id::isSame; -Identifier *Id::compiles; -void Id::initialize() -{ - IUnknown = Lexer::idPool("IUnknown"); - Object = Lexer::idPool("Object"); - object = Lexer::idPool("object"); - max = Lexer::idPool("max"); - min = Lexer::idPool("min"); - This = Lexer::idPool("this"); - ctor = Lexer::idPool("__ctor"); - dtor = Lexer::idPool("__dtor"); - cpctor = Lexer::idPool("__cpctor"); - _postblit = Lexer::idPool("__postblit"); - classInvariant = Lexer::idPool("__invariant"); - unitTest = Lexer::idPool("__unitTest"); - init = Lexer::idPool("init"); - size = Lexer::idPool("size"); - __sizeof = Lexer::idPool("sizeof"); - alignof = Lexer::idPool("alignof"); - mangleof = Lexer::idPool("mangleof"); - stringof = Lexer::idPool("stringof"); - tupleof = Lexer::idPool("tupleof"); - length = Lexer::idPool("length"); - remove = Lexer::idPool("remove"); - ptr = Lexer::idPool("ptr"); - funcptr = Lexer::idPool("funcptr"); - dollar = Lexer::idPool("__dollar"); - offset = Lexer::idPool("offset"); - offsetof = Lexer::idPool("offsetof"); - ModuleInfo = Lexer::idPool("ModuleInfo"); - ClassInfo = Lexer::idPool("ClassInfo"); - classinfo = Lexer::idPool("classinfo"); - typeinfo = Lexer::idPool("typeinfo"); - outer = Lexer::idPool("outer"); - Exception = Lexer::idPool("Exception"); - Throwable = Lexer::idPool("Throwable"); - withSym = Lexer::idPool("__withSym"); - result = Lexer::idPool("__result"); - returnLabel = Lexer::idPool("__returnLabel"); - delegate = Lexer::idPool("delegate"); - line = Lexer::idPool("line"); - empty = Lexer::idPool(""); - p = Lexer::idPool("p"); - coverage = Lexer::idPool("__coverage"); - __vptr = Lexer::idPool("__vptr"); - __monitor = Lexer::idPool("__monitor"); - system = Lexer::idPool("system"); - TypeInfo = Lexer::idPool("TypeInfo"); - TypeInfo_Class = Lexer::idPool("TypeInfo_Class"); - TypeInfo_Interface = Lexer::idPool("TypeInfo_Interface"); - TypeInfo_Struct = Lexer::idPool("TypeInfo_Struct"); - TypeInfo_Enum = Lexer::idPool("TypeInfo_Enum"); - TypeInfo_Typedef = Lexer::idPool("TypeInfo_Typedef"); - TypeInfo_Pointer = Lexer::idPool("TypeInfo_Pointer"); - TypeInfo_Array = Lexer::idPool("TypeInfo_Array"); - TypeInfo_StaticArray = Lexer::idPool("TypeInfo_StaticArray"); - TypeInfo_AssociativeArray = Lexer::idPool("TypeInfo_AssociativeArray"); - TypeInfo_Function = Lexer::idPool("TypeInfo_Function"); - TypeInfo_Delegate = Lexer::idPool("TypeInfo_Delegate"); - TypeInfo_Tuple = Lexer::idPool("TypeInfo_Tuple"); - TypeInfo_Const = Lexer::idPool("TypeInfo_Const"); - TypeInfo_Invariant = Lexer::idPool("TypeInfo_Invariant"); - TypeInfo_Shared = Lexer::idPool("TypeInfo_Shared"); - elements = Lexer::idPool("elements"); - _arguments_typeinfo = Lexer::idPool("_arguments_typeinfo"); - _arguments = Lexer::idPool("_arguments"); - _argptr = Lexer::idPool("_argptr"); - _match = Lexer::idPool("_match"); - destroy = Lexer::idPool("destroy"); - postblit = Lexer::idPool("postblit"); - LINE = Lexer::idPool("__LINE__"); - FILE = Lexer::idPool("__FILE__"); - DATE = Lexer::idPool("__DATE__"); - TIME = Lexer::idPool("__TIME__"); - TIMESTAMP = Lexer::idPool("__TIMESTAMP__"); - VENDOR = Lexer::idPool("__VENDOR__"); - VERSIONX = Lexer::idPool("__VERSION__"); - EOFX = Lexer::idPool("__EOF__"); - nan = Lexer::idPool("nan"); - infinity = Lexer::idPool("infinity"); - dig = Lexer::idPool("dig"); - epsilon = Lexer::idPool("epsilon"); - mant_dig = Lexer::idPool("mant_dig"); - max_10_exp = Lexer::idPool("max_10_exp"); - max_exp = Lexer::idPool("max_exp"); - min_10_exp = Lexer::idPool("min_10_exp"); - min_exp = Lexer::idPool("min_exp"); - re = Lexer::idPool("re"); - im = Lexer::idPool("im"); - C = Lexer::idPool("C"); - D = Lexer::idPool("D"); - Windows = Lexer::idPool("Windows"); - Pascal = Lexer::idPool("Pascal"); - System = Lexer::idPool("System"); - exit = Lexer::idPool("exit"); - success = Lexer::idPool("success"); - failure = Lexer::idPool("failure"); - keys = Lexer::idPool("keys"); - values = Lexer::idPool("values"); - rehash = Lexer::idPool("rehash"); - sort = Lexer::idPool("sort"); - reverse = Lexer::idPool("reverse"); - dup = Lexer::idPool("dup"); - idup = Lexer::idPool("idup"); - property = Lexer::idPool("property"); - ___out = Lexer::idPool("out"); - ___in = Lexer::idPool("in"); - __int = Lexer::idPool("int"); - __dollar = Lexer::idPool("$"); - __LOCAL_SIZE = Lexer::idPool("__LOCAL_SIZE"); - uadd = Lexer::idPool("opPos"); - neg = Lexer::idPool("opNeg"); - com = Lexer::idPool("opCom"); - add = Lexer::idPool("opAdd"); - add_r = Lexer::idPool("opAdd_r"); - sub = Lexer::idPool("opSub"); - sub_r = Lexer::idPool("opSub_r"); - mul = Lexer::idPool("opMul"); - mul_r = Lexer::idPool("opMul_r"); - div = Lexer::idPool("opDiv"); - div_r = Lexer::idPool("opDiv_r"); - mod = Lexer::idPool("opMod"); - mod_r = Lexer::idPool("opMod_r"); - eq = Lexer::idPool("opEquals"); - cmp = Lexer::idPool("opCmp"); - iand = Lexer::idPool("opAnd"); - iand_r = Lexer::idPool("opAnd_r"); - ior = Lexer::idPool("opOr"); - ior_r = Lexer::idPool("opOr_r"); - ixor = Lexer::idPool("opXor"); - ixor_r = Lexer::idPool("opXor_r"); - shl = Lexer::idPool("opShl"); - shl_r = Lexer::idPool("opShl_r"); - shr = Lexer::idPool("opShr"); - shr_r = Lexer::idPool("opShr_r"); - ushr = Lexer::idPool("opUShr"); - ushr_r = Lexer::idPool("opUShr_r"); - cat = Lexer::idPool("opCat"); - cat_r = Lexer::idPool("opCat_r"); - assign = Lexer::idPool("opAssign"); - addass = Lexer::idPool("opAddAssign"); - subass = Lexer::idPool("opSubAssign"); - mulass = Lexer::idPool("opMulAssign"); - divass = Lexer::idPool("opDivAssign"); - modass = Lexer::idPool("opModAssign"); - andass = Lexer::idPool("opAndAssign"); - orass = Lexer::idPool("opOrAssign"); - xorass = Lexer::idPool("opXorAssign"); - shlass = Lexer::idPool("opShlAssign"); - shrass = Lexer::idPool("opShrAssign"); - ushrass = Lexer::idPool("opUShrAssign"); - catass = Lexer::idPool("opCatAssign"); - postinc = Lexer::idPool("opPostInc"); - postdec = Lexer::idPool("opPostDec"); - index = Lexer::idPool("opIndex"); - indexass = Lexer::idPool("opIndexAssign"); - slice = Lexer::idPool("opSlice"); - sliceass = Lexer::idPool("opSliceAssign"); - call = Lexer::idPool("opCall"); - cast = Lexer::idPool("opCast"); - match = Lexer::idPool("opMatch"); - next = Lexer::idPool("opNext"); - opIn = Lexer::idPool("opIn"); - opIn_r = Lexer::idPool("opIn_r"); - opStar = Lexer::idPool("opStar"); - opDot = Lexer::idPool("opDot"); - opImplicitCast = Lexer::idPool("opImplicitCast"); - classNew = Lexer::idPool("new"); - classDelete = Lexer::idPool("delete"); - apply = Lexer::idPool("opApply"); - applyReverse = Lexer::idPool("opApplyReverse"); - Fempty = Lexer::idPool("empty"); - Fhead = Lexer::idPool("front"); - Ftoe = Lexer::idPool("back"); - Fnext = Lexer::idPool("popFront"); - Fretreat = Lexer::idPool("popBack"); - adDup = Lexer::idPool("_adDupT"); - adReverse = Lexer::idPool("_adReverse"); - aaLen = Lexer::idPool("_aaLen"); - aaKeys = Lexer::idPool("_aaKeys"); - aaValues = Lexer::idPool("_aaValues"); - aaRehash = Lexer::idPool("_aaRehash"); - monitorenter = Lexer::idPool("_d_monitorenter"); - monitorexit = Lexer::idPool("_d_monitorexit"); - criticalenter = Lexer::idPool("_d_criticalenter"); - criticalexit = Lexer::idPool("_d_criticalexit"); - GNU_asm = Lexer::idPool("GNU_asm"); - lib = Lexer::idPool("lib"); - msg = Lexer::idPool("msg"); - startaddress = Lexer::idPool("startaddress"); - intrinsic = Lexer::idPool("intrinsic"); - va_intrinsic = Lexer::idPool("va_intrinsic"); - no_typeinfo = Lexer::idPool("no_typeinfo"); - no_moduleinfo = Lexer::idPool("no_moduleinfo"); - Alloca = Lexer::idPool("alloca"); - vastart = Lexer::idPool("va_start"); - vacopy = Lexer::idPool("va_copy"); - vaend = Lexer::idPool("va_end"); - vaarg = Lexer::idPool("va_arg"); - ldc = Lexer::idPool("ldc"); - allow_inline = Lexer::idPool("allow_inline"); - llvm_inline_asm = Lexer::idPool("llvm_inline_asm"); - tohash = Lexer::idPool("toHash"); - tostring = Lexer::idPool("toString"); - getmembers = Lexer::idPool("getMembers"); - main = Lexer::idPool("main"); - WinMain = Lexer::idPool("WinMain"); - DllMain = Lexer::idPool("DllMain"); - tls_get_addr = Lexer::idPool("___tls_get_addr"); - std = Lexer::idPool("std"); - math = Lexer::idPool("math"); - sin = Lexer::idPool("sin"); - cos = Lexer::idPool("cos"); - tan = Lexer::idPool("tan"); - _sqrt = Lexer::idPool("sqrt"); - fabs = Lexer::idPool("fabs"); - isAbstractClass = Lexer::idPool("isAbstractClass"); - isArithmetic = Lexer::idPool("isArithmetic"); - isAssociativeArray = Lexer::idPool("isAssociativeArray"); - isFinalClass = Lexer::idPool("isFinalClass"); - isFloating = Lexer::idPool("isFloating"); - isIntegral = Lexer::idPool("isIntegral"); - isScalar = Lexer::idPool("isScalar"); - isStaticArray = Lexer::idPool("isStaticArray"); - isUnsigned = Lexer::idPool("isUnsigned"); - isVirtualFunction = Lexer::idPool("isVirtualFunction"); - isAbstractFunction = Lexer::idPool("isAbstractFunction"); - isFinalFunction = Lexer::idPool("isFinalFunction"); - hasMember = Lexer::idPool("hasMember"); - getMember = Lexer::idPool("getMember"); - getVirtualFunctions = Lexer::idPool("getVirtualFunctions"); - classInstanceSize = Lexer::idPool("classInstanceSize"); - allMembers = Lexer::idPool("allMembers"); - derivedMembers = Lexer::idPool("derivedMembers"); - isSame = Lexer::idPool("isSame"); - compiles = Lexer::idPool("compiles"); -} diff --git a/dmd2/id.h b/dmd2/id.h deleted file mode 100644 index 6556f412..00000000 --- a/dmd2/id.h +++ /dev/null @@ -1,242 +0,0 @@ -// File generated by idgen.c -#ifndef DMD_ID_H -#define DMD_ID_H 1 -struct Identifier; -struct Id -{ - static Identifier *IUnknown; - static Identifier *Object; - static Identifier *object; - static Identifier *max; - static Identifier *min; - static Identifier *This; - static Identifier *ctor; - static Identifier *dtor; - static Identifier *cpctor; - static Identifier *_postblit; - static Identifier *classInvariant; - static Identifier *unitTest; - static Identifier *init; - static Identifier *size; - static Identifier *__sizeof; - static Identifier *alignof; - static Identifier *mangleof; - static Identifier *stringof; - static Identifier *tupleof; - static Identifier *length; - static Identifier *remove; - static Identifier *ptr; - static Identifier *funcptr; - static Identifier *dollar; - static Identifier *offset; - static Identifier *offsetof; - static Identifier *ModuleInfo; - static Identifier *ClassInfo; - static Identifier *classinfo; - static Identifier *typeinfo; - static Identifier *outer; - static Identifier *Exception; - static Identifier *Throwable; - static Identifier *withSym; - static Identifier *result; - static Identifier *returnLabel; - static Identifier *delegate; - static Identifier *line; - static Identifier *empty; - static Identifier *p; - static Identifier *coverage; - static Identifier *__vptr; - static Identifier *__monitor; - static Identifier *system; - static Identifier *TypeInfo; - static Identifier *TypeInfo_Class; - static Identifier *TypeInfo_Interface; - static Identifier *TypeInfo_Struct; - static Identifier *TypeInfo_Enum; - static Identifier *TypeInfo_Typedef; - static Identifier *TypeInfo_Pointer; - static Identifier *TypeInfo_Array; - static Identifier *TypeInfo_StaticArray; - static Identifier *TypeInfo_AssociativeArray; - static Identifier *TypeInfo_Function; - static Identifier *TypeInfo_Delegate; - static Identifier *TypeInfo_Tuple; - static Identifier *TypeInfo_Const; - static Identifier *TypeInfo_Invariant; - static Identifier *TypeInfo_Shared; - static Identifier *elements; - static Identifier *_arguments_typeinfo; - static Identifier *_arguments; - static Identifier *_argptr; - static Identifier *_match; - static Identifier *destroy; - static Identifier *postblit; - static Identifier *LINE; - static Identifier *FILE; - static Identifier *DATE; - static Identifier *TIME; - static Identifier *TIMESTAMP; - static Identifier *VENDOR; - static Identifier *VERSIONX; - static Identifier *EOFX; - static Identifier *nan; - static Identifier *infinity; - static Identifier *dig; - static Identifier *epsilon; - static Identifier *mant_dig; - static Identifier *max_10_exp; - static Identifier *max_exp; - static Identifier *min_10_exp; - static Identifier *min_exp; - static Identifier *re; - static Identifier *im; - static Identifier *C; - static Identifier *D; - static Identifier *Windows; - static Identifier *Pascal; - static Identifier *System; - static Identifier *exit; - static Identifier *success; - static Identifier *failure; - static Identifier *keys; - static Identifier *values; - static Identifier *rehash; - static Identifier *sort; - static Identifier *reverse; - static Identifier *dup; - static Identifier *idup; - static Identifier *property; - static Identifier *___out; - static Identifier *___in; - static Identifier *__int; - static Identifier *__dollar; - static Identifier *__LOCAL_SIZE; - static Identifier *uadd; - static Identifier *neg; - static Identifier *com; - static Identifier *add; - static Identifier *add_r; - static Identifier *sub; - static Identifier *sub_r; - static Identifier *mul; - static Identifier *mul_r; - static Identifier *div; - static Identifier *div_r; - static Identifier *mod; - static Identifier *mod_r; - static Identifier *eq; - static Identifier *cmp; - static Identifier *iand; - static Identifier *iand_r; - static Identifier *ior; - static Identifier *ior_r; - static Identifier *ixor; - static Identifier *ixor_r; - static Identifier *shl; - static Identifier *shl_r; - static Identifier *shr; - static Identifier *shr_r; - static Identifier *ushr; - static Identifier *ushr_r; - static Identifier *cat; - static Identifier *cat_r; - static Identifier *assign; - static Identifier *addass; - static Identifier *subass; - static Identifier *mulass; - static Identifier *divass; - static Identifier *modass; - static Identifier *andass; - static Identifier *orass; - static Identifier *xorass; - static Identifier *shlass; - static Identifier *shrass; - static Identifier *ushrass; - static Identifier *catass; - static Identifier *postinc; - static Identifier *postdec; - static Identifier *index; - static Identifier *indexass; - static Identifier *slice; - static Identifier *sliceass; - static Identifier *call; - static Identifier *cast; - static Identifier *match; - static Identifier *next; - static Identifier *opIn; - static Identifier *opIn_r; - static Identifier *opStar; - static Identifier *opDot; - static Identifier *opImplicitCast; - static Identifier *classNew; - static Identifier *classDelete; - static Identifier *apply; - static Identifier *applyReverse; - static Identifier *Fempty; - static Identifier *Fhead; - static Identifier *Ftoe; - static Identifier *Fnext; - static Identifier *Fretreat; - static Identifier *adDup; - static Identifier *adReverse; - static Identifier *aaLen; - static Identifier *aaKeys; - static Identifier *aaValues; - static Identifier *aaRehash; - static Identifier *monitorenter; - static Identifier *monitorexit; - static Identifier *criticalenter; - static Identifier *criticalexit; - static Identifier *GNU_asm; - static Identifier *lib; - static Identifier *msg; - static Identifier *startaddress; - static Identifier *intrinsic; - static Identifier *va_intrinsic; - static Identifier *no_typeinfo; - static Identifier *no_moduleinfo; - static Identifier *Alloca; - static Identifier *vastart; - static Identifier *vacopy; - static Identifier *vaend; - static Identifier *vaarg; - static Identifier *ldc; - static Identifier *allow_inline; - static Identifier *llvm_inline_asm; - static Identifier *tohash; - static Identifier *tostring; - static Identifier *getmembers; - static Identifier *main; - static Identifier *WinMain; - static Identifier *DllMain; - static Identifier *tls_get_addr; - static Identifier *std; - static Identifier *math; - static Identifier *sin; - static Identifier *cos; - static Identifier *tan; - static Identifier *_sqrt; - static Identifier *fabs; - static Identifier *isAbstractClass; - static Identifier *isArithmetic; - static Identifier *isAssociativeArray; - static Identifier *isFinalClass; - static Identifier *isFloating; - static Identifier *isIntegral; - static Identifier *isScalar; - static Identifier *isStaticArray; - static Identifier *isUnsigned; - static Identifier *isVirtualFunction; - static Identifier *isAbstractFunction; - static Identifier *isFinalFunction; - static Identifier *hasMember; - static Identifier *getMember; - static Identifier *getVirtualFunctions; - static Identifier *classInstanceSize; - static Identifier *allMembers; - static Identifier *derivedMembers; - static Identifier *isSame; - static Identifier *compiles; - static void initialize(); -}; -#endif diff --git a/dmd2/identifier.c b/dmd2/identifier.c index 87279e18..178ae12b 100644 --- a/dmd2/identifier.c +++ b/dmd2/identifier.c @@ -1,102 +1,102 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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 -#include - -#include "root.h" -#include "identifier.h" -#include "mars.h" -#include "lexer.h" -#include "id.h" - -Identifier::Identifier(const char *string, int value) -{ - //printf("Identifier('%s', %d)\n", string, value); - this->string = string; - this->value = value; - this->len = strlen(string); -} - -hash_t Identifier::hashCode() -{ - return String::calcHash(string); -} - -int Identifier::equals(Object *o) -{ - return this == o || memcmp(string,o->toChars(),len+1) == 0; -} - -int Identifier::compare(Object *o) -{ - return memcmp(string, o->toChars(), len + 1); -} - -char *Identifier::toChars() -{ - return (char *)string; -} - -const char *Identifier::toHChars2() -{ - const char *p = NULL; - - if (this == Id::ctor) p = "this"; - else if (this == Id::dtor) p = "~this"; - else if (this == Id::classInvariant) p = "invariant"; - else if (this == Id::unitTest) p = "unittest"; - else if (this == Id::dollar) p = "$"; - else if (this == Id::withSym) p = "with"; - else if (this == Id::result) p = "result"; - else if (this == Id::returnLabel) p = "return"; - else - { p = toChars(); - if (*p == '_') - { - if (memcmp(p, "_staticCtor", 11) == 0) - p = "static this"; - else if (memcmp(p, "_staticDtor", 11) == 0) - p = "static ~this"; - } - } - - return p; -} - -void Identifier::print() -{ - fprintf(stdmsg, "%s",string); -} - -int Identifier::dyncast() -{ - return DYNCAST_IDENTIFIER; -} - -// BUG: these are redundant with Lexer::uniqueId() - -Identifier *Identifier::generateId(const char *prefix) -{ - static size_t i; - - return generateId(prefix, ++i); -} - -Identifier *Identifier::generateId(const char *prefix, size_t i) -{ OutBuffer buf; - - buf.writestring(prefix); - buf.printf("%zu", i); - - char *id = buf.toChars(); - buf.data = NULL; - return Lexer::idPool(id); -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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 +#include + +#include "root.h" +#include "identifier.h" +#include "mars.h" +#include "lexer.h" +#include "id.h" + +Identifier::Identifier(const char *string, int value) +{ + //printf("Identifier('%s', %d)\n", string, value); + this->string = string; + this->value = value; + this->len = strlen(string); +} + +hash_t Identifier::hashCode() +{ + return String::calcHash(string); +} + +int Identifier::equals(Object *o) +{ + return this == o || memcmp(string,o->toChars(),len+1) == 0; +} + +int Identifier::compare(Object *o) +{ + return memcmp(string, o->toChars(), len + 1); +} + +char *Identifier::toChars() +{ + return (char *)string; +} + +const char *Identifier::toHChars2() +{ + const char *p = NULL; + + if (this == Id::ctor) p = "this"; + else if (this == Id::dtor) p = "~this"; + else if (this == Id::classInvariant) p = "invariant"; + else if (this == Id::unitTest) p = "unittest"; + else if (this == Id::dollar) p = "$"; + else if (this == Id::withSym) p = "with"; + else if (this == Id::result) p = "result"; + else if (this == Id::returnLabel) p = "return"; + else + { p = toChars(); + if (*p == '_') + { + if (memcmp(p, "_staticCtor", 11) == 0) + p = "static this"; + else if (memcmp(p, "_staticDtor", 11) == 0) + p = "static ~this"; + } + } + + return p; +} + +void Identifier::print() +{ + fprintf(stdmsg, "%s",string); +} + +int Identifier::dyncast() +{ + return DYNCAST_IDENTIFIER; +} + +// BUG: these are redundant with Lexer::uniqueId() + +Identifier *Identifier::generateId(const char *prefix) +{ + static size_t i; + + return generateId(prefix, ++i); +} + +Identifier *Identifier::generateId(const char *prefix, size_t i) +{ OutBuffer buf; + + buf.writestring(prefix); + buf.printf("%zu", i); + + char *id = buf.toChars(); + buf.data = NULL; + return Lexer::idPool(id); +} diff --git a/dmd2/idgen.c b/dmd2/idgen.c index da1d0674..1691da58 100644 --- a/dmd2/idgen.c +++ b/dmd2/idgen.c @@ -1,385 +1,412 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -// Program to generate string files in d data structures. -// Saves much tedious typing, and eliminates typo problems. -// Generates: -// id.h -// id.c - -#include -#include -#include -#include -#include - -struct Msgtable -{ - const char *ident; // name to use in DMD source - const char *name; // name in D executable -}; - -Msgtable msgtable[] = -{ - { "IUnknown" }, - { "Object" }, - { "object" }, - { "max" }, - { "min" }, - { "This", "this" }, - { "ctor", "__ctor" }, - { "dtor", "__dtor" }, - { "cpctor", "__cpctor" }, - { "_postblit", "__postblit" }, - { "classInvariant", "__invariant" }, - { "unitTest", "__unitTest" }, - { "init" }, - { "size" }, - { "__sizeof", "sizeof" }, - { "alignof" }, - { "mangleof" }, - { "stringof" }, - { "tupleof" }, - { "length" }, - { "remove" }, - { "ptr" }, - { "funcptr" }, - { "dollar", "__dollar" }, - { "offset" }, - { "offsetof" }, - { "ModuleInfo" }, - { "ClassInfo" }, - { "classinfo" }, - { "typeinfo" }, - { "outer" }, - { "Exception" }, - { "Throwable" }, - { "withSym", "__withSym" }, - { "result", "__result" }, - { "returnLabel", "__returnLabel" }, - { "delegate" }, - { "line" }, - { "empty", "" }, - { "p" }, - { "coverage", "__coverage" }, - { "__vptr" }, - { "__monitor" }, - { "system" }, - - { "TypeInfo" }, - { "TypeInfo_Class" }, - { "TypeInfo_Interface" }, - { "TypeInfo_Struct" }, - { "TypeInfo_Enum" }, - { "TypeInfo_Typedef" }, - { "TypeInfo_Pointer" }, - { "TypeInfo_Array" }, - { "TypeInfo_StaticArray" }, - { "TypeInfo_AssociativeArray" }, - { "TypeInfo_Function" }, - { "TypeInfo_Delegate" }, - { "TypeInfo_Tuple" }, - { "TypeInfo_Const" }, - { "TypeInfo_Invariant" }, - { "TypeInfo_Shared" }, - { "elements" }, - { "_arguments_typeinfo" }, - { "_arguments" }, - { "_argptr" }, - { "_match" }, - { "destroy" }, - { "postblit" }, - - { "LINE", "__LINE__" }, - { "FILE", "__FILE__" }, - { "DATE", "__DATE__" }, - { "TIME", "__TIME__" }, - { "TIMESTAMP", "__TIMESTAMP__" }, - { "VENDOR", "__VENDOR__" }, - { "VERSIONX", "__VERSION__" }, - { "EOFX", "__EOF__" }, - - { "nan" }, - { "infinity" }, - { "dig" }, - { "epsilon" }, - { "mant_dig" }, - { "max_10_exp" }, - { "max_exp" }, - { "min_10_exp" }, - { "min_exp" }, - { "re" }, - { "im" }, - - { "C" }, - { "D" }, - { "Windows" }, - { "Pascal" }, - { "System" }, - - { "exit" }, - { "success" }, - { "failure" }, - - { "keys" }, - { "values" }, - { "rehash" }, - - { "sort" }, - { "reverse" }, - { "dup" }, - { "idup" }, - - { "property" }, - - // For inline assembler - { "___out", "out" }, - { "___in", "in" }, - { "__int", "int" }, - { "__dollar", "$" }, - { "__LOCAL_SIZE" }, - - // For operator overloads - { "uadd", "opPos" }, - { "neg", "opNeg" }, - { "com", "opCom" }, - { "add", "opAdd" }, - { "add_r", "opAdd_r" }, - { "sub", "opSub" }, - { "sub_r", "opSub_r" }, - { "mul", "opMul" }, - { "mul_r", "opMul_r" }, - { "div", "opDiv" }, - { "div_r", "opDiv_r" }, - { "mod", "opMod" }, - { "mod_r", "opMod_r" }, - { "eq", "opEquals" }, - { "cmp", "opCmp" }, - { "iand", "opAnd" }, - { "iand_r", "opAnd_r" }, - { "ior", "opOr" }, - { "ior_r", "opOr_r" }, - { "ixor", "opXor" }, - { "ixor_r", "opXor_r" }, - { "shl", "opShl" }, - { "shl_r", "opShl_r" }, - { "shr", "opShr" }, - { "shr_r", "opShr_r" }, - { "ushr", "opUShr" }, - { "ushr_r", "opUShr_r" }, - { "cat", "opCat" }, - { "cat_r", "opCat_r" }, - { "assign", "opAssign" }, - { "addass", "opAddAssign" }, - { "subass", "opSubAssign" }, - { "mulass", "opMulAssign" }, - { "divass", "opDivAssign" }, - { "modass", "opModAssign" }, - { "andass", "opAndAssign" }, - { "orass", "opOrAssign" }, - { "xorass", "opXorAssign" }, - { "shlass", "opShlAssign" }, - { "shrass", "opShrAssign" }, - { "ushrass", "opUShrAssign" }, - { "catass", "opCatAssign" }, - { "postinc", "opPostInc" }, - { "postdec", "opPostDec" }, - { "index", "opIndex" }, - { "indexass", "opIndexAssign" }, - { "slice", "opSlice" }, - { "sliceass", "opSliceAssign" }, - { "call", "opCall" }, - { "cast", "opCast" }, - { "match", "opMatch" }, - { "next", "opNext" }, - { "opIn" }, - { "opIn_r" }, - { "opStar" }, - { "opDot" }, - { "opImplicitCast" }, - - { "classNew", "new" }, - { "classDelete", "delete" }, - - // For foreach - { "apply", "opApply" }, - { "applyReverse", "opApplyReverse" }, - -#if 1 - { "Fempty", "empty" }, - { "Fhead", "front" }, - { "Ftoe", "back" }, - { "Fnext", "popFront" }, - { "Fretreat", "popBack" }, -#else - { "Fempty", "empty" }, - { "Fhead", "head" }, - { "Ftoe", "toe" }, - { "Fnext", "next" }, - { "Fretreat", "retreat" }, -#endif - - { "adDup", "_adDupT" }, - { "adReverse", "_adReverse" }, - - // For internal functions - { "aaLen", "_aaLen" }, - { "aaKeys", "_aaKeys" }, - { "aaValues", "_aaValues" }, - { "aaRehash", "_aaRehash" }, - { "monitorenter", "_d_monitorenter" }, - { "monitorexit", "_d_monitorexit" }, - { "criticalenter", "_d_criticalenter" }, - { "criticalexit", "_d_criticalexit" }, - - // For pragma's - { "GNU_asm" }, - { "lib" }, - { "msg" }, - { "startaddress" }, - -#if IN_LLVM - // LDC pragma's - { "intrinsic" }, - { "va_intrinsic" }, - { "no_typeinfo" }, - { "no_moduleinfo" }, - { "Alloca", "alloca" }, - { "vastart", "va_start" }, - { "vacopy", "va_copy" }, - { "vaend", "va_end" }, - { "vaarg", "va_arg" }, - { "ldc" }, - { "allow_inline" }, - { "llvm_inline_asm" }, -#endif - - // For special functions - { "tohash", "toHash" }, - { "tostring", "toString" }, - { "getmembers", "getMembers" }, - - // Special functions -#if IN_DMD - { "alloca" }, -#endif - { "main" }, - { "WinMain" }, - { "DllMain" }, - { "tls_get_addr", "___tls_get_addr" }, - - // Builtin functions - { "std" }, - { "math" }, - { "sin" }, - { "cos" }, - { "tan" }, - { "_sqrt", "sqrt" }, - { "fabs" }, - - // Traits - { "isAbstractClass" }, - { "isArithmetic" }, - { "isAssociativeArray" }, - { "isFinalClass" }, - { "isFloating" }, - { "isIntegral" }, - { "isScalar" }, - { "isStaticArray" }, - { "isUnsigned" }, - { "isVirtualFunction" }, - { "isAbstractFunction" }, - { "isFinalFunction" }, - { "hasMember" }, - { "getMember" }, - { "getVirtualFunctions" }, - { "classInstanceSize" }, - { "allMembers" }, - { "derivedMembers" }, - { "isSame" }, - { "compiles" }, -}; - - -int main() -{ - FILE *fp; - unsigned i; - - { - fp = fopen("id.h","w"); - if (!fp) - { printf("can't open id.h\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); -#if __DMC__ - fprintf(fp, "#pragma once\n"); -#endif - fprintf(fp, "#ifndef DMD_ID_H\n"); - fprintf(fp, "#define DMD_ID_H 1\n"); - fprintf(fp, "struct Identifier;\n"); - fprintf(fp, "struct Id\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - - fprintf(fp," static Identifier *%s;\n", id); - } - - fprintf(fp, " static void initialize();\n"); - fprintf(fp, "};\n"); - fprintf(fp, "#endif\n"); - - fclose(fp); - } - - { - fp = fopen("id.c","w"); - if (!fp) - { printf("can't open id.c\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); - fprintf(fp, "#include \"id.h\"\n"); - fprintf(fp, "#include \"identifier.h\"\n"); - fprintf(fp, "#include \"lexer.h\"\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp,"Identifier *Id::%s;\n", id); - } - - fprintf(fp, "void Id::initialize()\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p); - } - - fprintf(fp, "}\n"); - - fclose(fp); - } - - return EXIT_SUCCESS; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +// Program to generate string files in d data structures. +// Saves much tedious typing, and eliminates typo problems. +// Generates: +// id.h +// id.c + +#include +#include +#include +#include + +struct Msgtable +{ + const char *ident; // name to use in DMD source + const char *name; // name in D executable +}; + +Msgtable msgtable[] = +{ + { "IUnknown" }, + { "Object" }, + { "object" }, + { "max" }, + { "min" }, + { "This", "this" }, + { "ctor", "__ctor" }, + { "dtor", "__dtor" }, + { "cpctor", "__cpctor" }, + { "_postblit", "__postblit" }, + { "classInvariant", "__invariant" }, + { "unitTest", "__unitTest" }, + { "require", "__require" }, + { "ensure", "__ensure" }, + { "init" }, + { "size" }, + { "__sizeof", "sizeof" }, + { "__xalignof", "alignof" }, + { "mangleof" }, + { "stringof" }, + { "tupleof" }, + { "length" }, + { "remove" }, + { "ptr" }, + { "funcptr" }, + { "dollar", "__dollar" }, + { "ctfe", "__ctfe" }, + { "offset" }, + { "offsetof" }, + { "ModuleInfo" }, + { "ClassInfo" }, + { "classinfo" }, + { "typeinfo" }, + { "outer" }, + { "Exception" }, + { "AssociativeArray" }, + { "Throwable" }, + { "withSym", "__withSym" }, + { "result", "__result" }, + { "returnLabel", "__returnLabel" }, + { "delegate" }, + { "line" }, + { "empty", "" }, + { "p" }, + { "coverage", "__coverage" }, + { "__vptr" }, + { "__monitor" }, + + { "TypeInfo" }, + { "TypeInfo_Class" }, + { "TypeInfo_Interface" }, + { "TypeInfo_Struct" }, + { "TypeInfo_Enum" }, + { "TypeInfo_Typedef" }, + { "TypeInfo_Pointer" }, + { "TypeInfo_Array" }, + { "TypeInfo_StaticArray" }, + { "TypeInfo_AssociativeArray" }, + { "TypeInfo_Function" }, + { "TypeInfo_Delegate" }, + { "TypeInfo_Tuple" }, + { "TypeInfo_Const" }, + { "TypeInfo_Invariant" }, + { "TypeInfo_Shared" }, + { "TypeInfo_Wild", "TypeInfo_Inout" }, + { "elements" }, + { "_arguments_typeinfo" }, + { "_arguments" }, + { "_argptr" }, + { "_match" }, + { "destroy" }, + { "postblit" }, + + { "LINE", "__LINE__" }, + { "FILE", "__FILE__" }, + { "DATE", "__DATE__" }, + { "TIME", "__TIME__" }, + { "TIMESTAMP", "__TIMESTAMP__" }, + { "VENDOR", "__VENDOR__" }, + { "VERSIONX", "__VERSION__" }, + { "EOFX", "__EOF__" }, + + { "nan" }, + { "infinity" }, + { "dig" }, + { "epsilon" }, + { "mant_dig" }, + { "max_10_exp" }, + { "max_exp" }, + { "min_10_exp" }, + { "min_exp" }, + { "min_normal" }, + { "re" }, + { "im" }, + + { "C" }, + { "D" }, + { "Windows" }, + { "Pascal" }, + { "System" }, + + { "exit" }, + { "success" }, + { "failure" }, + + { "keys" }, + { "values" }, + { "rehash" }, + + { "sort" }, + { "reverse" }, + { "dup" }, + { "idup" }, + + { "property" }, + { "safe" }, + { "trusted" }, + { "system" }, + { "disable" }, + + // For inline assembler + { "___out", "out" }, + { "___in", "in" }, + { "__int", "int" }, + { "__dollar", "$" }, + { "__LOCAL_SIZE" }, + + // For operator overloads + { "uadd", "opPos" }, + { "neg", "opNeg" }, + { "com", "opCom" }, + { "add", "opAdd" }, + { "add_r", "opAdd_r" }, + { "sub", "opSub" }, + { "sub_r", "opSub_r" }, + { "mul", "opMul" }, + { "mul_r", "opMul_r" }, + { "div", "opDiv" }, + { "div_r", "opDiv_r" }, + { "mod", "opMod" }, + { "mod_r", "opMod_r" }, + { "eq", "opEquals" }, + { "cmp", "opCmp" }, + { "iand", "opAnd" }, + { "iand_r", "opAnd_r" }, + { "ior", "opOr" }, + { "ior_r", "opOr_r" }, + { "ixor", "opXor" }, + { "ixor_r", "opXor_r" }, + { "shl", "opShl" }, + { "shl_r", "opShl_r" }, + { "shr", "opShr" }, + { "shr_r", "opShr_r" }, + { "ushr", "opUShr" }, + { "ushr_r", "opUShr_r" }, + { "cat", "opCat" }, + { "cat_r", "opCat_r" }, + { "assign", "opAssign" }, + { "addass", "opAddAssign" }, + { "subass", "opSubAssign" }, + { "mulass", "opMulAssign" }, + { "divass", "opDivAssign" }, + { "modass", "opModAssign" }, + { "andass", "opAndAssign" }, + { "orass", "opOrAssign" }, + { "xorass", "opXorAssign" }, + { "shlass", "opShlAssign" }, + { "shrass", "opShrAssign" }, + { "ushrass", "opUShrAssign" }, + { "catass", "opCatAssign" }, + { "postinc", "opPostInc" }, + { "postdec", "opPostDec" }, + { "index", "opIndex" }, + { "indexass", "opIndexAssign" }, + { "slice", "opSlice" }, + { "sliceass", "opSliceAssign" }, + { "call", "opCall" }, + { "cast", "opCast" }, + { "match", "opMatch" }, + { "next", "opNext" }, + { "opIn" }, + { "opIn_r" }, + { "opStar" }, + { "opDot" }, + { "opDispatch" }, + { "opUnary" }, + { "opIndexUnary" }, + { "opSliceUnary" }, + { "opBinary" }, + { "opBinaryRight" }, + { "opOpAssign" }, + { "opIndexOpAssign" }, + { "opSliceOpAssign" }, + { "pow", "opPow" }, + { "pow_r", "opPow_r" }, + { "powass", "opPowAssign" }, + + { "classNew", "new" }, + { "classDelete", "delete" }, + + // For foreach + { "apply", "opApply" }, + { "applyReverse", "opApplyReverse" }, + +#if 1 + { "Fempty", "empty" }, + { "Fhead", "front" }, + { "Ftoe", "back" }, + { "Fnext", "popFront" }, + { "Fretreat", "popBack" }, +#else + { "Fempty", "empty" }, + { "Fhead", "head" }, + { "Ftoe", "toe" }, + { "Fnext", "next" }, + { "Fretreat", "retreat" }, +#endif + + { "adDup", "_adDupT" }, + { "adReverse", "_adReverse" }, + + // For internal functions + { "aaLen", "_aaLen" }, + { "aaKeys", "_aaKeys" }, + { "aaValues", "_aaValues" }, + { "aaRehash", "_aaRehash" }, + { "monitorenter", "_d_monitorenter" }, + { "monitorexit", "_d_monitorexit" }, + { "criticalenter", "_d_criticalenter" }, + { "criticalexit", "_d_criticalexit" }, + { "_ArrayEq" }, + + // For pragma's + { "GNU_asm" }, + { "lib" }, + { "msg" }, + { "startaddress" }, + +#if IN_LLVM + // LDC pragma's + { "intrinsic" }, + { "va_intrinsic" }, + { "no_typeinfo" }, + { "no_moduleinfo" }, + { "Alloca", "alloca" }, + { "vastart", "va_start" }, + { "vacopy", "va_copy" }, + { "vaend", "va_end" }, + { "vaarg", "va_arg" }, + { "ldc" }, + { "allow_inline" }, + { "llvm_inline_asm" }, +#endif + + // For special functions + { "tohash", "toHash" }, + { "tostring", "toString" }, + { "getmembers", "getMembers" }, + + // Special functions +#if IN_DMD + { "alloca" }, +#endif + { "main" }, + { "WinMain" }, + { "DllMain" }, + { "tls_get_addr", "___tls_get_addr" }, + + // Builtin functions + { "std" }, + { "math" }, + { "sin" }, + { "cos" }, + { "tan" }, + { "_sqrt", "sqrt" }, + { "_pow", "pow" }, + { "fabs" }, + + // Traits + { "isAbstractClass" }, + { "isArithmetic" }, + { "isAssociativeArray" }, + { "isFinalClass" }, + { "isFloating" }, + { "isIntegral" }, + { "isScalar" }, + { "isStaticArray" }, + { "isUnsigned" }, + { "isVirtualFunction" }, + { "isAbstractFunction" }, + { "isFinalFunction" }, + { "isStaticFunction" }, + { "isRef" }, + { "isOut" }, + { "isLazy" }, + { "hasMember" }, + { "identifier" }, + { "getMember" }, + { "getOverloads" }, + { "getVirtualFunctions" }, + { "classInstanceSize" }, + { "allMembers" }, + { "derivedMembers" }, + { "isSame" }, + { "compiles" }, +}; + + +int main() +{ + FILE *fp; + unsigned i; + + { + fp = fopen("id.h","w"); + if (!fp) + { printf("can't open id.h\n"); + exit(EXIT_FAILURE); + } + + fprintf(fp, "// File generated by idgen.c\n"); +#if __DMC__ + fprintf(fp, "#pragma once\n"); +#endif + fprintf(fp, "#ifndef DMD_ID_H\n"); + fprintf(fp, "#define DMD_ID_H 1\n"); + fprintf(fp, "struct Identifier;\n"); + fprintf(fp, "struct Id\n"); + fprintf(fp, "{\n"); + + for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) + { const char *id = msgtable[i].ident; + + fprintf(fp," static Identifier *%s;\n", id); + } + + fprintf(fp, " static void initialize();\n"); + fprintf(fp, "};\n"); + fprintf(fp, "#endif\n"); + + fclose(fp); + } + + { + fp = fopen("id.c","w"); + if (!fp) + { printf("can't open id.c\n"); + exit(EXIT_FAILURE); + } + + fprintf(fp, "// File generated by idgen.c\n"); + fprintf(fp, "#include \"id.h\"\n"); + fprintf(fp, "#include \"identifier.h\"\n"); + fprintf(fp, "#include \"lexer.h\"\n"); + + for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) + { const char *id = msgtable[i].ident; + const char *p = msgtable[i].name; + + if (!p) + p = id; + fprintf(fp,"Identifier *Id::%s;\n", id); + } + + fprintf(fp, "void Id::initialize()\n"); + fprintf(fp, "{\n"); + + for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) + { const char *id = msgtable[i].ident; + const char *p = msgtable[i].name; + + if (!p) + p = id; + fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p); + } + + fprintf(fp, "}\n"); + + fclose(fp); + } + + return EXIT_SUCCESS; +} diff --git a/dmd2/impcnvgen.c b/dmd2/impcnvgen.c index 4ab09fde..c4d9ac9f 100644 --- a/dmd2/impcnvgen.c +++ b/dmd2/impcnvgen.c @@ -1,462 +1,462 @@ - -// Copyright (c) 1999-2006 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 -#include - -#include "mtype.h" - -TY impcnvResult[TMAX][TMAX]; -TY impcnvType1[TMAX][TMAX]; -TY impcnvType2[TMAX][TMAX]; -int impcnvWarn[TMAX][TMAX]; - -int integral_promotion(int t) -{ - switch (t) - { - case Tchar: - case Twchar: - //case Tbit: - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: return Tint32; - case Tdchar: return Tuns32; - default: return t; - } -} - -void init() -{ int i, j; - - // Set conversion tables - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { impcnvResult[i][j] = Terror; - impcnvType1[i][j] = Terror; - impcnvType2[i][j] = Terror; - impcnvWarn[i][j] = 0; - } - -#define X(t1,t2, nt1,nt2, rt) \ - impcnvResult[t1][t2] = rt; \ - impcnvType1[t1][t2] = nt1; \ - impcnvType2[t1][t2] = nt2; - - /* ======================= */ - -#if 0 - X(Tbit,Tbit, Tint32,Tint32, Tint32) - X(Tbit,Tint8, Tint32,Tint32, Tint32) - X(Tbit,Tuns8, Tint32,Tint32, Tint32) - X(Tbit,Tint16, Tint32,Tint32, Tint32) - X(Tbit,Tuns16, Tint32,Tint32, Tint32) - X(Tbit,Tint32, Tint32,Tint32, Tint32) - X(Tbit,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbit,Tint64, Tint64,Tint64, Tint64) - X(Tbit,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbit,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbit,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbit,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbit,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbit,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbit,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) -#endif - - /* ======================= */ - - X(Tbool,Tbool, Tbool,Tbool, Tbool) - X(Tbool,Tint8, Tint32,Tint32, Tint32) - X(Tbool,Tuns8, Tint32,Tint32, Tint32) - X(Tbool,Tint16, Tint32,Tint32, Tint32) - X(Tbool,Tuns16, Tint32,Tint32, Tint32) - X(Tbool,Tint32, Tint32,Tint32, Tint32) - X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbool,Tint64, Tint64,Tint64, Tint64) - X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint8,Tint8, Tint32,Tint32, Tint32) - X(Tint8,Tuns8, Tint32,Tint32, Tint32) - X(Tint8,Tint16, Tint32,Tint32, Tint32) - X(Tint8,Tuns16, Tint32,Tint32, Tint32) - X(Tint8,Tint32, Tint32,Tint32, Tint32) - X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint8,Tint64, Tint64,Tint64, Tint64) - X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns8,Tuns8, Tint32,Tint32, Tint32) - X(Tuns8,Tint16, Tint32,Tint32, Tint32) - X(Tuns8,Tuns16, Tint32,Tint32, Tint32) - X(Tuns8,Tint32, Tint32,Tint32, Tint32) - X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns8,Tint64, Tint64,Tint64, Tint64) - X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint16,Tint16, Tint32,Tint32, Tint32) - X(Tint16,Tuns16, Tint32,Tint32, Tint32) - X(Tint16,Tint32, Tint32,Tint32, Tint32) - X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint16,Tint64, Tint64,Tint64, Tint64) - X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns16,Tuns16, Tint32,Tint32, Tint32) - X(Tuns16,Tint32, Tint32,Tint32, Tint32) - X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns16,Tint64, Tint64,Tint64, Tint64) - X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint32,Tint32, Tint32,Tint32, Tint32) - X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint32,Tint64, Tint64,Tint64, Tint64) - X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns32,Tint64, Tint64,Tint64, Tint64) - X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint64,Tint64, Tint64,Tint64, Tint64) - X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32) - X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32) - X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32) - X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - -#undef X - -#define Y(t1,t2) impcnvWarn[t1][t2] = 1; - -#if 0 - Y(Tint8, Tbit) - Y(Tuns8, Tbit) - Y(Tint16, Tbit) - Y(Tuns16, Tbit) - Y(Tint32, Tbit) - Y(Tuns32, Tbit) - Y(Tint64, Tbit) - Y(Tuns64, Tbit) -#endif - - Y(Tuns8, Tint8) - Y(Tint16, Tint8) - Y(Tuns16, Tint8) - Y(Tint32, Tint8) - Y(Tuns32, Tint8) - Y(Tint64, Tint8) - Y(Tuns64, Tint8) - - Y(Tint8, Tuns8) - Y(Tint16, Tuns8) - Y(Tuns16, Tuns8) - Y(Tint32, Tuns8) - Y(Tuns32, Tuns8) - Y(Tint64, Tuns8) - Y(Tuns64, Tuns8) - - Y(Tint8, Tchar) - Y(Tint16, Tchar) - Y(Tuns16, Tchar) - Y(Tint32, Tchar) - Y(Tuns32, Tchar) - Y(Tint64, Tchar) - Y(Tuns64, Tchar) - - Y(Tuns16, Tint16) - Y(Tint32, Tint16) - Y(Tuns32, Tint16) - Y(Tint64, Tint16) - Y(Tuns64, Tint16) - - Y(Tint16, Tuns16) - Y(Tint32, Tuns16) - Y(Tuns32, Tuns16) - Y(Tint64, Tuns16) - Y(Tuns64, Tuns16) - - Y(Tint16, Twchar) - Y(Tint32, Twchar) - Y(Tuns32, Twchar) - Y(Tint64, Twchar) - Y(Tuns64, Twchar) - -// Y(Tuns32, Tint32) - Y(Tint64, Tint32) - Y(Tuns64, Tint32) - -// Y(Tint32, Tuns32) - Y(Tint64, Tuns32) - Y(Tuns64, Tuns32) - - Y(Tint64, Tdchar) - Y(Tuns64, Tdchar) - - Y(Tint64, Tuns64) - Y(Tuns64, Tint64) - - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { - if (impcnvResult[i][j] == Terror) - { - impcnvResult[i][j] = impcnvResult[j][i]; - impcnvType1[i][j] = impcnvType2[j][i]; - impcnvType2[i][j] = impcnvType1[j][i]; - } - } -} - -int main() -{ FILE *fp; - int i; - int j; - - init(); - - fp = fopen("impcnvtab.c","w"); - - fprintf(fp,"// This file is generated by impcnvgen.c\n"); - fprintf(fp,"#include \"mtype.h\"\n"); - - fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvResult[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType1[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType2[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvWarn[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fclose(fp); - return EXIT_SUCCESS; -} + +// Copyright (c) 1999-2006 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 +#include + +#include "mtype.h" + +TY impcnvResult[TMAX][TMAX]; +TY impcnvType1[TMAX][TMAX]; +TY impcnvType2[TMAX][TMAX]; +int impcnvWarn[TMAX][TMAX]; + +int integral_promotion(int t) +{ + switch (t) + { + case Tchar: + case Twchar: + //case Tbit: + case Tbool: + case Tint8: + case Tuns8: + case Tint16: + case Tuns16: return Tint32; + case Tdchar: return Tuns32; + default: return t; + } +} + +void init() +{ int i, j; + + // Set conversion tables + for (i = 0; i < TMAX; i++) + for (j = 0; j < TMAX; j++) + { impcnvResult[i][j] = Terror; + impcnvType1[i][j] = Terror; + impcnvType2[i][j] = Terror; + impcnvWarn[i][j] = 0; + } + +#define X(t1,t2, nt1,nt2, rt) \ + impcnvResult[t1][t2] = rt; \ + impcnvType1[t1][t2] = nt1; \ + impcnvType2[t1][t2] = nt2; + + /* ======================= */ + +#if 0 + X(Tbit,Tbit, Tint32,Tint32, Tint32) + X(Tbit,Tint8, Tint32,Tint32, Tint32) + X(Tbit,Tuns8, Tint32,Tint32, Tint32) + X(Tbit,Tint16, Tint32,Tint32, Tint32) + X(Tbit,Tuns16, Tint32,Tint32, Tint32) + X(Tbit,Tint32, Tint32,Tint32, Tint32) + X(Tbit,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tbit,Tint64, Tint64,Tint64, Tint64) + X(Tbit,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tbit,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tbit,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tbit,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tbit,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tbit,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tbit,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tbit,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tbit,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tbit,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) +#endif + + /* ======================= */ + + X(Tbool,Tbool, Tbool,Tbool, Tbool) + X(Tbool,Tint8, Tint32,Tint32, Tint32) + X(Tbool,Tuns8, Tint32,Tint32, Tint32) + X(Tbool,Tint16, Tint32,Tint32, Tint32) + X(Tbool,Tuns16, Tint32,Tint32, Tint32) + X(Tbool,Tint32, Tint32,Tint32, Tint32) + X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tbool,Tint64, Tint64,Tint64, Tint64) + X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tint8,Tint8, Tint32,Tint32, Tint32) + X(Tint8,Tuns8, Tint32,Tint32, Tint32) + X(Tint8,Tint16, Tint32,Tint32, Tint32) + X(Tint8,Tuns16, Tint32,Tint32, Tint32) + X(Tint8,Tint32, Tint32,Tint32, Tint32) + X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tint8,Tint64, Tint64,Tint64, Tint64) + X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tuns8,Tuns8, Tint32,Tint32, Tint32) + X(Tuns8,Tint16, Tint32,Tint32, Tint32) + X(Tuns8,Tuns16, Tint32,Tint32, Tint32) + X(Tuns8,Tint32, Tint32,Tint32, Tint32) + X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tuns8,Tint64, Tint64,Tint64, Tint64) + X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tint16,Tint16, Tint32,Tint32, Tint32) + X(Tint16,Tuns16, Tint32,Tint32, Tint32) + X(Tint16,Tint32, Tint32,Tint32, Tint32) + X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tint16,Tint64, Tint64,Tint64, Tint64) + X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tuns16,Tuns16, Tint32,Tint32, Tint32) + X(Tuns16,Tint32, Tint32,Tint32, Tint32) + X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tuns16,Tint64, Tint64,Tint64, Tint64) + X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tint32,Tint32, Tint32,Tint32, Tint32) + X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tint32,Tint64, Tint64,Tint64, Tint64) + X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32) + X(Tuns32,Tint64, Tint64,Tint64, Tint64) + X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tint64,Tint64, Tint64,Tint64, Tint64) + X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64) + + X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) + X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + + X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) + X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + + X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) + X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) + X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + + X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64) + X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) + X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + + X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64) + X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) + X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80) + + X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80) + X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80) + X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80) + + X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80) + X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80) + X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32) + X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64) + X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80) + + X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32) + X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) + X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64) + X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80) + + X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64) + X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) + X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80) + + X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80) + X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80) + X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32) + X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) + X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) + X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) + + /* ======================= */ + + X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) + +#undef X + +#define Y(t1,t2) impcnvWarn[t1][t2] = 1; + +#if 0 + Y(Tint8, Tbit) + Y(Tuns8, Tbit) + Y(Tint16, Tbit) + Y(Tuns16, Tbit) + Y(Tint32, Tbit) + Y(Tuns32, Tbit) + Y(Tint64, Tbit) + Y(Tuns64, Tbit) +#endif + + Y(Tuns8, Tint8) + Y(Tint16, Tint8) + Y(Tuns16, Tint8) + Y(Tint32, Tint8) + Y(Tuns32, Tint8) + Y(Tint64, Tint8) + Y(Tuns64, Tint8) + + Y(Tint8, Tuns8) + Y(Tint16, Tuns8) + Y(Tuns16, Tuns8) + Y(Tint32, Tuns8) + Y(Tuns32, Tuns8) + Y(Tint64, Tuns8) + Y(Tuns64, Tuns8) + + Y(Tint8, Tchar) + Y(Tint16, Tchar) + Y(Tuns16, Tchar) + Y(Tint32, Tchar) + Y(Tuns32, Tchar) + Y(Tint64, Tchar) + Y(Tuns64, Tchar) + + Y(Tuns16, Tint16) + Y(Tint32, Tint16) + Y(Tuns32, Tint16) + Y(Tint64, Tint16) + Y(Tuns64, Tint16) + + Y(Tint16, Tuns16) + Y(Tint32, Tuns16) + Y(Tuns32, Tuns16) + Y(Tint64, Tuns16) + Y(Tuns64, Tuns16) + + Y(Tint16, Twchar) + Y(Tint32, Twchar) + Y(Tuns32, Twchar) + Y(Tint64, Twchar) + Y(Tuns64, Twchar) + +// Y(Tuns32, Tint32) + Y(Tint64, Tint32) + Y(Tuns64, Tint32) + +// Y(Tint32, Tuns32) + Y(Tint64, Tuns32) + Y(Tuns64, Tuns32) + + Y(Tint64, Tdchar) + Y(Tuns64, Tdchar) + +// Y(Tint64, Tuns64) +// Y(Tuns64, Tint64) + + for (i = 0; i < TMAX; i++) + for (j = 0; j < TMAX; j++) + { + if (impcnvResult[i][j] == Terror) + { + impcnvResult[i][j] = impcnvResult[j][i]; + impcnvType1[i][j] = impcnvType2[j][i]; + impcnvType2[i][j] = impcnvType1[j][i]; + } + } +} + +int main() +{ FILE *fp; + int i; + int j; + + init(); + + fp = fopen("impcnvtab.c","w"); + + fprintf(fp,"// This file is generated by impcnvgen.c\n"); + fprintf(fp,"#include \"mtype.h\"\n"); + + fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n"); + for (i = 0; i < TMAX; i++) + { + for (j = 0; j < TMAX; j++) + { + fprintf(fp, "%d,",impcnvResult[i][j]); + } + fprintf(fp, "\n"); + } + fprintf(fp,"};\n"); + + fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n"); + for (i = 0; i < TMAX; i++) + { + for (j = 0; j < TMAX; j++) + { + fprintf(fp, "%d,",impcnvType1[i][j]); + } + fprintf(fp, "\n"); + } + fprintf(fp,"};\n"); + + fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n"); + for (i = 0; i < TMAX; i++) + { + for (j = 0; j < TMAX; j++) + { + fprintf(fp, "%d,",impcnvType2[i][j]); + } + fprintf(fp, "\n"); + } + fprintf(fp,"};\n"); + + fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n"); + for (i = 0; i < TMAX; i++) + { + for (j = 0; j < TMAX; j++) + { + fprintf(fp, "%d,",impcnvWarn[i][j]); + } + fprintf(fp, "\n"); + } + fprintf(fp,"};\n"); + + fclose(fp); + return EXIT_SUCCESS; +} diff --git a/dmd2/imphint.c b/dmd2/imphint.c new file mode 100644 index 00000000..4e631304 --- /dev/null +++ b/dmd2/imphint.c @@ -0,0 +1,82 @@ + + +// Compiler implementation of the D programming language +// Copyright (c) 2010 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 +#include +#include +#include +#include + +/****************************************** + * Looks for undefined identifier s to see + * if it might be undefined because an import + * was not specified. + * Not meant to be a comprehensive list of names in each module, + * just the most common ones. + */ + +const char *importHint(const char *s) +{ +#if DMDV1 + static const char *modules[] = + { "std.c.stdio", + "std.stdio", + "std.math", + }; + static const char *names[] = + { + "printf", NULL, + "writefln", NULL, + "sin", "cos", "sqrt", "fabs", NULL, + }; +#else + static const char *modules[] = + { "core.stdc.stdio", + "std.stdio", + "std.math", + }; + static const char *names[] = + { + "printf", NULL, + "writeln", NULL, + "sin", "cos", "sqrt", "fabs", NULL, + }; +#endif + int m = 0; + for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) + { + const char *p = names[n]; + if (p == NULL) + { m++; + continue; + } + assert(m < sizeof(modules)/sizeof(modules[0])); + if (strcmp(s, p) == 0) + return modules[m]; + } + return NULL; // didn't find it +} + +#if UNITTEST + +void unittest_importHint() +{ + const char *p; + + p = importHint("printf"); + assert(p); + p = importHint("fabs"); + assert(p); + p = importHint("xxxxx"); + assert(!p); +} + +#endif diff --git a/dmd2/import.c b/dmd2/import.c index 002a560e..8a970d15 100644 --- a/dmd2/import.c +++ b/dmd2/import.c @@ -1,364 +1,388 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "root.h" -#include "dsymbol.h" -#include "import.h" -#include "identifier.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "mtype.h" -#include "declaration.h" -#include "id.h" -#include "attrib.h" - -/********************************* Import ****************************/ - -Import::Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, - int isstatic) - : Dsymbol(id) -{ - assert(id); - this->loc = loc; - this->packages = packages; - this->id = id; - this->aliasId = aliasId; - this->isstatic = isstatic; -#if IN_LLVM - protection = PROTundefined; -#endif - pkg = NULL; - mod = NULL; - - if (aliasId) - this->ident = aliasId; - // Kludge to change Import identifier to first package - else if (packages && packages->dim) - this->ident = (Identifier *)packages->data[0]; -} - -void Import::addAlias(Identifier *name, Identifier *alias) -{ - if (isstatic) - error("cannot have an import bind list"); - - if (!aliasId) - this->ident = NULL; // make it an anonymous import - - names.push(name); - aliases.push(alias); -} - -const char *Import::kind() -{ - return isstatic ? (char *)"static import" : (char *)"import"; -} - -#if IN_LLVM -enum PROT Import::prot() -{ - return protection; -} -#endif - -Dsymbol *Import::syntaxCopy(Dsymbol *s) -{ - assert(!s); - - Import *si; - - si = new Import(loc, packages, id, aliasId, isstatic); - - for (size_t i = 0; i < names.dim; i++) - { - si->addAlias((Identifier *)names.data[i], (Identifier *)aliases.data[i]); - } - - return si; -} - -void Import::load(Scope *sc) -{ - DsymbolTable *dst; - Dsymbol *s; - - //printf("Import::load('%s')\n", toChars()); - - // See if existing module - dst = Package::resolve(packages, NULL, &pkg); - - s = dst->lookup(id); - if (s) - { -#if TARGET_NET - mod = (Module *)s; -#else - if (s->isModule()) - mod = (Module *)s; - else - error("package and module have the same name"); -#endif - } - - if (!mod) - { - // Load module - mod = Module::load(loc, packages, id); - dst->insert(id, mod); // id may be different from mod->ident, - // if so then insert alias - if (!mod->importedFrom) - mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; - } - if (!pkg) - pkg = mod; - - //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); -} - -void escapePath(OutBuffer *buf, const char *fname) -{ - while (1) - { - switch (*fname) - { - case 0: - return; - case '(': - case ')': - case '\\': - buf->writebyte('\\'); - default: - buf->writebyte(*fname); - break; - } - fname++; - } -} - -void Import::semantic(Scope *sc) -{ - //printf("Import::semantic('%s')\n", toChars()); - - load(sc); - - if (mod) - { -#if 0 - if (mod->loc.linnum != 0) - { /* If the line number is not 0, then this is not - * a 'root' module, i.e. it was not specified on the command line. - */ - mod->importedFrom = sc->module->importedFrom; - assert(mod->importedFrom); - } -#endif - - // Modules need a list of each imported module - //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); - sc->module->aimports.push(mod); - - if (!isstatic && !aliasId && !names.dim) - { - /* Default to private importing - */ - enum PROT prot = sc->protection; - if (!sc->explicitProtection) - prot = PROTprivate; - sc->scopesym->importScope(mod, prot); - } - - mod->semantic(); - - if (mod->needmoduleinfo) - sc->module->needmoduleinfo = 1; - - sc = sc->push(mod); - for (size_t i = 0; i < aliasdecls.dim; i++) - { AliasDeclaration *ad = (AliasDeclaration *)aliasdecls.data[i]; - - //printf("\tImport alias semantic('%s')\n", s->toChars()); - if (!mod->search(loc, (Identifier *)names.data[i], 0)) - error("%s not found", ((Identifier *)names.data[i])->toChars()); - - ad->importprot = protection; - ad->semantic(sc); - } - sc = sc->pop(); - } - - if (global.params.moduleDeps != NULL) - { - /* The grammar of the file is: - * ImportDeclaration - * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " - * ModuleAliasIdentifier ] "\n" - * - * BasicImportDeclaration - * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection - * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" - * - * FilePath - * - any string with '(', ')' and '\' escaped with the '\' character - */ - - OutBuffer *ob = global.params.moduleDeps; - - ob->writestring(sc->module->toPrettyChars()); - ob->writestring(" ("); - escapePath(ob, sc->module->srcfile->toChars()); - ob->writestring(") : "); - - ProtDeclaration::protectionToCBuffer(ob, sc->protection); - if (isstatic) - StorageClassDeclaration::stcToCBuffer(ob, STCstatic); - ob->writestring(": "); - - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { - Identifier *pid = (Identifier *)packages->data[i]; - ob->printf("%s.", pid->toChars()); - } - } - - ob->writestring(id->toChars()); - ob->writestring(" ("); - if (mod) - escapePath(ob, mod->srcfile->toChars()); - else - ob->writestring("???"); - ob->writebyte(')'); - - for (size_t i = 0; i < names.dim; i++) - { - if (i == 0) - ob->writebyte(':'); - else - ob->writebyte(','); - - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; - - if (!alias) - { - ob->printf("%s", name->toChars()); - alias = name; - } - else - ob->printf("%s=%s", alias->toChars(), name->toChars()); - } - - if (aliasId) - ob->printf(" -> %s", aliasId->toChars()); - - ob->writenl(); - } - - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); -} - -void Import::semantic2(Scope *sc) -{ - //printf("Import::semantic2('%s')\n", toChars()); - mod->semantic2(); - if (mod->needmoduleinfo) - sc->module->needmoduleinfo = 1; -} - -Dsymbol *Import::toAlias() -{ - if (aliasId) - return mod; - return this; -} - -/***************************** - * Add import to sd's symbol table. - */ - -int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int result = 0; - - if (names.dim == 0) - return Dsymbol::addMember(sc, sd, memnum); - - if (aliasId) - result = Dsymbol::addMember(sc, sd, memnum); - - /* Instead of adding the import to sd's symbol table, - * add each of the alias=name pairs - */ - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = (Identifier *)names.data[i]; - Identifier *alias = (Identifier *)aliases.data[i]; - - if (!alias) - alias = name; - - TypeIdentifier *tname = new TypeIdentifier(loc, name); - AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname); - result |= ad->addMember(sc, sd, memnum); - - aliasdecls.push(ad); - } - - return result; -} - -Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); - - if (!pkg) - { load(NULL); - mod->semantic(); - } - - // Forward it to the package/module - return pkg->search(loc, ident, flags); -} - -int Import::overloadInsert(Dsymbol *s) -{ - // Allow multiple imports of the same name - return s->isImport() != NULL; -} - -void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && id == Id::object) - return; // object is imported by default - - if (isstatic) - buf->writestring("static "); - buf->writestring("import "); - if (aliasId) - { - buf->printf("%s = ", aliasId->toChars()); - } - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; - - buf->printf("%s.", pid->toChars()); - } - } - buf->printf("%s;", id->toChars()); - buf->writenl(); -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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 +#include + +#include "root.h" +#include "dsymbol.h" +#include "import.h" +#include "identifier.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "mtype.h" +#include "declaration.h" +#include "id.h" +#include "attrib.h" + +/********************************* Import ****************************/ + +Import::Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, + int isstatic) + : Dsymbol(id) +{ + assert(id); + this->loc = loc; + this->packages = packages; + this->id = id; + this->aliasId = aliasId; + this->isstatic = isstatic; +#if IN_LLVM + protection = PROTundefined; +#endif + pkg = NULL; + mod = NULL; + + if (aliasId) + this->ident = aliasId; + // Kludge to change Import identifier to first package + else if (packages && packages->dim) + this->ident = (Identifier *)packages->data[0]; +} + +void Import::addAlias(Identifier *name, Identifier *alias) +{ + if (isstatic) + error("cannot have an import bind list"); + + if (!aliasId) + this->ident = NULL; // make it an anonymous import + + names.push(name); + aliases.push(alias); +} + +const char *Import::kind() +{ + return isstatic ? (char *)"static import" : (char *)"import"; +} + +#if IN_LLVM +enum PROT Import::prot() +{ + return protection; +} +#endif + +Dsymbol *Import::syntaxCopy(Dsymbol *s) +{ + assert(!s); + + Import *si; + + si = new Import(loc, packages, id, aliasId, isstatic); + + for (size_t i = 0; i < names.dim; i++) + { + si->addAlias((Identifier *)names.data[i], (Identifier *)aliases.data[i]); + } + + return si; +} + +void Import::load(Scope *sc) +{ + //printf("Import::load('%s')\n", toChars()); + + // See if existing module + DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); + + Dsymbol *s = dst->lookup(id); + if (s) + { +#if TARGET_NET + mod = (Module *)s; +#else + if (s->isModule()) + mod = (Module *)s; + else + error("package and module have the same name"); +#endif + } + + if (!mod) + { + // Load module + mod = Module::load(loc, packages, id); + dst->insert(id, mod); // id may be different from mod->ident, + // if so then insert alias + if (!mod->importedFrom) + mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; + } + if (!pkg) + pkg = mod; + + //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); +} + +void escapePath(OutBuffer *buf, const char *fname) +{ + while (1) + { + switch (*fname) + { + case 0: + return; + case '(': + case ')': + case '\\': + buf->writebyte('\\'); + default: + buf->writebyte(*fname); + break; + } + fname++; + } +} + +void Import::importAll(Scope *sc) +{ + if (!mod) + { + load(sc); + mod->importAll(0); + + if (!isstatic && !aliasId && !names.dim) + { + /* Default to private importing + */ + enum PROT prot = sc->protection; + if (!sc->explicitProtection) + prot = PROTprivate; + sc->scopesym->importScope(mod, prot); + } + } +} + +void Import::semantic(Scope *sc) +{ + //printf("Import::semantic('%s')\n", toChars()); + + // Load if not already done so + if (!mod) + { load(sc); + mod->importAll(0); + } + + if (mod) + { +#if 0 + if (mod->loc.linnum != 0) + { /* If the line number is not 0, then this is not + * a 'root' module, i.e. it was not specified on the command line. + */ + mod->importedFrom = sc->module->importedFrom; + assert(mod->importedFrom); + } +#endif + + // Modules need a list of each imported module + //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); + sc->module->aimports.push(mod); + + if (!isstatic && !aliasId && !names.dim) + { + /* Default to private importing + */ + enum PROT prot = sc->protection; + if (!sc->explicitProtection) + prot = PROTprivate; + sc->scopesym->importScope(mod, prot); + } + + mod->semantic(); + + if (mod->needmoduleinfo) + { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); + sc->module->needmoduleinfo = 1; + } + + sc = sc->push(mod); + for (size_t i = 0; i < aliasdecls.dim; i++) + { AliasDeclaration *ad = (AliasDeclaration *)aliasdecls.data[i]; + + //printf("\tImport alias semantic('%s')\n", s->toChars()); + if (!mod->search(loc, (Identifier *)names.data[i], 0)) + error("%s not found", ((Identifier *)names.data[i])->toChars()); + + ad->importprot = protection; + ad->semantic(sc); + } + sc = sc->pop(); + } + + if (global.params.moduleDeps != NULL) + { + /* The grammar of the file is: + * ImportDeclaration + * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " + * ModuleAliasIdentifier ] "\n" + * + * BasicImportDeclaration + * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection + * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" + * + * FilePath + * - any string with '(', ')' and '\' escaped with the '\' character + */ + + OutBuffer *ob = global.params.moduleDeps; + + ob->writestring(sc->module->toPrettyChars()); + ob->writestring(" ("); + escapePath(ob, sc->module->srcfile->toChars()); + ob->writestring(") : "); + + ProtDeclaration::protectionToCBuffer(ob, sc->protection); + if (isstatic) + StorageClassDeclaration::stcToCBuffer(ob, STCstatic); + ob->writestring(": "); + + if (packages) + { + for (size_t i = 0; i < packages->dim; i++) + { + Identifier *pid = (Identifier *)packages->data[i]; + ob->printf("%s.", pid->toChars()); + } + } + + ob->writestring(id->toChars()); + ob->writestring(" ("); + if (mod) + escapePath(ob, mod->srcfile->toChars()); + else + ob->writestring("???"); + ob->writebyte(')'); + + for (size_t i = 0; i < names.dim; i++) + { + if (i == 0) + ob->writebyte(':'); + else + ob->writebyte(','); + + Identifier *name = (Identifier *)names.data[i]; + Identifier *alias = (Identifier *)aliases.data[i]; + + if (!alias) + { + ob->printf("%s", name->toChars()); + alias = name; + } + else + ob->printf("%s=%s", alias->toChars(), name->toChars()); + } + + if (aliasId) + ob->printf(" -> %s", aliasId->toChars()); + + ob->writenl(); + } + + //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); +} + +void Import::semantic2(Scope *sc) +{ + //printf("Import::semantic2('%s')\n", toChars()); + mod->semantic2(); + if (mod->needmoduleinfo) + { //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars()); + sc->module->needmoduleinfo = 1; + } +} + +Dsymbol *Import::toAlias() +{ + if (aliasId) + return mod; + return this; +} + +/***************************** + * Add import to sd's symbol table. + */ + +int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + int result = 0; + + if (names.dim == 0) + return Dsymbol::addMember(sc, sd, memnum); + + if (aliasId) + result = Dsymbol::addMember(sc, sd, memnum); + + /* Instead of adding the import to sd's symbol table, + * add each of the alias=name pairs + */ + for (size_t i = 0; i < names.dim; i++) + { + Identifier *name = (Identifier *)names.data[i]; + Identifier *alias = (Identifier *)aliases.data[i]; + + if (!alias) + alias = name; + + TypeIdentifier *tname = new TypeIdentifier(loc, name); + AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname); + result |= ad->addMember(sc, sd, memnum); + + aliasdecls.push(ad); + } + + return result; +} + +Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); + + if (!pkg) + { load(NULL); + mod->semantic(); + } + + // Forward it to the package/module + return pkg->search(loc, ident, flags); +} + +int Import::overloadInsert(Dsymbol *s) +{ + // Allow multiple imports of the same name + return s->isImport() != NULL; +} + +void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (hgs->hdrgen && id == Id::object) + return; // object is imported by default + + if (isstatic) + buf->writestring("static "); + buf->writestring("import "); + if (aliasId) + { + buf->printf("%s = ", aliasId->toChars()); + } + if (packages && packages->dim) + { + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = (Identifier *)packages->data[i]; + + buf->printf("%s.", pid->toChars()); + } + } + buf->printf("%s;", id->toChars()); + buf->writenl(); +} + diff --git a/dmd2/import.h b/dmd2/import.h index bc00129c..2ca47e37 100644 --- a/dmd2/import.h +++ b/dmd2/import.h @@ -1,71 +1,72 @@ - -// 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. - -#ifndef DMD_IMPORT_H -#define DMD_IMPORT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - - -struct Identifier; -struct Scope; -struct OutBuffer; -struct Module; -struct Package; -struct AliasDeclaration; -#ifdef _DH -struct HdrGenState; -#endif - -struct Import : Dsymbol -{ - Array *packages; // array of Identifier's representing packages - Identifier *id; // module Identifier - Identifier *aliasId; - int isstatic; // !=0 if static import -#if IN_LLVM - enum PROT protection; -#endif - - // Pairs of alias=name to bind into current namespace - Array names; - Array aliases; - - Array aliasdecls; // AliasDeclarations for names/aliases - - Module *mod; - Package *pkg; // leftmost package/module - - Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, - int isstatic); - void addAlias(Identifier *name, Identifier *alias); - - const char *kind(); -#if IN_LLVM - enum PROT prot(); -#endif - Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - void load(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - Dsymbol *toAlias(); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Import *isImport() { return this; } -}; - -#endif /* DMD_IMPORT_H */ + +// 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. + +#ifndef DMD_IMPORT_H +#define DMD_IMPORT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + + +struct Identifier; +struct Scope; +struct OutBuffer; +struct Module; +struct Package; +struct AliasDeclaration; +#ifdef _DH +struct HdrGenState; +#endif + +struct Import : Dsymbol +{ + Array *packages; // array of Identifier's representing packages + Identifier *id; // module Identifier + Identifier *aliasId; + int isstatic; // !=0 if static import +#if IN_LLVM + enum PROT protection; +#endif + + // Pairs of alias=name to bind into current namespace + Array names; + Array aliases; + + Array aliasdecls; // AliasDeclarations for names/aliases + + Module *mod; + Package *pkg; // leftmost package/module + + Import(Loc loc, Array *packages, Identifier *id, Identifier *aliasId, + int isstatic); + void addAlias(Identifier *name, Identifier *alias); + + const char *kind(); +#if IN_LLVM + enum PROT prot(); +#endif + Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees + void load(Scope *sc); + void importAll(Scope *sc); + void semantic(Scope *sc); + void semantic2(Scope *sc); + Dsymbol *toAlias(); + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + int overloadInsert(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Import *isImport() { return this; } +}; + +#endif /* DMD_IMPORT_H */ diff --git a/dmd2/inifile.c b/dmd2/inifile.c index 707da4c1..2d74918d 100644 --- a/dmd2/inifile.c +++ b/dmd2/inifile.c @@ -1,329 +1,333 @@ -/* - * Some portions copyright (c) 1994-1995 by Symantec - * Copyright (c) 1999-2009 by Digital Mars - * All Rights Reserved - * http://www.digitalmars.com - * Written by Walter Bright - * - * This source file is made available for personal use - * only. The license is in /dmd/src/dmd/backendlicense.txt - * For any other uses, please contact Digital Mars. - */ - -#include -#include -#include -#include - -#if _WIN32 -#include -#endif - -#if __APPLE__ -#include -#endif -#if __FreeBSD__ || __sun&&__SVR4 -// for PATH_MAX -#include -#endif - -#if __sun&&__SVR4 -#include -#endif - -#include "root.h" -#include "rmem.h" - -#define LOG 0 - -char *skipspace(const char *p); - -#if __GNUC__ -char *strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} -#endif /* unix */ - -/***************************** - * Read and analyze .ini file. - * Input: - * argv0 program name (argv[0]) - * inifile .ini file name - */ - -void inifile(const char *argv0x, const char *inifilex) -{ - char *argv0 = (char *)argv0x; - char *inifile = (char *)inifilex; // do const-correct later - char *path; // need path for @P macro - char *filename; - OutBuffer buf; - int i; - int k; - int envsection = 0; - -#if LOG - printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); -#endif - if (FileName::absolute(inifile)) - { - filename = inifile; - } - else - { - /* Look for inifile in the following sequence of places: - * o current directory - * o home directory - * o directory off of argv0 - * o /etc/ - */ - if (FileName::exists(inifile)) - { - filename = inifile; - } - else - { - filename = FileName::combine(getenv("HOME"), inifile); - if (!FileName::exists(filename)) - { -#if _WIN32 // This fix by Tim Matthews - char resolved_name[MAX_PATH + 1]; - if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name)) - { - filename = (char *)FileName::replaceName(resolved_name, inifile); - if(FileName::exists(filename)) - goto Ldone; - } -#endif - filename = (char *)FileName::replaceName(argv0, inifile); - if (!FileName::exists(filename)) - { -#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 -#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne - /* argv0 might be a symbolic link, - * so try again looking past it to the real path - */ -#if __APPLE__ || __FreeBSD__ || __sun&&__SVR4 - char resolved_name[PATH_MAX + 1]; - char* real_argv0 = realpath(argv0, resolved_name); -#else - char* real_argv0 = realpath(argv0, NULL); -#endif - //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0); - if (real_argv0) - { - filename = (char *)FileName::replaceName(real_argv0, inifile); -#if !(__APPLE__ || __FreeBSD__ || __sun&&__SVR4) - free(real_argv0); -#endif - if (FileName::exists(filename)) - goto Ldone; - } -#else -#error use of glibc non-standard extension realpath(char*, NULL) -#endif - if (1){ - // Search PATH for argv0 - const char *p = getenv("PATH"); - Array *paths = FileName::splitPath(p); - filename = FileName::searchPath(paths, argv0, 0); - if (!filename) - goto Letc; // argv0 not found on path - filename = (char *)FileName::replaceName(filename, inifile); - if (FileName::exists(filename)) - goto Ldone; - } -#endif - - // Search /etc/ for inifile - Letc: - filename = FileName::combine((char *)"/etc/", inifile); - - Ldone: - ; - } - } - } - } - path = FileName::path(filename); -#if LOG - printf("\tpath = '%s', filename = '%s'\n", path, filename); -#endif - - File file(filename); - - if (file.read()) - return; // error reading file - - // Parse into lines - int eof = 0; - for (i = 0; i < file.len && !eof; i++) - { - int linestart = i; - - for (; i < file.len; i++) - { - switch (file.buffer[i]) - { - case '\r': - break; - - case '\n': - // Skip if it was preceded by '\r' - if (i && file.buffer[i - 1] == '\r') - goto Lskip; - break; - - case 0: - case 0x1A: - eof = 1; - break; - - default: - continue; - } - break; - } - - // The line is file.buffer[linestart..i] - char *line; - int len; - char *p; - char *pn; - - line = (char *)&file.buffer[linestart]; - len = i - linestart; - - buf.reset(); - - // First, expand the macros. - // Macros are bracketed by % characters. - - for (k = 0; k < len; k++) - { - if (line[k] == '%') - { - int j; - - for (j = k + 1; j < len; j++) - { - if (line[j] == '%') - { - if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0) - { - // %@P% is special meaning the path to the .ini file - p = path; - if (!*p) - p = (char *)"."; - } - else - { int len = j - k; - char tmp[10]; // big enough most of the time - - if (len <= sizeof(tmp)) - p = tmp; - else - p = (char *)alloca(len); - len--; - memcpy(p, &line[k + 1], len); - p[len] = 0; - strupr(p); - p = getenv(p); - if (!p) - p = (char *)""; - } - buf.writestring(p); - k = j; - goto L1; - } - } - } - buf.writeByte(line[k]); - L1: - ; - } - - // Remove trailing spaces - while (buf.offset && isspace(buf.data[buf.offset - 1])) - buf.offset--; - - p = buf.toChars(); - - // The expanded line is in p. - // Now parse it for meaning. - - p = skipspace(p); - switch (*p) - { - case ';': // comment - case 0: // blank - break; - - case '[': // look for [Environment] - p = skipspace(p + 1); - for (pn = p; isalnum(*pn); pn++) - ; - if (pn - p == 11 && - memicmp(p, "Environment", 11) == 0 && - *skipspace(pn) == ']' - ) - envsection = 1; - else - envsection = 0; - break; - - default: - if (envsection) - { - pn = p; - - // Convert name to upper case; - // remove spaces bracketing = - for (p = pn; *p; p++) - { if (islower(*p)) - *p &= ~0x20; - else if (isspace(*p)) - memmove(p, p + 1, strlen(p)); - else if (*p == '=') - { - p++; - while (isspace(*p)) - memmove(p, p + 1, strlen(p)); - break; - } - } - - putenv(strdup(pn)); -#if LOG - printf("\tputenv('%s')\n", pn); - //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); -#endif - } - break; - } - - Lskip: - ; - } -} - -/******************** - * Skip spaces. - */ - -char *skipspace(const char *p) -{ - while (isspace(*p)) - p++; - return (char *)p; -} - +/* + * Some portions copyright (c) 1994-1995 by Symantec + * Copyright (c) 1999-2009 by Digital Mars + * All Rights Reserved + * http://www.digitalmars.com + * Written by Walter Bright + * + * This source file is made available for personal use + * only. The license is in /dmd/src/dmd/backendlicense.txt + * For any other uses, please contact Digital Mars. + */ + +#include +#include +#include +#include + +#if _WIN32 +#include +#endif + +#if __APPLE__ +#include +#endif +#if __FreeBSD__ || __sun&&__SVR4 +// for PATH_MAX +#include +#endif + +#if __sun&&__SVR4 +#include +#endif + +#include "root.h" +#include "rmem.h" + +#define LOG 0 + +char *skipspace(const char *p); + +#if __GNUC__ +char *strupr(char *s) +{ + char *t = s; + + while (*s) + { + *s = toupper(*s); + s++; + } + + return t; +} +#endif /* unix */ + +/***************************** + * Read and analyze .ini file. + * Input: + * argv0 program name (argv[0]) + * inifile .ini file name + * Returns: + * file name of ini file + * Note: this is a memory leak + */ + +const char *inifile(const char *argv0x, const char *inifilex) +{ + char *argv0 = (char *)argv0x; + char *inifile = (char *)inifilex; // do const-correct later + char *path; // need path for @P macro + char *filename; + OutBuffer buf; + int i; + int k; + int envsection = 0; + +#if LOG + printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); +#endif + if (FileName::absolute(inifile)) + { + filename = inifile; + } + else + { + /* Look for inifile in the following sequence of places: + * o current directory + * o home directory + * o directory off of argv0 + * o /etc/ + */ + if (FileName::exists(inifile)) + { + filename = inifile; + } + else + { + filename = FileName::combine(getenv("HOME"), inifile); + if (!FileName::exists(filename)) + { +#if _WIN32 // This fix by Tim Matthews + char resolved_name[MAX_PATH + 1]; + if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name)) + { + filename = (char *)FileName::replaceName(resolved_name, inifile); + if(FileName::exists(filename)) + goto Ldone; + } +#endif + filename = (char *)FileName::replaceName(argv0, inifile); + if (!FileName::exists(filename)) + { +#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 +#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne + /* argv0 might be a symbolic link, + * so try again looking past it to the real path + */ +#if __APPLE__ || __FreeBSD__ || __sun&&__SVR4 + char resolved_name[PATH_MAX + 1]; + char* real_argv0 = realpath(argv0, resolved_name); +#else + char* real_argv0 = realpath(argv0, NULL); +#endif + //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0); + if (real_argv0) + { + filename = (char *)FileName::replaceName(real_argv0, inifile); +#if !(__APPLE__ || __FreeBSD__ || __sun&&__SVR4) + free(real_argv0); +#endif + if (FileName::exists(filename)) + goto Ldone; + } +#else +#error use of glibc non-standard extension realpath(char*, NULL) +#endif + if (1){ + // Search PATH for argv0 + const char *p = getenv("PATH"); + Array *paths = FileName::splitPath(p); + filename = FileName::searchPath(paths, argv0, 0); + if (!filename) + goto Letc; // argv0 not found on path + filename = (char *)FileName::replaceName(filename, inifile); + if (FileName::exists(filename)) + goto Ldone; + } +#endif + + // Search /etc/ for inifile + Letc: + filename = FileName::combine((char *)"/etc/", inifile); + + Ldone: + ; + } + } + } + } + path = FileName::path(filename); +#if LOG + printf("\tpath = '%s', filename = '%s'\n", path, filename); +#endif + + File file(filename); + + if (file.read()) + return filename; // error reading file + + // Parse into lines + int eof = 0; + for (i = 0; i < file.len && !eof; i++) + { + int linestart = i; + + for (; i < file.len; i++) + { + switch (file.buffer[i]) + { + case '\r': + break; + + case '\n': + // Skip if it was preceded by '\r' + if (i && file.buffer[i - 1] == '\r') + goto Lskip; + break; + + case 0: + case 0x1A: + eof = 1; + break; + + default: + continue; + } + break; + } + + // The line is file.buffer[linestart..i] + char *line; + int len; + char *p; + char *pn; + + line = (char *)&file.buffer[linestart]; + len = i - linestart; + + buf.reset(); + + // First, expand the macros. + // Macros are bracketed by % characters. + + for (k = 0; k < len; k++) + { + if (line[k] == '%') + { + int j; + + for (j = k + 1; j < len; j++) + { + if (line[j] == '%') + { + if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0) + { + // %@P% is special meaning the path to the .ini file + p = path; + if (!*p) + p = (char *)"."; + } + else + { int len = j - k; + char tmp[10]; // big enough most of the time + + if (len <= sizeof(tmp)) + p = tmp; + else + p = (char *)alloca(len); + len--; + memcpy(p, &line[k + 1], len); + p[len] = 0; + strupr(p); + p = getenv(p); + if (!p) + p = (char *)""; + } + buf.writestring(p); + k = j; + goto L1; + } + } + } + buf.writeByte(line[k]); + L1: + ; + } + + // Remove trailing spaces + while (buf.offset && isspace(buf.data[buf.offset - 1])) + buf.offset--; + + p = buf.toChars(); + + // The expanded line is in p. + // Now parse it for meaning. + + p = skipspace(p); + switch (*p) + { + case ';': // comment + case 0: // blank + break; + + case '[': // look for [Environment] + p = skipspace(p + 1); + for (pn = p; isalnum(*pn); pn++) + ; + if (pn - p == 11 && + memicmp(p, "Environment", 11) == 0 && + *skipspace(pn) == ']' + ) + envsection = 1; + else + envsection = 0; + break; + + default: + if (envsection) + { + pn = p; + + // Convert name to upper case; + // remove spaces bracketing = + for (p = pn; *p; p++) + { if (islower(*p)) + *p &= ~0x20; + else if (isspace(*p)) + memmove(p, p + 1, strlen(p)); + else if (*p == '=') + { + p++; + while (isspace(*p)) + memmove(p, p + 1, strlen(p)); + break; + } + } + + putenv(strdup(pn)); +#if LOG + printf("\tputenv('%s')\n", pn); + //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); +#endif + } + break; + } + + Lskip: + ; + } + return filename; +} + +/******************** + * Skip spaces. + */ + +char *skipspace(const char *p) +{ + while (isspace(*p)) + p++; + return (char *)p; +} + diff --git a/dmd2/init.c b/dmd2/init.c index cf9d1cb5..a71e7e47 100644 --- a/dmd2/init.c +++ b/dmd2/init.c @@ -1,659 +1,716 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "statement.h" -#include "identifier.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "hdrgen.h" - -/********************************** Initializer *******************************/ - -Initializer::Initializer(Loc loc) -{ - this->loc = loc; -} - -Initializer *Initializer::syntaxCopy() -{ - return this; -} - -Initializer *Initializer::semantic(Scope *sc, Type *t) -{ - return this; -} - -Type *Initializer::inferType(Scope *sc) -{ - error(loc, "cannot infer type from initializer"); - return Type::terror; -} - -Initializers *Initializer::arraySyntaxCopy(Initializers *ai) -{ Initializers *a = NULL; - - if (ai) - { - a = new Initializers(); - a->setDim(ai->dim); - for (int i = 0; i < a->dim; i++) - { Initializer *e = (Initializer *)ai->data[i]; - - e = e->syntaxCopy(); - a->data[i] = e; - } - } - return a; -} - -char *Initializer::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -/********************************** VoidInitializer ***************************/ - -VoidInitializer::VoidInitializer(Loc loc) - : Initializer(loc) -{ - type = NULL; -} - - -Initializer *VoidInitializer::syntaxCopy() -{ - return new VoidInitializer(loc); -} - - -Initializer *VoidInitializer::semantic(Scope *sc, Type *t) -{ - //printf("VoidInitializer::semantic(t = %p)\n", t); - type = t; - return this; -} - - -Expression *VoidInitializer::toExpression() -{ - error(loc, "void initializer has no value"); - return new IntegerExp(0); -} - - -void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("void"); -} - - -/********************************** StructInitializer *************************/ - -StructInitializer::StructInitializer(Loc loc) - : Initializer(loc) -{ - ad = NULL; -} - -Initializer *StructInitializer::syntaxCopy() -{ - StructInitializer *ai = new StructInitializer(loc); - - assert(field.dim == value.dim); - ai->field.setDim(field.dim); - ai->value.setDim(value.dim); - for (int i = 0; i < field.dim; i++) - { - ai->field.data[i] = field.data[i]; - - Initializer *init = (Initializer *)value.data[i]; - init = init->syntaxCopy(); - ai->value.data[i] = init; - } - return ai; -} - -void StructInitializer::addInit(Identifier *field, Initializer *value) -{ - //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); - this->field.push(field); - this->value.push(value); -} - -Initializer *StructInitializer::semantic(Scope *sc, Type *t) -{ - TypeStruct *ts; - int errors = 0; - - //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); - vars.setDim(field.dim); - t = t->toBasetype(); - if (t->ty == Tstruct) - { unsigned i; - unsigned fieldi = 0; - - ts = (TypeStruct *)t; - ad = ts->sym; - for (i = 0; i < field.dim; i++) - { - Identifier *id = (Identifier *)field.data[i]; - Initializer *val = (Initializer *)value.data[i]; - Dsymbol *s; - VarDeclaration *v; - - if (id == NULL) - { - if (fieldi >= ad->fields.dim) - { error(loc, "too many initializers for %s", ad->toChars()); - field.remove(i); - i--; - continue; - } - else - { - s = (Dsymbol *)ad->fields.data[fieldi]; - } - } - else - { - //s = ad->symtab->lookup(id); - s = ad->search(loc, id, 0); - if (!s) - { - error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); - continue; - } - - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= ad->fields.dim) - { - s->error("is not a per-instance initializable field"); - break; - } - if (s == (Dsymbol *)ad->fields.data[fieldi]) - break; - } - } - if (s && (v = s->isVarDeclaration()) != NULL) - { - val = val->semantic(sc, v->type); - value.data[i] = (void *)val; - vars.data[i] = (void *)v; - } - else - { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); - errors = 1; - } - fieldi++; - } - } - else if (t->ty == Tdelegate && value.dim == 0) - { /* Rewrite as empty delegate literal { } - */ - Arguments *arguments = new Arguments; - Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); - FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); - fd->fbody = new CompoundStatement(loc, new Statements()); - fd->endloc = loc; - Expression *e = new FuncExp(loc, fd); - ExpInitializer *ie = new ExpInitializer(loc, e); - return ie->semantic(sc, t); - } - else - { - error(loc, "a struct is not a valid initializer for a %s", t->toChars()); - errors = 1; - } - if (errors) - { - field.setDim(0); - value.setDim(0); - vars.setDim(0); - } - return this; -} - - -/*************************************** - * This works by transforming a struct initializer into - * a struct literal. In the future, the two should be the - * same thing. - */ -Expression *StructInitializer::toExpression() -{ Expression *e; - - //printf("StructInitializer::toExpression() %s\n", toChars()); - if (!ad) // if fwd referenced - { - return NULL; - } - StructDeclaration *sd = ad->isStructDeclaration(); - if (!sd) - return NULL; - Expressions *elements = new Expressions(); - for (size_t i = 0; i < value.dim; i++) - { - if (field.data[i]) - goto Lno; - Initializer *iz = (Initializer *)value.data[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - goto Lno; - elements->push(ex); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = sd->type; - return e; - -Lno: - delete elements; - //error(loc, "struct initializers as expressions are not allowed"); - return NULL; -} - - -void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("StructInitializer::toCBuffer()\n"); - buf->writebyte('{'); - for (int i = 0; i < field.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Identifier *id = (Identifier *)field.data[i]; - if (id) - { - buf->writestring(id->toChars()); - buf->writebyte(':'); - } - Initializer *iz = (Initializer *)value.data[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writebyte('}'); -} - -/********************************** ArrayInitializer ************************************/ - -ArrayInitializer::ArrayInitializer(Loc loc) - : Initializer(loc) -{ - dim = 0; - type = NULL; - sem = 0; -} - -Initializer *ArrayInitializer::syntaxCopy() -{ - //printf("ArrayInitializer::syntaxCopy()\n"); - - ArrayInitializer *ai = new ArrayInitializer(loc); - - assert(index.dim == value.dim); - ai->index.setDim(index.dim); - ai->value.setDim(value.dim); - for (int i = 0; i < ai->value.dim; i++) - { Expression *e = (Expression *)index.data[i]; - if (e) - e = e->syntaxCopy(); - ai->index.data[i] = e; - - Initializer *init = (Initializer *)value.data[i]; - init = init->syntaxCopy(); - ai->value.data[i] = init; - } - return ai; -} - -void ArrayInitializer::addInit(Expression *index, Initializer *value) -{ - this->index.push(index); - this->value.push(value); - dim = 0; - type = NULL; -} - -Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) -{ unsigned i; - unsigned length; - - //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); - if (sem) // if semantic() already run - return this; - sem = 1; - type = t; - t = t->toBasetype(); - switch (t->ty) - { - case Tpointer: - case Tsarray: - case Tarray: - break; - - default: - error(loc, "cannot use array to initialize %s", type->toChars()); - return this; - } - - length = 0; - for (i = 0; i < index.dim; i++) - { Expression *idx; - Initializer *val; - - idx = (Expression *)index.data[i]; - if (idx) - { idx = idx->semantic(sc); - idx = idx->optimize(WANTvalue | WANTinterpret); - index.data[i] = (void *)idx; - length = idx->toInteger(); - } - - val = (Initializer *)value.data[i]; - val = val->semantic(sc, t->nextOf()); - value.data[i] = (void *)val; - length++; - if (length == 0) - error(loc, "array dimension overflow"); - if (length > dim) - dim = length; - } - unsigned long amax = 0x80000000; - if ((unsigned long) dim * t->nextOf()->size() >= amax) - error(loc, "array dimension %u exceeds max of %ju", dim, amax / t->nextOf()->size()); - return this; -} - -/******************************** - * If possible, convert array initializer to array literal. - */ - -Expression *ArrayInitializer::toExpression() -{ Expressions *elements; - Expression *e; - - //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); - //static int i; if (++i == 2) halt(); - - size_t edim; - Type *t = NULL; - if (type) - { - t = type->toBasetype(); - switch (t->ty) - { - case Tsarray: - edim = ((TypeSArray *)t)->dim->toInteger(); - break; - - case Tpointer: - case Tarray: - edim = dim; - break; - - default: - assert(0); - } - } - else - { - edim = value.dim; - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index.data[i]) - j = ((Expression *)index.data[i])->toInteger(); - if (j >= edim) - edim = j + 1; - } - } - - elements = new Expressions(); - elements->setDim(edim); - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index.data[i]) - j = ((Expression *)index.data[i])->toInteger(); - assert(j < edim); - Initializer *iz = (Initializer *)value.data[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - { - goto Lno; - } - elements->data[j] = ex; - } - - /* Fill in any missing elements with the default initializer - */ - { - Expression *init = NULL; - for (size_t i = 0; i < edim; i++) - { - if (!elements->data[i]) - { - if (!type) - goto Lno; - if (!init) - init = ((TypeNext *)t)->next->defaultInit(); - elements->data[i] = init; - } - } - - Expression *e = new ArrayLiteralExp(loc, elements); - e->type = type; - return e; - } - -Lno: - delete elements; - error(loc, "array initializers as expressions are not allowed"); - return new ErrorExp(); -} - - -/******************************** - * If possible, convert array initializer to associative array initializer. - */ - -Initializer *ArrayInitializer::toAssocArrayInitializer() -{ Expressions *keys; - Expressions *values; - Expression *e; - - //printf("ArrayInitializer::toAssocArrayInitializer()\n"); - //static int i; if (++i == 2) halt(); - keys = new Expressions(); - keys->setDim(value.dim); - values = new Expressions(); - values->setDim(value.dim); - - for (size_t i = 0; i < value.dim; i++) - { - e = (Expression *)index.data[i]; - if (!e) - goto Lno; - keys->data[i] = (void *)e; - - Initializer *iz = (Initializer *)value.data[i]; - if (!iz) - goto Lno; - e = iz->toExpression(); - if (!e) - goto Lno; - values->data[i] = (void *)e; - } - e = new AssocArrayLiteralExp(loc, keys, values); - return new ExpInitializer(loc, e); - -Lno: - delete keys; - delete values; - error(loc, "not an associative array initializer"); - return this; -} - - -Type *ArrayInitializer::inferType(Scope *sc) -{ - //printf("ArrayInitializer::inferType() %s\n", toChars()); - type = Type::terror; - for (size_t i = 0; i < value.dim; i++) - { - if (index.data[i]) - goto Lno; - } - for (size_t i = 0; i < value.dim; i++) - { - Initializer *iz = (Initializer *)value.data[i]; - if (iz) - { Type *t = iz->inferType(sc); - if (i == 0) - { t = new TypeSArray(t, new IntegerExp(value.dim)); - t = t->semantic(loc, sc); - type = t; - } - } - } - return type; - -Lno: - error(loc, "cannot infer type from this array initializer"); - return Type::terror; -} - - -void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writebyte('['); - for (int i = 0; i < index.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Expression *ex = (Expression *)index.data[i]; - if (ex) - { - ex->toCBuffer(buf, hgs); - buf->writebyte(':'); - } - Initializer *iz = (Initializer *)value.data[i]; - if (iz) - iz->toCBuffer(buf, hgs); - } - buf->writebyte(']'); -} - - -/********************************** ExpInitializer ************************************/ - -ExpInitializer::ExpInitializer(Loc loc, Expression *exp) - : Initializer(loc) -{ - this->exp = exp; -} - -Initializer *ExpInitializer::syntaxCopy() -{ - return new ExpInitializer(loc, exp->syntaxCopy()); -} - -Initializer *ExpInitializer::semantic(Scope *sc, Type *t) -{ - //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - Type *tb = t->toBasetype(); - - /* Look for case of initializing a static array with a too-short - * string literal, such as: - * char[5] foo = "abc"; - * Allow this by doing an explicit cast, which will lengthen the string - * literal. - */ - if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) - { StringExp *se = (StringExp *)exp; - - if (!se->committed && se->type->ty == Tsarray && - ((TypeSArray *)se->type)->dim->toInteger() < - ((TypeSArray *)t)->dim->toInteger()) - { - exp = se->castTo(sc, t); - goto L1; - } - } - - // Look for the case of statically initializing an array - // with a single member. - if (tb->ty == Tsarray && - !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && - exp->implicitConvTo(tb->nextOf()) - ) - { - t = tb->nextOf(); - } - - exp = exp->implicitCastTo(sc, t); -L1: - exp = exp->optimize(WANTvalue | WANTinterpret); - //printf("-ExpInitializer::semantic(): "); exp->print(); - return this; -} - -Type *ExpInitializer::inferType(Scope *sc) -{ - //printf("ExpInitializer::inferType() %s\n", toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - - // Give error for overloaded function addresses - if (exp->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)exp; - if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) - exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); - } - - Type *t = exp->type; - if (!t) - t = Initializer::inferType(sc); - return t; -} - -Expression *ExpInitializer::toExpression() -{ - return exp; -} - - -void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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 +#include + +#include "mars.h" +#include "init.h" +#include "expression.h" +#include "statement.h" +#include "identifier.h" +#include "declaration.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "hdrgen.h" + +/********************************** Initializer *******************************/ + +Initializer::Initializer(Loc loc) +{ + this->loc = loc; +} + +Initializer *Initializer::syntaxCopy() +{ + return this; +} + +Initializer *Initializer::semantic(Scope *sc, Type *t) +{ + return this; +} + +Type *Initializer::inferType(Scope *sc) +{ + error(loc, "cannot infer type from initializer"); + return Type::terror; +} + +Initializers *Initializer::arraySyntaxCopy(Initializers *ai) +{ Initializers *a = NULL; + + if (ai) + { + a = new Initializers(); + a->setDim(ai->dim); + for (int i = 0; i < a->dim; i++) + { Initializer *e = (Initializer *)ai->data[i]; + + e = e->syntaxCopy(); + a->data[i] = e; + } + } + return a; +} + +char *Initializer::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +/********************************** VoidInitializer ***************************/ + +VoidInitializer::VoidInitializer(Loc loc) + : Initializer(loc) +{ + type = NULL; +} + + +Initializer *VoidInitializer::syntaxCopy() +{ + return new VoidInitializer(loc); +} + + +Initializer *VoidInitializer::semantic(Scope *sc, Type *t) +{ + //printf("VoidInitializer::semantic(t = %p)\n", t); + type = t; + return this; +} + + +Expression *VoidInitializer::toExpression() +{ + error(loc, "void initializer has no value"); + return new IntegerExp(0); +} + + +void VoidInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("void"); +} + + +/********************************** StructInitializer *************************/ + +StructInitializer::StructInitializer(Loc loc) + : Initializer(loc) +{ + ad = NULL; +} + +Initializer *StructInitializer::syntaxCopy() +{ + StructInitializer *ai = new StructInitializer(loc); + + assert(field.dim == value.dim); + ai->field.setDim(field.dim); + ai->value.setDim(value.dim); + for (int i = 0; i < field.dim; i++) + { + ai->field.data[i] = field.data[i]; + + Initializer *init = (Initializer *)value.data[i]; + init = init->syntaxCopy(); + ai->value.data[i] = init; + } + return ai; +} + +void StructInitializer::addInit(Identifier *field, Initializer *value) +{ + //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); + this->field.push(field); + this->value.push(value); +} + +Initializer *StructInitializer::semantic(Scope *sc, Type *t) +{ + int errors = 0; + + //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); + vars.setDim(field.dim); + t = t->toBasetype(); + if (t->ty == Tstruct) + { + unsigned fieldi = 0; + + TypeStruct *ts = (TypeStruct *)t; + ad = ts->sym; + if (ad->ctor) + error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", + ad->kind(), ad->toChars(), ad->toChars()); + for (size_t i = 0; i < field.dim; i++) + { + Identifier *id = (Identifier *)field.data[i]; + Initializer *val = (Initializer *)value.data[i]; + Dsymbol *s; + VarDeclaration *v; + + if (id == NULL) + { + if (fieldi >= ad->fields.dim) + { error(loc, "too many initializers for %s", ad->toChars()); + field.remove(i); + i--; + continue; + } + else + { + s = (Dsymbol *)ad->fields.data[fieldi]; + } + } + else + { + //s = ad->symtab->lookup(id); + s = ad->search(loc, id, 0); + if (!s) + { + error(loc, "'%s' is not a member of '%s'", id->toChars(), t->toChars()); + continue; + } + + // Find out which field index it is + for (fieldi = 0; 1; fieldi++) + { + if (fieldi >= ad->fields.dim) + { + s->error("is not a per-instance initializable field"); + break; + } + if (s == (Dsymbol *)ad->fields.data[fieldi]) + break; + } + } + if (s && (v = s->isVarDeclaration()) != NULL) + { + val = val->semantic(sc, v->type); + value.data[i] = (void *)val; + vars.data[i] = (void *)v; + } + else + { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); + errors = 1; + } + fieldi++; + } + } + else if (t->ty == Tdelegate && value.dim == 0) + { /* Rewrite as empty delegate literal { } + */ + Parameters *arguments = new Parameters; + Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); + FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); + fd->fbody = new CompoundStatement(loc, new Statements()); + fd->endloc = loc; + Expression *e = new FuncExp(loc, fd); + ExpInitializer *ie = new ExpInitializer(loc, e); + return ie->semantic(sc, t); + } + else + { + error(loc, "a struct is not a valid initializer for a %s", t->toChars()); + errors = 1; + } + if (errors) + { + field.setDim(0); + value.setDim(0); + vars.setDim(0); + } + return this; +} + + +/*************************************** + * This works by transforming a struct initializer into + * a struct literal. In the future, the two should be the + * same thing. + */ +Expression *StructInitializer::toExpression() +{ Expression *e; + + //printf("StructInitializer::toExpression() %s\n", toChars()); + if (!ad) // if fwd referenced + { + return NULL; + } + StructDeclaration *sd = ad->isStructDeclaration(); + if (!sd) + return NULL; + Expressions *elements = new Expressions(); + for (size_t i = 0; i < value.dim; i++) + { + if (field.data[i]) + goto Lno; + Initializer *iz = (Initializer *)value.data[i]; + if (!iz) + goto Lno; + Expression *ex = iz->toExpression(); + if (!ex) + goto Lno; + elements->push(ex); + } + e = new StructLiteralExp(loc, sd, elements); + e->type = sd->type; + return e; + +Lno: + delete elements; + //error(loc, "struct initializers as expressions are not allowed"); + return NULL; +} + + +void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + //printf("StructInitializer::toCBuffer()\n"); + buf->writebyte('{'); + for (int i = 0; i < field.dim; i++) + { + if (i > 0) + buf->writebyte(','); + Identifier *id = (Identifier *)field.data[i]; + if (id) + { + buf->writestring(id->toChars()); + buf->writebyte(':'); + } + Initializer *iz = (Initializer *)value.data[i]; + if (iz) + iz->toCBuffer(buf, hgs); + } + buf->writebyte('}'); +} + +/********************************** ArrayInitializer ************************************/ + +ArrayInitializer::ArrayInitializer(Loc loc) + : Initializer(loc) +{ + dim = 0; + type = NULL; + sem = 0; +} + +Initializer *ArrayInitializer::syntaxCopy() +{ + //printf("ArrayInitializer::syntaxCopy()\n"); + + ArrayInitializer *ai = new ArrayInitializer(loc); + + assert(index.dim == value.dim); + ai->index.setDim(index.dim); + ai->value.setDim(value.dim); + for (int i = 0; i < ai->value.dim; i++) + { Expression *e = (Expression *)index.data[i]; + if (e) + e = e->syntaxCopy(); + ai->index.data[i] = e; + + Initializer *init = (Initializer *)value.data[i]; + init = init->syntaxCopy(); + ai->value.data[i] = init; + } + return ai; +} + +void ArrayInitializer::addInit(Expression *index, Initializer *value) +{ + this->index.push(index); + this->value.push(value); + dim = 0; + type = NULL; +} + +Initializer *ArrayInitializer::semantic(Scope *sc, Type *t) +{ unsigned i; + unsigned length; + const unsigned amax = 0x80000000; + + //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); + if (sem) // if semantic() already run + return this; + sem = 1; + type = t; + t = t->toBasetype(); + switch (t->ty) + { + case Tpointer: + case Tsarray: + case Tarray: + break; + + default: + error(loc, "cannot use array to initialize %s", type->toChars()); + goto Lerr; + } + + length = 0; + for (i = 0; i < index.dim; i++) + { + Expression *idx = (Expression *)index.data[i]; + if (idx) + { idx = idx->semantic(sc); + idx = idx->optimize(WANTvalue | WANTinterpret); + index.data[i] = (void *)idx; + length = idx->toInteger(); + } + + Initializer *val = (Initializer *)value.data[i]; + val = val->semantic(sc, t->nextOf()); + value.data[i] = (void *)val; + length++; + if (length == 0) + { error(loc, "array dimension overflow"); + goto Lerr; + } + if (length > dim) + dim = length; + } + if (t->ty == Tsarray) + { + dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); + if (dim > edim) + { + error(loc, "array initializer has %u elements, but array length is %jd", dim, edim); + goto Lerr; + } + } + + if ((unsigned long) dim * t->nextOf()->size() >= amax) + { error(loc, "array dimension %u exceeds max of %u", dim, amax / t->nextOf()->size()); + goto Lerr; + } + return this; + +Lerr: + return new ExpInitializer(loc, new ErrorExp()); +} + +/******************************** + * If possible, convert array initializer to array literal. + * Otherwise return NULL. + */ + +Expression *ArrayInitializer::toExpression() +{ Expressions *elements; + Expression *e; + + //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); + //static int i; if (++i == 2) halt(); + + size_t edim; + Type *t = NULL; + if (type) + { + if (type == Type::terror) + return new ErrorExp(); + + t = type->toBasetype(); + switch (t->ty) + { + case Tsarray: + edim = ((TypeSArray *)t)->dim->toInteger(); + break; + + case Tpointer: + case Tarray: + edim = dim; + break; + + default: + assert(0); + } + } + else + { + edim = value.dim; + for (size_t i = 0, j = 0; i < value.dim; i++, j++) + { + if (index.data[i]) + j = ((Expression *)index.data[i])->toInteger(); + if (j >= edim) + edim = j + 1; + } + } + + elements = new Expressions(); + elements->setDim(edim); + elements->zero(); + for (size_t i = 0, j = 0; i < value.dim; i++, j++) + { + if (index.data[i]) + j = ((Expression *)index.data[i])->toInteger(); + assert(j < edim); + Initializer *iz = (Initializer *)value.data[i]; + if (!iz) + goto Lno; + Expression *ex = iz->toExpression(); + if (!ex) + { + goto Lno; + } + elements->data[j] = ex; + } + + /* Fill in any missing elements with the default initializer + */ + { + Expression *init = NULL; + for (size_t i = 0; i < edim; i++) + { + if (!elements->data[i]) + { + if (!type) + goto Lno; + if (!init) + init = ((TypeNext *)t)->next->defaultInit(); + elements->data[i] = init; + } + } + + Expression *e = new ArrayLiteralExp(loc, elements); + e->type = type; + return e; + } + +Lno: + return NULL; +} + + +/******************************** + * If possible, convert array initializer to associative array initializer. + */ + +Expression *ArrayInitializer::toAssocArrayLiteral() +{ + Expression *e; + + //printf("ArrayInitializer::toAssocArrayInitializer()\n"); + //static int i; if (++i == 2) halt(); + Expressions *keys = new Expressions(); + keys->setDim(value.dim); + Expressions *values = new Expressions(); + values->setDim(value.dim); + + for (size_t i = 0; i < value.dim; i++) + { + e = (Expression *)index.data[i]; + if (!e) + goto Lno; + keys->data[i] = (void *)e; + + Initializer *iz = (Initializer *)value.data[i]; + if (!iz) + goto Lno; + e = iz->toExpression(); + if (!e) + goto Lno; + values->data[i] = (void *)e; + } + e = new AssocArrayLiteralExp(loc, keys, values); + return e; + +Lno: + delete keys; + delete values; + error(loc, "not an associative array initializer"); + return new ErrorExp(); +} + +int ArrayInitializer::isAssociativeArray() +{ + for (size_t i = 0; i < value.dim; i++) + { + if (index.data[i]) + return 1; + } + return 0; +} + +Type *ArrayInitializer::inferType(Scope *sc) +{ + //printf("ArrayInitializer::inferType() %s\n", toChars()); + assert(0); + return NULL; +#if 0 + type = Type::terror; + for (size_t i = 0; i < value.dim; i++) + { + if (index.data[i]) + goto Laa; + } + for (size_t i = 0; i < value.dim; i++) + { + Initializer *iz = (Initializer *)value.data[i]; + if (iz) + { Type *t = iz->inferType(sc); + if (i == 0) + { /* BUG: This gets the type from the first element. + * Fix to use all the elements to figure out the type. + */ + t = new TypeSArray(t, new IntegerExp(value.dim)); + t = t->semantic(loc, sc); + type = t; + } + } + } + return type; + +Laa: + /* It's possibly an associative array initializer. + * BUG: inferring type from first member. + */ + Initializer *iz = (Initializer *)value.data[0]; + Expression *indexinit = (Expression *)index.data[0]; + if (iz && indexinit) + { Type *t = iz->inferType(sc); + indexinit = indexinit->semantic(sc); + Type *indext = indexinit->type; + t = new TypeAArray(t, indext); + type = t->semantic(loc, sc); + } + else + error(loc, "cannot infer type from this array initializer"); + return type; +#endif +} + + +void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writebyte('['); + for (int i = 0; i < index.dim; i++) + { + if (i > 0) + buf->writebyte(','); + Expression *ex = (Expression *)index.data[i]; + if (ex) + { + ex->toCBuffer(buf, hgs); + buf->writebyte(':'); + } + Initializer *iz = (Initializer *)value.data[i]; + if (iz) + iz->toCBuffer(buf, hgs); + } + buf->writebyte(']'); +} + + +/********************************** ExpInitializer ************************************/ + +ExpInitializer::ExpInitializer(Loc loc, Expression *exp) + : Initializer(loc) +{ + this->exp = exp; +} + +Initializer *ExpInitializer::syntaxCopy() +{ + return new ExpInitializer(loc, exp->syntaxCopy()); +} + +Initializer *ExpInitializer::semantic(Scope *sc, Type *t) +{ + //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + Type *tb = t->toBasetype(); + + /* Look for case of initializing a static array with a too-short + * string literal, such as: + * char[5] foo = "abc"; + * Allow this by doing an explicit cast, which will lengthen the string + * literal. + */ + if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) + { StringExp *se = (StringExp *)exp; + + if (!se->committed && se->type->ty == Tsarray && + ((TypeSArray *)se->type)->dim->toInteger() < + ((TypeSArray *)t)->dim->toInteger()) + { + exp = se->castTo(sc, t); + goto L1; + } + } + + // Look for the case of statically initializing an array + // with a single member. + if (tb->ty == Tsarray && + !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && + exp->implicitConvTo(tb->nextOf()) + ) + { + t = tb->nextOf(); + } + + exp = exp->implicitCastTo(sc, t); +L1: + exp = exp->optimize(WANTvalue | WANTinterpret); + //printf("-ExpInitializer::semantic(): "); exp->print(); + return this; +} + +Type *ExpInitializer::inferType(Scope *sc) +{ + //printf("ExpInitializer::inferType() %s\n", toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + + // Give error for overloaded function addresses + if (exp->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)exp; + if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) + exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); + } + + // Give error for overloaded function addresses + if (exp->op == TOKdelegate) + { DelegateExp *se = (DelegateExp *)exp; + if ( + se->func->isFuncDeclaration() && + !se->func->isFuncDeclaration()->isUnique()) + exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); + } + + Type *t = exp->type; + if (!t) + t = Initializer::inferType(sc); + return t; +} + +Expression *ExpInitializer::toExpression() +{ + return exp; +} + + +void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + exp->toCBuffer(buf, hgs); +} + + + diff --git a/dmd2/init.h b/dmd2/init.h index d7a4bcf0..3ccbf68a 100644 --- a/dmd2/init.h +++ b/dmd2/init.h @@ -1,139 +1,140 @@ - -// 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. - -#ifndef INIT_H -#define INIT_H - -#include "root.h" - -#include "mars.h" -#include "arraytypes.h" - -struct Identifier; -struct Expression; -struct Scope; -struct Type; -struct dt_t; -struct AggregateDeclaration; -struct VoidInitializer; -struct StructInitializer; -struct ArrayInitializer; -struct ExpInitializer; -#ifdef _DH -struct HdrGenState; -#endif - -struct Initializer : Object -{ - Loc loc; - - Initializer(Loc loc); - virtual Initializer *syntaxCopy(); - virtual Initializer *semantic(Scope *sc, Type *t); - virtual Type *inferType(Scope *sc); - virtual Expression *toExpression() = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - char *toChars(); - - static Initializers *arraySyntaxCopy(Initializers *ai); - -#if IN_DMD - virtual dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return NULL; } - virtual StructInitializer *isStructInitializer() { return NULL; } - virtual ArrayInitializer *isArrayInitializer() { return NULL; } - virtual ExpInitializer *isExpInitializer() { return NULL; } -}; - -struct VoidInitializer : Initializer -{ - Type *type; // type that this will initialize to - - VoidInitializer(Loc loc); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return this; } -}; - -struct StructInitializer : Initializer -{ - Identifiers field; // of Identifier *'s - Initializers value; // parallel array of Initializer *'s - - Array vars; // parallel array of VarDeclaration *'s - AggregateDeclaration *ad; // which aggregate this is for - - StructInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - StructInitializer *isStructInitializer() { return this; } -}; - -struct ArrayInitializer : Initializer -{ - Expressions index; // indices - Initializers value; // of Initializer *'s - unsigned dim; // length of array being initialized - Type *type; // type that array will be used to initialize - int sem; // !=0 if semantic() is run - - ArrayInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t); - Type *inferType(Scope *sc); - Expression *toExpression(); - Initializer *toAssocArrayInitializer(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); - dt_t *toDtBit(); // for bit arrays -#endif - - ArrayInitializer *isArrayInitializer() { return this; } -}; - -struct ExpInitializer : Initializer -{ - Expression *exp; - - ExpInitializer(Loc loc, Expression *exp); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t); - Type *inferType(Scope *sc); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual ExpInitializer *isExpInitializer() { return this; } -}; - -#endif + +// 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. + +#ifndef INIT_H +#define INIT_H + +#include "root.h" + +#include "mars.h" +#include "arraytypes.h" + +struct Identifier; +struct Expression; +struct Scope; +struct Type; +struct dt_t; +struct AggregateDeclaration; +struct VoidInitializer; +struct StructInitializer; +struct ArrayInitializer; +struct ExpInitializer; +#ifdef _DH +struct HdrGenState; +#endif + +struct Initializer : Object +{ + Loc loc; + + Initializer(Loc loc); + virtual Initializer *syntaxCopy(); + virtual Initializer *semantic(Scope *sc, Type *t); + virtual Type *inferType(Scope *sc); + virtual Expression *toExpression() = 0; + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; + char *toChars(); + + static Initializers *arraySyntaxCopy(Initializers *ai); + +#if IN_DMD + virtual dt_t *toDt(); +#endif + + virtual VoidInitializer *isVoidInitializer() { return NULL; } + virtual StructInitializer *isStructInitializer() { return NULL; } + virtual ArrayInitializer *isArrayInitializer() { return NULL; } + virtual ExpInitializer *isExpInitializer() { return NULL; } +}; + +struct VoidInitializer : Initializer +{ + Type *type; // type that this will initialize to + + VoidInitializer(Loc loc); + Initializer *syntaxCopy(); + Initializer *semantic(Scope *sc, Type *t); + Expression *toExpression(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_DMD + dt_t *toDt(); +#endif + + virtual VoidInitializer *isVoidInitializer() { return this; } +}; + +struct StructInitializer : Initializer +{ + Identifiers field; // of Identifier *'s + Initializers value; // parallel array of Initializer *'s + + Array vars; // parallel array of VarDeclaration *'s + AggregateDeclaration *ad; // which aggregate this is for + + StructInitializer(Loc loc); + Initializer *syntaxCopy(); + void addInit(Identifier *field, Initializer *value); + Initializer *semantic(Scope *sc, Type *t); + Expression *toExpression(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_DMD + dt_t *toDt(); +#endif + + StructInitializer *isStructInitializer() { return this; } +}; + +struct ArrayInitializer : Initializer +{ + Expressions index; // indices + Initializers value; // of Initializer *'s + unsigned dim; // length of array being initialized + Type *type; // type that array will be used to initialize + int sem; // !=0 if semantic() is run + + ArrayInitializer(Loc loc); + Initializer *syntaxCopy(); + void addInit(Expression *index, Initializer *value); + Initializer *semantic(Scope *sc, Type *t); + int isAssociativeArray(); + Type *inferType(Scope *sc); + Expression *toExpression(); + Expression *toAssocArrayLiteral(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_DMD + dt_t *toDt(); + dt_t *toDtBit(); // for bit arrays +#endif + + ArrayInitializer *isArrayInitializer() { return this; } +}; + +struct ExpInitializer : Initializer +{ + Expression *exp; + + ExpInitializer(Loc loc, Expression *exp); + Initializer *syntaxCopy(); + Initializer *semantic(Scope *sc, Type *t); + Type *inferType(Scope *sc); + Expression *toExpression(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_DMD + dt_t *toDt(); +#endif + + virtual ExpInitializer *isExpInitializer() { return this; } +}; + +#endif diff --git a/dmd2/inline.c b/dmd2/inline.c index 42f1f6c3..8c071521 100644 --- a/dmd2/inline.c +++ b/dmd2/inline.c @@ -1,1535 +1,1622 @@ - -// Copyright (c) 1999-2009 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. - -// Routines to perform function inlining - -#define LOG 0 - -#include -#include -#include - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" - -/* ========== Compute cost of inlining =============== */ - -/* Walk trees to determine if inlining can be done, and if so, - * if it is too complex to be worth inlining or not. - */ - -struct InlineCostState -{ - int nested; - int hasthis; - int hdrscan; // !=0 if inline scan for 'header' content - FuncDeclaration *fd; -}; - -const int COST_MAX = 250; - -int Statement::inlineCost(InlineCostState *ics) -{ - return COST_MAX; // default is we can't inline it -} - -int ExpStatement::inlineCost(InlineCostState *ics) -{ - return exp ? exp->inlineCost(ics) : 0; -} - -int CompoundStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - cost += s->inlineCost(ics); - if (cost >= COST_MAX) - break; - } - } - return cost; -} - -int UnrolledLoopStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - cost += s->inlineCost(ics); - if (cost >= COST_MAX) - break; - } - } - return cost; -} - -int IfStatement::inlineCost(InlineCostState *ics) -{ - int cost; - -#if !IN_LLVM - /* Can't declare variables inside ?: expressions, so - * we cannot inline if a variable is declared. - */ - if (arg) - return COST_MAX; -#endif - - cost = condition->inlineCost(ics); - -#if !IN_LLVM - /* Specifically allow: - * if (condition) - * return exp1; - * else - * return exp2; - * Otherwise, we can't handle return statements nested in if's. - */ - - if (elsebody && ifbody && - ifbody->isReturnStatement() && - elsebody->isReturnStatement()) - { - cost += ifbody->inlineCost(ics); - cost += elsebody->inlineCost(ics); - //printf("cost = %d\n", cost); - } - else -#endif - { - ics->nested += 1; - if (ifbody) - cost += ifbody->inlineCost(ics); - if (elsebody) - cost += elsebody->inlineCost(ics); - ics->nested -= 1; - } - return cost; -} - -int ReturnStatement::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - // Can't handle return statements nested in if's - if (ics->nested) - return COST_MAX; -#endif - return exp ? exp->inlineCost(ics) : 0; -} - -/* -------------------------- */ - -int arrayInlineCost(InlineCostState *ics, Array *arguments) -{ int cost = 0; - - if (arguments) - { - for (int i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e) - cost += e->inlineCost(ics); - } - } - return cost; -} - -int Expression::inlineCost(InlineCostState *ics) -{ - return 1; -} - -int VarExp::inlineCost(InlineCostState *ics) -{ - //printf("VarExp::inlineCost() %s\n", toChars()); - return 1; -} - -int ThisExp::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - FuncDeclaration *fd = ics->fd; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int SuperExp::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - FuncDeclaration *fd = ics->fd; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int TupleExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, exps); -} - -int ArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, elements); -} - -int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); -} - -int StructLiteralExp::inlineCost(InlineCostState *ics) -{ - return 1 + arrayInlineCost(ics, elements); -} - -int FuncExp::inlineCost(InlineCostState *ics) -{ - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - // Right now, this makes the function be output to the .obj file twice. - return COST_MAX; -} - -int DelegateExp::inlineCost(InlineCostState *ics) -{ - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - return COST_MAX; -} - -int DeclarationExp::inlineCost(InlineCostState *ics) -{ int cost = 0; - VarDeclaration *vd; - - //printf("DeclarationExp::inlineCost()\n"); - vd = declaration->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { -#if 1 - return COST_MAX; // finish DeclarationExp::doInline -#else - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (Object *)td->objects->data[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - return COST_MAX; - Expression *eo = (Expression *)o; - if (eo->op != TOKdsymbol) - return COST_MAX; - } - return td->objects->dim; -#endif - } - // This breaks on LDC too, since nested static variables have internal - // linkage and thus can't be referenced from other objects. - if (!ics->hdrscan && vd->isDataseg()) - return COST_MAX; - cost += 1; - - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { - cost += ie->exp->inlineCost(ics); - } - } - } - - // These can contain functions, which when copied, get output twice. - // These break on LDC too, since nested static variables and functions have - // internal linkage and thus can't be referenced from other objects. - if (declaration->isStructDeclaration() || - declaration->isClassDeclaration() || - declaration->isFuncDeclaration() || - declaration->isTypedefDeclaration() || - declaration->isTemplateMixin()) - return COST_MAX; - - //printf("DeclarationExp::inlineCost('%s')\n", toChars()); - return cost; -} - -int UnaExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics); -} - -int AssertExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); -} - -int BinExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); -} - -int CallExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - -int SliceExp::inlineCost(InlineCostState *ics) -{ int cost; - - cost = 1 + e1->inlineCost(ics); - if (lwr) - cost += lwr->inlineCost(ics); - if (upr) - cost += upr->inlineCost(ics); - return cost; -} - -int ArrayExp::inlineCost(InlineCostState *ics) -{ - return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); -} - - -int CondExp::inlineCost(InlineCostState *ics) -{ - return 1 + - e1->inlineCost(ics) + - e2->inlineCost(ics) + - econd->inlineCost(ics); -} - - -/* ======================== Perform the inlining ============================== */ - -/* Inlining is done by: - * o Converting to an Expression - * o Copying the trees of the function to be inlined - * o Renaming the variables - */ - -struct InlineDoState -{ - VarDeclaration *vthis; - Array from; // old Dsymbols - Array to; // parallel array of new Dsymbols - Dsymbol *parent; // new parent -}; - -Expression *Statement::doInline(InlineDoState *ids) -{ - assert(0); - return NULL; // default is we can't inline it -} - -Expression *ExpStatement::doInline(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); -#endif - return exp ? exp->doInline(ids) : NULL; -} - -Expression *CompoundStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("CompoundStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - - } - } - return e; -} - -Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - } - } - return e; -} - -Expression *IfStatement::doInline(InlineDoState *ids) -{ - Expression *econd; - Expression *e1; - Expression *e2; - Expression *e; - - assert(!arg); - econd = condition->doInline(ids); - assert(econd); - if (ifbody) - e1 = ifbody->doInline(ids); - else - e1 = NULL; - if (elsebody) - e2 = elsebody->doInline(ids); - else - e2 = NULL; - if (e1 && e2) - { - e = new CondExp(econd->loc, econd, e1, e2); - e->type = e1->type; - } - else if (e1) - { - e = new AndAndExp(econd->loc, econd, e1); - e->type = Type::tvoid; - } - else if (e2) - { - e = new OrOrExp(econd->loc, econd, e2); - e->type = Type::tvoid; - } - else - { - e = econd; - } - return e; -} - -Expression *ReturnStatement::doInline(InlineDoState *ids) -{ - //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); - return exp ? exp->doInline(ids) : 0; -} - -/* --------------------------------------------------------------- */ - -/****************************** - * Perform doInline() on an array of Expressions. - */ - -Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) -{ Expressions *newa = NULL; - - if (a) - { - newa = new Expressions(); - newa->setDim(a->dim); - - for (int i = 0; i < a->dim; i++) - { Expression *e = (Expression *)a->data[i]; - - if (e) - { - e = e->doInline(ids); - newa->data[i] = (void *)e; - } - } - } - return newa; -} - -Expression *Expression::doInline(InlineDoState *ids) -{ - //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); - return copy(); -} - -Expression *SymOffExp::doInline(InlineDoState *ids) -{ - int i; - - //printf("SymOffExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) - { - if (var == (Declaration *)ids->from.data[i]) - { - SymOffExp *se = (SymOffExp *)copy(); - - se->var = (Declaration *)ids->to.data[i]; - return se; - } - } - return this; -} - -Expression *VarExp::doInline(InlineDoState *ids) -{ - int i; - - //printf("VarExp::doInline(%s)\n", toChars()); - for (i = 0; i < ids->from.dim; i++) - { - if (var == (Declaration *)ids->from.data[i]) - { - VarExp *ve = (VarExp *)copy(); - - ve->var = (Declaration *)ids->to.data[i]; - return ve; - } - } - return this; -} - -Expression *ThisExp::doInline(InlineDoState *ids) -{ - //if (!ids->vthis) - //error("no 'this' when inlining %s", ids->parent->toChars()); - if (!ids->vthis) - { - return this; - } - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *SuperExp::doInline(InlineDoState *ids) -{ - assert(ids->vthis); - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *DeclarationExp::doInline(InlineDoState *ids) -{ DeclarationExp *de = (DeclarationExp *)copy(); - VarDeclaration *vd; - - //printf("DeclarationExp::doInline(%s)\n", toChars()); - vd = declaration->isVarDeclaration(); - if (vd) - { -#if 0 - // Need to figure this out before inlining can work for tuples - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; - assert(se->op == TOKdsymbol); - se->s; - } - return st->objects->dim; - } -#endif - if (vd->isStatic()) - ; - else - { - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - if (vd->init->isVoidInitializer()) - { - vto->init = new VoidInitializer(vd->init->loc); - } - else - { - Expression *e = vd->init->toExpression(); - assert(e); - vto->init = new ExpInitializer(e->loc, e->doInline(ids)); - } - } - de->declaration = (Dsymbol *) (void *)vto; - } - } - /* This needs work, like DeclarationExp::toElem(), if we are - * to handle TemplateMixin's. For now, we just don't inline them. - */ - return de; -} - -Expression *NewExp::doInline(InlineDoState *ids) -{ - //printf("NewExp::doInline(): %s\n", toChars()); - NewExp *ne = (NewExp *)copy(); - - if (thisexp) - ne->thisexp = thisexp->doInline(ids); - ne->newargs = arrayExpressiondoInline(ne->newargs, ids); - ne->arguments = arrayExpressiondoInline(ne->arguments, ids); - return ne; -} - -Expression *UnaExp::doInline(InlineDoState *ids) -{ - UnaExp *ue = (UnaExp *)copy(); - - ue->e1 = e1->doInline(ids); - return ue; -} - -Expression *AssertExp::doInline(InlineDoState *ids) -{ - AssertExp *ae = (AssertExp *)copy(); - - ae->e1 = e1->doInline(ids); - if (msg) - ae->msg = msg->doInline(ids); - return ae; -} - -Expression *BinExp::doInline(InlineDoState *ids) -{ - BinExp *be = (BinExp *)copy(); - - be->e1 = e1->doInline(ids); - be->e2 = e2->doInline(ids); - return be; -} - -Expression *CallExp::doInline(InlineDoState *ids) -{ - CallExp *ce; - - ce = (CallExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *IndexExp::doInline(InlineDoState *ids) -{ - IndexExp *are = (IndexExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - are->e2 = e2->doInline(ids); - return are; -} - - -Expression *SliceExp::doInline(InlineDoState *ids) -{ - SliceExp *are = (SliceExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - if (lwr) - are->lwr = lwr->doInline(ids); - if (upr) - are->upr = upr->doInline(ids); - return are; -} - - -Expression *TupleExp::doInline(InlineDoState *ids) -{ - TupleExp *ce; - - ce = (TupleExp *)copy(); - ce->exps = arrayExpressiondoInline(exps, ids); - return ce; -} - - -Expression *ArrayLiteralExp::doInline(InlineDoState *ids) -{ - ArrayLiteralExp *ce; - - ce = (ArrayLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) -{ - AssocArrayLiteralExp *ce; - - ce = (AssocArrayLiteralExp *)copy(); - ce->keys = arrayExpressiondoInline(keys, ids); - ce->values = arrayExpressiondoInline(values, ids); - return ce; -} - - -Expression *StructLiteralExp::doInline(InlineDoState *ids) -{ - StructLiteralExp *ce; - - ce = (StructLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *ArrayExp::doInline(InlineDoState *ids) -{ - ArrayExp *ce; - - ce = (ArrayExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *CondExp::doInline(InlineDoState *ids) -{ - CondExp *ce = (CondExp *)copy(); - - ce->econd = econd->doInline(ids); - ce->e1 = e1->doInline(ids); - ce->e2 = e2->doInline(ids); - return ce; -} - - -/* ========== Walk the parse trees, and inline expand functions ============= */ - -/* Walk the trees, looking for functions to inline. - * Inline any that can be. - */ - -struct InlineScanState -{ - FuncDeclaration *fd; // function being scanned -}; - -Statement *Statement::inlineScan(InlineScanState *iss) -{ - return this; -} - -Statement *ExpStatement::inlineScan(InlineScanState *iss) -{ -#if LOG - printf("ExpStatement::inlineScan(%s)\n", toChars()); -#endif - if (exp) - exp = exp->inlineScan(iss); - return this; -} - -Statement *CompoundStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - statements->data[i] = (void *)s->inlineScan(iss); - } - return this; -} - -Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - statements->data[i] = (void *)s->inlineScan(iss); - } - return this; -} - -Statement *ScopeStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -Statement *WhileStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - return this; -} - - -Statement *DoStatement::inlineScan(InlineScanState *iss) -{ - body = body ? body->inlineScan(iss) : NULL; - condition = condition->inlineScan(iss); - return this; -} - - -Statement *ForStatement::inlineScan(InlineScanState *iss) -{ - if (init) - init = init->inlineScan(iss); - if (condition) - condition = condition->inlineScan(iss); - if (increment) - increment = increment->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *ForeachStatement::inlineScan(InlineScanState *iss) -{ - aggr = aggr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -#if DMDV2 -Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) -{ - lwr = lwr->inlineScan(iss); - upr = upr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} -#endif - - -Statement *IfStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - if (ifbody) - ifbody = ifbody->inlineScan(iss); - if (elsebody) - elsebody = elsebody->inlineScan(iss); - return this; -} - - -Statement *SwitchStatement::inlineScan(InlineScanState *iss) -{ - //printf("SwitchStatement::inlineScan()\n"); - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - if (sdefault) - sdefault = (DefaultStatement *)sdefault->inlineScan(iss); - if (cases) - { - for (int i = 0; i < cases->dim; i++) - { Statement *s; - - s = (Statement *) cases->data[i]; - cases->data[i] = (void *)s->inlineScan(iss); - } - } - return this; -} - - -Statement *CaseStatement::inlineScan(InlineScanState *iss) -{ - //printf("CaseStatement::inlineScan()\n"); - exp = exp->inlineScan(iss); - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *DefaultStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *ReturnStatement::inlineScan(InlineScanState *iss) -{ - //printf("ReturnStatement::inlineScan()\n"); - if (exp) - { - exp = exp->inlineScan(iss); - } - return this; -} - - -Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *WithStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *TryCatchStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (catches) - { - for (int i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; - - if (c->handler) - c->handler = c->handler->inlineScan(iss); - } - } - return this; -} - - -Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (finalbody) - finalbody = finalbody->inlineScan(iss); - return this; -} - - -Statement *ThrowStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - return this; -} - - -Statement *VolatileStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *LabelStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -/* -------------------------- */ - -void arrayInlineScan(InlineScanState *iss, Array *arguments) -{ - if (arguments) - { - for (int i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - if (e) - { - e = e->inlineScan(iss); - arguments->data[i] = (void *)e; - } - } - } -} - -Expression *Expression::inlineScan(InlineScanState *iss) -{ - return this; -} - -void scanVar(Dsymbol *s, InlineScanState *iss) -{ - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; - assert(se->op == TOKdsymbol); - scanVar(se->s, iss); - } - } - else - { - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { -#if DMDV2 - if (vd->type) - { Type *tb = vd->type->toBasetype(); - if (tb->ty == Tstruct) - { StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { /* The problem here is that if the initializer is a - * function call that returns a struct S with a cpctor: - * S s = foo(); - * the postblit is done by the return statement in foo() - * in s2ir.c, the intermediate code generator. - * But, if foo() is inlined and now the code looks like: - * S s = x; - * the postblit is not there, because such assignments - * are rewritten as s.cpctor(&x) by the front end. - * So, the inlining won't get the postblit called. - * Work around by not inlining these cases. - * A proper fix would be to move all the postblit - * additions to the front end. - */ - return; - } - } - } -#endif - ie->exp = ie->exp->inlineScan(iss); - } - } - } - } -} - -Expression *DeclarationExp::inlineScan(InlineScanState *iss) -{ - //printf("DeclarationExp::inlineScan()\n"); - scanVar(declaration, iss); - return this; -} - -Expression *UnaExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - return this; -} - -Expression *AssertExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (msg) - msg = msg->inlineScan(iss); - return this; -} - -Expression *BinExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -Expression *CallExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("CallExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0)) - { - e = fd->doInline(iss, NULL, arguments); - } - } - else if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(1)) - { - if (dve->e1->op == TOKcall && - dve->e1->type->toBasetype()->ty == Tstruct) - { - /* To create ethis, we'll need to take the address - * of dve->e1, but this won't work if dve->e1 is - * a function call. - */ - ; - } - else - e = fd->doInline(iss, dve->e1, arguments); - } - } - - return e; -} - - -Expression *SliceExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (lwr) - lwr = lwr->inlineScan(iss); - if (upr) - upr = upr->inlineScan(iss); - return this; -} - - -Expression *TupleExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("TupleExp::inlineScan()\n"); - arrayInlineScan(iss, exps); - - return e; -} - - -Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("AssocArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, keys); - arrayInlineScan(iss, values); - - return e; -} - - -Expression *StructLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("StructLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *ArrayExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - return e; -} - - -Expression *CondExp::inlineScan(InlineScanState *iss) -{ - econd = econd->inlineScan(iss); - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -/* ========== =============== */ - -void FuncDeclaration::inlineScan() -{ - InlineScanState iss; - -#if LOG - printf("FuncDeclaration::inlineScan('%s')\n", toChars()); -#endif - memset(&iss, 0, sizeof(iss)); - iss.fd = this; - if (fbody) - { - inlineNest++; - fbody = fbody->inlineScan(&iss); - inlineNest--; - } -} - -int FuncDeclaration::canInline(int hasthis, int hdrscan) -{ - InlineCostState ics; - int cost; - -#define CANINLINE_LOG 0 - -#if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); -#endif - - if (needThis() && !hasthis) - return 0; - - if (inlineNest || (semanticRun < 3 && !hdrscan)) - { -#if CANINLINE_LOG - printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); -#endif - return 0; - } - - switch (inlineStatus) - { - case ILSyes: -#if CANINLINE_LOG - printf("\t1: yes %s\n", toChars()); -#endif - return 1; - - case ILSno: -#if CANINLINE_LOG - printf("\t1: no %s\n", toChars()); -#endif - return 0; - - case ILSuninitialized: - break; - - default: - assert(0); - } - - if (type) - { assert(type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)(type); -#if IN_LLVM - // LDC: Only extern(C) varargs count. - if (tf->linkage != LINKd) -#endif - if (tf->varargs == 1) // no variadic parameter lists - goto Lno; - - /* Don't inline a function that returns non-void, but has - * no return expression. - */ - if (tf->next && tf->next->ty != Tvoid && - !(hasReturnExp & 1) && - !hdrscan) - goto Lno; - } -#if !IN_LLVM - // LDC: Only extern(C) varargs count, and ctors use extern(D). - else - { CtorDeclaration *ctor = isCtorDeclaration(); - - if (ctor && ctor->varargs == 1) - goto Lno; - } -#endif - - if ( - !fbody || - !hdrscan && - ( -#if 0 - isCtorDeclaration() || // cannot because need to convert: - // return; - // to: - // return this; -#endif - isSynchronized() || - isImportedSymbol() || -#if !IN_LLVM -#if DMDV2 - closureVars.dim || // no nested references to this frame -#else - nestedFrameRef || // no nested references to this frame -#endif -#endif // !IN_LLVM - (isVirtual() && !isFinal()) - )) - { - goto Lno; - } - -#if !IN_LLVM - /* If any parameters are Tsarray's (which are passed by reference) - * or out parameters (also passed by reference), don't do inlining. - */ - if (parameters) - { - for (int i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - if (v->isOut() || v->isRef() || v->type->toBasetype()->ty == Tsarray) - goto Lno; - } - } -#endif - - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); -#if CANINLINE_LOG - printf("cost = %d\n", cost); -#endif - if (cost >= COST_MAX) - goto Lno; - -#if !IN_LLVM - if (!hdrscan) // Don't scan recursively for header content scan - inlineScan(); -#endif - -Lyes: - if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSyes; -#if CANINLINE_LOG - printf("\t2: yes %s\n", toChars()); -#endif - return 1; - -Lno: - if (!hdrscan) // Don't modify inlineStatus for header content scan - inlineStatus = ILSno; -#if CANINLINE_LOG - printf("\t2: no %s\n", toChars()); -#endif - return 0; -} - -Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) -{ - InlineDoState ids; - DeclarationExp *de; - Expression *e = NULL; - -#if LOG - printf("FuncDeclaration::doInline('%s')\n", toChars()); -#endif - - memset(&ids, 0, sizeof(ids)); - ids.parent = iss->fd; - - // Set up vthis - if (ethis) - { - VarDeclaration *vthis; - ExpInitializer *ei; - VarExp *ve; - -#if STRUCTTHISREF - if (ethis->type->ty == Tpointer) - { Type *t = ethis->type->nextOf(); - ethis = new PtrExp(ethis->loc, ethis); - ethis->type = t; - } - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - if (ethis->type->ty != Tclass) - vthis->storage_class = STCref; - else - vthis->storage_class = STCin; -#else - if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) - { - ethis = ethis->addressOf(NULL); - } - - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - vthis->storage_class = STCin; -#endif - vthis->linkage = LINKd; - vthis->parent = iss->fd; - - ve = new VarExp(vthis->loc, vthis); - ve->type = vthis->type; - - ei->exp = new AssignExp(vthis->loc, ve, ethis); - ei->exp->type = ve->type; -#if STRUCTTHISREF - if (ethis->type->ty != Tclass) - { /* This is a reference initialization, not a simple assignment. - */ - ei->exp->op = TOKconstruct; - } -#endif - - ids.vthis = vthis; - } - - // Set up parameters - if (ethis) - { - e = new DeclarationExp(0, ids.vthis); - e->type = Type::tvoid; - } - - if (arguments && arguments->dim) - { - assert(parameters->dim == arguments->dim); - - for (int i = 0; i < arguments->dim; i++) - { - VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; - VarDeclaration *vto; - Expression *arg = (Expression *)arguments->data[i]; - ExpInitializer *ei; - VarExp *ve; - - ei = new ExpInitializer(arg->loc, arg); - - vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); - vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); - vto->linkage = vfrom->linkage; - vto->parent = iss->fd; - //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); - //printf("vto->parent = '%s'\n", iss->fd->toChars()); - - ve = new VarExp(vto->loc, vto); - //ve->type = vto->type; - ve->type = arg->type; - - ei->exp = new AssignExp(vto->loc, ve, arg); - ei->exp->type = ve->type; -//ve->type->print(); -//arg->type->print(); -//ei->exp->print(); - - ids.from.push(vfrom); - ids.to.push(vto); - - de = new DeclarationExp(0, vto); - de->type = Type::tvoid; - - e = Expression::combine(e, de); - } - } - - inlineNest++; - Expression *eb = fbody->doInline(&ids); - inlineNest--; -//eb->type->print(); -//eb->print(); -//eb->dump(0); - return Expression::combine(e, eb); -} - - - + +// Copyright (c) 1999-2010 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. + +// Routines to perform function inlining + +#define LOG 0 + +#include +#include +#include + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "statement.h" +#include "mtype.h" +#include "scope.h" + +/* ========== Compute cost of inlining =============== */ + +/* Walk trees to determine if inlining can be done, and if so, + * if it is too complex to be worth inlining or not. + */ + +struct InlineCostState +{ + int nested; + int hasthis; + int hdrscan; // !=0 if inline scan for 'header' content + FuncDeclaration *fd; +}; + +const int COST_MAX = 250; + +int Statement::inlineCost(InlineCostState *ics) +{ + return COST_MAX; // default is we can't inline it +} + +int ExpStatement::inlineCost(InlineCostState *ics) +{ + return exp ? exp->inlineCost(ics) : 0; +} + +int CompoundStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int UnrolledLoopStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int IfStatement::inlineCost(InlineCostState *ics) +{ + int cost; + +#if !IN_LLVM + /* Can't declare variables inside ?: expressions, so + * we cannot inline if a variable is declared. + */ + if (arg) + return COST_MAX; +#endif + + cost = condition->inlineCost(ics); + +#if !IN_LLVM + /* Specifically allow: + * if (condition) + * return exp1; + * else + * return exp2; + * Otherwise, we can't handle return statements nested in if's. + */ + + if (elsebody && ifbody && + ifbody->isReturnStatement() && + elsebody->isReturnStatement()) + { + cost += ifbody->inlineCost(ics); + cost += elsebody->inlineCost(ics); + //printf("cost = %d\n", cost); + } + else +#endif + { + ics->nested += 1; + if (ifbody) + cost += ifbody->inlineCost(ics); + if (elsebody) + cost += elsebody->inlineCost(ics); + ics->nested -= 1; + } + return cost; +} + +int ReturnStatement::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + // Can't handle return statements nested in if's + if (ics->nested) + return COST_MAX; +#endif + return exp ? exp->inlineCost(ics) : 0; +} + +/* -------------------------- */ + +int arrayInlineCost(InlineCostState *ics, Array *arguments) +{ int cost = 0; + + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + cost += e->inlineCost(ics); + } + } + return cost; +} + +int Expression::inlineCost(InlineCostState *ics) +{ + return 1; +} + +int VarExp::inlineCost(InlineCostState *ics) +{ + //printf("VarExp::inlineCost() %s\n", toChars()); + return 1; +} + +int ThisExp::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + //printf("ThisExp::inlineCost() %s\n", toChars()); + FuncDeclaration *fd = ics->fd; + if (!fd) + return COST_MAX; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; +#endif + return 1; +} + +int SuperExp::inlineCost(InlineCostState *ics) +{ +#if !IN_LLVM + FuncDeclaration *fd = ics->fd; + if (!fd) + return COST_MAX; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; +#endif + return 1; +} + +int TupleExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, exps); +} + +int ArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); +} + +int StructLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int FuncExp::inlineCost(InlineCostState *ics) +{ + //printf("FuncExp::inlineCost()\n"); + + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. + // Right now, this makes the function be output to the .obj file twice. + return COST_MAX; +} + +int DelegateExp::inlineCost(InlineCostState *ics) +{ + // This breaks on LDC too, since nested functions have internal linkage + // and thus can't be referenced from other objects. + return COST_MAX; +} + +int DeclarationExp::inlineCost(InlineCostState *ics) +{ int cost = 0; + VarDeclaration *vd; + + //printf("DeclarationExp::inlineCost()\n"); + vd = declaration->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { +#if 1 + return COST_MAX; // finish DeclarationExp::doInline +#else + for (size_t i = 0; i < td->objects->dim; i++) + { Object *o = (Object *)td->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + return COST_MAX; + Expression *eo = (Expression *)o; + if (eo->op != TOKdsymbol) + return COST_MAX; + } + return td->objects->dim; +#endif + } + // This breaks on LDC too, since nested static variables have internal + // linkage and thus can't be referenced from other objects. + if (!ics->hdrscan && vd->isDataseg()) + return COST_MAX; + cost += 1; + + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { + cost += ie->exp->inlineCost(ics); + } + } + } + + // These can contain functions, which when copied, get output twice. + // These break on LDC too, since nested static variables and functions have + // internal linkage and thus can't be referenced from other objects. + if (declaration->isStructDeclaration() || + declaration->isClassDeclaration() || + declaration->isFuncDeclaration() || + declaration->isTypedefDeclaration() || + declaration->isAttribDeclaration() || + declaration->isTemplateMixin()) + return COST_MAX; + + //printf("DeclarationExp::inlineCost('%s')\n", toChars()); + return cost; +} + +int UnaExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics); +} + +int AssertExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); +} + +int BinExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); +} + +int CallExp::inlineCost(InlineCostState *ics) +{ + // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner + // can't handle that at present. + if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper) + return COST_MAX; + + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + +int SliceExp::inlineCost(InlineCostState *ics) +{ int cost; + + cost = 1 + e1->inlineCost(ics); + if (lwr) + cost += lwr->inlineCost(ics); + if (upr) + cost += upr->inlineCost(ics); + return cost; +} + +int ArrayExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + + +int CondExp::inlineCost(InlineCostState *ics) +{ + return 1 + + e1->inlineCost(ics) + + e2->inlineCost(ics) + + econd->inlineCost(ics); +} + + +/* ======================== Perform the inlining ============================== */ + +/* Inlining is done by: + * o Converting to an Expression + * o Copying the trees of the function to be inlined + * o Renaming the variables + */ + +struct InlineDoState +{ + VarDeclaration *vthis; + Array from; // old Dsymbols + Array to; // parallel array of new Dsymbols + Dsymbol *parent; // new parent +}; + +Expression *Statement::doInline(InlineDoState *ids) +{ + assert(0); + return NULL; // default is we can't inline it +} + +Expression *ExpStatement::doInline(InlineDoState *ids) +{ +#if LOG + if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); +#endif + return exp ? exp->doInline(ids) : NULL; +} + +Expression *CompoundStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("CompoundStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + + /* Check for: + * if (condition) + * return exp1; + * else + * return exp2; + */ + IfStatement *ifs = s->isIfStatement(); + if (ifs && ifs->elsebody && ifs->ifbody && + ifs->ifbody->isReturnStatement() && + ifs->elsebody->isReturnStatement() + ) + break; + + } + } + return e; +} + +Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + } + } + return e; +} + +Expression *IfStatement::doInline(InlineDoState *ids) +{ + Expression *econd; + Expression *e1; + Expression *e2; + Expression *e; + + assert(!arg); + econd = condition->doInline(ids); + assert(econd); + if (ifbody) + e1 = ifbody->doInline(ids); + else + e1 = NULL; + if (elsebody) + e2 = elsebody->doInline(ids); + else + e2 = NULL; + if (e1 && e2) + { + e = new CondExp(econd->loc, econd, e1, e2); + e->type = e1->type; + } + else if (e1) + { + e = new AndAndExp(econd->loc, econd, e1); + e->type = Type::tvoid; + } + else if (e2) + { + e = new OrOrExp(econd->loc, econd, e2); + e->type = Type::tvoid; + } + else + { + e = econd; + } + return e; +} + +Expression *ReturnStatement::doInline(InlineDoState *ids) +{ + //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); + return exp ? exp->doInline(ids) : 0; +} + +/* --------------------------------------------------------------- */ + +/****************************** + * Perform doInline() on an array of Expressions. + */ + +Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) +{ Expressions *newa = NULL; + + if (a) + { + newa = new Expressions(); + newa->setDim(a->dim); + + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)a->data[i]; + + if (e) + e = e->doInline(ids); + newa->data[i] = (void *)e; + } + } + return newa; +} + +Expression *Expression::doInline(InlineDoState *ids) +{ + //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); + return copy(); +} + +Expression *SymOffExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("SymOffExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + SymOffExp *se = (SymOffExp *)copy(); + + se->var = (Declaration *)ids->to.data[i]; + return se; + } + } + return this; +} + +Expression *VarExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("VarExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + VarExp *ve = (VarExp *)copy(); + + ve->var = (Declaration *)ids->to.data[i]; + return ve; + } + } + return this; +} + +Expression *ThisExp::doInline(InlineDoState *ids) +{ + //if (!ids->vthis) + //error("no 'this' when inlining %s", ids->parent->toChars()); + if (!ids->vthis) + { + return this; + } + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *SuperExp::doInline(InlineDoState *ids) +{ + assert(ids->vthis); + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *DeclarationExp::doInline(InlineDoState *ids) +{ DeclarationExp *de = (DeclarationExp *)copy(); + VarDeclaration *vd; + + //printf("DeclarationExp::doInline(%s)\n", toChars()); + vd = declaration->isVarDeclaration(); + if (vd) + { +#if 0 + // Need to figure this out before inlining can work for tuples + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + se->s; + } + return st->objects->dim; + } +#endif + if (vd->isStatic()) + ; + else + { + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + if (vd->init->isVoidInitializer()) + { + vto->init = new VoidInitializer(vd->init->loc); + } + else + { + Expression *e = vd->init->toExpression(); + assert(e); + vto->init = new ExpInitializer(e->loc, e->doInline(ids)); + } + } + de->declaration = (Dsymbol *) (void *)vto; + } + } + /* This needs work, like DeclarationExp::toElem(), if we are + * to handle TemplateMixin's. For now, we just don't inline them. + */ + return de; +} + +Expression *NewExp::doInline(InlineDoState *ids) +{ + //printf("NewExp::doInline(): %s\n", toChars()); + NewExp *ne = (NewExp *)copy(); + + if (thisexp) + ne->thisexp = thisexp->doInline(ids); + ne->newargs = arrayExpressiondoInline(ne->newargs, ids); + ne->arguments = arrayExpressiondoInline(ne->arguments, ids); + return ne; +} + +Expression *UnaExp::doInline(InlineDoState *ids) +{ + UnaExp *ue = (UnaExp *)copy(); + + ue->e1 = e1->doInline(ids); + return ue; +} + +Expression *AssertExp::doInline(InlineDoState *ids) +{ + AssertExp *ae = (AssertExp *)copy(); + + ae->e1 = e1->doInline(ids); + if (msg) + ae->msg = msg->doInline(ids); + return ae; +} + +Expression *BinExp::doInline(InlineDoState *ids) +{ + BinExp *be = (BinExp *)copy(); + + be->e1 = e1->doInline(ids); + be->e2 = e2->doInline(ids); + return be; +} + +Expression *CallExp::doInline(InlineDoState *ids) +{ + CallExp *ce; + + ce = (CallExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *IndexExp::doInline(InlineDoState *ids) +{ + IndexExp *are = (IndexExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + are->e2 = e2->doInline(ids); + return are; +} + + +Expression *SliceExp::doInline(InlineDoState *ids) +{ + SliceExp *are = (SliceExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; +#if IN_DMD + vto->csym = NULL; + vto->isym = NULL; +#endif + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + if (lwr) + are->lwr = lwr->doInline(ids); + if (upr) + are->upr = upr->doInline(ids); + return are; +} + + +Expression *TupleExp::doInline(InlineDoState *ids) +{ + TupleExp *ce; + + ce = (TupleExp *)copy(); + ce->exps = arrayExpressiondoInline(exps, ids); + return ce; +} + + +Expression *ArrayLiteralExp::doInline(InlineDoState *ids) +{ + ArrayLiteralExp *ce; + + ce = (ArrayLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) +{ + AssocArrayLiteralExp *ce; + + ce = (AssocArrayLiteralExp *)copy(); + ce->keys = arrayExpressiondoInline(keys, ids); + ce->values = arrayExpressiondoInline(values, ids); + return ce; +} + + +Expression *StructLiteralExp::doInline(InlineDoState *ids) +{ + StructLiteralExp *ce; + + ce = (StructLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *ArrayExp::doInline(InlineDoState *ids) +{ + ArrayExp *ce; + + ce = (ArrayExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *CondExp::doInline(InlineDoState *ids) +{ + CondExp *ce = (CondExp *)copy(); + + ce->econd = econd->doInline(ids); + ce->e1 = e1->doInline(ids); + ce->e2 = e2->doInline(ids); + return ce; +} + + +/* ========== Walk the parse trees, and inline expand functions ============= */ + +/* Walk the trees, looking for functions to inline. + * Inline any that can be. + */ + +struct InlineScanState +{ + FuncDeclaration *fd; // function being scanned +}; + +Statement *Statement::inlineScan(InlineScanState *iss) +{ + return this; +} + +Statement *ExpStatement::inlineScan(InlineScanState *iss) +{ +#if LOG + printf("ExpStatement::inlineScan(%s)\n", toChars()); +#endif + if (exp) + exp = exp->inlineScan(iss); + return this; +} + +Statement *CompoundStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *ScopeStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +Statement *WhileStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + return this; +} + + +Statement *DoStatement::inlineScan(InlineScanState *iss) +{ + body = body ? body->inlineScan(iss) : NULL; + condition = condition->inlineScan(iss); + return this; +} + + +Statement *ForStatement::inlineScan(InlineScanState *iss) +{ + if (init) + init = init->inlineScan(iss); + if (condition) + condition = condition->inlineScan(iss); + if (increment) + increment = increment->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *ForeachStatement::inlineScan(InlineScanState *iss) +{ + aggr = aggr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +#if DMDV2 +Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) +{ + lwr = lwr->inlineScan(iss); + upr = upr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} +#endif + + +Statement *IfStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + if (ifbody) + ifbody = ifbody->inlineScan(iss); + if (elsebody) + elsebody = elsebody->inlineScan(iss); + return this; +} + + +Statement *SwitchStatement::inlineScan(InlineScanState *iss) +{ + //printf("SwitchStatement::inlineScan()\n"); + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + if (sdefault) + sdefault = (DefaultStatement *)sdefault->inlineScan(iss); + if (cases) + { + for (int i = 0; i < cases->dim; i++) + { Statement *s; + + s = (Statement *) cases->data[i]; + cases->data[i] = (void *)s->inlineScan(iss); + } + } + return this; +} + + +Statement *CaseStatement::inlineScan(InlineScanState *iss) +{ + //printf("CaseStatement::inlineScan()\n"); + exp = exp->inlineScan(iss); + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *DefaultStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *ReturnStatement::inlineScan(InlineScanState *iss) +{ + //printf("ReturnStatement::inlineScan()\n"); + if (exp) + { + exp = exp->inlineScan(iss); + } + return this; +} + + +Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *WithStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *TryCatchStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (catches) + { + for (int i = 0; i < catches->dim; i++) + { Catch *c = (Catch *)catches->data[i]; + + if (c->handler) + c->handler = c->handler->inlineScan(iss); + } + } + return this; +} + + +Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (finalbody) + finalbody = finalbody->inlineScan(iss); + return this; +} + + +Statement *ThrowStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + return this; +} + + +Statement *VolatileStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *LabelStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +/* -------------------------- */ + +void arrayInlineScan(InlineScanState *iss, Array *arguments) +{ + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + { + e = e->inlineScan(iss); + arguments->data[i] = (void *)e; + } + } + } +} + +Expression *Expression::inlineScan(InlineScanState *iss) +{ + return this; +} + +void scanVar(Dsymbol *s, InlineScanState *iss) +{ + VarDeclaration *vd = s->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + scanVar(se->s, iss); + } + } + else + { + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { +#if DMDV2 + if (vd->type) + { Type *tb = vd->type->toBasetype(); + if (tb->ty == Tstruct) + { StructDeclaration *sd = ((TypeStruct *)tb)->sym; + if (sd->cpctor) + { /* The problem here is that if the initializer is a + * function call that returns a struct S with a cpctor: + * S s = foo(); + * the postblit is done by the return statement in foo() + * in s2ir.c, the intermediate code generator. + * But, if foo() is inlined and now the code looks like: + * S s = x; + * the postblit is not there, because such assignments + * are rewritten as s.cpctor(&x) by the front end. + * So, the inlining won't get the postblit called. + * Work around by not inlining these cases. + * A proper fix would be to move all the postblit + * additions to the front end. + */ + return; + } + } + } +#endif + ie->exp = ie->exp->inlineScan(iss); + } + } + } + } +} + +Expression *DeclarationExp::inlineScan(InlineScanState *iss) +{ + //printf("DeclarationExp::inlineScan()\n"); + scanVar(declaration, iss); + return this; +} + +Expression *UnaExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + return this; +} + +Expression *AssertExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (msg) + msg = msg->inlineScan(iss); + return this; +} + +Expression *BinExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +Expression *CallExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("CallExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + FuncDeclaration *fd = ve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(0)) + { + e = fd->doInline(iss, NULL, arguments); + } + } + else if (e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *fd = dve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(1)) + { + if (dve->e1->op == TOKcall && + dve->e1->type->toBasetype()->ty == Tstruct) + { + /* To create ethis, we'll need to take the address + * of dve->e1, but this won't work if dve->e1 is + * a function call. + */ + ; + } + else + e = fd->doInline(iss, dve->e1, arguments); + } + } + + return e; +} + + +Expression *SliceExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (lwr) + lwr = lwr->inlineScan(iss); + if (upr) + upr = upr->inlineScan(iss); + return this; +} + + +Expression *TupleExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("TupleExp::inlineScan()\n"); + arrayInlineScan(iss, exps); + + return e; +} + + +Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("AssocArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, keys); + arrayInlineScan(iss, values); + + return e; +} + + +Expression *StructLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("StructLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *ArrayExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + return e; +} + + +Expression *CondExp::inlineScan(InlineScanState *iss) +{ + econd = econd->inlineScan(iss); + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +/* ========== =============== */ + +void FuncDeclaration::inlineScan() +{ + InlineScanState iss; + +#if LOG + printf("FuncDeclaration::inlineScan('%s')\n", toChars()); +#endif + memset(&iss, 0, sizeof(iss)); + iss.fd = this; + if (fbody) + { + inlineNest++; + fbody = fbody->inlineScan(&iss); + inlineNest--; + } +} + +int FuncDeclaration::canInline(int hasthis, int hdrscan) +{ + InlineCostState ics; + int cost; + +#define CANINLINE_LOG 0 + +#if CANINLINE_LOG + printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); +#endif + + if (needThis() && !hasthis) + return 0; + + if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) + { +#if CANINLINE_LOG + printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); +#endif + return 0; + } + + switch (inlineStatus) + { + case ILSyes: +#if CANINLINE_LOG + printf("\t1: yes %s\n", toChars()); +#endif + return 1; + + case ILSno: +#if CANINLINE_LOG + printf("\t1: no %s\n", toChars()); +#endif + return 0; + + case ILSuninitialized: + break; + + default: + assert(0); + } + + if (type) + { assert(type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)(type); +#if IN_LLVM + // LDC: Only extern(C) varargs count. + if (tf->linkage != LINKd) +#endif + if (tf->varargs == 1) // no variadic parameter lists + goto Lno; + + /* Don't inline a function that returns non-void, but has + * no return expression. + */ + if (tf->next && tf->next->ty != Tvoid && + !(hasReturnExp & 1) && + !hdrscan) + goto Lno; + } +#if !IN_LLVM + // LDC: Only extern(C) varargs count, and ctors use extern(D). + else + { CtorDeclaration *ctor = isCtorDeclaration(); + + if (ctor && ctor->varargs == 1) + goto Lno; + } +#endif + + if ( + !fbody || + !hdrscan && + ( +#if 0 + isCtorDeclaration() || // cannot because need to convert: + // return; + // to: + // return this; +#endif + isSynchronized() || + isImportedSymbol() || +#if !IN_LLVM +#if DMDV2 + closureVars.dim || // no nested references to this frame +#else + nestedFrameRef || // no nested references to this frame +#endif +#endif // !IN_LLVM + (isVirtual() && !isFinal()) + )) + { + goto Lno; + } + +#if !IN_LLVM + /* If any parameters are Tsarray's (which are passed by reference) + * or out parameters (also passed by reference), don't do inlining. + */ +#if 0 + if (parameters) + { + for (int i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if ( +#if DMDV1 + v->isOut() || v->isRef() || +#endif + v->type->toBasetype()->ty == Tsarray) + goto Lno; + } + } +#endif +#endif // !IN_LLVM + + memset(&ics, 0, sizeof(ics)); + ics.hasthis = hasthis; + ics.fd = this; + ics.hdrscan = hdrscan; + cost = fbody->inlineCost(&ics); +#if CANINLINE_LOG + printf("cost = %d\n", cost); +#endif + if (cost >= COST_MAX) + goto Lno; + +#if !IN_LLVM + if (!hdrscan) // Don't scan recursively for header content scan + inlineScan(); +#endif + +Lyes: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSyes; +#if CANINLINE_LOG + printf("\t2: yes %s\n", toChars()); +#endif + return 1; + +Lno: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSno; +#if CANINLINE_LOG + printf("\t2: no %s\n", toChars()); +#endif + return 0; +} + +Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) +{ + InlineDoState ids; + DeclarationExp *de; + Expression *e = NULL; + +#if LOG + printf("FuncDeclaration::doInline('%s')\n", toChars()); +#endif + + memset(&ids, 0, sizeof(ids)); + ids.parent = iss->fd; + + // Set up vthis + if (ethis) + { + VarDeclaration *vthis; + ExpInitializer *ei; + VarExp *ve; + +#if STRUCTTHISREF + if (ethis->type->ty == Tpointer) + { Type *t = ethis->type->nextOf(); + ethis = new PtrExp(ethis->loc, ethis); + ethis->type = t; + } + ei = new ExpInitializer(ethis->loc, ethis); + + vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); + if (ethis->type->ty != Tclass) + vthis->storage_class = STCref; + else + vthis->storage_class = STCin; +#else + if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) + { + ethis = ethis->addressOf(NULL); + } + + ei = new ExpInitializer(ethis->loc, ethis); + + vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); + vthis->storage_class = STCin; +#endif + vthis->linkage = LINKd; + vthis->parent = iss->fd; + + ve = new VarExp(vthis->loc, vthis); + ve->type = vthis->type; + + ei->exp = new AssignExp(vthis->loc, ve, ethis); + ei->exp->type = ve->type; +#if STRUCTTHISREF + if (ethis->type->ty != Tclass) + { /* This is a reference initialization, not a simple assignment. + */ + ei->exp->op = TOKconstruct; + } +#endif + + ids.vthis = vthis; + } + + // Set up parameters + if (ethis) + { + e = new DeclarationExp(0, ids.vthis); + e->type = Type::tvoid; + } + + if (arguments && arguments->dim) + { + assert(parameters->dim == arguments->dim); + + for (int i = 0; i < arguments->dim; i++) + { + VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; + VarDeclaration *vto; + Expression *arg = (Expression *)arguments->data[i]; + ExpInitializer *ei; + VarExp *ve; + + ei = new ExpInitializer(arg->loc, arg); + + vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); + vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); + vto->linkage = vfrom->linkage; + vto->parent = iss->fd; + //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); + //printf("vto->parent = '%s'\n", iss->fd->toChars()); + + ve = new VarExp(vto->loc, vto); + //ve->type = vto->type; + ve->type = arg->type; + + ei->exp = new ConstructExp(vto->loc, ve, arg); + ei->exp->type = ve->type; +//ve->type->print(); +//arg->type->print(); +//ei->exp->print(); + + ids.from.push(vfrom); + ids.to.push(vto); + + de = new DeclarationExp(0, vto); + de->type = Type::tvoid; + + e = Expression::combine(e, de); + } + } + + inlineNest++; + Expression *eb = fbody->doInline(&ids); + inlineNest--; +//eb->type->print(); +//eb->print(); +//eb->dump(0); + + e = Expression::combine(e, eb); + + /* There's a problem if what the function returns is used subsequently as an + * lvalue, as in a struct return that is then used as a 'this'. + * If we take the address of the return value, we will be taking the address + * of the original, not the copy. Fix this by assigning the return value to + * a temporary, then returning the temporary. If the temporary is used as an + * lvalue, it will work. + * This only happens with struct returns. + * See Bugzilla 2127 for an example. + */ + TypeFunction *tf = (TypeFunction*)type; + if (tf->next->ty == Tstruct) + { + /* Generate a new variable to hold the result and initialize it with the + * inlined body of the function: + * tret __inlineretval = e; + */ + ExpInitializer* ei = new ExpInitializer(loc, e); + + Identifier* tmp = Identifier::generateId("__inlineretval"); + VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei); + vd->storage_class = tf->isref ? STCref : 0; + vd->linkage = tf->linkage; + vd->parent = iss->fd; + + VarExp *ve = new VarExp(loc, vd); + ve->type = tf->next; + + ei->exp = new ConstructExp(loc, ve, e); + ei->exp->type = ve->type; + + DeclarationExp* de = new DeclarationExp(0, vd); + de->type = Type::tvoid; + + // Chain the two together: + // ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval + e = Expression::combine(de, ve); + + //fprintf(stderr, "CallExp::inlineScan: e = "); e->print(); + } + + return e; +} + + +/**************************************************** + * Perform the "inline copying" of a default argument for a function parameter. + */ + +Expression *Expression::inlineCopy(Scope *sc) +{ +#if 0 + /* See Bugzilla 2935 for explanation of why just a copy() is broken + */ + return copy(); +#else + InlineCostState ics; + + memset(&ics, 0, sizeof(ics)); + ics.hdrscan = 1; // so DeclarationExp:: will work on 'statics' which are not + int cost = inlineCost(&ics); + if (cost >= COST_MAX) + { error("cannot inline default argument %s", toChars()); + return new ErrorExp(); + } + InlineDoState ids; + memset(&ids, 0, sizeof(ids)); + ids.parent = sc->parent; + Expression *e = doInline(&ids); + return e; +#endif +} diff --git a/dmd2/interpret.c b/dmd2/interpret.c index 125965d2..4bdc7995 100644 --- a/dmd2/interpret.c +++ b/dmd2/interpret.c @@ -1,2740 +1,3320 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" - -#define LOG 0 - -struct InterState -{ - InterState *caller; // calling function's InterState - FuncDeclaration *fd; // function being interpreted - Dsymbols vars; // variables used in this function - Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result - Expression *localThis; // value of 'this', or NULL if none - - InterState(); -}; - -InterState::InterState() -{ - memset(this, 0, sizeof(InterState)); -} - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments); -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); -Expression *interpret_aaValues(InterState *istate, Expressions *arguments); - -/************************************* - * Attempt to interpret a function given the arguments. - * Input: - * istate state for calling function (NULL if none) - * arguments function arguments - * thisarg 'this', if a needThis() function, NULL if not. - * - * Return result expression if successful, NULL if not. - */ - -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) -{ -#if LOG - printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); - printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); -#endif - if (global.errors) - return NULL; - if (ident == Id::aaLen) - return interpret_aaLen(istate, arguments); - else if (ident == Id::aaKeys) - return interpret_aaKeys(istate, arguments); - else if (ident == Id::aaValues) - return interpret_aaValues(istate, arguments); - - if (cantInterpret || semanticRun == 3) - return NULL; - - if (!fbody) - { cantInterpret = 1; - return NULL; - } - - if (semanticRun < 3 && scope) - { - semantic3(scope); - if (global.errors) // if errors compiling this function - return NULL; - } - if (semanticRun < 4) - return NULL; - - Type *tb = type->toBasetype(); - assert(tb->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); - if (tf->varargs) - { cantInterpret = 1; - error("Variadic functions are not yet implemented in CTFE"); - return NULL; - } - - // Ensure there are no lazy parameters - if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(tf->parameters, i); - if (arg->storageClass & STClazy) - { cantInterpret = 1; - return NULL; - } - } - } - - InterState istatex; - istatex.caller = istate; - istatex.fd = this; - istatex.localThis = thisarg; - - Expressions vsave; // place to save previous parameter values - size_t dim = 0; - if (needThis() && !thisarg) - { cantInterpret = 1; - // error, no this. Prevent segfault. - error("need 'this' to access member %s", toChars()); - return NULL; - } - if (arguments) - { - dim = arguments->dim; - assert(!dim || (parameters && (parameters->dim == dim))); - vsave.setDim(dim); - - /* Evaluate all the arguments to the function, - * store the results in eargs[] - */ - Expressions eargs; - eargs.setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)arguments->data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - - if (arg->storageClass & (STCout | STCref)) - { - } - else - { /* Value parameters - */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - earg = earg->interpret(istate ? istate : &istatex); - if (earg == EXP_CANT_INTERPRET) - { cantInterpret = 1; - return NULL; - } - } - eargs.data[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = (Expression *)eargs.data[i]; - Argument *arg = Argument::getNth(tf->parameters, i); - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - vsave.data[i] = v->value; -#if LOG - printf("arg[%d] = %s\n", i, earg->toChars()); -#endif - if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar) - { - /* Bind out or ref parameter to the corresponding - * variable v2 - */ - if (!istate) - { cantInterpret = 1; - error("%s cannot be by passed by reference at compile time", earg->toChars()); - return NULL; // can't bind to non-interpreted vars - } - // We need to chase down all of the the passed parameters until - // we find something that isn't a TOKvar, then create a variable - // containg that expression. - VarDeclaration *v2; - while (1) - { - VarExp *ve = (VarExp *)earg; - v2 = ve->var->isVarDeclaration(); - if (!v2) - { cantInterpret = 1; - return NULL; - } - if (!v2->value || v2->value->op != TOKvar) - break; - if (((VarExp *)v2->value)->var->isStaticStructInitDeclaration()) - { // This can happen if v is a struct initialized to - // 0 using an __initZ StaticStructInitDeclaration from - // TypeStruct::defaultInit() - break; // eg default-initialized variable - } - earg = v2->value; - } - - v->value = new VarExp(earg->loc, v2); - - /* Don't restore the value of v2 upon function return - */ - assert(istate); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v == v2) - { istate->vars.data[i] = NULL; - break; - } - } - } - else - { // Value parameters and non-trivial references - v->value = earg; - } -#if LOG - printf("interpreted arg[%d] = %s\n", i, earg->toChars()); -#endif - } - } - // Don't restore the value of 'this' upon function return - if (needThis() && thisarg->op==TOKvar) { - VarDeclaration *thisvar = ((VarExp *)(thisarg))->var->isVarDeclaration(); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v == thisvar) - { istate->vars.data[i] = NULL; - break; - } - } - } - - /* Save the values of the local variables used - */ - Expressions valueSaves; - if (istate && !isNested()) - { - //printf("saving local variables...\n"); - valueSaves.setDim(istate->vars.dim); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { - //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - valueSaves.data[i] = v->value; - v->value = NULL; - } - } - } - - Expression *e = NULL; - while (1) - { - e = fbody->interpret(&istatex); - if (e == EXP_CANT_INTERPRET) - { -#if LOG - printf("function body failed to interpret\n"); -#endif - e = NULL; - } - - /* This is how we deal with a recursive statement AST - * that has arbitrary goto statements in it. - * Bubble up a 'result' which is the target of the goto - * statement, then go recursively down the AST looking - * for that statement, then execute starting there. - */ - if (e == EXP_GOTO_INTERPRET) - { - istatex.start = istatex.gotoTarget; // set starting statement - istatex.gotoTarget = NULL; - } - else - break; - } - /* Restore the parameter values - */ - for (size_t i = 0; i < dim; i++) - { - VarDeclaration *v = (VarDeclaration *)parameters->data[i]; - v->value = (Expression *)vsave.data[i]; - } - - if (istate && !isNested()) - { - /* Restore the variable values - */ - //printf("restoring local variables...\n"); - for (size_t i = 0; i < istate->vars.dim; i++) - { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; - if (v) - { v->value = (Expression *)valueSaves.data[i]; - //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); - } - } - } - return e; -} - -/******************************** Statement ***************************/ - -#define START() \ - if (istate->start) \ - { if (istate->start != this) \ - return NULL; \ - istate->start = NULL; \ - } - -/*********************************** - * Interpret the statement. - * Returns: - * NULL continue to next statement - * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement - */ - -Expression *Statement::interpret(InterState *istate) -{ -#if LOG - printf("Statement::interpret()\n"); -#endif - START() - return EXP_CANT_INTERPRET; -} - -Expression *ExpStatement::interpret(InterState *istate) -{ -#if LOG - printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (exp) - { - Expression *e = exp->interpret(istate); - if (e == EXP_CANT_INTERPRET) - { - //printf("-ExpStatement::interpret(): %p\n", e); - return EXP_CANT_INTERPRET; - } - } - return NULL; -} - -Expression *CompoundStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("CompoundStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (s) - { - e = s->interpret(istate); - if (e) - break; - } - } - } -#if LOG - printf("-CompoundStatement::interpret() %p\n", e); -#endif - return e; -} - -Expression *UnrolledLoopStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("UnrolledLoopStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - e = s->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - { e = NULL; - continue; - } - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - } - return e; -} - -Expression *IfStatement::interpret(InterState *istate) -{ -#if LOG - printf("IfStatement::interpret(%s)\n", condition->toChars()); -#endif - - if (istate->start == this) - istate->start = NULL; - if (istate->start) - { - Expression *e = NULL; - if (ifbody) - e = ifbody->interpret(istate); - if (istate->start && elsebody) - e = elsebody->interpret(istate); - return e; - } - - Expression *e = condition->interpret(istate); - assert(e); - //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = ifbody ? ifbody->interpret(istate) : NULL; - else if (e->isBool(FALSE)) - e = elsebody ? elsebody->interpret(istate) : NULL; - else - { - e = EXP_CANT_INTERPRET; - } - } - return e; -} - -Expression *ScopeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ScopeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -Expression *ReturnStatement::interpret(InterState *istate) -{ -#if LOG - printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (!exp) - return EXP_VOID_INTERPRET; -#if LOG - Expression *e = exp->interpret(istate); - printf("e = %p\n", e); - return e; -#else - return exp->interpret(istate); -#endif -} - -Expression *BreakStatement::interpret(InterState *istate) -{ -#if LOG - printf("BreakStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_BREAK_INTERPRET; -} - -Expression *ContinueStatement::interpret(InterState *istate) -{ -#if LOG - printf("ContinueStatement::interpret()\n"); -#endif - START() - if (ident) - return EXP_CANT_INTERPRET; - else - return EXP_CONTINUE_INTERPRET; -} - -Expression *WhileStatement::interpret(InterState *istate) -{ -#if LOG - printf("WhileStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e && e != EXP_CONTINUE_INTERPRET) - return e; - } - - while (1) - { - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - continue; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e) - break; - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *DoStatement::interpret(InterState *istate) -{ -#if LOG - printf("DoStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - - Lcontinue: - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (init) - { - e = init->interpret(istate); - if (e == EXP_CANT_INTERPRET) - return e; - assert(!e); - } - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - if (e == EXP_CONTINUE_INTERPRET) - goto Lcontinue; - if (e) - return e; - } - - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (e->isBool(TRUE)) - { - Lhead: - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - Lcontinue: - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForeachStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *eaggr; - - if (value->isOut() || value->isRef()) - return EXP_CANT_INTERPRET; - - eaggr = aggr->interpret(istate); - if (eaggr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *dim = ArrayLength(Type::tsize_t, eaggr); - if (dim == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key ? key->value : NULL; - Expression *valuesave = value->value; - - uinteger_t d = dim->toUInteger(); - uinteger_t index; - - if (op == TOKforeach) - { - for (index = 0; index < d; index++) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - else // TOKforeach_reverse - { - for (index = d; index-- != 0;) - { - Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); - if (key) - key->value = ekey; - e = Index(value->type, eaggr, ekey); - if (e == EXP_CANT_INTERPRET) - break; - value->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == EXP_CONTINUE_INTERPRET) - e = NULL; - else if (e) - break; - } - } - value->value = valuesave; - if (key) - key->value = keysave; - return e; -} - -#if DMDV2 -Expression *ForeachRangeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForeachRangeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (istate->start) - return NULL; - - Expression *e = NULL; - Expression *elwr = lwr->interpret(istate); - if (elwr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *eupr = upr->interpret(istate); - if (eupr == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Expression *keysave = key->value; - - if (op == TOKforeach) - { - key->value = elwr; - - while (1) - { - e = Cmp(TOKlt, key->value->type, key->value, eupr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - if (e == NULL || e == EXP_CONTINUE_INTERPRET) - { e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - } - else - break; - } - } - else // TOKforeach_reverse - { - key->value = eupr; - - do - { - e = Cmp(TOKgt, key->value->type, key->value, elwr); - if (e == EXP_CANT_INTERPRET) - break; - if (e->isBool(TRUE) == FALSE) - { e = NULL; - break; - } - - e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); - if (e == EXP_CANT_INTERPRET) - break; - key->value = e; - - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { e = NULL; - break; - } - } while (e == NULL || e == EXP_CONTINUE_INTERPRET); - } - key->value = keysave; - return e; -} -#endif - -Expression *SwitchStatement::interpret(InterState *istate) -{ -#if LOG - printf("SwitchStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e = NULL; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; - } - - - Expression *econdition = condition->interpret(istate); - if (econdition == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - Statement *s = NULL; - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)cases->data[i]; - e = Equal(TOKequal, Type::tint32, econdition, cs->exp); - if (e == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (e->isBool(TRUE)) - { s = cs; - break; - } - } - } - if (!s) - { if (hasNoDefault) - error("no default or case for %s in switch statement", econdition->toChars()); - s = sdefault; - } - - assert(s); - istate->start = s; - e = body ? body->interpret(istate) : NULL; - assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) - return NULL; - return e; -} - -Expression *CaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *DefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("DefaultStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *GotoStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoStatement::interpret()\n"); -#endif - START() - assert(label && label->statement); - istate->gotoTarget = label->statement; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoCaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoCaseStatement::interpret()\n"); -#endif - START() - assert(cs); - istate->gotoTarget = cs; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoDefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoDefaultStatement::interpret()\n"); -#endif - START() - assert(sw && sw->sdefault); - istate->gotoTarget = sw->sdefault; - return EXP_GOTO_INTERPRET; -} - -Expression *LabelStatement::interpret(InterState *istate) -{ -#if LOG - printf("LabelStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -/******************************** Expression ***************************/ - -Expression *Expression::interpret(InterState *istate) -{ -#if LOG - printf("Expression::interpret() %s\n", toChars()); - printf("type = %s\n", type->toChars()); - dump(0); -#endif - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *ThisExp::interpret(InterState *istate) -{ - if (istate->localThis) - return istate->localThis->interpret(istate); - return EXP_CANT_INTERPRET; -} - -Expression *NullExp::interpret(InterState *istate) -{ - return this; -} - -Expression *IntegerExp::interpret(InterState *istate) -{ -#if LOG - printf("IntegerExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *RealExp::interpret(InterState *istate) -{ -#if LOG - printf("RealExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *ComplexExp::interpret(InterState *istate) -{ - return this; -} - -Expression *StringExp::interpret(InterState *istate) -{ -#if LOG - printf("StringExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) -{ - Expression *e = EXP_CANT_INTERPRET; - VarDeclaration *v = d->isVarDeclaration(); -#if IN_LLVM - StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration(); -#else - SymbolDeclaration *s = d->isSymbolDeclaration(); -#endif - if (v) - { -#if DMDV2 - if ((v->isConst() || v->isInvariant() || v->storage_class & STCmanifest) && v->init && !v->value) -#else - if (v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (e && !e->type) - e->type = v->type; - } - else - { e = v->value; - if (v->isDataseg()) - { error(loc, "static variable %s cannot be read at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; - } - else if (!e) - error(loc, "variable %s is used before initialization", v->toChars()); - else if (e != EXP_CANT_INTERPRET) - e = e->interpret(istate); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { - Expressions *exps = new Expressions(); - e = new StructLiteralExp(0, s->dsym, exps); - e = e->semantic(NULL); - } - return e; -} - -Expression *VarExp::interpret(InterState *istate) -{ -#if LOG - printf("VarExp::interpret() %s\n", toChars()); -#endif - return getVarExp(loc, istate, var); -} - -Expression *DeclarationExp::interpret(InterState *istate) -{ -#if LOG - printf("DeclarationExp::interpret() %s\n", toChars()); -#endif - Expression *e; - VarDeclaration *v = declaration->isVarDeclaration(); - if (v) - { - Dsymbol *s = v->toAlias(); - if (s == v && !v->isStatic() && v->init) - { - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie) - e = ie->exp->interpret(istate); - else if (v->init->isVoidInitializer()) - e = NULL; - } -#if DMDV2 - else if (s == v && (v->isConst() || v->isInvariant()) && v->init) -#else - else if (s == v && v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (!e) - e = EXP_CANT_INTERPRET; - else if (!e->type) - e->type = v->type; - } - } - else if (declaration->isAttribDeclaration() || - declaration->isTemplateMixin() || - declaration->isTupleDeclaration()) - { // These can be made to work, too lazy now - error("Declaration %s is not yet implemented in CTFE", toChars()); - - e = EXP_CANT_INTERPRET; - } - else - { // Others should not contain executable code, so are trivial to evaluate - e = NULL; - } -#if LOG - printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); -#endif - return e; -} - -Expression *TupleExp::interpret(InterState *istate) -{ -#if LOG - printf("TupleExp::interpret() %s\n", toChars()); -#endif - Expressions *expsx = NULL; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(exps->dim); - for (size_t j = 0; j < i; j++) - { - expsx->data[j] = exps->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - if (expsx) - { TupleExp *te = new TupleExp(loc, expsx); - expandTuples(te->exps); - te->type = new TypeTuple(te->exps); - return te; - } - return this; -} - -Expression *ArrayLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("ArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - Expression *ex; - - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); - ae->type = type; - return ae; - } - return this; -} - -Expression *AssocArrayLiteralExp::interpret(InterState *istate) -{ Expressions *keysx = keys; - Expressions *valuesx = values; - -#if LOG - printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); -#endif - for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = (Expression *)keys->data[i]; - Expression *evalue = (Expression *)values->data[i]; - Expression *ex; - - ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != ekey) - { - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - keysx->data[i] = (void *)ex; - } - - ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - - /* If any changes, do Copy On Write - */ - if (ex != evalue) - { - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - valuesx->data[i] = (void *)ex; - } - } - if (keysx != keys) - expandTuples(keysx); - if (valuesx != values) - expandTuples(valuesx); - if (keysx->dim != valuesx->dim) - goto Lerr; - - /* Remove duplicate keys - */ - for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = (Expression *)keysx->data[i - 1]; - - for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = (Expression *)keysx->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->isBool(TRUE)) // if a match - { - // Remove ekey - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - keysx->remove(i - 1); - valuesx->remove(i - 1); - i -= 1; // redo the i'th iteration - break; - } - } - } - - if (keysx != keys || valuesx != values) - { - AssocArrayLiteralExp *ae; - ae = new AssocArrayLiteralExp(loc, keysx, valuesx); - ae->type = type; - return ae; - } - return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; -} - -Expression *StructLiteralExp::interpret(InterState *istate) -{ Expressions *expsx = NULL; - -#if LOG - printf("StructLiteralExp::interpret() %s\n", toChars()); -#endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - - Expression *ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - { delete expsx; - return EXP_CANT_INTERPRET; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->data[j] = elements->data[j]; - } - } - expsx->data[i] = (void *)ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); - se->type = type; - return se; - } - return this; -} - -Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) -{ Expression *e; - Expression *e1; - -#if LOG - printf("UnaExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -UNA_INTERPRET(Neg) -UNA_INTERPRET(Com) -UNA_INTERPRET(Not) -UNA_INTERPRET(Bool) - - -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon(istate, &op); \ -} - -BIN_INTERPRET(Add) -BIN_INTERPRET(Min) -BIN_INTERPRET(Mul) -BIN_INTERPRET(Div) -BIN_INTERPRET(Mod) -BIN_INTERPRET(Shl) -BIN_INTERPRET(Shr) -BIN_INTERPRET(Ushr) -BIN_INTERPRET(And) -BIN_INTERPRET(Or) -BIN_INTERPRET(Xor) - - -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon2() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isConst() != 1 && - e1->op != TOKnull && - e1->op != TOKstring && - e1->op != TOKarrayliteral && - e1->op != TOKstructliteral) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - if (e2->isConst() != 1 && - e2->op != TOKnull && - e2->op != TOKstring && - e2->op != TOKarrayliteral && - e2->op != TOKstructliteral) - goto Lcant; - - e = (*fp)(op, type, e1, e2); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET2(op) \ -Expression *op##Exp::interpret(InterState *istate) \ -{ \ - return interpretCommon2(istate, &op); \ -} - -BIN_INTERPRET2(Equal) -BIN_INTERPRET2(Identity) -BIN_INTERPRET2(Cmp) - -/* Helper functions for BinExp::interpretAssignCommon - */ - -/*************************************** - * Duplicate the elements array, then set field 'indexToChange' = newelem. - */ -Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem) -{ - Expressions *expsx = new Expressions(); - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == indexToChange) - expsx->data[j] = newelem; - else - expsx->data[j] = oldelems->data[j]; - } - return expsx; -} - -/*************************************** - * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint..$] - */ -Expressions *spliceElements(Expressions *oldelems, - Expressions *newelems, size_t insertpoint) -{ - Expressions *expsx = new Expressions(); - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j >= insertpoint && j < insertpoint + newelems->dim) - expsx->data[j] = newelems->data[j - insertpoint]; - else - expsx->data[j] = oldelems->data[j]; - } - return expsx; -} - -/****************************** - * Create an array literal consisting of 'elem' duplicated 'dim' times. - */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, - Expression *elem, size_t dim) -{ - Expressions *elements = new Expressions(); - elements->setDim(dim); - for (size_t i = 0; i < dim; i++) - elements->data[i] = elem; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = type; - return ae; -} - - -/******************************** - * Necessary because defaultInit() for a struct is a VarExp, not a StructLiteralExp. - */ -StructLiteralExp *createDefaultInitStructLiteral(Loc loc, StructDeclaration *sym) -{ - Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); - for (size_t j = 0; j < structelems->dim; j++) - { - structelems->data[j] = ((VarDeclaration *)(sym->fields.data[j]))->type->defaultInit(); - } - StructLiteralExp *structinit = new StructLiteralExp(loc, sym, structelems); - // Why doesn't the StructLiteralExp constructor do this, when - // sym->type != NULL ? - structinit->type = sym->type; - return structinit; -} - -/******************************** - * Add v to the istate list, unless it already exists there. - */ -void addVarToInterstate(InterState *istate, VarDeclaration *v) -{ - if (!v->isParameter()) - { - for (size_t i = 0; 1; i++) - { - if (i == istate->vars.dim) - { istate->vars.push(v); - //printf("\tadding %s to istate\n", v->toChars()); - break; - } - if (v == (VarDeclaration *)istate->vars.data[i]) - break; - } - } -} - -Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) -{ -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); -#endif - Expression *e = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - - if (fp) - { - if (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; - } - } - if (e1 == EXP_CANT_INTERPRET) - return e1; - Expression *e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - // Chase down rebinding of out and ref. - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isStaticStructInitDeclaration()) - { // This can happen if v is a struct initialized to - // 0 using an __initZ StaticStructInitDeclaration from - // TypeStruct::defaultInit() - } - else - e1 = v->value; - } - else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar)) - { - // It is no longer be a TOKvar, eg when a[4] is passed by ref. - e1 = v->value; - } - } - - // To reduce code complexity of handling dotvar expressions, - // extract the aggregate now. - Expression *aggregate; - if (e1->op == TOKdotvar) { - aggregate = ((DotVarExp *)e1)->e1; - // Get rid of 'this'. - if (aggregate->op == TOKthis && istate->localThis) - aggregate = istate->localThis; - } - - /* Assignment to variable of the form: - * v = e2 - */ - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - assert(v); - if (v && v->isDataseg()) - { // Can't modify global or static data - error("%s cannot be modified at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - if (v && !v->isDataseg()) - { - Expression *ev = v->value; - if (fp && !ev) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - if (fp) - e2 = (*fp)(v->type, ev, e2); - else - { /* Look for special case of struct being initialized with 0. - */ - if (v->type->toBasetype()->ty == Tstruct && e2->op == TOKint64) - { - e2 = v->type->defaultInit(); - } - e2 = Cast(v->type, v->type, e2); - } - if (e2 == EXP_CANT_INTERPRET) - return e2; - - addVarToInterstate(istate, v); - v->value = e2; - e = Cast(type, type, post ? ev : e2); - } - } - else if (e1->op == TOKdotvar && aggregate->op == TOKdotvar) - { // eg v.u.var = e2, v[3].u.var = e2, etc. - error("Nested struct assignment %s is not yet supported in CTFE", toChars()); - } - /* Assignment to struct member of the form: - * v.var = e2 - */ - else if (e1->op == TOKdotvar && aggregate->op == TOKvar) - { VarDeclaration *v = ((VarExp *)aggregate)->var->isVarDeclaration(); - - if (v->isDataseg()) - { // Can't modify global or static data - error("%s cannot be modified at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } else { - // Chase down rebinding of out and ref - if (v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isStaticStructInitDeclaration()) - { // This can happen if v is a struct initialized to - // 0 using an __initZ StaticStructInitDeclaration from - // TypeStruct::defaultInit() - } - else - v = ve2->var->isVarDeclaration(); - assert(v); - } - } - if (fp && !v->value) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - if (v->value == NULL && v->init->isVoidInitializer()) - { /* Since a void initializer initializes to undefined - * values, it is valid here to use the default initializer. - * No attempt is made to determine if someone actually relies - * on the void value - to do that we'd need a VoidExp. - * That's probably a good enhancement idea. - */ - v->value = v->type->defaultInit(); - } - Expression *vie = v->value; - if (vie->op == TOKvar) - { - Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); - } - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - StructLiteralExp *se = (StructLiteralExp *)vie; - VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration(); - if (!vf) - return EXP_CANT_INTERPRET; - int fieldi = se->getFieldIndex(type, vf->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - Expression *ev = se->getField(type, vf->offset); - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - addVarToInterstate(istate, v); - - /* Create new struct literal reflecting updated fieldi - */ - Expressions *expsx = changeOneElement(se->elements, fieldi, e2); - v->value = new StructLiteralExp(se->loc, se->sd, expsx); - v->value->type = se->type; - - e = Cast(type, type, post ? ev : e2); - } - /* Assignment to struct member of the form: - * *(symoffexp) = e2 - */ - else if (e1->op == TOKstar && ((PtrExp *)e1)->e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - - if (v->isDataseg()) - { - error("%s cannot be modified at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - if (fp && !v->value) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - Expression *vie = v->value; - if (vie->op == TOKvar) - { - Declaration *d = ((VarExp *)vie)->var; - vie = getVarExp(e1->loc, istate, d); - } - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - StructLiteralExp *se = (StructLiteralExp *)vie; - int fieldi = se->getFieldIndex(type, soe->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - Expression *ev = se->getField(type, soe->offset); - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - addVarToInterstate(istate, v); - - /* Create new struct literal reflecting updated fieldi - */ - Expressions *expsx = changeOneElement(se->elements, fieldi, e2); - v->value = new StructLiteralExp(se->loc, se->sd, expsx); - v->value->type = se->type; - - e = Cast(type, type, post ? ev : e2); - } - /* Assignment to array element of the form: - * a[i] = e2 - */ - else if (e1->op == TOKindex && ((IndexExp *)e1)->e1->op == TOKvar) - { IndexExp *ie = (IndexExp *)e1; - VarExp *ve = (VarExp *)ie->e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v || v->isDataseg()) - { - error("%s cannot be modified at compile time", v ? v->toChars(): "void"); - return EXP_CANT_INTERPRET; - } - if (v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isStaticStructInitDeclaration()) - { // This can happen if v is a struct initialized to - // 0 using an __initZ StaticStructInitDeclaration from - // TypeStruct::defaultInit() - } - else - v = ve2->var->isVarDeclaration(); - assert(v); - } - if (!v->value) - { - if (fp) - { error("variable %s is used before initialization", v->toChars()); - return e; - } - - Type *t = v->type->toBasetype(); - if (t->ty == Tsarray) - { - /* This array was void initialized. Create a - * default initializer for it. - * What we should do is fill the array literal with - * NULL data, so use-before-initialized can be detected. - * But we're too lazy at the moment to do it, as that - * involves redoing Index() and whoever calls it. - */ - - size_t dim = ((TypeSArray *)t)->dim->toInteger(); - v->value = createBlockDuplicatedArrayLiteral(v->type, - v->type->defaultInit(), dim); - } - else - return EXP_CANT_INTERPRET; - } - - ArrayLiteralExp *ae = NULL; - AssocArrayLiteralExp *aae = NULL; - StringExp *se = NULL; - if (v->value->op == TOKarrayliteral) - ae = (ArrayLiteralExp *)v->value; - else if (v->value->op == TOKassocarrayliteral) - aae = (AssocArrayLiteralExp *)v->value; - else if (v->value->op == TOKstring) - se = (StringExp *)v->value; - else if (v->value->op == TOKnull) - { - // This would be a runtime segfault - error("Cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - else - return EXP_CANT_INTERPRET; - - /* Set the $ variable - */ - Expression *ee = ArrayLength(Type::tsize_t, v->value); - if (ee != EXP_CANT_INTERPRET && ie->lengthVar) - ie->lengthVar->value = ee; - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - Expression *ev; - if (fp || ae || se) // not for aae, because key might not be there - { - ev = Index(type, v->value, index); - if (ev == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - addVarToInterstate(istate, v); - if (ae) - { - /* Create new array literal reflecting updated elem - */ - int elemi = index->toInteger(); - Expressions *expsx = changeOneElement(ae->elements, elemi, e2); - v->value = new ArrayLiteralExp(ae->loc, expsx); - v->value->type = ae->type; - } - else if (aae) - { - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = new Expressions(); - valuesx->setDim(aae->values->dim); - int updated = 0; - for (size_t j = valuesx->dim; j; ) - { j--; - Expression *ekey = (Expression *)aae->keys->data[j]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); - if (ex == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - if (ex->isBool(TRUE)) - { valuesx->data[j] = (void *)e2; - updated = 1; - } - else - valuesx->data[j] = aae->values->data[j]; - } - if (!updated) - { // Append index/e2 to keysx[]/valuesx[] - valuesx->push(e2); - keysx = (Expressions *)keysx->copy(); - keysx->push(index); - } - v->value = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); - v->value->type = aae->type; - } - else if (se) - { - /* Create new string literal reflecting updated elem - */ - int elemi = index->toInteger(); - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - unsigned value = e2->toInteger(); - switch (se->sz) - { - case 1: s[elemi] = value; break; - case 2: ((unsigned short *)s)[elemi] = value; break; - case 4: ((unsigned *)s)[elemi] = value; break; - default: - assert(0); - break; - } - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - v->value = se2; - } - else - assert(0); - - e = Cast(type, type, post ? ev : e2); - } - - /* Assignment to struct element in array, of the form: - * a[i].var = e2 - */ - else if (e1->op == TOKdotvar && aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKvar) - { - IndexExp * ie = (IndexExp *)aggregate; - VarExp *ve = (VarExp *)(ie->e1); - VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v || v->isDataseg()) - { - error("%s cannot be modified at compile time", v ? v->toChars(): "void"); - return EXP_CANT_INTERPRET; - } - Type *t = ve->type->toBasetype(); - ArrayLiteralExp *ae = (ArrayLiteralExp *)v->value; - if (!ae) - { - // assignment to one element in an uninitialized (static) array. - // This is quite difficult, because defaultInit() for a struct is a VarExp, - // not a StructLiteralExp. - Type *t = v->type->toBasetype(); - if (t->ty != Tsarray) - { - error("Cannot index an uninitialized variable"); - return EXP_CANT_INTERPRET; - } - - Type *telem = ((TypeSArray *)t)->nextOf()->toBasetype(); - if (telem->ty != Tstruct) { return EXP_CANT_INTERPRET; } - - // Create a default struct literal... - StructDeclaration *sym = ((TypeStruct *)telem)->sym; - StructLiteralExp *structinit = createDefaultInitStructLiteral(v->loc, sym); - - // ... and use to create a blank array literal - size_t dim = ((TypeSArray *)t)->dim->toInteger(); - ae = createBlockDuplicatedArrayLiteral(v->type, structinit, dim); - v->value = ae; - } - if ((Expression *)(ae->elements) == EXP_CANT_INTERPRET) - { - // Note that this would be a runtime segfault - error("Cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - // Set the $ variable - Expression *ee = ArrayLength(Type::tsize_t, v->value); - if (ee != EXP_CANT_INTERPRET && ie->lengthVar) - ie->lengthVar->value = ee; - // Determine the index, and check that it's OK. - Expression *index = ie->e2->interpret(istate); - if (index == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - - int elemi = index->toInteger(); - if (elemi >= ae->elements->dim) - { - error("array index %d is out of bounds %s[0..%d]", elemi, - v->toChars(), ae->elements->dim); - return EXP_CANT_INTERPRET; - } - // Get old element - Expression *vie = (Expression *)(ae->elements->data[elemi]); - if (vie->op != TOKstructliteral) - return EXP_CANT_INTERPRET; - - // Work out which field needs to be changed - StructLiteralExp *se = (StructLiteralExp *)vie; - VarDeclaration *vf = ((DotVarExp *)e1)->var->isVarDeclaration(); - if (!vf) - return EXP_CANT_INTERPRET; - - int fieldi = se->getFieldIndex(type, vf->offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - - Expression *ev = se->getField(type, vf->offset); - if (fp) - e2 = (*fp)(type, ev, e2); - else - e2 = Cast(type, type, e2); - if (e2 == EXP_CANT_INTERPRET) - return e2; - - // Create new struct literal reflecting updated field - Expressions *expsx = changeOneElement(se->elements, fieldi, e2); - Expression * newstruct = new StructLiteralExp(se->loc, se->sd, expsx); - - // Create new array literal reflecting updated struct elem - ae->elements = changeOneElement(ae->elements, elemi, newstruct); - return ae; - } - /* Slice assignment, initialization of static arrays - * a[] = e - */ - else if (e1->op == TOKslice && ((SliceExp *)e1)->e1->op==TOKvar) - { - SliceExp * sexp = (SliceExp *)e1; - VarExp *ve = (VarExp *)(sexp->e1); - VarDeclaration *v = ve->var->isVarDeclaration(); - if (!v || v->isDataseg()) - { - error("%s cannot be modified at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - // Chase down rebinding of out and ref - if (v->value && v->value->op == TOKvar) - { - VarExp *ve2 = (VarExp *)v->value; - if (ve2->var->isStaticStructInitDeclaration()) - { // This can happen if v is a struct initialized to - // 0 using an __initZ StaticStructInitDeclaration from - // TypeStruct::defaultInit() - } - else - v = ve2->var->isVarDeclaration(); - assert(v); - } - /* Set the $ variable - */ - Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) - : EXP_CANT_INTERPRET; - if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) - sexp->lengthVar->value = ee; - Expression *upper = NULL; - Expression *lower = NULL; - if (sexp->upr) - { - upper = sexp->upr->interpret(istate); - if (upper == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - if (sexp->lwr) - { - lower = sexp->lwr->interpret(istate); - if (lower == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - Type *t = v->type->toBasetype(); - size_t dim; - if (t->ty == Tsarray) - dim = ((TypeSArray *)t)->dim->toInteger(); - else if (t->ty == Tarray) - { - if (!v->value || v->value->op == TOKnull) - { - error("cannot assign to null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - if (v->value->op == TOKarrayliteral) - dim = ((ArrayLiteralExp *)v->value)->elements->dim; - else if (v->value->op ==TOKstring) - { - error("String slice assignment is not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - } - else - { - error("%s cannot be evaluated at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - int upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; - - ArrayLiteralExp *existing; - if (((int)lowerbound < 0) || (upperbound > dim)) - { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - if (upperbound-lowerbound != dim) - { - // Only modifying part of the array. Must create a new array literal. - // If the existing array is uninitialized (this can only happen - // with static arrays), create it. - if (v->value && v->value->op == TOKarrayliteral) - existing = (ArrayLiteralExp *)v->value; - else - { - // this can only happen with static arrays - existing = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); - } - } - - if (e2->op == TOKarrayliteral) - { - // Static array assignment from literal - ArrayLiteralExp *ae = (ArrayLiteralExp *)e2; - if (ae->elements->dim != (upperbound - lowerbound)) - { - error("Array length mismatch assigning [0..%d] to [%d..%d]", ae->elements->dim, lowerbound, upperbound); - return e; - } - if (upperbound - lowerbound == dim) - v->value = ae; - else - { - // value[] = value[0..lower] ~ ae ~ value[upper..$] - existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); - v->value = existing; - } - return e2; - } - else if (t->nextOf()->ty == e2->type->ty) - { - // Static array block assignment - if (upperbound-lowerbound ==dim) - v->value = createBlockDuplicatedArrayLiteral(v->type, e2, dim); - else - { - // value[] = value[0..lower] ~ ae ~ value[upper..$] - existing->elements = spliceElements(existing->elements, createBlockDuplicatedArrayLiteral(v->type, e2, upperbound-lowerbound)->elements, lowerbound); - v->value = existing; - } - return e2; - } - else if (e2->op == TOKstring) - { - StringExp *se = (StringExp *)e2; - // This is problematic. char[8] should be storing - // values as a string literal, not - // as an array literal. Then, for static arrays, we - // could do modifications - // in-place, with a dramatic memory and speed improvement. - error("String slice assignment is not yet supported in CTFE"); - return e2; - } - else - { - error("Slice operation %s cannot be evaluated at compile time", toChars()); - return e; - } - } - else - { - error("%s cannot be evaluated at compile time", toChars()); -#ifdef DEBUG - dump(0); -#endif - } - return e; -} - -Expression *AssignExp::interpret(InterState *istate) -{ - return interpretAssignCommon(istate, NULL); -} - -#define BIN_ASSIGN_INTERPRET(op) \ -Expression *op##AssignExp::interpret(InterState *istate) \ -{ \ - return interpretAssignCommon(istate, &op); \ -} - -BIN_ASSIGN_INTERPRET(Add) -BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET(Cat) -BIN_ASSIGN_INTERPRET(Mul) -BIN_ASSIGN_INTERPRET(Div) -BIN_ASSIGN_INTERPRET(Mod) -BIN_ASSIGN_INTERPRET(Shl) -BIN_ASSIGN_INTERPRET(Shr) -BIN_ASSIGN_INTERPRET(Ushr) -BIN_ASSIGN_INTERPRET(And) -BIN_ASSIGN_INTERPRET(Or) -BIN_ASSIGN_INTERPRET(Xor) - -Expression *PostExp::interpret(InterState *istate) -{ -#if LOG - printf("PostExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if (op == TOKplusplus) - e = interpretAssignCommon(istate, &Add, 1); - else - e = interpretAssignCommon(istate, &Min, 1); -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PostExp::interpret() CANT\n"); -#endif - return e; -} - -Expression *AndAndExp::interpret(InterState *istate) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *OrOrExp::interpret(InterState *istate) -{ -#if LOG - printf("OrOrExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else if (e->isBool(FALSE)) - { - e = e2->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - e = new IntegerExp(e1->loc, 0, type); - else if (e->isBool(TRUE)) - e = new IntegerExp(e1->loc, 1, type); - else - e = EXP_CANT_INTERPRET; - } - } - else - e = EXP_CANT_INTERPRET; - } - return e; -} - - -Expression *CallExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("CallExp::interpret() %s\n", toChars()); -#endif - if (e1->op == TOKdotvar) - { - Expression * pthis = ((DotVarExp*)e1)->e1; - FuncDeclaration *fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); - TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; - if (tf) - { // Member function call - if(pthis->op == TOKthis) - pthis = istate->localThis; - Expression *eresult = fd->interpret(istate, arguments, pthis); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - return e; - } - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (e1->op == TOKvar) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { -#if DMDV2 - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(arguments->dim); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = (Expression *)arguments->data[i]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return earg; - args.data[i] = (void *)earg; - } - e = eval_builtin(b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else -#endif - // Inline .dup - if (fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = (Expression *)arguments->data[1]; - e = e->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - e = expType(type, e); - } - } - else - { - Expression *eresult = fd->interpret(istate, arguments); - if (eresult) - e = eresult; - else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) - e = EXP_VOID_INTERPRET; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - return e; -} - -Expression *CommaExp::interpret(InterState *istate) -{ -#if LOG - printf("CommaExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (e != EXP_CANT_INTERPRET) - e = e2->interpret(istate); - return e; -} - -Expression *CondExp::interpret(InterState *istate) -{ -#if LOG - printf("CondExp::interpret() %s\n", toChars()); -#endif - Expression *e = econd->interpret(istate); - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(TRUE)) - e = e1->interpret(istate); - else if (e->isBool(FALSE)) - e = e2->interpret(istate); - else - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *ArrayLengthExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("ArrayLengthExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - else if (e1->op == TOKnull) - { - e = new IntegerExp(loc, 0, type); - } - else - goto Lcant; - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *IndexExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("IndexExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - - if (e1->op == TOKstring || e1->op == TOKarrayliteral) - { - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - } - - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Index(type, e1, e2); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *SliceExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *lwr; - Expression *upr; - -#if LOG - printf("SliceExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (!this->lwr) - { - e = e1->castTo(NULL, type); - return e->interpret(istate); - } - - /* Set the $ variable - */ - e = ArrayLength(Type::tsize_t, e1); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - if (lengthVar) - lengthVar->value = e; - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (lwr == EXP_CANT_INTERPRET) - goto Lcant; - upr = this->upr->interpret(istate); - if (upr == EXP_CANT_INTERPRET) - goto Lcant; - - return Slice(type, e1, lwr, upr); - -Lcant: - return EXP_CANT_INTERPRET; -} - - -Expression *CatExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("CatExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - { - goto Lcant; - } - e2 = this->e2->interpret(istate); - if (e2 == EXP_CANT_INTERPRET) - goto Lcant; - return Cat(type, e1, e2); - -Lcant: -#if LOG - printf("CatExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *CastExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("CastExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - return Cast(type, to, e1); - -Lcant: -#if LOG - printf("CastExp::interpret() %s CANT\n", toChars()); -#endif - return EXP_CANT_INTERPRET; -} - - -Expression *AssertExp::interpret(InterState *istate) -{ Expression *e; - Expression *e1; - -#if LOG - printf("AssertExp::interpret() %s\n", toChars()); -#endif - if( this->e1->op == TOKaddress) - { // Special case: deal with compiler-inserted assert(&this, "null this") - AddrExp *ade = (AddrExp *)this->e1; - if(ade->e1->op == TOKthis && istate->localThis) - return istate->localThis->interpret(istate); - } -if (this->e1->op == TOKthis) -{ - if(istate->localThis) - return istate->localThis->interpret(istate); -} - e1 = this->e1->interpret(istate); - if (e1 == EXP_CANT_INTERPRET) - goto Lcant; - if (e1->isBool(TRUE)) - { - } - else if (e1->isBool(FALSE)) - { - if (msg) - { - e = msg->interpret(istate); - if (e == EXP_CANT_INTERPRET) - goto Lcant; - error("%s", e->toChars()); - } - else - error("%s failed", toChars()); - goto Lcant; - } - else - goto Lcant; - return e1; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *PtrExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("PtrExp::interpret() %s\n", toChars()); -#endif - - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); - if (ex != EXP_CANT_INTERPRET) - { - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - unsigned offset = ae->e2->toInteger(); - e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - e = Ptr(type, e1); - } - else if (e1->op == TOKsymoff) - { SymOffExp *soe = (SymOffExp *)e1; - VarDeclaration *v = soe->var->isVarDeclaration(); - if (v) - { Expression *ev = getVarExp(loc, istate, v); - if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ev; - e = se->getField(type, soe->offset); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - } -#if DMDV2 -#else // this is required for D1, where structs return *this instead of 'this'. - else if (e1->op == TOKthis) - { - if(istate->localThis) - return istate->localThis->interpret(istate); - } -#endif -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *DotVarExp::interpret(InterState *istate) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("DotVarExp::interpret() %s\n", toChars()); -#endif - - Expression *ex = e1->interpret(istate); - if (ex != EXP_CANT_INTERPRET) - { - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { e = se->getField(type, v->offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } else error("%s.%s is not yet implemented at compile time", ex->toChars(), var->toChars()); - } - -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -/******************************* Special Functions ***************************/ - -Expression *interpret_aaLen(InterState *istate, Expressions *arguments) -{ - if (!arguments || arguments->dim != 1) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); - return e; -} - -Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) -{ -#if LOG - printf("interpret_aaKeys()\n"); -#endif - if (!arguments || arguments->dim != 2) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); - Type *elemType = ((TypeAArray *)aae->type)->index; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - return e; -} - -Expression *interpret_aaValues(InterState *istate, Expressions *arguments) -{ - //printf("interpret_aaValues()\n"); - if (!arguments || arguments->dim != 3) - return NULL; - Expression *earg = (Expression *)arguments->data[0]; - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (earg->op != TOKassocarrayliteral) - return NULL; - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - Expression *e = new ArrayLiteralExp(aae->loc, aae->values); - Type *elemType = ((TypeAArray *)aae->type)->next; - e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); - //printf("result is %s\n", e->toChars()); - return e; -} - +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include + +#include "rmem.h" + +#include "statement.h" +#include "expression.h" +#include "cond.h" +#include "init.h" +#include "staticassert.h" +#include "mtype.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" + +#define LOG 0 + +struct InterState +{ + InterState *caller; // calling function's InterState + FuncDeclaration *fd; // function being interpreted + Dsymbols vars; // variables used in this function + Statement *start; // if !=NULL, start execution at this statement + Statement *gotoTarget; // target of EXP_GOTO_INTERPRET result + Expression *localThis; // value of 'this', or NULL if none + bool awaitingLvalueReturn; // Support for ref return values: + // Any return to this function should return an lvalue. + InterState(); +}; + +InterState::InterState() +{ + memset(this, 0, sizeof(InterState)); +} + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments); +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments); +Expression *interpret_aaValues(InterState *istate, Expressions *arguments); + +Expression *interpret_length(InterState *istate, Expression *earg); +Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd); +Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd); + +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, Expression *elem, size_t dim); +Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference = NULL); +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d); + +/************************************* + * Attempt to interpret a function given the arguments. + * Input: + * istate state for calling function (NULL if none) + * arguments function arguments + * thisarg 'this', if a needThis() function, NULL if not. + * + * Return result expression if successful, NULL if not. + */ + +Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) +{ +#if LOG + printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); + printf("cantInterpret = %d, semanticRun = %d\n", cantInterpret, semanticRun); +#endif + if (global.errors) + return NULL; +#if DMDV2 + if (thisarg && + (!arguments || arguments->dim == 0)) + { + if (ident == Id::length) + return interpret_length(istate, thisarg); + else if (ident == Id::keys) + return interpret_keys(istate, thisarg, this); + else if (ident == Id::values) + return interpret_values(istate, thisarg, this); + } +#endif + + if (cantInterpret || semanticRun == PASSsemantic3) + return NULL; + + if (!fbody) + { cantInterpret = 1; + error("cannot be interpreted at compile time," + " because it has no available source code"); + return NULL; + } + + if (semanticRun < PASSsemantic3 && scope) + { + semantic3(scope); + if (global.errors) // if errors compiling this function + return NULL; + } + if (semanticRun < PASSsemantic3done) + return NULL; + + Type *tb = type->toBasetype(); + assert(tb->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)tb; + Type *tret = tf->next->toBasetype(); + if (tf->varargs && arguments && + ((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim))) + { cantInterpret = 1; + error("C-style variadic functions are not yet implemented in CTFE"); + return NULL; + } + + InterState istatex; + istatex.caller = istate; + istatex.fd = this; + istatex.localThis = thisarg; + + Expressions vsave; // place to save previous parameter values + size_t dim = 0; + if (needThis() && !thisarg) + { cantInterpret = 1; + // error, no this. Prevent segfault. + error("need 'this' to access member %s", toChars()); + return NULL; + } + if (thisarg && !istate) + { // Check that 'this' aleady has a value + if (thisarg->interpret(istate) == EXP_CANT_INTERPRET) + return NULL; + } + if (arguments) + { + dim = arguments->dim; + assert(!dim || (parameters && (parameters->dim == dim))); + vsave.setDim(dim); + + /* Evaluate all the arguments to the function, + * store the results in eargs[] + */ + Expressions eargs; + eargs.setDim(dim); + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)arguments->data[i]; + Parameter *arg = Parameter::getNth(tf->parameters, i); + + if (arg->storageClass & (STCout | STCref)) + { + if (!istate) + { + earg->error("%s cannot be passed by reference at compile time", earg->toChars()); + return NULL; + } + } + else if (arg->storageClass & STClazy) + { + } + else + { /* Value parameters + */ + Type *ta = arg->type->toBasetype(); + if (ta->ty == Tsarray && earg->op == TOKaddress) + { + /* Static arrays are passed by a simple pointer. + * Skip past this to get at the actual arg. + */ + earg = ((AddrExp *)earg)->e1; + } + earg = earg->interpret(istate); // ? istate : &istatex); + if (earg == EXP_CANT_INTERPRET) + { cantInterpret = 1; + return NULL; + } + } + eargs.data[i] = earg; + } + + for (size_t i = 0; i < dim; i++) + { Expression *earg = (Expression *)eargs.data[i]; + Parameter *arg = Parameter::getNth(tf->parameters, i); + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + vsave.data[i] = v->value; +#if LOG + printf("arg[%d] = %s\n", i, earg->toChars()); +#endif + if (arg->storageClass & (STCout | STCref) && earg->op==TOKvar) + { + VarExp *ve = (VarExp *)earg; + VarDeclaration *v2 = ve->var->isVarDeclaration(); + if (!v2) + { cantInterpret = 1; + return NULL; + } + v->value = earg; + /* Don't restore the value of v2 upon function return + */ + assert(istate); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *vx = (VarDeclaration *)istate->vars.data[i]; + if (vx == v2) + { istate->vars.data[i] = NULL; + break; + } + } + } + else + { // Value parameters and non-trivial references + v->value = earg; + } +#if LOG + printf("interpreted arg[%d] = %s\n", i, earg->toChars()); +#endif + } + } + // Don't restore the value of 'this' upon function return + if (needThis() && thisarg->op == TOKvar && istate) + { + VarDeclaration *thisvar = ((VarExp *)(thisarg))->var->isVarDeclaration(); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v == thisvar) + { istate->vars.data[i] = NULL; + break; + } + } + } + + /* Save the values of the local variables used + */ + Expressions valueSaves; + if (istate && !isNested()) + { + //printf("saving local variables...\n"); + valueSaves.setDim(istate->vars.dim); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { + //printf("\tsaving [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + valueSaves.data[i] = v->value; + v->value = NULL; + } + } + } + + Expression *e = NULL; + while (1) + { + e = fbody->interpret(&istatex); + if (e == EXP_CANT_INTERPRET) + { +#if LOG + printf("function body failed to interpret\n"); +#endif + e = NULL; + } + + /* This is how we deal with a recursive statement AST + * that has arbitrary goto statements in it. + * Bubble up a 'result' which is the target of the goto + * statement, then go recursively down the AST looking + * for that statement, then execute starting there. + */ + if (e == EXP_GOTO_INTERPRET) + { + istatex.start = istatex.gotoTarget; // set starting statement + istatex.gotoTarget = NULL; + } + else + break; + } + /* Restore the parameter values + */ + for (size_t i = 0; i < dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + v->value = (Expression *)vsave.data[i]; + } + + if (istate && !isNested()) + { + /* Restore the variable values + */ + //printf("restoring local variables...\n"); + for (size_t i = 0; i < istate->vars.dim; i++) + { VarDeclaration *v = (VarDeclaration *)istate->vars.data[i]; + if (v) + { v->value = (Expression *)valueSaves.data[i]; + //printf("\trestoring [%d] %s = %s\n", i, v->toChars(), v->value ? v->value->toChars() : ""); + } + } + } + return e; +} + +/******************************** Statement ***************************/ + +#define START() \ + if (istate->start) \ + { if (istate->start != this) \ + return NULL; \ + istate->start = NULL; \ + } + +/*********************************** + * Interpret the statement. + * Returns: + * NULL continue to next statement + * EXP_CANT_INTERPRET cannot interpret statement at compile time + * !NULL expression from return statement + */ + +Expression *Statement::interpret(InterState *istate) +{ +#if LOG + printf("Statement::interpret()\n"); +#endif + START() + error("Statement %s cannot be interpreted at compile time", this->toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *ExpStatement::interpret(InterState *istate) +{ +#if LOG + printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (exp) + { + Expression *e = exp->interpret(istate); + if (e == EXP_CANT_INTERPRET) + { + //printf("-ExpStatement::interpret(): %p\n", e); + return EXP_CANT_INTERPRET; + } + } + return NULL; +} + +Expression *CompoundStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("CompoundStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (s) + { + e = s->interpret(istate); + if (e) + break; + } + } + } +#if LOG + printf("-CompoundStatement::interpret() %p\n", e); +#endif + return e; +} + +Expression *UnrolledLoopStatement::interpret(InterState *istate) +{ Expression *e = NULL; + +#if LOG + printf("UnrolledLoopStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statements) + { + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + e = s->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_CONTINUE_INTERPRET) + { e = NULL; + continue; + } + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e) + break; + } + } + return e; +} + +Expression *IfStatement::interpret(InterState *istate) +{ +#if LOG + printf("IfStatement::interpret(%s)\n", condition->toChars()); +#endif + + if (istate->start == this) + istate->start = NULL; + if (istate->start) + { + Expression *e = NULL; + if (ifbody) + e = ifbody->interpret(istate); + if (istate->start && elsebody) + e = elsebody->interpret(istate); + return e; + } + + Expression *e = condition->interpret(istate); + assert(e); + //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = ifbody ? ifbody->interpret(istate) : NULL; + else if (e->isBool(FALSE)) + e = elsebody ? elsebody->interpret(istate) : NULL; + else + { + e = EXP_CANT_INTERPRET; + } + } + return e; +} + +Expression *ScopeStatement::interpret(InterState *istate) +{ +#if LOG + printf("ScopeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + +// Helper for ReturnStatement::interpret() for returning references. +// Given an original expression, which is known to be a reference to a reference, +// turn it into a reference. +Expression * replaceReturnReference(Expression *original, InterState *istate) +{ + Expression *e = original; + if (e->op == TOKcall) + { // If it's a function call, interpret it now. + // It also needs to return an lvalue. + istate->awaitingLvalueReturn = true; + e = e->interpret(istate); + if (e == EXP_CANT_INTERPRET) + return e; + } + // If it is a reference to a reference, convert it to a reference + if (e->op == TOKvar) + { + VarExp *ve = (VarExp *)e; + VarDeclaration *v = ve->var->isVarDeclaration(); + assert (v && v->value); + return v->value; + } + + if (e->op == TOKthis) + { + return istate->localThis; + } + + Expression *r = e->copy(); + e = r; + Expression *next; + for (;;) + { + if (e->op == TOKindex) + next = ((IndexExp*)e)->e1; + else if (e->op == TOKdotvar) + next = ((DotVarExp *)e)->e1; + else if (e->op == TOKdotti) + next = ((DotTemplateInstanceExp *)e)->e1; + else if (e->op == TOKslice) + next = ((SliceExp*)e)->e1; + else + return EXP_CANT_INTERPRET; + + Expression *old = next; + + if (next->op == TOKcall) + { + istate->awaitingLvalueReturn = true; + next = next->interpret(istate); + if (next == EXP_CANT_INTERPRET) return next; + } + if (next->op == TOKvar) + { + VarDeclaration * v = ((VarExp*)next)->var->isVarDeclaration(); + if (v) + next = v->value; + } + else if (next->op == TOKthis) + next = istate->localThis; + + if (old == next) + { // Haven't found the reference yet. Need to keep copying. + next = next->copy(); + old = next; + } + if (e->op == TOKindex) + ((IndexExp*)e)->e1 = next; + else if (e->op == TOKdotvar) + ((DotVarExp *)e)->e1 = next; + else if (e->op == TOKdotti) + ((DotTemplateInstanceExp *)e)->e1 = next; + else if (e->op == TOKslice) + ((SliceExp*)e)->e1 = next; + + if (old != next) + break; + e = next; + } + + return r; +} + +Expression *ReturnStatement::interpret(InterState *istate) +{ +#if LOG + printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); +#endif + START() + if (!exp) + return EXP_VOID_INTERPRET; + assert(istate && istate->fd && istate->fd->type); +#if DMDV2 + /* If the function returns a ref AND it's been called from an assignment, + * we need to return an lvalue. Otherwise, just do an (rvalue) interpret. + */ + if (istate->fd->type && istate->fd->type->ty==Tfunction) + { + TypeFunction *tf = (TypeFunction *)istate->fd->type; + if (tf->isref && istate->caller && istate->caller->awaitingLvalueReturn) + { // We need to return an lvalue. Can't do a normal interpret. + Expression *e = replaceReturnReference(exp, istate); + if (e == EXP_CANT_INTERPRET) + error("ref return %s is not yet supported in CTFE", exp->toChars()); + return e; + } + if (tf->next && (tf->next->ty == Tdelegate) && istate->fd->closureVars.dim > 0) + { + // To support this, we need to copy all the closure vars + // into the delegate literal. + error("closures are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } + } +#endif + +#if LOG + Expression *e = exp->interpret(istate); + printf("e = %p\n", e); + return e; +#else + return exp->interpret(istate); +#endif +} + +Expression *BreakStatement::interpret(InterState *istate) +{ +#if LOG + printf("BreakStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_BREAK_INTERPRET; +} + +Expression *ContinueStatement::interpret(InterState *istate) +{ +#if LOG + printf("ContinueStatement::interpret()\n"); +#endif + START() + if (ident) + return EXP_CANT_INTERPRET; + else + return EXP_CONTINUE_INTERPRET; +} + +Expression *WhileStatement::interpret(InterState *istate) +{ +#if LOG + printf("WhileStatement::interpret()\n"); +#endif + assert(0); // rewritten to ForStatement + return NULL; +} + +Expression *DoStatement::interpret(InterState *istate) +{ +#if LOG + printf("DoStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + + Lcontinue: + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForStatement::interpret(InterState *istate) +{ +#if LOG + printf("ForStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e; + + if (init) + { + e = init->interpret(istate); + if (e == EXP_CANT_INTERPRET) + return e; + assert(!e); + } + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + if (e == EXP_CONTINUE_INTERPRET) + goto Lcontinue; + if (e) + return e; + } + + while (1) + { + if (!condition) + goto Lhead; + e = condition->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + if (!e->isConst()) + { e = EXP_CANT_INTERPRET; + break; + } + if (e->isBool(TRUE)) + { + Lhead: + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e && e != EXP_CONTINUE_INTERPRET) + break; + Lcontinue: + if (increment) + { + e = increment->interpret(istate); + if (e == EXP_CANT_INTERPRET) + break; + } + } + else if (e->isBool(FALSE)) + { e = NULL; + break; + } + else + assert(0); + } + return e; +} + +Expression *ForeachStatement::interpret(InterState *istate) +{ +#if 1 + assert(0); // rewritten to ForStatement + return NULL; +#else +#if LOG + printf("ForeachStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *eaggr; + + if (value->isOut() || value->isRef()) + return EXP_CANT_INTERPRET; + + eaggr = aggr->interpret(istate); + if (eaggr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *dim = ArrayLength(Type::tsize_t, eaggr); + if (dim == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key ? key->value : NULL; + Expression *valuesave = value->value; + + uinteger_t d = dim->toUInteger(); + uinteger_t index; + + if (op == TOKforeach) + { + for (index = 0; index < d; index++) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + else // TOKforeach_reverse + { + for (index = d; index-- != 0;) + { + Expression *ekey = new IntegerExp(loc, index, Type::tsize_t); + if (key) + key->value = ekey; + e = Index(value->type, eaggr, ekey); + if (e == EXP_CANT_INTERPRET) + break; + value->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == EXP_CONTINUE_INTERPRET) + e = NULL; + else if (e) + break; + } + } + value->value = valuesave; + if (key) + key->value = keysave; + return e; +#endif +} + +#if DMDV2 +Expression *ForeachRangeStatement::interpret(InterState *istate) +{ +#if 1 + assert(0); // rewritten to ForStatement + return NULL; +#else +#if LOG + printf("ForeachRangeStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (istate->start) + return NULL; + + Expression *e = NULL; + Expression *elwr = lwr->interpret(istate); + if (elwr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *eupr = upr->interpret(istate); + if (eupr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Expression *keysave = key->value; + + if (op == TOKforeach) + { + key->value = elwr; + + while (1) + { + e = Cmp(TOKlt, key->value->type, key->value, eupr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + if (e == NULL || e == EXP_CONTINUE_INTERPRET) + { e = Add(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + } + else + break; + } + } + else // TOKforeach_reverse + { + key->value = eupr; + + do + { + e = Cmp(TOKgt, key->value->type, key->value, elwr); + if (e == EXP_CANT_INTERPRET) + break; + if (e->isBool(TRUE) == FALSE) + { e = NULL; + break; + } + + e = Min(key->value->type, key->value, new IntegerExp(loc, 1, key->value->type)); + if (e == EXP_CANT_INTERPRET) + break; + key->value = e; + + e = body ? body->interpret(istate) : NULL; + if (e == EXP_CANT_INTERPRET) + break; + if (e == EXP_BREAK_INTERPRET) + { e = NULL; + break; + } + } while (e == NULL || e == EXP_CONTINUE_INTERPRET); + } + key->value = keysave; + return e; +#endif +} +#endif + +Expression *SwitchStatement::interpret(InterState *istate) +{ +#if LOG + printf("SwitchStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + Expression *e = NULL; + + if (istate->start) + { + e = body ? body->interpret(istate) : NULL; + if (istate->start) + return NULL; + if (e == EXP_CANT_INTERPRET) + return e; + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; + } + + + Expression *econdition = condition->interpret(istate); + if (econdition == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + + Statement *s = NULL; + if (cases) + { + for (size_t i = 0; i < cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)cases->data[i]; + e = Equal(TOKequal, Type::tint32, econdition, cs->exp); + if (e == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (e->isBool(TRUE)) + { s = cs; + break; + } + } + } + if (!s) + { if (hasNoDefault) + error("no default or case for %s in switch statement", econdition->toChars()); + s = sdefault; + } + + assert(s); + istate->start = s; + e = body ? body->interpret(istate) : NULL; + assert(!istate->start); + if (e == EXP_BREAK_INTERPRET) + return NULL; + return e; +} + +Expression *CaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *DefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("DefaultStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + if (statement) + return statement->interpret(istate); + else + return NULL; +} + +Expression *GotoStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoStatement::interpret()\n"); +#endif + START() + assert(label && label->statement); + istate->gotoTarget = label->statement; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoCaseStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoCaseStatement::interpret()\n"); +#endif + START() + assert(cs); + istate->gotoTarget = cs; + return EXP_GOTO_INTERPRET; +} + +Expression *GotoDefaultStatement::interpret(InterState *istate) +{ +#if LOG + printf("GotoDefaultStatement::interpret()\n"); +#endif + START() + assert(sw && sw->sdefault); + istate->gotoTarget = sw->sdefault; + return EXP_GOTO_INTERPRET; +} + +Expression *LabelStatement::interpret(InterState *istate) +{ +#if LOG + printf("LabelStatement::interpret()\n"); +#endif + if (istate->start == this) + istate->start = NULL; + return statement ? statement->interpret(istate) : NULL; +} + + +Expression *TryCatchStatement::interpret(InterState *istate) +{ +#if LOG + printf("TryCatchStatement::interpret()\n"); +#endif + START() + error("try-catch statements are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; +} + + +Expression *TryFinallyStatement::interpret(InterState *istate) +{ +#if LOG + printf("TryFinallyStatement::interpret()\n"); +#endif + START() + error("try-finally statements are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; +} + +Expression *ThrowStatement::interpret(InterState *istate) +{ +#if LOG + printf("ThrowStatement::interpret()\n"); +#endif + START() + error("throw statements are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; +} + +Expression *OnScopeStatement::interpret(InterState *istate) +{ +#if LOG + printf("OnScopeStatement::interpret()\n"); +#endif + START() + error("scope guard statements are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; +} + +Expression *WithStatement::interpret(InterState *istate) +{ +#if LOG + printf("WithStatement::interpret()\n"); +#endif + START() + error("with statements are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; +} + +Expression *AsmStatement::interpret(InterState *istate) +{ +#if LOG + printf("AsmStatement::interpret()\n"); +#endif + START() + error("asm statements cannot be interpreted at compile time"); + return EXP_CANT_INTERPRET; +} + +/******************************** Expression ***************************/ + +Expression *Expression::interpret(InterState *istate) +{ +#if LOG + printf("Expression::interpret() %s\n", toChars()); + printf("type = %s\n", type->toChars()); + dump(0); +#endif + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *ThisExp::interpret(InterState *istate) +{ + if (istate && istate->localThis) + return istate->localThis->interpret(istate); + error("value of 'this' is not known at compile time"); + return EXP_CANT_INTERPRET; +} + +Expression *NullExp::interpret(InterState *istate) +{ + return this; +} + +Expression *IntegerExp::interpret(InterState *istate) +{ +#if LOG + printf("IntegerExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *RealExp::interpret(InterState *istate) +{ +#if LOG + printf("RealExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *ComplexExp::interpret(InterState *istate) +{ + return this; +} + +Expression *StringExp::interpret(InterState *istate) +{ +#if LOG + printf("StringExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *FuncExp::interpret(InterState *istate) +{ +#if LOG + printf("FuncExp::interpret() %s\n", toChars()); +#endif + return this; +} + +Expression *SymOffExp::interpret(InterState *istate) +{ +#if LOG + printf("SymOffExp::interpret() %s\n", toChars()); +#endif + if (var->isFuncDeclaration() && offset == 0) + { + return this; + } + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *DelegateExp::interpret(InterState *istate) +{ +#if LOG + printf("DelegateExp::interpret() %s\n", toChars()); +#endif + return this; +} + + +// ------------------------------------------------------------- +// Remove out, ref, and this +// ------------------------------------------------------------- +// The variable used in a dotvar, index, or slice expression, +// after 'out', 'ref', and 'this' have been removed. +// *isReference will be set to true if a reference was removed. +Expression * resolveReferences(Expression *e, Expression *thisval, bool *isReference /*=NULL */) +{ + if (isReference) + *isReference = false; + for(;;) + { + if (e->op == TOKthis) + { + assert(thisval); + assert(e != thisval); + e = thisval; + continue; + } + if (e->op == TOKvar) { + // Chase down rebinding of out and ref. + VarExp *ve = (VarExp *)e; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->value && v->value->op == TOKvar) // it's probably a reference + { + // Make sure it's a real reference. + // It's not a reference if v is a struct initialized to + // 0 using an __initZ StaticStructInitDeclaration from + // TypeStruct::defaultInit() + VarExp *ve2 = (VarExp *)v->value; + if (!ve2->var->isStaticStructInitDeclaration()) + { + if (isReference) + *isReference = true; + e = v->value; + continue; + } + } + else if (v && v->value && (v->value->op==TOKindex || v->value->op == TOKdotvar + || v->value->op == TOKthis || v->value->op == TOKslice )) + { + e = v->value; + continue; + } + } + break; + } + return e; +} + +Expression *getVarExp(Loc loc, InterState *istate, Declaration *d) +{ + Expression *e = EXP_CANT_INTERPRET; + VarDeclaration *v = d->isVarDeclaration(); +#if IN_LLVM + StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration(); +#else + SymbolDeclaration *s = d->isSymbolDeclaration(); +#endif + if (v) + { +#if DMDV2 +#if !IN_LLVM // TODO: + /* Magic variable __ctfe always returns true when interpreting + */ + if (v->ident == Id::ctfe) + return new IntegerExp(loc, 1, Type::tbool); +#endif + if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->value) +#else + if (v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (e && !e->type) + e->type = v->type; + } + else if ((v->isCTFE() || (!v->isDataseg() && istate)) && !v->value) + { + if (v->init) + { + if (v->init->isVoidInitializer()) + { + error(loc, "variable %s is used before initialization", v->toChars()); + return EXP_CANT_INTERPRET; + } + e = v->init->toExpression(); + e = e->interpret(istate); + } + else + e = v->type->defaultInitLiteral(loc); + } + else if (!v->isDataseg() && !istate) { + error(loc, "variable %s cannot be read at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + else + { e = v->value; + if (!v->isCTFE() && v->isDataseg()) + { error(loc, "static variable %s cannot be read at compile time", v->toChars()); + e = EXP_CANT_INTERPRET; + } + else if (!e) + error(loc, "variable %s is used before initialization", v->toChars()); + else if (e != EXP_CANT_INTERPRET) + e = e->interpret(istate); + } + if (!e) + e = EXP_CANT_INTERPRET; + } + else if (s) + { + Expressions *exps = new Expressions(); + e = new StructLiteralExp(0, s->dsym, exps); + e = e->semantic(NULL); + } + return e; +} + +Expression *VarExp::interpret(InterState *istate) +{ +#if LOG + printf("VarExp::interpret() %s\n", toChars()); +#endif + return getVarExp(loc, istate, var); +} + +Expression *DeclarationExp::interpret(InterState *istate) +{ +#if LOG + printf("DeclarationExp::interpret() %s\n", toChars()); +#endif + Expression *e; + VarDeclaration *v = declaration->isVarDeclaration(); + if (v) + { + Dsymbol *s = v->toAlias(); + if (s == v && !v->isStatic() && v->init) + { + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie) + e = ie->exp->interpret(istate); + else if (v->init->isVoidInitializer()) + e = NULL; + } +#if DMDV2 + else if (s == v && (v->isConst() || v->isImmutable()) && v->init) +#else + else if (s == v && v->isConst() && v->init) +#endif + { e = v->init->toExpression(); + if (!e) + e = EXP_CANT_INTERPRET; + else if (!e->type) + e->type = v->type; + } + } + else if (declaration->isAttribDeclaration() || + declaration->isTemplateMixin() || + declaration->isTupleDeclaration()) + { // These can be made to work, too lazy now + error("Declaration %s is not yet implemented in CTFE", toChars()); + + e = EXP_CANT_INTERPRET; + } + else + { // Others should not contain executable code, so are trivial to evaluate + e = NULL; + } +#if LOG + printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); +#endif + return e; +} + +Expression *TupleExp::interpret(InterState *istate) +{ +#if LOG + printf("TupleExp::interpret() %s\n", toChars()); +#endif + Expressions *expsx = NULL; + + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return ex; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(exps->dim); + for (size_t j = 0; j < i; j++) + { + expsx->data[j] = exps->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + if (expsx) + { TupleExp *te = new TupleExp(loc, expsx); + expandTuples(te->exps); + te->type = new TypeTuple(te->exps); + return te; + } + return this; +} + +Expression *ArrayLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("ArrayLiteralExp::interpret() %s\n", toChars()); +#endif + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + Expression *ex; + + ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerror; + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + goto Lerror; + ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); + ae->type = type; + return ae; + } + return this; + +Lerror: + if (expsx) + delete expsx; + error("cannot interpret array literal"); + return EXP_CANT_INTERPRET; +} + +Expression *AssocArrayLiteralExp::interpret(InterState *istate) +{ Expressions *keysx = keys; + Expressions *valuesx = values; + +#if LOG + printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); +#endif + for (size_t i = 0; i < keys->dim; i++) + { Expression *ekey = (Expression *)keys->data[i]; + Expression *evalue = (Expression *)values->data[i]; + Expression *ex; + + ex = ekey->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != ekey) + { + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + keysx->data[i] = (void *)ex; + } + + ex = evalue->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + + /* If any changes, do Copy On Write + */ + if (ex != evalue) + { + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + valuesx->data[i] = (void *)ex; + } + } + if (keysx != keys) + expandTuples(keysx); + if (valuesx != values) + expandTuples(valuesx); + if (keysx->dim != valuesx->dim) + goto Lerr; + + /* Remove duplicate keys + */ + for (size_t i = 1; i < keysx->dim; i++) + { Expression *ekey = (Expression *)keysx->data[i - 1]; + + for (size_t j = i; j < keysx->dim; j++) + { Expression *ekey2 = (Expression *)keysx->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, ekey2); + if (ex == EXP_CANT_INTERPRET) + goto Lerr; + if (ex->isBool(TRUE)) // if a match + { + // Remove ekey + if (keysx == keys) + keysx = (Expressions *)keys->copy(); + if (valuesx == values) + valuesx = (Expressions *)values->copy(); + keysx->remove(i - 1); + valuesx->remove(i - 1); + i -= 1; // redo the i'th iteration + break; + } + } + } + + if (keysx != keys || valuesx != values) + { + AssocArrayLiteralExp *ae; + ae = new AssocArrayLiteralExp(loc, keysx, valuesx); + ae->type = type; + return ae; + } + return this; + +Lerr: + if (keysx != keys) + delete keysx; + if (valuesx != values) + delete values; + return EXP_CANT_INTERPRET; +} + +Expression *StructLiteralExp::interpret(InterState *istate) +{ Expressions *expsx = NULL; + +#if LOG + printf("StructLiteralExp::interpret() %s\n", toChars()); +#endif + /* We don't know how to deal with overlapping fields + */ + if (sd->hasUnions) + { error("Unions with overlapping fields are not yet supported in CTFE"); + return EXP_CANT_INTERPRET; + } + + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + + Expression *ex = e->interpret(istate); + if (ex == EXP_CANT_INTERPRET) + { delete expsx; + return EXP_CANT_INTERPRET; + } + + /* If any changes, do Copy On Write + */ + if (ex != e) + { + if (!expsx) + { expsx = new Expressions(); + expsx->setDim(elements->dim); + for (size_t j = 0; j < elements->dim; j++) + { + expsx->data[j] = elements->data[j]; + } + } + expsx->data[i] = (void *)ex; + } + } + } + if (elements && expsx) + { + expandTuples(expsx); + if (expsx->dim != elements->dim) + { delete expsx; + return EXP_CANT_INTERPRET; + } + StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); + se->type = type; + return se; + } + return this; +} + +Expression *NewExp::interpret(InterState *istate) +{ +#if LOG + printf("NewExp::interpret() %s\n", toChars()); +#endif + if (newtype->ty == Tarray && arguments && arguments->dim == 1) + { + Expression *lenExpr = ((Expression *)(arguments->data[0]))->interpret(istate); + if (lenExpr == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + return createBlockDuplicatedArrayLiteral(newtype, + ((TypeArray *)newtype)->next->defaultInitLiteral(), + lenExpr->toInteger()); + } + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; +} + +Expression *UnaExp::interpretCommon(InterState *istate, Expression *(*fp)(Type *, Expression *)) +{ Expression *e; + Expression *e1; + +#if LOG + printf("UnaExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define UNA_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +UNA_INTERPRET(Neg) +UNA_INTERPRET(Com) +UNA_INTERPRET(Not) +UNA_INTERPRET(Bool) + + +typedef Expression *(*fp_t)(Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon(InterState *istate, fp_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1) + goto Lcant; + + e = (*fp)(type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon(istate, &op); \ +} + +BIN_INTERPRET(Add) +BIN_INTERPRET(Min) +BIN_INTERPRET(Mul) +BIN_INTERPRET(Div) +BIN_INTERPRET(Mod) +BIN_INTERPRET(Shl) +BIN_INTERPRET(Shr) +BIN_INTERPRET(Ushr) +BIN_INTERPRET(And) +BIN_INTERPRET(Or) +BIN_INTERPRET(Xor) + + +typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); + +Expression *BinExp::interpretCommon2(InterState *istate, fp2_t fp) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("BinExp::interpretCommon2() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isConst() != 1 && + e1->op != TOKnull && + e1->op != TOKstring && + e1->op != TOKarrayliteral && + e1->op != TOKstructliteral) + goto Lcant; + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + if (e2->isConst() != 1 && + e2->op != TOKnull && + e2->op != TOKstring && + e2->op != TOKarrayliteral && + e2->op != TOKstructliteral) + goto Lcant; + + e = (*fp)(op, type, e1, e2); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +#define BIN_INTERPRET2(op) \ +Expression *op##Exp::interpret(InterState *istate) \ +{ \ + return interpretCommon2(istate, &op); \ +} + +BIN_INTERPRET2(Equal) +BIN_INTERPRET2(Identity) +BIN_INTERPRET2(Cmp) + +/* Helper functions for BinExp::interpretAssignCommon + */ + +/*************************************** + * Duplicate the elements array, then set field 'indexToChange' = newelem. + */ +Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, void *newelem) +{ + Expressions *expsx = new Expressions(); + expsx->setDim(oldelems->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j == indexToChange) + expsx->data[j] = newelem; + else + expsx->data[j] = oldelems->data[j]; + } + return expsx; +} + +/*************************************** + * Returns oldelems[0..insertpoint] ~ newelems ~ oldelems[insertpoint+newelems.length..$] + */ +Expressions *spliceElements(Expressions *oldelems, + Expressions *newelems, size_t insertpoint) +{ + Expressions *expsx = new Expressions(); + expsx->setDim(oldelems->dim); + for (size_t j = 0; j < expsx->dim; j++) + { + if (j >= insertpoint && j < insertpoint + newelems->dim) + expsx->data[j] = newelems->data[j - insertpoint]; + else + expsx->data[j] = oldelems->data[j]; + } + return expsx; +} + +/*************************************** + * Returns oldstr[0..insertpoint] ~ newstr ~ oldstr[insertpoint+newlen..$] + */ +StringExp *spliceStringExp(StringExp *oldstr, StringExp *newstr, size_t insertpoint) +{ + assert(oldstr->sz==newstr->sz); + unsigned char *s; + size_t oldlen = oldstr->len; + size_t newlen = newstr->len; + size_t sz = oldstr->sz; + s = (unsigned char *)mem.calloc(oldlen + 1, sz); + memcpy(s, oldstr->string, oldlen * sz); + memcpy(s + insertpoint * sz, newstr->string, newlen * sz); + StringExp *se2 = new StringExp(oldstr->loc, s, oldlen); + se2->committed = oldstr->committed; + se2->postfix = oldstr->postfix; + se2->type = oldstr->type; + return se2; +} + +/****************************** + * Create an array literal consisting of 'elem' duplicated 'dim' times. + */ +ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Type *type, + Expression *elem, size_t dim) +{ + Expressions *elements = new Expressions(); + elements->setDim(dim); + for (size_t i = 0; i < dim; i++) + elements->data[i] = elem; + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = type; + return ae; +} + +/****************************** + * Create a string literal consisting of 'value' duplicated 'dim' times. + */ +StringExp *createBlockDuplicatedStringLiteral(Type *type, + unsigned value, size_t dim, int sz) +{ + unsigned char *s; + s = (unsigned char *)mem.calloc(dim + 1, sz); + for (int elemi=0; elemitype = type; + return se; +} + +/******************************** + * Add v to the istate list, unless it already exists there. + */ +void addVarToInterstate(InterState *istate, VarDeclaration *v) +{ + if (!v->isParameter()) + { + for (size_t i = 0; 1; i++) + { + if (i == istate->vars.dim) + { istate->vars.push(v); + //printf("\tadding %s to istate\n", v->toChars()); + break; + } + if (v == (VarDeclaration *)istate->vars.data[i]) + break; + } + } +} + +// Create a new struct literal, which is the same as se except that se.field[offset] = elem +Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval) +{ + int fieldi = se->getFieldIndex(newval->type, offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + /* Create new struct literal reflecting updated fieldi + */ + Expressions *expsx = changeOneElement(se->elements, fieldi, newval); + Expression * ee = new StructLiteralExp(se->loc, se->sd, expsx); + ee->type = se->type; + return ee; +} + +/******************************** + * Given an array literal arr (either arrayliteral, stringliteral, or assocArrayLiteral), + * set arr[index] = newval and return the new array. + * + */ +Expression * assignArrayElement(Loc loc, Expression *arr, Expression *index, Expression *newval) +{ + ArrayLiteralExp *ae = NULL; + AssocArrayLiteralExp *aae = NULL; + StringExp *se = NULL; + if (arr->op == TOKarrayliteral) + ae = (ArrayLiteralExp *)arr; + else if (arr->op == TOKassocarrayliteral) + aae = (AssocArrayLiteralExp *)arr; + else if (arr->op == TOKstring) + se = (StringExp *)arr; + else assert(0); + + if (ae) + { + int elemi = index->toInteger(); + if (elemi >= ae->elements->dim) + { + error(loc, "array index %d is out of bounds %s[0..%d]", elemi, + arr->toChars(), ae->elements->dim); + return EXP_CANT_INTERPRET; + } + // Create new array literal reflecting updated elem + Expressions *expsx = changeOneElement(ae->elements, elemi, newval); + Expression *ee = new ArrayLiteralExp(ae->loc, expsx); + ee->type = ae->type; + newval = ee; + } + else if (se) + { + /* Create new string literal reflecting updated elem + */ + int elemi = index->toInteger(); + if (elemi >= se->len) + { + error(loc, "array index %d is out of bounds %s[0..%d]", elemi, + arr->toChars(), se->len); + return EXP_CANT_INTERPRET; + } + unsigned char *s; + s = (unsigned char *)mem.calloc(se->len + 1, se->sz); + memcpy(s, se->string, se->len * se->sz); + unsigned value = newval->toInteger(); + switch (se->sz) + { + case 1: s[elemi] = value; break; + case 2: ((unsigned short *)s)[elemi] = value; break; + case 4: ((unsigned *)s)[elemi] = value; break; + default: + assert(0); + break; + } + StringExp *se2 = new StringExp(se->loc, s, se->len); + se2->committed = se->committed; + se2->postfix = se->postfix; + se2->type = se->type; + newval = se2; + } + else if (aae) + { + /* Create new associative array literal reflecting updated key/value + */ + Expressions *keysx = aae->keys; + Expressions *valuesx = new Expressions(); + valuesx->setDim(aae->values->dim); + int updated = 0; + for (size_t j = valuesx->dim; j; ) + { j--; + Expression *ekey = (Expression *)aae->keys->data[j]; + Expression *ex = Equal(TOKequal, Type::tbool, ekey, index); + if (ex == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + if (ex->isBool(TRUE)) + { valuesx->data[j] = (void *)newval; + updated = 1; + } + else + valuesx->data[j] = aae->values->data[j]; + } + if (!updated) + { // Append index/newval to keysx[]/valuesx[] + valuesx->push(newval); + keysx = (Expressions *)keysx->copy(); + keysx->push(index); + } + Expression *aae2 = new AssocArrayLiteralExp(aae->loc, keysx, valuesx); + aae2->type = aae->type; + return aae2; + } + return newval; +} + +// Return true if e is derived from UnaryExp. +// Consider moving this function into Expression. +UnaExp *isUnaExp(Expression *e) +{ + switch (e->op) + { + case TOKdotvar: + case TOKindex: + case TOKslice: + case TOKcall: + case TOKdot: + case TOKdotti: + case TOKdottype: + case TOKcast: + return (UnaExp *)e; + default: + break; + } + return NULL; +} + +// To resolve an assignment expression, we need to walk to the end of the +// expression to find the ultimate variable which is modified. But, in building +// up the expression, we need to walk the tree *backwards*. There isn't a +// standard way to do this, but if we know we're at depth d, iterating from +// the root up to depth d-1 will give us the parent node. Inefficient, but +// depth is almost always < 3. +struct ExpressionReverseIterator +{ + Expression *totalExpr; // The root expression + Expression *thisval; // The value to be used for TOKthis + int totalDepth; + + ExpressionReverseIterator(Expression *root, Expression *thisexpr) + { + totalExpr = root; + thisval = thisexpr; + totalDepth = findExpressionDepth(totalExpr); + } + + int findExpressionDepth(Expression *e); + Expression *getExpressionAtDepth(int depth); +}; + +// Determines the depth in unary expressions. +int ExpressionReverseIterator::findExpressionDepth(Expression *e) +{ + int depth = 0; + for (;;) + { + e = resolveReferences(e, thisval); + if (e->op == TOKvar) + return depth; + if (e->op == TOKcall) + return depth; + ++depth; + UnaExp *u = isUnaExp(e); + if (u) + e = u->e1; + else + return depth; + } +} + +Expression *ExpressionReverseIterator::getExpressionAtDepth(int depth) +{ + Expression *e = totalExpr; + int d = 0; + for (;;) + { + e = resolveReferences(e, thisval); + if (d == depth) return e; + ++d; + assert(e->op != TOKvar); + UnaExp *u = isUnaExp(e); + if (u) + e = u->e1; + else + return e; + } +} + +// Returns the variable which is eventually modified, or NULL if an rvalue. +// thisval is the current value of 'this'. +VarDeclaration * findParentVar(Expression *e, Expression *thisval) +{ + for (;;) + { + e = resolveReferences(e, thisval); + if (e->op == TOKvar) + break; + if (e->op == TOKindex) + e = ((IndexExp*)e)->e1; + else if (e->op == TOKdotvar) + e = ((DotVarExp *)e)->e1; + else if (e->op == TOKdotti) + e = ((DotTemplateInstanceExp *)e)->e1; + else if (e->op == TOKslice) + e = ((SliceExp*)e)->e1; + else + return NULL; + } + VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); + assert(v); + return v; +} + +// Returns the value to be assigned to the last dotVar, given the existing value at this depth. +Expression *assignDotVar(ExpressionReverseIterator rvs, int depth, Expression *existing, Expression *newval) +{ + if (depth == 0) + return newval; + assert(existing && existing != EXP_CANT_INTERPRET); + Expression *e = rvs.getExpressionAtDepth(depth - 1); + if (e->op == TOKdotvar) + { + VarDeclaration *member = ((DotVarExp *)e)->var->isVarDeclaration(); + assert(member); + assert(existing); + assert(existing != EXP_CANT_INTERPRET); + assert(existing->op == TOKstructliteral); + if (existing->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + + StructLiteralExp *se = (StructLiteralExp *)existing; + int fieldi = se->getFieldIndex(member->type, member->offset); + if (fieldi == -1) + return EXP_CANT_INTERPRET; + assert(fieldi>=0 && fieldi < se->elements->dim); + Expression *ex = (Expression *)(se->elements->data[fieldi]); + + newval = assignDotVar(rvs, depth - 1, ex, newval); + Expressions *expsx = changeOneElement(se->elements, fieldi, newval); + Expression * ee = new StructLiteralExp(se->loc, se->sd, expsx); + ee->type = se->type; + return ee; + } + assert(0); + return NULL; +} + + +Expression *BinExp::interpretAssignCommon(InterState *istate, fp_t fp, int post) +{ +#if LOG + printf("BinExp::interpretAssignCommon() %s\n", toChars()); +#endif + Expression *e = EXP_CANT_INTERPRET; + Expression *e1 = this->e1; + if (!istate) + { + error("value of %s is not known at compile time", e1->toChars()); + return e; + } + + if (fp) + { + if (e1->op == TOKcast) + { CastExp *ce = (CastExp *)e1; + e1 = ce->e1; + } + } + if (e1 == EXP_CANT_INTERPRET) + return e1; + + assert(istate); + + // ---------------------------------------------------- + // Deal with read-modify-write assignments. + // Set 'newval' to the final assignment value + // Also determine the return value (except for slice + // assignments, which are more complicated) + // ---------------------------------------------------- + Expression * newval = this->e2->interpret(istate); + if (newval == EXP_CANT_INTERPRET) + return newval; + + if (fp || e1->op == TOKarraylength) + { + // If it isn't a simple assignment, we need the existing value + Expression * oldval = e1->interpret(istate); + if (oldval == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + while (oldval->op == TOKvar) + { + oldval = resolveReferences(oldval, istate->localThis); + oldval = oldval->interpret(istate); + if (oldval == EXP_CANT_INTERPRET) + return oldval; + } + + if (fp) + { + newval = (*fp)(type, oldval, newval); + if (newval == EXP_CANT_INTERPRET) + { + error("Cannot interpret %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + // Determine the return value + e = Cast(type, type, post ? oldval : newval); + if (e == EXP_CANT_INTERPRET) + return e; + } + else + e = newval; + + if (e1->op == TOKarraylength) + { + size_t oldlen = oldval->toInteger(); + size_t newlen = newval->toInteger(); + if (oldlen == newlen) // no change required -- we're done! + return e; + // Now change the assignment from arr.length = n into arr = newval + e1 = ((ArrayLengthExp *)e1)->e1; + if (oldlen != 0) + { // Get the old array literal. + oldval = e1->interpret(istate); + while (oldval->op == TOKvar) + { oldval = resolveReferences(oldval, istate->localThis); + oldval = oldval->interpret(istate); + } + } + Type *t = e1->type->toBasetype(); + if (t->ty == Tarray) + { + Type *elemType= NULL; + elemType = ((TypeArray *)t)->next; + assert(elemType); + Expression *defaultElem = elemType->defaultInitLiteral(); + + Expressions *elements = new Expressions(); + elements->setDim(newlen); + size_t copylen = oldlen < newlen ? oldlen : newlen; + ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; + for (size_t i = 0; i < copylen; i++) + elements->data[i] = ae->elements->data[i]; + + for (size_t i = copylen; i < newlen; i++) + elements->data[i] = defaultElem; + ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); + aae->type = t; + newval = aae; + } + else + { + error("%s is not yet supported at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + + } + } + else if (e1->op != TOKslice) + { /* Look for special case of struct being initialized with 0. + */ + if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64) + { + newval = type->defaultInitLiteral(loc); + } + newval = Cast(type, type, newval); + e = newval; + } + if (newval == EXP_CANT_INTERPRET) + return newval; + + // ------------------------------------------------- + // Make sure destination can be modified + // ------------------------------------------------- + // Make sure we're not trying to modify a global or static variable + // We do this by locating the ultimate parent variable which gets modified. + VarDeclaration * ultimateVar = findParentVar(e1, istate->localThis); + if (ultimateVar && ultimateVar->isDataseg() && !ultimateVar->isCTFE()) + { // Can't modify global or static data + error("%s cannot be modified at compile time", ultimateVar->toChars()); + return EXP_CANT_INTERPRET; + } + + // This happens inside compiler-generated foreach statements. + if (op==TOKconstruct && this->e1->op==TOKvar + && ((VarExp*)this->e1)->var->storage_class & STCref) + { + //error("assignment to ref variable %s is not yet supported in CTFE", this->toChars()); + VarDeclaration *v = ((VarExp *)e1)->var->isVarDeclaration(); + v->value = e2; + return e2; + } + bool destinationIsReference = false; + e1 = resolveReferences(e1, istate->localThis, &destinationIsReference); + + // Unless we have a simple var assignment, we're + // only modifying part of the variable. So we need to make sure + // that the parent variable exists. + if (e1->op != TOKvar && ultimateVar && !ultimateVar->value) + ultimateVar->value = ultimateVar->type->defaultInitLiteral(); + + // ---------------------------------------- + // Deal with dotvar expressions + // ---------------------------------------- + // Because structs are not reference types, dotvar expressions can be + // collapsed into a single assignment. + bool startedWithCall = false; + if (e1->op == TOKcall) startedWithCall = true; + while (e1->op == TOKdotvar || e1->op == TOKcall) + { + ExpressionReverseIterator rvs(e1, istate->localThis); + Expression *lastNonDotVar = e1; + // Strip of all of the leading dotvars. + if (e1->op == TOKdotvar) + { + int numDotVars = 0; + while(lastNonDotVar->op == TOKdotvar) + { + ++numDotVars; + if (lastNonDotVar->op == TOKdotvar) + lastNonDotVar = ((DotVarExp *)lastNonDotVar)->e1; + lastNonDotVar = resolveReferences(lastNonDotVar, istate->localThis); + assert(lastNonDotVar); + } + // We need the value of this first nonvar, since only part of it will be + // modified. + Expression * existing = lastNonDotVar->interpret(istate); + if (existing == EXP_CANT_INTERPRET) + return existing; + assert(newval !=EXP_CANT_INTERPRET); + newval = assignDotVar(rvs, numDotVars, existing, newval); + e1 = lastNonDotVar; + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + v->value = newval; + return e; + } + assert(newval !=EXP_CANT_INTERPRET); + + } // end tokdotvar + else + { + Expression * existing = lastNonDotVar->interpret(istate); + if (existing == EXP_CANT_INTERPRET) + return existing; + // It might be a reference. Turn it into an rvalue, by interpreting again. + existing = existing->interpret(istate); + if (existing == EXP_CANT_INTERPRET) + return existing; + assert(newval !=EXP_CANT_INTERPRET); + newval = assignDotVar(rvs, 0, existing, newval); + assert(newval !=EXP_CANT_INTERPRET); + } + if (e1->op == TOKcall) + { + istate->awaitingLvalueReturn = true; + e1 = e1->interpret(istate); + istate->awaitingLvalueReturn = false; + + if (e1==EXP_CANT_INTERPRET) return e1; + assert(newval); + assert(newval !=EXP_CANT_INTERPRET); + } + } + + /* Assignment to variable of the form: + * v = newval + */ + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!destinationIsReference) + addVarToInterstate(istate, v); + v->value = newval; + } + else if (e1->op == TOKindex) + { + Expression *aggregate = resolveReferences(((IndexExp *)e1)->e1, istate->localThis); + /* Assignment to array element of the form: + * aggregate[i] = newval + */ + if (aggregate->op == TOKvar) + { IndexExp *ie = (IndexExp *)e1; + VarExp *ve = (VarExp *)aggregate; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v->value->op == TOKnull) + { + if (v->type->ty == Taarray) + { // Assign to empty associative array + Expressions *valuesx = new Expressions(); + Expressions *keysx = new Expressions(); + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + valuesx->push(newval); + keysx->push(index); + Expression *aae2 = new AssocArrayLiteralExp(loc, keysx, valuesx); + aae2->type = v->type; + newval = aae2; + v->value = newval; + return e; + } + // This would be a runtime segfault + error("Cannot index null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + else if (v->value->op != TOKarrayliteral + && v->value->op != TOKassocarrayliteral + && v->value->op != TOKstring) + { + error("CTFE internal compiler error"); + return EXP_CANT_INTERPRET; + } + // Set the $ variable + Expression *dollar = ArrayLength(Type::tsize_t, v->value); + if (dollar != EXP_CANT_INTERPRET && ie->lengthVar) + ie->lengthVar->value = dollar; + // Determine the index, and check that it's OK. + Expression *index = ie->e2->interpret(istate); + if (index == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + newval = assignArrayElement(loc, v->value, index, newval); + if (newval == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + v->value = newval; + return e; + } + else + error("Index assignment %s is not yet supported in CTFE ", toChars()); + + } + else if (e1->op == TOKslice) + { + Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); + // ------------------------------ + // aggregate[] = newval + // aggregate[low..upp] = newval + // ------------------------------ + /* Slice assignment, initialization of static arrays + * a[] = e + */ + if (aggregate->op==TOKvar) + { + SliceExp * sexp = (SliceExp *)e1; + VarExp *ve = (VarExp *)(aggregate); + VarDeclaration *v = ve->var->isVarDeclaration(); + /* Set the $ variable + */ + Expression *ee = v->value ? ArrayLength(Type::tsize_t, v->value) + : EXP_CANT_INTERPRET; + if (ee != EXP_CANT_INTERPRET && sexp->lengthVar) + sexp->lengthVar->value = ee; + Expression *upper = NULL; + Expression *lower = NULL; + if (sexp->upr) + { + upper = sexp->upr->interpret(istate); + if (upper == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + if (sexp->lwr) + { + lower = sexp->lwr->interpret(istate); + if (lower == EXP_CANT_INTERPRET) + return EXP_CANT_INTERPRET; + } + Type *t = v->type->toBasetype(); + size_t dim; + if (t->ty == Tsarray) + dim = ((TypeSArray *)t)->dim->toInteger(); + else if (t->ty == Tarray) + { + if (!v->value || v->value->op == TOKnull) + { + error("cannot assign to null array %s", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (v->value->op == TOKarrayliteral) + dim = ((ArrayLiteralExp *)v->value)->elements->dim; + else if (v->value->op ==TOKstring) + dim = ((StringExp *)v->value)->len; + } + else + { + error("%s cannot be evaluated at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + int upperbound = upper ? upper->toInteger() : dim; + int lowerbound = lower ? lower->toInteger() : 0; + + if (((int)lowerbound < 0) || (upperbound > dim)) + { + error("Array bounds [0..%d] exceeded in slice [%d..%d]", + dim, lowerbound, upperbound); + return EXP_CANT_INTERPRET; + } + // Could either be slice assignment (v[] = e[]), + // or block assignment (v[] = val). + // For the former, we check that the lengths match. + bool isSliceAssignment = (newval->op == TOKarrayliteral) + || (newval->op == TOKstring); + size_t srclen = 0; + if (newval->op == TOKarrayliteral) + srclen = ((ArrayLiteralExp *)newval)->elements->dim; + else if (newval->op == TOKstring) + srclen = ((StringExp *)newval)->len; + if (isSliceAssignment && srclen != (upperbound - lowerbound)) + { + error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); + return e; + } + if (newval->op == TOKarrayliteral) + { + // Static array assignment from literal + if (upperbound - lowerbound != dim) + { + ArrayLiteralExp *ae = (ArrayLiteralExp *)newval; + ArrayLiteralExp *existing = (ArrayLiteralExp *)v->value; + // value[] = value[0..lower] ~ ae ~ value[upper..$] + existing->elements = spliceElements(existing->elements, ae->elements, lowerbound); + newval = existing; + } + v->value = newval; + return newval; + } + else if (newval->op == TOKstring) + { + StringExp *se = (StringExp *)newval; + if (upperbound-lowerbound == dim) + v->value = newval; + else + { + if (!v->value) + v->value = createBlockDuplicatedStringLiteral(se->type, + se->type->defaultInit()->toInteger(), dim, se->sz); + if (v->value->op==TOKstring) + v->value = spliceStringExp((StringExp *)v->value, se, lowerbound); + else + error("String slice assignment is not yet supported in CTFE"); + } + return newval; + } + else if (t->nextOf()->ty == newval->type->ty) + { + // Static array block assignment + e = createBlockDuplicatedArrayLiteral(v->type, newval, upperbound-lowerbound); + + if (upperbound - lowerbound == dim) + newval = e; + else + { + ArrayLiteralExp * newarrayval; + // Only modifying part of the array. Must create a new array literal. + // If the existing array is uninitialized (this can only happen + // with static arrays), create it. + if (v->value && v->value->op == TOKarrayliteral) + newarrayval = (ArrayLiteralExp *)v->value; + else // this can only happen with static arrays + newarrayval = createBlockDuplicatedArrayLiteral(v->type, v->type->defaultInit(), dim); + // value[] = value[0..lower] ~ e ~ value[upper..$] + newarrayval->elements = spliceElements(newarrayval->elements, + ((ArrayLiteralExp *)e)->elements, lowerbound); + newval = newarrayval; + } + v->value = newval; + return e; + } + else + { + error("Slice operation %s cannot be evaluated at compile time", toChars()); + return e; + } + } + else + error("Slice operation %s cannot be evaluated at compile time", toChars()); + } + else if (e1->op == TOKstar) + { + /* Assignment to struct member of the form: + * *(symoffexp) = newval + */ + if (((PtrExp *)e1)->e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)((PtrExp *)e1)->e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + if (v->isDataseg() && !v->isCTFE()) + { + error("%s cannot be modified at compile time", v->toChars()); + return EXP_CANT_INTERPRET; + } + if (fp && !v->value) + { error("variable %s is used before initialization", v->toChars()); + return e; + } + Expression *vie = v->value; + if (vie->op == TOKvar) + { + Declaration *d = ((VarExp *)vie)->var; + vie = getVarExp(e1->loc, istate, d); + } + if (vie->op != TOKstructliteral) + return EXP_CANT_INTERPRET; + + StructLiteralExp *se = (StructLiteralExp *)vie; + + newval = modifyStructField(type, se, soe->offset, newval); + + addVarToInterstate(istate, v); + v->value = newval; + } + } + else + { + error("%s cannot be evaluated at compile time", toChars()); +#ifdef DEBUG + dump(0); +#endif + } + return e; +} + +Expression *AssignExp::interpret(InterState *istate) +{ + return interpretAssignCommon(istate, NULL); +} + +#define BIN_ASSIGN_INTERPRET(op) \ +Expression *op##AssignExp::interpret(InterState *istate) \ +{ \ + return interpretAssignCommon(istate, &op); \ +} + +BIN_ASSIGN_INTERPRET(Add) +BIN_ASSIGN_INTERPRET(Min) +BIN_ASSIGN_INTERPRET(Cat) +BIN_ASSIGN_INTERPRET(Mul) +BIN_ASSIGN_INTERPRET(Div) +BIN_ASSIGN_INTERPRET(Mod) +BIN_ASSIGN_INTERPRET(Shl) +BIN_ASSIGN_INTERPRET(Shr) +BIN_ASSIGN_INTERPRET(Ushr) +BIN_ASSIGN_INTERPRET(And) +BIN_ASSIGN_INTERPRET(Or) +BIN_ASSIGN_INTERPRET(Xor) + +Expression *PostExp::interpret(InterState *istate) +{ +#if LOG + printf("PostExp::interpret() %s\n", toChars()); +#endif + Expression *e; + if (op == TOKplusplus) + e = interpretAssignCommon(istate, &Add, 1); + else + e = interpretAssignCommon(istate, &Min, 1); +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PostExp::interpret() CANT\n"); +#endif + return e; +} + +Expression *AndAndExp::interpret(InterState *istate) +{ +#if LOG + printf("AndAndExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *OrOrExp::interpret(InterState *istate) +{ +#if LOG + printf("OrOrExp::interpret() %s\n", toChars()); +#endif + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else if (e->isBool(FALSE)) + { + e = e2->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(FALSE)) + e = new IntegerExp(e1->loc, 0, type); + else if (e->isBool(TRUE)) + e = new IntegerExp(e1->loc, 1, type); + else + e = EXP_CANT_INTERPRET; + } + } + else + e = EXP_CANT_INTERPRET; + } + return e; +} + + +Expression *CallExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("CallExp::interpret() %s\n", toChars()); +#endif + + Expression * pthis = NULL; + FuncDeclaration *fd = NULL; + Expression *ecall = e1; + if (ecall->op == TOKcall) + { + ecall = e1->interpret(istate); + if (ecall == EXP_CANT_INTERPRET) + return ecall; + } + if (ecall->op == TOKstar) + { // Calling a function pointer + Expression * pe = ((PtrExp*)ecall)->e1; + if (pe->op == TOKvar) { + VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); + if (vd && vd->value && vd->value->op==TOKsymoff) + fd = ((SymOffExp *)vd->value)->var->isFuncDeclaration(); + else { + ecall = vd->value->interpret(istate); + if (ecall->op==TOKsymoff) + fd = ((SymOffExp *)ecall)->var->isFuncDeclaration(); + } + } + else + ecall = ((PtrExp*)ecall)->e1->interpret(istate); + } + if (ecall->op == TOKindex) + ecall = e1->interpret(istate); + if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) + ecall = e1->interpret(istate); + + if (ecall->op == TOKdotvar) + { // Calling a member function + pthis = ((DotVarExp*)e1)->e1; + fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); + } + else if (ecall->op == TOKvar) + { + VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); + if (vd && vd->value) + ecall = vd->value; + else // Calling a function + fd = ((VarExp *)e1)->var->isFuncDeclaration(); + } + if (ecall->op == TOKdelegate) + { // Calling a delegate + fd = ((DelegateExp *)ecall)->func; + pthis = ((DelegateExp *)ecall)->e1; + } + else if (ecall->op == TOKfunction) + { // Calling a delegate literal + fd = ((FuncExp*)ecall)->fd; + } + else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op==TOKfunction) + { // Calling a function literal + fd = ((FuncExp*)((PtrExp*)ecall)->e1)->fd; + } + + TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; + if (!tf) + { // DAC: I'm not sure if this ever happens + //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + if (pthis && fd) + { // Member function call + if (pthis->op == TOKthis) + pthis = istate ? istate->localThis : NULL; + else if (pthis->op == TOKcomma) + pthis = pthis->interpret(istate); + if (!fd->fbody) + { + error("%s cannot be interpreted at compile time," + " because it has no available source code", fd->toChars()); + return EXP_CANT_INTERPRET; + } + Expression *eresult = fd->interpret(istate, arguments, pthis); + if (eresult) + e = eresult; + else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + return e; + } + else if (fd) + { // function call +#if DMDV2 + enum BUILTIN b = fd->isBuiltin(); + if (b) + { Expressions args; + args.setDim(arguments->dim); + for (size_t i = 0; i < args.dim; i++) + { + Expression *earg = (Expression *)arguments->data[i]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return earg; + args.data[i] = (void *)earg; + } + e = eval_builtin(b, &args); + if (!e) + e = EXP_CANT_INTERPRET; + } + else +#endif + +#if DMDV1 + if (fd->ident == Id::aaLen) + return interpret_aaLen(istate, arguments); + else if (fd->ident == Id::aaKeys) + return interpret_aaKeys(istate, arguments); + else if (fd->ident == Id::aaValues) + return interpret_aaValues(istate, arguments); +#endif + + // Inline .dup + if (fd->ident == Id::adDup && arguments && arguments->dim == 2) + { + e = (Expression *)arguments->data[1]; + e = e->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + e = expType(type, e); + } + } + else + { + if (!fd->fbody) + { + error("%s cannot be interpreted at compile time," + " because it has no available source code", fd->toChars()); + return EXP_CANT_INTERPRET; + } + Expression *eresult = fd->interpret(istate, arguments); + if (eresult) + e = eresult; + else if (fd->type->toBasetype()->nextOf()->ty == Tvoid && !global.errors) + e = EXP_VOID_INTERPRET; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + else + { + error("cannot evaluate %s at compile time", toChars()); + return EXP_CANT_INTERPRET; + } + return e; +} + +Expression *CommaExp::interpret(InterState *istate) +{ +#if LOG + printf("CommaExp::interpret() %s\n", toChars()); +#endif + + CommaExp * firstComma = this; + while (firstComma->e1->op == TOKcomma) + firstComma = (CommaExp *)firstComma->e1; + + // If it creates a variable, and there's no context for + // the variable to be created in, we need to create one now. + InterState istateComma; + if (!istate && firstComma->e1->op == TOKdeclaration) + istate = &istateComma; + + // If the comma returns a temporary variable, it needs to be an lvalue + // (this is particularly important for struct constructors) + if (e1->op == TOKdeclaration && e2->op == TOKvar + && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var) + { + VarExp* ve = (VarExp *)e2; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (!v->init && !v->value) + v->value = v->type->defaultInitLiteral(); + if (!v->value) + v->value = v->init->toExpression(); + // Bug 4027. Copy constructors are a weird case where the + // initializer is a void function (the variable is modified + // through a reference parameter instead). + Expression *newval = v->value->interpret(istate); + if (newval != EXP_VOID_INTERPRET) + v->value = newval; + return e2; + } + Expression *e = e1->interpret(istate); + if (e != EXP_CANT_INTERPRET) + e = e2->interpret(istate); + return e; +} + +Expression *CondExp::interpret(InterState *istate) +{ +#if LOG + printf("CondExp::interpret() %s\n", toChars()); +#endif + Expression *e = econd->interpret(istate); + if (e != EXP_CANT_INTERPRET) + { + if (e->isBool(TRUE)) + e = e1->interpret(istate); + else if (e->isBool(FALSE)) + e = e2->interpret(istate); + else + e = EXP_CANT_INTERPRET; + } + return e; +} + +Expression *ArrayLengthExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("ArrayLengthExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + else if (e1->op == TOKnull) + { + e = new IntegerExp(loc, 0, type); + } + else + goto Lcant; + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *IndexExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("IndexExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + + if (e1->op == TOKstring || e1->op == TOKarrayliteral) + { + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + } + + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + e = Index(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *SliceExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *lwr; + Expression *upr; + +#if LOG + printf("SliceExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (!this->lwr) + { + e = e1->castTo(NULL, type); + return e->interpret(istate); + } + + /* Set the $ variable + */ + e = ArrayLength(Type::tsize_t, e1); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + if (lengthVar) + lengthVar->value = e; + + /* Evaluate lower and upper bounds of slice + */ + lwr = this->lwr->interpret(istate); + if (lwr == EXP_CANT_INTERPRET) + goto Lcant; + upr = this->upr->interpret(istate); + if (upr == EXP_CANT_INTERPRET) + goto Lcant; + + e = Slice(type, e1, lwr, upr); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); + return e; + +Lcant: + return EXP_CANT_INTERPRET; +} + + +Expression *CatExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + Expression *e2; + +#if LOG + printf("CatExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + { + goto Lcant; + } + e2 = this->e2->interpret(istate); + if (e2 == EXP_CANT_INTERPRET) + goto Lcant; + e = Cat(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); + return e; + +Lcant: +#if LOG + printf("CatExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *CastExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("CastExp::interpret() %s\n", toChars()); +#endif + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + e = Cast(type, to, e1); + if (e == EXP_CANT_INTERPRET) + error("%s cannot be interpreted at compile time", toChars()); + return e; + +Lcant: +#if LOG + printf("CastExp::interpret() %s CANT\n", toChars()); +#endif + return EXP_CANT_INTERPRET; +} + + +Expression *AssertExp::interpret(InterState *istate) +{ Expression *e; + Expression *e1; + +#if LOG + printf("AssertExp::interpret() %s\n", toChars()); +#endif + if( this->e1->op == TOKaddress) + { // Special case: deal with compiler-inserted assert(&this, "null this") + AddrExp *ade = (AddrExp *)this->e1; + if (ade->e1->op == TOKthis && istate->localThis) + if (ade->e1->op == TOKdotvar + && ((DotVarExp *)(istate->localThis))->e1->op == TOKthis) + return getVarExp(loc, istate, ((DotVarExp*)(istate->localThis))->var); + else + return istate->localThis->interpret(istate); + } + if (this->e1->op == TOKthis) + { + if (istate->localThis) + return istate->localThis->interpret(istate); + } + e1 = this->e1->interpret(istate); + if (e1 == EXP_CANT_INTERPRET) + goto Lcant; + if (e1->isBool(TRUE)) + { + } + else if (e1->isBool(FALSE)) + { + if (msg) + { + e = msg->interpret(istate); + if (e == EXP_CANT_INTERPRET) + goto Lcant; + error("%s", e->toChars()); + } + else + error("%s failed", toChars()); + goto Lcant; + } + else + goto Lcant; + return e1; + +Lcant: + return EXP_CANT_INTERPRET; +} + +Expression *PtrExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("PtrExp::interpret() %s\n", toChars()); +#endif + + // Constant fold *(&structliteral + offset) + if (e1->op == TOKadd) + { AddExp *ae = (AddExp *)e1; + if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) + { AddrExp *ade = (AddrExp *)ae->e1; + Expression *ex = ade->e1; + ex = ex->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + unsigned offset = ae->e2->toInteger(); + e = se->getField(type, offset); + if (!e) + e = EXP_CANT_INTERPRET; + return e; + } + } + } + e = Ptr(type, e1); + } + else if (e1->op == TOKsymoff) + { SymOffExp *soe = (SymOffExp *)e1; + VarDeclaration *v = soe->var->isVarDeclaration(); + if (v) + { Expression *ev = getVarExp(loc, istate, v); + if (ev != EXP_CANT_INTERPRET && ev->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ev; + e = se->getField(type, soe->offset); + if (!e) + e = EXP_CANT_INTERPRET; + } + } + } +#if DMDV2 +#else // this is required for D1, where structs return *this instead of 'this'. + else if (e1->op == TOKthis) + { + if(istate->localThis) + return istate->localThis->interpret(istate); + } +#endif + else + error("Cannot interpret %s at compile time", toChars()); + +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +Expression *DotVarExp::interpret(InterState *istate) +{ Expression *e = EXP_CANT_INTERPRET; + +#if LOG + printf("DotVarExp::interpret() %s\n", toChars()); +#endif + + Expression *ex = e1->interpret(istate); + if (ex != EXP_CANT_INTERPRET) + { + if (ex->op == TOKstructliteral) + { StructLiteralExp *se = (StructLiteralExp *)ex; + VarDeclaration *v = var->isVarDeclaration(); + if (v) + { e = se->getField(type, v->offset); + if (!e) + { + error("couldn't find field %s in %s", v->toChars(), type->toChars()); + e = EXP_CANT_INTERPRET; + } + return e; + } + } + else + error("%s.%s is not yet implemented at compile time", e1->toChars(), var->toChars()); + } + +#if LOG + if (e == EXP_CANT_INTERPRET) + printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); +#endif + return e; +} + +/******************************* Special Functions ***************************/ + +#if DMDV1 + +Expression *interpret_aaLen(InterState *istate, Expressions *arguments) +{ + if (!arguments || arguments->dim != 1) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); + return e; +} + +Expression *interpret_aaKeys(InterState *istate, Expressions *arguments) +{ +#if LOG + printf("interpret_aaKeys()\n"); +#endif + if (!arguments || arguments->dim != 2) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); + Type *elemType = ((TypeAArray *)aae->type)->index; + e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); + return e; +} + +Expression *interpret_aaValues(InterState *istate, Expressions *arguments) +{ + //printf("interpret_aaValues()\n"); + if (!arguments || arguments->dim != 3) + return NULL; + Expression *earg = (Expression *)arguments->data[0]; + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->values); + Type *elemType = ((TypeAArray *)aae->type)->next; + e->type = new TypeSArray(elemType, new IntegerExp(arguments ? arguments->dim : 0)); + //printf("result is %s\n", e->toChars()); + return e; +} + +#endif + +#if DMDV2 + +Expression *interpret_length(InterState *istate, Expression *earg) +{ + //printf("interpret_length()\n"); + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new IntegerExp(aae->loc, aae->keys->dim, Type::tsize_t); + return e; +} + +Expression *interpret_keys(InterState *istate, Expression *earg, FuncDeclaration *fd) +{ +#if LOG + printf("interpret_keys()\n"); +#endif + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->keys); + assert(fd->type->ty == Tfunction); + assert(fd->type->nextOf()->ty == Tarray); + Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); + e->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); + return e; +} + +Expression *interpret_values(InterState *istate, Expression *earg, FuncDeclaration *fd) +{ + //printf("interpret_values()\n"); + earg = earg->interpret(istate); + if (earg == EXP_CANT_INTERPRET) + return NULL; + if (earg->op != TOKassocarrayliteral) + return NULL; + AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; + Expression *e = new ArrayLiteralExp(aae->loc, aae->values); + assert(fd->type->ty == Tfunction); + assert(fd->type->nextOf()->ty == Tarray); + Type *elemType = ((TypeFunction *)fd->type)->nextOf()->nextOf(); + e->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); + //printf("result is %s\n", e->toChars()); + return e; +} + +#endif diff --git a/dmd2/irstate.c b/dmd2/irstate.c index 391291f3..4ed43548 100644 --- a/dmd2/irstate.c +++ b/dmd2/irstate.c @@ -1,164 +1,186 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#include - -#include "irstate.h" - -IRState::IRState(IRState *irs, Statement *s) -{ - prev = irs; - statement = s; - symbol = NULL; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - startaddress = NULL; - if (irs) - { - m = irs->m; - shidden = irs->shidden; - sclosure = irs->sclosure; - sthis = irs->sthis; - blx = irs->blx; - deferToObj = irs->deferToObj; - } - else - { - m = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; - } -} - -IRState::IRState(IRState *irs, Dsymbol *s) -{ - prev = irs; - statement = NULL; - symbol = s; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - startaddress = NULL; - if (irs) - { - m = irs->m; - shidden = irs->shidden; - sclosure = irs->sclosure; - sthis = irs->sthis; - blx = irs->blx; - deferToObj = irs->deferToObj; - } - else - { - m = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; - } -} - -IRState::IRState(Module *m, Dsymbol *s) -{ - prev = NULL; - statement = NULL; - this->m = m; - symbol = s; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; - startaddress = NULL; -} - -block *IRState::getBreakBlock(Identifier *ident) -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (ident) - { - if (bc->prev && bc->prev->ident == ident) - return bc->breakBlock; - } - else if (bc->breakBlock) - return bc->breakBlock; - } - return NULL; -} - -block *IRState::getContBlock(Identifier *ident) -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (ident) - { - if (bc->prev && bc->prev->ident == ident) - return bc->contBlock; - } - else if (bc->contBlock) - return bc->contBlock; - } - return NULL; -} - -block *IRState::getSwitchBlock() -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (bc->switchBlock) - return bc->switchBlock; - } - return NULL; -} - -block *IRState::getDefaultBlock() -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (bc->defaultBlock) - return bc->defaultBlock; - } - return NULL; -} - -FuncDeclaration *IRState::getFunc() -{ - IRState *bc; - - for (bc = this; bc->prev; bc = bc->prev) - { - } - return (FuncDeclaration *)(bc->symbol); -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com + +#include + +#include "mars.h" +#include "mtype.h" +#include "declaration.h" +#include "irstate.h" + +IRState::IRState(IRState *irs, Statement *s) +{ + prev = irs; + statement = s; + symbol = NULL; + breakBlock = NULL; + contBlock = NULL; + switchBlock = NULL; + defaultBlock = NULL; + ident = NULL; + ehidden = NULL; + startaddress = NULL; + if (irs) + { + m = irs->m; + shidden = irs->shidden; + sclosure = irs->sclosure; + sthis = irs->sthis; + blx = irs->blx; + deferToObj = irs->deferToObj; + } + else + { + m = NULL; + shidden = NULL; + sclosure = NULL; + sthis = NULL; + blx = NULL; + deferToObj = NULL; + } +} + +IRState::IRState(IRState *irs, Dsymbol *s) +{ + prev = irs; + statement = NULL; + symbol = s; + breakBlock = NULL; + contBlock = NULL; + switchBlock = NULL; + defaultBlock = NULL; + ident = NULL; + ehidden = NULL; + startaddress = NULL; + if (irs) + { + m = irs->m; + shidden = irs->shidden; + sclosure = irs->sclosure; + sthis = irs->sthis; + blx = irs->blx; + deferToObj = irs->deferToObj; + } + else + { + m = NULL; + shidden = NULL; + sclosure = NULL; + sthis = NULL; + blx = NULL; + deferToObj = NULL; + } +} + +IRState::IRState(Module *m, Dsymbol *s) +{ + prev = NULL; + statement = NULL; + this->m = m; + symbol = s; + breakBlock = NULL; + contBlock = NULL; + switchBlock = NULL; + defaultBlock = NULL; + ident = NULL; + ehidden = NULL; + shidden = NULL; + sclosure = NULL; + sthis = NULL; + blx = NULL; + deferToObj = NULL; + startaddress = NULL; +} + +block *IRState::getBreakBlock(Identifier *ident) +{ + IRState *bc; + + for (bc = this; bc; bc = bc->prev) + { + if (ident) + { + if (bc->prev && bc->prev->ident == ident) + return bc->breakBlock; + } + else if (bc->breakBlock) + return bc->breakBlock; + } + return NULL; +} + +block *IRState::getContBlock(Identifier *ident) +{ + IRState *bc; + + for (bc = this; bc; bc = bc->prev) + { + if (ident) + { + if (bc->prev && bc->prev->ident == ident) + return bc->contBlock; + } + else if (bc->contBlock) + return bc->contBlock; + } + return NULL; +} + +block *IRState::getSwitchBlock() +{ + IRState *bc; + + for (bc = this; bc; bc = bc->prev) + { + if (bc->switchBlock) + return bc->switchBlock; + } + return NULL; +} + +block *IRState::getDefaultBlock() +{ + IRState *bc; + + for (bc = this; bc; bc = bc->prev) + { + if (bc->defaultBlock) + return bc->defaultBlock; + } + return NULL; +} + +FuncDeclaration *IRState::getFunc() +{ + IRState *bc; + + for (bc = this; bc->prev; bc = bc->prev) + { + } + return (FuncDeclaration *)(bc->symbol); +} + + +/********************** + * Return !=0 if do array bounds checking + */ +int IRState::arrayBoundsCheck() +{ + int result = global.params.useArrayBounds; + + if (result == 1) + { // For safe functions only + result = 0; + FuncDeclaration *fd = getFunc(); + if (fd) + { Type *t = fd->type; + if (t->ty == Tfunction && ((TypeFunction *)t)->trust == TRUSTsafe) + result = 1; + } + } + return result; +} diff --git a/dmd2/irstate.h b/dmd2/irstate.h index f84b3d77..ad77db0e 100644 --- a/dmd2/irstate.h +++ b/dmd2/irstate.h @@ -1,57 +1,58 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#ifndef DMD_CONTEXT_H -#define DMD_CONTEXT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -struct Module; -struct Statement; -struct block; -struct Dsymbol; -struct Identifier; -struct Symbol; -struct FuncDeclaration; -struct Blockx; -struct Array; -struct elem; - -struct IRState -{ - IRState *prev; - Statement *statement; - Module *m; // module - Dsymbol *symbol; - Identifier *ident; - Symbol *shidden; // hidden parameter to function - Symbol *sthis; // 'this' parameter to function (member and nested) - Symbol *sclosure; // pointer to closure instance - Blockx *blx; - Array *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later - elem *ehidden; // transmit hidden pointer to CallExp::toElem() - Symbol *startaddress; - - block *breakBlock; - block *contBlock; - block *switchBlock; - block *defaultBlock; - - IRState(IRState *irs, Statement *s); - IRState(IRState *irs, Dsymbol *s); - IRState(Module *m, Dsymbol *s); - - block *getBreakBlock(Identifier *ident); - block *getContBlock(Identifier *ident); - block *getSwitchBlock(); - block *getDefaultBlock(); - FuncDeclaration *getFunc(); -}; - -#endif /* DMD_CONTEXT_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com + +#ifndef DMD_CONTEXT_H +#define DMD_CONTEXT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +struct Module; +struct Statement; +struct block; +struct Dsymbol; +struct Identifier; +struct Symbol; +struct FuncDeclaration; +struct Blockx; +struct Array; +struct elem; + +struct IRState +{ + IRState *prev; + Statement *statement; + Module *m; // module + Dsymbol *symbol; + Identifier *ident; + Symbol *shidden; // hidden parameter to function + Symbol *sthis; // 'this' parameter to function (member and nested) + Symbol *sclosure; // pointer to closure instance + Blockx *blx; + Array *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later + elem *ehidden; // transmit hidden pointer to CallExp::toElem() + Symbol *startaddress; + + block *breakBlock; + block *contBlock; + block *switchBlock; + block *defaultBlock; + + IRState(IRState *irs, Statement *s); + IRState(IRState *irs, Dsymbol *s); + IRState(Module *m, Dsymbol *s); + + block *getBreakBlock(Identifier *ident); + block *getContBlock(Identifier *ident); + block *getSwitchBlock(); + block *getDefaultBlock(); + FuncDeclaration *getFunc(); + int arrayBoundsCheck(); +}; + +#endif /* DMD_CONTEXT_H */ diff --git a/dmd2/json.c b/dmd2/json.c new file mode 100644 index 00000000..1adf3709 --- /dev/null +++ b/dmd2/json.c @@ -0,0 +1,440 @@ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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. + +// This implements the JSON capability. + +#include +#include +#include +#include +#include + +#include "rmem.h" +#include "root.h" + +#include "mars.h" +#include "dsymbol.h" +#include "macro.h" +#include "template.h" +#include "lexer.h" +#include "aggregate.h" +#include "declaration.h" +#include "enum.h" +#include "id.h" +#include "module.h" +#include "scope.h" +#include "hdrgen.h" +#include "json.h" +#include "mtype.h" +#include "attrib.h" +#include "cond.h" + +const char Pname[] = "name"; +const char Pkind[] = "kind"; +const char Pfile[] = "file"; +const char Pline[] = "line"; +const char Ptype[] = "type"; +const char Pcomment[] = "comment"; +const char Pmembers[] = "members"; + +void JsonRemoveComma(OutBuffer *buf); + +void json_generate(Array *modules) +{ OutBuffer buf; + + buf.writestring("[\n"); + for (int i = 0; i < modules->dim; i++) + { Module *m = (Module *)modules->data[i]; + if (global.params.verbose) + printf("json gen %s\n", m->toChars()); + m->toJsonBuffer(&buf); + buf.writestring(",\n"); + } + JsonRemoveComma(&buf); + buf.writestring("]\n"); + + // Write buf to file + char *arg = global.params.xfilename; + if (!arg || !*arg) + { // Generate lib file name from first obj name + char *n = (char *)global.params.objfiles->data[0]; + + n = FileName::name(n); + FileName *fn = FileName::forceExt(n, global.json_ext); + arg = fn->toChars(); + } + else if (arg[0] == '-' && arg[1] == 0) + { // Write to stdout; assume it succeeds + int n = fwrite(buf.data, 1, buf.offset, stdout); + assert(n == buf.offset); // keep gcc happy about return values + return; + } +// if (!FileName::absolute(arg)) +// arg = FileName::combine(dir, arg); + FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext); + File *jsonfile = new File(jsonfilename); + assert(jsonfile); + jsonfile->setbuffer(buf.data, buf.offset); + jsonfile->ref = 1; + char *pt = FileName::path(jsonfile->toChars()); + if (*pt) + FileName::ensurePathExists(pt); + mem.free(pt); + jsonfile->writev(); +} + + +/********************************* + * Encode string into buf, and wrap it in double quotes. + */ +void JsonString(OutBuffer *buf, const char *s) +{ + buf->writeByte('\"'); + for (; *s; s++) + { + unsigned char c = (unsigned char) *s; + switch (c) + { + case '\n': + buf->writestring("\\n"); + break; + + case '\r': + buf->writestring("\\r"); + break; + + case '\t': + buf->writestring("\\t"); + break; + + case '\"': + buf->writestring("\\\""); + break; + + case '\\': + buf->writestring("\\\\"); + break; + + case '/': + buf->writestring("\\/"); + break; + + case '\b': + buf->writestring("\\b"); + break; + + case '\f': + buf->writestring("\\f"); + break; + + default: + if (c < 0x20) + buf->printf("\\u%04x", c); + else + // Note that UTF-8 chars pass through here just fine + buf->writeByte(c); + break; + } + } + buf->writeByte('\"'); +} + +void JsonProperty(OutBuffer *buf, const char *name, const char *value) +{ + JsonString(buf, name); + buf->writestring(" : "); + JsonString(buf, value); + buf->writestring(",\n"); +} + +void JsonProperty(OutBuffer *buf, const char *name, int value) +{ + JsonString(buf, name); + buf->writestring(" : "); + buf->printf("%d", value); + buf->writestring(",\n"); +} + +void JsonRemoveComma(OutBuffer *buf) +{ + if (buf->offset >= 2 && + buf->data[buf->offset - 2] == ',' && + buf->data[buf->offset - 1] == '\n') + buf->offset -= 2; +} + +void Dsymbol::toJsonBuffer(OutBuffer *buf) +{ +} + +void Module::toJsonBuffer(OutBuffer *buf) +{ + buf->writestring("{\n"); + + if (md) + JsonProperty(buf, Pname, md->toChars()); + + JsonProperty(buf, Pkind, kind()); + + JsonProperty(buf, Pfile, srcfile->toChars()); + + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + + JsonString(buf, Pmembers); + buf->writestring(" : [\n"); + + size_t offset = buf->offset; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + s->toJsonBuffer(buf); + } + + JsonRemoveComma(buf); + buf->writestring("]\n"); + + buf->writestring("}\n"); +} + +void AttribDeclaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("AttribDeclaration::toJsonBuffer()\n"); + + Array *d = include(NULL, NULL); + + if (d) + { + size_t offset = buf->offset; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + s->toJsonBuffer(buf); + } + JsonRemoveComma(buf); + } +} + + +void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("ConditionalDeclaration::toJsonBuffer()\n"); + if (condition->inc) + { + AttribDeclaration::toJsonBuffer(buf); + } +} + + +void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { } +void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { } +void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { } +void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { } +void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } +void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } +void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } +void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { } +#if DMDV2 +void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { } +#endif + +void Declaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("Declaration::toJsonBuffer()\n"); + buf->writestring("{\n"); + + JsonProperty(buf, Pname, toChars()); + JsonProperty(buf, Pkind, kind()); + if (type) + JsonProperty(buf, Ptype, type->toChars()); + + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + + if (loc.linnum) + JsonProperty(buf, Pline, loc.linnum); + + TypedefDeclaration *td = isTypedefDeclaration(); + if (td) + { + JsonProperty(buf, "base", td->basetype->toChars()); + } + + JsonRemoveComma(buf); + buf->writestring("}\n"); +} + +void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("AggregateDeclaration::toJsonBuffer()\n"); + buf->writestring("{\n"); + + JsonProperty(buf, Pname, toChars()); + JsonProperty(buf, Pkind, kind()); + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + if (loc.linnum) + JsonProperty(buf, Pline, loc.linnum); + + ClassDeclaration *cd = isClassDeclaration(); + if (cd) + { + if (cd->baseClass) + { + JsonProperty(buf, "base", cd->baseClass->toChars()); + } + if (cd->interfaces_dim) + { + JsonString(buf, "interfaces"); + buf->writestring(" : [\n"); + size_t offset = buf->offset; + for (int i = 0; i < cd->interfaces_dim; i++) + { BaseClass *b = cd->interfaces[i]; + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + JsonString(buf, b->base->toChars()); + } + JsonRemoveComma(buf); + buf->writestring("],\n"); + } + } + + if (members) + { + JsonString(buf, Pmembers); + buf->writestring(" : [\n"); + size_t offset = buf->offset; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + s->toJsonBuffer(buf); + } + JsonRemoveComma(buf); + buf->writestring("]\n"); + } + JsonRemoveComma(buf); + + buf->writestring("}\n"); +} + +void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("TemplateDeclaration::toJsonBuffer()\n"); + + buf->writestring("{\n"); + + JsonProperty(buf, Pname, toChars()); + JsonProperty(buf, Pkind, kind()); + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + + if (loc.linnum) + JsonProperty(buf, Pline, loc.linnum); + + JsonString(buf, Pmembers); + buf->writestring(" : [\n"); + size_t offset = buf->offset; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + s->toJsonBuffer(buf); + } + JsonRemoveComma(buf); + buf->writestring("]\n"); + + buf->writestring("}\n"); +} + +void EnumDeclaration::toJsonBuffer(OutBuffer *buf) +{ + //printf("EnumDeclaration::toJsonBuffer()\n"); + if (isAnonymous()) + { + if (members) + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->toJsonBuffer(buf); + buf->writestring(",\n"); + } + JsonRemoveComma(buf); + } + return; + } + + buf->writestring("{\n"); + + JsonProperty(buf, Pname, toChars()); + JsonProperty(buf, Pkind, kind()); + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + + if (loc.linnum) + JsonProperty(buf, Pline, loc.linnum); + + if (memtype) + JsonProperty(buf, "base", memtype->toChars()); + + if (members) + { + JsonString(buf, Pmembers); + buf->writestring(" : [\n"); + size_t offset = buf->offset; + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + if (offset != buf->offset) + { buf->writestring(",\n"); + offset = buf->offset; + } + s->toJsonBuffer(buf); + } + JsonRemoveComma(buf); + buf->writestring("]\n"); + } + JsonRemoveComma(buf); + + buf->writestring("}\n"); +} + +void EnumMember::toJsonBuffer(OutBuffer *buf) +{ + //printf("EnumMember::toJsonBuffer()\n"); + buf->writestring("{\n"); + + JsonProperty(buf, Pname, toChars()); + JsonProperty(buf, Pkind, kind()); + + if (comment) + JsonProperty(buf, Pcomment, (const char *)comment); + + if (loc.linnum) + JsonProperty(buf, Pline, loc.linnum); + + JsonRemoveComma(buf); + buf->writestring("}\n"); +} + + diff --git a/dmd2/json.h b/dmd2/json.h new file mode 100644 index 00000000..9633d170 --- /dev/null +++ b/dmd2/json.h @@ -0,0 +1,24 @@ + + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +#ifndef DMD_JSON_H +#define DMD_JSON_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +struct Array; + +void json_generate(Array *); + +#endif /* DMD_JSON_H */ + diff --git a/dmd2/lexer.c b/dmd2/lexer.c index bb5bbbdf..e6da85a5 100644 --- a/dmd2/lexer.c +++ b/dmd2/lexer.c @@ -1,3112 +1,3191 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#if IN_LLVM -#include -#endif - -/* Lexical Analyzer */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for time() and ctime() - -#include "rmem.h" - -#include "stringtable.h" - -#include "lexer.h" -#include "utf.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if _WIN32 && __DMC__ -// from \dm\src\include\setlocal.h -extern "C" char * __cdecl __locale_decpoint; -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -#define LS 0x2028 // UTF line separator -#define PS 0x2029 // UTF paragraph separator - -/******************************************** - * Do our own char maps - */ - -static unsigned char cmtable[256]; - -const int CMoctal = 0x1; -const int CMhex = 0x2; -const int CMidchar = 0x4; - -inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } -inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } -inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } - -static void cmtable_init() -{ - for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) - { - if ('0' <= c && c <= '7') - cmtable[c] |= CMoctal; - if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) - cmtable[c] |= CMhex; - if (isalnum(c) || c == '_') - cmtable[c] |= CMidchar; - } -} - - -/************************* Token **********************************************/ - -const char *Token::tochars[TOKMAX]; - -void *Token::operator new(size_t size) -{ Token *t; - - if (Lexer::freelist) - { - t = Lexer::freelist; - Lexer::freelist = t->next; - return t; - } - - return ::operator new(size); -} - -#ifdef DEBUG -void Token::print() -{ - fprintf(stdmsg, "%s\n", toChars()); -} -#endif - -const char *Token::toChars() -{ const char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = buffer; - switch (value) - { - case TOKint32v: - sprintf(buffer,"%d",(d_int32)int64value); - break; - - case TOKuns32v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - sprintf(buffer,"%uU",(d_uns32)uns64value); - break; - - case TOKint64v: - sprintf(buffer,"%jdL",int64value); - break; - - case TOKuns64v: - sprintf(buffer,"%juUL",uns64value); - break; - -#if IN_GCC - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - float80value.format(buffer, sizeof(buffer)); - break; - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - float80value.format(buffer, sizeof(buffer)); - // %% buffer - strcat(buffer, "i"); - break; -#else - case TOKfloat32v: - sprintf(buffer,"%Lgf", float80value); - break; - - case TOKfloat64v: - sprintf(buffer,"%Lg", float80value); - break; - - case TOKfloat80v: - sprintf(buffer,"%LgL", float80value); - break; - - case TOKimaginary32v: - sprintf(buffer,"%Lgfi", float80value); - break; - - case TOKimaginary64v: - sprintf(buffer,"%Lgi", float80value); - break; - - case TOKimaginary80v: - sprintf(buffer,"%LgLi", float80value); - break; -#endif - - case TOKstring: -#if CSTRINGS - p = string; -#else - { OutBuffer buf; - - buf.writeByte('"'); - for (size_t i = 0; i < len; ) - { unsigned c; - - utf_decodeChar((unsigned char *)ustring, len, &i, &c); - switch (c) - { - case 0: - break; - - case '"': - case '\\': - buf.writeByte('\\'); - default: - if (isprint(c)) - buf.writeByte(c); - else if (c <= 0x7F) - buf.printf("\\x%02x", c); - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - continue; - } - break; - } - buf.writeByte('"'); - if (postfix) - buf.writeByte('"'); - buf.writeByte(0); - p = (char *)buf.extractData(); - } -#endif - break; - - case TOKidentifier: - case TOKenum: - case TOKstruct: - case TOKimport: - CASE_BASIC_TYPES: - p = ident->toChars(); - break; - - default: - p = toChars(value); - break; - } - return p; -} - -const char *Token::toChars(enum TOK value) -{ const char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = tochars[value]; - if (!p) - { sprintf(buffer,"TOK%d",value); - p = buffer; - } - return p; -} - -/*************************** Lexer ********************************************/ - -Token *Lexer::freelist = NULL; -StringTable Lexer::stringtable; -OutBuffer Lexer::stringbuffer; - -Lexer::Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken) - : loc(mod, 1) -{ - //printf("Lexer::Lexer(%p,%d)\n",base,length); - //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); - memset(&token,0,sizeof(token)); - this->base = base; - this->end = base + endoffset; - p = base + begoffset; - this->mod = mod; - this->doDocComment = doDocComment; - this->anyToken = 0; - this->commentToken = commentToken; - //initKeywords(); - - /* If first line starts with '#!', ignore the line - */ - - if (p[0] == '#' && p[1] =='!') - { - p += 2; - while (1) - { unsigned char c = *p; - switch (c) - { - case '\n': - p++; - break; - - case '\r': - p++; - if (*p == '\n') - p++; - break; - - case 0: - case 0x1A: - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - p++; - continue; - } - break; - } - loc.linnum = 2; - } -} - - -void Lexer::error(const char *format, ...) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - global.errors++; -} - -void Lexer::error(Loc loc, const char *format, ...) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - va_list ap; - va_start(ap, format); - vfprintf(stdmsg, format, ap); - va_end(ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - global.errors++; -} - -TOK Lexer::nextToken() -{ Token *t; - - if (token.next) - { - t = token.next; - memcpy(&token,t,sizeof(Token)); - t->next = freelist; - freelist = t; - } - else - { - scan(&token); - } - //token.print(); - return token.value; -} - -Token *Lexer::peek(Token *ct) -{ Token *t; - - if (ct->next) - t = ct->next; - else - { - t = new Token(); - scan(t); - t->next = NULL; - ct->next = t; - } - return t; -} - -/*********************** - * Look ahead at next token's value. - */ - -TOK Lexer::peekNext() -{ - return peek(&token)->value; -} - -/*********************** - * Look 2 tokens ahead at value. - */ - -TOK Lexer::peekNext2() -{ - Token *t = peek(&token); - return peek(t)->value; -} - -/********************************* - * tk is on the opening (. - * Look ahead and return token that is past the closing ). - */ - -Token *Lexer::peekPastParen(Token *tk) -{ - //printf("peekPastParen()\n"); - int parens = 1; - int curlynest = 0; - while (1) - { - tk = peek(tk); - //tk->print(); - switch (tk->value) - { - case TOKlparen: - parens++; - continue; - - case TOKrparen: - --parens; - if (parens) - continue; - tk = peek(tk); - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - break; - - case TOKeof: - break; - - default: - continue; - } - return tk; - } -} - -/********************************** - * Determine if string is a valid Identifier. - * Placed here because of commonality with Lexer functionality. - * Returns: - * 0 invalid - */ - -int Lexer::isValidIdentifier(char *p) -{ - size_t len; - size_t idx; - - if (!p || !*p) - goto Linvalid; - - if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars - goto Linvalid; - - len = strlen(p); - idx = 0; - while (p[idx]) - { dchar_t dc; - - const char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc); - if (q) - goto Linvalid; - - if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) - goto Linvalid; - } - return 1; - -Linvalid: - return 0; -} - -/**************************** - * Turn next token in buffer into a token. - */ - -void Lexer::scan(Token *t) -{ - unsigned lastLine = loc.linnum; - unsigned linnum; - - t->blockComment = NULL; - t->lineComment = NULL; - while (1) - { - t->ptr = p; - //printf("p = %p, *p = '%c'\n",p,*p); - switch (*p) - { - case 0: - case 0x1A: - t->value = TOKeof; // end of file - return; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '\r': - p++; - if (*p != '\n') // if CR stands by itself - loc.linnum++; - continue; // skip white space - - case '\n': - p++; - loc.linnum++; - continue; // skip white space - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - t->value = number(t); - return; - -#if CSTRINGS - case '\'': - t->value = charConstant(t, 0); - return; - - case '"': - t->value = stringConstant(t,0); - return; - - case 'l': - case 'L': - if (p[1] == '\'') - { - p++; - t->value = charConstant(t, 1); - return; - } - else if (p[1] == '"') - { - p++; - t->value = stringConstant(t, 1); - return; - } -#else - case '\'': - t->value = charConstant(t,0); - return; - - case 'r': - if (p[1] != '"') - goto case_ident; - p++; - case '`': - t->value = wysiwygStringConstant(t, *p); - return; - - case 'x': - if (p[1] != '"') - goto case_ident; - p++; - t->value = hexStringConstant(t); - return; - -#if DMDV2 - case 'q': - if (p[1] == '"') - { - p++; - t->value = delimitedStringConstant(t); - return; - } - else if (p[1] == '{') - { - p++; - t->value = tokenStringConstant(t); - return; - } - else - goto case_ident; -#endif - - case '"': - t->value = escapeStringConstant(t,0); - return; -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': // escaped string literal - { unsigned c; - unsigned char *pstart = p; - - stringbuffer.reset(); - do - { - p++; - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - break; - - default: - c = escapeSequence(); - stringbuffer.writeByte(c); - break; - } - } while (*p == '\\'); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - t->postfix = 0; - t->value = TOKstring; - if (!global.params.useDeprecated) - error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", (int)(p - pstart), pstart, (int)(p - pstart), pstart); - return; - } -#endif - case 'l': - case 'L': -#endif - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'm': case 'n': case 'o': -#if DMDV2 - case 'p': /*case 'q': case 'r':*/ case 's': case 't': -#else - case 'p': case 'q': /*case 'r':*/ case 's': case 't': -#endif - case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - case_ident: - { unsigned char c; - StringValue *sv; - Identifier *id; - - do - { - c = *++p; - } while (isidchar(c) || (c & 0x80 && isUniAlpha(decodeUTF()))); - sv = stringtable.update((char *)t->ptr, p - t->ptr); - id = (Identifier *) sv->ptrvalue; - if (!id) - { id = new Identifier(sv->lstring.string,TOKidentifier); - sv->ptrvalue = id; - } - t->ident = id; - t->value = (enum TOK) id->value; - anyToken = 1; - if (*t->ptr == '_') // if special identifier token - { - static char date[11+1]; - static char time[8+1]; - static char timestamp[24+1]; - - if (!date[0]) // lazy evaluation - { time_t t; - char *p; - - ::time(&t); - p = ctime(&t); - assert(p); - sprintf(date, "%.6s %.4s", p + 4, p + 20); - sprintf(time, "%.8s", p + 11); - sprintf(timestamp, "%.24s", p); - } - -#if DMDV1 - if (mod && id == Id::FILE) - { - t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); - goto Lstr; - } - else if (mod && id == Id::LINE) - { - t->value = TOKint64v; - t->uns64value = loc.linnum; - } - else -#endif - if (id == Id::DATE) - { - t->ustring = (unsigned char *)date; - goto Lstr; - } - else if (id == Id::TIME) - { - t->ustring = (unsigned char *)time; - goto Lstr; - } - else if (id == Id::VENDOR) - { - t->ustring = (unsigned char *)"LDC"; - goto Lstr; - } - else if (id == Id::TIMESTAMP) - { - t->ustring = (unsigned char *)timestamp; - Lstr: - t->value = TOKstring; - Llen: - t->postfix = 0; - t->len = strlen((char *)t->ustring); - } - else if (id == Id::VERSIONX) - { unsigned major = 0; - unsigned minor = 0; - - for (const char *p = global.version + 1; 1; p++) - { - char c = *p; - if (isdigit(c)) - minor = minor * 10 + c - '0'; - else if (c == '.') - { major = minor; - minor = 0; - } - else - break; - } - t->value = TOKint64v; - t->uns64value = major * 1000 + minor; - } -#if DMDV2 - else if (id == Id::EOFX) - { - t->value = TOKeof; - // Advance scanner to end of file - while (!(*p == 0 || *p == 0x1A)) - p++; - } -#endif - } - //printf("t->value = %d\n",t->value); - return; - } - - case '/': - p++; - switch (*p) - { - case '=': - p++; - t->value = TOKdivass; - return; - - case '*': - p++; - linnum = loc.linnum; - while (1) - { - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - break; - - case '\n': - loc.linnum++; - p++; - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated /* */ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - p++; - if (p[-2] == '*' && p - 3 != t->ptr) - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) - { // if /** but not /**/ - getDocComment(t, lastLine == linnum); - } - continue; - - case '/': // do // style comments - linnum = loc.linnum; - while (1) - { unsigned char c = *++p; - switch (c) - { - case '\n': - break; - - case '\r': - if (p[1] == '\n') - p++; - break; - - case 0: - case 0x1A: - if (commentToken) - { - p = end; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - continue; - } - break; - } - - if (commentToken) - { - p++; - loc.linnum++; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - - p++; - loc.linnum++; - continue; - - case '+': - { int nest; - - linnum = loc.linnum; - p++; - nest = 1; - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - p++; - if (*p == '+') - { - p++; - nest++; - } - continue; - - case '+': - p++; - if (*p == '/') - { - p++; - if (--nest == 0) - break; - } - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case '\n': - loc.linnum++; - p++; - continue; - - case 0: - case 0x1A: - error("unterminated /+ +/ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) - { // if /++ but not /++/ - getDocComment(t, lastLine == linnum); - } - continue; - } - } - t->value = TOKdiv; - return; - - case '.': - p++; - if (isdigit(*p)) - { /* Note that we don't allow ._1 and ._ as being - * valid floating point numbers. - */ - p--; - t->value = inreal(t); - } - else if (p[0] == '.') - { - if (p[1] == '.') - { p += 2; - t->value = TOKdotdotdot; - } - else - { p++; - t->value = TOKslice; - } - } - else - t->value = TOKdot; - return; - - case '&': - p++; - if (*p == '=') - { p++; - t->value = TOKandass; - } - else if (*p == '&') - { p++; - t->value = TOKandand; - } - else - t->value = TOKand; - return; - - case '|': - p++; - if (*p == '=') - { p++; - t->value = TOKorass; - } - else if (*p == '|') - { p++; - t->value = TOKoror; - } - else - t->value = TOKor; - return; - - case '-': - p++; - if (*p == '=') - { p++; - t->value = TOKminass; - } -#if 0 - else if (*p == '>') - { p++; - t->value = TOKarrow; - } -#endif - else if (*p == '-') - { p++; - t->value = TOKminusminus; - } - else - t->value = TOKmin; - return; - - case '+': - p++; - if (*p == '=') - { p++; - t->value = TOKaddass; - } - else if (*p == '+') - { p++; - t->value = TOKplusplus; - } - else - t->value = TOKadd; - return; - - case '<': - p++; - if (*p == '=') - { p++; - t->value = TOKle; // <= - } - else if (*p == '<') - { p++; - if (*p == '=') - { p++; - t->value = TOKshlass; // <<= - } - else - t->value = TOKshl; // << - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKleg; // <>= - } - else - t->value = TOKlg; // <> - } - else - t->value = TOKlt; // < - return; - - case '>': - p++; - if (*p == '=') - { p++; - t->value = TOKge; // >= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKshrass; // >>= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKushrass; // >>>= - } - else - t->value = TOKushr; // >>> - } - else - t->value = TOKshr; // >> - } - else - t->value = TOKgt; // > - return; - - case '!': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKnotidentity; // !== - } - else - t->value = TOKnotequal; // != - } - else if (*p == '<') - { p++; - if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKunord; // !<>= - } - else - t->value = TOKue; // !<> - } - else if (*p == '=') - { p++; - t->value = TOKug; // !<= - } - else - t->value = TOKuge; // !< - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKul; // !>= - } - else - t->value = TOKule; // !> - } - else - t->value = TOKnot; // ! - return; - - case '=': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKidentity; // === - } - else - t->value = TOKequal; // == - } - else - t->value = TOKassign; // = - return; - - case '~': - p++; - if (*p == '=') - { p++; - t->value = TOKcatass; // ~= - } - else - t->value = TOKtilde; // ~ - return; - -#define SINGLE(c,tok) case c: p++; t->value = tok; return; - - SINGLE('(', TOKlparen) - SINGLE(')', TOKrparen) - SINGLE('[', TOKlbracket) - SINGLE(']', TOKrbracket) - SINGLE('{', TOKlcurly) - SINGLE('}', TOKrcurly) - SINGLE('?', TOKquestion) - SINGLE(',', TOKcomma) - SINGLE(';', TOKsemicolon) - SINGLE(':', TOKcolon) - SINGLE('$', TOKdollar) - SINGLE('@', TOKat) - -#undef SINGLE - -#define DOUBLE(c1,tok1,c2,tok2) \ - case c1: \ - p++; \ - if (*p == c2) \ - { p++; \ - t->value = tok2; \ - } \ - else \ - t->value = tok1; \ - return; - - DOUBLE('*', TOKmul, '=', TOKmulass) - DOUBLE('%', TOKmod, '=', TOKmodass) - DOUBLE('^', TOKxor, '=', TOKxorass) - -#undef DOUBLE - - case '#': - p++; - pragma(); - continue; - - default: - { unsigned char c = *p; - - if (c & 0x80) - { unsigned u = decodeUTF(); - - // Check for start of unicode identifier - if (isUniAlpha(u)) - goto case_ident; - - if (u == PS || u == LS) - { - loc.linnum++; - p++; - continue; - } - } - if (isprint(c)) - error("unsupported char '%c'", c); - else - error("unsupported char 0x%02x", c); - p++; - continue; - } - } - } -} - -/******************************************* - * Parse escape sequence. - */ - -unsigned Lexer::escapeSequence() -{ unsigned c = *p; - -#ifdef TEXTUAL_ASSEMBLY_OUT - return c; -#endif - int n; - int ndigits; - - switch (c) - { - case '\'': - case '"': - case '?': - case '\\': - Lconsume: - p++; - break; - - case 'a': c = 7; goto Lconsume; - case 'b': c = 8; goto Lconsume; - case 'f': c = 12; goto Lconsume; - case 'n': c = 10; goto Lconsume; - case 'r': c = 13; goto Lconsume; - case 't': c = 9; goto Lconsume; - case 'v': c = 11; goto Lconsume; - - case 'u': - ndigits = 4; - goto Lhex; - case 'U': - ndigits = 8; - goto Lhex; - case 'x': - ndigits = 2; - Lhex: - p++; - c = *p; - if (ishex(c)) - { unsigned v; - - n = 0; - v = 0; - while (1) - { - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - v = v * 16 + c; - c = *++p; - if (++n == ndigits) - break; - if (!ishex(c)) - { error("escape hex sequence has %d hex digits instead of %d", n, ndigits); - break; - } - } - if (ndigits != 2 && !utf_isValidDchar(v)) - { error("invalid UTF character \\U%08x", v); - v = '?'; // recover with valid UTF character - } - c = v; - } - else - error("undefined escape hex sequence \\%c\n",c); - break; - - case '&': // named character entity - for (unsigned char *idstart = ++p; 1; p++) - { - switch (*p) - { - case ';': - c = HtmlNamedEntity(idstart, p - idstart); - if (c == ~0) - { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart); - c = ' '; - } - p++; - break; - - default: - if (isalpha(*p) || - (p != idstart + 1 && isdigit(*p))) - continue; - error("unterminated named entity"); - break; - } - break; - } - break; - - case 0: - case 0x1A: // end of file - c = '\\'; - break; - - default: - if (isoctal(c)) - { unsigned v; - - n = 0; - v = 0; - do - { - v = v * 8 + (c - '0'); - c = *++p; - } while (++n < 3 && isoctal(c)); - c = v; - if (c > 0xFF) - error("0%03o is larger than a byte", c); - } - else - error("undefined escape sequence \\%c\n",c); - break; - } - return c; -} - -/************************************** - */ - -TOK Lexer::wysiwygStringConstant(Token *t, int tc) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - case '`': - if (c == tc) - { - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - } - break; - - default: - if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - stringbuffer.writeUTF8(u); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - -TOK Lexer::hexStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned n = 0; - unsigned v; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - - case '\r': - if (*p == '\n') - continue; // ignore - // Treat isolated '\r' as if it were a '\n' - case '\n': - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - if (n & 1) - { error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - default: - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - else - error("non-hex character \\u%x", u); - } - else - error("non-hex character '%c'", c); - if (n & 1) - { v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } -} - - -#if DMDV2 -/************************************** - * Lex delimited strings: - * q"(foo(xxx))" // "foo(xxx)" - * q"[foo(]" // "foo(" - * q"/foo]/" // "foo]" - * q"HERE - * foo - * HERE" // "foo\n" - * Input: - * p is on the " - */ - -TOK Lexer::delimitedStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned delimleft = 0; - unsigned delimright = 0; - unsigned nest = 1; - unsigned nestcount; - Identifier *hereid = NULL; - unsigned blankrol = 0; - unsigned startline = 0; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - //printf("c = '%c'\n", c); - switch (c) - { - case '\n': - Lnextline: - loc.linnum++; - startline = 1; - if (blankrol) - { blankrol = 0; - continue; - } - if (hereid) - { - stringbuffer.writeUTF8(c); - continue; - } - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - goto Lnextline; - - case 0: - case 0x1A: - goto Lerror; - - default: - if (c & 0x80) - { p--; - c = decodeUTF(); - p++; - if (c == PS || c == LS) - goto Lnextline; - } - break; - } - if (delimleft == 0) - { delimleft = c; - nest = 1; - nestcount = 1; - if (c == '(') - delimright = ')'; - else if (c == '{') - delimright = '}'; - else if (c == '[') - delimright = ']'; - else if (c == '<') - delimright = '>'; - else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) - { // Start of identifier; must be a heredoc - Token t; - p--; - scan(&t); // read in heredoc identifier - if (t.value != TOKidentifier) - { error("identifier expected for heredoc, not %s", t.toChars()); - delimright = c; - } - else - { hereid = t.ident; - //printf("hereid = '%s'\n", hereid->toChars()); - blankrol = 1; - } - nest = 0; - } - else - { delimright = c; - nest = 0; - if (isspace(c)) - error("delimiter cannot be whitespace"); - } - } - else - { - if (blankrol) - { error("heredoc rest of line should be blank"); - blankrol = 0; - continue; - } - if (nest == 1) - { - if (c == delimleft) - nestcount++; - else if (c == delimright) - { nestcount--; - if (nestcount == 0) - goto Ldone; - } - } - else if (c == delimright) - goto Ldone; - if (startline && isalpha(c) && hereid) - { Token t; - unsigned char *psave = p; - p--; - scan(&t); // read in possible heredoc identifier - //printf("endid = '%s'\n", t.ident->toChars()); - if (t.value == TOKidentifier && t.ident->equals(hereid)) - { /* should check that rest of line is blank - */ - goto Ldone; - } - p = psave; - } - stringbuffer.writeUTF8(c); - startline = 0; - } - } - -Ldone: - if (*p == '"') - p++; - else - error("delimited string must end in %c\"", delimright); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -/************************************** - * Lex delimited strings: - * q{ foo(xxx) } // " foo(xxx) " - * q{foo(} // "foo(" - * q{{foo}"}"} // "{foo}"}"" - * Input: - * p is on the q - */ - -TOK Lexer::tokenStringConstant(Token *t) -{ - unsigned nest = 1; - Loc start = loc; - unsigned char *pstart = ++p; - - while (1) - { Token tok; - - scan(&tok); - switch (tok.value) - { - case TOKlcurly: - nest++; - continue; - - case TOKrcurly: - if (--nest == 0) - goto Ldone; - continue; - - case TOKeof: - goto Lerror; - - default: - continue; - } - } - -Ldone: - t->len = p - 1 - pstart; - t->ustring = (unsigned char *)mem.malloc(t->len + 1); - memcpy(t->ustring, pstart, t->len); - t->ustring[t->len] = 0; - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated token string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -#endif - - -/************************************** - */ - -TOK Lexer::escapeStringConstant(Token *t, int wide) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { -#if !( TEXTUAL_ASSEMBLY_OUT ) - case '\\': - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - continue; - - default: - c = escapeSequence(); - break; - } - break; -#endif - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case '"': - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - case 0: - case 0x1A: - p--; - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - if (c == LS || c == PS) - { c = '\n'; - loc.linnum++; - } - p++; - stringbuffer.writeUTF8(c); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - */ - -TOK Lexer::charConstant(Token *t, int wide) -{ - unsigned c; - TOK tk = TOKcharv; - - //printf("Lexer::charConstant\n"); - p++; - c = *p++; - switch (c) - { -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': - switch (*p) - { - case 'u': - t->uns64value = escapeSequence(); - tk = TOKwcharv; - break; - - case 'U': - case '&': - t->uns64value = escapeSequence(); - tk = TOKdcharv; - break; - - default: - t->uns64value = escapeSequence(); - break; - } - break; -#endif - case '\n': - L1: - loc.linnum++; - case '\r': - case 0: - case 0x1A: - case '\'': - error("unterminated character constant"); - return tk; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - p++; - if (c == LS || c == PS) - goto L1; - if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) - tk = TOKwcharv; - else - tk = TOKdcharv; - } - t->uns64value = c; - break; - } - - if (*p != '\'') - { error("unterminated character constant"); - return tk; - } - p++; - return tk; -} - -/*************************************** - * Get postfix of string literal. - */ - -void Lexer::stringPostfix(Token *t) -{ - switch (*p) - { - case 'c': - case 'w': - case 'd': - t->postfix = *p; - p++; - break; - - default: - t->postfix = 0; - break; - } -} - -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - -/************************************** - * Read in a number. - * If it's an integer, store it in tok.TKutok.Vlong. - * integers can be decimal, octal or hex - * Handle the suffixes U, UL, LU, L, etc. - * If it's double, store it in tok.TKutok.Vdouble. - * Returns: - * TKnum - * TKdouble,... - */ - -TOK Lexer::number(Token *t) -{ - // We use a state machine to collect numbers - enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, - STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, - STATE_hexh, STATE_error }; - enum STATE state; - - enum FLAGS - { FLAGS_decimal = 1, // decimal - FLAGS_unsigned = 2, // u or U suffix - FLAGS_long = 4, // l or L suffix - }; - enum FLAGS flags = FLAGS_decimal; - - int i; - int base; - unsigned c; - unsigned char *start; - TOK result; - - //printf("Lexer::number()\n"); - state = STATE_initial; - base = 0; - stringbuffer.reset(); - start = p; - while (1) - { - c = *p; - switch (state) - { - case STATE_initial: // opening state - if (c == '0') - state = STATE_0; - else - state = STATE_decimal; - break; - - case STATE_0: - flags = (FLAGS) (flags & ~FLAGS_decimal); - switch (c) - { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif - case 'X': - case 'x': - state = STATE_hex0; - break; - - case '.': - if (p[1] == '.') // .. is a separate token - goto done; - case 'i': - case 'f': - case 'F': - goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif - case 'B': - case 'b': - state = STATE_binary0; - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - state = STATE_octal; - break; - -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif - case '_': - state = STATE_octal; - p++; - continue; - - case 'L': - if (p[1] == 'i') - goto real; - goto done; - - default: - goto done; - } - break; - - case STATE_decimal: // reading decimal number - if (!isdigit(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - else if (c == 'i' || c == 'f' || c == 'F' || - c == 'e' || c == 'E') - { - real: // It's a real number. Back up and rescan as a real - p = start; - return inreal(t); - } - else if (c == 'L' && p[1] == 'i') - goto real; - goto done; - } - break; - - case STATE_hex0: // reading hex number - case STATE_hex: - if (!ishex(c)) - { - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'P' || c == 'p' || c == 'i') - goto real; - if (state == STATE_hex0) - error("Hex digit expected, not '%c'", c); - goto done; - } - state = STATE_hex; - break; - -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - - case STATE_octal: // reading octal number - case STATE_octale: // reading octal number with non-octal digits - if (!isoctal(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'i') - goto real; - if (isdigit(c)) - { - state = STATE_octale; - } - else - goto done; - } - break; - - case STATE_binary0: // starting binary number - case STATE_binary: // reading binary number - if (c != '0' && c != '1') - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (state == STATE_binary0) - { error("binary digit expected"); - state = STATE_error; - break; - } - else - goto done; - } - state = STATE_binary; - break; - - case STATE_error: // for error recovery - if (!isdigit(c)) // scan until non-digit - goto done; - break; - - default: - assert(0); - } - stringbuffer.writeByte(c); - p++; - } -done: - stringbuffer.writeByte(0); // terminate string - if (state == STATE_octale) - error("Octal digit expected"); - - uinteger_t n; // unsigned >=64 bit integer type - - if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) - n = stringbuffer.data[0] - '0'; - else - { - // Convert string to integer -#if __DMC__ - errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); - if (errno == ERANGE) - error("integer overflow"); -#else - // Not everybody implements strtoull() - char *p = (char *)stringbuffer.data; - int r = 10, d; - - if (*p == '0') - { - if (p[1] == 'x' || p[1] == 'X') - p += 2, r = 16; - else if (p[1] == 'b' || p[1] == 'B') - p += 2, r = 2; - else if (isdigit(p[1])) - p += 1, r = 8; - } - - n = 0; - while (1) - { - if (*p >= '0' && *p <= '9') - d = *p - '0'; - else if (*p >= 'a' && *p <= 'z') - d = *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'Z') - d = *p - 'A' + 10; - else - break; - if (d >= r) - break; - uinteger_t n2 = n * r; - //printf("n2 / r = %llx, n = %llx\n", n2/r, n); - if (n2 / r != n || n2 + d < n) - { - error ("integer overflow"); - break; - } - - n = n2 + d; - p++; - } -#endif - if (sizeof(n) > 8 && - n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits - error("integer overflow"); - } - - // Parse trailing 'u', 'U', 'l' or 'L' in any combination - while (1) - { unsigned char f; - - switch (*p) - { case 'U': - case 'u': - f = FLAGS_unsigned; - goto L1; - - case 'l': - if (1 || !global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - f = FLAGS_long; - L1: - p++; - if (flags & f) - error("unrecognized token"); - flags = (FLAGS) (flags | f); - continue; - default: - break; - } - break; - } - - switch (flags) - { - case 0: - /* Octal or Hexadecimal constant. - * First that fits: int, uint, long, ulong - */ - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else if (n & 0xFFFFFFFF00000000LL) - result = TOKint64v; - else if (n & 0x80000000) - result = TOKuns32v; - else - result = TOKint32v; - break; - - case FLAGS_decimal: - /* First that fits: int, long, long long - */ - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else if (n & 0xFFFFFFFF80000000LL) - result = TOKint64v; - else - result = TOKint32v; - break; - - case FLAGS_unsigned: - case FLAGS_decimal | FLAGS_unsigned: - /* First that fits: uint, ulong - */ - if (n & 0xFFFFFFFF00000000LL) - result = TOKuns64v; - else - result = TOKuns32v; - break; - - case FLAGS_decimal | FLAGS_long: - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else - result = TOKint64v; - break; - - case FLAGS_long: - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else - result = TOKint64v; - break; - - case FLAGS_unsigned | FLAGS_long: - case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: - result = TOKuns64v; - break; - - default: - #ifdef DEBUG - printf("%x\n",flags); - #endif - assert(0); - } - t->uns64value = n; - return result; -} - -/************************************** - * Read in characters, converting them to real. - * Bugs: - * Exponent overflow not detected. - * Too much requested precision is not detected. - */ - -TOK Lexer::inreal(Token *t) -#ifdef __DMC__ -__in -{ - assert(*p == '.' || isdigit(*p)); -} -__out (result) -{ - switch (result) - { - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - break; - - default: - assert(0); - } -} -__body -#endif /* __DMC__ */ -{ int dblstate; - unsigned c; - char hex; // is this a hexadecimal-floating-constant? - TOK result; - - //printf("Lexer::inreal()\n"); - stringbuffer.reset(); - dblstate = 0; - hex = 0; -Lnext: - while (1) - { - // Get next char from input - c = *p++; - //printf("dblstate = %d, c = '%c'\n", dblstate, c); - while (1) - { - switch (dblstate) - { - case 0: // opening state - if (c == '0') - dblstate = 9; - else if (c == '.') - dblstate = 3; - else - dblstate = 1; - break; - - case 9: - dblstate = 1; - if (c == 'X' || c == 'x') - { hex++; - break; - } - case 1: // digits to left of . - case 3: // digits to right of . - case 7: // continuing exponent digits - if (!isdigit(c) && !(hex && isxdigit(c))) - { - if (c == '_') - goto Lnext; // ignore embedded '_' - dblstate++; - continue; - } - break; - - case 2: // no more digits to left of . - if (c == '.') - { dblstate++; - break; - } - case 4: // no more digits to right of . - if ((c == 'E' || c == 'e') || - hex && (c == 'P' || c == 'p')) - { dblstate = 5; - hex = 0; // exponent is always decimal - break; - } - if (hex) - error("binary-exponent-part required"); - goto done; - - case 5: // looking immediately to right of E - dblstate++; - if (c == '-' || c == '+') - break; - case 6: // 1st exponent digit expected - if (!isdigit(c)) - error("exponent expected"); - dblstate++; - break; - - case 8: // past end of exponent digits - goto done; - } - break; - } - stringbuffer.writeByte(c); - } -done: - p--; - - stringbuffer.writeByte(0); - -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; -#endif -#ifdef IN_GCC - t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#else - t->float80value = strtold((char *)stringbuffer.data, NULL); -#endif - errno = 0; - float strtofres; - double strtodres; - switch (*p) - { - case 'F': - case 'f': -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Float); -#else - strtofres = strtof((char *)stringbuffer.data, NULL); - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtofres != 0 && strtofres != HUGE_VALF && strtofres != -HUGE_VALF) - errno = 0; -#endif - result = TOKfloat32v; - p++; - break; - - default: -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Double); -#else - strtodres = strtod((char *)stringbuffer.data, NULL); - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtodres != 0 && strtodres != HUGE_VAL && strtodres != -HUGE_VAL) - errno = 0; -#endif - result = TOKfloat64v; - break; - - case 'l': - if (!global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - result = TOKfloat80v; - p++; - break; - } - if (*p == 'i' || *p == 'I') - { - if (!global.params.useDeprecated && *p == 'I') - error("'I' suffix is deprecated, use 'i' instead"); - p++; - switch (result) - { - case TOKfloat32v: - result = TOKimaginary32v; - break; - case TOKfloat64v: - result = TOKimaginary64v; - break; - case TOKfloat80v: - result = TOKimaginary80v; - break; - } - } -#if _WIN32 && __DMC__ - __locale_decpoint = save; -#endif - if (errno == ERANGE) - error("number is not representable"); - return result; -} - -/********************************************* - * Do pragma. - * Currently, the only pragma supported is: - * #line linnum [filespec] - */ - -void Lexer::pragma() -{ - Token tok; - int linnum; - char *filespec = NULL; - Loc loc = this->loc; - - scan(&tok); - if (tok.value != TOKidentifier || tok.ident != Id::line) - goto Lerr; - - scan(&tok); - if (tok.value == TOKint32v || tok.value == TOKint64v) - linnum = tok.uns64value - 1; - else - goto Lerr; - - while (1) - { - switch (*p) - { - case 0: - case 0x1A: - case '\n': - Lnewline: - this->loc.linnum = linnum; - if (filespec) - this->loc.filename = filespec; - return; - - case '\r': - p++; - if (*p != '\n') - { p--; - goto Lnewline; - } - continue; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '_': - if (mod && memcmp(p, "__FILE__", 8) == 0) - { - p += 8; - filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); - } - continue; - - case '"': - if (filespec) - goto Lerr; - stringbuffer.reset(); - p++; - while (1) - { unsigned c; - - c = *p; - switch (c) - { - case '\n': - case '\r': - case 0: - case 0x1A: - goto Lerr; - - case '"': - stringbuffer.writeByte(0); - filespec = mem.strdup((char *)stringbuffer.data); - p++; - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lerr; - } - stringbuffer.writeByte(c); - p++; - continue; - } - break; - } - continue; - - default: - if (*p & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lnewline; - } - goto Lerr; - } - } - -Lerr: - error(loc, "#line integer [\"filespec\"]\\n expected"); -} - - -/******************************************** - * Decode UTF character. - * Issue error messages for invalid sequences. - * Return decoded character, advance p to last character in UTF sequence. - */ - -unsigned Lexer::decodeUTF() -{ - dchar_t u; - unsigned char c; - unsigned char *s = p; - size_t len; - size_t idx; - const char *msg; - - c = *s; - assert(c & 0x80); - - // Check length of remaining string up to 6 UTF-8 characters - for (len = 1; len < 6 && s[len]; len++) - ; - - idx = 0; - msg = utf_decodeChar(s, len, &idx, &u); - p += idx - 1; - if (msg) - { - error("%s", msg); - } - return u; -} - - -/*************************************************** - * Parse doc comment embedded between t->ptr and p. - * Remove trailing blanks and tabs from lines. - * Replace all newlines with \n. - * Remove leading comment character from each line. - * Decide if it's a lineComment or a blockComment. - * Append to previous one for this token. - */ - -void Lexer::getDocComment(Token *t, unsigned lineComment) -{ - /* ct tells us which kind of comment it is: '/', '*', or '+' - */ - unsigned char ct = t->ptr[2]; - - /* Start of comment text skips over / * *, / + +, or / / / - */ - unsigned char *q = t->ptr + 3; // start of comment text - - unsigned char *qend = p; - if (ct == '*' || ct == '+') - qend -= 2; - - /* Scan over initial row of ****'s or ++++'s or ////'s - */ - for (; q < qend; q++) - { - if (*q != ct) - break; - } - - /* Remove trailing row of ****'s or ++++'s - */ - if (ct != '/') - { - for (; q < qend; qend--) - { - if (qend[-1] != ct) - break; - } - } - - /* Comment is now [q .. qend]. - * Canonicalize it into buf[]. - */ - OutBuffer buf; - int linestart = 0; - - for (; q < qend; q++) - { - unsigned char c = *q; - - switch (c) - { - case '*': - case '+': - if (linestart && c == ct) - { linestart = 0; - /* Trim preceding whitespace up to preceding \n - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - continue; - } - break; - - case ' ': - case '\t': - break; - - case '\r': - if (q[1] == '\n') - continue; // skip the \r - goto Lnewline; - - default: - if (c == 226) - { - // If LS or PS - if (q[1] == 128 && - (q[2] == 168 || q[2] == 169)) - { - q += 2; - goto Lnewline; - } - } - linestart = 0; - break; - - Lnewline: - c = '\n'; // replace all newlines with \n - case '\n': - linestart = 1; - - /* Trim trailing whitespace - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - - break; - } - buf.writeByte(c); - } - - // Always end with a newline - if (!buf.offset || buf.data[buf.offset - 1] != '\n') - buf.writeByte('\n'); - - buf.writeByte(0); - - // It's a line comment if the start of the doc comment comes - // after other non-whitespace on the same line. - unsigned char** dc = (lineComment && anyToken) - ? &t->lineComment - : &t->blockComment; - - // Combine with previous doc comment, if any - if (*dc) - *dc = combineComments(*dc, (unsigned char *)buf.data); - else - *dc = (unsigned char *)buf.extractData(); -} - -/******************************************** - * Combine two document comments into one, - * separated by a newline. - */ - -unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) -{ - //printf("Lexer::combineComments('%s', '%s')\n", c1, c2); - - unsigned char *c = c2; - - if (c1) - { c = c1; - if (c2) - { size_t len1 = strlen((char *)c1); - size_t len2 = strlen((char *)c2); - - c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1); - memcpy(c, c1, len1); - if (len1 && c1[len1 - 1] != '\n') - { c[len1] = '\n'; - len1++; - } - memcpy(c + len1, c2, len2); - c[len1 + len2] = 0; - } - } - return c; -} - -/******************************************** - * Create an identifier in the string table. - */ - -Identifier *Lexer::idPool(const char *s) -{ - size_t len = strlen(s); - StringValue *sv = stringtable.update(s, len); - Identifier *id = (Identifier *) sv->ptrvalue; - if (!id) - { - id = new Identifier(sv->lstring.string, TOKidentifier); - sv->ptrvalue = id; - } - return id; -} - -/********************************************* - * Create a unique identifier using the prefix s. - */ - -Identifier *Lexer::uniqueId(const char *s, int num) -{ char buffer[32]; - size_t slen = strlen(s); - - assert(slen + sizeof(num) * 3 + 1 <= sizeof(buffer)); - sprintf(buffer, "%s%d", s, num); - return idPool(buffer); -} - -Identifier *Lexer::uniqueId(const char *s) -{ - static int num; - return uniqueId(s, ++num); -} - -/**************************************** - */ - -struct Keyword -{ const char *name; - enum TOK value; -}; - -static Keyword keywords[] = -{ -// { "", TOK }, - - { "this", TOKthis }, - { "super", TOKsuper }, - { "assert", TOKassert }, - { "null", TOKnull }, - { "true", TOKtrue }, - { "false", TOKfalse }, - { "cast", TOKcast }, - { "new", TOKnew }, - { "delete", TOKdelete }, - { "throw", TOKthrow }, - { "module", TOKmodule }, - { "pragma", TOKpragma }, - { "typeof", TOKtypeof }, - { "typeid", TOKtypeid }, - - { "template", TOKtemplate }, - - { "void", TOKvoid }, - { "byte", TOKint8 }, - { "ubyte", TOKuns8 }, - { "short", TOKint16 }, - { "ushort", TOKuns16 }, - { "int", TOKint32 }, - { "uint", TOKuns32 }, - { "long", TOKint64 }, - { "ulong", TOKuns64 }, - { "cent", TOKcent, }, - { "ucent", TOKucent, }, - { "float", TOKfloat32 }, - { "double", TOKfloat64 }, - { "real", TOKfloat80 }, - - { "bool", TOKbool }, - { "char", TOKchar }, - { "wchar", TOKwchar }, - { "dchar", TOKdchar }, - - { "ifloat", TOKimaginary32 }, - { "idouble", TOKimaginary64 }, - { "ireal", TOKimaginary80 }, - - { "cfloat", TOKcomplex32 }, - { "cdouble", TOKcomplex64 }, - { "creal", TOKcomplex80 }, - - { "delegate", TOKdelegate }, - { "function", TOKfunction }, - - { "is", TOKis }, - { "if", TOKif }, - { "else", TOKelse }, - { "while", TOKwhile }, - { "for", TOKfor }, - { "do", TOKdo }, - { "switch", TOKswitch }, - { "case", TOKcase }, - { "default", TOKdefault }, - { "break", TOKbreak }, - { "continue", TOKcontinue }, - { "synchronized", TOKsynchronized }, - { "return", TOKreturn }, - { "goto", TOKgoto }, - { "try", TOKtry }, - { "catch", TOKcatch }, - { "finally", TOKfinally }, - { "with", TOKwith }, - { "asm", TOKasm }, - { "foreach", TOKforeach }, - { "foreach_reverse", TOKforeach_reverse }, - { "scope", TOKscope }, - - { "struct", TOKstruct }, - { "class", TOKclass }, - { "interface", TOKinterface }, - { "union", TOKunion }, - { "enum", TOKenum }, - { "import", TOKimport }, - { "mixin", TOKmixin }, - { "static", TOKstatic }, - { "final", TOKfinal }, - { "const", TOKconst }, - { "typedef", TOKtypedef }, - { "alias", TOKalias }, - { "override", TOKoverride }, - { "abstract", TOKabstract }, - { "volatile", TOKvolatile }, - { "debug", TOKdebug }, - { "deprecated", TOKdeprecated }, - { "in", TOKin }, - { "out", TOKout }, - { "inout", TOKinout }, - { "lazy", TOKlazy }, - { "auto", TOKauto }, - - { "align", TOKalign }, - { "extern", TOKextern }, - { "private", TOKprivate }, - { "package", TOKpackage }, - { "protected", TOKprotected }, - { "public", TOKpublic }, - { "export", TOKexport }, - - { "body", TOKbody }, - { "invariant", TOKinvariant }, - { "unittest", TOKunittest }, - { "version", TOKversion }, - //{ "manifest", TOKmanifest }, - - // Added after 1.0 - { "ref", TOKref }, - { "macro", TOKmacro }, -#if DMDV2 - { "pure", TOKpure }, - { "nothrow", TOKnothrow }, - { "__thread", TOKtls }, - { "__gshared", TOKgshared }, - { "__traits", TOKtraits }, - { "__overloadset", TOKoverloadset }, - { "__FILE__", TOKfile }, - { "__LINE__", TOKline }, - { "shared", TOKshared }, - { "immutable", TOKimmutable }, -#endif -}; - -int Token::isKeyword() -{ - for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) - { - if (keywords[u].value == value) - return 1; - } - return 0; -} - -void Lexer::initKeywords() -{ StringValue *sv; - unsigned u; - enum TOK v; - unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - - if (global.params.Dversion == 1) - nkeywords -= 2; - - cmtable_init(); - - for (u = 0; u < nkeywords; u++) - { const char *s; - - //printf("keyword[%d] = '%s'\n",u, keywords[u].name); - s = keywords[u].name; - v = keywords[u].value; - sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); - - //printf("tochars[%d] = '%s'\n",v, s); - Token::tochars[v] = s; - } - - Token::tochars[TOKeof] = "EOF"; - Token::tochars[TOKlcurly] = "{"; - Token::tochars[TOKrcurly] = "}"; - Token::tochars[TOKlparen] = "("; - Token::tochars[TOKrparen] = ")"; - Token::tochars[TOKlbracket] = "["; - Token::tochars[TOKrbracket] = "]"; - Token::tochars[TOKsemicolon] = ";"; - Token::tochars[TOKcolon] = ":"; - Token::tochars[TOKcomma] = ","; - Token::tochars[TOKdot] = "."; - Token::tochars[TOKxor] = "^"; - Token::tochars[TOKxorass] = "^="; - Token::tochars[TOKassign] = "="; - Token::tochars[TOKconstruct] = "="; -#if DMDV2 - Token::tochars[TOKblit] = "="; -#endif - Token::tochars[TOKlt] = "<"; - Token::tochars[TOKgt] = ">"; - Token::tochars[TOKle] = "<="; - Token::tochars[TOKge] = ">="; - Token::tochars[TOKequal] = "=="; - Token::tochars[TOKnotequal] = "!="; - Token::tochars[TOKnotidentity] = "!is"; - Token::tochars[TOKtobool] = "!!"; - - Token::tochars[TOKunord] = "!<>="; - Token::tochars[TOKue] = "!<>"; - Token::tochars[TOKlg] = "<>"; - Token::tochars[TOKleg] = "<>="; - Token::tochars[TOKule] = "!>"; - Token::tochars[TOKul] = "!>="; - Token::tochars[TOKuge] = "!<"; - Token::tochars[TOKug] = "!<="; - - Token::tochars[TOKnot] = "!"; - Token::tochars[TOKtobool] = "!!"; - Token::tochars[TOKshl] = "<<"; - Token::tochars[TOKshr] = ">>"; - Token::tochars[TOKushr] = ">>>"; - Token::tochars[TOKadd] = "+"; - Token::tochars[TOKmin] = "-"; - Token::tochars[TOKmul] = "*"; - Token::tochars[TOKdiv] = "/"; - Token::tochars[TOKmod] = "%"; - Token::tochars[TOKslice] = ".."; - Token::tochars[TOKdotdotdot] = "..."; - Token::tochars[TOKand] = "&"; - Token::tochars[TOKandand] = "&&"; - Token::tochars[TOKor] = "|"; - Token::tochars[TOKoror] = "||"; - Token::tochars[TOKarray] = "[]"; - Token::tochars[TOKindex] = "[i]"; - Token::tochars[TOKaddress] = "&"; - Token::tochars[TOKstar] = "*"; - Token::tochars[TOKtilde] = "~"; - Token::tochars[TOKdollar] = "$"; - Token::tochars[TOKcast] = "cast"; - Token::tochars[TOKplusplus] = "++"; - Token::tochars[TOKminusminus] = "--"; - Token::tochars[TOKtype] = "type"; - Token::tochars[TOKquestion] = "?"; - Token::tochars[TOKneg] = "-"; - Token::tochars[TOKuadd] = "+"; - Token::tochars[TOKvar] = "var"; - Token::tochars[TOKaddass] = "+="; - Token::tochars[TOKminass] = "-="; - Token::tochars[TOKmulass] = "*="; - Token::tochars[TOKdivass] = "/="; - Token::tochars[TOKmodass] = "%="; - Token::tochars[TOKshlass] = "<<="; - Token::tochars[TOKshrass] = ">>="; - Token::tochars[TOKushrass] = ">>>="; - Token::tochars[TOKandass] = "&="; - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKcatass] = "~="; - Token::tochars[TOKcat] = "~"; - Token::tochars[TOKcall] = "call"; - Token::tochars[TOKidentity] = "is"; - Token::tochars[TOKnotidentity] = "!is"; - - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKidentifier] = "identifier"; - Token::tochars[TOKat] = "@"; - - // For debugging - Token::tochars[TOKdotexp] = "dotexp"; - Token::tochars[TOKdotti] = "dotti"; - Token::tochars[TOKdotvar] = "dotvar"; - Token::tochars[TOKdottype] = "dottype"; - Token::tochars[TOKsymoff] = "symoff"; - Token::tochars[TOKarraylength] = "arraylength"; - Token::tochars[TOKarrayliteral] = "arrayliteral"; - Token::tochars[TOKassocarrayliteral] = "assocarrayliteral"; - Token::tochars[TOKstructliteral] = "structliteral"; - Token::tochars[TOKstring] = "string"; - Token::tochars[TOKdsymbol] = "symbol"; - Token::tochars[TOKtuple] = "tuple"; - Token::tochars[TOKdeclaration] = "declaration"; - Token::tochars[TOKdottd] = "dottd"; - Token::tochars[TOKon_scope_exit] = "scope(exit)"; - Token::tochars[TOKon_scope_success] = "scope(success)"; - Token::tochars[TOKon_scope_failure] = "scope(failure)"; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#if IN_LLVM +#include +#endif + +/* Lexical Analyzer */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for time() and ctime() + +#include "rmem.h" + +#include "stringtable.h" + +#include "lexer.h" +#include "utf.h" +#include "identifier.h" +#include "id.h" +#include "module.h" + +#if _WIN32 && __DMC__ +// from \dm\src\include\setlocal.h +extern "C" char * __cdecl __locale_decpoint; +#endif + +extern int HtmlNamedEntity(unsigned char *p, int length); + +#define LS 0x2028 // UTF line separator +#define PS 0x2029 // UTF paragraph separator + +void unittest_lexer(); + +/******************************************** + * Do our own char maps + */ + +static unsigned char cmtable[256]; + +const int CMoctal = 0x1; +const int CMhex = 0x2; +const int CMidchar = 0x4; + +inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } +inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } +inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } + +static void cmtable_init() +{ + for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) + { + if ('0' <= c && c <= '7') + cmtable[c] |= CMoctal; + if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) + cmtable[c] |= CMhex; + if (isalnum(c) || c == '_') + cmtable[c] |= CMidchar; + } +} + + +/************************* Token **********************************************/ + +const char *Token::tochars[TOKMAX]; + +void *Token::operator new(size_t size) +{ Token *t; + + if (Lexer::freelist) + { + t = Lexer::freelist; + Lexer::freelist = t->next; + return t; + } + + return ::operator new(size); +} + +#ifdef DEBUG +void Token::print() +{ + fprintf(stdmsg, "%s\n", toChars()); +} +#endif + +const char *Token::toChars() +{ const char *p; + static char buffer[3 + 3 * sizeof(value) + 1]; + + p = buffer; + switch (value) + { + case TOKint32v: + sprintf(buffer,"%d",(d_int32)int64value); + break; + + case TOKuns32v: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + sprintf(buffer,"%uU",(d_uns32)uns64value); + break; + + case TOKint64v: + sprintf(buffer,"%jdL",int64value); + break; + + case TOKuns64v: + sprintf(buffer,"%juUL",uns64value); + break; + +#if IN_GCC + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + float80value.format(buffer, sizeof(buffer)); + break; + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + float80value.format(buffer, sizeof(buffer)); + // %% buffer + strcat(buffer, "i"); + break; +#else + case TOKfloat32v: + sprintf(buffer,"%Lgf", float80value); + break; + + case TOKfloat64v: + sprintf(buffer,"%Lg", float80value); + break; + + case TOKfloat80v: + sprintf(buffer,"%LgL", float80value); + break; + + case TOKimaginary32v: + sprintf(buffer,"%Lgfi", float80value); + break; + + case TOKimaginary64v: + sprintf(buffer,"%Lgi", float80value); + break; + + case TOKimaginary80v: + sprintf(buffer,"%LgLi", float80value); + break; +#endif + + case TOKstring: +#if CSTRINGS + p = string; +#else + { OutBuffer buf; + + buf.writeByte('"'); + for (size_t i = 0; i < len; ) + { unsigned c; + + utf_decodeChar((unsigned char *)ustring, len, &i, &c); + switch (c) + { + case 0: + break; + + case '"': + case '\\': + buf.writeByte('\\'); + default: + if (isprint(c)) + buf.writeByte(c); + else if (c <= 0x7F) + buf.printf("\\x%02x", c); + else if (c <= 0xFFFF) + buf.printf("\\u%04x", c); + else + buf.printf("\\U%08x", c); + continue; + } + break; + } + buf.writeByte('"'); + if (postfix) + buf.writeByte('"'); + buf.writeByte(0); + p = (char *)buf.extractData(); + } +#endif + break; + + case TOKidentifier: + case TOKenum: + case TOKstruct: + case TOKimport: + case BASIC_TYPES: + p = ident->toChars(); + break; + + default: + p = toChars(value); + break; + } + return p; +} + +const char *Token::toChars(enum TOK value) +{ const char *p; + static char buffer[3 + 3 * sizeof(value) + 1]; + + p = tochars[value]; + if (!p) + { sprintf(buffer,"TOK%d",value); + p = buffer; + } + return p; +} + +/*************************** Lexer ********************************************/ + +Token *Lexer::freelist = NULL; +StringTable Lexer::stringtable; +OutBuffer Lexer::stringbuffer; + +Lexer::Lexer(Module *mod, + unsigned char *base, unsigned begoffset, unsigned endoffset, + int doDocComment, int commentToken) + : loc(mod, 1) +{ + //printf("Lexer::Lexer(%p,%d)\n",base,length); + //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); + memset(&token,0,sizeof(token)); + this->base = base; + this->end = base + endoffset; + p = base + begoffset; + this->mod = mod; + this->doDocComment = doDocComment; + this->anyToken = 0; + this->commentToken = commentToken; + //initKeywords(); + + /* If first line starts with '#!', ignore the line + */ + + if (p[0] == '#' && p[1] =='!') + { + p += 2; + while (1) + { unsigned char c = *p; + switch (c) + { + case '\n': + p++; + break; + + case '\r': + p++; + if (*p == '\n') + p++; + break; + + case 0: + case 0x1A: + break; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + break; + } + p++; + continue; + } + break; + } + loc.linnum = 2; + } +} + + +void Lexer::error(const char *format, ...) +{ + if (mod && !global.gag) + { + char *p = loc.toChars(); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); + } + global.errors++; +} + +void Lexer::error(Loc loc, const char *format, ...) +{ + if (mod && !global.gag) + { + char *p = loc.toChars(); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); + + va_list ap; + va_start(ap, format); + vfprintf(stdmsg, format, ap); + va_end(ap); + + fprintf(stdmsg, "\n"); + fflush(stdmsg); + + if (global.errors >= 20) // moderate blizzard of cascading messages + fatal(); + } + global.errors++; +} + +TOK Lexer::nextToken() +{ Token *t; + + if (token.next) + { + t = token.next; + memcpy(&token,t,sizeof(Token)); + t->next = freelist; + freelist = t; + } + else + { + scan(&token); + } + //token.print(); + return token.value; +} + +Token *Lexer::peek(Token *ct) +{ Token *t; + + if (ct->next) + t = ct->next; + else + { + t = new Token(); + scan(t); + t->next = NULL; + ct->next = t; + } + return t; +} + +/*********************** + * Look ahead at next token's value. + */ + +TOK Lexer::peekNext() +{ + return peek(&token)->value; +} + +/*********************** + * Look 2 tokens ahead at value. + */ + +TOK Lexer::peekNext2() +{ + Token *t = peek(&token); + return peek(t)->value; +} + +/********************************* + * tk is on the opening (. + * Look ahead and return token that is past the closing ). + */ + +Token *Lexer::peekPastParen(Token *tk) +{ + //printf("peekPastParen()\n"); + int parens = 1; + int curlynest = 0; + while (1) + { + tk = peek(tk); + //tk->print(); + switch (tk->value) + { + case TOKlparen: + parens++; + continue; + + case TOKrparen: + --parens; + if (parens) + continue; + tk = peek(tk); + break; + + case TOKlcurly: + curlynest++; + continue; + + case TOKrcurly: + if (--curlynest >= 0) + continue; + break; + + case TOKsemicolon: + if (curlynest) + continue; + break; + + case TOKeof: + break; + + default: + continue; + } + return tk; + } +} + +/********************************** + * Determine if string is a valid Identifier. + * Placed here because of commonality with Lexer functionality. + * Returns: + * 0 invalid + */ + +int Lexer::isValidIdentifier(char *p) +{ + size_t len; + size_t idx; + + if (!p || !*p) + goto Linvalid; + + if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars + goto Linvalid; + + len = strlen(p); + idx = 0; + while (p[idx]) + { dchar_t dc; + + const char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc); + if (q) + goto Linvalid; + + if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) + goto Linvalid; + } + return 1; + +Linvalid: + return 0; +} + +/**************************** + * Turn next token in buffer into a token. + */ + +void Lexer::scan(Token *t) +{ + unsigned lastLine = loc.linnum; + unsigned linnum; + + t->blockComment = NULL; + t->lineComment = NULL; + while (1) + { + t->ptr = p; + //printf("p = %p, *p = '%c'\n",p,*p); + switch (*p) + { + case 0: + case 0x1A: + t->value = TOKeof; // end of file + return; + + case ' ': + case '\t': + case '\v': + case '\f': + p++; + continue; // skip white space + + case '\r': + p++; + if (*p != '\n') // if CR stands by itself + loc.linnum++; + continue; // skip white space + + case '\n': + p++; + loc.linnum++; + continue; // skip white space + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + t->value = number(t); + return; + +#if CSTRINGS + case '\'': + t->value = charConstant(t, 0); + return; + + case '"': + t->value = stringConstant(t,0); + return; + + case 'l': + case 'L': + if (p[1] == '\'') + { + p++; + t->value = charConstant(t, 1); + return; + } + else if (p[1] == '"') + { + p++; + t->value = stringConstant(t, 1); + return; + } +#else + case '\'': + t->value = charConstant(t,0); + return; + + case 'r': + if (p[1] != '"') + goto case_ident; + p++; + case '`': + t->value = wysiwygStringConstant(t, *p); + return; + + case 'x': + if (p[1] != '"') + goto case_ident; + p++; + t->value = hexStringConstant(t); + return; + +#if DMDV2 + case 'q': + if (p[1] == '"') + { + p++; + t->value = delimitedStringConstant(t); + return; + } + else if (p[1] == '{') + { + p++; + t->value = tokenStringConstant(t); + return; + } + else + goto case_ident; +#endif + + case '"': + t->value = escapeStringConstant(t,0); + return; + +#if ! TEXTUAL_ASSEMBLY_OUT + case '\\': // escaped string literal + { unsigned c; + unsigned char *pstart = p; + + stringbuffer.reset(); + do + { + p++; + switch (*p) + { + case 'u': + case 'U': + case '&': + c = escapeSequence(); + stringbuffer.writeUTF8(c); + break; + + default: + c = escapeSequence(); + stringbuffer.writeByte(c); + break; + } + } while (*p == '\\'); + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + t->postfix = 0; + t->value = TOKstring; +#if DMDV2 + if (!global.params.useDeprecated) + error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", (int)(p - pstart), pstart, (int)(p - pstart), pstart); +#endif + return; + } +#endif + + case 'l': + case 'L': +#endif + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'm': case 'n': case 'o': +#if DMDV2 + case 'p': /*case 'q': case 'r':*/ case 's': case 't': +#else + case 'p': case 'q': /*case 'r':*/ case 's': case 't': +#endif + case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '_': + case_ident: + { unsigned char c; + + while (1) + { + c = *++p; + if (isidchar(c)) + continue; + else if (c & 0x80) + { unsigned char *s = p; + unsigned u = decodeUTF(); + if (isUniAlpha(u)) + continue; + error("char 0x%04x not allowed in identifier", u); + p = s; + } + break; + } + + StringValue *sv = stringtable.update((char *)t->ptr, p - t->ptr); + Identifier *id = (Identifier *) sv->ptrvalue; + if (!id) + { id = new Identifier(sv->lstring.string,TOKidentifier); + sv->ptrvalue = id; + } + t->ident = id; + t->value = (enum TOK) id->value; + anyToken = 1; + if (*t->ptr == '_') // if special identifier token + { + static char date[11+1]; + static char time[8+1]; + static char timestamp[24+1]; + + if (!date[0]) // lazy evaluation + { time_t t; + char *p; + + ::time(&t); + p = ctime(&t); + assert(p); + sprintf(date, "%.6s %.4s", p + 4, p + 20); + sprintf(time, "%.8s", p + 11); + sprintf(timestamp, "%.24s", p); + } + +#if DMDV1 + if (mod && id == Id::FILE) + { + t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); + goto Lstr; + } + else if (mod && id == Id::LINE) + { + t->value = TOKint64v; + t->uns64value = loc.linnum; + } + else +#endif + if (id == Id::DATE) + { + t->ustring = (unsigned char *)date; + goto Lstr; + } + else if (id == Id::TIME) + { + t->ustring = (unsigned char *)time; + goto Lstr; + } + else if (id == Id::VENDOR) + { + t->ustring = (unsigned char *)"LDC"; + goto Lstr; + } + else if (id == Id::TIMESTAMP) + { + t->ustring = (unsigned char *)timestamp; + Lstr: + t->value = TOKstring; + Llen: + t->postfix = 0; + t->len = strlen((char *)t->ustring); + } + else if (id == Id::VERSIONX) + { unsigned major = 0; + unsigned minor = 0; + + for (const char *p = global.version + 1; 1; p++) + { + char c = *p; + if (isdigit(c)) + minor = minor * 10 + c - '0'; + else if (c == '.') + { major = minor; + minor = 0; + } + else + break; + } + t->value = TOKint64v; + t->uns64value = major * 1000 + minor; + } +#if DMDV2 + else if (id == Id::EOFX) + { + t->value = TOKeof; + // Advance scanner to end of file + while (!(*p == 0 || *p == 0x1A)) + p++; + } +#endif + } + //printf("t->value = %d\n",t->value); + return; + } + + case '/': + p++; + switch (*p) + { + case '=': + p++; + t->value = TOKdivass; + return; + + case '*': + p++; + linnum = loc.linnum; + while (1) + { + while (1) + { unsigned char c = *p; + switch (c) + { + case '/': + break; + + case '\n': + loc.linnum++; + p++; + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case 0: + case 0x1A: + error("unterminated /* */ comment"); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + p++; + if (p[-2] == '*' && p - 3 != t->ptr) + break; + } + if (commentToken) + { + t->value = TOKcomment; + return; + } + else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) + { // if /** but not /**/ + getDocComment(t, lastLine == linnum); + } + continue; + + case '/': // do // style comments + linnum = loc.linnum; + while (1) + { unsigned char c = *++p; + switch (c) + { + case '\n': + break; + + case '\r': + if (p[1] == '\n') + p++; + break; + + case 0: + case 0x1A: + if (commentToken) + { + p = end; + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '/') + getDocComment(t, lastLine == linnum); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + break; + } + continue; + } + break; + } + + if (commentToken) + { + p++; + loc.linnum++; + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '/') + getDocComment(t, lastLine == linnum); + + p++; + loc.linnum++; + continue; + + case '+': + { int nest; + + linnum = loc.linnum; + p++; + nest = 1; + while (1) + { unsigned char c = *p; + switch (c) + { + case '/': + p++; + if (*p == '+') + { + p++; + nest++; + } + continue; + + case '+': + p++; + if (*p == '/') + { + p++; + if (--nest == 0) + break; + } + continue; + + case '\r': + p++; + if (*p != '\n') + loc.linnum++; + continue; + + case '\n': + loc.linnum++; + p++; + continue; + + case 0: + case 0x1A: + error("unterminated /+ +/ comment"); + p = end; + t->value = TOKeof; + return; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + loc.linnum++; + } + p++; + continue; + } + break; + } + if (commentToken) + { + t->value = TOKcomment; + return; + } + if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) + { // if /++ but not /++/ + getDocComment(t, lastLine == linnum); + } + continue; + } + } + t->value = TOKdiv; + return; + + case '.': + p++; + if (isdigit(*p)) + { /* Note that we don't allow ._1 and ._ as being + * valid floating point numbers. + */ + p--; + t->value = inreal(t); + } + else if (p[0] == '.') + { + if (p[1] == '.') + { p += 2; + t->value = TOKdotdotdot; + } + else + { p++; + t->value = TOKslice; + } + } + else + t->value = TOKdot; + return; + + case '&': + p++; + if (*p == '=') + { p++; + t->value = TOKandass; + } + else if (*p == '&') + { p++; + t->value = TOKandand; + } + else + t->value = TOKand; + return; + + case '|': + p++; + if (*p == '=') + { p++; + t->value = TOKorass; + } + else if (*p == '|') + { p++; + t->value = TOKoror; + } + else + t->value = TOKor; + return; + + case '-': + p++; + if (*p == '=') + { p++; + t->value = TOKminass; + } +#if 0 + else if (*p == '>') + { p++; + t->value = TOKarrow; + } +#endif + else if (*p == '-') + { p++; + t->value = TOKminusminus; + } + else + t->value = TOKmin; + return; + + case '+': + p++; + if (*p == '=') + { p++; + t->value = TOKaddass; + } + else if (*p == '+') + { p++; + t->value = TOKplusplus; + } + else + t->value = TOKadd; + return; + + case '<': + p++; + if (*p == '=') + { p++; + t->value = TOKle; // <= + } + else if (*p == '<') + { p++; + if (*p == '=') + { p++; + t->value = TOKshlass; // <<= + } + else + t->value = TOKshl; // << + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKleg; // <>= + } + else + t->value = TOKlg; // <> + } + else + t->value = TOKlt; // < + return; + + case '>': + p++; + if (*p == '=') + { p++; + t->value = TOKge; // >= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKshrass; // >>= + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKushrass; // >>>= + } + else + t->value = TOKushr; // >>> + } + else + t->value = TOKshr; // >> + } + else + t->value = TOKgt; // > + return; + + case '!': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t->value = TOKnotidentity; // !== + } + else + t->value = TOKnotequal; // != + } + else if (*p == '<') + { p++; + if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKunord; // !<>= + } + else + t->value = TOKue; // !<> + } + else if (*p == '=') + { p++; + t->value = TOKug; // !<= + } + else + t->value = TOKuge; // !< + } + else if (*p == '>') + { p++; + if (*p == '=') + { p++; + t->value = TOKul; // !>= + } + else + t->value = TOKule; // !> + } + else + t->value = TOKnot; // ! + return; + + case '=': + p++; + if (*p == '=') + { p++; + if (*p == '=' && global.params.Dversion == 1) + { p++; + t->value = TOKidentity; // === + } + else + t->value = TOKequal; // == + } + else + t->value = TOKassign; // = + return; + + case '~': + p++; + if (*p == '=') + { p++; + t->value = TOKcatass; // ~= + } + else + t->value = TOKtilde; // ~ + return; + +#if DMDV2 + case '^': + p++; + if (*p == '^') + { p++; + if (*p == '=') + { p++; + t->value = TOKpowass; // ^^= + } + else + t->value = TOKpow; // ^^ + } + else if (*p == '=') + { p++; + t->value = TOKxorass; // ^= + } + else + t->value = TOKxor; // ^ + return; +#endif + +#define SINGLE(c,tok) case c: p++; t->value = tok; return; + + SINGLE('(', TOKlparen) + SINGLE(')', TOKrparen) + SINGLE('[', TOKlbracket) + SINGLE(']', TOKrbracket) + SINGLE('{', TOKlcurly) + SINGLE('}', TOKrcurly) + SINGLE('?', TOKquestion) + SINGLE(',', TOKcomma) + SINGLE(';', TOKsemicolon) + SINGLE(':', TOKcolon) + SINGLE('$', TOKdollar) +#if DMDV2 + SINGLE('@', TOKat) +#endif +#undef SINGLE + +#define DOUBLE(c1,tok1,c2,tok2) \ + case c1: \ + p++; \ + if (*p == c2) \ + { p++; \ + t->value = tok2; \ + } \ + else \ + t->value = tok1; \ + return; + + DOUBLE('*', TOKmul, '=', TOKmulass) + DOUBLE('%', TOKmod, '=', TOKmodass) +#if DMDV1 + DOUBLE('^', TOKxor, '=', TOKxorass) +#endif +#undef DOUBLE + + case '#': + p++; + pragma(); + continue; + + default: + { unsigned c = *p; + + if (c & 0x80) + { c = decodeUTF(); + + // Check for start of unicode identifier + if (isUniAlpha(c)) + goto case_ident; + + if (c == PS || c == LS) + { + loc.linnum++; + p++; + continue; + } + } + if (c < 0x80 && isprint(c)) + error("unsupported char '%c'", c); + else + error("unsupported char 0x%02x", c); + p++; + continue; + } + } + } +} + +/******************************************* + * Parse escape sequence. + */ + +unsigned Lexer::escapeSequence() +{ unsigned c = *p; + +#ifdef TEXTUAL_ASSEMBLY_OUT + return c; +#endif + int n; + int ndigits; + + switch (c) + { + case '\'': + case '"': + case '?': + case '\\': + Lconsume: + p++; + break; + + case 'a': c = 7; goto Lconsume; + case 'b': c = 8; goto Lconsume; + case 'f': c = 12; goto Lconsume; + case 'n': c = 10; goto Lconsume; + case 'r': c = 13; goto Lconsume; + case 't': c = 9; goto Lconsume; + case 'v': c = 11; goto Lconsume; + + case 'u': + ndigits = 4; + goto Lhex; + case 'U': + ndigits = 8; + goto Lhex; + case 'x': + ndigits = 2; + Lhex: + p++; + c = *p; + if (ishex(c)) + { unsigned v; + + n = 0; + v = 0; + while (1) + { + if (isdigit(c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + v = v * 16 + c; + c = *++p; + if (++n == ndigits) + break; + if (!ishex(c)) + { error("escape hex sequence has %d hex digits instead of %d", n, ndigits); + break; + } + } + if (ndigits != 2 && !utf_isValidDchar(v)) + { error("invalid UTF character \\U%08x", v); + v = '?'; // recover with valid UTF character + } + c = v; + } + else + error("undefined escape hex sequence \\%c\n",c); + break; + + case '&': // named character entity + for (unsigned char *idstart = ++p; 1; p++) + { + switch (*p) + { + case ';': + c = HtmlNamedEntity(idstart, p - idstart); + if (c == ~0) + { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart); + c = ' '; + } + p++; + break; + + default: + if (isalpha(*p) || + (p != idstart + 1 && isdigit(*p))) + continue; + error("unterminated named entity"); + break; + } + break; + } + break; + + case 0: + case 0x1A: // end of file + c = '\\'; + break; + + default: + if (isoctal(c)) + { unsigned v; + + n = 0; + v = 0; + do + { + v = v * 8 + (c - '0'); + c = *++p; + } while (++n < 3 && isoctal(c)); + c = v; + if (c > 0xFF) + error("0%03o is larger than a byte", c); + } + else + error("undefined escape sequence \\%c\n",c); + break; + } + return c; +} + +/************************************** + */ + +TOK Lexer::wysiwygStringConstant(Token *t, int tc) +{ unsigned c; + Loc start = loc; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + switch (c) + { + case '\n': + loc.linnum++; + break; + + case '\r': + if (*p == '\n') + continue; // ignore + c = '\n'; // treat EndOfLine as \n character + loc.linnum++; + break; + + case 0: + case 0x1A: + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; + + case '"': + case '`': + if (c == tc) + { + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + } + break; + + default: + if (c & 0x80) + { p--; + unsigned u = decodeUTF(); + p++; + if (u == PS || u == LS) + loc.linnum++; + stringbuffer.writeUTF8(u); + continue; + } + break; + } + stringbuffer.writeByte(c); + } +} + +/************************************** + * Lex hex strings: + * x"0A ae 34FE BD" + */ + +TOK Lexer::hexStringConstant(Token *t) +{ unsigned c; + Loc start = loc; + unsigned n = 0; + unsigned v; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + switch (c) + { + case ' ': + case '\t': + case '\v': + case '\f': + continue; // skip white space + + case '\r': + if (*p == '\n') + continue; // ignore + // Treat isolated '\r' as if it were a '\n' + case '\n': + loc.linnum++; + continue; + + case 0: + case 0x1A: + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; + + case '"': + if (n & 1) + { error("odd number (%d) of hex characters in hex string", n); + stringbuffer.writeByte(v); + } + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + + default: + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else if (c & 0x80) + { p--; + unsigned u = decodeUTF(); + p++; + if (u == PS || u == LS) + loc.linnum++; + else + error("non-hex character \\u%04x", u); + } + else + error("non-hex character '%c'", c); + if (n & 1) + { v = (v << 4) | c; + stringbuffer.writeByte(v); + } + else + v = c; + n++; + break; + } + } +} + + +#if DMDV2 +/************************************** + * Lex delimited strings: + * q"(foo(xxx))" // "foo(xxx)" + * q"[foo(]" // "foo(" + * q"/foo]/" // "foo]" + * q"HERE + * foo + * HERE" // "foo\n" + * Input: + * p is on the " + */ + +TOK Lexer::delimitedStringConstant(Token *t) +{ unsigned c; + Loc start = loc; + unsigned delimleft = 0; + unsigned delimright = 0; + unsigned nest = 1; + unsigned nestcount; + Identifier *hereid = NULL; + unsigned blankrol = 0; + unsigned startline = 0; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + //printf("c = '%c'\n", c); + switch (c) + { + case '\n': + Lnextline: + loc.linnum++; + startline = 1; + if (blankrol) + { blankrol = 0; + continue; + } + if (hereid) + { + stringbuffer.writeUTF8(c); + continue; + } + break; + + case '\r': + if (*p == '\n') + continue; // ignore + c = '\n'; // treat EndOfLine as \n character + goto Lnextline; + + case 0: + case 0x1A: + goto Lerror; + + default: + if (c & 0x80) + { p--; + c = decodeUTF(); + p++; + if (c == PS || c == LS) + goto Lnextline; + } + break; + } + if (delimleft == 0) + { delimleft = c; + nest = 1; + nestcount = 1; + if (c == '(') + delimright = ')'; + else if (c == '{') + delimright = '}'; + else if (c == '[') + delimright = ']'; + else if (c == '<') + delimright = '>'; + else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) + { // Start of identifier; must be a heredoc + Token t; + p--; + scan(&t); // read in heredoc identifier + if (t.value != TOKidentifier) + { error("identifier expected for heredoc, not %s", t.toChars()); + delimright = c; + } + else + { hereid = t.ident; + //printf("hereid = '%s'\n", hereid->toChars()); + blankrol = 1; + } + nest = 0; + } + else + { delimright = c; + nest = 0; +#if DMDV2 + if (isspace(c)) + error("delimiter cannot be whitespace"); +#endif + } + } + else + { + if (blankrol) + { error("heredoc rest of line should be blank"); + blankrol = 0; + continue; + } + if (nest == 1) + { + if (c == delimleft) + nestcount++; + else if (c == delimright) + { nestcount--; + if (nestcount == 0) + goto Ldone; + } + } + else if (c == delimright) + goto Ldone; + if (startline && isalpha(c) +#if DMDV2 + && hereid +#endif + ) + { Token t; + unsigned char *psave = p; + p--; + scan(&t); // read in possible heredoc identifier + //printf("endid = '%s'\n", t.ident->toChars()); + if (t.value == TOKidentifier && t.ident->equals(hereid)) + { /* should check that rest of line is blank + */ + goto Ldone; + } + p = psave; + } + stringbuffer.writeUTF8(c); + startline = 0; + } + } + +Ldone: + if (*p == '"') + p++; + else + error("delimited string must end in %c\"", delimright); + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + +Lerror: + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; +} + +/************************************** + * Lex delimited strings: + * q{ foo(xxx) } // " foo(xxx) " + * q{foo(} // "foo(" + * q{{foo}"}"} // "{foo}"}"" + * Input: + * p is on the q + */ + +TOK Lexer::tokenStringConstant(Token *t) +{ + unsigned nest = 1; + Loc start = loc; + unsigned char *pstart = ++p; + + while (1) + { Token tok; + + scan(&tok); + switch (tok.value) + { + case TOKlcurly: + nest++; + continue; + + case TOKrcurly: + if (--nest == 0) + goto Ldone; + continue; + + case TOKeof: + goto Lerror; + + default: + continue; + } + } + +Ldone: + t->len = p - 1 - pstart; + t->ustring = (unsigned char *)mem.malloc(t->len + 1); + memcpy(t->ustring, pstart, t->len); + t->ustring[t->len] = 0; + stringPostfix(t); + return TOKstring; + +Lerror: + error("unterminated token string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; +} + +#endif + + +/************************************** + */ + +TOK Lexer::escapeStringConstant(Token *t, int wide) +{ unsigned c; + Loc start = loc; + + p++; + stringbuffer.reset(); + while (1) + { + c = *p++; + switch (c) + { +#if !( TEXTUAL_ASSEMBLY_OUT ) + case '\\': + switch (*p) + { + case 'u': + case 'U': + case '&': + c = escapeSequence(); + stringbuffer.writeUTF8(c); + continue; + + default: + c = escapeSequence(); + break; + } + break; +#endif + case '\n': + loc.linnum++; + break; + + case '\r': + if (*p == '\n') + continue; // ignore + c = '\n'; // treat EndOfLine as \n character + loc.linnum++; + break; + + case '"': + t->len = stringbuffer.offset; + stringbuffer.writeByte(0); + t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); + memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); + stringPostfix(t); + return TOKstring; + + case 0: + case 0x1A: + p--; + error("unterminated string constant starting at %s", start.toChars()); + t->ustring = (unsigned char *)""; + t->len = 0; + t->postfix = 0; + return TOKstring; + + default: + if (c & 0x80) + { + p--; + c = decodeUTF(); + if (c == LS || c == PS) + { c = '\n'; + loc.linnum++; + } + p++; + stringbuffer.writeUTF8(c); + continue; + } + break; + } + stringbuffer.writeByte(c); + } +} + +/************************************** + */ + +TOK Lexer::charConstant(Token *t, int wide) +{ + unsigned c; + TOK tk = TOKcharv; + + //printf("Lexer::charConstant\n"); + p++; + c = *p++; + switch (c) + { +#if ! TEXTUAL_ASSEMBLY_OUT + case '\\': + switch (*p) + { + case 'u': + t->uns64value = escapeSequence(); + tk = TOKwcharv; + break; + + case 'U': + case '&': + t->uns64value = escapeSequence(); + tk = TOKdcharv; + break; + + default: + t->uns64value = escapeSequence(); + break; + } + break; +#endif + case '\n': + L1: + loc.linnum++; + case '\r': + case 0: + case 0x1A: + case '\'': + error("unterminated character constant"); + return tk; + + default: + if (c & 0x80) + { + p--; + c = decodeUTF(); + p++; + if (c == LS || c == PS) + goto L1; + if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) + tk = TOKwcharv; + else + tk = TOKdcharv; + } + t->uns64value = c; + break; + } + + if (*p != '\'') + { error("unterminated character constant"); + return tk; + } + p++; + return tk; +} + +/*************************************** + * Get postfix of string literal. + */ + +void Lexer::stringPostfix(Token *t) +{ + switch (*p) + { + case 'c': + case 'w': + case 'd': + t->postfix = *p; + p++; + break; + + default: + t->postfix = 0; + break; + } +} + +/*************************************** + * Read \u or \U unicode sequence + * Input: + * u 'u' or 'U' + */ + +#if 0 +unsigned Lexer::wchar(unsigned u) +{ + unsigned value; + unsigned n; + unsigned char c; + unsigned nchars; + + nchars = (u == 'U') ? 8 : 4; + value = 0; + for (n = 0; 1; n++) + { + ++p; + if (n == nchars) + break; + c = *p; + if (!ishex(c)) + { error("\\%c sequence must be followed by %d hex characters", u, nchars); + break; + } + if (isdigit(c)) + c -= '0'; + else if (islower(c)) + c -= 'a' - 10; + else + c -= 'A' - 10; + value <<= 4; + value |= c; + } + return value; +} +#endif + +/************************************** + * Read in a number. + * If it's an integer, store it in tok.TKutok.Vlong. + * integers can be decimal, octal or hex + * Handle the suffixes U, UL, LU, L, etc. + * If it's double, store it in tok.TKutok.Vdouble. + * Returns: + * TKnum + * TKdouble,... + */ + +TOK Lexer::number(Token *t) +{ + // We use a state machine to collect numbers + enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, + STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, + STATE_hexh, STATE_error }; + enum STATE state; + + enum FLAGS + { FLAGS_decimal = 1, // decimal + FLAGS_unsigned = 2, // u or U suffix + FLAGS_long = 4, // l or L suffix + }; + enum FLAGS flags = FLAGS_decimal; + + int i; + int base; + unsigned c; + unsigned char *start; + TOK result; + + //printf("Lexer::number()\n"); + state = STATE_initial; + base = 0; + stringbuffer.reset(); + start = p; + while (1) + { + c = *p; + switch (state) + { + case STATE_initial: // opening state + if (c == '0') + state = STATE_0; + else + state = STATE_decimal; + break; + + case STATE_0: + flags = (FLAGS) (flags & ~FLAGS_decimal); + switch (c) + { +#if ZEROH + case 'H': // 0h + case 'h': + goto hexh; +#endif + case 'X': + case 'x': + state = STATE_hex0; + break; + + case '.': + if (p[1] == '.') // .. is a separate token + goto done; + case 'i': + case 'f': + case 'F': + goto real; +#if ZEROH + case 'E': + case 'e': + goto case_hex; +#endif + case 'B': + case 'b': + state = STATE_binary0; + break; + + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + state = STATE_octal; + break; + +#if ZEROH + case '8': case '9': case 'A': + case 'C': case 'D': case 'F': + case 'a': case 'c': case 'd': case 'f': + case_hex: + state = STATE_hexh; + break; +#endif + case '_': + state = STATE_octal; + p++; + continue; + + case 'L': + if (p[1] == 'i') + goto real; + goto done; + + default: + goto done; + } + break; + + case STATE_decimal: // reading decimal number + if (!isdigit(c)) + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + else if (c == 'i' || c == 'f' || c == 'F' || + c == 'e' || c == 'E') + { + real: // It's a real number. Back up and rescan as a real + p = start; + return inreal(t); + } + else if (c == 'L' && p[1] == 'i') + goto real; + goto done; + } + break; + + case STATE_hex0: // reading hex number + case STATE_hex: + if (!ishex(c)) + { + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + if (c == 'P' || c == 'p' || c == 'i') + goto real; + if (state == STATE_hex0) + error("Hex digit expected, not '%c'", c); + goto done; + } + state = STATE_hex; + break; + +#if ZEROH + hexh: + state = STATE_hexh; + case STATE_hexh: // parse numbers like 0FFh + if (!ishex(c)) + { + if (c == 'H' || c == 'h') + { + p++; + base = 16; + goto done; + } + else + { + // Check for something like 1E3 or 0E24 + if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || + memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) + goto real; + error("Hex digit expected, not '%c'", c); + goto done; + } + } + break; +#endif + + case STATE_octal: // reading octal number + case STATE_octale: // reading octal number with non-octal digits + if (!isoctal(c)) + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (c == '.' && p[1] != '.') + goto real; + if (c == 'i') + goto real; + if (isdigit(c)) + { + state = STATE_octale; + } + else + goto done; + } + break; + + case STATE_binary0: // starting binary number + case STATE_binary: // reading binary number + if (c != '0' && c != '1') + { +#if ZEROH + if (ishex(c) + || c == 'H' || c == 'h' + ) + goto hexh; +#endif + if (c == '_') // ignore embedded _ + { p++; + continue; + } + if (state == STATE_binary0) + { error("binary digit expected"); + state = STATE_error; + break; + } + else + goto done; + } + state = STATE_binary; + break; + + case STATE_error: // for error recovery + if (!isdigit(c)) // scan until non-digit + goto done; + break; + + default: + assert(0); + } + stringbuffer.writeByte(c); + p++; + } +done: + stringbuffer.writeByte(0); // terminate string + if (state == STATE_octale) + error("Octal digit expected"); + + uinteger_t n; // unsigned >=64 bit integer type + + if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) + n = stringbuffer.data[0] - '0'; + else + { + // Convert string to integer +#if __DMC__ + errno = 0; + n = strtoull((char *)stringbuffer.data,NULL,base); + if (errno == ERANGE) + error("integer overflow"); +#else + // Not everybody implements strtoull() + char *p = (char *)stringbuffer.data; + int r = 10, d; + + if (*p == '0') + { + if (p[1] == 'x' || p[1] == 'X') + p += 2, r = 16; + else if (p[1] == 'b' || p[1] == 'B') + p += 2, r = 2; + else if (isdigit(p[1])) + p += 1, r = 8; + } + + n = 0; + while (1) + { + if (*p >= '0' && *p <= '9') + d = *p - '0'; + else if (*p >= 'a' && *p <= 'z') + d = *p - 'a' + 10; + else if (*p >= 'A' && *p <= 'Z') + d = *p - 'A' + 10; + else + break; + if (d >= r) + break; + uinteger_t n2 = n * r; + //printf("n2 / r = %llx, n = %llx\n", n2/r, n); + if (n2 / r != n || n2 + d < n) + { + error ("integer overflow"); + break; + } + + n = n2 + d; + p++; + } +#endif + if (sizeof(n) > 8 && + n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits + error("integer overflow"); + } + + // Parse trailing 'u', 'U', 'l' or 'L' in any combination + while (1) + { unsigned char f; + + switch (*p) + { case 'U': + case 'u': + f = FLAGS_unsigned; + goto L1; + + case 'l': + if (1 || !global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + f = FLAGS_long; + L1: + p++; + if (flags & f) + error("unrecognized token"); + flags = (FLAGS) (flags | f); + continue; + default: + break; + } + break; + } + + switch (flags) + { + case 0: + /* Octal or Hexadecimal constant. + * First that fits: int, uint, long, ulong + */ + if (n & 0x8000000000000000LL) + result = TOKuns64v; + else if (n & 0xFFFFFFFF00000000LL) + result = TOKint64v; + else if (n & 0x80000000) + result = TOKuns32v; + else + result = TOKint32v; + break; + + case FLAGS_decimal: + /* First that fits: int, long, long long + */ + if (n & 0x8000000000000000LL) + { error("signed integer overflow"); + result = TOKuns64v; + } + else if (n & 0xFFFFFFFF80000000LL) + result = TOKint64v; + else + result = TOKint32v; + break; + + case FLAGS_unsigned: + case FLAGS_decimal | FLAGS_unsigned: + /* First that fits: uint, ulong + */ + if (n & 0xFFFFFFFF00000000LL) + result = TOKuns64v; + else + result = TOKuns32v; + break; + + case FLAGS_decimal | FLAGS_long: + if (n & 0x8000000000000000LL) + { error("signed integer overflow"); + result = TOKuns64v; + } + else + result = TOKint64v; + break; + + case FLAGS_long: + if (n & 0x8000000000000000LL) + result = TOKuns64v; + else + result = TOKint64v; + break; + + case FLAGS_unsigned | FLAGS_long: + case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: + result = TOKuns64v; + break; + + default: + #ifdef DEBUG + printf("%x\n",flags); + #endif + assert(0); + } + t->uns64value = n; + return result; +} + +/************************************** + * Read in characters, converting them to real. + * Bugs: + * Exponent overflow not detected. + * Too much requested precision is not detected. + */ + +TOK Lexer::inreal(Token *t) +#ifdef __DMC__ +__in +{ + assert(*p == '.' || isdigit(*p)); +} +__out (result) +{ + switch (result) + { + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + break; + + default: + assert(0); + } +} +__body +#endif /* __DMC__ */ +{ int dblstate; + unsigned c; + char hex; // is this a hexadecimal-floating-constant? + TOK result; + + //printf("Lexer::inreal()\n"); + stringbuffer.reset(); + dblstate = 0; + hex = 0; +Lnext: + while (1) + { + // Get next char from input + c = *p++; + //printf("dblstate = %d, c = '%c'\n", dblstate, c); + while (1) + { + switch (dblstate) + { + case 0: // opening state + if (c == '0') + dblstate = 9; + else if (c == '.') + dblstate = 3; + else + dblstate = 1; + break; + + case 9: + dblstate = 1; + if (c == 'X' || c == 'x') + { hex++; + break; + } + case 1: // digits to left of . + case 3: // digits to right of . + case 7: // continuing exponent digits + if (!isdigit(c) && !(hex && isxdigit(c))) + { + if (c == '_') + goto Lnext; // ignore embedded '_' + dblstate++; + continue; + } + break; + + case 2: // no more digits to left of . + if (c == '.') + { dblstate++; + break; + } + case 4: // no more digits to right of . + if ((c == 'E' || c == 'e') || + hex && (c == 'P' || c == 'p')) + { dblstate = 5; + hex = 0; // exponent is always decimal + break; + } + if (hex) + error("binary-exponent-part required"); + goto done; + + case 5: // looking immediately to right of E + dblstate++; + if (c == '-' || c == '+') + break; + case 6: // 1st exponent digit expected + if (!isdigit(c)) + error("exponent expected"); + dblstate++; + break; + + case 8: // past end of exponent digits + goto done; + } + break; + } + stringbuffer.writeByte(c); + } +done: + p--; + + stringbuffer.writeByte(0); + +#if _WIN32 && __DMC__ + char *save = __locale_decpoint; + __locale_decpoint = "."; +#endif +#ifdef IN_GCC + t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); +#else + t->float80value = strtold((char *)stringbuffer.data, NULL); +#endif + errno = 0; + float strtofres; + double strtodres; + switch (*p) + { + case 'F': + case 'f': +#ifdef IN_GCC + real_t::parse((char *)stringbuffer.data, real_t::Float); +#else + strtofres = strtof((char *)stringbuffer.data, NULL); + // LDC change: don't error on gradual underflow + if (errno == ERANGE && + strtofres != 0 && strtofres != HUGE_VALF && strtofres != -HUGE_VALF) + errno = 0; +#endif + result = TOKfloat32v; + p++; + break; + + default: +#ifdef IN_GCC + real_t::parse((char *)stringbuffer.data, real_t::Double); +#else + strtodres = strtod((char *)stringbuffer.data, NULL); + // LDC change: don't error on gradual underflow + if (errno == ERANGE && + strtodres != 0 && strtodres != HUGE_VAL && strtodres != -HUGE_VAL) + errno = 0; +#endif + result = TOKfloat64v; + break; + + case 'l': + if (!global.params.useDeprecated) + error("'l' suffix is deprecated, use 'L' instead"); + case 'L': + result = TOKfloat80v; + p++; + break; + } + if (*p == 'i' || *p == 'I') + { + if (!global.params.useDeprecated && *p == 'I') + error("'I' suffix is deprecated, use 'i' instead"); + p++; + switch (result) + { + case TOKfloat32v: + result = TOKimaginary32v; + break; + case TOKfloat64v: + result = TOKimaginary64v; + break; + case TOKfloat80v: + result = TOKimaginary80v; + break; + } + } +#if _WIN32 && __DMC__ + __locale_decpoint = save; +#endif + if (errno == ERANGE) + error("number is not representable"); + return result; +} + +/********************************************* + * Do pragma. + * Currently, the only pragma supported is: + * #line linnum [filespec] + */ + +void Lexer::pragma() +{ + Token tok; + int linnum; + char *filespec = NULL; + Loc loc = this->loc; + + scan(&tok); + if (tok.value != TOKidentifier || tok.ident != Id::line) + goto Lerr; + + scan(&tok); + if (tok.value == TOKint32v || tok.value == TOKint64v) + linnum = tok.uns64value - 1; + else + goto Lerr; + + while (1) + { + switch (*p) + { + case 0: + case 0x1A: + case '\n': + Lnewline: + this->loc.linnum = linnum; + if (filespec) + this->loc.filename = filespec; + return; + + case '\r': + p++; + if (*p != '\n') + { p--; + goto Lnewline; + } + continue; + + case ' ': + case '\t': + case '\v': + case '\f': + p++; + continue; // skip white space + + case '_': + if (mod && memcmp(p, "__FILE__", 8) == 0) + { + p += 8; + filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); + } + continue; + + case '"': + if (filespec) + goto Lerr; + stringbuffer.reset(); + p++; + while (1) + { unsigned c; + + c = *p; + switch (c) + { + case '\n': + case '\r': + case 0: + case 0x1A: + goto Lerr; + + case '"': + stringbuffer.writeByte(0); + filespec = mem.strdup((char *)stringbuffer.data); + p++; + break; + + default: + if (c & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + goto Lerr; + } + stringbuffer.writeByte(c); + p++; + continue; + } + break; + } + continue; + + default: + if (*p & 0x80) + { unsigned u = decodeUTF(); + if (u == PS || u == LS) + goto Lnewline; + } + goto Lerr; + } + } + +Lerr: + error(loc, "#line integer [\"filespec\"]\\n expected"); +} + + +/******************************************** + * Decode UTF character. + * Issue error messages for invalid sequences. + * Return decoded character, advance p to last character in UTF sequence. + */ + +unsigned Lexer::decodeUTF() +{ + dchar_t u; + unsigned char c; + unsigned char *s = p; + size_t len; + size_t idx; + const char *msg; + + c = *s; + assert(c & 0x80); + + // Check length of remaining string up to 6 UTF-8 characters + for (len = 1; len < 6 && s[len]; len++) + ; + + idx = 0; + msg = utf_decodeChar(s, len, &idx, &u); + p += idx - 1; + if (msg) + { + error("%s", msg); + } + return u; +} + + +/*************************************************** + * Parse doc comment embedded between t->ptr and p. + * Remove trailing blanks and tabs from lines. + * Replace all newlines with \n. + * Remove leading comment character from each line. + * Decide if it's a lineComment or a blockComment. + * Append to previous one for this token. + */ + +void Lexer::getDocComment(Token *t, unsigned lineComment) +{ + /* ct tells us which kind of comment it is: '/', '*', or '+' + */ + unsigned char ct = t->ptr[2]; + + /* Start of comment text skips over / * *, / + +, or / / / + */ + unsigned char *q = t->ptr + 3; // start of comment text + + unsigned char *qend = p; + if (ct == '*' || ct == '+') + qend -= 2; + + /* Scan over initial row of ****'s or ++++'s or ////'s + */ + for (; q < qend; q++) + { + if (*q != ct) + break; + } + + /* Remove trailing row of ****'s or ++++'s + */ + if (ct != '/') + { + for (; q < qend; qend--) + { + if (qend[-1] != ct) + break; + } + } + + /* Comment is now [q .. qend]. + * Canonicalize it into buf[]. + */ + OutBuffer buf; + int linestart = 0; + + for (; q < qend; q++) + { + unsigned char c = *q; + + switch (c) + { + case '*': + case '+': + if (linestart && c == ct) + { linestart = 0; + /* Trim preceding whitespace up to preceding \n + */ + while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) + buf.offset--; + continue; + } + break; + + case ' ': + case '\t': + break; + + case '\r': + if (q[1] == '\n') + continue; // skip the \r + goto Lnewline; + + default: + if (c == 226) + { + // If LS or PS + if (q[1] == 128 && + (q[2] == 168 || q[2] == 169)) + { + q += 2; + goto Lnewline; + } + } + linestart = 0; + break; + + Lnewline: + c = '\n'; // replace all newlines with \n + case '\n': + linestart = 1; + + /* Trim trailing whitespace + */ + while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) + buf.offset--; + + break; + } + buf.writeByte(c); + } + + // Always end with a newline + if (!buf.offset || buf.data[buf.offset - 1] != '\n') + buf.writeByte('\n'); + + buf.writeByte(0); + + // It's a line comment if the start of the doc comment comes + // after other non-whitespace on the same line. + unsigned char** dc = (lineComment && anyToken) + ? &t->lineComment + : &t->blockComment; + + // Combine with previous doc comment, if any + if (*dc) + *dc = combineComments(*dc, (unsigned char *)buf.data); + else + *dc = (unsigned char *)buf.extractData(); +} + +/******************************************** + * Combine two document comments into one, + * separated by a newline. + */ + +unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) +{ + //printf("Lexer::combineComments('%s', '%s')\n", c1, c2); + + unsigned char *c = c2; + + if (c1) + { c = c1; + if (c2) + { size_t len1 = strlen((char *)c1); + size_t len2 = strlen((char *)c2); + + c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1); + memcpy(c, c1, len1); + if (len1 && c1[len1 - 1] != '\n') + { c[len1] = '\n'; + len1++; + } + memcpy(c + len1, c2, len2); + c[len1 + len2] = 0; + } + } + return c; +} + +/******************************************** + * Create an identifier in the string table. + */ + +Identifier *Lexer::idPool(const char *s) +{ + size_t len = strlen(s); + StringValue *sv = stringtable.update(s, len); + Identifier *id = (Identifier *) sv->ptrvalue; + if (!id) + { + id = new Identifier(sv->lstring.string, TOKidentifier); + sv->ptrvalue = id; + } + return id; +} + +/********************************************* + * Create a unique identifier using the prefix s. + */ + +Identifier *Lexer::uniqueId(const char *s, int num) +{ char buffer[32]; + size_t slen = strlen(s); + + assert(slen + sizeof(num) * 3 + 1 <= sizeof(buffer)); + sprintf(buffer, "%s%d", s, num); + return idPool(buffer); +} + +Identifier *Lexer::uniqueId(const char *s) +{ + static int num; + return uniqueId(s, ++num); +} + +/**************************************** + */ + +struct Keyword +{ const char *name; + enum TOK value; +}; + +static Keyword keywords[] = +{ +// { "", TOK }, + + { "this", TOKthis }, + { "super", TOKsuper }, + { "assert", TOKassert }, + { "null", TOKnull }, + { "true", TOKtrue }, + { "false", TOKfalse }, + { "cast", TOKcast }, + { "new", TOKnew }, + { "delete", TOKdelete }, + { "throw", TOKthrow }, + { "module", TOKmodule }, + { "pragma", TOKpragma }, + { "typeof", TOKtypeof }, + { "typeid", TOKtypeid }, + + { "template", TOKtemplate }, + + { "void", TOKvoid }, + { "byte", TOKint8 }, + { "ubyte", TOKuns8 }, + { "short", TOKint16 }, + { "ushort", TOKuns16 }, + { "int", TOKint32 }, + { "uint", TOKuns32 }, + { "long", TOKint64 }, + { "ulong", TOKuns64 }, + { "cent", TOKcent, }, + { "ucent", TOKucent, }, + { "float", TOKfloat32 }, + { "double", TOKfloat64 }, + { "real", TOKfloat80 }, + + { "bool", TOKbool }, + { "char", TOKchar }, + { "wchar", TOKwchar }, + { "dchar", TOKdchar }, + + { "ifloat", TOKimaginary32 }, + { "idouble", TOKimaginary64 }, + { "ireal", TOKimaginary80 }, + + { "cfloat", TOKcomplex32 }, + { "cdouble", TOKcomplex64 }, + { "creal", TOKcomplex80 }, + + { "delegate", TOKdelegate }, + { "function", TOKfunction }, + + { "is", TOKis }, + { "if", TOKif }, + { "else", TOKelse }, + { "while", TOKwhile }, + { "for", TOKfor }, + { "do", TOKdo }, + { "switch", TOKswitch }, + { "case", TOKcase }, + { "default", TOKdefault }, + { "break", TOKbreak }, + { "continue", TOKcontinue }, + { "synchronized", TOKsynchronized }, + { "return", TOKreturn }, + { "goto", TOKgoto }, + { "try", TOKtry }, + { "catch", TOKcatch }, + { "finally", TOKfinally }, + { "with", TOKwith }, + { "asm", TOKasm }, + { "foreach", TOKforeach }, + { "foreach_reverse", TOKforeach_reverse }, + { "scope", TOKscope }, + + { "struct", TOKstruct }, + { "class", TOKclass }, + { "interface", TOKinterface }, + { "union", TOKunion }, + { "enum", TOKenum }, + { "import", TOKimport }, + { "mixin", TOKmixin }, + { "static", TOKstatic }, + { "final", TOKfinal }, + { "const", TOKconst }, + { "typedef", TOKtypedef }, + { "alias", TOKalias }, + { "override", TOKoverride }, + { "abstract", TOKabstract }, + { "volatile", TOKvolatile }, + { "debug", TOKdebug }, + { "deprecated", TOKdeprecated }, + { "in", TOKin }, + { "out", TOKout }, + { "inout", TOKinout }, + { "lazy", TOKlazy }, + { "auto", TOKauto }, + + { "align", TOKalign }, + { "extern", TOKextern }, + { "private", TOKprivate }, + { "package", TOKpackage }, + { "protected", TOKprotected }, + { "public", TOKpublic }, + { "export", TOKexport }, + + { "body", TOKbody }, + { "invariant", TOKinvariant }, + { "unittest", TOKunittest }, + { "version", TOKversion }, + //{ "manifest", TOKmanifest }, + + // Added after 1.0 + { "ref", TOKref }, + { "macro", TOKmacro }, +#if DMDV2 + { "pure", TOKpure }, + { "nothrow", TOKnothrow }, + { "__thread", TOKtls }, + { "__gshared", TOKgshared }, + { "__traits", TOKtraits }, + { "__overloadset", TOKoverloadset }, + { "__FILE__", TOKfile }, + { "__LINE__", TOKline }, + { "shared", TOKshared }, + { "immutable", TOKimmutable }, +#endif +}; + +int Token::isKeyword() +{ + for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) + { + if (keywords[u].value == value) + return 1; + } + return 0; +} + +void Lexer::initKeywords() +{ StringValue *sv; + unsigned u; + enum TOK v; + unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); + + if (global.params.Dversion == 1) + nkeywords -= 2; + + cmtable_init(); + + for (u = 0; u < nkeywords; u++) + { const char *s; + + //printf("keyword[%d] = '%s'\n",u, keywords[u].name); + s = keywords[u].name; + v = keywords[u].value; + sv = stringtable.insert(s, strlen(s)); + sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); + + //printf("tochars[%d] = '%s'\n",v, s); + Token::tochars[v] = s; + } + + Token::tochars[TOKeof] = "EOF"; + Token::tochars[TOKlcurly] = "{"; + Token::tochars[TOKrcurly] = "}"; + Token::tochars[TOKlparen] = "("; + Token::tochars[TOKrparen] = ")"; + Token::tochars[TOKlbracket] = "["; + Token::tochars[TOKrbracket] = "]"; + Token::tochars[TOKsemicolon] = ";"; + Token::tochars[TOKcolon] = ":"; + Token::tochars[TOKcomma] = ","; + Token::tochars[TOKdot] = "."; + Token::tochars[TOKxor] = "^"; + Token::tochars[TOKxorass] = "^="; + Token::tochars[TOKassign] = "="; + Token::tochars[TOKconstruct] = "="; +#if DMDV2 + Token::tochars[TOKblit] = "="; +#endif + Token::tochars[TOKlt] = "<"; + Token::tochars[TOKgt] = ">"; + Token::tochars[TOKle] = "<="; + Token::tochars[TOKge] = ">="; + Token::tochars[TOKequal] = "=="; + Token::tochars[TOKnotequal] = "!="; + Token::tochars[TOKnotidentity] = "!is"; + Token::tochars[TOKtobool] = "!!"; + + Token::tochars[TOKunord] = "!<>="; + Token::tochars[TOKue] = "!<>"; + Token::tochars[TOKlg] = "<>"; + Token::tochars[TOKleg] = "<>="; + Token::tochars[TOKule] = "!>"; + Token::tochars[TOKul] = "!>="; + Token::tochars[TOKuge] = "!<"; + Token::tochars[TOKug] = "!<="; + + Token::tochars[TOKnot] = "!"; + Token::tochars[TOKtobool] = "!!"; + Token::tochars[TOKshl] = "<<"; + Token::tochars[TOKshr] = ">>"; + Token::tochars[TOKushr] = ">>>"; + Token::tochars[TOKadd] = "+"; + Token::tochars[TOKmin] = "-"; + Token::tochars[TOKmul] = "*"; + Token::tochars[TOKdiv] = "/"; + Token::tochars[TOKmod] = "%"; + Token::tochars[TOKslice] = ".."; + Token::tochars[TOKdotdotdot] = "..."; + Token::tochars[TOKand] = "&"; + Token::tochars[TOKandand] = "&&"; + Token::tochars[TOKor] = "|"; + Token::tochars[TOKoror] = "||"; + Token::tochars[TOKarray] = "[]"; + Token::tochars[TOKindex] = "[i]"; + Token::tochars[TOKaddress] = "&"; + Token::tochars[TOKstar] = "*"; + Token::tochars[TOKtilde] = "~"; + Token::tochars[TOKdollar] = "$"; + Token::tochars[TOKcast] = "cast"; + Token::tochars[TOKplusplus] = "++"; + Token::tochars[TOKminusminus] = "--"; + Token::tochars[TOKpreplusplus] = "++"; + Token::tochars[TOKpreminusminus] = "--"; + Token::tochars[TOKtype] = "type"; + Token::tochars[TOKquestion] = "?"; + Token::tochars[TOKneg] = "-"; + Token::tochars[TOKuadd] = "+"; + Token::tochars[TOKvar] = "var"; + Token::tochars[TOKaddass] = "+="; + Token::tochars[TOKminass] = "-="; + Token::tochars[TOKmulass] = "*="; + Token::tochars[TOKdivass] = "/="; + Token::tochars[TOKmodass] = "%="; + Token::tochars[TOKshlass] = "<<="; + Token::tochars[TOKshrass] = ">>="; + Token::tochars[TOKushrass] = ">>>="; + Token::tochars[TOKandass] = "&="; + Token::tochars[TOKorass] = "|="; + Token::tochars[TOKcatass] = "~="; + Token::tochars[TOKcat] = "~"; + Token::tochars[TOKcall] = "call"; + Token::tochars[TOKidentity] = "is"; + Token::tochars[TOKnotidentity] = "!is"; + + Token::tochars[TOKorass] = "|="; + Token::tochars[TOKidentifier] = "identifier"; +#if DMDV2 + Token::tochars[TOKat] = "@"; + Token::tochars[TOKpow] = "^^"; + Token::tochars[TOKpowass] = "^^="; +#endif + + // For debugging + Token::tochars[TOKerror] = "error"; + Token::tochars[TOKdotexp] = "dotexp"; + Token::tochars[TOKdotti] = "dotti"; + Token::tochars[TOKdotvar] = "dotvar"; + Token::tochars[TOKdottype] = "dottype"; + Token::tochars[TOKsymoff] = "symoff"; + Token::tochars[TOKarraylength] = "arraylength"; + Token::tochars[TOKarrayliteral] = "arrayliteral"; + Token::tochars[TOKassocarrayliteral] = "assocarrayliteral"; + Token::tochars[TOKstructliteral] = "structliteral"; + Token::tochars[TOKstring] = "string"; + Token::tochars[TOKdsymbol] = "symbol"; + Token::tochars[TOKtuple] = "tuple"; + Token::tochars[TOKdeclaration] = "declaration"; + Token::tochars[TOKdottd] = "dottd"; + Token::tochars[TOKon_scope_exit] = "scope(exit)"; + Token::tochars[TOKon_scope_success] = "scope(success)"; + Token::tochars[TOKon_scope_failure] = "scope(failure)"; + +#if UNITTEST + unittest_lexer(); +#endif +} + +#if UNITTEST + +void unittest_lexer() +{ + //printf("unittest_lexer()\n"); + + /* Not much here, just trying things out. + */ + const unsigned char text[] = "int"; + Lexer lex1(NULL, (unsigned char *)text, 0, sizeof(text), 0, 0); + TOK tok; + tok = lex1.nextToken(); + //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOKint32); + assert(tok == TOKint32); + tok = lex1.nextToken(); + assert(tok == TOKeof); + tok = lex1.nextToken(); + assert(tok == TOKeof); +} + +#endif + diff --git a/dmd2/lexer.h b/dmd2/lexer.h index 895ea903..3c0cd040 100644 --- a/dmd2/lexer.h +++ b/dmd2/lexer.h @@ -1,310 +1,318 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_LEXER_H -#define DMD_LEXER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "mars.h" - -struct StringTable; -struct Identifier; -struct Module; - -/* Tokens: - ( ) - [ ] - { } - < > <= >= == != === !== - << >> <<= >>= >>> >>>= - + - += -= - * / % *= /= %= - & | ^ &= |= ^= - = ! ~ @ - ++ -- - . -> : , - ? && || - */ - -enum TOK -{ - TOKreserved, - - // Other - TOKlparen, TOKrparen, - TOKlbracket, TOKrbracket, - TOKlcurly, TOKrcurly, - TOKcolon, TOKneg, - TOKsemicolon, TOKdotdotdot, - TOKeof, TOKcast, - TOKnull, TOKassert, - TOKtrue, TOKfalse, - TOKarray, TOKcall, - TOKaddress, - TOKtype, TOKthrow, - TOKnew, TOKdelete, - TOKstar, TOKsymoff, - TOKvar, TOKdotvar, - TOKdotti, TOKdotexp, - TOKdottype, TOKslice, - TOKarraylength, TOKversion, - TOKmodule, TOKdollar, - TOKtemplate, TOKdottd, - TOKdeclaration, TOKtypeof, - TOKpragma, TOKdsymbol, - TOKtypeid, TOKuadd, - TOKremove, - TOKnewanonclass, TOKcomment, - TOKarrayliteral, TOKassocarrayliteral, - TOKstructliteral, - - // Operators - TOKlt, TOKgt, - TOKle, TOKge, - TOKequal, TOKnotequal, - TOKidentity, TOKnotidentity, - TOKindex, TOKis, - TOKtobool, - -// 60 - // NCEG floating point compares - // !<>= <> <>= !> !>= !< !<= !<> - TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, - - TOKshl, TOKshr, - TOKshlass, TOKshrass, - TOKushr, TOKushrass, - TOKcat, TOKcatass, // ~ ~= - TOKadd, TOKmin, TOKaddass, TOKminass, - TOKmul, TOKdiv, TOKmod, - TOKmulass, TOKdivass, TOKmodass, - TOKand, TOKor, TOKxor, - TOKandass, TOKorass, TOKxorass, - TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, - TOKdot, TOKarrow, TOKcomma, - TOKquestion, TOKandand, TOKoror, - -// 104 - // Numeric literals - TOKint32v, TOKuns32v, - TOKint64v, TOKuns64v, - TOKfloat32v, TOKfloat64v, TOKfloat80v, - TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, - - // Char constants - TOKcharv, TOKwcharv, TOKdcharv, - - // Leaf operators - TOKidentifier, TOKstring, - TOKthis, TOKsuper, - TOKhalt, TOKtuple, - - // Basic types - TOKvoid, - TOKint8, TOKuns8, - TOKint16, TOKuns16, - TOKint32, TOKuns32, - TOKint64, TOKuns64, - TOKfloat32, TOKfloat64, TOKfloat80, - TOKimaginary32, TOKimaginary64, TOKimaginary80, - TOKcomplex32, TOKcomplex64, TOKcomplex80, - TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, - TOKcent, TOKucent, - - // Aggregates - TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, - TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, - TOKmixin, - - TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, - TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, - TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, TOKmanifest, TOKimmutable, - - // Statements - TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, - TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, - TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, - TOKscope, - TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, - - // Contracts - TOKbody, TOKinvariant, - - // Testing - TOKunittest, - - // Added after 1.0 - TOKref, - TOKmacro, -#if DMDV2 - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKtls, - TOKgshared, - TOKline, - TOKfile, - TOKshared, - TOKat, -#endif - -// LDC specific -#if IN_LLVM - TOKgep, -#endif - - TOKMAX -}; - -#define CASE_BASIC_TYPES \ - case TOKwchar: case TOKdchar: \ - case TOKbit: case TOKbool: case TOKchar: \ - case TOKint8: case TOKuns8: \ - case TOKint16: case TOKuns16: \ - case TOKint32: case TOKuns32: \ - case TOKint64: case TOKuns64: \ - case TOKfloat32: case TOKfloat64: case TOKfloat80: \ - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ - case TOKvoid - -#define CASE_BASIC_TYPES_X(t) \ - case TOKvoid: t = Type::tvoid; goto LabelX; \ - case TOKint8: t = Type::tint8; goto LabelX; \ - case TOKuns8: t = Type::tuns8; goto LabelX; \ - case TOKint16: t = Type::tint16; goto LabelX; \ - case TOKuns16: t = Type::tuns16; goto LabelX; \ - case TOKint32: t = Type::tint32; goto LabelX; \ - case TOKuns32: t = Type::tuns32; goto LabelX; \ - case TOKint64: t = Type::tint64; goto LabelX; \ - case TOKuns64: t = Type::tuns64; goto LabelX; \ - case TOKfloat32: t = Type::tfloat32; goto LabelX; \ - case TOKfloat64: t = Type::tfloat64; goto LabelX; \ - case TOKfloat80: t = Type::tfloat80; goto LabelX; \ - case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ - case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ - case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ - case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \ - case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \ - case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \ - case TOKbit: t = Type::tbit; goto LabelX; \ - case TOKbool: t = Type::tbool; goto LabelX; \ - case TOKchar: t = Type::tchar; goto LabelX; \ - case TOKwchar: t = Type::twchar; goto LabelX; \ - case TOKdchar: t = Type::tdchar; goto LabelX; \ - LabelX - -struct Token -{ - Token *next; - unsigned char *ptr; // pointer to first character of this token within buffer - enum TOK value; - unsigned char *blockComment; // doc comment string prior to this token - unsigned char *lineComment; // doc comment for previous token - union - { - // Integers - d_int32 int32value; - d_uns32 uns32value; - d_int64 int64value; - d_uns64 uns64value; - - // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else - d_float80 float80value; -#endif - - struct - { unsigned char *ustring; // UTF8 string - unsigned len; - unsigned char postfix; // 'c', 'w', 'd' - }; - - Identifier *ident; - }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif - - static const char *tochars[TOKMAX]; - static void *operator new(size_t sz); - - int isKeyword(); - void print(); - const char *toChars(); - static const char *toChars(enum TOK); -}; - -struct Lexer -{ - static StringTable stringtable; - static OutBuffer stringbuffer; - static Token *freelist; - - Loc loc; // for error messages - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - Token token; - Module *mod; - int doDocComment; // collect doc comment information - int anyToken; // !=0 means seen at least one token - int commentToken; // !=0 means comments are TOKcomment's - - Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); - - static void initKeywords(); - static Identifier *idPool(const char *s); - static Identifier *uniqueId(const char *s); - static Identifier *uniqueId(const char *s, int num); - - TOK nextToken(); - TOK peekNext(); - TOK peekNext2(); - void scan(Token *t); - Token *peek(Token *t); - Token *peekPastParen(Token *t); - unsigned escapeSequence(); - TOK wysiwygStringConstant(Token *t, int tc); - TOK hexStringConstant(Token *t); -#if DMDV2 - TOK delimitedStringConstant(Token *t); - TOK tokenStringConstant(Token *t); -#endif - TOK escapeStringConstant(Token *t, int wide); - TOK charConstant(Token *t, int wide); - void stringPostfix(Token *t); - unsigned wchar(unsigned u); - TOK number(Token *t); - TOK inreal(Token *t); - void error(const char *format, ...) IS_PRINTF(2); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void pragma(); - unsigned decodeUTF(); - void getDocComment(Token *t, unsigned lineComment); - - static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); -}; - -#endif /* DMD_LEXER_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_LEXER_H +#define DMD_LEXER_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "mars.h" + +struct StringTable; +struct Identifier; +struct Module; + +/* Tokens: + ( ) + [ ] + { } + < > <= >= == != === !== + << >> <<= >>= >>> >>>= + + - += -= + * / % *= /= %= + & | ^ &= |= ^= + = ! ~ @ + ^^ ^^= + ++ -- + . -> : , + ? && || + */ + +enum TOK +{ + TOKreserved, + + // Other + TOKlparen, TOKrparen, + TOKlbracket, TOKrbracket, + TOKlcurly, TOKrcurly, + TOKcolon, TOKneg, + TOKsemicolon, TOKdotdotdot, + TOKeof, TOKcast, + TOKnull, TOKassert, + TOKtrue, TOKfalse, + TOKarray, TOKcall, + TOKaddress, + TOKtype, TOKthrow, + TOKnew, TOKdelete, + TOKstar, TOKsymoff, + TOKvar, TOKdotvar, + TOKdotti, TOKdotexp, + TOKdottype, TOKslice, + TOKarraylength, TOKversion, + TOKmodule, TOKdollar, + TOKtemplate, TOKdottd, + TOKdeclaration, TOKtypeof, + TOKpragma, TOKdsymbol, + TOKtypeid, TOKuadd, + TOKremove, + TOKnewanonclass, TOKcomment, + TOKarrayliteral, TOKassocarrayliteral, + TOKstructliteral, + + // Operators + TOKlt, TOKgt, + TOKle, TOKge, + TOKequal, TOKnotequal, + TOKidentity, TOKnotidentity, + TOKindex, TOKis, + TOKtobool, + +// 60 + // NCEG floating point compares + // !<>= <> <>= !> !>= !< !<= !<> + TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, + + TOKshl, TOKshr, + TOKshlass, TOKshrass, + TOKushr, TOKushrass, + TOKcat, TOKcatass, // ~ ~= + TOKadd, TOKmin, TOKaddass, TOKminass, + TOKmul, TOKdiv, TOKmod, + TOKmulass, TOKdivass, TOKmodass, + TOKand, TOKor, TOKxor, + TOKandass, TOKorass, TOKxorass, + TOKassign, TOKnot, TOKtilde, + TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, + TOKdot, TOKarrow, TOKcomma, + TOKquestion, TOKandand, TOKoror, + TOKpreplusplus, TOKpreminusminus, + +// 106 + // Numeric literals + TOKint32v, TOKuns32v, + TOKint64v, TOKuns64v, + TOKfloat32v, TOKfloat64v, TOKfloat80v, + TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, + + // Char constants + TOKcharv, TOKwcharv, TOKdcharv, + + // Leaf operators + TOKidentifier, TOKstring, + TOKthis, TOKsuper, + TOKhalt, TOKtuple, + TOKerror, + + // Basic types + TOKvoid, + TOKint8, TOKuns8, + TOKint16, TOKuns16, + TOKint32, TOKuns32, + TOKint64, TOKuns64, + TOKfloat32, TOKfloat64, TOKfloat80, + TOKimaginary32, TOKimaginary64, TOKimaginary80, + TOKcomplex32, TOKcomplex64, TOKcomplex80, + TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, + TOKcent, TOKucent, + +// 152 + // Aggregates + TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, + TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, + TOKmixin, + + TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, + TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, + TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, + TOKauto, TOKpackage, TOKmanifest, TOKimmutable, + + // Statements + TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, + TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, + TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, + TOKasm, TOKforeach, TOKforeach_reverse, + TOKscope, + TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, + + // Contracts + TOKbody, TOKinvariant, + + // Testing + TOKunittest, + + // Added after 1.0 + TOKref, + TOKmacro, +#if DMDV2 + TOKtraits, + TOKoverloadset, + TOKpure, + TOKnothrow, + TOKtls, + TOKgshared, + TOKline, + TOKfile, + TOKshared, + TOKat, + TOKpow, + TOKpowass, +#endif + +// LDC specific +#if IN_LLVM + TOKgep, +#endif + + TOKMAX +}; + +#define TOKwild TOKinout + +#define BASIC_TYPES \ + TOKwchar: case TOKdchar: \ + case TOKbit: case TOKbool: case TOKchar: \ + case TOKint8: case TOKuns8: \ + case TOKint16: case TOKuns16: \ + case TOKint32: case TOKuns32: \ + case TOKint64: case TOKuns64: \ + case TOKfloat32: case TOKfloat64: case TOKfloat80: \ + case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ + case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ + case TOKvoid + +#define BASIC_TYPES_X(t) \ + TOKvoid: t = Type::tvoid; goto LabelX; \ + case TOKint8: t = Type::tint8; goto LabelX; \ + case TOKuns8: t = Type::tuns8; goto LabelX; \ + case TOKint16: t = Type::tint16; goto LabelX; \ + case TOKuns16: t = Type::tuns16; goto LabelX; \ + case TOKint32: t = Type::tint32; goto LabelX; \ + case TOKuns32: t = Type::tuns32; goto LabelX; \ + case TOKint64: t = Type::tint64; goto LabelX; \ + case TOKuns64: t = Type::tuns64; goto LabelX; \ + case TOKfloat32: t = Type::tfloat32; goto LabelX; \ + case TOKfloat64: t = Type::tfloat64; goto LabelX; \ + case TOKfloat80: t = Type::tfloat80; goto LabelX; \ + case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ + case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ + case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ + case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \ + case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \ + case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \ + case TOKbit: t = Type::tbit; goto LabelX; \ + case TOKbool: t = Type::tbool; goto LabelX; \ + case TOKchar: t = Type::tchar; goto LabelX; \ + case TOKwchar: t = Type::twchar; goto LabelX; \ + case TOKdchar: t = Type::tdchar; goto LabelX; \ + LabelX + +struct Token +{ + Token *next; + unsigned char *ptr; // pointer to first character of this token within buffer + enum TOK value; + unsigned char *blockComment; // doc comment string prior to this token + unsigned char *lineComment; // doc comment for previous token + union + { + // Integers + d_int32 int32value; + d_uns32 uns32value; + d_int64 int64value; + d_uns64 uns64value; + + // Floats +#ifdef IN_GCC + // real_t float80value; // can't use this in a union! +#else + d_float80 float80value; +#endif + + struct + { unsigned char *ustring; // UTF8 string + unsigned len; + unsigned char postfix; // 'c', 'w', 'd' + }; + + Identifier *ident; + }; +#ifdef IN_GCC + real_t float80value; // can't use this in a union! +#endif + + static const char *tochars[TOKMAX]; + static void *operator new(size_t sz); + + int isKeyword(); + void print(); + const char *toChars(); + static const char *toChars(enum TOK); +}; + +struct Lexer +{ + static StringTable stringtable; + static OutBuffer stringbuffer; + static Token *freelist; + + Loc loc; // for error messages + + unsigned char *base; // pointer to start of buffer + unsigned char *end; // past end of buffer + unsigned char *p; // current character + Token token; + Module *mod; + int doDocComment; // collect doc comment information + int anyToken; // !=0 means seen at least one token + int commentToken; // !=0 means comments are TOKcomment's + + Lexer(Module *mod, + unsigned char *base, unsigned begoffset, unsigned endoffset, + int doDocComment, int commentToken); + + static void initKeywords(); + static Identifier *idPool(const char *s); + static Identifier *uniqueId(const char *s); + static Identifier *uniqueId(const char *s, int num); + + TOK nextToken(); + TOK peekNext(); + TOK peekNext2(); + void scan(Token *t); + Token *peek(Token *t); + Token *peekPastParen(Token *t); + unsigned escapeSequence(); + TOK wysiwygStringConstant(Token *t, int tc); + TOK hexStringConstant(Token *t); +#if DMDV2 + TOK delimitedStringConstant(Token *t); + TOK tokenStringConstant(Token *t); +#endif + TOK escapeStringConstant(Token *t, int wide); + TOK charConstant(Token *t, int wide); + void stringPostfix(Token *t); + unsigned wchar(unsigned u); + TOK number(Token *t); + TOK inreal(Token *t); + void error(const char *format, ...) IS_PRINTF(2); + void error(Loc loc, const char *format, ...) IS_PRINTF(3); + void pragma(); + unsigned decodeUTF(); + void getDocComment(Token *t, unsigned lineComment); + + static int isValidIdentifier(char *p); + static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); +}; + +#endif /* DMD_LEXER_H */ diff --git a/dmd2/lib.h b/dmd2/lib.h index 86850caa..31ac1f99 100644 --- a/dmd2/lib.h +++ b/dmd2/lib.h @@ -1,49 +1,49 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_LIB_H -#define DMD_LIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -struct ObjModule; - -struct ObjSymbol -{ - char *name; - ObjModule *om; -}; - -struct Library -{ - File *libfile; - Array objmodules; // ObjModule[] - Array objsymbols; // ObjSymbol[] - - StringTable tab; - - Library(); - void setFilename(char *dir, char *filename); - void addObject(const char *module_name, void *buf, size_t buflen); - void addLibrary(void *buf, size_t buflen); - void write(); - - private: - void addSymbol(ObjModule *om, char *name, int pickAny = 0); - void scanObjModule(ObjModule *om); - unsigned short numDictPages(unsigned padding); - int FillDict(unsigned char *bucketsP, unsigned short uNumPages); - void WriteLibToBuffer(OutBuffer *libbuf); -}; - -#endif /* DMD_LIB_H */ - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +#ifndef DMD_LIB_H +#define DMD_LIB_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +struct ObjModule; + +struct ObjSymbol +{ + char *name; + ObjModule *om; +}; + +struct Library +{ + File *libfile; + Array objmodules; // ObjModule[] + Array objsymbols; // ObjSymbol[] + + StringTable tab; + + Library(); + void setFilename(char *dir, char *filename); + void addObject(const char *module_name, void *buf, size_t buflen); + void addLibrary(void *buf, size_t buflen); + void write(); + + private: + void addSymbol(ObjModule *om, char *name, int pickAny = 0); + void scanObjModule(ObjModule *om); + unsigned short numDictPages(unsigned padding); + int FillDict(unsigned char *bucketsP, unsigned short uNumPages); + void WriteLibToBuffer(OutBuffer *libbuf); +}; + +#endif /* DMD_LIB_H */ + diff --git a/dmd2/macro.c b/dmd2/macro.c index 6f800b6d..398ba77f 100644 --- a/dmd2/macro.c +++ b/dmd2/macro.c @@ -1,449 +1,449 @@ - -// Copyright (c) 1999-2006 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. - -/* Simple macro text processor. - */ - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "macro.h" - -#define isidstart(c) (isalpha(c) || (c) == '_') -#define isidchar(c) (isalnum(c) || (c) == '_') - -unsigned char *memdup(unsigned char *p, size_t len) -{ - return (unsigned char *)memcpy(mem.malloc(len), p, len); -} - -Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - next = NULL; - -#if 1 - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#else - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#endif - inuse = 0; -} - - -Macro *Macro::search(unsigned char *name, size_t namelen) -{ Macro *table; - - //printf("Macro::search(%.*s)\n", namelen, name); - for (table = this; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - //printf("\tfound %d\n", table->textlen); - break; - } - } - return table; -} - -Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); - - Macro *table; - - //assert(ptable); - for (table = *ptable; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - table->text = text; - table->textlen = textlen; - return table; - } - } - table = new Macro(name, namelen, text, textlen); - table->next = *ptable; - *ptable = table; - return table; -} - -/********************************************************** - * Given buffer p[0..end], extract argument marg[0..marglen]. - * Params: - * n 0: get entire argument - * 1..9: get nth argument - * -1: get 2nd through end - */ - -unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n) -{ - /* Scan forward for matching right parenthesis. - * Nest parentheses. - * Skip over $( and $) - * Skip over "..." and '...' strings inside HTML tags. - * Skip over comments. - * Skip over previous macro insertions - * Set marglen. - */ - unsigned parens = 1; - unsigned char instring = 0; - unsigned incomment = 0; - unsigned intag = 0; - unsigned inexp = 0; - unsigned argn = 0; - - unsigned v = 0; - - Largstart: -#if 1 - // Skip first space, if any, to find the start of the macro argument - if (v < end && isspace(p[v])) - v++; -#else - // Skip past spaces to find the start of the macro argument - for (; v < end && isspace(p[v]); v++) - ; -#endif - *pmarg = p + v; - - for (; v < end; v++) - { unsigned char c = p[v]; - - switch (c) - { - case ',': - if (!inexp && !instring && !incomment && parens == 1) - { - argn++; - if (argn == 1 && n == -1) - { v++; - goto Largstart; - } - if (argn == n) - break; - if (argn + 1 == n) - { v++; - goto Largstart; - } - } - continue; - - case '(': - if (!inexp && !instring && !incomment) - parens++; - continue; - - case ')': - if (!inexp && !instring && !incomment && --parens == 0) - { - break; - } - continue; - - case '"': - case '\'': - if (!inexp && !incomment && intag) - { - if (c == instring) - instring = 0; - else if (!instring) - instring = c; - } - continue; - - case '<': - if (!inexp && !instring && !incomment) - { - if (v + 6 < end && - p[v + 1] == '!' && - p[v + 2] == '-' && - p[v + 3] == '-') - { - incomment = 1; - v += 3; - } - else if (v + 2 < end && - isalpha(p[v + 1])) - intag = 1; - } - continue; - - case '>': - if (!inexp) - intag = 0; - continue; - - case '-': - if (!inexp && - !instring && - incomment && - v + 2 < end && - p[v + 1] == '-' && - p[v + 2] == '>') - { - incomment = 0; - v += 2; - } - continue; - - case 0xFF: - if (v + 1 < end) - { - if (p[v + 1] == '{') - inexp++; - else if (p[v + 1] == '}') - inexp--; - } - continue; - - default: - continue; - } - break; - } - if (argn == 0 && n == -1) - *pmarg = p + v; - *pmarglen = p + v - *pmarg; - //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg); - return v; -} - - -/***************************************************** - * Expand macro in place in buf. - * Only look at the text in buf from start to end. - */ - -void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen) -{ -#if 0 - printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); - printf("Buf is: '%.*s'\n", *pend - start, buf->data + start); -#endif - - static int nest; - if (nest > 100) // limit recursive expansion - return; - nest++; - - unsigned end = *pend; - assert(start <= end); - assert(end <= buf->offset); - - /* First pass - replace $0 - */ - arg = memdup(arg, arglen); - for (unsigned u = start; u + 1 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* Look for $0, but not $$0, and replace it with arg. - */ - if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) - { - if (u > start && p[u - 1] == '$') - { // Don't expand $$0, but replace it with $0 - buf->remove(u - 1, 1); - end--; - u += 1; // now u is one past the closing '1' - continue; - } - - unsigned char c = p[u + 1]; - int n = (c == '+') ? -1 : c - '0'; - - unsigned char *marg; - unsigned marglen; - extractArgN(arg, arglen, &marg, &marglen, n); - if (marglen == 0) - { // Just remove macro invocation - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - end -= 2; - } - else if (c == '+') - { - // Replace '$+' with 'arg' - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - buf->insert(u, marg, marglen); - end += marglen - 2; - - // Scan replaced text for further expansion - unsigned mend = u + marglen; - expand(buf, u, &mend, NULL, 0); - end += mend - (u + marglen); - u = mend; - } - else - { - // Replace '$1' with '\xFF{arg\xFF}' - //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg); - buf->data[u] = 0xFF; - buf->data[u + 1] = '{'; - buf->insert(u + 2, marg, marglen); - buf->insert(u + 2 + marglen, "\xFF}", 2); - end += -2 + 2 + marglen + 2; - - // Scan replaced text for further expansion - unsigned mend = u + 2 + marglen; - expand(buf, u + 2, &mend, NULL, 0); - end += mend - (u + 2 + marglen); - u = mend; - } - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end, &buf->data[0]); - continue; - } - - u++; - } - - /* Second pass - replace other macros - */ - for (unsigned u = start; u + 4 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* A valid start of macro expansion is $(c, where c is - * an id start character, and not $$(c. - */ - if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2])) - { - //printf("\tfound macro start '%c'\n", p[u + 2]); - unsigned char *name = p + u + 2; - unsigned namelen = 0; - - unsigned char *marg; - unsigned marglen; - - unsigned v; - /* Scan forward to find end of macro name and - * beginning of macro argument (marg). - */ - for (v = u + 2; v < end; v++) - { unsigned char c = p[v]; - - if (!isidchar(c)) - { // We've gone past the end of the macro name. - namelen = v - (u + 2); - break; - } - } - - v += extractArgN(p + v, end - v, &marg, &marglen, 0); - assert(v <= end); - - if (v < end) - { // v is on the closing ')' - if (u > start && p[u - 1] == '$') - { // Don't expand $$(NAME), but replace it with $(NAME) - buf->remove(u - 1, 1); - end--; - u = v; // now u is one past the closing ')' - continue; - } - - Macro *m = search(name, namelen); - if (m) - { -#if 0 - if (m->textlen && m->text[0] == ' ') - { m->text++; - m->textlen--; - } -#endif - if (m->inuse && marglen == 0) - { // Remove macro invocation - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - } - else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0) - { // Recursive expansion; just leave in place - - } - else - { - //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text); -#if 1 - marg = memdup(marg, marglen); - // Insert replacement text - buf->spread(v + 1, 2 + m->textlen + 2); - buf->data[v + 1] = 0xFF; - buf->data[v + 2] = '{'; - memcpy(buf->data + v + 3, m->text, m->textlen); - buf->data[v + 3 + m->textlen] = 0xFF; - buf->data[v + 3 + m->textlen + 1] = '}'; - - end += 2 + m->textlen + 2; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + 2+m->textlen+2; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + 2+m->textlen+2); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#else - // Insert replacement text - buf->insert(v + 1, m->text, m->textlen); - end += m->textlen; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + m->textlen; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + m->textlen); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#endif - mem.free(marg); - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end - u, &buf->data[u]); - continue; - } - } - else - { - // Replace $(NAME) with nothing - buf->remove(u, v + 1 - u); - end -= (v + 1 - u); - continue; - } - } - } - u++; - } - mem.free(arg); - *pend = end; - nest--; -} + +// Copyright (c) 1999-2006 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. + +/* Simple macro text processor. + */ + +#include +#include +#include +#include +#include + +#include "rmem.h" +#include "root.h" + +#include "macro.h" + +#define isidstart(c) (isalpha(c) || (c) == '_') +#define isidchar(c) (isalnum(c) || (c) == '_') + +unsigned char *memdup(unsigned char *p, size_t len) +{ + return (unsigned char *)memcpy(mem.malloc(len), p, len); +} + +Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) +{ + next = NULL; + +#if 1 + this->name = name; + this->namelen = namelen; + + this->text = text; + this->textlen = textlen; +#else + this->name = name; + this->namelen = namelen; + + this->text = text; + this->textlen = textlen; +#endif + inuse = 0; +} + + +Macro *Macro::search(unsigned char *name, size_t namelen) +{ Macro *table; + + //printf("Macro::search(%.*s)\n", namelen, name); + for (table = this; table; table = table->next) + { + if (table->namelen == namelen && + memcmp(table->name, name, namelen) == 0) + { + //printf("\tfound %d\n", table->textlen); + break; + } + } + return table; +} + +Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) +{ + //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); + + Macro *table; + + //assert(ptable); + for (table = *ptable; table; table = table->next) + { + if (table->namelen == namelen && + memcmp(table->name, name, namelen) == 0) + { + table->text = text; + table->textlen = textlen; + return table; + } + } + table = new Macro(name, namelen, text, textlen); + table->next = *ptable; + *ptable = table; + return table; +} + +/********************************************************** + * Given buffer p[0..end], extract argument marg[0..marglen]. + * Params: + * n 0: get entire argument + * 1..9: get nth argument + * -1: get 2nd through end + */ + +unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n) +{ + /* Scan forward for matching right parenthesis. + * Nest parentheses. + * Skip over $( and $) + * Skip over "..." and '...' strings inside HTML tags. + * Skip over comments. + * Skip over previous macro insertions + * Set marglen. + */ + unsigned parens = 1; + unsigned char instring = 0; + unsigned incomment = 0; + unsigned intag = 0; + unsigned inexp = 0; + unsigned argn = 0; + + unsigned v = 0; + + Largstart: +#if 1 + // Skip first space, if any, to find the start of the macro argument + if (v < end && isspace(p[v])) + v++; +#else + // Skip past spaces to find the start of the macro argument + for (; v < end && isspace(p[v]); v++) + ; +#endif + *pmarg = p + v; + + for (; v < end; v++) + { unsigned char c = p[v]; + + switch (c) + { + case ',': + if (!inexp && !instring && !incomment && parens == 1) + { + argn++; + if (argn == 1 && n == -1) + { v++; + goto Largstart; + } + if (argn == n) + break; + if (argn + 1 == n) + { v++; + goto Largstart; + } + } + continue; + + case '(': + if (!inexp && !instring && !incomment) + parens++; + continue; + + case ')': + if (!inexp && !instring && !incomment && --parens == 0) + { + break; + } + continue; + + case '"': + case '\'': + if (!inexp && !incomment && intag) + { + if (c == instring) + instring = 0; + else if (!instring) + instring = c; + } + continue; + + case '<': + if (!inexp && !instring && !incomment) + { + if (v + 6 < end && + p[v + 1] == '!' && + p[v + 2] == '-' && + p[v + 3] == '-') + { + incomment = 1; + v += 3; + } + else if (v + 2 < end && + isalpha(p[v + 1])) + intag = 1; + } + continue; + + case '>': + if (!inexp) + intag = 0; + continue; + + case '-': + if (!inexp && + !instring && + incomment && + v + 2 < end && + p[v + 1] == '-' && + p[v + 2] == '>') + { + incomment = 0; + v += 2; + } + continue; + + case 0xFF: + if (v + 1 < end) + { + if (p[v + 1] == '{') + inexp++; + else if (p[v + 1] == '}') + inexp--; + } + continue; + + default: + continue; + } + break; + } + if (argn == 0 && n == -1) + *pmarg = p + v; + *pmarglen = p + v - *pmarg; + //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg); + return v; +} + + +/***************************************************** + * Expand macro in place in buf. + * Only look at the text in buf from start to end. + */ + +void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend, + unsigned char *arg, unsigned arglen) +{ +#if 0 + printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); + printf("Buf is: '%.*s'\n", *pend - start, buf->data + start); +#endif + + static int nest; + if (nest > 100) // limit recursive expansion + return; + nest++; + + unsigned end = *pend; + assert(start <= end); + assert(end <= buf->offset); + + /* First pass - replace $0 + */ + arg = memdup(arg, arglen); + for (unsigned u = start; u + 1 < end; ) + { + unsigned char *p = buf->data; // buf->data is not loop invariant + + /* Look for $0, but not $$0, and replace it with arg. + */ + if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) + { + if (u > start && p[u - 1] == '$') + { // Don't expand $$0, but replace it with $0 + buf->remove(u - 1, 1); + end--; + u += 1; // now u is one past the closing '1' + continue; + } + + unsigned char c = p[u + 1]; + int n = (c == '+') ? -1 : c - '0'; + + unsigned char *marg; + unsigned marglen; + extractArgN(arg, arglen, &marg, &marglen, n); + if (marglen == 0) + { // Just remove macro invocation + //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); + buf->remove(u, 2); + end -= 2; + } + else if (c == '+') + { + // Replace '$+' with 'arg' + //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); + buf->remove(u, 2); + buf->insert(u, marg, marglen); + end += marglen - 2; + + // Scan replaced text for further expansion + unsigned mend = u + marglen; + expand(buf, u, &mend, NULL, 0); + end += mend - (u + marglen); + u = mend; + } + else + { + // Replace '$1' with '\xFF{arg\xFF}' + //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg); + buf->data[u] = 0xFF; + buf->data[u + 1] = '{'; + buf->insert(u + 2, marg, marglen); + buf->insert(u + 2 + marglen, "\xFF}", 2); + end += -2 + 2 + marglen + 2; + + // Scan replaced text for further expansion + unsigned mend = u + 2 + marglen; + expand(buf, u + 2, &mend, NULL, 0); + end += mend - (u + 2 + marglen); + u = mend; + } + //printf("u = %d, end = %d\n", u, end); + //printf("#%.*s#\n", end, &buf->data[0]); + continue; + } + + u++; + } + + /* Second pass - replace other macros + */ + for (unsigned u = start; u + 4 < end; ) + { + unsigned char *p = buf->data; // buf->data is not loop invariant + + /* A valid start of macro expansion is $(c, where c is + * an id start character, and not $$(c. + */ + if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2])) + { + //printf("\tfound macro start '%c'\n", p[u + 2]); + unsigned char *name = p + u + 2; + unsigned namelen = 0; + + unsigned char *marg; + unsigned marglen; + + unsigned v; + /* Scan forward to find end of macro name and + * beginning of macro argument (marg). + */ + for (v = u + 2; v < end; v++) + { unsigned char c = p[v]; + + if (!isidchar(c)) + { // We've gone past the end of the macro name. + namelen = v - (u + 2); + break; + } + } + + v += extractArgN(p + v, end - v, &marg, &marglen, 0); + assert(v <= end); + + if (v < end) + { // v is on the closing ')' + if (u > start && p[u - 1] == '$') + { // Don't expand $$(NAME), but replace it with $(NAME) + buf->remove(u - 1, 1); + end--; + u = v; // now u is one past the closing ')' + continue; + } + + Macro *m = search(name, namelen); + if (m) + { +#if 0 + if (m->textlen && m->text[0] == ' ') + { m->text++; + m->textlen--; + } +#endif + if (m->inuse && marglen == 0) + { // Remove macro invocation + buf->remove(u, v + 1 - u); + end -= v + 1 - u; + } + else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0) + { // Recursive expansion; just leave in place + + } + else + { + //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text); +#if 1 + marg = memdup(marg, marglen); + // Insert replacement text + buf->spread(v + 1, 2 + m->textlen + 2); + buf->data[v + 1] = 0xFF; + buf->data[v + 2] = '{'; + memcpy(buf->data + v + 3, m->text, m->textlen); + buf->data[v + 3 + m->textlen] = 0xFF; + buf->data[v + 3 + m->textlen + 1] = '}'; + + end += 2 + m->textlen + 2; + + // Scan replaced text for further expansion + m->inuse++; + unsigned mend = v + 1 + 2+m->textlen+2; + expand(buf, v + 1, &mend, marg, marglen); + end += mend - (v + 1 + 2+m->textlen+2); + m->inuse--; + + buf->remove(u, v + 1 - u); + end -= v + 1 - u; + u += mend - (v + 1); +#else + // Insert replacement text + buf->insert(v + 1, m->text, m->textlen); + end += m->textlen; + + // Scan replaced text for further expansion + m->inuse++; + unsigned mend = v + 1 + m->textlen; + expand(buf, v + 1, &mend, marg, marglen); + end += mend - (v + 1 + m->textlen); + m->inuse--; + + buf->remove(u, v + 1 - u); + end -= v + 1 - u; + u += mend - (v + 1); +#endif + mem.free(marg); + //printf("u = %d, end = %d\n", u, end); + //printf("#%.*s#\n", end - u, &buf->data[u]); + continue; + } + } + else + { + // Replace $(NAME) with nothing + buf->remove(u, v + 1 - u); + end -= (v + 1 - u); + continue; + } + } + } + u++; + } + mem.free(arg); + *pend = end; + nest--; +} diff --git a/dmd2/macro.h b/dmd2/macro.h index ecaf96b9..1b8c73aa 100644 --- a/dmd2/macro.h +++ b/dmd2/macro.h @@ -1,44 +1,44 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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. - -#ifndef DMD_MACRO_H -#define DMD_MACRO_H 1 - -#include -#include -#include -#include - -#include "root.h" - - -class Macro -{ - Macro *next; // next in list - - unsigned char *name; // macro name - size_t namelen; // length of macro name - - unsigned char *text; // macro replacement text - size_t textlen; // length of replacement text - - int inuse; // macro is in use (don't expand) - - Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - Macro *search(unsigned char *name, size_t namelen); - - public: - static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - - void expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen); -}; - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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. + +#ifndef DMD_MACRO_H +#define DMD_MACRO_H 1 + +#include +#include +#include +#include + +#include "root.h" + + +class Macro +{ + Macro *next; // next in list + + unsigned char *name; // macro name + size_t namelen; // length of macro name + + unsigned char *text; // macro replacement text + size_t textlen; // length of replacement text + + int inuse; // macro is in use (don't expand) + + Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); + Macro *search(unsigned char *name, size_t namelen); + + public: + static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); + + void expand(OutBuffer *buf, unsigned start, unsigned *pend, + unsigned char *arg, unsigned arglen); +}; + +#endif diff --git a/dmd2/mangle.c b/dmd2/mangle.c index 38875ea9..bda5d326 100644 --- a/dmd2/mangle.c +++ b/dmd2/mangle.c @@ -1,298 +1,298 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include - -#include "root.h" - -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "mtype.h" -#include "attrib.h" -#include "template.h" -#include "id.h" -#include "module.h" - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS -char *cpp_mangle(Dsymbol *s); -#endif - -char *mangle(Declaration *sthis) -{ - OutBuffer buf; - char *id; - Dsymbol *s; - - //printf("::mangle(%s)\n", sthis->toChars()); - s = sthis; - do - { - //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); - if (s->ident) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (s != sthis && fd) - { - id = mangle(fd); - buf.prependstring(id); - goto L1; - } - else - { - id = s->ident->toChars(); - int len = strlen(id); - char tmp[sizeof(len) * 3 + 1]; - buf.prependstring(id); - sprintf(tmp, "%d", len); - buf.prependstring(tmp); - } - } - else - buf.prependstring("0"); - s = s->parent; - } while (s); - -// buf.prependstring("_D"); -L1: - //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); - //printf("sthis->type = %s\n", sthis->type->toChars()); - FuncDeclaration *fd = sthis->isFuncDeclaration(); - if (fd && (fd->needThis() || fd->isNested())) - buf.writeByte(Type::needThisPrefix()); - if (sthis->type->deco) - buf.writestring(sthis->type->deco); - else - { -#ifdef DEBUG - if (!fd->inferRetType) - printf("%s\n", fd->toChars()); -#endif - assert(fd->inferRetType); - } - - id = buf.toChars(); - buf.data = NULL; - return id; -} - -char *Declaration::mangle() -#if __DMC__ - __out(result) - { - int len = strlen(result); - - assert(len > 0); - //printf("mangle: '%s' => '%s'\n", toChars(), result); - for (int i = 0; i < len; i++) - { - assert(result[i] == '_' || - result[i] == '@' || - isalnum(result[i]) || result[i] & 0x80); - } - } - __body -#endif - { - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); - if (!parent || parent->isModule() || linkage == LINKcpp) // if at global scope - { - // If it's not a D declaration, no mangling - switch (linkage) - { - case LINKd: - break; - -#if IN_LLVM - case LINKintrinsic: -#endif - case LINKc: - case LINKwindows: - case LINKpascal: - return ident->toChars(); - - case LINKcpp: -#if CPP_MANGLE - return cpp_mangle(this); -#else - // Windows C++ mangling is done by C++ back end - return ident->toChars(); -#endif - - case LINKdefault: - error("forward declaration"); - return ident->toChars(); - - default: - fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); - assert(0); - } - } - char *p = ::mangle(this); - OutBuffer buf; - buf.writestring("_D"); - buf.writestring(p); - p = buf.toChars(); - buf.data = NULL; - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); - return p; - } - -char *FuncDeclaration::mangle() -#if __DMC__ - __out(result) - { - assert(strlen(result) > 0); - } - __body -#endif - { - if (isMain()) - return (char *)"_Dmain"; - - if (isWinMain() || isDllMain() || ident == Id::tls_get_addr) - return ident->toChars(); - - assert(this); - return Declaration::mangle(); - } - -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *TypedefDeclaration::mangle() -{ - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *ClassDeclaration::mangle() -{ - Dsymbol *parentsave = parent; - - //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident == Id::Exception) - { if (parent->ident == Id::object) - parent = NULL; - } - else if (ident == Id::TypeInfo || -// ident == Id::Exception || - ident == Id::TypeInfo_Struct || - ident == Id::TypeInfo_Class || - ident == Id::TypeInfo_Typedef || - ident == Id::TypeInfo_Tuple || - this == object || - this == classinfo || - this == Module::moduleinfo || - memcmp(ident->toChars(), "TypeInfo_", 9) == 0 - ) - parent = NULL; - - char *id = Dsymbol::mangle(); - parent = parentsave; - return id; -} - - -char *TemplateInstance::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateInstance::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (!tempdecl) - error("is not defined"); - else if (tempdecl->parent) - { - char *p = tempdecl->parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); - return id; -} - -#if IN_LLVM -char *TemplateMixin::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateMixin::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); - return id; -} -#endif - -char *Dsymbol::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("Dsymbol::mangle() '%s'", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); - return id; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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 +#include +#include +#include + +#include "root.h" + +#include "init.h" +#include "declaration.h" +#include "aggregate.h" +#include "mtype.h" +#include "attrib.h" +#include "template.h" +#include "id.h" +#include "module.h" + +#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS +char *cpp_mangle(Dsymbol *s); +#endif + +char *mangle(Declaration *sthis) +{ + OutBuffer buf; + char *id; + Dsymbol *s; + + //printf("::mangle(%s)\n", sthis->toChars()); + s = sthis; + do + { + //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); + if (s->ident) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (s != sthis && fd) + { + id = mangle(fd); + buf.prependstring(id); + goto L1; + } + else + { + id = s->ident->toChars(); + int len = strlen(id); + char tmp[sizeof(len) * 3 + 1]; + buf.prependstring(id); + sprintf(tmp, "%d", len); + buf.prependstring(tmp); + } + } + else + buf.prependstring("0"); + s = s->parent; + } while (s); + +// buf.prependstring("_D"); +L1: + //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); + //printf("sthis->type = %s\n", sthis->type->toChars()); + FuncDeclaration *fd = sthis->isFuncDeclaration(); + if (fd && (fd->needThis() || fd->isNested())) + buf.writeByte(Type::needThisPrefix()); + if (sthis->type->deco) + buf.writestring(sthis->type->deco); + else + { +#ifdef DEBUG + if (!fd->inferRetType) + printf("%s\n", fd->toChars()); +#endif + assert(fd && fd->inferRetType); + } + + id = buf.toChars(); + buf.data = NULL; + return id; +} + +char *Declaration::mangle() +#if __DMC__ + __out(result) + { + int len = strlen(result); + + assert(len > 0); + //printf("mangle: '%s' => '%s'\n", toChars(), result); + for (int i = 0; i < len; i++) + { + assert(result[i] == '_' || + result[i] == '@' || + isalnum(result[i]) || result[i] & 0x80); + } + } + __body +#endif + { + //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); + if (!parent || parent->isModule() || linkage == LINKcpp) // if at global scope + { + // If it's not a D declaration, no mangling + switch (linkage) + { + case LINKd: + break; + +#if IN_LLVM + case LINKintrinsic: +#endif + case LINKc: + case LINKwindows: + case LINKpascal: + return ident->toChars(); + + case LINKcpp: +#if CPP_MANGLE + return cpp_mangle(this); +#else + // Windows C++ mangling is done by C++ back end + return ident->toChars(); +#endif + + case LINKdefault: + error("forward declaration"); + return ident->toChars(); + + default: + fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); + assert(0); + } + } + char *p = ::mangle(this); + OutBuffer buf; + buf.writestring("_D"); + buf.writestring(p); + p = buf.toChars(); + buf.data = NULL; + //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); + return p; + } + +char *FuncDeclaration::mangle() +#if __DMC__ + __out(result) + { + assert(strlen(result) > 0); + } + __body +#endif + { + if (isMain()) + return (char *)"_Dmain"; + + if (isWinMain() || isDllMain() || ident == Id::tls_get_addr) + return ident->toChars(); + + assert(this); + return Declaration::mangle(); + } + +char *StructDeclaration::mangle() +{ + //printf("StructDeclaration::mangle() '%s'\n", toChars()); + return Dsymbol::mangle(); +} + + +char *TypedefDeclaration::mangle() +{ + //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); + return Dsymbol::mangle(); +} + + +char *ClassDeclaration::mangle() +{ + Dsymbol *parentsave = parent; + + //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); + + /* These are reserved to the compiler, so keep simple + * names for them. + */ + if (ident == Id::Exception) + { if (parent->ident == Id::object) + parent = NULL; + } + else if (ident == Id::TypeInfo || +// ident == Id::Exception || + ident == Id::TypeInfo_Struct || + ident == Id::TypeInfo_Class || + ident == Id::TypeInfo_Typedef || + ident == Id::TypeInfo_Tuple || + this == object || + this == classinfo || + this == Module::moduleinfo || + memcmp(ident->toChars(), "TypeInfo_", 9) == 0 + ) + parent = NULL; + + char *id = Dsymbol::mangle(); + parent = parentsave; + return id; +} + + +char *TemplateInstance::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("TemplateInstance::mangle() %s", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (!tempdecl) + error("is not defined"); + else if (tempdecl->parent) + { + char *p = tempdecl->parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); + return id; +} + +#if IN_LLVM +char *TemplateMixin::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("TemplateMixin::mangle() %s", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (parent) + { + char *p = parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); + return id; +} +#endif + +char *Dsymbol::mangle() +{ + OutBuffer buf; + char *id; + +#if 0 + printf("Dsymbol::mangle() '%s'", toChars()); + if (parent) + printf(" parent = %s %s", parent->kind(), parent->toChars()); + printf("\n"); +#endif + id = ident ? ident->toChars() : toChars(); + if (parent) + { + char *p = parent->mangle(); + if (p[0] == '_' && p[1] == 'D') + p += 2; + buf.writestring(p); + } + buf.printf("%zu%s", strlen(id), id); + id = buf.toChars(); + buf.data = NULL; + //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); + return id; +} + + diff --git a/dmd2/mars.c b/dmd2/mars.c index c445fc49..07a8c49d 100644 --- a/dmd2/mars.c +++ b/dmd2/mars.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -36,6 +36,7 @@ #include "expression.h" #include "lexer.h" #include "lib.h" +#include "json.h" #if WINDOWS_SEH #include @@ -60,6 +61,8 @@ Global::Global() hdr_ext = "di"; doc_ext = "html"; ddoc_ext = "ddoc"; + json_ext = "json"; + map_ext = "map"; #if IN_LLVM ll_ext = "ll"; @@ -89,13 +92,13 @@ Global::Global() #endif #endif - copyright = "Copyright (c) 1999-2009 by Digital Mars"; + copyright = "Copyright (c) 1999-2010 by Digital Mars"; written = "written by Walter Bright" #if TARGET_NET "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; #endif ; - version = "v2.032"; + version = "v2.049"; #if IN_LLVM ldc_version = "LDC trunk"; llvm_version = "LLVM 2.8"; @@ -116,11 +119,11 @@ char *Loc::toChars() if (filename) { - buf.printf("%s", filename); + buf.printf("%s", filename); } if (linnum) - buf.printf("(%d)", linnum); + buf.printf("(%d)", linnum); buf.writeByte(0); return (char *)buf.extractData(); } @@ -150,29 +153,34 @@ void error(Loc loc, const char *format, ...) void warning(Loc loc, const char *format, ...) { - if (global.params.warnings && !global.gag) - { - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); - } + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end( ap ); } void verror(Loc loc, const char *format, va_list ap) { if (!global.gag) { - char *p = loc.toChars(); + char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); + if (*p) + fprintf(stdmsg, "%s: ", p); + mem.free(p); - fprintf(stdmsg, "Error: "); - vfprintf(stdmsg, format, ap); - fprintf(stdmsg, "\n"); - fflush(stdmsg); + fprintf(stdmsg, "Error: "); + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); +#if _MSC_VER + fprintf(stdmsg, "%s", tmp.toChars()); +#else + vfprintf(stdmsg, format, ap); +#endif + fprintf(stdmsg, "\n"); + fflush(stdmsg); +//halt(); } global.errors++; } @@ -188,9 +196,19 @@ void vwarning(Loc loc, const char *format, va_list ap) mem.free(p); fprintf(stdmsg, "Warning: "); +#if _MSC_VER + // MS doesn't recognize %zu format + OutBuffer tmp; + tmp.vprintf(format, ap); + fprintf(stdmsg, "%s", tmp.toChars()); +#else vfprintf(stdmsg, format, ap); +#endif fprintf(stdmsg, "\n"); fflush(stdmsg); +//halt(); + if (global.params.warnings == 1) + global.warnings++; // warnings don't count if gagged } } @@ -226,25 +244,20 @@ void halt() void getenv_setargv(const char *envvar, int *pargc, char** *pargv) { - char *env; char *p; - Array *argv; - int argc; - int wildcard; // do wildcard expansion int instring; int slash; char c; - int j; - env = getenv(envvar); + char *env = getenv(envvar); if (!env) - return; + return; - env = mem.strdup(env); // create our own writable copy + env = mem.strdup(env); // create our own writable copy - argc = *pargc; - argv = new Array(); + int argc = *pargc; + Array *argv = new Array(); argv->setDim(argc); int argc_left = 0; @@ -259,83 +272,83 @@ void getenv_setargv(const char *envvar, int *pargc, char** *pargv) argv->setDim(i); break; } else { - argv->data[i] = (void *)(*pargv)[i]; + argv->data[i] = (void *)(*pargv)[i]; } } // HACK to stop required values from command line being drawn from DFLAGS argv->push((char*)""); argc++; - j = 1; // leave argv[0] alone + int j = 1; // leave argv[0] alone while (1) { - wildcard = 1; - switch (*env) - { - case ' ': - case '\t': - env++; - break; + int wildcard = 1; // do wildcard expansion + switch (*env) + { + case ' ': + case '\t': + env++; + break; - case 0: - goto Ldone; + case 0: + goto Ldone; - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; + case '"': + wildcard = 0; + default: + argv->push(env); // append + //argv->insert(j, env); // insert at position j + j++; + argc++; + p = env; + slash = 0; + instring = 0; + c = 0; - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; + while (1) + { + c = *env++; + switch (c) + { + case '"': + p -= (slash >> 1); + if (slash & 1) + { p--; + goto Laddc; + } + instring ^= 1; + slash = 0; + continue; - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; + case ' ': + case '\t': + if (instring) + goto Laddc; + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + break; - case '\\': - slash++; - *p++ = c; - continue; + case '\\': + slash++; + *p++ = c; + continue; - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; + case 0: + *p = 0; + //if (wildcard) + //wildcardexpand(); // not implemented + goto Ldone; - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } + default: + Laddc: + slash = 0; + *p++ = c; + continue; + } + break; + } + } } Ldone: diff --git a/dmd2/mars.h b/dmd2/mars.h index bf34ae9f..c98ebfed 100644 --- a/dmd2/mars.h +++ b/dmd2/mars.h @@ -1,462 +1,479 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_MARS_H -#define DMD_MARS_H - -#ifdef __DMC__ -#pragma once -#endif - -/* -It is very important to use version control macros correctly - the -idea is that host and target are independent. If these are done -correctly, cross compilers can be built. -The host compiler and host operating system are also different, -and are predefined by the host compiler. The ones used in -dmd are: - -Macros defined by the compiler, not the code: - - Compiler: - __DMC__ Digital Mars compiler - _MSC_VER Microsoft compiler - __GNUC__ Gnu compiler - - Host operating system: - _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, - Windows 2000, Win XP, Vista - _WIN64 Windows for AMD64 - linux Linux - __APPLE__ Mac OSX - __FreeBSD__ FreeBSD - __sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary) - -For the target systems, there are the target operating system and -the target object file format: - - Target operating system: - TARGET_WINDOS Covers 32 bit windows and 64 bit windows - TARGET_LINUX Covers 32 and 64 bit linux - TARGET_OSX Covers 32 and 64 bit Mac OSX - TARGET_FREEBSD Covers 32 and 64 bit FreeBSD - TARGET_SOLARIS Covers 32 and 64 bit Solaris - TARGET_NET Covers .Net - - It is expected that the compiler for each platform will be able - to generate 32 and 64 bit code from the same compiler binary. - - Target object module format: - OMFOBJ Intel Object Module Format, used on Windows - ELFOBJ Elf Object Module Format, used on linux, FreeBSD and Solaris - MACHOBJ Mach-O Object Module Format, used on Mac OSX - - There are currently no macros for byte endianness order. - */ - - -#include -#include -#include -#include -#define __STDC_FORMAT_MACROS 1 -#include -#include - -#ifdef __DMC__ -#ifdef DEBUG -#undef assert -#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) -#endif -#endif - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - -#define DMDV1 0 -#define DMDV2 1 // Version 2.0 features -#define BREAKABI 1 // 0 if not ready to break the ABI just yet -#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer -#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN - -// Set if C++ mangling is done by the front end -#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS)) - -/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD and - * TARGET_SOLARIS, which are - * set on the command line via the compiler makefile. - */ - -#if _WIN32 -#define TARGET_WINDOS 1 // Windows dmd generates Windows targets -#define OMFOBJ 1 -#endif - -#if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS -#ifndef ELFOBJ -#define ELFOBJ 1 -#endif -#endif - -#if TARGET_OSX -#ifndef MACHOBJ -#define MACHOBJ 1 -#endif -#endif - - -struct Array; -struct OutBuffer; - -#if IN_LLVM -enum ARCH -{ - ARCHinvalid, - ARCHx86, - ARCHx86_64, - ARCHppc, - ARCHppc_64, - ARCHarm, - ARCHthumb -}; -enum OUTPUTFLAG -{ - OUTPUTFLAGno, - OUTPUTFLAGdefault, // for the .o default - OUTPUTFLAGset // for -output -}; - -enum OS -{ - OSinvalid, - OSLinux, - OSWindows, - OSMacOSX, - OSFreeBSD, - OSSolaris, -}; - -typedef unsigned char ubyte; -#endif - -// Put command line switches in here -struct Param -{ - bool obj; // write object file - bool link; // perform link - bool verbose; // verbose compile - bool vtls; // identify thread local variables - ubyte symdebug; // insert debug symbolic information -#if !IN_LLVM - // LDC uses a different mechanism - bool optimize; // run optimizer - char optimizeLevel; // optimization level -#endif - ARCH cpu; // target CPU - OS os; - bool is64bit; // generate X86_64 bit code - bool isLE; // generate little endian code - bool useDeprecated; // allow use of deprecated features - bool useAssert; // generate runtime code for assert()'s - bool useInvariants; // generate class invariant checks - bool useIn; // generate precondition checks - bool useOut; // generate postcondition checks - bool useArrayBounds; // generate array bounds checks - bool useSwitchError; // check for switches without a default - bool useUnitTests; // generate unittest code - bool useInline; // inline expand functions - bool warnings; // enable warnings - ubyte Dversion; // D version number - char safe; // enforce safe memory model - - char *argv0; // program name - Array *imppath; // array of char*'s of where to look for import modules - Array *fileImppath; // array of char*'s of where to look for file import modules - char *objdir; // .obj file output directory - char *objname; // .obj file output name - - bool doDocComments; // process embedded documentation comments - char *docdir; // write documentation file to docdir directory - char *docname; // write documentation file to docname - Array *ddocfiles; // macro include files for Ddoc - - bool doHdrGeneration; // process embedded documentation comments - char *hdrdir; // write 'header' file to docdir directory - char *hdrname; // write 'header' file to docname - - unsigned debuglevel; // debug level - Array *debugids; // debug identifiers - - unsigned versionlevel; // version level - Array *versionids; // version identifiers - - bool dump_source; - - Array *defaultlibnames; // default libraries for non-debug builds - Array *debuglibnames; // default libraries for debug builds - - const char *xmlname; // filename for XML output - - char *moduleDepsFile; // filename for deps output - OutBuffer *moduleDeps; // contents to be written to deps file - - // Hidden debug switches - bool debuga; - bool debugb; - bool debugc; - bool debugf; - bool debugr; - bool debugw; - bool debugx; - bool debugy; - - bool run; // run resulting executable - - // Linker stuff - Array *objfiles; - Array *linkswitches; - Array *libfiles; - char *deffile; - char *resfile; - char *exefile; - -#if IN_LLVM - // LDC stuff - OUTPUTFLAG output_ll; - OUTPUTFLAG output_bc; - OUTPUTFLAG output_s; - OUTPUTFLAG output_o; - bool llvmAnnotate; - bool useInlineAsm; - bool verbose_cg; - bool useAvailableExternally; - - // target stuff - const char* llvmArch; - const char *targetTriple; - const char *dataLayout; -#endif -}; - -struct Global -{ - const char *mars_ext; - const char *sym_ext; - const char *obj_ext; -#if IN_LLVM -#if _WIN32 - char *obj_ext_alt; -#endif - char *ll_ext; - char *bc_ext; - char *s_ext; -#endif - const char *lib_ext; - const char *doc_ext; // for Ddoc generated files - const char *ddoc_ext; // for Ddoc macro include files - const char *hdr_ext; // for D 'header' import files - const char *copyright; - const char *written; - Array *path; // Array of char*'s which form the import lookup path - Array *filePath; // Array of char*'s which form the file import lookup path - int structalign; - const char *version; -#if IN_LLVM - char *ldc_version; - char *llvm_version; -#endif - - Param params; - unsigned errors; // number of errors reported so far - unsigned gag; // !=0 means gag reporting of errors - - Global(); -}; - -extern Global global; - -/* Set if Windows Structured Exception Handling C extensions are supported. - * Apparently, VC has dropped support for these? - */ -#define WINDOWS_SEH (_WIN32 && __DMC__) - - -#ifdef __DMC__ - typedef _Complex long double complex_t; -#else - #ifndef IN_GCC - #include "complex_t.h" - #endif - #ifdef __APPLE__ - //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" - #endif -#endif - -// Be careful not to care about sign when using dinteger_t -//typedef uint64_t integer_t; -typedef uint64_t dinteger_t; // use this instead of integer_t to - // avoid conflicts with system #include's - -// Signed and unsigned variants -typedef int64_t sinteger_t; -typedef uint64_t uinteger_t; - -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; - -typedef float d_float32; -typedef double d_float64; -typedef long double d_float80; - -typedef d_uns8 d_char; -typedef d_uns16 d_wchar; -typedef d_uns32 d_dchar; - -#ifdef IN_GCC -#include "d-gcc-real.h" -#else -typedef long double real_t; -#endif - -// Modify OutBuffer::writewchar to write the correct size of wchar -#if _WIN32 -#define writewchar writeword -#else -// This needs a configuration test... -#define writewchar write4 -#endif - -#ifdef IN_GCC -#include "d-gcc-complex_t.h" -#endif - -struct Module; - -//typedef unsigned Loc; // file location -struct Loc -{ - const char *filename; - unsigned linnum; - - Loc() - { - linnum = 0; - filename = NULL; - } - - Loc(int x) - { - linnum = x; - filename = NULL; - } - - Loc(Module *mod, unsigned linnum); - - char *toChars(); - bool equals(const Loc& loc); -}; - -#ifndef GCC_SAFE_DMD -#define TRUE 1 -#define FALSE 0 -#endif - -#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry - // in interface vtbl[]'s -#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears - // in the inheritance graph multiple - // times, only one is used - -enum LINK -{ - LINKdefault, - LINKd, - LINKc, - LINKcpp, - LINKwindows, - LINKpascal, - -#if IN_LLVM - LINKintrinsic, -#endif -}; - -enum DYNCAST -{ - DYNCAST_OBJECT, - DYNCAST_EXPRESSION, - DYNCAST_DSYMBOL, - DYNCAST_TYPE, - DYNCAST_IDENTIFIER, - DYNCAST_TUPLE, -}; - -enum MATCH -{ - MATCHnomatch, // no match - MATCHconvert, // match with conversions -#if DMDV2 - MATCHconst, // match with conversion to const -#endif - MATCHexact // exact match -}; - -void warning(Loc loc, const char *format, ...) IS_PRINTF(2); -void vwarning(Loc loc, const char *format, va_list); -void error(Loc loc, const char *format, ...) IS_PRINTF(2); -void verror(Loc loc, const char *format, va_list); -void fatal(); -void err_nomem(); -#if IN_LLVM -void inifile(char *argv0, const char *inifile); -#else -int runLINK(); -void deleteExeFile(); -int runProgram(); -void inifile(const char *argv0, const char *inifile); -#endif -void halt(); -#if !IN_LLVM -void util_progress(); -#endif - -/*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM -#define stdmsg stderr -#else -#define stdmsg stderr -#endif - -#if !IN_LLVM -struct Dsymbol; -struct Library; -struct File; -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); -void obj_append(Dsymbol *s); -void obj_write_deferred(Library *library); -#endif - -#endif /* DMD_MARS_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_MARS_H +#define DMD_MARS_H + +#ifdef __DMC__ +#pragma once +#endif + +/* +It is very important to use version control macros correctly - the +idea is that host and target are independent. If these are done +correctly, cross compilers can be built. +The host compiler and host operating system are also different, +and are predefined by the host compiler. The ones used in +dmd are: + +Macros defined by the compiler, not the code: + + Compiler: + __DMC__ Digital Mars compiler + _MSC_VER Microsoft compiler + __GNUC__ Gnu compiler + + Host operating system: + _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, + Windows 2000, Win XP, Vista + _WIN64 Windows for AMD64 + linux Linux + __APPLE__ Mac OSX + __FreeBSD__ FreeBSD + __sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary) + +For the target systems, there are the target operating system and +the target object file format: + + Target operating system: + TARGET_WINDOS Covers 32 bit windows and 64 bit windows + TARGET_LINUX Covers 32 and 64 bit linux + TARGET_OSX Covers 32 and 64 bit Mac OSX + TARGET_FREEBSD Covers 32 and 64 bit FreeBSD + TARGET_SOLARIS Covers 32 and 64 bit Solaris + TARGET_NET Covers .Net + + It is expected that the compiler for each platform will be able + to generate 32 and 64 bit code from the same compiler binary. + + Target object module format: + OMFOBJ Intel Object Module Format, used on Windows + ELFOBJ Elf Object Module Format, used on linux, FreeBSD and Solaris + MACHOBJ Mach-O Object Module Format, used on Mac OSX + + There are currently no macros for byte endianness order. + */ + + +#include +#include +#include +#include +#define __STDC_FORMAT_MACROS 1 +#include +#include + +#ifdef __DMC__ +#ifdef DEBUG +#undef assert +#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) +#endif +#endif + +#ifdef DEBUG +#define UNITTEST 1 +#endif +void unittests(); + +#ifndef IS_PRINTF +# ifdef __GNUC__ +# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) +# else +# define IS_PRINTF(FMTARG) +# endif +#endif + +#ifdef IN_GCC +/* Changes for the GDC compiler by David Friedman */ +#endif + +#define DMDV1 0 +#define DMDV2 1 // Version 2.0 features +#define BREAKABI 1 // 0 if not ready to break the ABI just yet +#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer +#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN +#define SARRAYVALUE DMDV2 // static arrays are value types +#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class + +// Set if C++ mangling is done by the front end +#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS)) + +/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD and + * TARGET_SOLARIS, which are + * set on the command line via the compiler makefile. + */ + +#if _WIN32 +#define TARGET_WINDOS 1 // Windows dmd generates Windows targets +#define OMFOBJ 1 +#endif + +#if TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS +#ifndef ELFOBJ +#define ELFOBJ 1 +#endif +#endif + +#if TARGET_OSX +#ifndef MACHOBJ +#define MACHOBJ 1 +#endif +#endif + + +struct Array; +struct OutBuffer; + +#if IN_LLVM +enum ARCH +{ + ARCHinvalid, + ARCHx86, + ARCHx86_64, + ARCHppc, + ARCHppc_64, + ARCHarm, + ARCHthumb +}; +enum OUTPUTFLAG +{ + OUTPUTFLAGno, + OUTPUTFLAGdefault, // for the .o default + OUTPUTFLAGset // for -output +}; + +enum OS +{ + OSinvalid, + OSLinux, + OSWindows, + OSMacOSX, + OSFreeBSD, + OSSolaris, +}; + +typedef unsigned char ubyte; +#endif + +// Put command line switches in here +struct Param +{ + bool obj; // write object file + bool link; // perform link + bool verbose; // verbose compile + bool vtls; // identify thread local variables + ubyte symdebug; // insert debug symbolic information +#if !IN_LLVM + // LDC uses a different mechanism + bool optimize; // run optimizer + char optimizeLevel; // optimization level +#endif + ARCH cpu; // target CPU + OS os; + bool is64bit; // generate X86_64 bit code + char map; // generate linker .map file + bool isLE; // generate little endian code + bool useDeprecated; // allow use of deprecated features + bool useAssert; // generate runtime code for assert()'s + bool useInvariants; // generate class invariant checks + bool useIn; // generate precondition checks + bool useOut; // generate postcondition checks + bool useArrayBounds; // generate array bounds checks + bool useSwitchError; // check for switches without a default + bool useUnitTests; // generate unittest code + bool useInline; // inline expand functions + bool warnings; // enable warnings + ubyte Dversion; // D version number + + char *argv0; // program name + Array *imppath; // array of char*'s of where to look for import modules + Array *fileImppath; // array of char*'s of where to look for file import modules + char *objdir; // .obj file output directory + char *objname; // .obj file output name + + bool doDocComments; // process embedded documentation comments + char *docdir; // write documentation file to docdir directory + char *docname; // write documentation file to docname + Array *ddocfiles; // macro include files for Ddoc + + bool doHdrGeneration; // process embedded documentation comments + char *hdrdir; // write 'header' file to docdir directory + char *hdrname; // write 'header' file to docname + + char doXGeneration; // write JSON file + char *xfilename; // write JSON file to xfilename + + unsigned debuglevel; // debug level + Array *debugids; // debug identifiers + + unsigned versionlevel; // version level + Array *versionids; // version identifiers + + bool dump_source; + + Array *defaultlibnames; // default libraries for non-debug builds + Array *debuglibnames; // default libraries for debug builds + + char *moduleDepsFile; // filename for deps output + OutBuffer *moduleDeps; // contents to be written to deps file + + // Hidden debug switches + bool debuga; + bool debugb; + bool debugc; + bool debugf; + bool debugr; + bool debugw; + bool debugx; + bool debugy; + + bool run; // run resulting executable + + // Linker stuff + Array *objfiles; + Array *linkswitches; + Array *libfiles; + char *deffile; + char *resfile; + char *exefile; + char *mapfile; +#if IN_LLVM + // LDC stuff + OUTPUTFLAG output_ll; + OUTPUTFLAG output_bc; + OUTPUTFLAG output_s; + OUTPUTFLAG output_o; + bool llvmAnnotate; + bool useInlineAsm; + bool verbose_cg; + bool useAvailableExternally; + + // target stuff + const char* llvmArch; + const char *targetTriple; + const char *dataLayout; +#endif +}; + +struct Global +{ + const char *mars_ext; + const char *sym_ext; + const char *obj_ext; +#if IN_LLVM +#if _WIN32 + char *obj_ext_alt; +#endif + char *ll_ext; + char *bc_ext; + char *s_ext; +#endif + const char *lib_ext; + const char *dll_ext; + const char *doc_ext; // for Ddoc generated files + const char *ddoc_ext; // for Ddoc macro include files + const char *hdr_ext; // for D 'header' import files + const char *json_ext; // for JSON files + const char *map_ext; // for .map files + const char *copyright; + const char *written; + Array *path; // Array of char*'s which form the import lookup path + Array *filePath; // Array of char*'s which form the file import lookup path + int structalign; + const char *version; +#if IN_LLVM + char *ldc_version; + char *llvm_version; +#endif + + Param params; + unsigned errors; // number of errors reported so far + unsigned warnings; // number of warnings reported so far + unsigned gag; // !=0 means gag reporting of errors & warnings + + Global(); +}; + +extern Global global; + +/* Set if Windows Structured Exception Handling C extensions are supported. + * Apparently, VC has dropped support for these? + */ +#define WINDOWS_SEH (_WIN32 && __DMC__) + + +#ifdef __DMC__ + typedef _Complex long double complex_t; +#else + #ifndef IN_GCC + #include "complex_t.h" + #endif + #ifdef __APPLE__ + //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" + #endif +#endif + +// Be careful not to care about sign when using dinteger_t +//typedef uint64_t integer_t; +typedef uint64_t dinteger_t; // use this instead of integer_t to + // avoid conflicts with system #include's + +// Signed and unsigned variants +typedef int64_t sinteger_t; +typedef uint64_t uinteger_t; + +typedef int8_t d_int8; +typedef uint8_t d_uns8; +typedef int16_t d_int16; +typedef uint16_t d_uns16; +typedef int32_t d_int32; +typedef uint32_t d_uns32; +typedef int64_t d_int64; +typedef uint64_t d_uns64; + +typedef float d_float32; +typedef double d_float64; +typedef long double d_float80; + +typedef d_uns8 d_char; +typedef d_uns16 d_wchar; +typedef d_uns32 d_dchar; + +#ifdef IN_GCC +#include "d-gcc-real.h" +#else +typedef long double real_t; +#endif + +// Modify OutBuffer::writewchar to write the correct size of wchar +#if _WIN32 +#define writewchar writeword +#else +// This needs a configuration test... +#define writewchar write4 +#endif + +#ifdef IN_GCC +#include "d-gcc-complex_t.h" +#endif + +struct Module; + +//typedef unsigned Loc; // file location +struct Loc +{ + const char *filename; + unsigned linnum; + + Loc() + { + linnum = 0; + filename = NULL; + } + + Loc(int x) + { + linnum = x; + filename = NULL; + } + + Loc(Module *mod, unsigned linnum); + + char *toChars(); + bool equals(const Loc& loc); +}; + +#ifndef GCC_SAFE_DMD +#define TRUE 1 +#define FALSE 0 +#endif + +#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry + // in interface vtbl[]'s +#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears + // in the inheritance graph multiple + // times, only one is used + +enum LINK +{ + LINKdefault, + LINKd, + LINKc, + LINKcpp, + LINKwindows, + LINKpascal, + +#if IN_LLVM + LINKintrinsic, +#endif +}; + +enum DYNCAST +{ + DYNCAST_OBJECT, + DYNCAST_EXPRESSION, + DYNCAST_DSYMBOL, + DYNCAST_TYPE, + DYNCAST_IDENTIFIER, + DYNCAST_TUPLE, +}; + +enum MATCH +{ + MATCHnomatch, // no match + MATCHconvert, // match with conversions +#if DMDV2 + MATCHconst, // match with conversion to const +#endif + MATCHexact // exact match +}; + +typedef uint64_t StorageClass; + + +void warning(Loc loc, const char *format, ...) IS_PRINTF(2); +void error(Loc loc, const char *format, ...) IS_PRINTF(2); +void verror(Loc loc, const char *format, va_list); +void vwarning(Loc loc, const char *format, va_list); +void fatal(); +void err_nomem(); +#if IN_LLVM +void inifile(char *argv0, const char *inifile); +#else +int runLINK(); +void deleteExeFile(); +int runProgram(); +const char *inifile(const char *argv0, const char *inifile); +#endif +void halt(); +#if !IN_LLVM +void util_progress(); +#endif + +/*** Where to send error messages ***/ +#if IN_GCC || IN_LLVM +#define stdmsg stderr +#else +#define stdmsg stderr +#endif + +#if !IN_LLVM +struct Dsymbol; +struct Library; +struct File; +void obj_start(char *srcfile); +void obj_end(Library *library, File *objfile); +void obj_append(Dsymbol *s); +void obj_write_deferred(Library *library); +#endif + +const char *importHint(const char *s); + +#endif /* DMD_MARS_H */ diff --git a/dmd2/module.c b/dmd2/module.c index 5dd3ba84..02e1ead5 100644 --- a/dmd2/module.c +++ b/dmd2/module.c @@ -1,1212 +1,1345 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#include "rmem.h" - -#include "mars.h" -#include "module.h" -#include "parse.h" -#include "scope.h" -#include "identifier.h" -#include "id.h" -#include "import.h" -#include "dsymbol.h" -#include "hdrgen.h" -#include "lexer.h" - -#define MARS 1 -#include "html.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -#if IN_LLVM -#include "llvm/Support/CommandLine.h" -#include - -static llvm::cl::opt preservePaths("op", - llvm::cl::desc("Do not strip paths from source file"), - llvm::cl::ZeroOrMore); - -static llvm::cl::opt fqnNames("oq", - llvm::cl::desc("Write object files with fully qualified names"), - llvm::cl::ZeroOrMore); -#endif - -ClassDeclaration *Module::moduleinfo; - -Module *Module::rootModule; -DsymbolTable *Module::modules; -Array Module::amodules; - -Array Module::deferred; // deferred Dsymbol's needing semantic() run on them -unsigned Module::dprogress; - -void Module::init() -{ - modules = new DsymbolTable(); -} - -Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) - : Package(ident) -{ - FileName *srcfilename; -#if IN_DMD - FileName *cfilename; - FileName *hfilename; - FileName *objfilename; - FileName *symfilename; -#endif - -// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); - this->arg = filename; - md = NULL; - errors = 0; - numlines = 0; - members = NULL; - isHtml = 0; - isDocFile = 0; - needmoduleinfo = 0; -#ifdef IN_GCC - strictlyneedmoduleinfo = 0; -#endif - selfimports = 0; - insearch = 0; - searchCacheIdent = NULL; - searchCacheSymbol = NULL; - searchCacheFlags = 0; - semanticstarted = 0; - semanticRun = 0; - decldefs = NULL; - vmoduleinfo = NULL; -#if IN_DMD - massert = NULL; - marray = NULL; - sictor = NULL; - sctor = NULL; - sdtor = NULL; - stest = NULL; - sfilename = NULL; -#endif - root = 0; - importedFrom = NULL; - srcfile = NULL; - objfile = NULL; - docfile = NULL; - hdrfile = NULL; - - debuglevel = 0; - debugids = NULL; - debugidsNot = NULL; - versionlevel = 0; - versionids = NULL; - versionidsNot = NULL; - - macrotable = NULL; - escapetable = NULL; - safe = FALSE; -#if IN-DMD - doppelganger = 0; - cov = NULL; - covb = NULL; -#endif - - srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext) && - !srcfilename->equalsExt(global.hdr_ext) && - !srcfilename->equalsExt("dd")) - { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - { if (!global.params.useDeprecated) - error("html source files is deprecated %s", srcfilename->toChars()); - isHtml = 1; - } - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } - } -#if !IN_LLVM - char *argobj; - if (global.params.objname) - argobj = global.params.objname; - else if (global.params.preservePaths) - argobj = filename; - else - argobj = FileName::name(filename); - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(global.params.objdir, argobj); - } - - if (global.params.objname) - objfilename = new FileName(argobj, 0); - else - objfilename = FileName::forceExt(argobj, global.obj_ext); - - symfilename = FileName::forceExt(filename, global.sym_ext); -#endif - - srcfile = new File(srcfilename); -#if IN_DMD - if (doDocComment) - { - setDocfile(); - } - - if (doHdrGen) - { - setHdrfile(); - } - - objfile = new File(objfilename); - symfile = new File(symfilename); -#endif -#if IN_LLVM - // LDC - llvmForceLogging = false; - this->doDocComment = doDocComment; - this->doHdrGen = doHdrGen; -#endif -} -#if IN_LLVM -File* Module::buildFilePath(const char* forcename, const char* path, const char* ext) -{ - const char *argobj; - if (forcename) - argobj = forcename; - else - { - if (preservePaths) - argobj = (char*)this->arg; - else - argobj = FileName::name((char*)this->arg); - - if (fqnNames) - { - if(md) - argobj = FileName::replaceName((char*)argobj, md->toChars()); - else - argobj = FileName::replaceName((char*)argobj, toChars()); - - // add ext, otherwise forceExt will make nested.module into nested.bc - size_t len = strlen(argobj); - size_t extlen = strlen(ext); - char* s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s, argobj, len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - s[len+1+extlen] = 0; - argobj = s; - } - } - - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(path, argobj); - } - - FileName::ensurePathExists(FileName::path(argobj)); - -// always append the extension! otherwise hard to make output switches consistent -// if (forcename) -// return new File(argobj); -// else - // allow for .o and .obj on windows -#if _WIN32 - if (ext == global.params.objdir && FileName::ext(argobj) - && stricmp(FileName::ext(argobj), global.obj_ext_alt) == 0) - return new File((char*)argobj); -#endif - return new File(FileName::forceExt(argobj, ext)); -} -#endif -#if IN_DMD -void Module::setDocfile() -{ - FileName *docfilename; - char *argdoc; - - if (global.params.docname) - argdoc = global.params.docname; - else if (global.params.preservePaths) - argdoc = (char *)arg; - else - argdoc = FileName::name((char *)arg); - if (!FileName::absolute(argdoc)) - { //FileName::ensurePathExists(global.params.docdir); - argdoc = FileName::combine(global.params.docdir, argdoc); - } - if (global.params.docname) - docfilename = new FileName(argdoc, 0); - else - docfilename = FileName::forceExt(argdoc, global.doc_ext); - - if (docfilename->equals(srcfile->name)) - { error("Source file and documentation file have same name '%s'", srcfile->name->str); - fatal(); - } - - docfile = new File(docfilename); -} - -void Module::setHdrfile() -{ - FileName *hdrfilename; - char *arghdr; - - if (global.params.hdrname) - arghdr = global.params.hdrname; - else if (global.params.preservePaths) - arghdr = (char *)arg; - else - arghdr = FileName::name((char *)arg); - if (!FileName::absolute(arghdr)) - { //FileName::ensurePathExists(global.params.hdrdir); - arghdr = FileName::combine(global.params.hdrdir, arghdr); - } - if (global.params.hdrname) - hdrfilename = new FileName(arghdr, 0); - else - hdrfilename = FileName::forceExt(arghdr, global.hdr_ext); - - if (hdrfilename->equals(srcfile->name)) - { error("Source file and 'header' file have same name '%s'", srcfile->name->str); - fatal(); - } - - hdrfile = new File(hdrfilename); -} -#endif - -#if IN_LLVM - -// LDC -static void check_and_add_output_file(Module* NewMod, const std::string& str) -{ - typedef std::map map_t; - static map_t files; - - map_t::iterator i = files.find(str); - if (i != files.end()) - { - Module* ThisMod = i->second; - error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", - str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); - fatal(); - } - files.insert(std::make_pair(str, NewMod)); -} - -void Module::buildTargetFiles(bool singleObj) -{ - if(objfile && - (!doDocComment || docfile) && - (!doHdrGen || hdrfile)) - return; - - if(!objfile) - { - if (global.params.output_bc) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); - else if (global.params.output_ll) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); - else if (global.params.output_s) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); - else - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.obj_ext); - } - if(doDocComment && !docfile) - docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); - if(doHdrGen && !hdrfile) - hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); - - // safety check: never allow obj, doc or hdr file to have the source file's name - if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output object files with the same name as the source file are forbidden"); - fatal(); - } - if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output doc files with the same name as the source file are forbidden"); - fatal(); - } - if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output header files with the same name as the source file are forbidden"); - fatal(); - } - - // LDC - // another safety check to make sure we don't overwrite previous output files - if (!singleObj) - check_and_add_output_file(this, objfile->name->str); - if (docfile) - check_and_add_output_file(this, docfile->name->str); - if (hdrfile) - check_and_add_output_file(this, hdrfile->name->str); -} - -#endif - -void Module::deleteObjFile() -{ - if (global.params.obj) - objfile->remove(); - //if (global.params.llvmBC) - //bcfile->remove(); - if (doDocComment && docfile) - docfile->remove(); -} - -Module::~Module() -{ -} - -const char *Module::kind() -{ - return "module"; -} - -Module *Module::load(Loc loc, Array *packages, Identifier *ident) -{ Module *m; - char *filename; - - //printf("Module::load(ident = '%s')\n", ident->toChars()); - - // Build module filename by turning: - // foo.bar.baz - // into: - // foo\bar\baz - filename = ident->toChars(); - if (packages && packages->dim) - { - OutBuffer buf; - int i; - - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; - - buf.writestring(pid->toChars()); -#if _WIN32 - buf.writeByte('\\'); -#else - buf.writeByte('/'); -#endif - } - buf.writestring(filename); - buf.writeByte(0); - filename = (char *)buf.extractData(); - } - - m = new Module(filename, ident, 0, 0); - m->loc = loc; - - /* Search along global.path for .di file, then .d file. - */ - char *result = NULL; - FileName *fdi = FileName::forceExt(filename, global.hdr_ext); - FileName *fd = FileName::forceExt(filename, global.mars_ext); - char *sdi = fdi->toChars(); - char *sd = fd->toChars(); - - if (FileName::exists(sdi)) - result = sdi; - else if (FileName::exists(sd)) - result = sd; - else if (FileName::absolute(filename)) - ; - else if (!global.path) - ; - else - { - for (size_t i = 0; i < global.path->dim; i++) - { - char *p = (char *)global.path->data[i]; - char *n = FileName::combine(p, sdi); - if (FileName::exists(n)) - { result = n; - break; - } - mem.free(n); - n = FileName::combine(p, sd); - if (FileName::exists(n)) - { result = n; - break; - } - mem.free(n); - } - } - if (result) - m->srcfile = new File(result); - - if (global.params.verbose) - { - printf("import "); - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; - printf("%s.", pid->toChars()); - } - } - printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); - } - - m->read(loc); - m->parse(); - -#ifdef IN_GCC - d_gcc_magic_module(m); -#endif - - return m; -} - -void Module::read(Loc loc) -{ - //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); - if (srcfile->read()) - { error(loc, "cannot read file '%s'", srcfile->toChars()); - fatal(); - } -} - -inline unsigned readwordLE(unsigned short *p) -{ -#if __I86__ - return *p; -#else - return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; -#endif -} - -inline unsigned readwordBE(unsigned short *p) -{ - return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; -} - -inline unsigned readlongLE(unsigned *p) -{ -#if __I86__ - return *p; -#else - return ((unsigned char *)p)[0] | - (((unsigned char *)p)[1] << 8) | - (((unsigned char *)p)[2] << 16) | - (((unsigned char *)p)[3] << 24); -#endif -} - -inline unsigned readlongBE(unsigned *p) -{ - return ((unsigned char *)p)[3] | - (((unsigned char *)p)[2] << 8) | - (((unsigned char *)p)[1] << 16) | - (((unsigned char *)p)[0] << 24); -} - -#if IN_GCC -void Module::parse(bool dump_source) -#else -void Module::parse() -#endif -{ char *srcname; - unsigned char *buf; - unsigned buflen; - unsigned le; - unsigned bom; - - //printf("Module::parse()\n"); - - srcname = srcfile->name->toChars(); - //printf("Module::parse(srcname = '%s')\n", srcname); - - buf = srcfile->buffer; - buflen = srcfile->len; - - if (buflen >= 2) - { - /* Convert all non-UTF-8 formats to UTF-8. - * BOM : http://www.unicode.org/faq/utf_bom.html - * 00 00 FE FF UTF-32BE, big-endian - * FF FE 00 00 UTF-32LE, little-endian - * FE FF UTF-16BE, big-endian - * FF FE UTF-16LE, little-endian - * EF BB BF UTF-8 - */ - - bom = 1; // assume there's a BOM - if (buf[0] == 0xFF && buf[1] == 0xFE) - { - if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - - Lutf32: - OutBuffer dbuf; - unsigned *pu = (unsigned *)(buf); - unsigned *pumax = &pu[buflen / 4]; - - if (buflen & 3) - { error("odd length of UTF-32 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 4); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readlongLE(pu) : readlongBE(pu); - if (u & ~0x7F) - { - if (u > 0x10FFFF) - { error("UTF-32 value %08x greater than 0x10FFFF", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - else - { // UTF-16LE (X86) - // Convert it to UTF-8 - le = 1; - - Lutf16: - OutBuffer dbuf; - unsigned short *pu = (unsigned short *)(buf); - unsigned short *pumax = &pu[buflen / 2]; - - if (buflen & 1) - { error("odd length of UTF-16 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 2); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readwordLE(pu) : readwordBE(pu); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (++pu > pumax) - { error("surrogate UTF-16 high value %04x at EOF", u); - fatal(); - } - u2 = le ? readwordLE(pu) : readwordBE(pu); - if (u2 < 0xDC00 || u2 > 0xDFFF) - { error("surrogate UTF-16 low value %04x out of range", u2); - fatal(); - } - u = (u - 0xD7C0) << 10; - u |= (u2 - 0xDC00); - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { error("unpaired surrogate UTF-16 value %04x", u); - fatal(); - } - else if (u == 0xFFFE || u == 0xFFFF) - { error("illegal UTF-16 value %04x", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - } - else if (buf[0] == 0xFE && buf[1] == 0xFF) - { // UTF-16BE - le = 0; - goto Lutf16; - } - else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) - { // UTF-32BE - le = 0; - goto Lutf32; - } - else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) - { // UTF-8 - - buf += 3; - buflen -= 3; - } - else - { - /* There is no BOM. Make use of Arcane Jill's insight that - * the first char of D source must be ASCII to - * figure out the encoding. - */ - - bom = 0; - if (buflen >= 4) - { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - goto Lutf32; - } - else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) - { // UTF-32BE - le = 0; - goto Lutf32; - } - } - if (buflen >= 2) - { - if (buf[1] == 0) - { // UTF-16LE - le = 1; - goto Lutf16; - } - else if (buf[0] == 0) - { // UTF-16BE - le = 0; - goto Lutf16; - } - } - - // It's UTF-8 - if (buf[0] >= 0x80) - { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); - fatal(); - } - } - } - -#ifdef IN_GCC - // dump utf-8 encoded source - if (dump_source) - { // %% srcname could contain a path ... - d_gcc_dump_source(srcname, "utf-8", buf, buflen); - } -#endif - - /* If it starts with the string "Ddoc", then it's a documentation - * source file. - */ - if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) - { - comment = buf + 4; - isDocFile = 1; -#if IN_DMD - if (!docfile) - setDocfile(); -#endif - return; - } - if (isHtml) - { - OutBuffer *dbuf = new OutBuffer(); - Html h(srcname, buf, buflen); - h.extractCode(dbuf); - buf = dbuf->data; - buflen = dbuf->offset; -#ifdef IN_GCC - // dump extracted source - if (dump_source) - d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); -#endif - } - Parser p(this, buf, buflen, docfile != NULL); - p.nextToken(); - members = p.parseModule(); - md = p.md; - numlines = p.loc.linnum; - - DsymbolTable *dst; - - if (md) - { this->ident = md->id; - this->safe = md->safe; - dst = Package::resolve(md->packages, &this->parent, NULL); - } - else - { - dst = modules; - - /* Check to see if module name is a valid identifier - */ - if (!Lexer::isValidIdentifier(this->ident->toChars())) - error("has non-identifier characters in filename, use module declaration instead"); - } - - // Update global list of modules - if (!dst->insert(this)) - { - if (md) - error(loc, "is in multiple packages %s", md->toChars()); - else - error(loc, "is in multiple defined"); - } - else - { - amodules.push(this); - } -} - -void Module::semantic(Scope* unused_sc) -{ int i; - - if (semanticstarted) - return; - - //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - semanticstarted = 1; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope - - //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); - - // Add import of "object" if this module isn't "object" - if (ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } - - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(NULL, sc->scopesym, 1); - } - - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - for (i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->setScope(sc); - } - - // Pass 1 semantic routines: do public side of the definition - for (i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - - //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); - s->semantic(sc); - runDeferredSemantic(); - } - - sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 - semanticRun = semanticstarted; - //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); -} - -void Module::semantic2(Scope* unused_sc) -{ int i; - - if (deferred.dim) - { - for (int i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = (Dsymbol *)deferred.data[i]; - - sd->error("unable to resolve forward reference in definition"); - } - return; - } - //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); - if (semanticstarted >= 2) - return; - assert(semanticstarted == 1); - semanticstarted = 2; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope - //printf("Module = %p\n", sc.scopesym); - - // Pass 2 semantic routines: do initializers and function bodies - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; - s->semantic2(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; - //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); -} - -void Module::semantic3(Scope* unused_sc) -{ int i; - - //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); - if (semanticstarted >= 3) - return; - assert(semanticstarted == 2); - semanticstarted = 3; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = Scope::createGlobal(this); // create root scope - //printf("Module = %p\n", sc.scopesym); - - // Pass 3 semantic routines: do initializers and function bodies - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; - //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); - s->semantic3(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; -} - -void Module::inlineScan() -{ int i; - - if (semanticstarted >= 4) - return; - assert(semanticstarted == 3); - semanticstarted = 4; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - //printf("Module = %p\n", sc.scopesym); - - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; - //if (global.params.verbose) - //printf("inline scan symbol %s\n", s->toChars()); - - s->inlineScan(); - } - semanticRun = semanticstarted; -} - -/**************************************************** - */ - -// is this used anywhere? -/* -void Module::gensymfile() -{ - OutBuffer buf; - HdrGenState hgs; - - //printf("Module::gensymfile()\n"); - - buf.printf("// Sym file generated from '%s'", srcfile->toChars()); - buf.writenl(); - - for (int i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - - s->toCBuffer(&buf, &hgs); - } - - // Transfer image to file - symfile->setbuffer(buf.data, buf.offset); - buf.data = NULL; - - symfile->writev(); -}*/ - -/********************************** - * Determine if we need to generate an instance of ModuleInfo - * for this Module. - */ - -int Module::needModuleInfo() -{ - return needmoduleinfo; -} - -Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) -{ - /* Since modules can be circularly referenced, - * need to stop infinite recursive searches. - */ - - //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); - Dsymbol *s; - if (insearch) - s = NULL; - else if (searchCacheIdent == ident && searchCacheFlags == flags) - s = searchCacheSymbol; - else - { - insearch = 1; - s = ScopeDsymbol::search(loc, ident, flags); - insearch = 0; - - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; - } - return s; -} - -/******************************************* - * Can't run semantic on s now, try again later. - */ - -void Module::addDeferredSemantic(Dsymbol *s) -{ - // Don't add it if it is already there - for (int i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = (Dsymbol *)deferred.data[i]; - - if (sd == s) - return; - } - - //printf("Module::addDeferredSemantic('%s')\n", s->toChars()); - deferred.push(s); -} - - -/****************************************** - * Run semantic() on deferred symbols. - */ - -void Module::runDeferredSemantic() -{ - size_t len; - - static int nested; - if (nested) - return; - //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); - nested++; - - do - { - dprogress = 0; - len = deferred.dim; - if (!len) - break; - - Dsymbol **todo; - Dsymbol *tmp; - if (len == 1) - { - todo = &tmp; - } - else - { - todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); - assert(todo); - } - memcpy(todo, deferred.data, len * sizeof(Dsymbol *)); - deferred.setDim(0); - - for (int i = 0; i < len; i++) - { - Dsymbol *s = todo[i]; - - s->semantic(NULL); - //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars()); - } - //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); - } while (deferred.dim < len || dprogress); // while making progress - nested--; - //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); -} - -/************************************ - * Recursively look at every module this module imports, - * return TRUE if it imports m. - * Can be used to detect circular imports. - */ - -int Module::imports(Module *m) -{ - //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); - int aimports_dim = aimports.dim; -#if 0 - for (int i = 0; i < aimports.dim; i++) - { Module *mi = (Module *)aimports.data[i]; - printf("\t[%d] %s\n", i, mi->toChars()); - } -#endif - for (int i = 0; i < aimports.dim; i++) - { Module *mi = (Module *)aimports.data[i]; - if (mi == m) - return TRUE; - if (!mi->insearch) - { - mi->insearch = 1; - int r = mi->imports(m); - if (r) - return r; - } - } - return FALSE; -} - -/************************************* - * Return !=0 if module imports itself. - */ - -int Module::selfImports() -{ - //printf("Module::selfImports() %s\n", toChars()); - if (!selfimports) - { - for (int i = 0; i < amodules.dim; i++) - { Module *mi = (Module *)amodules.data[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - - selfimports = imports(this) + 1; - - for (int i = 0; i < amodules.dim; i++) - { Module *mi = (Module *)amodules.data[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - } - return selfimports - 1; -} - - -/* =========================== ModuleDeclaration ===================== */ - -ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id, bool safe) -{ - this->packages = packages; - this->id = id; - this->safe = safe; -} - -char *ModuleDeclaration::toChars() -{ - OutBuffer buf; - int i; - - if (packages && packages->dim) - { - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; - - buf.writestring(pid->toChars()); - buf.writeByte('.'); - } - } - buf.writestring(id->toChars()); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* =========================== Package ===================== */ - -Package::Package(Identifier *ident) - : ScopeDsymbol(ident) -{ -} - - -const char *Package::kind() -{ - return "package"; -} - - -DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg) -{ - DsymbolTable *dst = Module::modules; - Dsymbol *parent = NULL; - - //printf("Package::resolve()\n"); - if (ppkg) - *ppkg = NULL; - - if (packages) - { int i; - - for (i = 0; i < packages->dim; i++) - { Identifier *pid = (Identifier *)packages->data[i]; - Dsymbol *p; - - p = dst->lookup(pid); - if (!p) - { - p = new Package(pid); - dst->insert(p); - p->parent = parent; - ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); - } - else - { - assert(p->isPackage()); -#if TARGET_NET //dot net needs modules and packages with same name -#else - if (p->isModule()) - { p->error("module and package have the same name"); - fatal(); - break; - } -#endif - } - parent = p; - dst = ((Package *)p)->symtab; - if (ppkg && !*ppkg) - *ppkg = (Package *)p; - } - if (pparent) - { - *pparent = parent; - } - } - return dst; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include + +#if (defined (__SVR4) && defined (__sun)) +#include +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include +#endif + +#if IN_GCC +#include "gdc_alloca.h" +#endif + +#include "rmem.h" + +#include "mars.h" +#include "module.h" +#include "parse.h" +#include "scope.h" +#include "identifier.h" +#include "id.h" +#include "import.h" +#include "dsymbol.h" +#include "hdrgen.h" +#include "lexer.h" + +#define MARS 1 +#include "html.h" + +#ifdef IN_GCC +#include "d-dmd-gcc.h" +#endif + +#if IN_LLVM +#include "llvm/Support/CommandLine.h" +#include + +static llvm::cl::opt preservePaths("op", + llvm::cl::desc("Do not strip paths from source file"), + llvm::cl::ZeroOrMore); + +static llvm::cl::opt fqnNames("oq", + llvm::cl::desc("Write object files with fully qualified names"), + llvm::cl::ZeroOrMore); +#endif + +ClassDeclaration *Module::moduleinfo; + +Module *Module::rootModule; +DsymbolTable *Module::modules; +Array Module::amodules; + +Array Module::deferred; // deferred Dsymbol's needing semantic() run on them +unsigned Module::dprogress; + +void Module::init() +{ + modules = new DsymbolTable(); +} + +Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) + : Package(ident) +{ + FileName *srcfilename; +#if IN_DMD + FileName *cfilename; + FileName *hfilename; + FileName *objfilename; + FileName *symfilename; +#endif + +// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); + this->arg = filename; + md = NULL; + errors = 0; + numlines = 0; + members = NULL; + isHtml = 0; + isDocFile = 0; + needmoduleinfo = 0; +#ifdef IN_GCC + strictlyneedmoduleinfo = 0; +#endif + selfimports = 0; + insearch = 0; + searchCacheIdent = NULL; + searchCacheSymbol = NULL; + searchCacheFlags = 0; + semanticstarted = 0; + semanticRun = 0; + decldefs = NULL; + vmoduleinfo = NULL; +#if IN_DMD + massert = NULL; + munittest = NULL; + marray = NULL; + sictor = NULL; + sctor = NULL; + sdtor = NULL; + ssharedctor = NULL; + sshareddtor = NULL; + stest = NULL; + sfilename = NULL; +#endif + root = 0; + importedFrom = NULL; + srcfile = NULL; + objfile = NULL; + docfile = NULL; + hdrfile = NULL; + + debuglevel = 0; + debugids = NULL; + debugidsNot = NULL; + versionlevel = 0; + versionids = NULL; + versionidsNot = NULL; + + macrotable = NULL; + escapetable = NULL; + safe = FALSE; +#if IN-DMD + doppelganger = 0; + cov = NULL; + covb = NULL; +#endif + + nameoffset = 0; + namelen = 0; + + srcfilename = FileName::defaultExt(filename, global.mars_ext); + if (!srcfilename->equalsExt(global.mars_ext) && + !srcfilename->equalsExt(global.hdr_ext) && + !srcfilename->equalsExt("dd")) + { + if (srcfilename->equalsExt("html") || + srcfilename->equalsExt("htm") || + srcfilename->equalsExt("xhtml")) + { if (!global.params.useDeprecated) + error("html source files is deprecated %s", srcfilename->toChars()); + isHtml = 1; + } + else + { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + fatal(); + } + } +#if !IN_LLVM + char *argobj; + if (global.params.objname) + argobj = global.params.objname; +#if 0 + else if (global.params.preservePaths) + argobj = filename; + else + argobj = FileName::name(filename); + if (!FileName::absolute(argobj)) + { + argobj = FileName::combine(global.params.objdir, argobj); + } +#else // Bugzilla 3547 + else + { + if (global.params.preservePaths) + argobj = filename; + else + argobj = FileName::name(filename); + if (!FileName::absolute(argobj)) + { + argobj = FileName::combine(global.params.objdir, argobj); + } + } +#endif + + if (global.params.objname) + objfilename = new FileName(argobj, 0); + else + objfilename = FileName::forceExt(argobj, global.obj_ext); + + symfilename = FileName::forceExt(filename, global.sym_ext); +#endif + + srcfile = new File(srcfilename); +#if IN_DMD + if (doDocComment) + { + setDocfile(); + } + + if (doHdrGen) + { + setHdrfile(); + } + + objfile = new File(objfilename); + symfile = new File(symfilename); +#endif +#if IN_LLVM + // LDC + llvmForceLogging = false; + this->doDocComment = doDocComment; + this->doHdrGen = doHdrGen; +#endif +} +#if IN_LLVM +File* Module::buildFilePath(const char* forcename, const char* path, const char* ext) +{ + const char *argobj; + if (forcename) + argobj = forcename; + else + { + if (preservePaths) + argobj = (char*)this->arg; + else + argobj = FileName::name((char*)this->arg); + + if (fqnNames) + { + if(md) + argobj = FileName::replaceName((char*)argobj, md->toChars()); + else + argobj = FileName::replaceName((char*)argobj, toChars()); + + // add ext, otherwise forceExt will make nested.module into nested.bc + size_t len = strlen(argobj); + size_t extlen = strlen(ext); + char* s = (char *)alloca(len + 1 + extlen + 1); + memcpy(s, argobj, len); + s[len] = '.'; + memcpy(s + len + 1, ext, extlen + 1); + s[len+1+extlen] = 0; + argobj = s; + } + } + + if (!FileName::absolute(argobj)) + { + argobj = FileName::combine(path, argobj); + } + + FileName::ensurePathExists(FileName::path(argobj)); + +// always append the extension! otherwise hard to make output switches consistent +// if (forcename) +// return new File(argobj); +// else + // allow for .o and .obj on windows +#if _WIN32 + if (ext == global.params.objdir && FileName::ext(argobj) + && stricmp(FileName::ext(argobj), global.obj_ext_alt) == 0) + return new File((char*)argobj); +#endif + return new File(FileName::forceExt(argobj, ext)); +} +#endif +#if IN_DMD +void Module::setDocfile() +{ + FileName *docfilename; + char *argdoc; + + if (global.params.docname) + argdoc = global.params.docname; + else if (global.params.preservePaths) + argdoc = (char *)arg; + else + argdoc = FileName::name((char *)arg); + if (!FileName::absolute(argdoc)) + { //FileName::ensurePathExists(global.params.docdir); + argdoc = FileName::combine(global.params.docdir, argdoc); + } + if (global.params.docname) + docfilename = new FileName(argdoc, 0); + else + docfilename = FileName::forceExt(argdoc, global.doc_ext); + + if (docfilename->equals(srcfile->name)) + { error("Source file and documentation file have same name '%s'", srcfile->name->str); + fatal(); + } + + docfile = new File(docfilename); +} + +void Module::setHdrfile() +{ + FileName *hdrfilename; + char *arghdr; + + if (global.params.hdrname) + arghdr = global.params.hdrname; + else if (global.params.preservePaths) + arghdr = (char *)arg; + else + arghdr = FileName::name((char *)arg); + if (!FileName::absolute(arghdr)) + { //FileName::ensurePathExists(global.params.hdrdir); + arghdr = FileName::combine(global.params.hdrdir, arghdr); + } + if (global.params.hdrname) + hdrfilename = new FileName(arghdr, 0); + else + hdrfilename = FileName::forceExt(arghdr, global.hdr_ext); + + if (hdrfilename->equals(srcfile->name)) + { error("Source file and 'header' file have same name '%s'", srcfile->name->str); + fatal(); + } + + hdrfile = new File(hdrfilename); +} +#endif + +#if IN_LLVM + +// LDC +static void check_and_add_output_file(Module* NewMod, const std::string& str) +{ + typedef std::map map_t; + static map_t files; + + map_t::iterator i = files.find(str); + if (i != files.end()) + { + Module* ThisMod = i->second; + error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", + str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); + fatal(); + } + files.insert(std::make_pair(str, NewMod)); +} + +void Module::buildTargetFiles(bool singleObj) +{ + if(objfile && + (!doDocComment || docfile) && + (!doHdrGen || hdrfile)) + return; + + if(!objfile) + { + if (global.params.output_bc) + objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); + else if (global.params.output_ll) + objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); + else if (global.params.output_s) + objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); + else + objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.obj_ext); + } + if(doDocComment && !docfile) + docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); + if(doHdrGen && !hdrfile) + hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); + + // safety check: never allow obj, doc or hdr file to have the source file's name + if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) + { + error("Output object files with the same name as the source file are forbidden"); + fatal(); + } + if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) + { + error("Output doc files with the same name as the source file are forbidden"); + fatal(); + } + if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) + { + error("Output header files with the same name as the source file are forbidden"); + fatal(); + } + + // LDC + // another safety check to make sure we don't overwrite previous output files + if (!singleObj) + check_and_add_output_file(this, objfile->name->str); + if (docfile) + check_and_add_output_file(this, docfile->name->str); + if (hdrfile) + check_and_add_output_file(this, hdrfile->name->str); +} + +#endif + +void Module::deleteObjFile() +{ + if (global.params.obj) + objfile->remove(); + //if (global.params.llvmBC) + //bcfile->remove(); + if (doDocComment && docfile) + docfile->remove(); +} + +Module::~Module() +{ +} + +const char *Module::kind() +{ + return "module"; +} + +Module *Module::load(Loc loc, Array *packages, Identifier *ident) +{ Module *m; + char *filename; + + //printf("Module::load(ident = '%s')\n", ident->toChars()); + + // Build module filename by turning: + // foo.bar.baz + // into: + // foo\bar\baz + filename = ident->toChars(); + if (packages && packages->dim) + { + OutBuffer buf; + int i; + + for (i = 0; i < packages->dim; i++) + { Identifier *pid = (Identifier *)packages->data[i]; + + buf.writestring(pid->toChars()); +#if _WIN32 + buf.writeByte('\\'); +#else + buf.writeByte('/'); +#endif + } + buf.writestring(filename); + buf.writeByte(0); + filename = (char *)buf.extractData(); + } + + m = new Module(filename, ident, 0, 0); + m->loc = loc; + + /* Search along global.path for .di file, then .d file. + */ + char *result = NULL; + FileName *fdi = FileName::forceExt(filename, global.hdr_ext); + FileName *fd = FileName::forceExt(filename, global.mars_ext); + char *sdi = fdi->toChars(); + char *sd = fd->toChars(); + + if (FileName::exists(sdi)) + result = sdi; + else if (FileName::exists(sd)) + result = sd; + else if (FileName::absolute(filename)) + ; + else if (!global.path) + ; + else + { + for (size_t i = 0; i < global.path->dim; i++) + { + char *p = (char *)global.path->data[i]; + char *n = FileName::combine(p, sdi); + if (FileName::exists(n)) + { result = n; + break; + } + mem.free(n); + n = FileName::combine(p, sd); + if (FileName::exists(n)) + { result = n; + break; + } + mem.free(n); + } + } + if (result) + m->srcfile = new File(result); + + if (global.params.verbose) + { + printf("import "); + if (packages) + { + for (size_t i = 0; i < packages->dim; i++) + { Identifier *pid = (Identifier *)packages->data[i]; + printf("%s.", pid->toChars()); + } + } + printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); + } + + m->read(loc); + m->parse(); + +#ifdef IN_GCC + d_gcc_magic_module(m); +#endif + + return m; +} + +void Module::read(Loc loc) +{ + //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); + if (srcfile->read()) + { error(loc, "is in file '%s' which cannot be read", srcfile->toChars()); + if (!global.gag) + { /* Print path + */ + if (global.path) + { + for (int i = 0; i < global.path->dim; i++) + { + char *p = (char *)global.path->data[i]; + fprintf(stdmsg, "import path[%d] = %s\n", i, p); + } + } + else + fprintf(stdmsg, "Specify path to file '%s' with -I switch\n", srcfile->toChars()); + } + fatal(); + } +} + +inline unsigned readwordLE(unsigned short *p) +{ +#if __I86__ + return *p; +#else + return (((unsigned char *)p)[1] << 8) | ((unsigned char *)p)[0]; +#endif +} + +inline unsigned readwordBE(unsigned short *p) +{ + return (((unsigned char *)p)[0] << 8) | ((unsigned char *)p)[1]; +} + +inline unsigned readlongLE(unsigned *p) +{ +#if __I86__ + return *p; +#else + return ((unsigned char *)p)[0] | + (((unsigned char *)p)[1] << 8) | + (((unsigned char *)p)[2] << 16) | + (((unsigned char *)p)[3] << 24); +#endif +} + +inline unsigned readlongBE(unsigned *p) +{ + return ((unsigned char *)p)[3] | + (((unsigned char *)p)[2] << 8) | + (((unsigned char *)p)[1] << 16) | + (((unsigned char *)p)[0] << 24); +} + +#if IN_GCC +void Module::parse(bool dump_source) +#else +void Module::parse() +#endif +{ char *srcname; + unsigned char *buf; + unsigned buflen; + unsigned le; + unsigned bom; + + //printf("Module::parse()\n"); + + srcname = srcfile->name->toChars(); + //printf("Module::parse(srcname = '%s')\n", srcname); + + buf = srcfile->buffer; + buflen = srcfile->len; + + if (buflen >= 2) + { + /* Convert all non-UTF-8 formats to UTF-8. + * BOM : http://www.unicode.org/faq/utf_bom.html + * 00 00 FE FF UTF-32BE, big-endian + * FF FE 00 00 UTF-32LE, little-endian + * FE FF UTF-16BE, big-endian + * FF FE UTF-16LE, little-endian + * EF BB BF UTF-8 + */ + + bom = 1; // assume there's a BOM + if (buf[0] == 0xFF && buf[1] == 0xFE) + { + if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) + { // UTF-32LE + le = 1; + + Lutf32: + OutBuffer dbuf; + unsigned *pu = (unsigned *)(buf); + unsigned *pumax = &pu[buflen / 4]; + + if (buflen & 3) + { error("odd length of UTF-32 char source %u", buflen); + fatal(); + } + + dbuf.reserve(buflen / 4); + for (pu += bom; pu < pumax; pu++) + { unsigned u; + + u = le ? readlongLE(pu) : readlongBE(pu); + if (u & ~0x7F) + { + if (u > 0x10FFFF) + { error("UTF-32 value %08x greater than 0x10FFFF", u); + fatal(); + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); // add 0 as sentinel for scanner + buflen = dbuf.offset - 1; // don't include sentinel in count + buf = (unsigned char *) dbuf.extractData(); + } + else + { // UTF-16LE (X86) + // Convert it to UTF-8 + le = 1; + + Lutf16: + OutBuffer dbuf; + unsigned short *pu = (unsigned short *)(buf); + unsigned short *pumax = &pu[buflen / 2]; + + if (buflen & 1) + { error("odd length of UTF-16 char source %u", buflen); + fatal(); + } + + dbuf.reserve(buflen / 2); + for (pu += bom; pu < pumax; pu++) + { unsigned u; + + u = le ? readwordLE(pu) : readwordBE(pu); + if (u & ~0x7F) + { if (u >= 0xD800 && u <= 0xDBFF) + { unsigned u2; + + if (++pu > pumax) + { error("surrogate UTF-16 high value %04x at EOF", u); + fatal(); + } + u2 = le ? readwordLE(pu) : readwordBE(pu); + if (u2 < 0xDC00 || u2 > 0xDFFF) + { error("surrogate UTF-16 low value %04x out of range", u2); + fatal(); + } + u = (u - 0xD7C0) << 10; + u |= (u2 - 0xDC00); + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { error("unpaired surrogate UTF-16 value %04x", u); + fatal(); + } + else if (u == 0xFFFE || u == 0xFFFF) + { error("illegal UTF-16 value %04x", u); + fatal(); + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); // add 0 as sentinel for scanner + buflen = dbuf.offset - 1; // don't include sentinel in count + buf = (unsigned char *) dbuf.extractData(); + } + } + else if (buf[0] == 0xFE && buf[1] == 0xFF) + { // UTF-16BE + le = 0; + goto Lutf16; + } + else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) + { // UTF-32BE + le = 0; + goto Lutf32; + } + else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) + { // UTF-8 + + buf += 3; + buflen -= 3; + } + else + { + /* There is no BOM. Make use of Arcane Jill's insight that + * the first char of D source must be ASCII to + * figure out the encoding. + */ + + bom = 0; + if (buflen >= 4) + { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) + { // UTF-32LE + le = 1; + goto Lutf32; + } + else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) + { // UTF-32BE + le = 0; + goto Lutf32; + } + } + if (buflen >= 2) + { + if (buf[1] == 0) + { // UTF-16LE + le = 1; + goto Lutf16; + } + else if (buf[0] == 0) + { // UTF-16BE + le = 0; + goto Lutf16; + } + } + + // It's UTF-8 + if (buf[0] >= 0x80) + { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); + fatal(); + } + } + } + +#ifdef IN_GCC + // dump utf-8 encoded source + if (dump_source) + { // %% srcname could contain a path ... + d_gcc_dump_source(srcname, "utf-8", buf, buflen); + } +#endif + + /* If it starts with the string "Ddoc", then it's a documentation + * source file. + */ + if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) + { + comment = buf + 4; + isDocFile = 1; +#if IN_DMD + if (!docfile) + setDocfile(); +#endif + return; + } + if (isHtml) + { + OutBuffer *dbuf = new OutBuffer(); + Html h(srcname, buf, buflen); + h.extractCode(dbuf); + buf = dbuf->data; + buflen = dbuf->offset; +#ifdef IN_GCC + // dump extracted source + if (dump_source) + d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); +#endif + } + Parser p(this, buf, buflen, docfile != NULL); + p.nextToken(); + members = p.parseModule(); + md = p.md; + numlines = p.loc.linnum; + + DsymbolTable *dst; + + if (md) + { this->ident = md->id; + this->safe = md->safe; + dst = Package::resolve(md->packages, &this->parent, NULL); + } + else + { + dst = modules; + + /* Check to see if module name is a valid identifier + */ + if (!Lexer::isValidIdentifier(this->ident->toChars())) + error("has non-identifier characters in filename, use module declaration instead"); + } + + // Update global list of modules + if (!dst->insert(this)) + { + Dsymbol *prev = dst->lookup(ident); + assert(prev); + Module *mprev = prev->isModule(); + if (mprev) + error(loc, "from file %s conflicts with another module %s from file %s", + srcname, mprev->toChars(), mprev->srcfile->toChars()); + else + { + Package *pkg = prev->isPackage(); + assert(pkg); + error(loc, "from file %s conflicts with package name %s", + srcname, pkg->toChars()); + } + } + else + { + amodules.push(this); + } +} + +void Module::importAll(Scope *prevsc) +{ + //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); + + if (scope) + return; // already done + + /* Note that modules get their own scope, from scratch. + * This is so regardless of where in the syntax a module + * gets imported, it is unaffected by context. + * Ignore prevsc. + */ + Scope *sc = Scope::createGlobal(this); // create root scope + + // Add import of "object" if this module isn't "object" + if (ident != Id::object) + { + if (members->dim == 0 || ((Dsymbol *)members->data[0])->ident != Id::object) + { + Import *im = new Import(0, NULL, Id::object, NULL, 0); + members->shift(im); + } + } + + if (!symtab) + { + // Add all symbols into module's symbol table + symtab = new DsymbolTable(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(NULL, sc->scopesym, 1); + } + } + // anything else should be run after addMember, so version/debug symbols are defined + + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + setScope(sc); // remember module scope for semantic + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + s->setScope(sc); + } + + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->importAll(sc); + } + + sc = sc->pop(); + sc->pop(); // 2 pops because Scope::createGlobal() created 2 +} + +void Module::semantic(Scope* unused_sc) +{ + if (semanticstarted) + return; + + //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); + semanticstarted = 1; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope *sc = scope; // see if already got one from importAll() + if (!sc) + { printf("test2\n"); + Scope::createGlobal(this); // create root scope + } + + //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); + +#if 0 + // Add import of "object" if this module isn't "object" + if (ident != Id::object) + { + Import *im = new Import(0, NULL, Id::object, NULL, 0); + members->shift(im); + } + + // Add all symbols into module's symbol table + symtab = new DsymbolTable(); + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + s->addMember(NULL, sc->scopesym, 1); + } + + /* Set scope for the symbols so that if we forward reference + * a symbol, it can possibly be resolved on the spot. + * If this works out well, it can be extended to all modules + * before any semantic() on any of them. + */ + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + s->setScope(sc); + } +#endif + + // Do semantic() on members that don't depend on others + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + + //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); + s->semantic0(sc); + } + + // Pass 1 semantic routines: do public side of the definition + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + + //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); + s->semantic(sc); + runDeferredSemantic(); + } + + if (!scope) + { sc = sc->pop(); + sc->pop(); // 2 pops because Scope::createGlobal() created 2 + } + semanticRun = semanticstarted; + //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); +} + +void Module::semantic2(Scope* unused_sc) +{ int i; + + if (deferred.dim) + { + for (int i = 0; i < deferred.dim; i++) + { + Dsymbol *sd = (Dsymbol *)deferred.data[i]; + + sd->error("unable to resolve forward reference in definition"); + } + return; + } + //printf("Module::semantic2('%s'): parent = %p\n", toChars(), parent); + if (semanticstarted >= 2) + return; + assert(semanticstarted == 1); + semanticstarted = 2; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope *sc = Scope::createGlobal(this); // create root scope + //printf("Module = %p\n", sc.scopesym); + + // Pass 2 semantic routines: do initializers and function bodies + for (i = 0; i < members->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + s->semantic2(sc); + } + + sc = sc->pop(); + sc->pop(); + semanticRun = semanticstarted; + //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); +} + +void Module::semantic3(Scope* unused_sc) +{ int i; + + //printf("Module::semantic3('%s'): parent = %p\n", toChars(), parent); + if (semanticstarted >= 3) + return; + assert(semanticstarted == 2); + semanticstarted = 3; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + Scope *sc = Scope::createGlobal(this); // create root scope + //printf("Module = %p\n", sc.scopesym); + + // Pass 3 semantic routines: do initializers and function bodies + for (i = 0; i < members->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); + s->semantic3(sc); + } + + sc = sc->pop(); + sc->pop(); + semanticRun = semanticstarted; +} + +void Module::inlineScan() +{ + if (semanticstarted >= 4) + return; + assert(semanticstarted == 3); + semanticstarted = 4; + + // Note that modules get their own scope, from scratch. + // This is so regardless of where in the syntax a module + // gets imported, it is unaffected by context. + //printf("Module = %p\n", sc.scopesym); + + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + //if (global.params.verbose) + //printf("inline scan symbol %s\n", s->toChars()); + + s->inlineScan(); + } + semanticRun = semanticstarted; +} + +/**************************************************** + */ + +// is this used anywhere? +/* +void Module::gensymfile() +{ + OutBuffer buf; + HdrGenState hgs; + + //printf("Module::gensymfile()\n"); + + buf.printf("// Sym file generated from '%s'", srcfile->toChars()); + buf.writenl(); + + for (int i = 0; i < members->dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + + s->toCBuffer(&buf, &hgs); + } + + // Transfer image to file + symfile->setbuffer(buf.data, buf.offset); + buf.data = NULL; + + symfile->writev(); +}*/ + +/********************************** + * Determine if we need to generate an instance of ModuleInfo + * for this Module. + */ + +int Module::needModuleInfo() +{ + //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); + return needmoduleinfo; +} + +Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) +{ + /* Since modules can be circularly referenced, + * need to stop infinite recursive searches. + * This is done with the cache. + */ + + //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); + Dsymbol *s; + if (insearch) + s = NULL; + else if (searchCacheIdent == ident && searchCacheFlags == flags) + { + s = searchCacheSymbol; + //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null"); + } + else + { + insearch = 1; + s = ScopeDsymbol::search(loc, ident, flags); + insearch = 0; + + searchCacheIdent = ident; + searchCacheSymbol = s; + searchCacheFlags = flags; + } + return s; +} + +Dsymbol *Module::symtabInsert(Dsymbol *s) +{ + searchCacheIdent = 0; // symbol is inserted, so invalidate cache + return Package::symtabInsert(s); +} + +void Module::clearCache() +{ + for (int i = 0; i < amodules.dim; i++) + { Module *m = (Module *)amodules.data[i]; + m->searchCacheIdent = NULL; + } +} + +/******************************************* + * Can't run semantic on s now, try again later. + */ + +void Module::addDeferredSemantic(Dsymbol *s) +{ + // Don't add it if it is already there + for (int i = 0; i < deferred.dim; i++) + { + Dsymbol *sd = (Dsymbol *)deferred.data[i]; + + if (sd == s) + return; + } + + //printf("Module::addDeferredSemantic('%s')\n", s->toChars()); + deferred.push(s); +} + + +/****************************************** + * Run semantic() on deferred symbols. + */ + +void Module::runDeferredSemantic() +{ + if (dprogress == 0) + return; + + static int nested; + if (nested) + return; + //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); + nested++; + + size_t len; + do + { + dprogress = 0; + len = deferred.dim; + if (!len) + break; + + Dsymbol **todo; + Dsymbol *tmp; + if (len == 1) + { + todo = &tmp; + } + else + { + todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); + assert(todo); + } + memcpy(todo, deferred.data, len * sizeof(Dsymbol *)); + deferred.setDim(0); + + for (int i = 0; i < len; i++) + { + Dsymbol *s = todo[i]; + + s->semantic(NULL); + //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars()); + } + //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); + } while (deferred.dim < len || dprogress); // while making progress + nested--; + //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); +} + +/************************************ + * Recursively look at every module this module imports, + * return TRUE if it imports m. + * Can be used to detect circular imports. + */ + +int Module::imports(Module *m) +{ + //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); + int aimports_dim = aimports.dim; +#if 0 + for (int i = 0; i < aimports.dim; i++) + { Module *mi = (Module *)aimports.data[i]; + printf("\t[%d] %s\n", i, mi->toChars()); + } +#endif + for (int i = 0; i < aimports.dim; i++) + { Module *mi = (Module *)aimports.data[i]; + if (mi == m) + return TRUE; + if (!mi->insearch) + { + mi->insearch = 1; + int r = mi->imports(m); + if (r) + return r; + } + } + return FALSE; +} + +/************************************* + * Return !=0 if module imports itself. + */ + +int Module::selfImports() +{ + //printf("Module::selfImports() %s\n", toChars()); + if (!selfimports) + { + for (int i = 0; i < amodules.dim; i++) + { Module *mi = (Module *)amodules.data[i]; + //printf("\t[%d] %s\n", i, mi->toChars()); + mi->insearch = 0; + } + + selfimports = imports(this) + 1; + + for (int i = 0; i < amodules.dim; i++) + { Module *mi = (Module *)amodules.data[i]; + //printf("\t[%d] %s\n", i, mi->toChars()); + mi->insearch = 0; + } + } + return selfimports - 1; +} + + +/* =========================== ModuleDeclaration ===================== */ + +ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id, bool safe) +{ + this->packages = packages; + this->id = id; + this->safe = safe; +} + +char *ModuleDeclaration::toChars() +{ + OutBuffer buf; + int i; + + if (packages && packages->dim) + { + for (i = 0; i < packages->dim; i++) + { Identifier *pid = (Identifier *)packages->data[i]; + + buf.writestring(pid->toChars()); + buf.writeByte('.'); + } + } + buf.writestring(id->toChars()); + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* =========================== Package ===================== */ + +Package::Package(Identifier *ident) + : ScopeDsymbol(ident) +{ +} + + +const char *Package::kind() +{ + return "package"; +} + + +DsymbolTable *Package::resolve(Array *packages, Dsymbol **pparent, Package **ppkg) +{ + DsymbolTable *dst = Module::modules; + Dsymbol *parent = NULL; + + //printf("Package::resolve()\n"); + if (ppkg) + *ppkg = NULL; + + if (packages) + { int i; + + for (i = 0; i < packages->dim; i++) + { Identifier *pid = (Identifier *)packages->data[i]; + Dsymbol *p; + + p = dst->lookup(pid); + if (!p) + { + p = new Package(pid); + dst->insert(p); + p->parent = parent; + ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); + } + else + { + assert(p->isPackage()); +#if TARGET_NET //dot net needs modules and packages with same name +#else + if (p->isModule()) + { p->error("module and package have the same name"); + fatal(); + break; + } +#endif + } + parent = p; + dst = ((Package *)p)->symtab; + if (ppkg && !*ppkg) + *ppkg = (Package *)p; + } + if (pparent) + { + *pparent = parent; + } + } + return dst; +} diff --git a/dmd2/module.h b/dmd2/module.h index 4b13721e..7937e9ac 100644 --- a/dmd2/module.h +++ b/dmd2/module.h @@ -1,215 +1,226 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_MODULE_H -#define DMD_MODULE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct ModuleInfoDeclaration; -struct ClassDeclaration; -struct ModuleDeclaration; -struct Macro; -struct Escape; -struct VarDeclaration; -struct Library; - -// Back end -#if IN_LLVM -class Ir; -struct DValue; -typedef DValue elem; -namespace llvm { - class LLVMContext; - class Module; -} -#else - -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#else -struct elem; -#endif -#endif - -struct Package : ScopeDsymbol -{ - Package(Identifier *ident); - const char *kind(); - - static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg); - - Package *isPackage() { return this; } - - virtual void semantic(Scope *sc) { } -}; - -struct Module : Package -{ - static Module *rootModule; - static DsymbolTable *modules; // symbol table of all modules - static Array amodules; // array of all modules - static Array deferred; // deferred Dsymbol's needing semantic() run on them - static unsigned dprogress; // progress resolving the deferred list - static void init(); - - static ClassDeclaration *moduleinfo; - - - const char *arg; // original argument name - ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration - File *srcfile; // input source file - - File *objfile; // output object file - File *docfile; // output doc file - File *hdrfile; // output hdr file - - unsigned errors; // if any errors in file - unsigned numlines; // number of lines in source file - int isHtml; // if it is an HTML file - int isDocFile; // if it is a documentation input file, not D source - int needmoduleinfo; -#ifdef IN_GCC - int strictlyneedmoduleinfo; -#endif - - int selfimports; // 0: don't know, 1: does not, 2: does - int selfImports(); // returns !=0 if module imports itself - - int insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - - int semanticstarted; // has semantic() been started? - int semanticRun; // has semantic() been done? - int root; // != 0 if this is a 'root' module, - // i.e. a module that will be taken all the - // way to an object file - Module *importedFrom; // module from command line we're imported from, - // i.e. a module that will be taken all the - // way to an object file - - Array *decldefs; // top level declarations for this Module - - Array aimports; // all imported modules - - ModuleInfoDeclaration *vmoduleinfo; - - unsigned debuglevel; // debug level - Array *debugids; // debug identifiers - Array *debugidsNot; // forward referenced debug identifiers - - unsigned versionlevel; // version level - Array *versionids; // version identifiers - Array *versionidsNot; // forward referenced version identifiers - - Macro *macrotable; // document comment macros - Escape *escapetable; // document comment escapes - bool safe; // TRUE if module is marked as 'safe' - - int doDocComment; // enable generating doc comments for this module - int doHdrGen; // enable generating header file for this module - - Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); - ~Module(); - - static Module *load(Loc loc, Array *packages, Identifier *ident); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -#if !IN_LLVM - void setDocfile(); // set docfile member -#endif - void read(Loc loc); // read file -#if IN_GCC - void parse(bool dump_source = false); // syntactic parse -#else - void parse(); // syntactic parse -#endif - void semantic(Scope* unused_sc = NULL); // semantic analysis - void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis - void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis - void inlineScan(); // scan for functions to inline -#if !IN_LLVM - void setHdrfile(); // set hdrfile member -#endif -#ifdef _DH - void genhdrfile(); // generate D import file -#endif -// void gensymfile(); - void gendocfile(); - int needModuleInfo(); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void deleteObjFile(); - void addDeferredSemantic(Dsymbol *s); - void runDeferredSemantic(); - int imports(Module *m); - - // Back end -#if IN_DMD - int doppelganger; // sub-module - Symbol *cov; // private uint[] __coverage; - unsigned *covb; // bit array of valid code line numbers - - Symbol *sictor; // module order independent constructor - Symbol *sctor; // module constructor - Symbol *sdtor; // module destructor - Symbol *stest; // module unit test - - Symbol *sfilename; // symbol for filename - - Symbol *massert; // module assert function - Symbol *toModuleAssert(); // get module assert function - - Symbol *marray; // module array bounds function - Symbol *toModuleArray(); // get module array bounds function - - - static Symbol *gencritsec(); - elem *toEfilename(); - elem *toEmodulename(); - - Symbol *toSymbol(); -#endif - void genmoduleinfo(); - -#if IN_LLVM - // LDC - llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir); - void buildTargetFiles(bool singleObj); - File* buildFilePath(const char* forcename, const char* path, const char* ext); - Module *isModule() { return this; } - - bool llvmForceLogging; - - // array ops emitted in this module already - StringTable arrayfuncs; -#endif -}; - - -struct ModuleDeclaration -{ - Identifier *id; - Array *packages; // array of Identifier's representing packages - bool safe; - - ModuleDeclaration(Array *packages, Identifier *id, bool safe); - - char *toChars(); -}; - -#endif /* DMD_MODULE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2008 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. + +#ifndef DMD_MODULE_H +#define DMD_MODULE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "dsymbol.h" + +struct ModuleInfoDeclaration; +struct ClassDeclaration; +struct ModuleDeclaration; +struct Macro; +struct Escape; +struct VarDeclaration; +struct Library; + +// Back end +#if IN_LLVM +class Ir; +struct DValue; +typedef DValue elem; +namespace llvm { + class LLVMContext; + class Module; +} +#else + +#ifdef IN_GCC +union tree_node; typedef union tree_node elem; +#else +struct elem; +#endif +#endif + +struct Package : ScopeDsymbol +{ + Package(Identifier *ident); + const char *kind(); + + static DsymbolTable *resolve(Array *packages, Dsymbol **pparent, Package **ppkg); + + Package *isPackage() { return this; } + + virtual void semantic(Scope *sc) { } +}; + +struct Module : Package +{ + static Module *rootModule; + static DsymbolTable *modules; // symbol table of all modules + static Array amodules; // array of all modules + static Array deferred; // deferred Dsymbol's needing semantic() run on them + static unsigned dprogress; // progress resolving the deferred list + static void init(); + + static ClassDeclaration *moduleinfo; + + + const char *arg; // original argument name + ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration + File *srcfile; // input source file + File *objfile; // output .obj file + File *hdrfile; // 'header' file + File *symfile; // output symbol file + File *docfile; // output documentation file + + unsigned errors; // if any errors in file + unsigned numlines; // number of lines in source file + int isHtml; // if it is an HTML file + int isDocFile; // if it is a documentation input file, not D source + int needmoduleinfo; +#ifdef IN_GCC + int strictlyneedmoduleinfo; +#endif + + int selfimports; // 0: don't know, 1: does not, 2: does + int selfImports(); // returns !=0 if module imports itself + + int insearch; + Identifier *searchCacheIdent; + Dsymbol *searchCacheSymbol; // cached value of search + int searchCacheFlags; // cached flags + + int semanticstarted; // has semantic() been started? + int semanticRun; // has semantic() been done? + int root; // != 0 if this is a 'root' module, + // i.e. a module that will be taken all the + // way to an object file + Module *importedFrom; // module from command line we're imported from, + // i.e. a module that will be taken all the + // way to an object file + + Array *decldefs; // top level declarations for this Module + + Array aimports; // all imported modules + + ModuleInfoDeclaration *vmoduleinfo; + + unsigned debuglevel; // debug level + Array *debugids; // debug identifiers + Array *debugidsNot; // forward referenced debug identifiers + + unsigned versionlevel; // version level + Array *versionids; // version identifiers + Array *versionidsNot; // forward referenced version identifiers + + Macro *macrotable; // document comment macros + Escape *escapetable; // document comment escapes + bool safe; // TRUE if module is marked as 'safe' + + size_t nameoffset; // offset of module name from start of ModuleInfo + size_t namelen; // length of module name in characters + + int doDocComment; // enable generating doc comments for this module + int doHdrGen; // enable generating header file for this module + + Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); + ~Module(); + + static Module *load(Loc loc, Array *packages, Identifier *ident); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void toJsonBuffer(OutBuffer *buf); + const char *kind(); +#if !IN_LLVM + void setDocfile(); // set docfile member +#endif + void read(Loc loc); // read file +#if IN_GCC + void parse(bool dump_source = false); // syntactic parse +#else + void parse(); // syntactic parse +#endif + void importAll(Scope *sc); + void semantic(Scope* unused_sc = NULL); // semantic analysis + void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis + void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis + void inlineScan(); // scan for functions to inline +#if !IN_LLVM + void setHdrfile(); // set hdrfile member +#endif +#ifdef _DH + void genhdrfile(); // generate D import file +#endif +// void gensymfile(); + void gendocfile(); + int needModuleInfo(); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + Dsymbol *symtabInsert(Dsymbol *s); + void deleteObjFile(); + void addDeferredSemantic(Dsymbol *s); + static void runDeferredSemantic(); + static void clearCache(); + int imports(Module *m); + + // Back end +#if IN_DMD + int doppelganger; // sub-module + Symbol *cov; // private uint[] __coverage; + unsigned *covb; // bit array of valid code line numbers + + Symbol *sictor; // module order independent constructor + Symbol *sctor; // module constructor + Symbol *sdtor; // module destructor + Symbol *ssharedctor; // module shared constructor + Symbol *sshareddtor; // module shared destructor + Symbol *stest; // module unit test + + Symbol *sfilename; // symbol for filename + + Symbol *massert; // module assert function + Symbol *toModuleAssert(); // get module assert function + + Symbol *munittest; // module unittest failure function + Symbol *toModuleUnittest(); // get module unittest failure function + + Symbol *marray; // module array bounds function + Symbol *toModuleArray(); // get module array bounds function + + + static Symbol *gencritsec(); + elem *toEfilename(); + + Symbol *toSymbol(); +#endif + void genmoduleinfo(); + +#if IN_LLVM + // LDC + llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir); + void buildTargetFiles(bool singleObj); + File* buildFilePath(const char* forcename, const char* path, const char* ext); + Module *isModule() { return this; } + + bool llvmForceLogging; + + // array ops emitted in this module already + StringTable arrayfuncs; +#endif +}; + + +struct ModuleDeclaration +{ + Identifier *id; + Array *packages; // array of Identifier's representing packages + bool safe; + + ModuleDeclaration(Array *packages, Identifier *id, bool safe); + + char *toChars(); +}; + +#endif /* DMD_MODULE_H */ diff --git a/dmd2/mtype.c b/dmd2/mtype.c index 0771164b..078cec2d 100644 --- a/dmd2/mtype.c +++ b/dmd2/mtype.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -8,8 +8,8 @@ // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#define __USE_ISOC99 1 // so signbit() gets defined +#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more +#define __USE_ISOC99 1 // so signbit() gets defined #if (defined (__SVR4) && defined (__sun)) #include @@ -61,11 +61,11 @@ unsigned GetTypeAlignment(Ir* ir, Type* t); FuncDeclaration *hasThis(Scope *sc); -#define LOGDOTEXP 0 // log ::dotExp() -#define LOGDEFAULTINIT 0 // log ::defaultInit() +#define LOGDOTEXP 0 // log ::dotExp() +#define LOGDEFAULTINIT 0 // log ::defaultInit() // Allow implicit conversion of T[] to T* -#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated +#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated /* These have default values for 32 bit code, they get * adjusted for 64 bit code. @@ -118,8 +118,12 @@ ClassDeclaration *Type::typeinfotypelist; ClassDeclaration *Type::typeinfoconst; ClassDeclaration *Type::typeinfoinvariant; ClassDeclaration *Type::typeinfoshared; +ClassDeclaration *Type::typeinfowild; + +TemplateDeclaration *Type::associativearray; Type *Type::tvoidptr; +Type *Type::tstring; Type *Type::basic[TMAX]; unsigned char Type::mangleChar[TMAX]; unsigned char Type::sizeTy[TMAX]; @@ -141,6 +145,8 @@ Type::Type(TY ty/*, Type *next*/) this->ito = NULL; this->sto = NULL; this->scto = NULL; + this->wto = NULL; + this->swto = NULL; #endif this->pto = NULL; this->rto = NULL; @@ -169,11 +175,11 @@ int Type::equals(Object *o) t = (Type *)o; //printf("Type::equals(%s, %s)\n", toChars(), t->toChars()); if (this == o || - (t && deco == t->deco) && // deco strings are unique - deco != NULL) // and semantic() has been run + (t && deco == t->deco) && // deco strings are unique + deco != NULL) // and semantic() has been run { - //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 1; + //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); + return 1; } //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); return 0; @@ -181,7 +187,7 @@ int Type::equals(Object *o) char Type::needThisPrefix() { - return 'M'; // name mangling prefix for functions needing 'this' + return 'M'; // name mangling prefix for functions needing 'this' } #if IN_LLVM @@ -195,7 +201,7 @@ void Type::init() Lexer::initKeywords(); for (i = 0; i < TMAX; i++) - sizeTy[i] = sizeof(TypeBasic); + sizeTy[i] = sizeof(TypeBasic); sizeTy[Tsarray] = sizeof(TypeSArray); sizeTy[Tarray] = sizeof(TypeDArray); //sizeTy[Tnarray] = sizeof(TypeNArray); @@ -255,6 +261,7 @@ void Type::init() mangleChar[Twchar] = 'u'; mangleChar[Tdchar] = 'w'; + // '@' shouldn't appear anywhere in the deco'd names mangleChar[Tbit] = '@'; mangleChar[Tinstance] = '@'; mangleChar[Terror] = '@'; @@ -264,28 +271,29 @@ void Type::init() mangleChar[Treturn] = '@'; for (i = 0; i < TMAX; i++) - { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %d\n", i); - assert(mangleChar[i]); + { if (!mangleChar[i]) + fprintf(stdmsg, "ty = %d\n", i); + assert(mangleChar[i]); } // Set basic types static TY basetab[] = - { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, - Tfloat32, Tfloat64, Tfloat80, - Timaginary32, Timaginary64, Timaginary80, - Tcomplex32, Tcomplex64, Tcomplex80, - Tbool, - Tascii, Twchar, Tdchar }; + { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, + Tfloat32, Tfloat64, Tfloat80, + Timaginary32, Timaginary64, Timaginary80, + Tcomplex32, Tcomplex64, Tcomplex80, + Tbool, + Tascii, Twchar, Tdchar }; for (i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) - { Type *t = new TypeBasic(basetab[i]); - t = t->merge(); - basic[basetab[i]] = t; + { Type *t = new TypeBasic(basetab[i]); + t = t->merge(); + basic[basetab[i]] = t; } - basic[Terror] = basic[Tint32]; + basic[Terror] = new TypeError(); tvoidptr = tvoid->pointerTo(); + tstring = tchar->invariantOf()->arrayOf(); // LDC sir = _sir; @@ -293,25 +301,25 @@ void Type::init() // set size_t / ptrdiff_t types and pointer size if (global.params.is64bit) { - Tsize_t = Tuns64; - Tptrdiff_t = Tint64; - PTRSIZE = 8; + Tsize_t = Tuns64; + Tptrdiff_t = Tint64; + PTRSIZE = 8; } else { - PTRSIZE = 4; + PTRSIZE = 4; #if TARGET_OSX - REALSIZE = 16; - REALPAD = 6; + REALSIZE = 16; + REALPAD = 6; #elif TARGET_LINUX || TARGET_FREEBSD || TARGET_SOLARIS - REALSIZE = 12; - REALPAD = 2; + REALSIZE = 12; + REALPAD = 2; #else - REALSIZE = 10; - REALPAD = 0; + REALSIZE = 10; + REALPAD = 0; #endif - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; + Tsize_t = Tuns32; + Tptrdiff_t = Tint32; PTRSIZE = 4; } @@ -356,15 +364,17 @@ Type *Type::semantic(Loc loc, Scope *sc) Type *Type::trySemantic(Loc loc, Scope *sc) { + //printf("+trySemantic(%s) %d\n", toChars(), global.errors); unsigned errors = global.errors; - global.gag++; // suppress printing of error messages + global.gag++; // suppress printing of error messages Type *t = semantic(loc, sc); global.gag--; - if (errors != global.errors) // if any errors happened + if (errors != global.errors) // if any errors happened { - global.errors = errors; - t = NULL; + global.errors = errors; + t = NULL; } + //printf("-trySemantic(%s) %d\n", toChars(), global.errors); return t; } @@ -372,17 +382,17 @@ Type *Type::trySemantic(Loc loc, Scope *sc) * Determine if converting 'this' to 'to' is an identity operation, * a conversion to const operation, or the types aren't the same. * Returns: - * MATCHequal 'this' == 'to' - * MATCHconst 'to' is const - * MATCHnomatch conversion to mutable or invariant + * MATCHequal 'this' == 'to' + * MATCHconst 'to' is const + * MATCHnomatch conversion to mutable or invariant */ MATCH Type::constConv(Type *to) { if (equals(to)) - return MATCHexact; - if (ty == to->ty && to->mod == MODconst) - return MATCHconst; + return MATCHexact; + if (ty == to->ty && MODimplicitConv(mod, to->mod)) + return MATCHconst; return MATCHnomatch; } @@ -392,34 +402,18 @@ MATCH Type::constConv(Type *to) Type *Type::constOf() { -#if 0 - //printf("Type::constOf() %p %s\n", this, toChars()); - if (isConst()) - return this; - if (cto) - return cto; - Type *t = makeConst(); - t = t->merge(); - cto = t; - if (ito) - ito->cto = t; - //if (t->nextOf()) assert(t->nextOf()->isConst()); - //printf("-Type::constOf() %p %s\n", t, toChars()); - return t; -#else //printf("Type::constOf() %p %s\n", this, toChars()); if (mod == MODconst) - return this; + return this; if (cto) - { assert(cto->mod == MODconst); - return cto; + { assert(cto->mod == MODconst); + return cto; } Type *t = makeConst(); t = t->merge(); t->fixTo(this); //printf("-Type::constOf() %p %s\n", t, toChars()); return t; -#endif } /******************************** @@ -428,48 +422,21 @@ Type *Type::constOf() Type *Type::invariantOf() { -#if 0 //printf("Type::invariantOf() %p %s\n", this, toChars()); - if (isInvariant()) + if (isImmutable()) { - return this; + return this; } if (ito) { - //if (!ito->isInvariant()) printf("\tito is %p %s\n", ito, ito->toChars()); - assert(ito->isInvariant()); - return ito; - } - Type *t = makeInvariant(); - t = t->merge(); - ito = t; - if (cto) - cto->ito = t; -#if 0 // fails for function types - if (t->nextOf() && !t->nextOf()->isInvariant()) - { - assert(0); - } -#endif - //printf("\t%p\n", t); - return t; -#else - //printf("Type::invariantOf() %p %s\n", this, toChars()); - if (isInvariant()) - { - return this; - } - if (ito) - { - assert(ito->isInvariant()); - return ito; + assert(ito->isImmutable()); + return ito; } Type *t = makeInvariant(); t = t->merge(); t->fixTo(this); //printf("\t%p\n", t); return t; -#endif } /******************************** @@ -478,108 +445,35 @@ Type *Type::invariantOf() Type *Type::mutableOf() { -#if 0 //printf("Type::mutableOf() %p, %s\n", this, toChars()); Type *t = this; if (isConst()) - { t = cto; - assert(!t || t->isMutable()); + { if (isShared()) + t = sto; // shared const => shared + else + t = cto; // const => naked + assert(!t || t->isMutable()); } - else if (isInvariant()) - { t = ito; - assert(!t || t->isMutable()); + else if (isImmutable()) + { t = ito; // immutable => naked + assert(!t || (t->isMutable() && !t->isShared())); + } + else if (isWild()) + { + if (isShared()) + t = sto; // shared wild => shared + else + t = wto; // wild => naked + assert(!t || t->isMutable()); } if (!t) { - unsigned sz = sizeTy[ty]; - t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = 0; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->vtinfo = NULL; - if (ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)t; - //ta->next = ta->next->mutableOf(); - } - t = t->merge(); - if (isConst()) - { cto = t; - t->cto = this; - if (ito) - ito->cto = this; - } - else if (isInvariant()) - { ito = t; - t->ito = this; - if (cto) - cto->ito = this; - } + t = makeMutable(); + t = t->merge(); + t->fixTo(this); } + assert(t->isMutable()); return t; -#else - //printf("Type::mutableOf() %p, %s\n", this, toChars()); - Type *t = this; - if (isConst()) - { if (isShared()) - t = sto; // shared const => shared - else - t = cto; - assert(!t || t->isMutable()); - } - else if (isInvariant()) - { t = ito; - assert(!t || (t->isMutable() && !t->isShared())); - } - if (!t) - { - unsigned sz = sizeTy[ty]; - t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = 0; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->vtinfo = NULL; - t = t->merge(); - - t->fixTo(this); - - switch (mod) - { - case MODconst: - t->cto = this; - break; - - case MODinvariant: - t->ito = this; - break; - - case MODshared: - t->sto = this; - break; - - case MODshared | MODconst: - t->scto = this; - break; - - default: - assert(0); - } - } - return t; -#endif } Type *Type::sharedOf() @@ -587,12 +481,12 @@ Type *Type::sharedOf() //printf("Type::sharedOf() %p, %s\n", this, toChars()); if (mod == MODshared) { - return this; + return this; } if (sto) { - assert(sto->isShared()); - return sto; + assert(sto->isShared()); + return sto; } Type *t = makeShared(); t = t->merge(); @@ -606,12 +500,12 @@ Type *Type::sharedConstOf() //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); if (mod == (MODshared | MODconst)) { - return this; + return this; } if (scto) { - assert(scto->mod == (MODshared | MODconst)); - return scto; + assert(scto->mod == (MODshared | MODconst)); + return scto; } Type *t = makeSharedConst(); t = t->merge(); @@ -621,9 +515,103 @@ Type *Type::sharedConstOf() } +/******************************** + * Make type unshared. + * 0 => 0 + * const => const + * immutable => immutable + * shared => 0 + * shared const => const + * wild => wild + * shared wild => wild + */ + +Type *Type::unSharedOf() +{ + //printf("Type::unSharedOf() %p, %s\n", this, toChars()); + Type *t = this; + + if (isShared()) + { + if (isConst()) + t = cto; // shared const => const + else if (isWild()) + t = wto; // shared wild => wild + else + t = sto; + assert(!t || !t->isShared()); + } + + if (!t) + { + unsigned sz = sizeTy[ty]; + t = (Type *)mem.malloc(sz); + memcpy(t, this, sz); + t->mod = mod & ~MODshared; + t->deco = NULL; + t->arrayof = NULL; + t->pto = NULL; + t->rto = NULL; + t->cto = NULL; + t->ito = NULL; + t->sto = NULL; + t->scto = NULL; + t->wto = NULL; + t->swto = NULL; + t->vtinfo = NULL; + t = t->merge(); + + t->fixTo(this); + } + assert(!t->isShared()); + return t; +} + +/******************************** + * Convert to 'wild'. + */ + +Type *Type::wildOf() +{ + //printf("Type::wildOf() %p %s\n", this, toChars()); + if (mod == MODwild) + { + return this; + } + if (wto) + { + assert(wto->isWild()); + return wto; + } + Type *t = makeWild(); + t = t->merge(); + t->fixTo(this); + //printf("\t%p %s\n", t, t->toChars()); + return t; +} + +Type *Type::sharedWildOf() +{ + //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); + if (mod == (MODshared | MODwild)) + { + return this; + } + if (swto) + { + assert(swto->mod == (MODshared | MODwild)); + return swto; + } + Type *t = makeSharedWild(); + t = t->merge(); + t->fixTo(this); + //printf("\t%p\n", t); + return t; +} + /********************************** * For our new type 'this', which is type-constructed from t, - * fill in the cto, ito, sto, scto shortcuts. + * fill in the cto, ito, sto, scto, wto shortcuts. */ void Type::fixTo(Type *t) @@ -640,106 +628,203 @@ void Type::fixTo(Type *t) #endif assert(mod != t->mod); -#define X(m, n) (((m) << 3) | (n)) +#define X(m, n) (((m) << 4) | (n)) switch (X(mod, t->mod)) { - case X(0, MODconst): - cto = t; - break; + case X(0, MODconst): + cto = t; + break; - case X(0, MODinvariant): - ito = t; - break; + case X(0, MODimmutable): + ito = t; + break; - case X(0, MODshared): - sto = t; - break; + case X(0, MODshared): + sto = t; + break; - case X(0, MODshared | MODconst): - scto = t; - break; + case X(0, MODshared | MODconst): + scto = t; + break; + + case X(0, MODwild): + wto = t; + break; + + case X(0, MODshared | MODwild): + swto = t; + break; - case X(MODconst, 0): - cto = NULL; - goto L2; + case X(MODconst, 0): + cto = NULL; + goto L2; - case X(MODconst, MODinvariant): - ito = t; - goto L2; + case X(MODconst, MODimmutable): + ito = t; + goto L2; - case X(MODconst, MODshared): - sto = t; - goto L2; + case X(MODconst, MODshared): + sto = t; + goto L2; - case X(MODconst, MODshared | MODconst): - scto = t; - L2: - t->cto = this; - break; + case X(MODconst, MODshared | MODconst): + scto = t; + goto L2; + + case X(MODconst, MODwild): + wto = t; + goto L2; + + case X(MODconst, MODshared | MODwild): + swto = t; + L2: + t->cto = this; + break; - case X(MODinvariant, 0): - ito = NULL; - goto L3; + case X(MODimmutable, 0): + ito = NULL; + goto L3; - case X(MODinvariant, MODconst): - cto = t; - goto L3; + case X(MODimmutable, MODconst): + cto = t; + goto L3; - case X(MODinvariant, MODshared): - sto = t; - goto L3; + case X(MODimmutable, MODshared): + sto = t; + goto L3; - case X(MODinvariant, MODshared | MODconst): - scto = t; - L3: - t->ito = this; - if (t->cto) t->cto->ito = this; - if (t->sto) t->sto->ito = this; - if (t->scto) t->scto->ito = this; - break; + case X(MODimmutable, MODshared | MODconst): + scto = t; + goto L3; + + case X(MODimmutable, MODwild): + wto = t; + goto L3; + + case X(MODimmutable, MODshared | MODwild): + swto = t; + L3: + t->ito = this; + if (t->cto) t->cto->ito = this; + if (t->sto) t->sto->ito = this; + if (t->scto) t->scto->ito = this; + if (t->wto) t->wto->ito = this; + if (t->swto) t->swto->ito = this; + break; - case X(MODshared, 0): - sto = NULL; - goto L4; + case X(MODshared, 0): + sto = NULL; + goto L4; - case X(MODshared, MODconst): - cto = t; - goto L4; + case X(MODshared, MODconst): + cto = t; + goto L4; - case X(MODshared, MODinvariant): - ito = t; - goto L4; + case X(MODshared, MODimmutable): + ito = t; + goto L4; - case X(MODshared, MODshared | MODconst): - scto = t; - L4: - t->sto = this; - break; + case X(MODshared, MODshared | MODconst): + scto = t; + goto L4; + + case X(MODshared, MODwild): + wto = t; + goto L4; + + case X(MODshared, MODshared | MODwild): + swto = t; + L4: + t->sto = this; + break; - case X(MODshared | MODconst, 0): - scto = NULL; - break; + case X(MODshared | MODconst, 0): + scto = NULL; + goto L5; - case X(MODshared | MODconst, MODconst): - cto = t; - break; + case X(MODshared | MODconst, MODconst): + cto = t; + goto L5; - case X(MODshared | MODconst, MODinvariant): - ito = t; - break; + case X(MODshared | MODconst, MODimmutable): + ito = t; + goto L5; - case X(MODshared | MODconst, MODshared): - sto = t; - L5: - t->scto = this; - break; + case X(MODshared | MODconst, MODwild): + wto = t; + goto L5; - default: - assert(0); + case X(MODshared | MODconst, MODshared): + sto = t; + goto L5; + + case X(MODshared | MODconst, MODshared | MODwild): + swto = t; + L5: + t->scto = this; + break; + + + case X(MODwild, 0): + wto = NULL; + goto L6; + + case X(MODwild, MODconst): + cto = t; + goto L6; + + case X(MODwild, MODimmutable): + ito = t; + goto L6; + + case X(MODwild, MODshared): + sto = t; + goto L6; + + case X(MODwild, MODshared | MODconst): + scto = t; + goto L6; + + case X(MODwild, MODshared | MODwild): + swto = t; + L6: + t->wto = this; + break; + + + case X(MODshared | MODwild, 0): + swto = NULL; + goto L7; + + case X(MODshared | MODwild, MODconst): + cto = t; + goto L7; + + case X(MODshared | MODwild, MODimmutable): + ito = t; + goto L7; + + case X(MODshared | MODwild, MODshared): + sto = t; + goto L7; + + case X(MODshared | MODwild, MODshared | MODconst): + scto = t; + goto L7; + + case X(MODshared | MODwild, MODwild): + wto = t; + L7: + t->swto = this; + break; + + + default: + assert(0); } #undef X @@ -756,73 +841,109 @@ void Type::check() { switch (mod) { - case 0: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODinvariant); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - break; + case 0: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; - case MODconst: - if (cto) assert(cto->mod == 0); - if (ito) assert(ito->mod == MODinvariant); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - break; + case MODconst: + if (cto) assert(cto->mod == 0); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; - case MODinvariant: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == 0); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - break; + case MODimmutable: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == 0); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; - case MODshared: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODinvariant); - if (sto) assert(sto->mod == 0); - if (scto) assert(scto->mod == (MODshared | MODconst)); - break; + case MODshared: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == 0); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; - case MODshared | MODconst: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODinvariant); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == 0); - break; + case MODshared | MODconst: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == 0); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; - default: - assert(0); + case MODwild: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == 0); + if (swto) assert(swto->mod == (MODshared | MODwild)); + break; + + case MODshared | MODwild: + if (cto) assert(cto->mod == MODconst); + if (ito) assert(ito->mod == MODimmutable); + if (sto) assert(sto->mod == MODshared); + if (scto) assert(scto->mod == (MODshared | MODconst)); + if (wto) assert(wto->mod == MODwild); + if (swto) assert(swto->mod == 0); + break; + + default: + assert(0); } Type *tn = nextOf(); if (tn && ty != Tfunction && ty != Tdelegate) - { // Verify transitivity - switch (mod) - { - case 0: - break; + { // Verify transitivity + switch (mod) + { + case 0: + break; - case MODconst: - assert(tn->mod & MODinvariant || tn->mod & MODconst); - break; + case MODconst: + assert(tn->mod & MODimmutable || tn->mod & MODconst); + break; - case MODinvariant: - assert(tn->mod == MODinvariant); - break; + case MODimmutable: + assert(tn->mod == MODimmutable); + break; - case MODshared: - assert(tn->mod & MODinvariant || tn->mod & MODshared); - break; + case MODshared: + assert(tn->mod & MODimmutable || tn->mod & MODshared); + break; - case MODshared | MODconst: - assert(tn->mod & MODinvariant || tn->mod & (MODshared | MODconst)); - break; + case MODshared | MODconst: + assert(tn->mod & MODimmutable || tn->mod & (MODshared | MODconst)); + break; - default: - assert(0); - } - tn->check(); + case MODwild: + assert(tn->mod); + break; + + case MODshared | MODwild: + assert(tn->mod == MODimmutable || tn->mod == (MODshared | MODconst) || tn->mod == (MODshared | MODwild)); + break; + + default: + assert(0); + } + tn->check(); } } @@ -830,7 +951,7 @@ Type *Type::makeConst() { //printf("Type::makeConst() %p, %s\n", this, toChars()); if (cto) - return cto; + return cto; unsigned sz = sizeTy[ty]; Type *t = (Type *)mem.malloc(sz); memcpy(t, this, sz); @@ -843,6 +964,8 @@ Type *Type::makeConst() t->ito = NULL; t->sto = NULL; t->scto = NULL; + t->wto = NULL; + t->swto = NULL; t->vtinfo = NULL; //printf("-Type::makeConst() %p, %s\n", t, toChars()); return t; @@ -851,11 +974,11 @@ Type *Type::makeConst() Type *Type::makeInvariant() { if (ito) - return ito; + return ito; unsigned sz = sizeTy[ty]; Type *t = (Type *)mem.malloc(sz); memcpy(t, this, sz); - t->mod = MODinvariant; + t->mod = MODimmutable; t->deco = NULL; t->arrayof = NULL; t->pto = NULL; @@ -864,6 +987,8 @@ Type *Type::makeInvariant() t->ito = NULL; t->sto = NULL; t->scto = NULL; + t->wto = NULL; + t->swto = NULL; t->vtinfo = NULL; return t; } @@ -871,7 +996,7 @@ Type *Type::makeInvariant() Type *Type::makeShared() { if (sto) - return sto; + return sto; unsigned sz = sizeTy[ty]; Type *t = (Type *)mem.malloc(sz); memcpy(t, this, sz); @@ -884,6 +1009,8 @@ Type *Type::makeShared() t->ito = NULL; t->sto = NULL; t->scto = NULL; + t->wto = NULL; + t->swto = NULL; t->vtinfo = NULL; return t; } @@ -891,7 +1018,7 @@ Type *Type::makeShared() Type *Type::makeSharedConst() { if (scto) - return scto; + return scto; unsigned sz = sizeTy[ty]; Type *t = (Type *)mem.malloc(sz); memcpy(t, this, sz); @@ -904,6 +1031,72 @@ Type *Type::makeSharedConst() t->ito = NULL; t->sto = NULL; t->scto = NULL; + t->wto = NULL; + t->swto = NULL; + t->vtinfo = NULL; + return t; +} + +Type *Type::makeWild() +{ + if (wto) + return wto; + unsigned sz = sizeTy[ty]; + Type *t = (Type *)mem.malloc(sz); + memcpy(t, this, sz); + t->mod = MODwild; + t->deco = NULL; + t->arrayof = NULL; + t->pto = NULL; + t->rto = NULL; + t->cto = NULL; + t->ito = NULL; + t->sto = NULL; + t->scto = NULL; + t->wto = NULL; + t->swto = NULL; + t->vtinfo = NULL; + return t; +} + +Type *Type::makeSharedWild() +{ + if (swto) + return swto; + unsigned sz = sizeTy[ty]; + Type *t = (Type *)mem.malloc(sz); + memcpy(t, this, sz); + t->mod = MODshared | MODwild; + t->deco = NULL; + t->arrayof = NULL; + t->pto = NULL; + t->rto = NULL; + t->cto = NULL; + t->ito = NULL; + t->sto = NULL; + t->scto = NULL; + t->wto = NULL; + t->swto = NULL; + t->vtinfo = NULL; + return t; +} + +Type *Type::makeMutable() +{ + unsigned sz = sizeTy[ty]; + Type *t = (Type *)mem.malloc(sz); + memcpy(t, this, sz); + t->mod = mod & MODshared; + t->deco = NULL; + t->arrayof = NULL; + t->pto = NULL; + t->rto = NULL; + t->cto = NULL; + t->ito = NULL; + t->sto = NULL; + t->scto = NULL; + t->wto = NULL; + t->swto = NULL; t->vtinfo = NULL; return t; } @@ -917,28 +1110,36 @@ Type *Type::castMod(unsigned mod) switch (mod) { - case 0: - t = mutableOf(); - break; + case 0: + t = unSharedOf()->mutableOf(); + break; - case MODconst: - t = constOf(); - break; + case MODconst: + t = unSharedOf()->constOf(); + break; - case MODinvariant: - t = invariantOf(); - break; + case MODimmutable: + t = invariantOf(); + break; - case MODshared: - t = sharedOf(); - break; + case MODshared: + t = mutableOf()->sharedOf(); + break; - case MODshared | MODconst: - t = sharedConstOf(); - break; + case MODshared | MODconst: + t = sharedConstOf(); + break; - default: - assert(0); + case MODwild: + t = unSharedOf()->wildOf(); + break; + + case MODshared | MODwild: + t = sharedWildOf(); + break; + + default: + assert(0); } return t; } @@ -954,38 +1155,54 @@ Type *Type::addMod(unsigned mod) /* Add anything to immutable, and it remains immutable */ - if (!t->isInvariant()) + if (!t->isImmutable()) { - switch (mod) - { - case 0: - break; + //printf("addMod(%x) %s\n", mod, toChars()); + switch (mod) + { + case 0: + break; - case MODconst: - if (isShared()) - t = sharedConstOf(); - else - t = constOf(); - break; + case MODconst: + if (isShared()) + t = sharedConstOf(); + else + t = constOf(); + break; - case MODinvariant: - t = invariantOf(); - break; + case MODimmutable: + t = invariantOf(); + break; - case MODshared: - if (isConst()) - t = sharedConstOf(); - else - t = sharedOf(); - break; + case MODshared: + if (isConst()) + t = sharedConstOf(); + else if (isWild()) + t = sharedWildOf(); + else + t = sharedOf(); + break; - case MODshared | MODconst: - t = sharedConstOf(); - break; + case MODshared | MODconst: + t = sharedConstOf(); + break; - default: - assert(0); - } + case MODwild: + if (isConst()) + ; + else if (isShared()) + t = sharedWildOf(); + else + t = wildOf(); + break; + + case MODshared | MODwild: + t = sharedWildOf(); + break; + + default: + assert(0); + } } return t; } @@ -994,19 +1211,21 @@ Type *Type::addMod(unsigned mod) * Add storage class modifiers to type. */ -Type *Type::addStorageClass(unsigned stc) +Type *Type::addStorageClass(StorageClass stc) { /* Just translate to MOD bits and let addMod() do the work */ unsigned mod = 0; if (stc & STCimmutable) - mod = MODinvariant; + mod = MODimmutable; else - { if (stc & (STCconst | STCin)) - mod = MODconst; - if (stc & STCshared) - mod |= MODshared; + { if (stc & (STCconst | STCin)) + mod = MODconst; + if (stc & STCshared) + mod |= MODshared; + if (stc & STCwild) + mod |= MODwild; } return addMod(mod); } @@ -1017,17 +1236,17 @@ Type *Type::addStorageClass(unsigned stc) Type *Type::toHeadMutable() { if (!mod) - return this; + return this; return mutableOf(); } Type *Type::pointerTo() { if (!pto) - { Type *t; + { Type *t; - t = new TypePointer(this); - pto = t->merge(); + t = new TypePointer(this); + pto = t->merge(); } return pto; } @@ -1035,10 +1254,10 @@ Type *Type::pointerTo() Type *Type::referenceTo() { if (!rto) - { Type *t; + { Type *t; - t = new TypeReference(this); - rto = t->merge(); + t = new TypeReference(this); + rto = t->merge(); } return rto; } @@ -1046,10 +1265,10 @@ Type *Type::referenceTo() Type *Type::arrayOf() { if (!arrayof) - { Type *t; + { Type *t; - t = new TypeDArray(this); - arrayof = t->merge(); + t = new TypeDArray(this); + arrayof = t->merge(); } return arrayof; } @@ -1069,26 +1288,171 @@ Type *Type::toBasetype() return this; } +/*************************** + * Return !=0 if modfrom can be implicitly converted to modto + */ +int MODimplicitConv(unsigned char modfrom, unsigned char modto) +{ + if (modfrom == modto) + return 1; + + //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); + #define X(m, n) (((m) << 4) | (n)) + switch (X(modfrom, modto)) + { + case X(0, MODconst): + case X(MODimmutable, MODconst): + case X(MODwild, MODconst): + case X(MODimmutable, MODconst | MODshared): + case X(MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + return 1; + + default: + return 0; + } + #undef X +} + +/*************************** + * Merge mod bits to form common mod. + */ +int MODmerge(unsigned char mod1, unsigned char mod2) +{ + if (mod1 == mod2) + return mod1; + + //printf("MODmerge(1 = %x, 2 = %x)\n", modfrom, modto); + #define X(m, n) (((m) << 4) | (n)) + // cases are commutative + #define Y(m, n) X(m, n): case X(n, m) + switch (X(mod1, mod2)) + { +#if 0 + case X(0, 0): + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODshared | MODconst, MODshared | MODconst): + case X(MODwild, MODwild): + case X(MODshared | MODwild, MODshared | MODwild): +#endif + + case Y(0, MODconst): + case Y(0, MODimmutable): + case Y(MODconst, MODimmutable): + case Y(MODconst, MODwild): + case Y(0, MODwild): + case Y(MODimmutable, MODwild): + return MODconst; + + case Y(0, MODshared): + return MODshared; + + case Y(0, MODshared | MODconst): + case Y(MODconst, MODshared): + case Y(MODconst, MODshared | MODconst): + case Y(MODimmutable, MODshared): + case Y(MODimmutable, MODshared | MODconst): + case Y(MODshared, MODshared | MODconst): + case Y(0, MODshared | MODwild): + case Y(MODconst, MODshared | MODwild): + case Y(MODimmutable, MODshared | MODwild): + case Y(MODshared, MODwild): + case Y(MODshared, MODshared | MODwild): + case Y(MODshared | MODconst, MODwild): + case Y(MODshared | MODconst, MODshared | MODwild): + return MODshared | MODconst; + + case Y(MODwild, MODshared | MODwild): + return MODshared | MODwild; + + default: + assert(0); + } + #undef Y + #undef X + assert(0); + return 0; +} + +/********************************* + * Mangling for mod. + */ +void MODtoDecoBuffer(OutBuffer *buf, unsigned char mod) +{ + switch (mod) + { case 0: + break; + case MODconst: + buf->writeByte('x'); + break; + case MODimmutable: + buf->writeByte('y'); + break; + case MODshared: + buf->writeByte('O'); + break; + case MODshared | MODconst: + buf->writestring("Ox"); + break; + case MODwild: + buf->writestring("Ng"); + break; + case MODshared | MODwild: + buf->writestring("ONg"); + break; + default: + assert(0); + } +} + +/********************************* + * Name for mod. + */ +void MODtoBuffer(OutBuffer *buf, unsigned char mod) +{ + switch (mod) + { case 0: + break; + + case MODimmutable: + buf->writestring(Token::tochars[TOKimmutable]); + break; + + case MODshared: + buf->writestring(Token::tochars[TOKshared]); + break; + + case MODshared | MODconst: + buf->writestring(Token::tochars[TOKshared]); + buf->writeByte(' '); + case MODconst: + buf->writestring(Token::tochars[TOKconst]); + break; + + case MODshared | MODwild: + buf->writestring(Token::tochars[TOKshared]); + buf->writeByte(' '); + case MODwild: + buf->writestring(Token::tochars[TOKwild]); + break; + default: + assert(0); + } +} + /******************************** * Name mangling. * Input: - * flag 0x100 do not do const/invariant + * flag 0x100 do not do const/invariant */ void Type::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) // Possible conflict from merge { if (flag != mod && flag != 0x100) { - if (mod & MODshared) - buf->writeByte('O'); - - if (mod & MODconst) - buf->writeByte('x'); - else if (mod & MODinvariant) - buf->writeByte('y'); - - // Cannot be both const and invariant - assert((mod & (MODconst | MODinvariant)) != (MODconst | MODinvariant)); + MODtoDecoBuffer(buf, mod); } buf->writeByte(mangleChar[ty]); } @@ -1110,16 +1474,16 @@ void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) { toCBuffer2(buf, hgs, 0); if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); + { buf->writeByte(' '); + buf->writestring(ident->toChars()); } } void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(toChars()); } @@ -1127,40 +1491,35 @@ void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { const char *p; - - if (this->mod & MODshared) - buf->writestring("shared("); - switch (this->mod & (MODconst | MODinvariant)) - { - case 0: - toCBuffer2(buf, hgs, this->mod); - break; - case MODconst: - p = "const("; - goto L1; - case MODinvariant: - p = "immutable("; - L1: buf->writestring(p); - toCBuffer2(buf, hgs, this->mod); - buf->writeByte(')'); - break; - default: - assert(0); - } - if (this->mod & MODshared) - buf->writeByte(')'); + { + if (this->mod & MODshared) + { + MODtoBuffer(buf, this->mod & MODshared); + buf->writeByte('('); + } + if (this->mod & ~MODshared) + { + MODtoBuffer(buf, this->mod & ~MODshared); + buf->writeByte('('); + toCBuffer2(buf, hgs, this->mod); + buf->writeByte(')'); + } + else + toCBuffer2(buf, hgs, this->mod); + if (this->mod & MODshared) + { + buf->writeByte(')'); + } } } void Type::modToBuffer(OutBuffer *buf) { - if (mod & MODshared) - buf->writestring(" shared"); - if (mod & MODconst) - buf->writestring(" const"); - if (mod & MODinvariant) - buf->writestring(" immutable"); + if (mod) + { + buf->writeByte(' '); + MODtoBuffer(buf, mod); + } } /************************************ @@ -1174,25 +1533,25 @@ Type *Type::merge() assert(t); if (!deco) { - OutBuffer buf; - StringValue *sv; + OutBuffer buf; + StringValue *sv; - //if (next) - //next = next->merge(); + //if (next) + //next = next->merge(); toDecoBuffer(&buf, false); - sv = stringtable.update((char *)buf.data, buf.offset); - if (sv->ptrvalue) - { t = (Type *) sv->ptrvalue; + sv = stringtable.update((char *)buf.data, buf.offset); + if (sv->ptrvalue) + { t = (Type *) sv->ptrvalue; #ifdef DEBUG - if (!t->deco) - printf("t = %s\n", t->toChars()); + if (!t->deco) + printf("t = %s\n", t->toChars()); #endif - assert(t->deco); - //printf("old value, deco = '%s' %p\n", t->deco, t->deco); - } - else - { - sv->ptrvalue = this; + assert(t->deco); + //printf("old value, deco = '%s' %p\n", t->deco, t->deco); + } + else + { + sv->ptrvalue = this; // we still need deco strings to be unique // or Type::equals fails, which breaks a bunch of stuff, @@ -1210,8 +1569,8 @@ Type *Type::merge() sv2->ptrvalue = this; deco = (char *)sv2->lstring.string; } - //printf("new value, deco = '%s' %p\n", t->deco, t->deco); - } + //printf("new value, deco = '%s' %p\n", t->deco, t->deco); + } } return t; } @@ -1226,15 +1585,15 @@ Type *Type::merge2() Type *t = this; assert(t); if (!t->deco) - return t->merge(); + return t->merge(); StringValue *sv = deco_stringtable.lookup((char *)t->deco, strlen(t->deco)); if (sv && sv->ptrvalue) { t = (Type *) sv->ptrvalue; - assert(t->deco); + assert(t->deco); } else - assert(0); + assert(0); return t; } @@ -1278,7 +1637,7 @@ ClassDeclaration *Type::isClassHandle() return NULL; } -int Type::isauto() +int Type::isscope() { return FALSE; } @@ -1290,9 +1649,9 @@ int Type::isString() /************************** * Given: - * T a, b; + * T a, b; * Can we assign: - * a = b; + * a = b; * ? */ int Type::isAssignable() @@ -1314,7 +1673,7 @@ void Type::checkDeprecated(Loc loc, Scope *sc) Dsymbol *s = toDsymbol(sc); if (s) - s->checkDeprecated(loc, sc); + s->checkDeprecated(loc, sc); } @@ -1326,21 +1685,33 @@ Expression *Type::defaultInit(Loc loc) return NULL; } +/*************************************** + * Use when we prefer the default initializer to be a literal, + * rather than a global immutable variable. + */ +Expression *Type::defaultInitLiteral(Loc loc) +{ +#if LOGDEFAULTINIT + printf("Type::defaultInitLiteral() '%s'\n", toChars()); +#endif + return defaultInit(loc); +} + int Type::isZeroInit(Loc loc) { - return 0; // assume not + return 0; // assume not } int Type::isBaseOf(Type *t, int *poffset) { - return 0; // assume not + return 0; // assume not } /******************************** * Determine if 'this' can be implicitly converted * to type 'to'. * Returns: - * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact + * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact */ MATCH Type::implicitConvTo(Type *to) @@ -1349,7 +1720,7 @@ MATCH Type::implicitConvTo(Type *to) //printf("from: %s\n", toChars()); //printf("to : %s\n", to->toChars()); if (this == to) - return MATCHexact; + return MATCHexact; return MATCHnomatch; } @@ -1361,51 +1732,59 @@ Expression *Type::getProperty(Loc loc, Identifier *ident) #endif if (ident == Id::__sizeof) { - e = new IntegerExp(loc, size(loc), Type::tsize_t); + e = new IntegerExp(loc, size(loc), Type::tsize_t); } else if (ident == Id::size) { - error(loc, ".size property should be replaced with .sizeof"); - e = new ErrorExp(); + error(loc, ".size property should be replaced with .sizeof"); + e = new ErrorExp(); } - else if (ident == Id::alignof) + else if (ident == Id::__xalignof) { - e = new IntegerExp(loc, alignsize(), Type::tsize_t); + e = new IntegerExp(loc, alignsize(), Type::tsize_t); } else if (ident == Id::typeinfo) { - if (!global.params.useDeprecated) - error(loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(NULL); + if (!global.params.useDeprecated) + error(loc, ".typeinfo deprecated, use typeid(type)"); + e = getTypeInfo(NULL); } else if (ident == Id::init) { - if (ty == Tvoid) - error(loc, "void does not have an initializer"); - e = defaultInit(loc); + if (ty == Tvoid) + error(loc, "void does not have an initializer"); + e = defaultInitLiteral(loc); } else if (ident == Id::mangleof) - { const char *s; - if (!deco) - { s = toChars(); - error(loc, "forward reference of type %s.mangleof", s); - } - else - s = deco; - e = new StringExp(loc, (char *)s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); + { const char *s; + if (!deco) + { s = toChars(); + error(loc, "forward reference of type %s.mangleof", s); + } + else + s = deco; + e = new StringExp(loc, (char *)s, strlen(s), 'c'); + Scope sc; + e = e->semantic(&sc); } else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); + { char *s = toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + Scope sc; + e = e->semantic(&sc); } else { - error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); - e = new ErrorExp(); + Dsymbol *s = NULL; + if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef) + s = toDsymbol(NULL); + if (s) + s = s->search_correct(ident); + if (s) + error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars()); + else + error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); + e = new ErrorExp(); } return e; } @@ -1418,81 +1797,154 @@ Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (e->op == TOKdotvar) { - DotVarExp *dv = (DotVarExp *)e; - v = dv->var->isVarDeclaration(); + DotVarExp *dv = (DotVarExp *)e; + v = dv->var->isVarDeclaration(); } else if (e->op == TOKvar) { - VarExp *ve = (VarExp *)e; - v = ve->var->isVarDeclaration(); + VarExp *ve = (VarExp *)e; + v = ve->var->isVarDeclaration(); } if (v) { - if (ident == Id::offset) - { - if (!global.params.useDeprecated) - error(e->loc, ".offset deprecated, use .offsetof"); - goto Loffset; - } - else if (ident == Id::offsetof) - { - Loffset: - if (v->storage_class & STCfield) - { - e = new IntegerExp(e->loc, v->offset, Type::tsize_t); - return e; - } - } - else if (ident == Id::init) - { + if (ident == Id::offset) + { + if (!global.params.useDeprecated) + error(e->loc, ".offset deprecated, use .offsetof"); + goto Loffset; + } + else if (ident == Id::offsetof) + { + Loffset: + if (v->storage_class & STCfield) + { + e = new IntegerExp(e->loc, v->offset, Type::tsize_t); + return e; + } + } + else if (ident == Id::init) + { #if 0 - if (v->init) - { - if (v->init->isVoidInitializer()) - error(e->loc, "%s.init is void", v->toChars()); - else - { Loc loc = e->loc; - e = v->init->toExpression(); - if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit) - { - e = ((AssignExp *)e)->e2; + if (v->init) + { + if (v->init->isVoidInitializer()) + error(e->loc, "%s.init is void", v->toChars()); + else + { Loc loc = e->loc; + e = v->init->toExpression(); + if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit) + { + e = ((AssignExp *)e)->e2; - /* Take care of case where we used a 0 - * to initialize the struct. - */ - if (e->type == Type::tint32 && - e->isBool(0) && - v->type->toBasetype()->ty == Tstruct) - { - e = v->type->defaultInit(e->loc); - } - } - e = e->optimize(WANTvalue | WANTinterpret); -// if (!e->isConst()) -// error(loc, ".init cannot be evaluated at compile time"); - } - return e; - } + /* Take care of case where we used a 0 + * to initialize the struct. + */ + if (e->type == Type::tint32 && + e->isBool(0) && + v->type->toBasetype()->ty == Tstruct) + { + e = v->type->defaultInit(e->loc); + } + } + e = e->optimize(WANTvalue | WANTinterpret); +// if (!e->isConst()) +// error(loc, ".init cannot be evaluated at compile time"); + } + goto Lreturn; + } #endif - Expression *ex = defaultInit(e->loc); - return ex; - } + e = defaultInitLiteral(e->loc); + goto Lreturn; + } } if (ident == Id::typeinfo) { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(sc); - return e; + if (!global.params.useDeprecated) + error(e->loc, ".typeinfo deprecated, use typeid(type)"); + e = getTypeInfo(sc); } - if (ident == Id::stringof) - { char *s = e->toChars(); - e = new StringExp(e->loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - return e; + else if (ident == Id::stringof) + { /* Bugzilla 3796: this should demangle e->type->deco rather than + * pretty-printing the type. + */ + char *s = e->toChars(); + e = new StringExp(e->loc, s, strlen(s), 'c'); } - return getProperty(e->loc, ident); + else + e = getProperty(e->loc, ident); + +Lreturn: + e = e->semantic(sc); + return e; +} + +/*************************************** + * Figures out what to do with an undefined member reference + * for classes and structs. + */ +Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) +{ + assert(ty == Tstruct || ty == Tclass); + AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration(); + assert(sym); + + if (ident != Id::__sizeof && + ident != Id::__xalignof && + ident != Id::init && + ident != Id::mangleof && + ident != Id::stringof && + ident != Id::offsetof) + { + /* See if we should forward to the alias this. + */ + if (sym->aliasthis) + { /* Rewrite e.ident as: + * e.aliasthis.ident + */ + e = new DotIdExp(e->loc, e, sym->aliasthis->ident); + e = new DotIdExp(e->loc, e, ident); + return e->semantic(sc); + } + + /* Look for overloaded opDot() to see if we should forward request + * to it. + */ + Dsymbol *fd = search_function(sym, Id::opDot); + if (fd) + { /* Rewrite e.ident as: + * e.opDot().ident + */ + e = build_overload(e->loc, sc, e, NULL, fd->ident); + e = new DotIdExp(e->loc, e, ident); + return e->semantic(sc); + } + + /* Look for overloaded opDispatch to see if we should forward request + * to it. + */ + fd = search_function(sym, Id::opDispatch); + if (fd) + { + /* Rewrite e.ident as: + * e.opDispatch!("ident") + */ + TemplateDeclaration *td = fd->isTemplateDeclaration(); + if (!td) + { + fd->error("must be a template opDispatch(string s), not a %s", fd->kind()); + return new ErrorExp(); + } + StringExp *se = new StringExp(e->loc, ident->toChars()); + Objects *tiargs = new Objects(); + tiargs->push(se); + e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); + ((DotTemplateInstanceExp *)e)->ti->tempdecl = td; + return e; + //return e->semantic(sc); + } + } + + return Type::dotExp(sc, e, ident); } unsigned Type::memalign(unsigned salign) @@ -1510,13 +1962,10 @@ void Type::error(Loc loc, const char *format, ...) void Type::warning(Loc loc, const char *format, ...) { - if (global.params.warnings && !global.gag) - { - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); - } + va_list ap; + va_start(ap, format); + ::vwarning(loc, format, ap); + va_end( ap ); } Identifier *Type::getTypeInfoIdent(int internal) @@ -1528,9 +1977,9 @@ Identifier *Type::getTypeInfoIdent(int internal) int len; if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); + { buf.writeByte(mangleChar[ty]); + if (ty == Tarray) + buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); } else toDecoBuffer(&buf, true); @@ -1577,6 +2026,24 @@ Type *Type::reliesOnTident() return NULL; } +/*************************************** + * Return !=0 if the type or any of its subtypes is wild. + */ + +int Type::hasWild() +{ + return mod & MODwild; +} + +/*************************************** + * Return MOD bits matching argument type (targ) to wild parameter type (this). + */ + +unsigned Type::wildMatch(Type *targ) +{ + return 0; +} + /******************************** * We've mistakenly parsed this as a type. * Redo it as an Expression. @@ -1616,28 +2083,46 @@ uinteger_t Type::sizemask() switch (toBasetype()->ty) { - case Tbool: m = 1; break; - case Tchar: - case Tint8: - case Tuns8: m = 0xFF; break; - case Twchar: - case Tint16: - case Tuns16: m = 0xFFFFUL; break; - case Tdchar: - case Tint32: - case Tuns32: m = 0xFFFFFFFFUL; break; - case Tint64: - case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break; - default: - assert(0); + case Tbool: m = 1; break; + case Tchar: + case Tint8: + case Tuns8: m = 0xFF; break; + case Twchar: + case Tint16: + case Tuns16: m = 0xFFFFUL; break; + case Tdchar: + case Tint32: + case Tuns32: m = 0xFFFFFFFFUL; break; + case Tint64: + case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break; + default: + assert(0); } return m; } +/* ============================= TypeError =========================== */ + +TypeError::TypeError() + : Type(Terror) +{ +} + +void TypeError::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) +{ + buf->writestring("_error_"); +} + +d_uns64 TypeError::size(Loc loc) { return 1; } +Expression *TypeError::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); } +Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); } +Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); } +Expression *TypeError::defaultInitLiteral(Loc loc) { return new ErrorExp(); } + /* ============================= TypeNext =========================== */ TypeNext::TypeNext(TY ty, Type *next) - : Type(ty) + : Type(ty) { this->next = next; } @@ -1653,8 +2138,8 @@ void TypeNext::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeNext::checkDeprecated(Loc loc, Scope *sc) { Type::checkDeprecated(loc, sc); - if (next) // next can be NULL if TypeFunction and auto return type - next->checkDeprecated(loc, sc); + if (next) // next can be NULL if TypeFunction and auto return type + next->checkDeprecated(loc, sc); } @@ -1663,6 +2148,35 @@ Type *TypeNext::reliesOnTident() return next->reliesOnTident(); } +int TypeNext::hasWild() +{ + return mod == MODwild || next->hasWild(); +} + +/*************************************** + * Return MOD bits matching argument type (targ) to wild parameter type (this). + */ + +unsigned TypeNext::wildMatch(Type *targ) +{ unsigned mod; + + Type *tb = targ->nextOf(); + if (!tb) + return 0; + tb = tb->toBasetype(); + if (tb->isMutable()) + mod = MODmutable; + else if (tb->isConst() || tb->isWild()) + return MODconst; + else if (tb->isImmutable()) + mod = MODimmutable; + else + assert(0); + mod |= next->wildMatch(tb); + return mod; +} + + /******************************* * For TypeFunction, nextOf() can return NULL if the function return * type is meant to be inferred, and semantic() hasn't yet ben run @@ -1678,17 +2192,21 @@ Type *TypeNext::makeConst() { //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); if (cto) - { assert(cto->mod == MODconst); - return cto; - } + { assert(cto->mod == MODconst); + return cto; + } TypeNext *t = (TypeNext *)Type::makeConst(); if (ty != Tfunction && ty != Tdelegate && - (next->deco || next->ty == Tfunction) && - !next->isInvariant() && !next->isConst()) - { if (next->isShared()) - t->next = next->sharedConstOf(); - else - t->next = next->constOf(); + (next->deco || next->ty == Tfunction) && + !next->isImmutable() && !next->isConst()) + { if (next->isShared()) + t->next = next->sharedConstOf(); + else + t->next = next->constOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it } //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars()); return t; @@ -1698,14 +2216,18 @@ Type *TypeNext::makeInvariant() { //printf("TypeNext::makeInvariant() %s\n", toChars()); if (ito) - { assert(ito->isInvariant()); - return ito; + { assert(ito->isImmutable()); + return ito; } TypeNext *t = (TypeNext *)Type::makeInvariant(); if (ty != Tfunction && ty != Tdelegate && - (next->deco || next->ty == Tfunction) && - !next->isInvariant()) - { t->next = next->invariantOf(); + (next->deco || next->ty == Tfunction) && + !next->isImmutable()) + { t->next = next->invariantOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it } return t; } @@ -1714,18 +2236,22 @@ Type *TypeNext::makeShared() { //printf("TypeNext::makeShared() %s\n", toChars()); if (sto) - { assert(sto->mod == MODshared); - return sto; - } + { assert(sto->mod == MODshared); + return sto; + } TypeNext *t = (TypeNext *)Type::makeShared(); if (ty != Tfunction && ty != Tdelegate && - (next->deco || next->ty == Tfunction) && - !next->isInvariant() && !next->isShared()) + (next->deco || next->ty == Tfunction) && + !next->isImmutable() && !next->isShared()) { - if (next->isConst()) - t->next = next->sharedConstOf(); - else - t->next = next->sharedOf(); + if (next->isConst() || next->isWild()) + t->next = next->sharedConstOf(); + else + t->next = next->sharedOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it } //printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars()); return t; @@ -1735,26 +2261,95 @@ Type *TypeNext::makeSharedConst() { //printf("TypeNext::makeSharedConst() %s\n", toChars()); if (scto) - { assert(scto->mod == (MODshared | MODconst)); - return scto; - } + { assert(scto->mod == (MODshared | MODconst)); + return scto; + } TypeNext *t = (TypeNext *)Type::makeSharedConst(); if (ty != Tfunction && ty != Tdelegate && - (next->deco || next->ty == Tfunction) && - !next->isInvariant() && !next->isSharedConst()) + (next->deco || next->ty == Tfunction) && + !next->isImmutable() && !next->isSharedConst()) { - t->next = next->sharedConstOf(); + t->next = next->sharedConstOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it } //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars()); return t; } +Type *TypeNext::makeWild() +{ + //printf("TypeNext::makeWild() %s\n", toChars()); + if (wto) + { assert(wto->mod == MODwild); + return wto; + } + TypeNext *t = (TypeNext *)Type::makeWild(); + if (ty != Tfunction && ty != Tdelegate && + (next->deco || next->ty == Tfunction) && + !next->isImmutable() && !next->isConst() && !next->isWild()) + { + if (next->isShared()) + t->next = next->sharedWildOf(); + else + t->next = next->wildOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it + } + //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars()); + return t; +} + +Type *TypeNext::makeSharedWild() +{ + //printf("TypeNext::makeSharedWild() %s\n", toChars()); + if (swto) + { assert(swto->isSharedWild()); + return swto; + } + TypeNext *t = (TypeNext *)Type::makeSharedWild(); + if (ty != Tfunction && ty != Tdelegate && + (next->deco || next->ty == Tfunction) && + !next->isImmutable() && !next->isSharedConst()) + { + t->next = next->sharedWildOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it + } + //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars()); + return t; +} + +Type *TypeNext::makeMutable() +{ + //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); + TypeNext *t = (TypeNext *)Type::makeMutable(); + if (ty != Tfunction && ty != Tdelegate && + (next->deco || next->ty == Tfunction) && + next->isWild()) + { + t->next = next->mutableOf(); + } + if (ty == Taarray) + { + ((TypeAArray *)t)->impl = NULL; // lazily recompute it + } + //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars()); + return t; +} + MATCH TypeNext::constConv(Type *to) { MATCH m = Type::constConv(to); if (m == MATCHconst && next->constConv(((TypeNext *)to)->next) == MATCHnomatch) - m = MATCHnomatch; + m = MATCHnomatch; return m; } @@ -1769,108 +2364,108 @@ void TypeNext::transitive() /* ============================= TypeBasic =========================== */ TypeBasic::TypeBasic(TY ty) - : Type(ty) + : Type(ty) { const char *d; unsigned flags; -#define TFLAGSintegral 1 -#define TFLAGSfloating 2 -#define TFLAGSunsigned 4 -#define TFLAGSreal 8 -#define TFLAGSimaginary 0x10 -#define TFLAGScomplex 0x20 +#define TFLAGSintegral 1 +#define TFLAGSfloating 2 +#define TFLAGSunsigned 4 +#define TFLAGSreal 8 +#define TFLAGSimaginary 0x10 +#define TFLAGScomplex 0x20 flags = 0; switch (ty) { - case Tvoid: d = Token::toChars(TOKvoid); - break; + case Tvoid: d = Token::toChars(TOKvoid); + break; - case Tint8: d = Token::toChars(TOKint8); - flags |= TFLAGSintegral; - break; + case Tint8: d = Token::toChars(TOKint8); + flags |= TFLAGSintegral; + break; - case Tuns8: d = Token::toChars(TOKuns8); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tuns8: d = Token::toChars(TOKuns8); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tint16: d = Token::toChars(TOKint16); - flags |= TFLAGSintegral; - break; + case Tint16: d = Token::toChars(TOKint16); + flags |= TFLAGSintegral; + break; - case Tuns16: d = Token::toChars(TOKuns16); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tuns16: d = Token::toChars(TOKuns16); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tint32: d = Token::toChars(TOKint32); - flags |= TFLAGSintegral; - break; + case Tint32: d = Token::toChars(TOKint32); + flags |= TFLAGSintegral; + break; - case Tuns32: d = Token::toChars(TOKuns32); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tuns32: d = Token::toChars(TOKuns32); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tfloat32: d = Token::toChars(TOKfloat32); - flags |= TFLAGSfloating | TFLAGSreal; - break; + case Tfloat32: d = Token::toChars(TOKfloat32); + flags |= TFLAGSfloating | TFLAGSreal; + break; - case Tint64: d = Token::toChars(TOKint64); - flags |= TFLAGSintegral; - break; + case Tint64: d = Token::toChars(TOKint64); + flags |= TFLAGSintegral; + break; - case Tuns64: d = Token::toChars(TOKuns64); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tuns64: d = Token::toChars(TOKuns64); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tfloat64: d = Token::toChars(TOKfloat64); - flags |= TFLAGSfloating | TFLAGSreal; - break; + case Tfloat64: d = Token::toChars(TOKfloat64); + flags |= TFLAGSfloating | TFLAGSreal; + break; - case Tfloat80: d = Token::toChars(TOKfloat80); - flags |= TFLAGSfloating | TFLAGSreal; - break; + case Tfloat80: d = Token::toChars(TOKfloat80); + flags |= TFLAGSfloating | TFLAGSreal; + break; - case Timaginary32: d = Token::toChars(TOKimaginary32); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; + case Timaginary32: d = Token::toChars(TOKimaginary32); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; - case Timaginary64: d = Token::toChars(TOKimaginary64); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; + case Timaginary64: d = Token::toChars(TOKimaginary64); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; - case Timaginary80: d = Token::toChars(TOKimaginary80); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; + case Timaginary80: d = Token::toChars(TOKimaginary80); + flags |= TFLAGSfloating | TFLAGSimaginary; + break; - case Tcomplex32: d = Token::toChars(TOKcomplex32); - flags |= TFLAGSfloating | TFLAGScomplex; - break; + case Tcomplex32: d = Token::toChars(TOKcomplex32); + flags |= TFLAGSfloating | TFLAGScomplex; + break; - case Tcomplex64: d = Token::toChars(TOKcomplex64); - flags |= TFLAGSfloating | TFLAGScomplex; - break; + case Tcomplex64: d = Token::toChars(TOKcomplex64); + flags |= TFLAGSfloating | TFLAGScomplex; + break; - case Tcomplex80: d = Token::toChars(TOKcomplex80); - flags |= TFLAGSfloating | TFLAGScomplex; - break; + case Tcomplex80: d = Token::toChars(TOKcomplex80); + flags |= TFLAGSfloating | TFLAGScomplex; + break; - case Tbool: d = "bool"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tbool: d = "bool"; + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tascii: d = Token::toChars(TOKchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tascii: d = Token::toChars(TOKchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Twchar: d = Token::toChars(TOKwchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Twchar: d = Token::toChars(TOKwchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - case Tdchar: d = Token::toChars(TOKdchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; + case Tdchar: d = Token::toChars(TOKdchar); + flags |= TFLAGSintegral | TFLAGSunsigned; + break; - default: assert(0); + default: assert(0); } this->dstring = d; this->flags = flags; @@ -1893,8 +2488,8 @@ void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { //printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod); if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(dstring); } @@ -1905,43 +2500,43 @@ d_uns64 TypeBasic::size(Loc loc) //printf("TypeBasic::size()\n"); switch (ty) { - case Tint8: - case Tuns8: size = 1; break; - case Tint16: - case Tuns16: size = 2; break; - case Tint32: - case Tuns32: - case Tfloat32: - case Timaginary32: - size = 4; break; - case Tint64: - case Tuns64: - case Tfloat64: - case Timaginary64: - size = 8; break; - case Tfloat80: - case Timaginary80: - size = REALSIZE; break; - case Tcomplex32: - size = 8; break; - case Tcomplex64: - size = 16; break; - case Tcomplex80: - size = REALSIZE * 2; break; + case Tint8: + case Tuns8: size = 1; break; + case Tint16: + case Tuns16: size = 2; break; + case Tint32: + case Tuns32: + case Tfloat32: + case Timaginary32: + size = 4; break; + case Tint64: + case Tuns64: + case Tfloat64: + case Timaginary64: + size = 8; break; + case Tfloat80: + case Timaginary80: + size = REALSIZE; break; + case Tcomplex32: + size = 8; break; + case Tcomplex64: + size = 16; break; + case Tcomplex80: + size = REALSIZE * 2; break; - case Tvoid: - //size = Type::size(); // error message - size = 1; - break; + case Tvoid: + //size = Type::size(); // error message + size = 1; + break; - case Tbool: size = 1; break; - case Tascii: size = 1; break; - case Twchar: size = 2; break; - case Tdchar: size = 4; break; + case Tbool: size = 1; break; + case Tascii: size = 1; break; + case Twchar: size = 2; break; + case Tdchar: size = 4; break; - default: - assert(0); - break; + default: + assert(0); + break; } //printf("TypeBasic::size() = %d\n", size); return size; @@ -1953,19 +2548,19 @@ unsigned TypeBasic::alignsize() return 1; return GetTypeAlignment(sir, this); #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_SOLARIS - case Tint64: - case Tuns64: - case Tfloat64: - case Timaginary64: - case Tcomplex32: - case Tcomplex64: - sz = 4; - break; + case Tint64: + case Tuns64: + case Tfloat64: + case Timaginary64: + case Tcomplex32: + case Tcomplex64: + sz = 4; + break; #endif #if IN_DMD - default: - sz = size(0); - break; + default: + sz = size(0); + break; } return sz; #endif @@ -1985,200 +2580,218 @@ Expression *TypeBasic::getProperty(Loc loc, Identifier *ident) //printf("TypeBasic::getProperty('%s')\n", ident->toChars()); if (ident == Id::max) { - switch (ty) - { - case Tint8: ivalue = 0x7F; goto Livalue; - case Tuns8: ivalue = 0xFF; goto Livalue; - case Tint16: ivalue = 0x7FFFUL; goto Livalue; - case Tuns16: ivalue = 0xFFFFUL; goto Livalue; - case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue; - case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; - case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; - case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; - case Tbool: ivalue = 1; goto Livalue; - case Tchar: ivalue = 0xFF; goto Livalue; - case Twchar: ivalue = 0xFFFFUL; goto Livalue; - case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; + switch (ty) + { + case Tint8: ivalue = 0x7F; goto Livalue; + case Tuns8: ivalue = 0xFF; goto Livalue; + case Tint16: ivalue = 0x7FFFUL; goto Livalue; + case Tuns16: ivalue = 0xFFFFUL; goto Livalue; + case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue; + case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; + case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; + case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; + case Tbool: ivalue = 1; goto Livalue; + case Tchar: ivalue = 0xFF; goto Livalue; + case Twchar: ivalue = 0xFFFFUL; goto Livalue; + case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_MAX; goto Lfvalue; - } + case Tcomplex32: + case Timaginary32: + case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; + case Tcomplex64: + case Timaginary64: + case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; + case Tcomplex80: + case Timaginary80: + case Tfloat80: fvalue = Port::ldbl_max; goto Lfvalue; + } } else if (ident == Id::min) { - switch (ty) - { - case Tint8: ivalue = -128; goto Livalue; - case Tuns8: ivalue = 0; goto Livalue; - case Tint16: ivalue = -32768; goto Livalue; - case Tuns16: ivalue = 0; goto Livalue; - case Tint32: ivalue = -2147483647L - 1; goto Livalue; - case Tuns32: ivalue = 0; goto Livalue; - case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; - case Tuns64: ivalue = 0; goto Livalue; - case Tbool: ivalue = 0; goto Livalue; - case Tchar: ivalue = 0; goto Livalue; - case Twchar: ivalue = 0; goto Livalue; - case Tdchar: ivalue = 0; goto Livalue; + switch (ty) + { + case Tint8: ivalue = -128; goto Livalue; + case Tuns8: ivalue = 0; goto Livalue; + case Tint16: ivalue = -32768; goto Livalue; + case Tuns16: ivalue = 0; goto Livalue; + case Tint32: ivalue = -2147483647L - 1; goto Livalue; + case Tuns32: ivalue = 0; goto Livalue; + case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; + case Tuns64: ivalue = 0; goto Livalue; + case Tbool: ivalue = 0; goto Livalue; + case Tchar: ivalue = 0; goto Livalue; + case Twchar: ivalue = 0; goto Livalue; + case Tdchar: ivalue = 0; goto Livalue; - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MIN; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MIN; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue; - } + case Tcomplex32: + case Timaginary32: + case Tfloat32: + case Tcomplex64: + case Timaginary64: + case Tfloat64: + case Tcomplex80: + case Timaginary80: + case Tfloat80: + // For backwards compatibility - eventually, deprecate + goto Lmin_normal; + } + } + else if (ident == Id::min_normal) + { + Lmin_normal: + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: fvalue = FLT_MIN; goto Lfvalue; + case Tcomplex64: + case Timaginary64: + case Tfloat64: fvalue = DBL_MIN; goto Lfvalue; + case Tcomplex80: + case Timaginary80: + case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue; + } } else if (ident == Id::nan) { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - { - fvalue = Port::nan; - goto Lfvalue; - } - } + switch (ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + case Timaginary32: + case Timaginary64: + case Timaginary80: + case Tfloat32: + case Tfloat64: + case Tfloat80: + { + fvalue = Port::nan; + goto Lfvalue; + } + } } else if (ident == Id::infinity) { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - fvalue = Port::infinity; - goto Lfvalue; - } + switch (ty) + { + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + case Timaginary32: + case Timaginary64: + case Timaginary80: + case Tfloat32: + case Tfloat64: + case Tfloat80: + fvalue = Port::infinity; + goto Lfvalue; + } } else if (ident == Id::dig) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_DIG; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_DIG; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_DIG; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_DIG; goto Lint; + } } else if (ident == Id::epsilon) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue; + case Tcomplex64: + case Timaginary64: + case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue; + case Tcomplex80: + case Timaginary80: + case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue; + } } else if (ident == Id::mant_dig) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint; + } } else if (ident == Id::max_10_exp) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint; + } } else if (ident == Id::max_exp) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint; + } } else if (ident == Id::min_10_exp) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint; + } } else if (ident == Id::min_exp) { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint; - } + switch (ty) + { + case Tcomplex32: + case Timaginary32: + case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint; + case Tcomplex64: + case Timaginary64: + case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint; + case Tcomplex80: + case Timaginary80: + case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint; + } } Ldefault: @@ -2190,23 +2803,23 @@ Livalue: Lfvalue: if (isreal() || isimaginary()) - e = new RealExp(loc, fvalue, this); + e = new RealExp(loc, fvalue, this); else { - complex_t cvalue; + complex_t cvalue; #if __DMC__ - //((real_t *)&cvalue)[0] = fvalue; - //((real_t *)&cvalue)[1] = fvalue; - cvalue = fvalue + fvalue * I; + //((real_t *)&cvalue)[0] = fvalue; + //((real_t *)&cvalue)[1] = fvalue; + cvalue = fvalue + fvalue * I; #else - cvalue.re = fvalue; - cvalue.im = fvalue; + cvalue.re = fvalue; + cvalue.im = fvalue; #endif - //for (int i = 0; i < 20; i++) - // printf("%02x ", ((unsigned char *)&cvalue)[i]); - //printf("\n"); - e = new ComplexExp(loc, cvalue, this); + //for (int i = 0; i < 20; i++) + // printf("%02x ", ((unsigned char *)&cvalue)[i]); + //printf("\n"); + e = new ComplexExp(loc, cvalue, this); } return e; @@ -2224,66 +2837,69 @@ Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) if (ident == Id::re) { - switch (ty) - { - case Tcomplex32: t = tfloat32; goto L1; - case Tcomplex64: t = tfloat64; goto L1; - case Tcomplex80: t = tfloat80; goto L1; - L1: - e = e->castTo(sc, t); - break; + switch (ty) + { + case Tcomplex32: t = tfloat32; goto L1; + case Tcomplex64: t = tfloat64; goto L1; + case Tcomplex80: t = tfloat80; goto L1; + L1: + e = e->castTo(sc, t); + break; - case Tfloat32: - case Tfloat64: - case Tfloat80: - break; + case Tfloat32: + case Tfloat64: + case Tfloat80: + break; - case Timaginary32: t = tfloat32; goto L2; - case Timaginary64: t = tfloat64; goto L2; - case Timaginary80: t = tfloat80; goto L2; - L2: - e = new RealExp(0, 0.0, t); - break; + case Timaginary32: t = tfloat32; goto L2; + case Timaginary64: t = tfloat64; goto L2; + case Timaginary80: t = tfloat80; goto L2; + L2: + e = new RealExp(0, 0.0, t); + break; - default: - return Type::getProperty(e->loc, ident); - } + default: + e = Type::getProperty(e->loc, ident); + break; + } } else if (ident == Id::im) - { Type *t2; + { Type *t2; - switch (ty) - { - case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3; - case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3; - case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3; - L3: - e = e->castTo(sc, t); - e->type = t2; - break; + switch (ty) + { + case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3; + case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3; + case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3; + L3: + e = e->castTo(sc, t); + e->type = t2; + break; - case Timaginary32: t = tfloat32; goto L4; - case Timaginary64: t = tfloat64; goto L4; - case Timaginary80: t = tfloat80; goto L4; - L4: - e = e->copy(); - e->type = t; - break; + case Timaginary32: t = tfloat32; goto L4; + case Timaginary64: t = tfloat64; goto L4; + case Timaginary80: t = tfloat80; goto L4; + L4: + e = e->copy(); + e->type = t; + break; - case Tfloat32: - case Tfloat64: - case Tfloat80: - e = new RealExp(0, 0.0, this); - break; + case Tfloat32: + case Tfloat64: + case Tfloat80: + e = new RealExp(0, 0.0, this); + break; - default: - return Type::getProperty(e->loc, ident); - } + default: + e = Type::getProperty(e->loc, ident); + break; + } } else { - return Type::dotExp(sc, e, ident); + return Type::dotExp(sc, e, ident); } + e = e->semantic(sc); return e; } @@ -2296,14 +2912,17 @@ Expression *TypeBasic::defaultInit(Loc loc) * so that uninitialised variables can be * detected even if exceptions are disabled. */ - unsigned short snan[8] = { 0, 0, 0, 0xA000, 0x7FFF }; + union + { unsigned short us[8]; + long double ld; + } snan = {{ 0, 0, 0, 0xA000, 0x7FFF }}; /* * Although long doubles are 10 bytes long, some * C ABIs pad them out to 12 or even 16 bytes, so * leave enough space in the snan array. */ assert(REALSIZE <= sizeof(snan)); - d_float80 fvalue = *(long double*)snan; + d_float80 fvalue = snan.ld; #endif #if LOGDEFAULTINIT @@ -2311,43 +2930,44 @@ Expression *TypeBasic::defaultInit(Loc loc) #endif switch (ty) { - case Tchar: - value = 0xFF; - break; + case Tchar: + value = 0xFF; + break; - case Twchar: - case Tdchar: - value = 0xFFFF; - break; + case Twchar: + case Tdchar: + value = 0xFFFF; + break; - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: + case Timaginary32: + case Timaginary64: + case Timaginary80: + case Tfloat32: + case Tfloat64: + case Tfloat80: #if SNAN_DEFAULT_INIT - return new RealExp(loc, fvalue, this); + return new RealExp(loc, fvalue, this); #else - return getProperty(loc, Id::nan); + return getProperty(loc, Id::nan); #endif - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: #if SNAN_DEFAULT_INIT - { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). - complex_t cvalue; - ((real_t *)&cvalue)[0] = fvalue; - ((real_t *)&cvalue)[1] = fvalue; - return new ComplexExp(loc, cvalue, this); - } + { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). + complex_t cvalue; + ((real_t *)&cvalue)[0] = fvalue; + ((real_t *)&cvalue)[1] = fvalue; + return new ComplexExp(loc, cvalue, this); + } #else - return getProperty(loc, Id::nan); + return getProperty(loc, Id::nan); #endif - case Tvoid: - error(loc, "void does not have a default initializer"); + case Tvoid: + error(loc, "void does not have a default initializer"); + return new ErrorExp(); } return new IntegerExp(loc, value, this); } @@ -2356,21 +2976,21 @@ int TypeBasic::isZeroInit(Loc loc) { switch (ty) { - case Tchar: - case Twchar: - case Tdchar: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - return 0; // no + case Tchar: + case Twchar: + case Tdchar: + case Timaginary32: + case Timaginary64: + case Timaginary80: + case Tfloat32: + case Tfloat64: + case Tfloat80: + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: + return 0; // no } - return 1; // yes + return 1; // yes } int TypeBasic::isintegral() @@ -2413,68 +3033,68 @@ MATCH TypeBasic::implicitConvTo(Type *to) { //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); if (this == to) - return MATCHexact; + return MATCHexact; #if DMDV2 if (ty == to->ty) { - return (mod == to->mod) ? MATCHexact : MATCHconst; + return (mod == to->mod) ? MATCHexact : MATCHconst; } #endif if (ty == Tvoid || to->ty == Tvoid) - return MATCHnomatch; + return MATCHnomatch; if (to->ty == Tbool) - return MATCHnomatch; + return MATCHnomatch; if (!to->isTypeBasic()) - return MATCHnomatch; + return MATCHnomatch; TypeBasic *tob = (TypeBasic *)to; if (flags & TFLAGSintegral) { - // Disallow implicit conversion of integers to imaginary or complex - if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) - return MATCHnomatch; + // Disallow implicit conversion of integers to imaginary or complex + if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) + return MATCHnomatch; #if DMDV2 - // If converting from integral to integral - if (1 && tob->flags & TFLAGSintegral) - { d_uns64 sz = size(0); - d_uns64 tosz = tob->size(0); + // If converting from integral to integral + if (1 && tob->flags & TFLAGSintegral) + { d_uns64 sz = size(0); + d_uns64 tosz = tob->size(0); - /* Can't convert to smaller size - */ - if (sz > tosz) - return MATCHnomatch; + /* Can't convert to smaller size + */ + if (sz > tosz) + return MATCHnomatch; - /* Can't change sign if same size - */ - /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) - return MATCHnomatch;*/ - } + /* Can't change sign if same size + */ + /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) + return MATCHnomatch;*/ + } #endif } else if (flags & TFLAGSfloating) { - // Disallow implicit conversion of floating point to integer - if (tob->flags & TFLAGSintegral) - return MATCHnomatch; + // Disallow implicit conversion of floating point to integer + if (tob->flags & TFLAGSintegral) + return MATCHnomatch; - assert(tob->flags & TFLAGSfloating); + assert(tob->flags & TFLAGSfloating); - // Disallow implicit conversion from complex to non-complex - if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex)) - return MATCHnomatch; + // Disallow implicit conversion from complex to non-complex + if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex)) + return MATCHnomatch; - // Disallow implicit conversion of real or imaginary to complex - if (flags & (TFLAGSreal | TFLAGSimaginary) && - tob->flags & TFLAGScomplex) - return MATCHnomatch; + // Disallow implicit conversion of real or imaginary to complex + if (flags & (TFLAGSreal | TFLAGSimaginary) && + tob->flags & TFLAGScomplex) + return MATCHnomatch; - // Disallow implicit conversion to-from real and imaginary - if ((flags & (TFLAGSreal | TFLAGSimaginary)) != - (tob->flags & (TFLAGSreal | TFLAGSimaginary))) - return MATCHnomatch; + // Disallow implicit conversion to-from real and imaginary + if ((flags & (TFLAGSreal | TFLAGSimaginary)) != + (tob->flags & (TFLAGSreal | TFLAGSimaginary))) + return MATCHnomatch; } return MATCHconvert; } @@ -2493,29 +3113,29 @@ TypeArray::TypeArray(TY ty, Type *next) Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) { - Type *n = this->next->toBasetype(); // uncover any typedef's + Type *n = this->next->toBasetype(); // uncover any typedef's #if LOGDOTEXP printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); #endif if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar)) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; //LDC: Build arguments. static FuncDeclaration *adReverseChar_fd = NULL; if(!adReverseChar_fd) { - Arguments* args = new Arguments; + Parameters* args = new Parameters; Type* arrty = Type::tchar->arrayOf(); - args->push(new Argument(STCin, arrty, NULL, NULL)); + args->push(new Parameter(STCin, arrty, NULL, NULL)); adReverseChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseChar"); } static FuncDeclaration *adReverseWchar_fd = NULL; if(!adReverseWchar_fd) { - Arguments* args = new Arguments; + Parameters* args = new Parameters; Type* arrty = Type::twchar->arrayOf(); - args->push(new Argument(STCin, arrty, NULL, NULL)); + args->push(new Parameter(STCin, arrty, NULL, NULL)); adReverseWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseWchar"); } @@ -2523,30 +3143,30 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) ec = new VarExp(0, adReverseWchar_fd); else ec = new VarExp(0, adReverseChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments->push(e); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); } else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar)) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; //LDC: Build arguments. static FuncDeclaration *adSortChar_fd = NULL; if(!adSortChar_fd) { - Arguments* args = new Arguments; + Parameters* args = new Parameters; Type* arrty = Type::tchar->arrayOf(); - args->push(new Argument(STCin, arrty, NULL, NULL)); + args->push(new Parameter(STCin, arrty, NULL, NULL)); adSortChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortChar"); } static FuncDeclaration *adSortWchar_fd = NULL; if(!adSortWchar_fd) { - Arguments* args = new Arguments; + Parameters* args = new Parameters; Type* arrty = Type::twchar->arrayOf(); - args->push(new Argument(STCin, arrty, NULL, NULL)); + args->push(new Parameter(STCin, arrty, NULL, NULL)); adSortWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortWchar"); } @@ -2554,34 +3174,34 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) ec = new VarExp(0, adSortWchar_fd); else ec = new VarExp(0, adSortChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + arguments->push(e); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); } else if (ident == Id::reverse || ident == Id::dup || ident == Id::idup) { - Expression *ec; - Expressions *arguments; - int size = next->size(e->loc); - int dup; + Expression *ec; + Expressions *arguments; + int size = next->size(e->loc); + int dup; - assert(size); - dup = (ident == Id::dup || ident == Id::idup); + assert(size); + dup = (ident == Id::dup || ident == Id::idup); //LDC: Build arguments. static FuncDeclaration *adDup_fd = NULL; if(!adDup_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL)); - args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL)); + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); + args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup); } static FuncDeclaration *adReverse_fd = NULL; if(!adReverse_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); + args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); adReverse_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adReverse); } @@ -2589,10 +3209,10 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) ec = new VarExp(0, adDup_fd); else ec = new VarExp(0, adReverse_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - if (dup) - arguments->push(getTypeInfo(sc)); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); + if (dup) + arguments->push(getTypeInfo(sc)); // LDC repaint array type to void[] if (n->ty != Tvoid) { @@ -2601,37 +3221,37 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } arguments->push(e); - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - if (ident == Id::idup) - { Type *einv = next->invariantOf(); - if (next->implicitConvTo(einv) < MATCHconst) - error(e->loc, "cannot implicitly convert element type %s to immutable", next->toChars()); - e->type = einv->arrayOf(); - } - else - e->type = next->mutableOf()->arrayOf(); + if (!dup) + arguments->push(new IntegerExp(0, size, Type::tsize_t)); + e = new CallExp(e->loc, ec, arguments); + if (ident == Id::idup) + { Type *einv = next->invariantOf(); + if (next->implicitConvTo(einv) < MATCHconst) + error(e->loc, "cannot implicitly convert element type %s to immutable", next->toChars()); + e->type = einv->arrayOf(); + } + else + e->type = next->mutableOf()->arrayOf(); } else if (ident == Id::sort) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; bool isBit = (n->ty == Tbit); //LDC: Build arguments. static FuncDeclaration *adSort_fd = NULL; if(!adSort_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL)); + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); + args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort"); } static FuncDeclaration *adSortBit_fd = NULL; if(!adSortBit_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL)); + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); + args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); adSortBit_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSortBit"); } @@ -2639,26 +3259,27 @@ Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) ec = new VarExp(0, adSortBit_fd); else ec = new VarExp(0, adSort_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); + e = e->castTo(sc, n->arrayOf()); // convert to dynamic array + arguments = new Expressions(); // LDC repaint array type to void[] if (n->ty != Tvoid) { e = new CastExp(e->loc, e, e->type); e->type = Type::tvoid->arrayOf(); } - arguments->push(e); + arguments->push(e); if (next->ty != Tbit) arguments->push(n->getTypeInfo(sc)); // LDC, we don't support the getInternalTypeInfo // optimization arbitrarily, not yet at least... - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); } else { - e = Type::dotExp(sc, e, ident); + e = Type::dotExp(sc, e, ident); } + e = e->semantic(sc); return e; } @@ -2685,16 +3306,16 @@ d_uns64 TypeSArray::size(Loc loc) { dinteger_t sz; if (!dim) - return Type::size(loc); + return Type::size(loc); sz = dim->toInteger(); - { dinteger_t n, n2; + { dinteger_t n, n2; - n = next->size(); - n2 = n * sz; - if (n && (n2 / n) != sz) - goto Loverflow; - sz = n2; + n = next->size(); + n2 = n * sz; + if (n && (n2 / n) != sz) + goto Loverflow; + sz = n2; } return sz; @@ -2715,16 +3336,16 @@ unsigned TypeSArray::alignsize() Expression *semanticLength(Scope *sc, Type *t, Expression *exp) { if (t->ty == Ttuple) - { ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t); - sym->parent = sc->scopesym; - sc = sc->push(sym); + { ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t); + sym->parent = sc->scopesym; + sc = sc->push(sym); - exp = exp->semantic(sc); + exp = exp->semantic(sc); - sc->pop(); + sc->pop(); } else - exp = exp->semantic(sc); + exp = exp->semantic(sc); return exp; } @@ -2746,61 +3367,61 @@ void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol next->resolve(loc, sc, pe, pt, ps); //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); if (*pe) - { // It's really an index expression - Expression *e = new IndexExp(loc, *pe, dim); - *pe = e; + { // It's really an index expression + Expression *e = new IndexExp(loc, *pe, dim); + *pe = e; } else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); - sym->parent = sc->scopesym; - sc = sc->push(sym); + { Dsymbol *s = *ps; + TupleDeclaration *td = s->isTupleDeclaration(); + if (td) + { + ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); + sym->parent = sc->scopesym; + sc = sc->push(sym); - dim = dim->semantic(sc); - dim = dim->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); + dim = dim->semantic(sc); + dim = dim->optimize(WANTvalue | WANTinterpret); + uinteger_t d = dim->toUInteger(); - sc = sc->pop(); + sc = sc->pop(); - if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); - goto Ldefault; - } - Object *o = (Object *)td->objects->data[(size_t)d]; - if (o->dyncast() == DYNCAST_DSYMBOL) - { - *ps = (Dsymbol *)o; - return; - } - if (o->dyncast() == DYNCAST_EXPRESSION) - { - *ps = NULL; - *pe = (Expression *)o; - return; - } + if (d >= td->objects->dim) + { error(loc, "tuple index %ju exceeds %u", d, td->objects->dim); + goto Ldefault; + } + Object *o = (Object *)td->objects->data[(size_t)d]; + if (o->dyncast() == DYNCAST_DSYMBOL) + { + *ps = (Dsymbol *)o; + return; + } + if (o->dyncast() == DYNCAST_EXPRESSION) + { + *ps = NULL; + *pe = (Expression *)o; + return; + } - /* Create a new TupleDeclaration which - * is a slice [d..d+1] out of the old one. - * Do it this way because TemplateInstance::semanticTiargs() - * can handle unresolved Objects this way. - */ - Objects *objects = new Objects; - objects->setDim(1); - objects->data[0] = o; + /* Create a new TupleDeclaration which + * is a slice [d..d+1] out of the old one. + * Do it this way because TemplateInstance::semanticTiargs() + * can handle unresolved Objects this way. + */ + Objects *objects = new Objects; + objects->setDim(1); + objects->data[0] = o; - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; + TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); + *ps = tds; + } + else + goto Ldefault; } else { Ldefault: - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps); } } @@ -2813,23 +3434,23 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) Dsymbol *s; next->resolve(loc, sc, &e, &t, &s); if (dim && s && s->isTupleDeclaration()) - { TupleDeclaration *sd = s->isTupleDeclaration(); + { TupleDeclaration *sd = s->isTupleDeclaration(); - dim = semanticLength(sc, sd, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); + dim = semanticLength(sc, sd, dim); + dim = dim->optimize(WANTvalue | WANTinterpret); + uinteger_t d = dim->toUInteger(); - if (d >= sd->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); - return Type::terror; - } - Object *o = (Object *)sd->objects->data[(size_t)d]; - if (o->dyncast() != DYNCAST_TYPE) - { error(loc, "%s is not a type", toChars()); - return Type::terror; - } - t = (Type *)o; - return t; + if (d >= sd->objects->dim) + { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); + return Type::terror; + } + Object *o = (Object *)sd->objects->data[(size_t)d]; + if (o->dyncast() != DYNCAST_TYPE) + { error(loc, "%s is not a type", toChars()); + return Type::terror; + } + t = (Type *)o; + return t; } next = next->semantic(loc,sc); @@ -2838,81 +3459,81 @@ Type *TypeSArray::semantic(Loc loc, Scope *sc) Type *tbn = next->toBasetype(); if (dim) - { dinteger_t n, n2; + { dinteger_t n, n2; - dim = semanticLength(sc, tbn, dim); + dim = semanticLength(sc, tbn, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); - if (sc && sc->parameterSpecialization && dim->op == TOKvar && - ((VarExp *)dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : T[N], size_t N); - */ - return this; - } - dinteger_t d1 = dim->toInteger(); - dim = dim->castTo(sc, tsize_t); - dim = dim->optimize(WANTvalue); - dinteger_t d2 = dim->toInteger(); + dim = dim->optimize(WANTvalue | WANTinterpret); + if (sc && sc->parameterSpecialization && dim->op == TOKvar && + ((VarExp *)dim)->var->storage_class & STCtemplateparameter) + { + /* It could be a template parameter N which has no value yet: + * template Foo(T : T[N], size_t N); + */ + return this; + } + dinteger_t d1 = dim->toInteger(); + dim = dim->castTo(sc, tsize_t); + dim = dim->optimize(WANTvalue); + dinteger_t d2 = dim->toInteger(); - if (d1 != d2) - goto Loverflow; + if (d1 != d2) + goto Loverflow; - if (tbn->isintegral() || - tbn->isfloating() || - tbn->ty == Tpointer || - tbn->ty == Tarray || - tbn->ty == Tsarray || - tbn->ty == Taarray || - tbn->ty == Tclass) - { - /* Only do this for types that don't need to have semantic() - * run on them for the size, since they may be forward referenced. - */ - n = tbn->size(loc); - n2 = n * d2; - if ((int)n2 < 0) - goto Loverflow; - if (n2 >= 0x1000000) // put a 'reasonable' limit on it - goto Loverflow; - if (n && n2 / n != d2) - { - Loverflow: - error(loc, "index %jd overflow for static array", d1); - dim = new IntegerExp(0, 1, tsize_t); - } - } + if (tbn->isintegral() || + tbn->isfloating() || + tbn->ty == Tpointer || + tbn->ty == Tarray || + tbn->ty == Tsarray || + tbn->ty == Taarray || + tbn->ty == Tclass) + { + /* Only do this for types that don't need to have semantic() + * run on them for the size, since they may be forward referenced. + */ + n = tbn->size(loc); + n2 = n * d2; + if ((int)n2 < 0) + goto Loverflow; + if (n2 >= 0x1000000) // put a 'reasonable' limit on it + goto Loverflow; + if (n && n2 / n != d2) + { + Loverflow: + error(loc, "index %jd overflow for static array", d1); + dim = new IntegerExp(0, 1, tsize_t); + } + } } switch (tbn->ty) { - case Ttuple: - { // Index the tuple to get the type - assert(dim); - TypeTuple *tt = (TypeTuple *)tbn; - uinteger_t d = dim->toUInteger(); + case Ttuple: + { // Index the tuple to get the type + assert(dim); + TypeTuple *tt = (TypeTuple *)tbn; + uinteger_t d = dim->toUInteger(); - if (d >= tt->arguments->dim) - { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); - return Type::terror; - } - Argument *arg = (Argument *)tt->arguments->data[(size_t)d]; - return arg->type; - } - case Tstruct: - { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) - error(loc, "cannot have array of inner structs %s", ts->toChars()); - break; - } - case Tfunction: - case Tnone: - error(loc, "can't have array of %s", tbn->toChars()); - tbn = next = tint32; - break; + if (d >= tt->arguments->dim) + { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); + return Type::terror; + } + Parameter *arg = (Parameter *)tt->arguments->data[(size_t)d]; + return arg->type; + } + case Tstruct: + { TypeStruct *ts = (TypeStruct *)tbn; + if (ts->sym->isnested) + error(loc, "cannot have array of inner structs %s", ts->toChars()); + break; + } + case Tfunction: + case Tnone: + error(loc, "can't have array of %s", tbn->toChars()); + tbn = next = tint32; + break; } - if (tbn->isauto()) - error(loc, "cannot have array of auto %s", tbn->toChars()); + if (tbn->isscope()) + error(loc, "cannot have array of scope %s", tbn->toChars()); return merge(); } @@ -2920,21 +3541,21 @@ void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) { Type::toDecoBuffer(buf, flag, mangle); if (dim) - buf->printf("%ju", dim->toInteger()); + buf->printf("%ju", dim->toInteger()); if (next) - /* Note that static arrays are value types, so - * for a parameter, propagate the 0x100 to the next - * level, since for T[4][3], any const should apply to the T, - * not the [4]. - */ + /* Note that static arrays are value types, so + * for a parameter, propagate the 0x100 to the next + * level, since for T[4][3], any const should apply to the T, + * not the [4]. + */ next->toDecoBuffer(buf, (flag & 0x100) ? flag : mod, mangle); } void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); buf->printf("[%s]", dim->toChars()); @@ -2947,16 +3568,17 @@ Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (ident == Id::length) { - e = dim; + e = dim; } else if (ident == Id::ptr) { - e = e->castTo(sc, next->pointerTo()); + e = e->castTo(sc, next->pointerTo()); } else { - e = TypeArray::dotExp(sc, e, ident); + e = TypeArray::dotExp(sc, e, ident); } + e = e->semantic(sc); return e; } @@ -2975,9 +3597,9 @@ MATCH TypeSArray::constConv(Type *to) { if (to->ty == Tsarray) { - TypeSArray *tsa = (TypeSArray *)to; - if (!dim->equals(tsa->dim)) - return MATCHnomatch; + TypeSArray *tsa = (TypeSArray *)to; + if (!dim->equals(tsa->dim)) + return MATCHnomatch; } return TypeNext::constConv(to); } @@ -2989,53 +3611,54 @@ MATCH TypeSArray::implicitConvTo(Type *to) // Allow implicit conversion of static array to pointer or dynamic array if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) { - TypePointer *tp = (TypePointer *)to; + TypePointer *tp = (TypePointer *)to; - if (next->mod != tp->next->mod && tp->next->mod != MODconst) - return MATCHnomatch; + if (!MODimplicitConv(next->mod, tp->next->mod)) + return MATCHnomatch; - if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch) - { - return MATCHconvert; - } - return MATCHnomatch; + if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch) + { + return MATCHconvert; + } + return MATCHnomatch; } if (to->ty == Tarray) - { int offset = 0; - TypeDArray *ta = (TypeDArray *)to; + { int offset = 0; + TypeDArray *ta = (TypeDArray *)to; - if (next->mod != ta->next->mod && ta->next->mod != MODconst) - return MATCHnomatch; + if (!MODimplicitConv(next->mod, ta->next->mod)) + return MATCHnomatch; - if (next->equals(ta->next) || - next->implicitConvTo(ta->next) >= MATCHconst || - (ta->next->isBaseOf(next, &offset) && offset == 0) || - ta->next->ty == Tvoid) - return MATCHconvert; - return MATCHnomatch; + if (next->equals(ta->next) || +// next->implicitConvTo(ta->next) >= MATCHconst || + next->constConv(ta->next) != MATCHnomatch || + (ta->next->isBaseOf(next, &offset) && offset == 0) || + ta->next->ty == Tvoid) + return MATCHconvert; + return MATCHnomatch; } if (to->ty == Tsarray) { - if (this == to) - return MATCHexact; + if (this == to) + return MATCHexact; - TypeSArray *tsa = (TypeSArray *)to; + TypeSArray *tsa = (TypeSArray *)to; - if (dim->equals(tsa->dim)) - { - /* Since static arrays are value types, allow - * conversions from const elements to non-const - * ones, just like we allow conversion from const int - * to int. - */ - MATCH m = next->implicitConvTo(tsa->next); - if (m >= MATCHconst) - { - if (mod != to->mod) - m = MATCHconst; - return m; - } - } + if (dim->equals(tsa->dim)) + { + /* Since static arrays are value types, allow + * conversions from const elements to non-const + * ones, just like we allow conversion from const int + * to int. + */ + MATCH m = next->implicitConvTo(tsa->next); + if (m >= MATCHconst) + { + if (mod != to->mod) + m = MATCHconst; + return m; + } + } } return MATCHnomatch; } @@ -3053,14 +3676,29 @@ int TypeSArray::isZeroInit(Loc loc) return next->isZeroInit(loc); } +Expression *TypeSArray::defaultInitLiteral(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); +#endif + size_t d = dim->toInteger(); + Expression *elementinit = next->defaultInitLiteral(loc); + Expressions *elements = new Expressions(); + elements->setDim(d); + for (size_t i = 0; i < d; i++) + elements->data[i] = elementinit; + ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); + ae->type = this; + return ae; +} Expression *TypeSArray::toExpression() { Expression *e = next->toExpression(); if (e) - { Expressions *arguments = new Expressions(); - arguments->push(dim); - e = new ArrayExp(dim->loc, e, arguments); + { Expressions *arguments = new Expressions(); + arguments->push(dim); + e = new ArrayExp(dim->loc, e, arguments); } return e; } @@ -3082,10 +3720,10 @@ Type *TypeDArray::syntaxCopy() { Type *t = next->syntaxCopy(); if (t == next) - t = this; + t = this; else - { t = new TypeDArray(t); - t->mod = mod; + { t = new TypeDArray(t); + t->mod = mod; } return t; } @@ -3110,21 +3748,21 @@ Type *TypeDArray::semantic(Loc loc, Scope *sc) Type *tbn = tn->toBasetype(); switch (tbn->ty) { - case Tfunction: - case Tnone: - case Ttuple: - error(loc, "can't have array of %s", tbn->toChars()); - tn = next = tint32; - break; - case Tstruct: - { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) - error(loc, "cannot have array of inner structs %s", ts->toChars()); - break; - } + case Tfunction: + case Tnone: + case Ttuple: + error(loc, "can't have array of %s", tbn->toChars()); + tn = next = tint32; + break; + case Tstruct: + { TypeStruct *ts = (TypeStruct *)tbn; + if (ts->sym->isnested) + error(loc, "cannot have array of inner structs %s", ts->toChars()); + break; + } } - if (tn->isauto()) - error(loc, "cannot have array of auto %s", tn->toChars()); + if (tn->isscope()) + error(loc, "cannot have array of scope %s", tn->toChars()); next = tn; transitive(); @@ -3141,11 +3779,15 @@ void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; + } + if (equals(tstring)) + buf->writestring("string"); + else + { next->toCBuffer2(buf, hgs, this->mod); + buf->writestring("[]"); } - next->toCBuffer2(buf, hgs, this->mod); - buf->writestring("[]"); } Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) @@ -3155,23 +3797,23 @@ Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (ident == Id::length) { - if (e->op == TOKstring) - { StringExp *se = (StringExp *)e; + if (e->op == TOKstring) + { StringExp *se = (StringExp *)e; - return new IntegerExp(se->loc, se->len, Type::tindex); - } - e = new ArrayLengthExp(e->loc, e); - e->type = Type::tsize_t; - return e; + return new IntegerExp(se->loc, se->len, Type::tindex); + } + e = new ArrayLengthExp(e->loc, e); + e->type = Type::tsize_t; + return e; } else if (ident == Id::ptr) { - e = e->castTo(sc, next->pointerTo()); - return e; + e = e->castTo(sc, next->pointerTo()); + return e; } else { - e = TypeArray::dotExp(sc, e, ident); + e = TypeArray::dotExp(sc, e, ident); } return e; } @@ -3186,59 +3828,61 @@ MATCH TypeDArray::implicitConvTo(Type *to) { //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); if (equals(to)) - return MATCHexact; + return MATCHexact; // Allow implicit conversion of array to pointer if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) { - TypePointer *tp = (TypePointer *)to; + TypePointer *tp = (TypePointer *)to; - /* Allow conversion to void* - */ - if (tp->next->ty == Tvoid && - (next->mod == tp->next->mod || tp->next->mod == MODconst)) - { - return MATCHconvert; - } + /* Allow conversion to void* + */ + if (tp->next->ty == Tvoid && + MODimplicitConv(next->mod, tp->next->mod)) + { + return MATCHconvert; + } - return next->constConv(to); + return next->constConv(to); } if (to->ty == Tarray) - { int offset = 0; - TypeDArray *ta = (TypeDArray *)to; + { int offset = 0; + TypeDArray *ta = (TypeDArray *)to; - if (!(next->mod == ta->next->mod || ta->next->mod == MODconst)) - return MATCHnomatch; // not const-compatible + if (!MODimplicitConv(next->mod, ta->next->mod)) + return MATCHnomatch; // not const-compatible - /* Allow conversion to void[] - */ - if (next->ty != Tvoid && ta->next->ty == Tvoid) - { - return MATCHconvert; - } + /* Allow conversion to void[] + */ + if (next->ty != Tvoid && ta->next->ty == Tvoid) + { + return MATCHconvert; + } - MATCH m = next->constConv(ta->next); - if (m != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - return m; - } + MATCH m = next->constConv(ta->next); + if (m != MATCHnomatch) + { + if (m == MATCHexact && mod != to->mod) + m = MATCHconst; + return m; + } - /* Allow conversions of T[][] to const(T)[][] - */ - if (mod == ta->mod && next->ty == Tarray && ta->next->ty == Tarray) - { - m = next->implicitConvTo(ta->next); - if (m == MATCHconst) - return m; - } +#if 0 + /* Allow conversions of T[][] to const(T)[][] + */ + if (mod == ta->mod && next->ty == Tarray && ta->next->ty == Tarray) + { + m = next->implicitConvTo(ta->next); + if (m == MATCHconst) + return m; + } +#endif - /* Conversion of array of derived to array of base - */ - if (ta->next->isBaseOf(next, &offset) && offset == 0) - return MATCHconvert; + /* Conversion of array of derived to array of base + */ + if (ta->next->isBaseOf(next, &offset) && offset == 0) + return MATCHconvert; } return Type::implicitConvTo(to); } @@ -3248,10 +3892,7 @@ Expression *TypeDArray::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeDArray::defaultInit() '%s'\n", toChars()); #endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypeDArray::isZeroInit(Loc loc) @@ -3275,7 +3916,7 @@ int TypeDArray::hasPointers() #if 0 TypeNewArray::TypeNewArray(Type *telement) - : TypeArray(Tnewarray, telement) + : TypeArray(Tnewarray, telement) { sym = NULL; } @@ -3284,10 +3925,10 @@ Type *TypeNewArray::syntaxCopy() { Type *t = next->syntaxCopy(); if (t == next) - t = this; + t = this; else - { t = new TypeNewArray(t); - t->mod = mod; + { t = new TypeNewArray(t); + t->mod = mod; } return t; } @@ -3310,21 +3951,21 @@ Type *TypeNewArray::semantic(Loc loc, Scope *sc) Type *tbn = tn->toBasetype(); switch (tbn->ty) { - case Tfunction: - case Tnone: - case Ttuple: - error(loc, "can't have array of %s", tbn->toChars()); - tn = next = tint32; - break; - case Tstruct: - { TypeStruct *ts = (TypeStruct *)tbn; - if (ts->sym->isnested) - error(loc, "cannot have array of inner structs %s", ts->toChars()); - break; - } + case Tfunction: + case Tnone: + case Ttuple: + error(loc, "can't have array of %s", tbn->toChars()); + tn = next = tint32; + break; + case Tstruct: + { TypeStruct *ts = (TypeStruct *)tbn; + if (ts->sym->isnested) + error(loc, "cannot have array of inner structs %s", ts->toChars()); + break; + } } - if (tn->isauto()) - error(loc, "cannot have array of auto %s", tn->toChars()); + if (tn->isscope()) + error(loc, "cannot have array of scope %s", tn->toChars()); next = tn; transitive(); @@ -3336,14 +3977,14 @@ void TypeNewArray::toDecoBuffer(OutBuffer *buf, int flag) Type::toDecoBuffer(buf, flag); buf->writeByte('e'); if (next) - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); + next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod); } void TypeNewArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); buf->writestring("[new]"); @@ -3357,6 +3998,9 @@ TypeAArray::TypeAArray(Type *t, Type *index) : TypeArray(Taarray, t) { this->index = index; + this->impl = NULL; + this->loc = 0; + this->sc = NULL; } Type *TypeAArray::syntaxCopy() @@ -3364,10 +4008,10 @@ Type *TypeAArray::syntaxCopy() Type *t = next->syntaxCopy(); Type *ti = index->syntaxCopy(); if (t == next && ti == index) - t = this; + t = this; else - { t = new TypeAArray(t, ti); - t->mod = mod; + { t = new TypeAArray(t, ti); + t->mod = mod; } return t; } @@ -3381,35 +4025,41 @@ d_uns64 TypeAArray::size(Loc loc) Type *TypeAArray::semantic(Loc loc, Scope *sc) { //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty); + this->loc = loc; + this->sc = sc; + if (sc) + sc->setNoFree(); // Deal with the case where we thought the index was a type, but // in reality it was an expression. if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) { - Expression *e; - Type *t; - Dsymbol *s; + Expression *e; + Type *t; + Dsymbol *s; - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array - TypeSArray *tsa; + index->resolve(loc, sc, &e, &t, &s); + if (e) + { // It was an expression - + // Rewrite as a static array + TypeSArray *tsa; - tsa = new TypeSArray(next, e); - return tsa->semantic(loc,sc); - } - else if (t) - index = t; - else - index->error(loc, "index is not a type or an expression"); + tsa = new TypeSArray(next, e); + return tsa->semantic(loc,sc); + } + else if (t) + index = t; + else + { index->error(loc, "index is not a type or an expression"); + return Type::terror; + } } else - index = index->semantic(loc,sc); + index = index->semantic(loc,sc); - if (index->nextOf() && !index->nextOf()->isInvariant()) + if (index->nextOf() && !index->nextOf()->isImmutable()) { - index = index->constOf()->mutableOf(); + index = index->constOf()->mutableOf(); #if 0 printf("index is %p %s\n", index, index->toChars()); index->check(); @@ -3424,29 +4074,87 @@ printf("index->ito->ito = x%x\n", index->ito->ito); switch (index->toBasetype()->ty) { - case Tbool: - case Tfunction: - case Tvoid: - case Tnone: - error(loc, "can't have associative array key of %s", index->toBasetype()->toChars()); - break; + case Tbool: + case Tfunction: + case Tvoid: + case Tnone: + case Ttuple: + error(loc, "can't have associative array key of %s", index->toBasetype()->toChars()); + return Type::terror; } next = next->semantic(loc,sc); transitive(); switch (next->toBasetype()->ty) { - case Tfunction: - case Tnone: - error(loc, "can't have associative array of %s", next->toChars()); - break; + case Tfunction: + case Tnone: + error(loc, "can't have associative array of %s", next->toChars()); + return Type::terror; + } + if (next->isscope()) + { error(loc, "cannot have array of scope %s", next->toChars()); + return Type::terror; } - if (next->isauto()) - error(loc, "cannot have array of auto %s", next->toChars()); - return merge(); } +StructDeclaration *TypeAArray::getImpl() +{ + // Do it lazily + if (!impl) + { + Type *index = this->index; + Type *next = this->next; + if (index->reliesOnTident() || next->reliesOnTident()) + { + error(loc, "cannot create associative array %s", toChars()); + index = terror; + next = terror; + + // Head off future failures + StructDeclaration *s = new StructDeclaration(0, NULL); + s->type = terror; + impl = s; + return impl; + } + /* This is really a proxy for the template instance AssocArray!(index, next) + * But the instantiation can fail if it is a template specialization field + * which has Tident's instead of real types. + */ + Objects *tiargs = new Objects(); + tiargs->push(index); + tiargs->push(next); + + // Create AssociativeArray!(index, next) +#if 1 + TemplateInstance *ti = new TemplateInstance(loc, Type::associativearray, tiargs); +#else + //Expression *e = new IdentifierExp(loc, Id::object); + Expression *e = new IdentifierExp(loc, Id::empty); + //e = new DotIdExp(loc, e, Id::object); + DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(loc, + e, + Id::AssociativeArray, + tiargs); + dti->semantic(sc); + TemplateInstance *ti = dti->ti; +#endif + ti->semantic(sc); + ti->semantic2(sc); + ti->semantic3(sc); + impl = ti->toAlias()->isStructDeclaration(); +#ifdef DEBUG + if (!impl) + { Dsymbol *s = ti->toAlias(); + printf("%s %s\n", s->kind(), s->toChars()); + } +#endif + assert(impl); + } + return impl; +} + void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) { //printf("TypeAArray::resolve() %s\n", toChars()); @@ -3455,22 +4163,22 @@ void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol // in reality it was an expression. if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) { - Expression *e; - Type *t; - Dsymbol *s; + Expression *e; + Type *t; + Dsymbol *s; - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array + index->resolve(loc, sc, &e, &t, &s); + if (e) + { // It was an expression - + // Rewrite as a static array - TypeSArray *tsa = new TypeSArray(next, e); - return tsa->resolve(loc, sc, pe, pt, ps); - } - else if (t) - index = t; - else - index->error(loc, "index is not a type or an expression"); + TypeSArray *tsa = new TypeSArray(next, e); + return tsa->resolve(loc, sc, pe, pt, ps); + } + else if (t) + index = t; + else + index->error(loc, "index is not a type or an expression"); } Type::resolve(loc, sc, pe, pt, ps); } @@ -3481,10 +4189,11 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) #if LOGDOTEXP printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); #endif +#if 0 if (ident == Id::length) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; //LDC: Build arguments. static FuncDeclaration *aaLen_fd = NULL; @@ -3495,18 +4204,19 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } ec = new VarExp(0, aaLen_fd); - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); + arguments = new Expressions(); + arguments->push(e); + e = new CallExp(e->loc, ec, arguments); e->type = aaLen_fd->type->nextOf(); } - else if (ident == Id::keys) + else + if (ident == Id::keys) { - Expression *ec; - Expressions *arguments; - int size = index->size(e->loc); + Expression *ec; + Expressions *arguments; + int size = index->size(e->loc); - assert(size); + assert(size); //LDC: Build arguments. static FuncDeclaration *aaKeys_fd = NULL; if(!aaKeys_fd) { @@ -3517,16 +4227,16 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } ec = new VarExp(0, aaKeys_fd); - arguments = new Expressions(); - arguments->push(e); - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = index->arrayOf(); + arguments = new Expressions(); + arguments->push(e); + arguments->push(new IntegerExp(0, size, Type::tsize_t)); + e = new CallExp(e->loc, ec, arguments); + e->type = index->arrayOf(); } else if (ident == Id::values) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; //LDC: Build arguments. static FuncDeclaration *aaValues_fd = NULL; @@ -3539,19 +4249,19 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } ec = new VarExp(0, aaValues_fd); - arguments = new Expressions(); - arguments->push(e); - size_t keysize = index->size(e->loc); - keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); - arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); - arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); + arguments = new Expressions(); + arguments->push(e); + size_t keysize = index->size(e->loc); + keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); + arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); + arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); + e = new CallExp(e->loc, ec, arguments); + e->type = next->arrayOf(); } else if (ident == Id::rehash) { - Expression *ec; - Expressions *arguments; + Expression *ec; + Expressions *arguments; //LDC: Build arguments. static FuncDeclaration *aaRehash_fd = NULL; @@ -3563,15 +4273,18 @@ Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) } ec = new VarExp(0, aaRehash_fd); - arguments = new Expressions(); - arguments->push(e->addressOf(sc)); + arguments = new Expressions(); + arguments->push(e->addressOf(sc)); arguments->push(index->getInternalTypeInfo(sc)); // LDC doesn't support getInternalTypeInfo, see above - e = new CallExp(e->loc, ec, arguments); - e->type = this; + e = new CallExp(e->loc, ec, arguments); + e->type = this; } else +#endif { - e = Type::dotExp(sc, e, ident); + e->type = getImpl()->type; + e = e->type->dotExp(sc, e, ident); + //e = Type::dotExp(sc, e, ident); } return e; } @@ -3586,8 +4299,8 @@ void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); buf->writeByte('['); @@ -3600,10 +4313,7 @@ Expression *TypeAArray::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeAArray::defaultInit() '%s'\n", toChars()); #endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypeAArray::isZeroInit(Loc loc) @@ -3625,27 +4335,27 @@ MATCH TypeAArray::implicitConvTo(Type *to) { //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); if (equals(to)) - return MATCHexact; + return MATCHexact; if (to->ty == Taarray) - { TypeAArray *ta = (TypeAArray *)to; + { TypeAArray *ta = (TypeAArray *)to; - if (!(next->mod == ta->next->mod || ta->next->mod == MODconst)) - return MATCHnomatch; // not const-compatible + if (!MODimplicitConv(next->mod, ta->next->mod)) + return MATCHnomatch; // not const-compatible - if (!(index->mod == ta->index->mod || ta->index->mod == MODconst)) - return MATCHnomatch; // not const-compatible + if (!MODimplicitConv(index->mod, ta->index->mod)) + return MATCHnomatch; // not const-compatible - MATCH m = next->constConv(ta->next); - MATCH mi = index->constConv(ta->index); - if (m != MATCHnomatch && mi != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - if (mi < m) - m = mi; - return m; - } + MATCH m = next->constConv(ta->next); + MATCH mi = index->constConv(ta->index); + if (m != MATCHnomatch && mi != MATCHnomatch) + { + if (m == MATCHexact && mod != to->mod) + m = MATCHconst; + if (mi < m) + m = mi; + return m; + } } return Type::implicitConvTo(to); } @@ -3654,14 +4364,14 @@ MATCH TypeAArray::constConv(Type *to) { if (to->ty == Taarray) { - TypeAArray *taa = (TypeAArray *)to; - MATCH mindex = index->constConv(taa->index); - MATCH mkey = next->constConv(taa->next); - // Pick the worst match - return mkey < mindex ? mkey : mindex; + TypeAArray *taa = (TypeAArray *)to; + MATCH mindex = index->constConv(taa->index); + MATCH mkey = next->constConv(taa->next); + // Pick the worst match + return mkey < mindex ? mkey : mindex; } else - return Type::constConv(to); + return Type::constConv(to); } /***************************** TypePointer *****************************/ @@ -3675,10 +4385,10 @@ Type *TypePointer::syntaxCopy() { Type *t = next->syntaxCopy(); if (t == next) - t = this; + t = this; else - { t = new TypePointer(t); - t->mod = mod; + { t = new TypePointer(t); + t->mod = mod; } return t; } @@ -3687,18 +4397,18 @@ Type *TypePointer::semantic(Loc loc, Scope *sc) { //printf("TypePointer::semantic()\n"); if (deco) - return this; + return this; Type *n = next->semantic(loc, sc); switch (n->toBasetype()->ty) { - case Ttuple: - error(loc, "can't have pointer to %s", n->toChars()); - n = tint32; - break; + case Ttuple: + error(loc, "can't have pointer to %s", n->toChars()); + n = tint32; + break; } if (n != next) { - deco = NULL; + deco = NULL; } next = n; transitive(); @@ -3715,12 +4425,12 @@ void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); if (next->ty != Tfunction) - buf->writeByte('*'); + buf->writeByte('*'); } MATCH TypePointer::implicitConvTo(Type *to) @@ -3728,12 +4438,12 @@ MATCH TypePointer::implicitConvTo(Type *to) //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); if (equals(to)) - return MATCHexact; + return MATCHexact; if (to->ty == Tpointer) - { TypePointer *tp = (TypePointer *)to; - assert(tp->next); + { TypePointer *tp = (TypePointer *)to; + assert(tp->next); - if (!(next->mod == tp->next->mod || tp->next->mod == MODconst)) + if (!MODimplicitConv(next->mod, tp->next->mod)) return MATCHnomatch; // not const-compatible /* Alloc conversion to void[] @@ -3745,15 +4455,15 @@ MATCH TypePointer::implicitConvTo(Type *to) MATCH m = next->constConv(tp->next); if (m != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; + { + if (m == MATCHexact && mod != to->mod) + m = MATCHconst; return m; - } + } /* Conversion of ptr to derived to ptr to base */ - int offset = 0; + int offset = 0; if (tp->next->isBaseOf(next, &offset) && offset == 0) return MATCHconvert; } @@ -3770,10 +4480,7 @@ Expression *TypePointer::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypePointer::defaultInit() '%s'\n", toChars()); #endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypePointer::isZeroInit(Loc loc) @@ -3799,10 +4506,10 @@ Type *TypeReference::syntaxCopy() { Type *t = next->syntaxCopy(); if (t == next) - t = this; + t = this; else - { t = new TypeReference(t); - t->mod = mod; + { t = new TypeReference(t); + t->mod = mod; } return t; } @@ -3812,7 +4519,7 @@ Type *TypeReference::semantic(Loc loc, Scope *sc) //printf("TypeReference::semantic()\n"); Type *n = next->semantic(loc, sc); if (n != next) - deco = NULL; + deco = NULL; next = n; transitive(); return merge(); @@ -3827,8 +4534,8 @@ d_uns64 TypeReference::size(Loc loc) void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); buf->writeByte('&'); @@ -3849,9 +4556,7 @@ Expression *TypeReference::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeReference::defaultInit() '%s'\n", toChars()); #endif - Expression *e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypeReference::isZeroInit(Loc loc) @@ -3862,7 +4567,7 @@ int TypeReference::isZeroInit(Loc loc) /***************************** TypeFunction *****************************/ -TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage) +TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc) : TypeNext(Tfunction, treturn) { //if (!treturn) *(char*)0=0; @@ -3876,32 +4581,49 @@ TypeFunction::TypeFunction(Arguments *parameters, Type *treturn, int varargs, en this->ispure = false; this->isproperty = false; this->isref = false; + this->fargs = NULL; #if IN_LLVM this->funcdecl = NULL; #endif + if (stc & STCnothrow) + this->isnothrow = true; + if (stc & STCproperty) + this->isproperty = true; + + this->trust = TRUSTdefault; + if (stc & STCsafe) + this->trust = TRUSTsafe; + if (stc & STCsystem) + this->trust = TRUSTsystem; + if (stc & STCtrusted) + this->trust = TRUSTtrusted; } Type *TypeFunction::syntaxCopy() { Type *treturn = next ? next->syntaxCopy() : NULL; - Arguments *params = Argument::arraySyntaxCopy(parameters); + Parameters *params = Parameter::arraySyntaxCopy(parameters); TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage); t->mod = mod; t->isnothrow = isnothrow; t->ispure = ispure; t->isproperty = isproperty; t->isref = isref; + t->trust = trust; + t->fargs = fargs; return t; } /******************************* + * Covariant means that 'this' can substitute for 't', + * i.e. a pure function is a match for an impure type. * Returns: - * 0 types are distinct - * 1 this is covariant with t - * 2 arguments match as far as overloading goes, - * but types are not covariant - * 3 cannot determine covariance because of forward references + * 0 types are distinct + * 1 this is covariant with t + * 2 arguments match as far as overloading goes, + * but types are not covariant + * 3 cannot determine covariance because of forward references */ int Type::covariant(Type *t) @@ -3919,101 +4641,119 @@ int Type::covariant(Type *t) TypeFunction *t2; if (equals(t)) - return 1; // covariant + return 1; // covariant if (ty != Tfunction || t->ty != Tfunction) - goto Ldistinct; + goto Ldistinct; t1 = (TypeFunction *)this; t2 = (TypeFunction *)t; if (t1->varargs != t2->varargs) - goto Ldistinct; + goto Ldistinct; if (t1->parameters && t2->parameters) { - size_t dim = Argument::dim(t1->parameters); - if (dim != Argument::dim(t2->parameters)) - goto Ldistinct; + size_t dim = Parameter::dim(t1->parameters); + if (dim != Parameter::dim(t2->parameters)) + goto Ldistinct; - for (size_t i = 0; i < dim; i++) - { Argument *arg1 = Argument::getNth(t1->parameters, i); - Argument *arg2 = Argument::getNth(t2->parameters, i); + for (size_t i = 0; i < dim; i++) + { Parameter *arg1 = Parameter::getNth(t1->parameters, i); + Parameter *arg2 = Parameter::getNth(t2->parameters, i); - if (!arg1->type->equals(arg2->type)) - { + if (!arg1->type->equals(arg2->type)) + { #if 0 // turn on this for contravariant argument types, see bugzilla 3075 - // We can add const, but not subtract it - if (arg2->type->implicitConvTo(arg1->type) < MATCHconst) + // BUG: cannot convert ref to const to ref to immutable + // We can add const, but not subtract it + if (arg2->type->implicitConvTo(arg1->type) < MATCHconst) #endif - goto Ldistinct; - } - if ((arg1->storageClass & ~STCscope) != (arg2->storageClass & ~STCscope)) - inoutmismatch = 1; - // We can add scope, but not subtract it - if (!(arg1->storageClass & STCscope) && (arg2->storageClass & STCscope)) - inoutmismatch = 1; - } + goto Ldistinct; + } + const StorageClass sc = STCref | STCin | STCout | STClazy; + if ((arg1->storageClass & sc) != (arg2->storageClass & sc)) + inoutmismatch = 1; + // We can add scope, but not subtract it + if (!(arg1->storageClass & STCscope) && (arg2->storageClass & STCscope)) + inoutmismatch = 1; + } } else if (t1->parameters != t2->parameters) - goto Ldistinct; + goto Ldistinct; // The argument lists match if (inoutmismatch) - goto Lnotcovariant; + goto Lnotcovariant; if (t1->linkage != t2->linkage) - goto Lnotcovariant; + goto Lnotcovariant; { - // Return types + // Return types Type *t1n = t1->next; Type *t2n = t2->next; + if (!t1n || !t2n) // happens with return type inference + goto Lnotcovariant; + if (t1n->equals(t2n)) - goto Lcovariant; + goto Lcovariant; if (t1n->ty == Tclass && t2n->ty == Tclass) { - /* If same class type, but t2n is const, then it's - * covariant. Do this test first because it can work on - * forward references. - */ - if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym && - t2n->mod == MODconst) - goto Lcovariant; + /* If same class type, but t2n is const, then it's + * covariant. Do this test first because it can work on + * forward references. + */ + if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym && + MODimplicitConv(t1n->mod, t2n->mod)) + goto Lcovariant; - // If t1n is forward referenced: - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; - if (!cd->baseClass && cd->baseclasses.dim && !cd->isInterfaceDeclaration()) - { - return 3; - } + // If t1n is forward referenced: + ClassDeclaration *cd = ((TypeClass *)t1n)->sym; +#if 0 + if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) +#else + if (!cd->isBaseInfoComplete()) +#endif + { + return 3; // forward references + } } if (t1n->implicitConvTo(t2n)) - goto Lcovariant; + goto Lcovariant; } goto Lnotcovariant; Lcovariant: /* Can convert mutable to const */ + if (!MODimplicitConv(t2->mod, t1->mod)) + goto Lnotcovariant; +#if 0 if (t1->mod != t2->mod) { - if (!(t1->mod & MODconst) && (t2->mod & MODconst)) - goto Lnotcovariant; - if (!(t1->mod & MODshared) && (t2->mod & MODshared)) - goto Lnotcovariant; + if (!(t1->mod & MODconst) && (t2->mod & MODconst)) + goto Lnotcovariant; + if (!(t1->mod & MODshared) && (t2->mod & MODshared)) + goto Lnotcovariant; } +#endif /* Can convert pure to impure, and nothrow to throw */ if (!t1->ispure && t2->ispure) - goto Lnotcovariant; + goto Lnotcovariant; if (!t1->isnothrow && t2->isnothrow) - goto Lnotcovariant; + goto Lnotcovariant; if (t1->isref != t2->isref) - goto Lnotcovariant; + goto Lnotcovariant; + + /* Can convert safe/trusted to system + */ + if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted) + goto Lnotcovariant; //printf("\tcovaraint: 1\n"); return 1; @@ -4033,43 +4773,45 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars()); //static int nest; if (++nest == 50) *(char*)0=0; if (inuse) - { inuse = 2; // flag error to caller - return; + { inuse = 2; // flag error to caller + return; } inuse++; -#if 1 - if (mod & MODshared) - buf->writeByte('O'); - if (mod & MODconst) - buf->writeByte('x'); - else if (mod & MODinvariant) - buf->writeByte('y'); -#endif + MODtoDecoBuffer(buf, mod); switch (linkage) { - case LINKd: mc = 'F'; break; - case LINKc: mc = 'U'; break; - case LINKwindows: mc = 'W'; break; - case LINKpascal: mc = 'V'; break; - case LINKcpp: mc = 'R'; break; + case LINKd: mc = 'F'; break; + case LINKc: mc = 'U'; break; + case LINKwindows: mc = 'W'; break; + case LINKpascal: mc = 'V'; break; + case LINKcpp: mc = 'R'; break; // LDC case LINKintrinsic: mc = 'Q'; break; - default: - assert(0); + default: + assert(0); } buf->writeByte(mc); - if (ispure || isnothrow || isproperty || isref) + if (ispure || isnothrow || isproperty || isref || trust) { - if (ispure) - buf->writestring("Na"); - if (isnothrow) - buf->writestring("Nb"); - if (isref) - buf->writestring("Nc"); - if (isproperty) - buf->writestring("Nd"); + if (ispure) + buf->writestring("Na"); + if (isnothrow) + buf->writestring("Nb"); + if (isref) + buf->writestring("Nc"); + if (isproperty) + buf->writestring("Nd"); + switch (trust) + { + case TRUSTtrusted: + buf->writestring("Ne"); + break; + case TRUSTsafe: + buf->writestring("Nf"); + break; + } } // LDC: if we're not producing a mangle string, add the this @@ -4098,9 +4840,10 @@ void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) } // Write argument types - Argument::argsToDecoBuffer(buf, parameters, mangle); + Parameter::argsToDecoBuffer(buf, parameters, mangle); //if (buf->data[buf->offset - 1] == '@') halt(); - buf->writeByte('Z' - varargs); // mark end of arg list + buf->writeByte('Z' - varargs); // mark end of arg list + assert(next); next->toDecoBuffer(buf, mangle); inuse--; } @@ -4111,56 +4854,70 @@ void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs const char *p = NULL; if (inuse) - { inuse = 2; // flag error to caller - return; + { inuse = 2; // flag error to caller + return; } inuse++; /* Use 'storage class' style for attributes */ - if (mod & MODconst) - buf->writestring("const "); - if (mod & MODinvariant) - buf->writestring("immutable "); - if (mod & MODshared) - buf->writestring("shared "); + if (mod) + { + MODtoBuffer(buf, mod); + buf->writeByte(' '); + } if (ispure) - buf->writestring("pure "); + buf->writestring("pure "); if (isnothrow) - buf->writestring("nothrow "); + buf->writestring("nothrow "); if (isproperty) - buf->writestring("@property "); + buf->writestring("@property "); if (isref) - buf->writestring("ref "); + buf->writestring("ref "); + + switch (trust) + { + case TRUSTsystem: + buf->writestring("@system "); + break; + + case TRUSTtrusted: + buf->writestring("@trusted "); + break; + + case TRUSTsafe: + buf->writestring("@safe "); + break; + } if (next && (!ident || ident->toHChars2() == ident->toChars())) - next->toCBuffer2(buf, hgs, 0); + next->toCBuffer2(buf, hgs, 0); if (hgs->ddoc != 1) { - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; + switch (linkage) + { + case LINKd: p = NULL; break; + case LINKc: p = "C "; break; + case LINKwindows: p = "Windows "; break; + case LINKpascal: p = "Pascal "; break; + case LINKcpp: p = "C++ "; break; // LDC case LINKintrinsic: p = "Intrinsic"; break; - default: - assert(0); - } + default: + assert(0); + } } if (!hgs->hdrgen && p) - buf->writestring(p); + buf->writestring(p); if (ident) { buf->writeByte(' '); - buf->writestring(ident->toHChars2()); + buf->writestring(ident->toHChars2()); } - Argument::argsToCBuffer(buf, hgs, parameters, varargs); + Parameter::argsToCBuffer(buf, hgs, parameters, varargs); inuse--; } @@ -4170,62 +4927,80 @@ void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) const char *p = NULL; if (inuse) - { inuse = 2; // flag error to caller - return; + { inuse = 2; // flag error to caller + return; } inuse++; if (next) - next->toCBuffer2(buf, hgs, 0); + next->toCBuffer2(buf, hgs, 0); if (hgs->ddoc != 1) { - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C "; break; - case LINKwindows: p = "Windows "; break; - case LINKpascal: p = "Pascal "; break; - case LINKcpp: p = "C++ "; break; + switch (linkage) + { + case LINKd: p = NULL; break; + case LINKc: p = " C"; break; + case LINKwindows: p = " Windows"; break; + case LINKpascal: p = " Pascal"; break; + case LINKcpp: p = " C++"; break; // LDC case LINKintrinsic: p = "Intrinsic"; break; - default: - assert(0); - } + default: + assert(0); + } } if (!hgs->hdrgen && p) - buf->writestring(p); + buf->writestring(p); buf->writestring(" function"); - Argument::argsToCBuffer(buf, hgs, parameters, varargs); + Parameter::argsToCBuffer(buf, hgs, parameters, varargs); + attributesToCBuffer(buf, mod); + inuse--; +} +void TypeFunction::attributesToCBuffer(OutBuffer *buf, int mod) +{ /* Use postfix style for attributes */ if (mod != this->mod) { - modToBuffer(buf); + modToBuffer(buf); } if (ispure) - buf->writestring(" pure"); + buf->writestring(" pure"); if (isnothrow) - buf->writestring(" nothrow"); + buf->writestring(" nothrow"); if (isproperty) - buf->writestring(" @property"); + buf->writestring(" @property"); if (isref) - buf->writestring(" ref"); + buf->writestring(" ref"); - inuse--; + switch (trust) + { + case TRUSTsystem: + buf->writestring(" @system"); + break; + + case TRUSTtrusted: + buf->writestring(" @trusted"); + break; + + case TRUSTsafe: + buf->writestring(" @safe"); + break; + } } Type *TypeFunction::semantic(Loc loc, Scope *sc) { - if (deco) // if semantic() already run + if (deco) // if semantic() already run { - //printf("already done\n"); - return this; + //printf("already done\n"); + return this; } //printf("TypeFunction::semantic() this = %p\n", this); - //printf("TypeFunction::semantic() %s, sc->stc = %x\n", toChars(), sc->stc); + //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs); /* Copy in order to not mess up original. * This can produce redundant copies if inferring return type, @@ -4234,99 +5009,185 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); memcpy(tf, this, sizeof(TypeFunction)); if (parameters) - { tf->parameters = (Arguments *)parameters->copy(); - for (size_t i = 0; i < parameters->dim; i++) - { Argument *arg = (Argument *)parameters->data[i]; - Argument *cpy = (Argument *)mem.malloc(sizeof(Argument)); - memcpy(cpy, arg, sizeof(Argument)); - tf->parameters->data[i] = (void *)cpy; - } + { tf->parameters = (Parameters *)parameters->copy(); + for (size_t i = 0; i < parameters->dim; i++) + { Parameter *arg = (Parameter *)parameters->data[i]; + Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); + memcpy(cpy, arg, sizeof(Parameter)); + tf->parameters->data[i] = (void *)cpy; + } } if (sc->stc & STCpure) - tf->ispure = TRUE; + tf->ispure = TRUE; if (sc->stc & STCnothrow) - tf->isnothrow = TRUE; + tf->isnothrow = TRUE; if (sc->stc & STCref) - tf->isref = TRUE; + tf->isref = TRUE; + if (sc->stc & STCsafe) + tf->trust = TRUSTsafe; + if (sc->stc & STCtrusted) + tf->trust = TRUSTtrusted; + if (sc->stc & STCproperty) + tf->isproperty = TRUE; tf->linkage = sc->linkage; + + /* If the parent is @safe, then this function defaults to safe + * too. + */ + if (tf->trust == TRUSTdefault) + for (Dsymbol *p = sc->func; p; p = p->toParent2()) + { FuncDeclaration *fd = p->isFuncDeclaration(); + if (fd) + { + if (fd->isSafe()) + tf->trust = TRUSTsafe; // default to @safe + break; + } + } + + bool wildreturn = FALSE; if (tf->next) { - tf->next = tf->next->semantic(loc,sc); - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isauto() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return scope %s", tf->next->toChars()); + tf->next = tf->next->semantic(loc,sc); +#if !SARRAYVALUE + if (tf->next->toBasetype()->ty == Tsarray) + { error(loc, "functions cannot return static array %s", tf->next->toChars()); + tf->next = Type::terror; + } +#endif + if (tf->next->toBasetype()->ty == Tfunction) + { error(loc, "functions cannot return a function"); + tf->next = Type::terror; + } + if (tf->next->toBasetype()->ty == Ttuple) + { error(loc, "functions cannot return a tuple"); + tf->next = Type::terror; + } + if (tf->next->isscope() && !(sc->flags & SCOPEctor)) + error(loc, "functions cannot return scope %s", tf->next->toChars()); + if (tf->next->toBasetype()->ty == Tvoid) + tf->isref = FALSE; // rewrite "ref void" as just "void" + if (tf->next->isWild()) + wildreturn = TRUE; } + bool wildparams = FALSE; + bool wildsubparams = FALSE; if (tf->parameters) - { size_t dim = Argument::dim(tf->parameters); + { + /* Create a scope for evaluating the default arguments for the parameters + */ + Scope *argsc = sc->push(); + argsc->stc = 0; // don't inherit storage class + argsc->protection = PROTpublic; - for (size_t i = 0; i < dim; i++) - { Argument *arg = Argument::getNth(tf->parameters, i); + size_t dim = Parameter::dim(tf->parameters); + for (size_t i = 0; i < dim; i++) + { Parameter *fparam = Parameter::getNth(tf->parameters, i); - tf->inuse++; - arg->type = arg->type->semantic(loc,sc); - if (tf->inuse == 1) tf->inuse--; + tf->inuse++; + fparam->type = fparam->type->semantic(loc, argsc); + if (tf->inuse == 1) tf->inuse--; - arg->type = arg->type->addStorageClass(arg->storageClass); + fparam->type = fparam->type->addStorageClass(fparam->storageClass); - if (arg->storageClass & (STCauto | STCalias | STCstatic)) - { - if (!arg->type) - continue; - } + if (fparam->storageClass & (STCauto | STCalias | STCstatic)) + { + if (!fparam->type) + continue; + } // Possible merge conflict - Type *t = arg->type->toBasetype(); + Type *t = fparam->type->toBasetype(); - if (arg->storageClass & (STCout | STCref | STClazy)) - { - if (t->ty == Tsarray) - error(loc, "cannot have out or ref parameter of type %s", t->toChars()); - if (arg->storageClass & STCout && arg->type->mod) - error(loc, "cannot have const/invariant out parameter of type %s", t->toChars()); - } - if (!(arg->storageClass & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", arg->type->toChars()); + if (fparam->storageClass & (STCout | STCref | STClazy)) + { + //if (t->ty == Tsarray) + //error(loc, "cannot have out or ref parameter of type %s", t->toChars()); + if (fparam->storageClass & STCout && fparam->type->mod & (STCconst | STCimmutable)) + error(loc, "cannot have const or immutable out parameter of type %s", t->toChars()); + } + if (!(fparam->storageClass & STClazy) && t->ty == Tvoid) + error(loc, "cannot have parameter of type %s", fparam->type->toChars()); - if (arg->defaultArg) - { - arg->defaultArg = arg->defaultArg->semantic(sc); - arg->defaultArg = resolveProperties(sc, arg->defaultArg); - arg->defaultArg = arg->defaultArg->implicitCastTo(sc, arg->type); - } + if (t->isWild()) + { + wildparams = TRUE; + if (tf->next && !wildreturn) + error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')"); + } + else if (!wildsubparams && t->hasWild()) + wildsubparams = TRUE; - /* If arg turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { dim = Argument::dim(tf->parameters); - i--; - } - } + if (fparam->defaultArg) + { + fparam->defaultArg = fparam->defaultArg->semantic(argsc); + fparam->defaultArg = resolveProperties(argsc, fparam->defaultArg); + fparam->defaultArg = fparam->defaultArg->implicitCastTo(argsc, fparam->type); + } + + /* If fparam turns out to be a tuple, the number of parameters may + * change. + */ + if (t->ty == Ttuple) + { + // Propagate storage class from tuple parameters to their element-parameters. + TypeTuple *tt = (TypeTuple *)t; + if (tt->arguments) + { + size_t tdim = tt->arguments->dim; + for (size_t j = 0; j < tdim; j++) + { Parameter *narg = (Parameter *)tt->arguments->data[j]; + narg->storageClass = fparam->storageClass; + } + } + + /* Reset number of parameters, and back up one to do this fparam again, + * now that it is the first element of a tuple + */ + dim = Parameter::dim(tf->parameters); + i--; + continue; + } + + /* Resolve "auto ref" storage class to be either ref or value, + * based on the argument matching the parameter + */ + if (fparam->storageClass & STCauto) + { + if (fargs && i < fargs->dim) + { Expression *farg = (Expression *)fargs->data[i]; + if (farg->isLvalue()) + ; // ref parameter + else + fparam->storageClass &= ~STCref; // value parameter + } + else + error(loc, "auto can only be used for template function parameters"); + } + } + argsc->pop(); } + if (wildreturn && !wildparams) + error(loc, "inout on return means inout must be on a parameter as well for %s", toChars()); + if (wildsubparams && wildparams) + error(loc, "inout must be all or none on top level for %s", toChars()); + if (tf->next) - tf->deco = tf->merge()->deco; + tf->deco = tf->merge()->deco; if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; + { error(loc, "recursive type"); + tf->inuse = 0; + return terror; } - if (tf->varargs == 1 && tf->linkage != LINKd && Argument::dim(tf->parameters) == 0) - error(loc, "variadic functions with non-D linkage must have at least one parameter"); + if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 1)) + error(loc, "properties can only have zero or one parameter"); + + if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0) + error(loc, "variadic functions with non-D linkage must have at least one parameter"); /* Don't return merge(), because arg identifiers and default args * can be different @@ -4338,134 +5199,183 @@ Type *TypeFunction::semantic(Loc loc, Scope *sc) /******************************** * 'args' are being matched to function 'this' * Determine match level. + * Input: + * flag 1 performing a partial ordering match * Returns: - * MATCHxxxx + * MATCHxxxx */ -int TypeFunction::callMatch(Expression *ethis, Expressions *args) +int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) { //printf("TypeFunction::callMatch() %s\n", toChars()); - MATCH match = MATCHexact; // assume exact match + MATCH match = MATCHexact; // assume exact match + bool exactwildmatch = FALSE; + bool wildmatch = FALSE; if (ethis) - { Type *t = ethis->type; - if (t->toBasetype()->ty == Tpointer) - t = t->toBasetype()->nextOf(); // change struct* to struct - if (t->mod != mod) - { - if (mod == MODconst) - match = MATCHconst; - else - return MATCHnomatch; - } + { Type *t = ethis->type; + if (t->toBasetype()->ty == Tpointer) + t = t->toBasetype()->nextOf(); // change struct* to struct + if (t->mod != mod) + { + if (MODimplicitConv(t->mod, mod)) + match = MATCHconst; + else + return MATCHnomatch; + } } - size_t nparams = Argument::dim(parameters); + size_t nparams = Parameter::dim(parameters); size_t nargs = args ? args->dim : 0; if (nparams == nargs) - ; + ; else if (nargs > nparams) { - if (varargs == 0) - goto Nomatch; // too many args; no match - match = MATCHconvert; // match ... with a "conversion" match level + if (varargs == 0) + goto Nomatch; // too many args; no match + match = MATCHconvert; // match ... with a "conversion" match level } for (size_t u = 0; u < nparams; u++) - { MATCH m; - Expression *arg; + { MATCH m; + Expression *arg; - // BUG: what about out and ref? + // BUG: what about out and ref? - Argument *p = Argument::getNth(parameters, u); - assert(p); - if (u >= nargs) - { - if (p->defaultArg) - continue; - if (varargs == 2 && u + 1 == nparams) - goto L1; - goto Nomatch; // not enough arguments - } - arg = (Expression *)args->data[u]; - assert(arg); + Parameter *p = Parameter::getNth(parameters, u); + assert(p); + if (u >= nargs) + { + if (p->defaultArg) + continue; + if (varargs == 2 && u + 1 == nparams) + goto L1; + goto Nomatch; // not enough arguments + } + arg = (Expression *)args->data[u]; + assert(arg); + //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars()); - // Non-lvalues do not match ref or out parameters - if (p->storageClass & (STCref | STCout) && !arg->isLvalue()) - goto Nomatch; + // Non-lvalues do not match ref or out parameters + if (p->storageClass & (STCref | STCout)) + { if (!arg->isLvalue()) + goto Nomatch; + } - if (p->storageClass & STClazy && p->type->ty == Tvoid && - arg->type->ty != Tvoid) - m = MATCHconvert; - else - m = arg->implicitConvTo(p->type); - //printf("\tm = %d\n", m); - if (m == MATCHnomatch) // if no match - { - L1: - if (varargs == 2 && u + 1 == nparams) // if last varargs param - { Type *tb = p->type->toBasetype(); - TypeSArray *tsa; - dinteger_t sz; + if (p->storageClass & STCref) + { + /* Don't allow static arrays to be passed to mutable references + * to static arrays if the argument cannot be modified. + */ + Type *targb = arg->type->toBasetype(); + Type *tparb = p->type->toBasetype(); + //printf("%s\n", targb->toChars()); + //printf("%s\n", tparb->toChars()); + if (targb->nextOf() && tparb->ty == Tsarray && + !MODimplicitConv(targb->nextOf()->mod, tparb->nextOf()->mod)) + goto Nomatch; + } - switch (tb->ty) - { - case Tsarray: - tsa = (TypeSArray *)tb; - sz = tsa->dim->toInteger(); - if (sz != nargs - u) - goto Nomatch; - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; u < nargs; u++) - { - arg = (Expression *)args->data[u]; - assert(arg); + if (p->storageClass & STClazy && p->type->ty == Tvoid && + arg->type->ty != Tvoid) + m = MATCHconvert; + else + { + //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), arg->type->toChars(), p->type->toChars()); + if (flag) + // for partial ordering, value is an irrelevant mockup, just look at the type + m = arg->type->implicitConvTo(p->type); + else + m = arg->implicitConvTo(p->type); + //printf("match %d\n", m); + if (p->type->isWild()) + { + if (m == MATCHnomatch) + { + m = arg->implicitConvTo(p->type->constOf()); + if (m == MATCHnomatch) + m = arg->implicitConvTo(p->type->sharedConstOf()); + if (m != MATCHnomatch) + wildmatch = TRUE; // mod matched to wild + } + else + exactwildmatch = TRUE; // wild matched to wild + + /* If both are allowed, then there could be more than one + * binding of mod to wild, leaving a gaping type hole. + */ + if (wildmatch && exactwildmatch) + m = MATCHnomatch; + } + } + + //printf("\tm = %d\n", m); + if (m == MATCHnomatch) // if no match + { + L1: + if (varargs == 2 && u + 1 == nparams) // if last varargs param + { Type *tb = p->type->toBasetype(); + TypeSArray *tsa; + dinteger_t sz; + + switch (tb->ty) + { + case Tsarray: + tsa = (TypeSArray *)tb; + sz = tsa->dim->toInteger(); + if (sz != nargs - u) + goto Nomatch; + case Tarray: + { TypeArray *ta = (TypeArray *)tb; + for (; u < nargs; u++) + { + arg = (Expression *)args->data[u]; + assert(arg); #if 1 - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = p->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - m = arg->implicitConvTo(ta->next); + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type *tret = p->isLazyArray(); + if (tret) + { + if (ta->next->equals(arg->type)) + { m = MATCHexact; + } + else + { + m = arg->implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + } + } + else + m = arg->implicitConvTo(ta->next); #else - m = arg->implicitConvTo(ta->next); + m = arg->implicitConvTo(ta->next); #endif - if (m == MATCHnomatch) - goto Nomatch; - if (m < match) - match = m; - } - goto Ldone; - } - case Tclass: - // Should see if there's a constructor match? - // Or just leave it ambiguous? - goto Ldone; + if (m == MATCHnomatch) + goto Nomatch; + if (m < match) + match = m; + } + goto Ldone; + } + case Tclass: + // Should see if there's a constructor match? + // Or just leave it ambiguous? + goto Ldone; - default: - goto Nomatch; - } - } - goto Nomatch; - } - if (m < match) - match = m; // pick worst match + default: + goto Nomatch; + } + } + goto Nomatch; + } + if (m < match) + match = m; // pick worst match } Ldone: @@ -4479,16 +5389,14 @@ Nomatch: Type *TypeFunction::reliesOnTident() { - if (parameters) - { - for (size_t i = 0; i < parameters->dim; i++) - { Argument *arg = (Argument *)parameters->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } + size_t dim = Parameter::dim(parameters); + for (size_t i = 0; i < dim; i++) + { Parameter *fparam = Parameter::getNth(parameters, i); + Type *t = fparam->type->reliesOnTident(); + if (t) + return t; } - return next->reliesOnTident(); + return next ? next->reliesOnTident() : NULL; } /*************************** @@ -4496,7 +5404,7 @@ Type *TypeFunction::reliesOnTident() * p can 'escape' the scope of the function. */ -bool TypeFunction::parameterEscapes(Argument *p) +bool TypeFunction::parameterEscapes(Parameter *p) { /* Scope parameters do not escape. @@ -4506,19 +5414,19 @@ bool TypeFunction::parameterEscapes(Argument *p) * escaping. */ if (p->storageClass & (STCscope | STClazy)) - return FALSE; + return FALSE; if (ispure) - { /* With pure functions, we need only be concerned if p escapes - * via any return statement. - */ - Type* tret = nextOf()->toBasetype(); - if (!isref && !tret->hasPointers()) - { /* The result has no references, so p could not be escaping - * that way. - */ - return FALSE; - } + { /* With pure functions, we need only be concerned if p escapes + * via any return statement. + */ + Type* tret = nextOf()->toBasetype(); + if (!isref && !tret->hasPointers()) + { /* The result has no references, so p could not be escaping + * that way. + */ + return FALSE; + } } /* Assume it escapes in the absence of better information. @@ -4538,20 +5446,20 @@ Type *TypeDelegate::syntaxCopy() { Type *t = next->syntaxCopy(); if (t == next) - t = this; + t = this; else - { t = new TypeDelegate(t); - t->mod = mod; + { t = new TypeDelegate(t); + t->mod = mod; } return t; } Type *TypeDelegate::semantic(Loc loc, Scope *sc) { - if (deco) // if semantic() already run + if (deco) // if semantic() already run { - //printf("already done\n"); - return this; + //printf("already done\n"); + return this; } next = next->semantic(loc,sc); return merge(); @@ -4570,17 +5478,32 @@ unsigned TypeDelegate::alignsize() return PTRSIZE; } +MATCH TypeDelegate::implicitConvTo(Type *to) +{ + //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to); + //printf("from: %s\n", toChars()); + //printf("to : %s\n", to->toChars()); + if (this == to) + return MATCHexact; +#if 0 // not allowing covariant conversions because it interferes with overriding + if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1) + return MATCHconvert; +#endif + return MATCHnomatch; +} + void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } TypeFunction *tf = (TypeFunction *)next; tf->next->toCBuffer2(buf, hgs, 0); buf->writestring(" delegate"); - Argument::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); + Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); + tf->attributesToCBuffer(buf, mod); } Expression *TypeDelegate::defaultInit(Loc loc) @@ -4588,10 +5511,7 @@ Expression *TypeDelegate::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeDelegate::defaultInit() '%s'\n", toChars()); #endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypeDelegate::isZeroInit(Loc loc) @@ -4612,18 +5532,18 @@ Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) if (ident == Id::ptr) { e = new GEPExp(e->loc, e, ident, 0); - e->type = tvoidptr; - return e; + e->type = tvoidptr; + return e; } else if (ident == Id::funcptr) { - e = new GEPExp(e->loc, e, ident, 1); - e->type = tvoidptr; - return e; + e = new GEPExp(e->loc, e, ident, 1); + e->type = tvoidptr; + return e; } else { - e = Type::dotExp(sc, e, ident); + e = Type::dotExp(sc, e, ident); } return e; } @@ -4649,15 +5569,15 @@ void TypeQualified::syntaxCopyHelper(TypeQualified *t) idents.setDim(t->idents.dim); for (int i = 0; i < idents.dim; i++) { - Identifier *id = (Identifier *)t->idents.data[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; + Identifier *id = (Identifier *)t->idents.data[i]; + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - idents.data[i] = id; + ti = (TemplateInstance *)ti->syntaxCopy(NULL); + id = (Identifier *)ti; + } + idents.data[i] = id; } } @@ -4672,17 +5592,17 @@ void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) int i; for (i = 0; i < idents.dim; i++) - { Identifier *id = (Identifier *)idents.data[i]; + { Identifier *id = (Identifier *)idents.data[i]; - buf->writeByte('.'); + buf->writeByte('.'); - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->toCBuffer(buf, hgs); - } - else - buf->writestring(id->toChars()); + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; + ti->toCBuffer(buf, hgs); + } + else + buf->writestring(id->toChars()); } } @@ -4696,15 +5616,16 @@ d_uns64 TypeQualified::size(Loc loc) * Takes an array of Identifiers and figures out if * it represents a Type or an Expression. * Output: - * if expression, *pe is set - * if type, *pt is set + * if expression, *pe is set + * if type, *pt is set */ void TypeQualified::resolveHelper(Loc loc, Scope *sc, - Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps) + Dsymbol *s, Dsymbol *scopesym, + Expression **pe, Type **pt, Dsymbol **ps) { VarDeclaration *v; + FuncDeclaration *fd; EnumMember *em; TupleDeclaration *td; Expression *e; @@ -4712,162 +5633,168 @@ void TypeQualified::resolveHelper(Loc loc, Scope *sc, #if 0 printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); if (scopesym) - printf("\tscopesym = '%s'\n", scopesym->toChars()); + printf("\tscopesym = '%s'\n", scopesym->toChars()); #endif *pe = NULL; *pt = NULL; *ps = NULL; if (s) { - //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - s->checkDeprecated(loc, sc); // check for deprecated aliases - s = s->toAlias(); - //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (int i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)idents.data[i]; - Dsymbol *sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("\tgetType = '%s'\n", s->getType()->toChars()); - if (!sm) - { Type *t; + //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + s->checkDeprecated(loc, sc); // check for deprecated aliases + s = s->toAlias(); + //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + for (int i = 0; i < idents.dim; i++) + { + Identifier *id = (Identifier *)idents.data[i]; + Dsymbol *sm = s->searchX(loc, sc, id); + //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); + //printf("\tgetType = '%s'\n", s->getType()->toChars()); + if (!sm) + { Type *t; - v = s->isVarDeclaration(); - if (v && id == Id::length) - { - e = v->getConstInitializer(); - if (!e) - e = new VarExp(loc, v); - t = e->type; - if (!t) - goto Lerror; - goto L3; - } - t = s->getType(); - if (!t && s->isDeclaration()) - t = s->isDeclaration()->type; - if (t) - { - sm = t->toDsymbol(sc); - if (sm) - { sm = sm->search(loc, id, 0); - if (sm) - goto L2; - } - //e = t->getProperty(loc, id); - e = new TypeExp(loc, t); - e = t->dotExp(sc, e, id); - i++; - L3: - for (; i < idents.dim; i++) - { - id = (Identifier *)idents.data[i]; - //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); - if (id == Id::offsetof) - { e = new DotIdExp(e->loc, e, id); - e = e->semantic(sc); - } - else - e = e->type->dotExp(sc, e, id); - } - *pe = e; - } - else - Lerror: - error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); - return; - } - L2: - s = sm->toAlias(); - } + v = s->isVarDeclaration(); + if (v && id == Id::length) + { + e = v->getConstInitializer(); + if (!e) + e = new VarExp(loc, v); + t = e->type; + if (!t) + goto Lerror; + goto L3; + } + else if (v && id == Id::stringof) + { + e = new DsymbolExp(loc, s, 0); + do + { + id = (Identifier *)idents.data[i]; + e = new DotIdExp(loc, e, id); + } while (++i < idents.dim); + e = e->semantic(sc); + *pe = e; + return; + } - v = s->isVarDeclaration(); - if (v) - { + t = s->getType(); + if (!t && s->isDeclaration()) + t = s->isDeclaration()->type; + if (t) + { + sm = t->toDsymbol(sc); + if (sm) + { sm = sm->search(loc, id, 0); + if (sm) + goto L2; + } + //e = t->getProperty(loc, id); + e = new TypeExp(loc, t); + e = t->dotExp(sc, e, id); + i++; + L3: + for (; i < idents.dim; i++) + { + id = (Identifier *)idents.data[i]; + //printf("e: '%s', id: '%s', type = %p\n", e->toChars(), id->toChars(), e->type); + if (id == Id::offsetof || !e->type) + { e = new DotIdExp(e->loc, e, id); + e = e->semantic(sc); + } + else + e = e->type->dotExp(sc, e, id); + } + *pe = e; + } + else + Lerror: + error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); + return; + } + L2: + s = sm->toAlias(); + } + + v = s->isVarDeclaration(); + if (v) + { + *pe = new VarExp(loc, v); + return; + } #if 0 - // It's not a type, it's an expression - Expression *e = v->getConstInitializer(); - if (e) - { - *pe = e->copy(); // make copy so we can change loc - (*pe)->loc = loc; - } - else + fd = s->isFuncDeclaration(); + if (fd) + { + *pe = new DsymbolExp(loc, fd, 1); + return; + } #endif - { -#if 0 - WithScopeSymbol *withsym; - if (scopesym && (withsym = scopesym->isWithScopeSymbol()) != NULL) - { - // Same as wthis.ident - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - //assert(0); // BUG: should handle this - } - else -#endif - *pe = new VarExp(loc, v); - } - return; - } - em = s->isEnumMember(); - if (em) - { - // It's not a type, it's an expression - *pe = em->value->copy(); - return; - } + em = s->isEnumMember(); + if (em) + { + // It's not a type, it's an expression + *pe = em->value->copy(); + return; + } L1: - Type *t = s->getType(); - if (!t) - { - // If the symbol is an import, try looking inside the import - Import *si; + Type *t = s->getType(); + if (!t) + { + // If the symbol is an import, try looking inside the import + Import *si; - si = s->isImport(); - if (si) - { - s = si->search(loc, s->ident, 0); - if (s && s != si) - goto L1; - s = si; - } - *ps = s; - return; - } - if (t->ty == Tinstance && t != this && !t->deco) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } + si = s->isImport(); + if (si) + { + s = si->search(loc, s->ident, 0); + if (s && s != si) + goto L1; + s = si; + } + *ps = s; + return; + } + if (t->ty == Tinstance && t != this && !t->deco) + { error(loc, "forward reference to '%s'", t->toChars()); + return; + } - if (t != this) - { - if (t->reliesOnTident()) - { - Scope *scx; - - for (scx = sc; 1; scx = scx->enclosing) - { - if (!scx) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - if (scx->scopesym == scopesym) - break; - } - t = t->semantic(loc, scx); - //((TypeIdentifier *)t)->resolve(loc, scx, pe, &t, ps); - } - } - if (t->ty == Ttuple) - *pt = t; - else - *pt = t->merge(); + if (t != this) + { + if (t->reliesOnTident()) + { + if (s->scope) + t = t->semantic(loc, s->scope); + else + { + /* Attempt to find correct scope in which to evaluate t. + * Not sure if this is right or not, or if we should just + * give forward reference error if s->scope is not set. + */ + for (Scope *scx = sc; 1; scx = scx->enclosing) + { + if (!scx) + { error(loc, "forward reference to '%s'", t->toChars()); + return; + } + if (scx->scopesym == scopesym) + { + t = t->semantic(loc, scx); + break; + } + } + } + } + } + if (t->ty == Ttuple) + *pt = t; + else + *pt = t->merge(); } if (!s) { - error(loc, "identifier '%s' is not defined", toChars()); + error(loc, "identifier '%s' is not defined", toChars()); } } @@ -4903,8 +5830,8 @@ void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(this->ident->toChars()); toCBuffer2Helper(buf, hgs); @@ -4914,8 +5841,8 @@ void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) * Takes an array of Identifiers and figures out if * it represents a Type or an Expression. * Output: - * if expression, *pe is set - * if type, *pt is set + * if expression, *pe is set + * if type, *pt is set */ void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) @@ -4926,7 +5853,7 @@ void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsy Dsymbol *s = sc->search(loc, ident, &scopesym); resolveHelper(loc, sc, s, scopesym, pe, pt, ps); if (*pt) - (*pt) = (*pt)->addMod(mod); + (*pt) = (*pt)->addMod(mod); } /***************************************** @@ -4938,22 +5865,22 @@ Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) { //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); if (!sc) - return NULL; + return NULL; //printf("ident = '%s'\n", ident->toChars()); Dsymbol *scopesym; Dsymbol *s = sc->search(loc, ident, &scopesym); if (s) { - for (int i = 0; i < idents.dim; i++) - { - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - if (!s) // failed to find a symbol - { //printf("\tdidn't find a symbol\n"); - break; - } - } + for (int i = 0; i < idents.dim; i++) + { + Identifier *id = (Identifier *)idents.data[i]; + s = s->searchX(loc, sc, id); + if (!s) // failed to find a symbol + { //printf("\tdidn't find a symbol\n"); + break; + } + } } return s; } @@ -4968,30 +5895,30 @@ Type *TypeIdentifier::semantic(Loc loc, Scope *sc) resolve(loc, sc, &e, &t, &s); if (t) { - //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); + //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); - if (t->ty == Ttypedef) - { TypeTypedef *tt = (TypeTypedef *)t; + if (t->ty == Ttypedef) + { TypeTypedef *tt = (TypeTypedef *)t; - if (tt->sym->sem == 1) - error(loc, "circular reference of typedef %s", tt->toChars()); - } - t = t->addMod(mod); + if (tt->sym->sem == 1) + error(loc, "circular reference of typedef %s", tt->toChars()); + } + t = t->addMod(mod); } else { #ifdef DEBUG - if (!global.gag) - printf("1: "); + if (!global.gag) + printf("1: "); #endif - if (s) - { - s->error(loc, "is used as a type"); - //halt(); - } - else - error(loc, "%s is used as a type", toChars()); - t = tvoid; + if (s) + { + s->error(loc, "is used as a type"); + //halt(); + } + else + error(loc, "%s is used as a type", toChars()); + t = terror; } //t->print(); return t; @@ -5007,8 +5934,8 @@ Expression *TypeIdentifier::toExpression() Expression *e = new IdentifierExp(loc, ident); for (int i = 0; i < idents.dim; i++) { - Identifier *id = (Identifier *)idents.data[i]; - e = new DotIdExp(loc, e, id); + Identifier *id = (Identifier *)idents.data[i]; + e = new DotIdExp(loc, e, id); } return e; @@ -5037,8 +5964,8 @@ Type *TypeInstance::syntaxCopy() void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } tempinst->toCBuffer(buf, hgs); toCBuffer2Helper(buf, hgs); @@ -5057,18 +5984,18 @@ void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymb #if 0 if (!idents.dim) { - error(loc, "template instance '%s' has no identifier", toChars()); - return; + error(loc, "template instance '%s' has no identifier", toChars()); + return; } #endif //id = (Identifier *)idents.data[0]; //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); s = tempinst; if (s) - s->semantic(sc); + s->semantic(sc); resolveHelper(loc, sc, s, NULL, pe, pt, ps); if (*pt) - *pt = (*pt)->addMod(mod); + *pt = (*pt)->addMod(mod); //printf("pt = '%s'\n", (*pt)->toChars()); } @@ -5082,28 +6009,28 @@ Type *TypeInstance::semantic(Loc loc, Scope *sc) if (sc->parameterSpecialization) { - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.errors; + global.gag++; - resolve(loc, sc, &e, &t, &s); + resolve(loc, sc, &e, &t, &s); - global.gag--; - if (errors != global.errors) - { if (global.gag == 0) - global.errors = errors; - return this; - } + global.gag--; + if (errors != global.errors) + { if (global.gag == 0) + global.errors = errors; + return this; + } } else - resolve(loc, sc, &e, &t, &s); + resolve(loc, sc, &e, &t, &s); if (!t) { #ifdef DEBUG - printf("2: "); + printf("2: "); #endif - error(loc, "%s is used as a type", toChars()); - t = tvoid; + error(loc, "%s is used as a type", toChars()); + t = tvoid; } return t; } @@ -5118,20 +6045,20 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) if (sc->parameterSpecialization) { - unsigned errors = global.errors; - global.gag++; + unsigned errors = global.errors; + global.gag++; - resolve(loc, sc, &e, &t, &s); + resolve(loc, sc, &e, &t, &s); - global.gag--; - if (errors != global.errors) - { if (global.gag == 0) - global.errors = errors; - return NULL; - } + global.gag--; + if (errors != global.errors) + { if (global.gag == 0) + global.errors = errors; + return NULL; + } } else - resolve(loc, sc, &e, &t, &s); + resolve(loc, sc, &e, &t, &s); return s; } @@ -5140,7 +6067,7 @@ Dsymbol *TypeInstance::toDsymbol(Scope *sc) /***************************** TypeTypeof *****************************/ TypeTypeof::TypeTypeof(Loc loc, Expression *exp) - : TypeQualified(Ttypeof, loc) + : TypeQualified(Ttypeof, loc) { this->exp = exp; } @@ -5162,15 +6089,15 @@ Dsymbol *TypeTypeof::toDsymbol(Scope *sc) t = semantic(loc, sc); if (t == this) - return NULL; + return NULL; return t->toDsymbol(sc); } void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring("typeof("); exp->toCBuffer(buf, hgs); @@ -5192,91 +6119,99 @@ Type *TypeTypeof::semantic(Loc loc, Scope *sc) */ if (exp->op == TOKthis || exp->op == TOKsuper) { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - StructDeclaration *sd; + // Find enclosing struct or class + for (Dsymbol *s = sc->parent; 1; s = s->parent) + { + ClassDeclaration *cd; + StructDeclaration *sd; - if (!s) - { - error(loc, "%s is not in a struct or class scope", exp->toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - if (exp->op == TOKsuper) - { - cd = cd->baseClass; - if (!cd) - { error(loc, "class %s has no 'super'", s->toChars()); - goto Lerr; - } - } - t = cd->type; - break; - } - sd = s->isStructDeclaration(); - if (sd) - { - if (exp->op == TOKsuper) - { - error(loc, "struct %s has no 'super'", sd->toChars()); - goto Lerr; - } - t = sd->type->pointerTo(); - break; - } - } + if (!s) + { + error(loc, "%s is not in a struct or class scope", exp->toChars()); + goto Lerr; + } + cd = s->isClassDeclaration(); + if (cd) + { + if (exp->op == TOKsuper) + { + cd = cd->baseClass; + if (!cd) + { error(loc, "class %s has no 'super'", s->toChars()); + goto Lerr; + } + } + t = cd->type; + break; + } + sd = s->isStructDeclaration(); + if (sd) + { + if (exp->op == TOKsuper) + { + error(loc, "struct %s has no 'super'", sd->toChars()); + goto Lerr; + } + t = sd->type->pointerTo(); + break; + } + } } else #endif { - sc->intypeof++; - exp = exp->semantic(sc); - sc->intypeof--; - if (exp->op == TOKtype) - { - error(loc, "argument %s to typeof is not an expression", exp->toChars()); - } - t = exp->type; - if (!t) - { - error(loc, "expression (%s) has no type", exp->toChars()); - goto Lerr; - } - if (t->ty == Ttypeof) - error(loc, "forward reference to %s", toChars()); + sc->intypeof++; + exp = exp->semantic(sc); +#if DMDV2 + if (exp->type && exp->type->ty == Tfunction && + ((TypeFunction *)exp->type)->isproperty) + exp = resolveProperties(sc, exp); +#endif + sc->intypeof--; + if (exp->op == TOKtype) + { + error(loc, "argument %s to typeof is not an expression", exp->toChars()); + goto Lerr; + } + t = exp->type; + if (!t) + { + error(loc, "expression (%s) has no type", exp->toChars()); + goto Lerr; + } + if (t->ty == Ttypeof) + { error(loc, "forward reference to %s", toChars()); + goto Lerr; + } - /* typeof should reflect the true type, - * not what 'auto' would have gotten us. - */ - //t = t->toHeadMutable(); + /* typeof should reflect the true type, + * not what 'auto' would have gotten us. + */ + //t = t->toHeadMutable(); } if (idents.dim) { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - } + Dsymbol *s = t->toDsymbol(sc); + for (size_t i = 0; i < idents.dim; i++) + { + if (!s) + break; + Identifier *id = (Identifier *)idents.data[i]; + s = s->searchX(loc, sc, id); + } - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } + if (s) + { + t = s->getType(); + if (!t) + { error(loc, "%s is not a type", s->toChars()); + goto Lerr; + } + } + else + { error(loc, "cannot resolve .property for %s", toChars()); + goto Lerr; + } } return t; @@ -5287,9 +6222,9 @@ Lerr: d_uns64 TypeTypeof::size(Loc loc) { if (exp->type) - return exp->type->size(loc); + return exp->type->size(loc); else - return TypeQualified::size(loc); + return TypeQualified::size(loc); } @@ -5297,7 +6232,7 @@ d_uns64 TypeTypeof::size(Loc loc) /***************************** TypeReturn *****************************/ TypeReturn::TypeReturn(Loc loc) - : TypeQualified(Treturn, loc) + : TypeQualified(Treturn, loc) { } @@ -5313,7 +6248,7 @@ Dsymbol *TypeReturn::toDsymbol(Scope *sc) { Type *t = semantic(0, sc); if (t == this) - return NULL; + return NULL; return t->toDsymbol(sc); } @@ -5321,34 +6256,39 @@ Type *TypeReturn::semantic(Loc loc, Scope *sc) { Type *t; if (!sc->func) - { error(loc, "typeof(return) must be inside function"); - goto Lerr; + { error(loc, "typeof(return) must be inside function"); + goto Lerr; } t = sc->func->type->nextOf(); + if (!t) + { + error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars()); + goto Lerr; + } t = t->addMod(mod); if (idents.dim) { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = (Identifier *)idents.data[i]; - s = s->searchX(loc, sc, id); - } - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } + Dsymbol *s = t->toDsymbol(sc); + for (size_t i = 0; i < idents.dim; i++) + { + if (!s) + break; + Identifier *id = (Identifier *)idents.data[i]; + s = s->searchX(loc, sc, id); + } + if (s) + { + t = s->getType(); + if (!t) + { error(loc, "%s is not a type", s->toChars()); + goto Lerr; + } + } + else + { error(loc, "cannot resolve .property for %s", toChars()); + goto Lerr; + } } return t; @@ -5359,8 +6299,8 @@ Lerr: void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring("typeof(return)"); toCBuffer2Helper(buf, hgs); @@ -5370,7 +6310,7 @@ void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) /***************************** TypeEnum *****************************/ TypeEnum::TypeEnum(EnumDeclaration *sym) - : Type(Tenum) + : Type(Tenum) { this->sym = sym; } @@ -5378,7 +6318,7 @@ TypeEnum::TypeEnum(EnumDeclaration *sym) char *TypeEnum::toChars() { if (mod) - return Type::toChars(); + return Type::toChars(); return sym->toChars(); } @@ -5398,8 +6338,8 @@ d_uns64 TypeEnum::size(Loc loc) { if (!sym->memtype) { - error(loc, "enum %s is forward referenced", sym->toChars()); - return 4; + error(loc, "enum %s is forward referenced", sym->toChars()); + return 4; } return sym->memtype->size(loc); } @@ -5409,10 +6349,10 @@ unsigned TypeEnum::alignsize() if (!sym->memtype) { #ifdef DEBUG - printf("1: "); + printf("1: "); #endif - error(0, "enum %s is forward referenced", sym->toChars()); - return 4; + error(0, "enum %s is forward referenced", sym->toChars()); + return 4; } return sym->memtype->alignsize(); } @@ -5424,13 +6364,24 @@ Dsymbol *TypeEnum::toDsymbol(Scope *sc) Type *TypeEnum::toBasetype() { + if (sym->scope) + { // Enum is forward referenced. We don't need to resolve the whole thing, + // just the base type + if (sym->memtype) + { sym->memtype = sym->memtype->semantic(sym->loc, sym->scope); + } + else + { if (!sym->isAnonymous()) + sym->memtype = Type::tint32; + } + } if (!sym->memtype) { #ifdef DEBUG - printf("2: "); + printf("2: "); #endif - error(sym->loc, "enum %s is forward referenced", sym->toChars()); - return tint32; + error(sym->loc, "enum %s is forward referenced", sym->toChars()); + return tint32; } return sym->memtype->toBasetype(); } @@ -5445,8 +6396,8 @@ void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(sym->toChars()); } @@ -5459,16 +6410,16 @@ Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident) Dsymbol *s = sym->search(e->loc, ident, 0); if (!s) { - if (ident == Id::max || - ident == Id::min || - ident == Id::init || - ident == Id::stringof || - !sym->memtype - ) - { - return getProperty(e->loc, ident); - } - return sym->memtype->dotExp(sc, e, ident); + if (ident == Id::max || + ident == Id::min || + ident == Id::init || + ident == Id::mangleof || + !sym->memtype + ) + { + return getProperty(e->loc, ident); + } + return sym->memtype->dotExp(sc, e, ident); } EnumMember *m = s->isEnumMember(); Expression *em = m->value->copy(); @@ -5481,29 +6432,33 @@ Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) if (ident == Id::max) { - if (!sym->maxval) - goto Lfwd; - e = sym->maxval; + if (!sym->maxval) + goto Lfwd; + e = sym->maxval; } else if (ident == Id::min) { - if (!sym->minval) - goto Lfwd; - e = sym->minval; + if (!sym->minval) + goto Lfwd; + e = sym->minval; } else if (ident == Id::init) { - e = defaultInit(loc); + e = defaultInitLiteral(loc); } else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); + { char *s = toChars(); + e = new StringExp(loc, s, strlen(s), 'c'); + Scope sc; + e = e->semantic(&sc); + } + else if (ident == Id::mangleof) + { + e = Type::getProperty(loc, ident); } else { - e = toBasetype()->getProperty(loc, ident); + e = toBasetype()->getProperty(loc, ident); } return e; @@ -5514,12 +6469,27 @@ Lfwd: int TypeEnum::isintegral() { - return 1; + return sym->memtype->isintegral(); } int TypeEnum::isfloating() { - return 0; + return sym->memtype->isfloating(); +} + +int TypeEnum::isreal() +{ + return sym->memtype->isreal(); +} + +int TypeEnum::isimaginary() +{ + return sym->memtype->isimaginary(); +} + +int TypeEnum::iscomplex() +{ + return sym->memtype->iscomplex(); } int TypeEnum::isunsigned() @@ -5529,8 +6499,17 @@ int TypeEnum::isunsigned() int TypeEnum::isscalar() { - return 1; - //return sym->memtype->isscalar(); + return sym->memtype->isscalar(); +} + +int TypeEnum::isAssignable() +{ + return sym->memtype->isAssignable(); +} + +int TypeEnum::checkBoolean() +{ + return sym->memtype->checkBoolean(); } MATCH TypeEnum::implicitConvTo(Type *to) @@ -5538,21 +6517,21 @@ MATCH TypeEnum::implicitConvTo(Type *to) //printf("TypeEnum::implicitConvTo()\n"); if (ty == to->ty && sym == ((TypeEnum *)to)->sym) - m = (mod == to->mod) ? MATCHexact : MATCHconst; + m = (mod == to->mod) ? MATCHexact : MATCHconst; else if (sym->memtype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions + m = MATCHconvert; // match with conversions else - m = MATCHnomatch; // no match + m = MATCHnomatch; // no match return m; } MATCH TypeEnum::constConv(Type *to) { if (equals(to)) - return MATCHexact; + return MATCHexact; if (ty == to->ty && sym == ((TypeEnum *)to)->sym && - to->mod == MODconst) - return MATCHconst; + MODimplicitConv(mod, to->mod)) + return MATCHconst; return MATCHnomatch; } @@ -5566,21 +6545,25 @@ Expression *TypeEnum::defaultInit(Loc loc) //printf("%s\n", sym->defaultval->type->toChars()); if (!sym->defaultval) { - error(loc, "forward reference of %s.init", toChars()); - return new ErrorExp(); + error(loc, "forward reference of %s.init", toChars()); + return new ErrorExp(); } return sym->defaultval; } int TypeEnum::isZeroInit(Loc loc) { + if (!sym->defaultval && sym->scope) + { // Enum is forward referenced. We need to resolve the whole thing. + sym->semantic(NULL); + } if (!sym->defaultval) { #ifdef DEBUG - printf("3: "); + printf("3: "); #endif - error(loc, "enum %s is forward referenced", sym->toChars()); - return 0; + error(loc, "enum %s is forward referenced", sym->toChars()); + return 0; } return sym->defaultval->isBool(FALSE); } @@ -5593,7 +6576,7 @@ int TypeEnum::hasPointers() /***************************** TypeTypedef *****************************/ TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef) + : Type(Ttypedef) { this->sym = sym; } @@ -5633,14 +6616,14 @@ Dsymbol *TypeTypedef::toDsymbol(Scope *sc) Type *TypeTypedef::toHeadMutable() { if (!mod) - return this; + return this; Type *tb = toBasetype(); Type *t = tb->toHeadMutable(); if (t->equals(tb)) - return this; + return this; else - return mutableOf(); + return mutableOf(); } void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) @@ -5654,8 +6637,8 @@ void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars()); if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(sym->toChars()); } @@ -5667,7 +6650,7 @@ Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (ident == Id::init) { - return Type::dotExp(sc, e, ident); + return Type::dotExp(sc, e, ident); } return sym->basetype->dotExp(sc, e, ident); } @@ -5679,7 +6662,7 @@ Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident) #endif if (ident == Id::init) { - return Type::getProperty(loc, ident); + return Type::getProperty(loc, ident); } return sym->basetype->getProperty(loc, ident); } @@ -5736,9 +6719,9 @@ Type *TypeTypedef::toBasetype() { if (sym->inuse) { - sym->error("circular definition"); - sym->basetype = Type::terror; - return Type::terror; + sym->error("circular definition"); + sym->basetype = Type::terror; + return Type::terror; } sym->inuse = 1; Type *t = sym->basetype->toBasetype(); @@ -5752,66 +6735,80 @@ MATCH TypeTypedef::implicitConvTo(Type *to) //printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); if (equals(to)) - m = MATCHexact; // exact match + m = MATCHexact; // exact match else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions + m = MATCHconvert; // match with conversions else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) { - m = constConv(to); + m = constConv(to); } else - m = MATCHnomatch; // no match + m = MATCHnomatch; // no match return m; } MATCH TypeTypedef::constConv(Type *to) { if (equals(to)) - return MATCHexact; + return MATCHexact; if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) - return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype); + return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype); return MATCHnomatch; } Expression *TypeTypedef::defaultInit(Loc loc) -{ Expression *e; - Type *bt; - +{ #if LOGDEFAULTINIT printf("TypeTypedef::defaultInit() '%s'\n", toChars()); #endif if (sym->init) { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); + //sym->init->toExpression()->print(); + return sym->init->toExpression(); } - bt = sym->basetype; - e = bt->defaultInit(loc); + Type *bt = sym->basetype; + Expression *e = bt->defaultInit(loc); e->type = this; while (bt->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)bt; - e->type = tsa->next; - bt = tsa->next->toBasetype(); + { TypeSArray *tsa = (TypeSArray *)bt; + e->type = tsa->next; + bt = tsa->next->toBasetype(); } return e; } +Expression *TypeTypedef::defaultInitLiteral(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeTypedef::defaultInitLiteral() '%s'\n", toChars()); +#endif + if (sym->init) + { + //sym->init->toExpression()->print(); + return sym->init->toExpression(); + } + Type *bt = sym->basetype; + Expression *e = bt->defaultInitLiteral(loc); + e->type = this; + return e; +} + int TypeTypedef::isZeroInit(Loc loc) { if (sym->init) { - if (sym->init->isVoidInitializer()) - return 1; // initialize voids to 0 - Expression *e = sym->init->toExpression(); - if (e && e->isBool(FALSE)) - return 1; - return 0; // assume not + if (sym->init->isVoidInitializer()) + return 1; // initialize voids to 0 + Expression *e = sym->init->toExpression(); + if (e && e->isBool(FALSE)) + return 1; + return 0; // assume not } if (sym->inuse) { - sym->error("circular definition"); - sym->basetype = Type::terror; + sym->error("circular definition"); + sym->basetype = Type::terror; } sym->inuse = 1; int result = sym->basetype->isZeroInit(loc); @@ -5824,10 +6821,15 @@ int TypeTypedef::hasPointers() return toBasetype()->hasPointers(); } +int TypeTypedef::hasWild() +{ + return mod & MODwild || toBasetype()->hasWild(); +} + /***************************** TypeStruct *****************************/ TypeStruct::TypeStruct(StructDeclaration *sym) - : Type(Tstruct) + : Type(Tstruct) { this->sym = sym; @@ -5839,11 +6841,11 @@ char *TypeStruct::toChars() { //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); if (mod) - return Type::toChars(); + return Type::toChars(); TemplateInstance *ti = sym->parent->isTemplateInstance(); if (ti && ti->toAlias() == sym) { - return ti->toChars(); + return ti->toChars(); } return sym->toChars(); } @@ -5873,10 +6875,10 @@ d_uns64 TypeStruct::size(Loc loc) unsigned TypeStruct::alignsize() { unsigned sz; - sym->size(0); // give error for forward references + sym->size(0); // give error for forward references sz = sym->alignsize; if (sz > sym->structalign) - sz = sym->structalign; + sz = sym->structalign; return sz; } @@ -5896,14 +6898,14 @@ void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } TemplateInstance *ti = sym->parent->isTemplateInstance(); if (ti && ti->toAlias() == sym) - buf->writestring(ti->toChars()); + buf->writestring(ti->toChars()); else - buf->writestring(sym->toChars()); + buf->writestring(sym->toChars()); } Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) @@ -5919,119 +6921,88 @@ Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (!sym->members) { - error(e->loc, "struct %s is forward referenced", sym->toChars()); - return new ErrorExp(); + error(e->loc, "struct %s is forward referenced", sym->toChars()); + return new ErrorExp(); } /* If e.tupleof */ if (ident == Id::tupleof) { - /* Create a TupleExp out of the fields of the struct e: - * (e.field0, e.field1, e.field2, ...) - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; + /* Create a TupleExp out of the fields of the struct e: + * (e.field0, e.field1, e.field2, ...) + */ + e = e->semantic(sc); // do this before turning on noaccesscheck + Expressions *exps = new Expressions; + exps->reserve(sym->fields.dim); + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + Expression *fe = new DotVarExp(e->loc, e, v); + exps->push(fe); + } + e = new TupleExp(e->loc, exps); + sc = sc->push(); + sc->noaccesscheck = 1; + e = e->semantic(sc); + sc->pop(); + return e; } if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; + { DotExp *de = (DotExp *)e; - if (de->e1->op == TOKimport) - { - assert(0); // cannot find a case where this happens; leave - // assert in until we do - ScopeExp *se = (ScopeExp *)de->e1; + if (de->e1->op == TOKimport) + { + assert(0); // cannot find a case where this happens; leave + // assert in until we do + ScopeExp *se = (ScopeExp *)de->e1; - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } + s = se->sds->search(e->loc, ident, 0); + e = de->e1; + goto L1; + } } s = sym->search(e->loc, ident, 0); L1: if (!s) { - if (ident != Id::__sizeof && - ident != Id::alignof && - ident != Id::init && - ident != Id::mangleof && - ident != Id::stringof && - ident != Id::offsetof) - { - /* See if we should forward to the alias this. - */ - if (sym->aliasthis) - { /* Rewrite e.ident as: - * e.aliasthis.ident - */ - e = new DotIdExp(e->loc, e, sym->aliasthis->ident); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - - /* Look for overloaded opDot() to see if we should forward request - * to it. - */ - Dsymbol *fd = search_function(sym, Id::opDot); - if (fd) - { /* Rewrite e.ident as: - * e.opId().ident - */ - e = build_overload(e->loc, sc, e, NULL, fd->ident); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - } - return Type::dotExp(sc, e, ident); + return noMember(sc, e, ident); } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); + if (!s->isFuncDeclaration()) // because of overloading + s->checkDeprecated(e->loc, sc); s = s->toAlias(); v = s->isVarDeclaration(); if (v && !v->isDataseg()) { - Expression *ei = v->getConstInitializer(); - if (ei) - { e = ei->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } + Expression *ei = v->getConstInitializer(); + if (ei) + { e = ei->copy(); // need to copy it if it's a StringExp + e = e->semantic(sc); + return e; + } } if (s->getType()) { - //return new DotTypeExp(e->loc, e, s); - return new TypeExp(e->loc, s->getType()); + //return new DotTypeExp(e->loc, e, s); + return new TypeExp(e->loc, s->getType()); } EnumMember *em = s->isEnumMember(); if (em) { - assert(em->value); - return em->value->copy(); + assert(em->value); + return em->value->copy(); } TemplateMixin *tm = s->isTemplateMixin(); if (tm) { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); + de->type = e->type; + return de; } TemplateDeclaration *td = s->isTemplateDeclaration(); @@ -6039,100 +7010,104 @@ L1: { e = new DotTemplateExp(e->loc, e, td); e->semantic(sc); - return e; + return e; } TemplateInstance *ti = s->isTemplateInstance(); if (ti) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; + { if (!ti->semanticRun) + { + if (global.errors) + return new ErrorExp(); // TemplateInstance::semantic() will fail anyway + ti->semantic(sc); + } + s = ti->inst->toAlias(); + if (!s->isTemplateInstance()) + goto L1; + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); + de->type = e->type; + return de; } Import *timp = s->isImport(); if (timp) { - e = new DsymbolExp(e->loc, s, 0); - e = e->semantic(sc); - return e; + e = new DsymbolExp(e->loc, s, 0); + e = e->semantic(sc); + return e; } OverloadSet *o = s->isOverloadSet(); if (o) - { /* We really should allow this, triggered by: - * template c() - * { - * void a(); - * void b () { this.a(); } - * } - * struct S - * { - * mixin c; - * mixin c; - * } - * alias S e; - */ - error(e->loc, "overload set for %s.%s not allowed in struct declaration", e->toChars(), ident->toChars()); - return new ErrorExp(); + { /* We really should allow this, triggered by: + * template c() + * { + * void a(); + * void b () { this.a(); } + * } + * struct S + * { + * mixin c; + * mixin c; + * } + * alias S e; + */ + error(e->loc, "overload set for %s.%s not allowed in struct declaration", e->toChars(), ident->toChars()); + return new ErrorExp(); } d = s->isDeclaration(); #ifdef DEBUG if (!d) - printf("d = %s '%s'\n", s->kind(), s->toChars()); + printf("d = %s '%s'\n", s->kind(), s->toChars()); #endif assert(d); if (e->op == TOKtype) - { FuncDeclaration *fd = sc->func; + { FuncDeclaration *fd = sc->func; - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - if (d->needThis() && fd && fd->vthis) - { - e = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = e->semantic(sc); - return e; - } - return new VarExp(e->loc, d, 1); + if (d->isTupleDeclaration()) + { + e = new TupleExp(e->loc, d->isTupleDeclaration()); + e = e->semantic(sc); + return e; + } + if (d->needThis() && fd && fd->vthis) + { + e = new DotVarExp(e->loc, new ThisExp(e->loc), d); + e = e->semantic(sc); + return e; + } + return new VarExp(e->loc, d, 1); } if (d->isDataseg()) { - // (e, d) - VarExp *ve; + // (e, d) + VarExp *ve; - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; + accessCheck(e->loc, sc, e, d); + ve = new VarExp(e->loc, d); + e = new CommaExp(e->loc, e, ve); + e->type = d->type; + return e; } if (v) { - if (v->toParent() != sym) - sym->error(e->loc, "'%s' is not a member", v->toChars()); + if (v->toParent() != sym) + sym->error(e->loc, "'%s' is not a member", v->toChars()); - // *(&e + offset) - accessCheck(e->loc, sc, e, d); + // *(&e + offset) + accessCheck(e->loc, sc, e, d); #if 0 - Expression *b = new AddrExp(e->loc, e); - b->type = e->type->pointerTo(); - b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32)); - b->type = v->type->pointerTo(); - b = new PtrExp(e->loc, b); - b->type = v->type->addMod(e->type->mod); - return b; + Expression *b = new AddrExp(e->loc, e); + b->type = e->type->pointerTo(); + b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32)); + b->type = v->type->pointerTo(); + b = new PtrExp(e->loc, b); + b->type = v->type->addMod(e->type->mod); + return b; #endif } @@ -6142,22 +7117,52 @@ L1: unsigned TypeStruct::memalign(unsigned salign) { - sym->size(0); // give error for forward references + sym->size(0); // give error for forward references return sym->structalign; } Expression *TypeStruct::defaultInit(Loc loc) -{ Declaration *d; - +{ #if LOGDEFAULTINIT printf("TypeStruct::defaultInit() '%s'\n", toChars()); #endif - d = new StaticStructInitDeclaration(sym->loc, sym); + Declaration *d = new StaticStructInitDeclaration(sym->loc, sym); assert(d); d->type = this; return new VarExp(sym->loc, d); } +/*************************************** + * Use when we prefer the default initializer to be a literal, + * rather than a global immutable variable. + */ +Expression *TypeStruct::defaultInitLiteral(Loc loc) +{ +#if LOGDEFAULTINIT + printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); +#endif + if (sym->isNested()) + return defaultInit(loc); + Expressions *structelems = new Expressions(); + structelems->setDim(sym->fields.dim); + for (size_t j = 0; j < structelems->dim; j++) + { + VarDeclaration *vd = (VarDeclaration *)(sym->fields.data[j]); + Expression *e; + if (vd->init) + e = vd->init->toExpression(); + else + e = vd->type->defaultInitLiteral(); + structelems->data[j] = e; + } + StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); + // Why doesn't the StructLiteralExp constructor do this, when + // sym->type != NULL ? + structinit->type = sym->type; + return structinit; +} + + int TypeStruct::isZeroInit(Loc loc) { return sym->zeroInit; @@ -6175,23 +7180,24 @@ int TypeStruct::isAssignable() */ for (size_t i = 0; i < sym->fields.dim; i++) { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; - if (v->isConst() || v->isInvariant()) - return FALSE; + if (v->isConst() || v->isImmutable()) + return FALSE; } return TRUE; } int TypeStruct::hasPointers() { + // Probably should cache this information in sym rather than recompute StructDeclaration *s = sym; - sym->size(0); // give error for forward references + sym->size(0); // give error for forward references for (size_t i = 0; i < s->fields.dim; i++) { - Dsymbol *sm = (Dsymbol *)s->fields.data[i]; - Declaration *d = sm->isDeclaration(); - if (d->storage_class & STCref || d->hasPointers()) - return TRUE; + Dsymbol *sm = (Dsymbol *)s->fields.data[i]; + Declaration *d = sm->isDeclaration(); + if (d->storage_class & STCref || d->hasPointers()) + return TRUE; } return FALSE; } @@ -6200,47 +7206,62 @@ MATCH TypeStruct::implicitConvTo(Type *to) { MATCH m; //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars()); + if (to->ty == Taarray) + { + /* If there is an error instantiating AssociativeArray!(), it shouldn't + * be reported -- it just means implicit conversion is impossible. + */ + ++global.gag; + int errs = global.errors; + to = ((TypeAArray*)to)->getImpl()->type; + --global.gag; + if (errs != global.errors) + { global.errors = errs; + return MATCHnomatch; + } + } + if (ty == to->ty && sym == ((TypeStruct *)to)->sym) - { m = MATCHexact; // exact match - if (mod != to->mod) - { - if (to->mod == MODconst) - m = MATCHconst; - else - { /* Check all the fields. If they can all be converted, - * allow the conversion. - */ - for (int i = 0; i < sym->fields.dim; i++) - { Dsymbol *s = (Dsymbol *)sym->fields.data[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); + { m = MATCHexact; // exact match + if (mod != to->mod) + { + if (MODimplicitConv(mod, to->mod)) + m = MATCHconst; + else + { /* Check all the fields. If they can all be converted, + * allow the conversion. + */ + for (int i = 0; i < sym->fields.dim; i++) + { Dsymbol *s = (Dsymbol *)sym->fields.data[i]; + VarDeclaration *v = s->isVarDeclaration(); + assert(v && v->storage_class & STCfield); - // 'from' type - Type *tvf = v->type->addMod(mod); + // 'from' type + Type *tvf = v->type->addMod(mod); - // 'to' type - Type *tv = v->type->castMod(to->mod); + // 'to' type + Type *tv = v->type->castMod(to->mod); - //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv)); - if (tvf->implicitConvTo(tv) < MATCHconst) - return MATCHnomatch; - } - m = MATCHconst; - } - } + //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv)); + if (tvf->implicitConvTo(tv) < MATCHconst) + return MATCHnomatch; + } + m = MATCHconst; + } + } } else if (sym->aliasthis) { - m = MATCHnomatch; - Declaration *d = sym->aliasthis->isDeclaration(); - if (d) - { assert(d->type); - Type *t = d->type->addMod(mod); - m = t->implicitConvTo(to); - } + m = MATCHnomatch; + Declaration *d = sym->aliasthis->isDeclaration(); + if (d) + { assert(d->type); + Type *t = d->type->addMod(mod); + m = t->implicitConvTo(to); + } } else - m = MATCHnomatch; // no match + m = MATCHnomatch; // no match return m; } @@ -6252,10 +7273,10 @@ Type *TypeStruct::toHeadMutable() MATCH TypeStruct::constConv(Type *to) { if (equals(to)) - return MATCHexact; + return MATCHexact; if (ty == to->ty && sym == ((TypeStruct *)to)->sym && - to->mod == MODconst) - return MATCHconst; + MODimplicitConv(mod, to->mod)) + return MATCHconst; return MATCHnomatch; } @@ -6263,7 +7284,7 @@ MATCH TypeStruct::constConv(Type *to) /***************************** TypeClass *****************************/ TypeClass::TypeClass(ClassDeclaration *sym) - : Type(Tclass) + : Type(Tclass) { this->sym = sym; } @@ -6271,7 +7292,7 @@ TypeClass::TypeClass(ClassDeclaration *sym) char *TypeClass::toChars() { if (mod) - return Type::toChars(); + return Type::toChars(); return (char *)sym->toPrettyChars(); } @@ -6284,7 +7305,7 @@ Type *TypeClass::semantic(Loc loc, Scope *sc) { //printf("TypeClass::semantic(%s)\n", sym->toChars()); if (deco) - return this; + return this; //printf("\t%s\n", merge()->deco); return merge(); } @@ -6310,8 +7331,8 @@ void TypeClass::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } buf->writestring(sym->toChars()); } @@ -6328,69 +7349,72 @@ Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) #endif if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; + { DotExp *de = (DotExp *)e; - if (de->e1->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)de->e1; + if (de->e1->op == TOKimport) + { + ScopeExp *se = (ScopeExp *)de->e1; - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } + s = se->sds->search(e->loc, ident, 0); + e = de->e1; + goto L1; + } } if (ident == Id::tupleof) { - /* Create a TupleExp - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; - Expression *fe = new DotVarExp(e->loc, e, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; + /* Create a TupleExp + */ + e = e->semantic(sc); // do this before turning on noaccesscheck + Expressions *exps = new Expressions; + exps->reserve(sym->fields.dim); + for (size_t i = 0; i < sym->fields.dim; i++) + { VarDeclaration *v = (VarDeclaration *)sym->fields.data[i]; + // Don't include hidden 'this' pointer + if (v->isThisDeclaration()) + continue; + Expression *fe = new DotVarExp(e->loc, e, v); + exps->push(fe); + } + e = new TupleExp(e->loc, exps); + sc = sc->push(); + sc->noaccesscheck = 1; + e = e->semantic(sc); + sc->pop(); + return e; } s = sym->search(e->loc, ident, 0); L1: if (!s) { - // See if it's a base class - ClassDeclaration *cbase; - for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass) - { - if (cbase->ident->equals(ident)) - { - e = new DotTypeExp(0, e, cbase); - return e; - } - } + // See if it's a base class + ClassDeclaration *cbase; + for (cbase = sym->baseClass; cbase; cbase = cbase->baseClass) + { + if (cbase->ident->equals(ident)) + { + e = new DotTypeExp(0, e, cbase); + return e; + } + } - if (ident == Id::classinfo) - { - assert(ClassDeclaration::classinfo); - Type *t = ClassDeclaration::classinfo->type; - if (e->op == TOKtype || e->op == TOKdottype) - { - /* For type.classinfo, we know the classinfo - * at compile time. - */ - if (!sym->vclassinfo) - sym->vclassinfo = new ClassInfoDeclaration(sym); - e = new VarExp(e->loc, sym->vclassinfo); - e = e->addressOf(sc); - e->type = t; // do this so we don't get redundant dereference - } - else + if (ident == Id::classinfo) + { + assert(ClassDeclaration::classinfo); + Type *t = ClassDeclaration::classinfo->type; + if (e->op == TOKtype || e->op == TOKdottype) + { + /* For type.classinfo, we know the classinfo + * at compile time. + */ + if (!sym->vclassinfo) + sym->vclassinfo = new TypeInfoClassDeclaration(sym->type); + e = new VarExp(e->loc, sym->vclassinfo); + e = e->addressOf(sc); + e->type = t; // do this so we don't get redundant dereference + } + else { /* For class objects, the classinfo reference is the first * entry in the vtbl[] @@ -6432,138 +7456,105 @@ L1: #else - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - if (sym->isInterfaceDeclaration()) - { - if (sym->isCPPinterface()) - { /* C++ interface vtbl[]s are different in that the - * first entry is always pointer to the first virtual - * function, not classinfo. - * We can't get a .classinfo for it. - */ - error(e->loc, "no .classinfo for C++ interface objects"); - } - /* For an interface, the first entry in the vtbl[] - * is actually a pointer to an instance of struct Interface. - * The first member of Interface is the .classinfo, - * so add an extra pointer indirection. - */ - e->type = e->type->pointerTo(); - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - } - e = new PtrExp(e->loc, e, t); + e = new PtrExp(e->loc, e); + e->type = t->pointerTo(); + if (sym->isInterfaceDeclaration()) + { + if (sym->isCPPinterface()) + { /* C++ interface vtbl[]s are different in that the + * first entry is always pointer to the first virtual + * function, not classinfo. + * We can't get a .classinfo for it. + */ + error(e->loc, "no .classinfo for C++ interface objects"); + } + /* For an interface, the first entry in the vtbl[] + * is actually a pointer to an instance of struct Interface. + * The first member of Interface is the .classinfo, + * so add an extra pointer indirection. + */ + e->type = e->type->pointerTo(); + e = new PtrExp(e->loc, e); + e->type = t->pointerTo(); + } + e = new PtrExp(e->loc, e, t); } #endif // !LDC - return e; - } + return e; + } - if (ident == Id::__vptr) - { /* The pointer to the vtbl[] - * *cast(invariant(void*)**)e - */ - e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo()); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } + if (ident == Id::__vptr) + { /* The pointer to the vtbl[] + * *cast(invariant(void*)**)e + */ + e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo()); + e = new PtrExp(e->loc, e); + e = e->semantic(sc); + return e; + } - if (ident == Id::__monitor) - { /* The handle to the monitor (call it a void*) - * *(cast(void**)e + 1) - */ - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } + if (ident == Id::__monitor) + { /* The handle to the monitor (call it a void*) + * *(cast(void**)e + 1) + */ + e = e->castTo(sc, tvoidptr->pointerTo()); + e = new AddExp(e->loc, e, new IntegerExp(1)); + e = new PtrExp(e->loc, e); + e = e->semantic(sc); + return e; + } - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - return getTypeInfo(sc); - } - if (ident == Id::outer && sym->vthis) - { - s = sym->vthis; - } - else - { - - if (ident != Id::__sizeof && - ident != Id::alignof && - ident != Id::init && - ident != Id::mangleof && - ident != Id::stringof && - ident != Id::offsetof) - { - /* See if we should forward to the alias this. - */ - if (sym->aliasthis) - { /* Rewrite e.ident as: - * e.aliasthis.ident - */ - e = new DotIdExp(e->loc, e, sym->aliasthis->ident); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - - /* Look for overloaded opDot() to see if we should forward request - * to it. - */ - Dsymbol *fd = search_function(sym, Id::opDot); - if (fd) - { /* Rewrite e.ident as: - * e.opId().ident - */ - e = build_overload(e->loc, sc, e, NULL, fd->ident); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - } - - return Type::dotExp(sc, e, ident); - } + if (ident == Id::typeinfo) + { + if (!global.params.useDeprecated) + error(e->loc, ".typeinfo deprecated, use typeid(type)"); + return getTypeInfo(sc); + } + if (ident == Id::outer && sym->vthis) + { + s = sym->vthis; + } + else + { + return noMember(sc, e, ident); + } } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); + if (!s->isFuncDeclaration()) // because of overloading + s->checkDeprecated(e->loc, sc); s = s->toAlias(); v = s->isVarDeclaration(); if (v && !v->isDataseg()) - { Expression *ei = v->getConstInitializer(); + { Expression *ei = v->getConstInitializer(); - if (ei) - { e = ei->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } + if (ei) + { e = ei->copy(); // need to copy it if it's a StringExp + e = e->semantic(sc); + return e; + } } if (s->getType()) { -// if (e->op == TOKtype) - return new TypeExp(e->loc, s->getType()); -// return new DotTypeExp(e->loc, e, s); +// if (e->op == TOKtype) + return new TypeExp(e->loc, s->getType()); +// return new DotTypeExp(e->loc, e, s); } EnumMember *em = s->isEnumMember(); if (em) { - assert(em->value); - return em->value->copy(); + assert(em->value); + return em->value->copy(); } TemplateMixin *tm = s->isTemplateMixin(); if (tm) { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); + de->type = e->type; + return de; } TemplateDeclaration *td = s->isTemplateDeclaration(); @@ -6571,106 +7562,110 @@ L1: { e = new DotTemplateExp(e->loc, e, td); e->semantic(sc); - return e; + return e; } TemplateInstance *ti = s->isTemplateInstance(); if (ti) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; + { if (!ti->semanticRun) + { + if (global.errors) + return new ErrorExp(); // TemplateInstance::semantic() will fail anyway + ti->semantic(sc); + } + s = ti->inst->toAlias(); + if (!s->isTemplateInstance()) + goto L1; + Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); + de->type = e->type; + return de; } OverloadSet *o = s->isOverloadSet(); if (o) - { /* We really should allow this - */ - error(e->loc, "overload set for %s.%s not allowed in struct declaration", e->toChars(), ident->toChars()); - return new ErrorExp(); + { /* We really should allow this + */ + error(e->loc, "overload set for %s.%s not allowed in struct declaration", e->toChars(), ident->toChars()); + return new ErrorExp(); } Declaration *d = s->isDeclaration(); if (!d) { - e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); - return new ErrorExp(); + e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); + return new ErrorExp(); } if (e->op == TOKtype) { - /* It's: - * Class.d - */ - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - else if (d->needThis() && (hasThis(sc) || !d->isFuncDeclaration())) - { - if (sc->func) - { - ClassDeclaration *thiscd; - thiscd = sc->func->toParent()->isClassDeclaration(); + /* It's: + * Class.d + */ + if (d->isTupleDeclaration()) + { + e = new TupleExp(e->loc, d->isTupleDeclaration()); + e = e->semantic(sc); + return e; + } + else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration()))) + { + if (sc->func) + { + ClassDeclaration *thiscd; + thiscd = sc->func->toParent()->isClassDeclaration(); - if (thiscd) - { - ClassDeclaration *cd = e->type->isClassHandle(); + if (thiscd) + { + ClassDeclaration *cd = e->type->isClassHandle(); - if (cd == thiscd) - { - e = new ThisExp(e->loc); - e = new DotTypeExp(e->loc, e, cd); - DotVarExp *de = new DotVarExp(e->loc, e, d); - e = de->semantic(sc); - return e; - } - else if ((!cd || !cd->isBaseOf(thiscd, NULL)) && - !d->isFuncDeclaration()) - e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars()); - } - } + if (cd == thiscd) + { + e = new ThisExp(e->loc); + e = new DotTypeExp(e->loc, e, cd); + DotVarExp *de = new DotVarExp(e->loc, e, d); + e = de->semantic(sc); + return e; + } + else if ((!cd || !cd->isBaseOf(thiscd, NULL)) && + !d->isFuncDeclaration()) + e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars()); + } + } - /* Rewrite as: - * this.d - */ - DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = de->semantic(sc); - return e; - } - else - { - VarExp *ve = new VarExp(e->loc, d, 1); - return ve; - } + /* Rewrite as: + * this.d + */ + DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d); + e = de->semantic(sc); + return e; + } + else + { + VarExp *ve = new VarExp(e->loc, d, 1); + return ve; + } } if (d->isDataseg()) { - // (e, d) - VarExp *ve; + // (e, d) + VarExp *ve; - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; + accessCheck(e->loc, sc, e, d); + ve = new VarExp(e->loc, d); + e = new CommaExp(e->loc, e, ve); + e->type = d->type; + return e; } if (d->parent && d->toParent()->isModule()) { - // (e, d) + // (e, d) - VarExp *ve = new VarExp(e->loc, d, 1); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; + VarExp *ve = new VarExp(e->loc, d, 1); + e = new CommaExp(e->loc, e, ve); + e->type = d->type; + return e; } DotVarExp *de = new DotVarExp(e->loc, e, d); @@ -6682,9 +7677,9 @@ ClassDeclaration *TypeClass::isClassHandle() return sym; } -int TypeClass::isauto() +int TypeClass::isscope() { - return sym->isauto; + return sym->isscope; } int TypeClass::isBaseOf(Type *t, int *poffset) @@ -6692,9 +7687,9 @@ int TypeClass::isBaseOf(Type *t, int *poffset) if (t->ty == Tclass) { ClassDeclaration *cd; - cd = ((TypeClass *)t)->sym; - if (sym->isBaseOf(cd, poffset)) - return 1; + cd = ((TypeClass *)t)->sym; + if (sym->isBaseOf(cd, poffset)) + return 1; } return 0; } @@ -6704,30 +7699,30 @@ MATCH TypeClass::implicitConvTo(Type *to) //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars()); MATCH m = constConv(to); if (m != MATCHnomatch) - return m; + return m; ClassDeclaration *cdto = to->isClassHandle(); if (cdto && cdto->isBaseOf(sym, NULL)) - { //printf("'to' is base\n"); - return MATCHconvert; + { //printf("'to' is base\n"); + return MATCHconvert; } if (global.params.Dversion == 1) { - // Allow conversion to (void *) - if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid) - return MATCHconvert; + // Allow conversion to (void *) + if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid) + return MATCHconvert; } m = MATCHnomatch; if (sym->aliasthis) { - Declaration *d = sym->aliasthis->isDeclaration(); - if (d) - { assert(d->type); - Type *t = d->type->addMod(mod); - m = t->implicitConvTo(to); - } + Declaration *d = sym->aliasthis->isDeclaration(); + if (d) + { assert(d->type); + Type *t = d->type->addMod(mod); + m = t->implicitConvTo(to); + } } return m; @@ -6736,10 +7731,10 @@ MATCH TypeClass::implicitConvTo(Type *to) MATCH TypeClass::constConv(Type *to) { if (equals(to)) - return MATCHexact; + return MATCHexact; if (ty == to->ty && sym == ((TypeClass *)to)->sym && - to->mod == MODconst) - return MATCHconst; + MODimplicitConv(mod, to->mod)) + return MATCHconst; return MATCHnomatch; } @@ -6753,10 +7748,7 @@ Expression *TypeClass::defaultInit(Loc loc) #if LOGDEFAULTINIT printf("TypeClass::defaultInit() '%s'\n", toChars()); #endif - Expression *e; - e = new NullExp(loc); - e->type = this; - return e; + return new NullExp(loc, this); } int TypeClass::isZeroInit(Loc loc) @@ -6776,20 +7768,20 @@ int TypeClass::hasPointers() /***************************** TypeTuple *****************************/ -TypeTuple::TypeTuple(Arguments *arguments) +TypeTuple::TypeTuple(Parameters *arguments) : Type(Ttuple) { //printf("TypeTuple(this = %p)\n", this); this->arguments = arguments; - //printf("TypeTuple() %s\n", toChars()); + //printf("TypeTuple() %p, %s\n", this, toChars()); #ifdef DEBUG if (arguments) { - for (size_t i = 0; i < arguments->dim; i++) - { - Argument *arg = (Argument *)arguments->data[i]; - assert(arg && arg->type); - } + for (size_t i = 0; i < arguments->dim; i++) + { + Parameter *arg = (Parameter *)arguments->data[i]; + assert(arg && arg->type); + } } #endif } @@ -6802,24 +7794,25 @@ TypeTuple::TypeTuple(Arguments *arguments) TypeTuple::TypeTuple(Expressions *exps) : Type(Ttuple) { - Arguments *arguments = new Arguments; + Parameters *arguments = new Parameters; if (exps) { - arguments->setDim(exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - if (e->type->ty == Ttuple) - e->error("cannot form tuple of tuples"); - Argument *arg = new Argument(STCundefined, e->type, NULL, NULL); - arguments->data[i] = (void *)arg; - } + arguments->setDim(exps->dim); + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + if (e->type->ty == Ttuple) + e->error("cannot form tuple of tuples"); + Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL); + arguments->data[i] = (void *)arg; + } } this->arguments = arguments; + //printf("TypeTuple() %p, %s\n", this, toChars()); } Type *TypeTuple::syntaxCopy() { - Arguments *args = Argument::arraySyntaxCopy(arguments); + Parameters *args = Parameter::arraySyntaxCopy(arguments); Type *t = new TypeTuple(args); t->mod = mod; return t; @@ -6828,9 +7821,9 @@ Type *TypeTuple::syntaxCopy() Type *TypeTuple::semantic(Loc loc, Scope *sc) { //printf("TypeTuple::semantic(this = %p)\n", this); - //printf("TypeTuple::semantic() %s\n", toChars()); + //printf("TypeTuple::semantic() %p, %s\n", this, toChars()); if (!deco) - deco = merge()->deco; + deco = merge()->deco; /* Don't return merge(), because a tuple with one type has the * same deco as that type. @@ -6845,22 +7838,22 @@ int TypeTuple::equals(Object *o) //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars()); if (this == t) { - return 1; + return 1; } if (t->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)t; + { TypeTuple *tt = (TypeTuple *)t; - if (arguments->dim == tt->arguments->dim) - { - for (size_t i = 0; i < tt->arguments->dim; i++) - { Argument *arg1 = (Argument *)arguments->data[i]; - Argument *arg2 = (Argument *)tt->arguments->data[i]; + if (arguments->dim == tt->arguments->dim) + { + for (size_t i = 0; i < tt->arguments->dim; i++) + { Parameter *arg1 = (Parameter *)arguments->data[i]; + Parameter *arg2 = (Parameter *)tt->arguments->data[i]; - if (!arg1->type->equals(arg2->type)) - return 0; - } - return 1; - } + if (!arg1->type->equals(arg2->type)) + return 0; + } + return 1; + } } return 0; } @@ -6869,13 +7862,13 @@ Type *TypeTuple::reliesOnTident() { if (arguments) { - for (size_t i = 0; i < arguments->dim; i++) - { - Argument *arg = (Argument *)arguments->data[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } + for (size_t i = 0; i < arguments->dim; i++) + { + Parameter *arg = (Parameter *)arguments->data[i]; + Type *t = arg->type->reliesOnTident(); + if (t) + return t; + } } return NULL; } @@ -6885,14 +7878,14 @@ Type *TypeTuple::makeConst() { //printf("TypeTuple::makeConst() %s\n", toChars()); if (cto) - return cto; + return cto; TypeTuple *t = (TypeTuple *)Type::makeConst(); - t->arguments = new Arguments(); + t->arguments = new Parameters(); t->arguments->setDim(arguments->dim); for (size_t i = 0; i < arguments->dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - Argument *narg = new Argument(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg); - t->arguments->data[i] = (Argument *)narg; + { Parameter *arg = (Parameter *)arguments->data[i]; + Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg); + t->arguments->data[i] = (Parameter *)narg; } return t; } @@ -6900,7 +7893,7 @@ Type *TypeTuple::makeConst() void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { - Argument::argsToCBuffer(buf, hgs, arguments, 0); + Parameter::argsToCBuffer(buf, hgs, arguments, 0); } void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) @@ -6908,7 +7901,7 @@ void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) //printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars()); Type::toDecoBuffer(buf, flag, mangle); OutBuffer buf2; - Argument::argsToDecoBuffer(&buf2, arguments, mangle); + Parameter::argsToDecoBuffer(&buf2, arguments, mangle); unsigned len = buf2.offset; buf->printf("%d%.*s", len, len, (char *)buf2.extractData()); } @@ -6921,12 +7914,12 @@ Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) #endif if (ident == Id::length) { - e = new IntegerExp(loc, arguments->dim, Type::tsize_t); + e = new IntegerExp(loc, arguments->dim, Type::tsize_t); } else { - error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars()); - e = new ErrorExp(); + error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars()); + e = new ErrorExp(); } return e; } @@ -6959,8 +7952,8 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) Type *tbn = next->toBasetype(); if (tbn->ty != Ttuple) - { error(loc, "can only slice tuple types, not %s", tbn->toChars()); - return Type::terror; + { error(loc, "can only slice tuple types, not %s", tbn->toChars()); + return Type::terror; } TypeTuple *tt = (TypeTuple *)tbn; @@ -6973,89 +7966,90 @@ Type *TypeSlice::semantic(Loc loc, Scope *sc) uinteger_t i2 = upr->toUInteger(); if (!(i1 <= i2 && i2 <= tt->arguments->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim); - return Type::terror; + { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim); + return Type::terror; } - Arguments *args = new Arguments; + Parameters *args = new Parameters; args->reserve(i2 - i1); for (size_t i = i1; i < i2; i++) - { Argument *arg = (Argument *)tt->arguments->data[i]; - args->push(arg); + { Parameter *arg = (Parameter *)tt->arguments->data[i]; + args->push(arg); } - return new TypeTuple(args); + Type *t = (new TypeTuple(args))->semantic(loc, sc); + return t; } void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) { next->resolve(loc, sc, pe, pt, ps); if (*pe) - { // It's really a slice expression - Expression *e; - e = new SliceExp(loc, *pe, lwr, upr); - *pe = e; + { // It's really a slice expression + Expression *e; + e = new SliceExp(loc, *pe, lwr, upr); + *pe = e; } else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - /* It's a slice of a TupleDeclaration - */ - ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); - sym->parent = sc->scopesym; - sc = sc->push(sym); + { Dsymbol *s = *ps; + TupleDeclaration *td = s->isTupleDeclaration(); + if (td) + { + /* It's a slice of a TupleDeclaration + */ + ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); + sym->parent = sc->scopesym; + sc = sc->push(sym); - lwr = lwr->semantic(sc); - lwr = lwr->optimize(WANTvalue); - uinteger_t i1 = lwr->toUInteger(); + lwr = lwr->semantic(sc); + lwr = lwr->optimize(WANTvalue); + uinteger_t i1 = lwr->toUInteger(); - upr = upr->semantic(sc); - upr = upr->optimize(WANTvalue); - uinteger_t i2 = upr->toUInteger(); + upr = upr->semantic(sc); + upr = upr->optimize(WANTvalue); + uinteger_t i2 = upr->toUInteger(); - sc = sc->pop(); + sc = sc->pop(); - if (!(i1 <= i2 && i2 <= td->objects->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim); - goto Ldefault; - } + if (!(i1 <= i2 && i2 <= td->objects->dim)) + { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim); + goto Ldefault; + } - if (i1 == 0 && i2 == td->objects->dim) - { - *ps = td; - return; - } + if (i1 == 0 && i2 == td->objects->dim) + { + *ps = td; + return; + } - /* Create a new TupleDeclaration which - * is a slice [i1..i2] out of the old one. - */ - Objects *objects = new Objects; - objects->setDim(i2 - i1); - for (size_t i = 0; i < objects->dim; i++) - { - objects->data[i] = td->objects->data[(size_t)i1 + i]; - } + /* Create a new TupleDeclaration which + * is a slice [i1..i2] out of the old one. + */ + Objects *objects = new Objects; + objects->setDim(i2 - i1); + for (size_t i = 0; i < objects->dim; i++) + { + objects->data[i] = td->objects->data[(size_t)i1 + i]; + } - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; + TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); + *ps = tds; + } + else + goto Ldefault; } else { Ldefault: - Type::resolve(loc, sc, pe, pt, ps); + Type::resolve(loc, sc, pe, pt, ps); } } void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) { if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; + { toCBuffer3(buf, hgs, mod); + return; } next->toCBuffer2(buf, hgs, this->mod); @@ -7063,9 +8057,30 @@ void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) buf->printf("%s]", upr->toChars()); } -/***************************** Argument *****************************/ +/***************************** TypeNewArray *****************************/ -Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg) +/* T[new] + */ + +TypeNewArray::TypeNewArray(Type *next) + : TypeNext(Tnarray, next) +{ + //printf("TypeNewArray\n"); +} + +void TypeNewArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) +{ + if (mod != this->mod) + { toCBuffer3(buf, hgs, mod); + return; + } + next->toCBuffer2(buf, hgs, this->mod); + buf->writestring("[new]"); +} + +/***************************** Parameter *****************************/ + +Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg) { this->type = type; this->ident = ident; @@ -7073,33 +8088,33 @@ Argument::Argument(unsigned storageClass, Type *type, Identifier *ident, Express this->defaultArg = defaultArg; } -Argument *Argument::syntaxCopy() +Parameter *Parameter::syntaxCopy() { - Argument *a = new Argument(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); + Parameter *a = new Parameter(storageClass, + type ? type->syntaxCopy() : NULL, + ident, + defaultArg ? defaultArg->syntaxCopy() : NULL); return a; } -Arguments *Argument::arraySyntaxCopy(Arguments *args) -{ Arguments *a = NULL; +Parameters *Parameter::arraySyntaxCopy(Parameters *args) +{ Parameters *a = NULL; if (args) { - a = new Arguments(); - a->setDim(args->dim); - for (size_t i = 0; i < a->dim; i++) - { Argument *arg = (Argument *)args->data[i]; + a = new Parameters(); + a->setDim(args->dim); + for (size_t i = 0; i < a->dim; i++) + { Parameter *arg = (Parameter *)args->data[i]; - arg = arg->syntaxCopy(); - a->data[i] = (void *)arg; - } + arg = arg->syntaxCopy(); + a->data[i] = (void *)arg; + } } return a; } -char *Argument::argsTypesToChars(Arguments *args, int varargs) +char *Parameter::argsTypesToChars(Parameters *args, int varargs) { OutBuffer *buf = new OutBuffer(); @@ -7109,101 +8124,102 @@ char *Argument::argsTypesToChars(Arguments *args, int varargs) #else buf->writeByte('('); if (args) - { OutBuffer argbuf; - HdrGenState hgs; + { OutBuffer argbuf; + HdrGenState hgs; - for (int i = 0; i < args->dim; i++) - { if (i) - buf->writeByte(','); - Argument *arg = (Argument *)args->data[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, &hgs, 0); - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } + for (int i = 0; i < args->dim; i++) + { if (i) + buf->writeByte(','); + Parameter *arg = (Parameter *)args->data[i]; + argbuf.reset(); + arg->type->toCBuffer2(&argbuf, &hgs, 0); + buf->write(&argbuf); + } + if (varargs) + { + if (i && varargs == 1) + buf->writeByte(','); + buf->writestring("..."); + } } buf->writeByte(')'); #endif return buf->toChars(); } -void Argument::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs) +void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) { buf->writeByte('('); if (arguments) - { int i; - OutBuffer argbuf; + { int i; + OutBuffer argbuf; - for (i = 0; i < arguments->dim; i++) - { - if (i) - buf->writestring(", "); - Argument *arg = (Argument *)arguments->data[i]; + for (i = 0; i < arguments->dim; i++) + { + if (i) + buf->writestring(", "); + Parameter *arg = (Parameter *)arguments->data[i]; - if (arg->storageClass & STCout) - buf->writestring("out "); - else if (arg->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char *)"inout " : (char *)"ref "); - else if (arg->storageClass & STCin) - buf->writestring("in "); - else if (arg->storageClass & STClazy) - buf->writestring("lazy "); - else if (arg->storageClass & STCalias) - buf->writestring("alias "); - else if (arg->storageClass & STCauto) - buf->writestring("auto "); + if (arg->storageClass & STCauto) + buf->writestring("auto "); - unsigned stc = arg->storageClass; - if (arg->type && arg->type->mod & MODshared) - stc &= ~STCshared; + if (arg->storageClass & STCout) + buf->writestring("out "); + else if (arg->storageClass & STCref) + buf->writestring((global.params.Dversion == 1) + ? "inout " : "ref "); + else if (arg->storageClass & STCin) + buf->writestring("in "); + else if (arg->storageClass & STClazy) + buf->writestring("lazy "); + else if (arg->storageClass & STCalias) + buf->writestring("alias "); - StorageClassDeclaration::stcToCBuffer(buf, - stc & (STCconst | STCimmutable | STCshared | STCscope)); + StorageClass stc = arg->storageClass; + if (arg->type && arg->type->mod & MODshared) + stc &= ~STCshared; - argbuf.reset(); - if (arg->storageClass & STCalias) - { if (arg->ident) - argbuf.writestring(arg->ident->toChars()); - } - else - arg->type->toCBuffer(&argbuf, arg->ident, hgs); - if (arg->defaultArg) - { - argbuf.writestring(" = "); - arg->defaultArg->toCBuffer(&argbuf, hgs); - } - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } + StorageClassDeclaration::stcToCBuffer(buf, + stc & (STCconst | STCimmutable | STCshared | STCscope)); + + argbuf.reset(); + if (arg->storageClass & STCalias) + { if (arg->ident) + argbuf.writestring(arg->ident->toChars()); + } + else + arg->type->toCBuffer(&argbuf, arg->ident, hgs); + if (arg->defaultArg) + { + argbuf.writestring(" = "); + arg->defaultArg->toCBuffer(&argbuf, hgs); + } + buf->write(&argbuf); + } + if (varargs) + { + if (i && varargs == 1) + buf->writeByte(','); + buf->writestring("..."); + } } buf->writeByte(')'); } -void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle) +void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle) { - //printf("Argument::argsToDecoBuffer()\n"); + //printf("Parameter::argsToDecoBuffer()\n"); // Write argument types if (arguments) { - size_t dim = Argument::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - Argument *arg = Argument::getNth(arguments, i); + size_t dim = Parameter::dim(arguments); + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = Parameter::getNth(arguments, i); arg->toDecoBuffer(buf, mangle); - } + } } } @@ -7213,19 +8229,19 @@ void Argument::argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangl * (i.e. it has auto or alias parameters) */ -int Argument::isTPL(Arguments *arguments) +int Parameter::isTPL(Parameters *arguments) { - //printf("Argument::isTPL()\n"); + //printf("Parameter::isTPL()\n"); if (arguments) { - size_t dim = Argument::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - Argument *arg = Argument::getNth(arguments, i); - if (arg->storageClass & (STCalias | STCauto | STCstatic)) - return 1; - } + size_t dim = Parameter::dim(arguments); + for (size_t i = 0; i < dim; i++) + { + Parameter *arg = Parameter::getNth(arguments, i); + if (arg->storageClass & (STCalias | STCauto | STCstatic)) + return 1; + } } return 0; } @@ -7236,56 +8252,56 @@ int Argument::isTPL(Arguments *arguments) * If not, return NULL. */ -Type *Argument::isLazyArray() +Type *Parameter::isLazyArray() { // if (inout == Lazy) { - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray || tb->ty == Tarray) - { - Type *tel = ((TypeArray *)tb)->next->toBasetype(); - if (tel->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tel; - TypeFunction *tf = (TypeFunction *)td->next; + Type *tb = type->toBasetype(); + if (tb->ty == Tsarray || tb->ty == Tarray) + { + Type *tel = ((TypeArray *)tb)->next->toBasetype(); + if (tel->ty == Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)tel; + TypeFunction *tf = (TypeFunction *)td->next; - if (!tf->varargs && Argument::dim(tf->parameters) == 0) - { - return tf->next; // return type of delegate - } - } - } + if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + { + return tf->next; // return type of delegate + } + } + } } return NULL; } -void Argument::toDecoBuffer(OutBuffer *buf, bool mangle) +void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) { if (storageClass & STCscope) - buf->writeByte('M'); + buf->writeByte('M'); switch (storageClass & (STCin | STCout | STCref | STClazy)) { case 0: - case STCin: - break; - case STCout: - buf->writeByte('J'); - break; - case STCref: - buf->writeByte('K'); - break; - case STClazy: - buf->writeByte('L'); - break; - default: + case STCin: + break; + case STCout: + buf->writeByte('J'); + break; + case STCref: + buf->writeByte('K'); + break; + case STClazy: + buf->writeByte('L'); + break; + default: #ifdef DEBUG - halt(); + halt(); #endif - assert(0); + assert(0); } #if 0 int mod = 0x100; if (type->toBasetype()->ty == Tclass) - mod = 0; + mod = 0; type->toDecoBuffer(buf, mod); #else //type->toHeadMutable()->toDecoBuffer(buf, 0); @@ -7297,57 +8313,57 @@ void Argument::toDecoBuffer(OutBuffer *buf, bool mangle) * Determine number of arguments, folding in tuples. */ -size_t Argument::dim(Arguments *args) +size_t Parameter::dim(Parameters *args) { size_t n = 0; if (args) { - for (size_t i = 0; i < args->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - Type *t = arg->type->toBasetype(); + for (size_t i = 0; i < args->dim; i++) + { Parameter *arg = (Parameter *)args->data[i]; + Type *t = arg->type->toBasetype(); - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - n += dim(tu->arguments); - } - else - n++; - } + if (t->ty == Ttuple) + { TypeTuple *tu = (TypeTuple *)t; + n += dim(tu->arguments); + } + else + n++; + } } return n; } /*************************************** - * Get nth Argument, folding in tuples. + * Get nth Parameter, folding in tuples. * Returns: - * Argument* nth Argument - * NULL not found, *pn gets incremented by the number - * of Arguments + * Parameter* nth Parameter + * NULL not found, *pn gets incremented by the number + * of Parameters */ -Argument *Argument::getNth(Arguments *args, size_t nth, size_t *pn) +Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn) { if (!args) - return NULL; + return NULL; size_t n = 0; for (size_t i = 0; i < args->dim; i++) - { Argument *arg = (Argument *)args->data[i]; - Type *t = arg->type->toBasetype(); + { Parameter *arg = (Parameter *)args->data[i]; + Type *t = arg->type->toBasetype(); - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - arg = getNth(tu->arguments, nth - n, &n); - if (arg) - return arg; - } - else if (n == nth) - return arg; - else - n++; + if (t->ty == Ttuple) + { TypeTuple *tu = (TypeTuple *)t; + arg = getNth(tu->arguments, nth - n, &n); + if (arg) + return arg; + } + else if (n == nth) + return arg; + else + n++; } if (pn) - *pn += n; + *pn += n; return NULL; } diff --git a/dmd2/mtype.h b/dmd2/mtype.h index b78b4c92..d7a380c5 100644 --- a/dmd2/mtype.h +++ b/dmd2/mtype.h @@ -1,904 +1,979 @@ - -// 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. - -#ifndef DMD_MTYPE_H -#define DMD_MTYPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "expression.h" - -#if IN_LLVM -#include "../ir/irfuncty.h" -namespace llvm { class Type; } -class Ir; -class IrType; -#endif - -struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; -struct CppMangleState; -enum LINK; - -struct TypeBasic; -struct HdrGenState; -struct Argument; - -// Back end -#if IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; -#endif - -#if IN_DMD -typedef struct TYPE type; -struct Symbol; -#endif - - -enum ENUMTY -{ - Tarray, // slice array, aka T[] - Tsarray, // static array, aka T[dimension] - Tnarray, // resizable array, aka T[new] - Taarray, // associative array, aka T[type] - Tpointer, - Treference, - Tfunction, - Tident, - Tclass, - Tstruct, - Tenum, - Ttypedef, - Tdelegate, - - Tnone, - Tvoid, - Tint8, - Tuns8, - Tint16, - Tuns16, - Tint32, - Tuns32, - Tint64, - Tuns64, - Tfloat32, - Tfloat64, - Tfloat80, - - Timaginary32, - Timaginary64, - Timaginary80, - - Tcomplex32, - Tcomplex64, - Tcomplex80, - - Tbit, - Tbool, - Tchar, - Twchar, - Tdchar, - - Terror, - Tinstance, - Ttypeof, - Ttuple, - Tslice, - Treturn, - TMAX -}; -typedef unsigned char TY; // ENUMTY - -#define Tascii Tchar - -extern int Tsize_t; -extern int Tptrdiff_t; - - -struct Type : Object -{ - TY ty; - unsigned char mod; // modifiers MODxxxx - /* pick this order of numbers so switch statements work better - */ - #define MODconst 1 // type is const - #define MODinvariant 4 // type is invariant - #define MODshared 2 // type is shared - char *deco; - - /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. - * They should not be referenced by anybody but mtype.c. - * They can be NULL if not lazily evaluated yet. - * Note that there is no "shared immutable", because that is just immutable - */ - - Type *cto; // MODconst ? mutable version of this type : const version - Type *ito; // MODinvariant ? mutable version of this type : invariant version - Type *sto; // MODshared ? mutable version of this type : shared mutable version - Type *scto; // MODshared|MODconst ? mutable version of this type : shared const version - - Type *pto; // merged pointer to this type - Type *rto; // reference to this type - Type *arrayof; // array of this type - TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type - -#if IN_DMD - type *ctype; // for back end -#endif - - #define tvoid basic[Tvoid] - #define tint8 basic[Tint8] - #define tuns8 basic[Tuns8] - #define tint16 basic[Tint16] - #define tuns16 basic[Tuns16] - #define tint32 basic[Tint32] - #define tuns32 basic[Tuns32] - #define tint64 basic[Tint64] - #define tuns64 basic[Tuns64] - #define tfloat32 basic[Tfloat32] - #define tfloat64 basic[Tfloat64] - #define tfloat80 basic[Tfloat80] - - #define timaginary32 basic[Timaginary32] - #define timaginary64 basic[Timaginary64] - #define timaginary80 basic[Timaginary80] - - #define tcomplex32 basic[Tcomplex32] - #define tcomplex64 basic[Tcomplex64] - #define tcomplex80 basic[Tcomplex80] - - #define tbit basic[Tbit] - #define tbool basic[Tbool] - #define tchar basic[Tchar] - #define twchar basic[Twchar] - #define tdchar basic[Tdchar] - - // Some special types - #define tshiftcnt tint32 // right side of shift expression -// #define tboolean tint32 // result of boolean expression - #define tboolean tbool // result of boolean expression - #define tindex tint32 // array/ptr index - static Type *tvoidptr; // void* - #define terror basic[Terror] // for error recovery - - #define tsize_t basic[Tsize_t] // matches size_t alias - #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias - #define thash_t tsize_t // matches hash_t alias - - static ClassDeclaration *typeinfo; - static ClassDeclaration *typeinfoclass; - static ClassDeclaration *typeinfointerface; - static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; - static ClassDeclaration *typeinfopointer; - static ClassDeclaration *typeinfoarray; - static ClassDeclaration *typeinfostaticarray; - static ClassDeclaration *typeinfoassociativearray; - static ClassDeclaration *typeinfoenum; - static ClassDeclaration *typeinfofunction; - static ClassDeclaration *typeinfodelegate; - static ClassDeclaration *typeinfotypelist; - static ClassDeclaration *typeinfoconst; - static ClassDeclaration *typeinfoinvariant; - static ClassDeclaration *typeinfoshared; - - static Type *basic[TMAX]; - static unsigned char mangleChar[TMAX]; - static unsigned char sizeTy[TMAX]; - static StringTable stringtable; -#if IN_LLVM - static StringTable deco_stringtable; -#endif - - // These tables are for implicit conversion of binary ops; - // the indices are the type of operand one, followed by operand two. - static unsigned char impcnvResult[TMAX][TMAX]; - static unsigned char impcnvType1[TMAX][TMAX]; - static unsigned char impcnvType2[TMAX][TMAX]; - - // If !=0, give warning on implicit conversion - static unsigned char impcnvWarn[TMAX][TMAX]; - - Type(TY ty); - virtual Type *syntaxCopy(); - int equals(Object *o); - int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() - int covariant(Type *t); - char *toChars(); - static char needThisPrefix(); -#if IN_LLVM - static void init(Ir*); -#else - static void init(); -#endif - d_uns64 size(); - virtual d_uns64 size(Loc loc); - virtual unsigned alignsize(); - virtual Type *semantic(Loc loc, Scope *sc); - Type *trySemantic(Loc loc, Scope *sc); - // append the mangleof or a string uniquely identifying this type to buf - virtual void toDecoBuffer(OutBuffer *buf, int flag = 0, bool mangle=false); - Type *merge(); - Type *merge2(); - virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod); - void modToBuffer(OutBuffer *buf); -#if CPP_MANGLE - virtual void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - virtual int isintegral(); - virtual int isfloating(); // real, imaginary, or complex - virtual int isreal(); - virtual int isimaginary(); - virtual int iscomplex(); - virtual int isscalar(); - virtual int isunsigned(); - virtual int isauto(); - virtual int isString(); - virtual int isAssignable(); - virtual int checkBoolean(); // if can be converted to boolean value - virtual void checkDeprecated(Loc loc, Scope *sc); - int isConst() { return mod & MODconst; } - int isInvariant() { return mod & MODinvariant; } - int isMutable() { return !(mod & (MODconst | MODinvariant)); } - int isShared() { return mod & MODshared; } - int isSharedConst() { return mod == (MODshared | MODconst); } - Type *constOf(); - Type *invariantOf(); - Type *mutableOf(); - Type *sharedOf(); - Type *sharedConstOf(); - void fixTo(Type *t); - void check(); - Type *castMod(unsigned mod); - Type *addMod(unsigned mod); - Type *addStorageClass(unsigned stc); - Type *pointerTo(); - Type *referenceTo(); - Type *arrayOf(); - virtual Type *makeConst(); - virtual Type *makeInvariant(); - virtual Type *makeShared(); - virtual Type *makeSharedConst(); - virtual Dsymbol *toDsymbol(Scope *sc); - virtual Type *toBasetype(); - virtual Type *toHeadMutable(); - virtual int isBaseOf(Type *t, int *poffset); - virtual MATCH constConv(Type *to); - virtual MATCH implicitConvTo(Type *to); - virtual ClassDeclaration *isClassHandle(); - virtual Expression *getProperty(Loc loc, Identifier *ident); - virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - virtual unsigned memalign(unsigned salign); - virtual Expression *defaultInit(Loc loc = 0); - virtual int isZeroInit(Loc loc = 0); // if initializer is 0 -#if IN_DMD - virtual dt_t **toDt(dt_t **pdt); -#endif - Identifier *getTypeInfoIdent(int internal); - virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Expression *getInternalTypeInfo(Scope *sc); - Expression *getTypeInfo(Scope *sc); - virtual TypeInfoDeclaration *getTypeInfoDeclaration(); - virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); - virtual Expression *toExpression(); - virtual int hasPointers(); - //Type *next; - virtual Type *nextOf(); - uinteger_t sizemask(); - - - static void error(Loc loc, const char *format, ...) IS_PRINTF(2); - static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); - -#if IN_DMD - // For backend - virtual unsigned totym(); - virtual type *toCtype(); - virtual type *toCParamtype(); - virtual Symbol *toSymbol(); -#endif - - // For eliminating dynamic_cast - virtual TypeBasic *isTypeBasic(); - -#if IN_LLVM - static Ir* sir; - IrType* irtype; -#endif -}; - -struct TypeNext : Type -{ - Type *next; - - TypeNext(TY ty, Type *next); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void checkDeprecated(Loc loc, Scope *sc); - Type *reliesOnTident(); - Type *nextOf(); - Type *makeConst(); - Type *makeInvariant(); - Type *makeShared(); - Type *makeSharedConst(); - MATCH constConv(Type *to); - void transitive(); -}; - -struct TypeBasic : Type -{ - const char *dstring; - unsigned flags; - - TypeBasic(TY ty); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - char *toChars(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - int isintegral(); - int isbit(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int builtinTypeInfo(); - - // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); -}; - -struct TypeArray : TypeNext -{ - TypeArray(TY ty, Type *next); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); -}; - -// Static array, one with a fixed dimension -struct TypeSArray : TypeArray -{ - Expression *dim; - - TypeSArray(Type *t, Expression *dim); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - unsigned memalign(unsigned salign); - MATCH constConv(Type *to); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); - dt_t **toDtElem(dt_t **pdt, Expression *e); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -// Dynamic array, no dimension -struct TypeDArray : TypeArray -{ - TypeDArray(Type *t); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - int checkBoolean(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int builtinTypeInfo(); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeAArray : TypeArray -{ - Type *index; // key type - - TypeAArray(Type *t, Type *index); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - // Back end - Symbol *aaGetSymbol(const char *func, int flags); - - type *toCtype(); -#endif -}; - -struct TypePointer : TypeNext -{ - TypePointer(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH implicitConvTo(Type *to); - int isscalar(); - // LDC: pointers are unsigned - int isunsigned() { return TRUE; }; - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeReference : TypeNext -{ - TypeReference(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif -}; - -enum RET -{ - RETregs = 1, // returned in registers - RETstack = 2, // returned on stack -}; - -struct TypeFunction : TypeNext -{ - // .next is the return type - - Arguments *parameters; // function parameters - int varargs; // 1: T t, ...) style for variable number of arguments - // 2: T t ...) style for variable number of arguments - bool isnothrow; // true: nothrow - bool ispure; // true: pure - bool isproperty; // can be called without parentheses - bool isref; // true: returns a reference - enum LINK linkage; // calling convention - - int inuse; - - TypeFunction(Arguments *parameters, Type *treturn, int varargs, enum LINK linkage); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - bool parameterEscapes(Argument *p); - - int callMatch(Expression *ethis, Expressions *toargs); -#if IN_DMD - type *toCtype(); -#endif - - enum RET retStyle(); - -#if IN_DMD - unsigned totym(); -#elif IN_LLVM - // LDC - IrFuncTy fty; - - FuncDeclaration* funcdecl; -#endif -}; - -struct TypeDelegate : TypeNext -{ - // .next is a TypeFunction - - TypeDelegate(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - unsigned alignsize(); // added in LDC - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int hasPointers(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeQualified : Type -{ - Loc loc; - Array idents; // array of Identifier's representing ident.ident.ident etc. - - TypeQualified(TY ty, Loc loc); - void syntaxCopyHelper(TypeQualified *t); - void addIdent(Identifier *ident); - void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); - d_uns64 size(Loc loc); - void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps); -}; - -struct TypeIdentifier : TypeQualified -{ - Identifier *ident; - - TypeIdentifier(Loc loc, Identifier *ident); - Type *syntaxCopy(); - //char *toChars(); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - Type *reliesOnTident(); - Expression *toExpression(); -}; - -/* Similar to TypeIdentifier, but with a TemplateInstance as the root - */ -struct TypeInstance : TypeQualified -{ - TemplateInstance *tempinst; - - TypeInstance(Loc loc, TemplateInstance *tempinst); - Type *syntaxCopy(); - //char *toChars(); - //void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); -}; - -struct TypeTypeof : TypeQualified -{ - Expression *exp; - - TypeTypeof(Loc loc, Expression *exp); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); -}; - -struct TypeReturn : TypeQualified -{ - TypeReturn(Loc loc); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -struct TypeStruct : Type -{ - StructDeclaration *sym; - - TypeStruct(StructDeclaration *sym); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int isAssignable(); - int checkBoolean(); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Type *toHeadMutable(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#elif IN_LLVM - // LDC - // cache the hasUnalignedFields check - // 0 = not checked, 1 = aligned, 2 = unaligned - int unaligned; -#endif -}; - -struct TypeEnum : Type -{ - EnumDeclaration *sym; - - TypeEnum(EnumDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isintegral(); - int isfloating(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Type *toBasetype(); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeTypedef : Type -{ - TypedefDeclaration *sym; - - TypeTypedef(TypedefDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isbit(); - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - int isAssignable(); - Type *toBasetype(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - Type *toHeadMutable(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -struct TypeClass : Type -{ - ClassDeclaration *sym; - - TypeClass(ClassDeclaration *sym); - d_uns64 size(Loc loc); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - ClassDeclaration *isClassHandle(); - int isBaseOf(Type *t, int *poffset); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); - int isauto(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - int builtinTypeInfo(); -#if DMDV2 - Type *toHeadMutable(); - MATCH constConv(Type *to); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif -#endif - -#if IN_DMD - type *toCtype(); - - Symbol *toSymbol(); -#endif -}; - -struct TypeTuple : Type -{ - Arguments *arguments; // types making up the tuple - - TypeTuple(Arguments *arguments); - TypeTuple(Expressions *exps); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - int equals(Object *o); - Type *reliesOnTident(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - Expression *getProperty(Loc loc, Identifier *ident); - TypeInfoDeclaration *getTypeInfoDeclaration(); -}; - -struct TypeSlice : TypeNext -{ - Expression *lwr; - Expression *upr; - - TypeSlice(Type *next, Expression *lwr, Expression *upr); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -/**************************************************************/ - -//enum InOut { None, In, Out, InOut, Lazy }; - -struct Argument : Object -{ - //enum InOut inout; - unsigned storageClass; - Type *type; - Identifier *ident; - Expression *defaultArg; - - Argument(unsigned storageClass, Type *type, Identifier *ident, Expression *defaultArg); - Argument *syntaxCopy(); - Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf, bool mangle); - static Arguments *arraySyntaxCopy(Arguments *args); - static char *argsTypesToChars(Arguments *args, int varargs); - static void argsCppMangle(OutBuffer *buf, CppMangleState *cms, Arguments *arguments, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Arguments *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments, bool mangle); - static int isTPL(Arguments *arguments); - static size_t dim(Arguments *arguments); - static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL); -}; - -extern int PTRSIZE; -extern int REALSIZE; -extern int REALPAD; -extern int Tsize_t; -extern int Tptrdiff_t; - -int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); - -#endif /* DMD_MTYPE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_MTYPE_H +#define DMD_MTYPE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" +#include "stringtable.h" + +#include "arraytypes.h" +#include "expression.h" + +#if IN_LLVM +#include "../ir/irfuncty.h" +namespace llvm { class Type; } +class Ir; +class IrType; +#endif + +struct Scope; +struct Identifier; +struct Expression; +struct StructDeclaration; +struct ClassDeclaration; +struct VarDeclaration; +struct EnumDeclaration; +struct TypedefDeclaration; +struct TypeInfoDeclaration; +struct Dsymbol; +struct TemplateInstance; +struct CppMangleState; +struct TemplateDeclaration; +enum LINK; + +struct TypeBasic; +struct HdrGenState; +struct Parameter; + +// Back end +#if IN_GCC +union tree_node; typedef union tree_node TYPE; +typedef TYPE type; +#endif + +#if IN_DMD +typedef struct TYPE type; +struct Symbol; +#endif + + +enum ENUMTY +{ + Tarray, // slice array, aka T[] + Tsarray, // static array, aka T[dimension] + Tnarray, // resizable array, aka T[new] + Taarray, // associative array, aka T[type] + Tpointer, + Treference, + Tfunction, + Tident, + Tclass, + Tstruct, + + Tenum, + Ttypedef, + Tdelegate, + Tnone, + Tvoid, + Tint8, + Tuns8, + Tint16, + Tuns16, + Tint32, + + Tuns32, + Tint64, + Tuns64, + Tfloat32, + Tfloat64, + Tfloat80, + Timaginary32, + Timaginary64, + Timaginary80, + Tcomplex32, + + Tcomplex64, + Tcomplex80, + Tbit, + Tbool, + Tchar, + Twchar, + Tdchar, + Terror, + Tinstance, + Ttypeof, + + Ttuple, + Tslice, + Treturn, + TMAX +}; +typedef unsigned char TY; // ENUMTY + +#define Tascii Tchar + +extern int Tsize_t; +extern int Tptrdiff_t; + + +struct Type : Object +{ + TY ty; + unsigned char mod; // modifiers MODxxxx + /* pick this order of numbers so switch statements work better + */ + #define MODconst 1 // type is const + #define MODimmutable 4 // type is immutable + #define MODshared 2 // type is shared + #define MODwild 8 // type is wild + #define MODmutable 0x10 // type is mutable (only used in wildcard matching) + char *deco; + + /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. + * They should not be referenced by anybody but mtype.c. + * They can be NULL if not lazily evaluated yet. + * Note that there is no "shared immutable", because that is just immutable + * Naked == no MOD bits + */ + + Type *cto; // MODconst ? naked version of this type : const version + Type *ito; // MODimmutable ? naked version of this type : immutable version + Type *sto; // MODshared ? naked version of this type : shared mutable version + Type *scto; // MODshared|MODconst ? naked version of this type : shared const version + Type *wto; // MODwild ? naked version of this type : wild version + Type *swto; // MODshared|MODwild ? naked version of this type : shared wild version + + Type *pto; // merged pointer to this type + Type *rto; // reference to this type + Type *arrayof; // array of this type + TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type + +#if IN_DMD + type *ctype; // for back end +#endif + + #define tvoid basic[Tvoid] + #define tint8 basic[Tint8] + #define tuns8 basic[Tuns8] + #define tint16 basic[Tint16] + #define tuns16 basic[Tuns16] + #define tint32 basic[Tint32] + #define tuns32 basic[Tuns32] + #define tint64 basic[Tint64] + #define tuns64 basic[Tuns64] + #define tfloat32 basic[Tfloat32] + #define tfloat64 basic[Tfloat64] + #define tfloat80 basic[Tfloat80] + + #define timaginary32 basic[Timaginary32] + #define timaginary64 basic[Timaginary64] + #define timaginary80 basic[Timaginary80] + + #define tcomplex32 basic[Tcomplex32] + #define tcomplex64 basic[Tcomplex64] + #define tcomplex80 basic[Tcomplex80] + + #define tbit basic[Tbit] + #define tbool basic[Tbool] + #define tchar basic[Tchar] + #define twchar basic[Twchar] + #define tdchar basic[Tdchar] + + // Some special types + #define tshiftcnt tint32 // right side of shift expression +// #define tboolean tint32 // result of boolean expression + #define tboolean tbool // result of boolean expression + #define tindex tint32 // array/ptr index + static Type *tvoidptr; // void* + static Type *tstring; // immutable(char)[] + #define terror basic[Terror] // for error recovery + + #define tsize_t basic[Tsize_t] // matches size_t alias + #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias + #define thash_t tsize_t // matches hash_t alias + + static ClassDeclaration *typeinfo; + static ClassDeclaration *typeinfoclass; + static ClassDeclaration *typeinfointerface; + static ClassDeclaration *typeinfostruct; + static ClassDeclaration *typeinfotypedef; + static ClassDeclaration *typeinfopointer; + static ClassDeclaration *typeinfoarray; + static ClassDeclaration *typeinfostaticarray; + static ClassDeclaration *typeinfoassociativearray; + static ClassDeclaration *typeinfoenum; + static ClassDeclaration *typeinfofunction; + static ClassDeclaration *typeinfodelegate; + static ClassDeclaration *typeinfotypelist; + static ClassDeclaration *typeinfoconst; + static ClassDeclaration *typeinfoinvariant; + static ClassDeclaration *typeinfoshared; + static ClassDeclaration *typeinfowild; + + static TemplateDeclaration *associativearray; + + static Type *basic[TMAX]; + static unsigned char mangleChar[TMAX]; + static unsigned char sizeTy[TMAX]; + static StringTable stringtable; +#if IN_LLVM + static StringTable deco_stringtable; +#endif + + // These tables are for implicit conversion of binary ops; + // the indices are the type of operand one, followed by operand two. + static unsigned char impcnvResult[TMAX][TMAX]; + static unsigned char impcnvType1[TMAX][TMAX]; + static unsigned char impcnvType2[TMAX][TMAX]; + + // If !=0, give warning on implicit conversion + static unsigned char impcnvWarn[TMAX][TMAX]; + + Type(TY ty); + virtual Type *syntaxCopy(); + int equals(Object *o); + int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() + int covariant(Type *t); + char *toChars(); + static char needThisPrefix(); +#if IN_LLVM + static void init(Ir*); +#else + static void init(); +#endif + d_uns64 size(); + virtual d_uns64 size(Loc loc); + virtual unsigned alignsize(); + virtual Type *semantic(Loc loc, Scope *sc); + Type *trySemantic(Loc loc, Scope *sc); + // append the mangleof or a string uniquely identifying this type to buf + virtual void toDecoBuffer(OutBuffer *buf, int flag = 0, bool mangle=false); + Type *merge(); + Type *merge2(); + virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod); + void modToBuffer(OutBuffer *buf); +#if CPP_MANGLE + virtual void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + virtual int isintegral(); + virtual int isfloating(); // real, imaginary, or complex + virtual int isreal(); + virtual int isimaginary(); + virtual int iscomplex(); + virtual int isscalar(); + virtual int isunsigned(); + virtual int isscope(); + virtual int isString(); + virtual int isAssignable(); + virtual int checkBoolean(); // if can be converted to boolean value + virtual void checkDeprecated(Loc loc, Scope *sc); + int isConst() { return mod & MODconst; } + int isImmutable() { return mod & MODimmutable; } + int isMutable() { return !(mod & (MODconst | MODimmutable | MODwild)); } + int isShared() { return mod & MODshared; } + int isSharedConst() { return mod == (MODshared | MODconst); } + int isWild() { return mod & MODwild; } + int isSharedWild() { return mod == (MODshared | MODwild); } + int isNaked() { return mod == 0; } + Type *constOf(); + Type *invariantOf(); + Type *mutableOf(); + Type *sharedOf(); + Type *sharedConstOf(); + Type *unSharedOf(); + Type *wildOf(); + Type *sharedWildOf(); + void fixTo(Type *t); + void check(); + Type *castMod(unsigned mod); + Type *addMod(unsigned mod); + Type *addStorageClass(StorageClass stc); + Type *pointerTo(); + Type *referenceTo(); + Type *arrayOf(); + virtual Type *makeConst(); + virtual Type *makeInvariant(); + virtual Type *makeShared(); + virtual Type *makeSharedConst(); + virtual Type *makeWild(); + virtual Type *makeSharedWild(); + virtual Type *makeMutable(); + virtual Dsymbol *toDsymbol(Scope *sc); + virtual Type *toBasetype(); + virtual Type *toHeadMutable(); + virtual int isBaseOf(Type *t, int *poffset); + virtual MATCH constConv(Type *to); + virtual MATCH implicitConvTo(Type *to); + virtual ClassDeclaration *isClassHandle(); + virtual Expression *getProperty(Loc loc, Identifier *ident); + virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *noMember(Scope *sc, Expression *e, Identifier *ident); + virtual unsigned memalign(unsigned salign); + virtual Expression *defaultInit(Loc loc = 0); + virtual Expression *defaultInitLiteral(Loc loc = 0); + virtual int isZeroInit(Loc loc = 0); // if initializer is 0 +#if IN_DMD + virtual dt_t **toDt(dt_t **pdt); +#endif + Identifier *getTypeInfoIdent(int internal); + virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + Expression *getInternalTypeInfo(Scope *sc); + Expression *getTypeInfo(Scope *sc); + virtual TypeInfoDeclaration *getTypeInfoDeclaration(); + virtual int builtinTypeInfo(); + virtual Type *reliesOnTident(); + virtual int hasWild(); + virtual unsigned wildMatch(Type *targ); + virtual Expression *toExpression(); + virtual int hasPointers(); + //Type *next; + virtual Type *nextOf(); + uinteger_t sizemask(); + + + static void error(Loc loc, const char *format, ...) IS_PRINTF(2); + static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); + +#if IN_DMD + // For backend + virtual unsigned totym(); + virtual type *toCtype(); + virtual type *toCParamtype(); + virtual Symbol *toSymbol(); +#endif + + // For eliminating dynamic_cast + virtual TypeBasic *isTypeBasic(); + +#if IN_LLVM + static Ir* sir; + IrType* irtype; +#endif +}; + +struct TypeError : Type +{ + TypeError(); + + void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + + d_uns64 size(Loc loc); + Expression *getProperty(Loc loc, Identifier *ident); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *defaultInit(Loc loc); + Expression *defaultInitLiteral(Loc loc); +}; + +struct TypeNext : Type +{ + Type *next; + + TypeNext(TY ty, Type *next); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void checkDeprecated(Loc loc, Scope *sc); + Type *reliesOnTident(); + int hasWild(); + unsigned wildMatch(Type *targ); + Type *nextOf(); + Type *makeConst(); + Type *makeInvariant(); + Type *makeShared(); + Type *makeSharedConst(); + Type *makeWild(); + Type *makeSharedWild(); + Type *makeMutable(); + MATCH constConv(Type *to); + void transitive(); +}; + +struct TypeBasic : Type +{ + const char *dstring; + unsigned flags; + + TypeBasic(TY ty); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + Expression *getProperty(Loc loc, Identifier *ident); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + char *toChars(); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + int isintegral(); + int isbit(); + int isfloating(); + int isreal(); + int isimaginary(); + int iscomplex(); + int isscalar(); + int isunsigned(); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); + int builtinTypeInfo(); + + // For eliminating dynamic_cast + TypeBasic *isTypeBasic(); +}; + +struct TypeArray : TypeNext +{ + TypeArray(TY ty, Type *next); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); +}; + +// Static array, one with a fixed dimension +struct TypeSArray : TypeArray +{ + Expression *dim; + + TypeSArray(Type *t, Expression *dim); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + Type *semantic(Loc loc, Scope *sc); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int isString(); + int isZeroInit(Loc loc); + unsigned memalign(unsigned salign); + MATCH constConv(Type *to); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + Expression *defaultInitLiteral(Loc loc); +#if IN_DMD + dt_t **toDt(dt_t **pdt); + dt_t **toDtElem(dt_t **pdt, Expression *e); +#endif + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Expression *toExpression(); + int hasPointers(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); + type *toCParamtype(); +#endif +}; + +// Dynamic array, no dimension +struct TypeDArray : TypeArray +{ + TypeDArray(Type *t); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + Type *semantic(Loc loc, Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int isString(); + int isZeroInit(Loc loc); + int checkBoolean(); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + int builtinTypeInfo(); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); +#endif +}; + +struct TypeAArray : TypeArray +{ + Type *index; // key type + Loc loc; + Scope *sc; + + StructDeclaration *impl; // implementation + + TypeAArray(Type *t, Type *index); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + Type *semantic(Loc loc, Scope *sc); + StructDeclaration *getImpl(); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *defaultInit(Loc loc); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + int isZeroInit(Loc loc); + int checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + MATCH implicitConvTo(Type *to); + MATCH constConv(Type *to); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + // Back end + Symbol *aaGetSymbol(const char *func, int flags); + + type *toCtype(); +#endif +}; + +struct TypePointer : TypeNext +{ + TypePointer(Type *t); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + MATCH implicitConvTo(Type *to); + int isscalar(); + // LDC: pointers are unsigned + int isunsigned() { return TRUE; }; + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); +#endif +}; + +struct TypeReference : TypeNext +{ + TypeReference(Type *t); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif +}; + +enum RET +{ + RETregs = 1, // returned in registers + RETstack = 2, // returned on stack +}; + +enum TRUST +{ + TRUSTdefault = 0, + TRUSTsystem = 1, // @system (same as TRUSTdefault) + TRUSTtrusted = 2, // @trusted + TRUSTsafe = 3, // @safe +}; + +struct TypeFunction : TypeNext +{ + // .next is the return type + + Parameters *parameters; // function parameters + int varargs; // 1: T t, ...) style for variable number of arguments + // 2: T t ...) style for variable number of arguments + bool isnothrow; // true: nothrow + bool ispure; // true: pure + bool isproperty; // can be called without parentheses + bool isref; // true: returns a reference + enum LINK linkage; // calling convention + enum TRUST trust; // level of trust + Expressions *fargs; // function arguments + + int inuse; + + TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc = 0); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void attributesToCBuffer(OutBuffer *buf, int mod); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Type *reliesOnTident(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + bool parameterEscapes(Parameter *p); + + int callMatch(Expression *ethis, Expressions *toargs, int flag = 0); +#if IN_DMD + type *toCtype(); +#endif + + enum RET retStyle(); + +#if IN_DMD + unsigned totym(); +#elif IN_LLVM + // LDC + IrFuncTy fty; + + FuncDeclaration* funcdecl; +#endif +}; + +struct TypeDelegate : TypeNext +{ + // .next is a TypeFunction + + TypeDelegate(Type *t); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); + unsigned alignsize(); + MATCH implicitConvTo(Type *to); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); + int checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + int hasPointers(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); +#endif +}; + +struct TypeQualified : Type +{ + Loc loc; + Array idents; // array of Identifier's representing ident.ident.ident etc. + + TypeQualified(TY ty, Loc loc); + void syntaxCopyHelper(TypeQualified *t); + void addIdent(Identifier *ident); + void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); + d_uns64 size(Loc loc); + void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, + Expression **pe, Type **pt, Dsymbol **ps); +}; + +struct TypeIdentifier : TypeQualified +{ + Identifier *ident; + + TypeIdentifier(Loc loc, Identifier *ident); + Type *syntaxCopy(); + //char *toChars(); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + Dsymbol *toDsymbol(Scope *sc); + Type *semantic(Loc loc, Scope *sc); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + Type *reliesOnTident(); + Expression *toExpression(); +}; + +/* Similar to TypeIdentifier, but with a TemplateInstance as the root + */ +struct TypeInstance : TypeQualified +{ + TemplateInstance *tempinst; + + TypeInstance(Loc loc, TemplateInstance *tempinst); + Type *syntaxCopy(); + //char *toChars(); + //void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); +}; + +struct TypeTypeof : TypeQualified +{ + Expression *exp; + + TypeTypeof(Loc loc, Expression *exp); + Type *syntaxCopy(); + Dsymbol *toDsymbol(Scope *sc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Type *semantic(Loc loc, Scope *sc); + d_uns64 size(Loc loc); +}; + +struct TypeReturn : TypeQualified +{ + TypeReturn(Loc loc); + Type *syntaxCopy(); + Dsymbol *toDsymbol(Scope *sc); + Type *semantic(Loc loc, Scope *sc); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +}; + +struct TypeStruct : Type +{ + StructDeclaration *sym; + + TypeStruct(StructDeclaration *sym); + d_uns64 size(Loc loc); + unsigned alignsize(); + char *toChars(); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + unsigned memalign(unsigned salign); + Expression *defaultInit(Loc loc); + Expression *defaultInitLiteral(Loc loc); + int isZeroInit(Loc loc); + int isAssignable(); + int checkBoolean(); +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + MATCH implicitConvTo(Type *to); + MATCH constConv(Type *to); + Type *toHeadMutable(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); +#elif IN_LLVM + // LDC + // cache the hasUnalignedFields check + // 0 = not checked, 1 = aligned, 2 = unaligned + int unaligned; +#endif +}; + +struct TypeEnum : Type +{ + EnumDeclaration *sym; + + TypeEnum(EnumDeclaration *sym); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + char *toChars(); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *getProperty(Loc loc, Identifier *ident); + int isintegral(); + int isfloating(); + int isreal(); + int isimaginary(); + int iscomplex(); + int isscalar(); + int isunsigned(); + int checkBoolean(); + int isAssignable(); + MATCH implicitConvTo(Type *to); + MATCH constConv(Type *to); + Type *toBasetype(); + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); +#endif +}; + +struct TypeTypedef : Type +{ + TypedefDeclaration *sym; + + TypeTypedef(TypedefDeclaration *sym); + Type *syntaxCopy(); + d_uns64 size(Loc loc); + unsigned alignsize(); + char *toChars(); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + Expression *getProperty(Loc loc, Identifier *ident); + int isbit(); + int isintegral(); + int isfloating(); + int isreal(); + int isimaginary(); + int iscomplex(); + int isscalar(); + int isunsigned(); + int checkBoolean(); + int isAssignable(); + Type *toBasetype(); + MATCH implicitConvTo(Type *to); + MATCH constConv(Type *to); + Expression *defaultInit(Loc loc); + Expression *defaultInitLiteral(Loc loc); + int isZeroInit(Loc loc); +#if IN_DMD + dt_t **toDt(dt_t **pdt); +#endif + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + int hasWild(); + Type *toHeadMutable(); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif + +#if IN_DMD + type *toCtype(); + type *toCParamtype(); +#endif +}; + +struct TypeClass : Type +{ + ClassDeclaration *sym; + + TypeClass(ClassDeclaration *sym); + d_uns64 size(Loc loc); + char *toChars(); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + Dsymbol *toDsymbol(Scope *sc); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); + ClassDeclaration *isClassHandle(); + int isBaseOf(Type *t, int *poffset); + MATCH implicitConvTo(Type *to); + Expression *defaultInit(Loc loc); + int isZeroInit(Loc loc); + MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes); + int isscope(); + int checkBoolean(); + TypeInfoDeclaration *getTypeInfoDeclaration(); + int hasPointers(); + int builtinTypeInfo(); +#if DMDV2 + Type *toHeadMutable(); + MATCH constConv(Type *to); +#if CPP_MANGLE + void toCppMangle(OutBuffer *buf, CppMangleState *cms); +#endif +#endif + +#if IN_DMD + type *toCtype(); + + Symbol *toSymbol(); +#endif +}; + +struct TypeTuple : Type +{ + Parameters *arguments; // types making up the tuple + + TypeTuple(Parameters *arguments); + TypeTuple(Expressions *exps); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + int equals(Object *o); + Type *reliesOnTident(); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); + void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); + Expression *getProperty(Loc loc, Identifier *ident); + TypeInfoDeclaration *getTypeInfoDeclaration(); +}; + +struct TypeSlice : TypeNext +{ + Expression *lwr; + Expression *upr; + + TypeSlice(Type *next, Expression *lwr, Expression *upr); + Type *syntaxCopy(); + Type *semantic(Loc loc, Scope *sc); + void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +}; + +struct TypeNewArray : TypeNext +{ + TypeNewArray(Type *next); + void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); +}; + +/**************************************************************/ + +//enum InOut { None, In, Out, InOut, Lazy }; + +struct Parameter : Object +{ + //enum InOut inout; + StorageClass storageClass; + Type *type; + Identifier *ident; + Expression *defaultArg; + + Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); + Parameter *syntaxCopy(); + Type *isLazyArray(); + void toDecoBuffer(OutBuffer *buf, bool mangle); + static Parameters *arraySyntaxCopy(Parameters *args); + static char *argsTypesToChars(Parameters *args, int varargs); + static void argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs); + static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs); + static void argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle); + static int isTPL(Parameters *arguments); + static size_t dim(Parameters *arguments); + static Parameter *getNth(Parameters *arguments, size_t nth, size_t *pn = NULL); +}; + +extern int PTRSIZE; +extern int REALSIZE; +extern int REALPAD; +extern int Tsize_t; +extern int Tptrdiff_t; + +int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); +void MODtoBuffer(OutBuffer *buf, unsigned char mod); +int MODimplicitConv(unsigned char modfrom, unsigned char modto); +int MODmerge(unsigned char mod1, unsigned char mod2); + +#endif /* DMD_MTYPE_H */ diff --git a/dmd2/objfile.h b/dmd2/objfile.h index 4d47e987..a872f4d0 100644 --- a/dmd2/objfile.h +++ b/dmd2/objfile.h @@ -1,61 +1,61 @@ - - -#ifndef OBJFILE_H -#define OBJFILE_H - -#include "root.h" - -typedef void *SymHandle; -typedef unsigned SegOffset; - -enum ObjFormat -{ - NTCOFF, - ELF -}; - -struct ObjFile : File -{ - ObjFile(FileName *); - ~ObjFile(); - - ObjFile *init(ObjFormat); - - void comment(const char *); // insert comment into object file - void modulename(const char *); // set module name - void library(const char *); // add default library - void startaddress(SegHandle seg, SegOffset offset); // set start address - - // Segments - enum SegHandle - { code = 1, - data, bss - }; - - SymHandle defineSym(const char *name, SegHandle seg, SegOffset offset); - SymHandle externSym(const char *name); - - SegOffset write(SegHandle seg, const void *data, unsigned nbytes); - SegOffset writestring(SegHandle seg, char *string); - SegOffset write8(SegHandle seg, unsigned b); - SegOffset write16(SegHandle seg, unsigned w); - SegOffset write32(SegHandle seg, unsigned long v); - SegOffset write64(SegHandle seg, unsigned long long v); - SegOffset fill0(SegHandle seg, unsigned nbytes); - SegOffset align(SegHandle seg, unsigned size); - SegOffset writefixup(SegHandle seg, SymHandle sym, unsigned value, int selfrelative); - - // Non-binding hint as to how big seg will grow - void reserve(SegHandle seg, SegOffset size); - - // Set actual size - void setSize(SegHandle seg, SegOffset size); - - // Get/set offset for subsequent writes - void setOffset(SegHandle seg, SegOffset offset); - SegOffset getOffset(SegHandle seg); - - SegHandle createSeg(const char *name); -}; - -#endif + + +#ifndef OBJFILE_H +#define OBJFILE_H + +#include "root.h" + +typedef void *SymHandle; +typedef unsigned SegOffset; + +enum ObjFormat +{ + NTCOFF, + ELF +}; + +struct ObjFile : File +{ + ObjFile(FileName *); + ~ObjFile(); + + ObjFile *init(ObjFormat); + + void comment(const char *); // insert comment into object file + void modulename(const char *); // set module name + void library(const char *); // add default library + void startaddress(SegHandle seg, SegOffset offset); // set start address + + // Segments + enum SegHandle + { code = 1, + data, bss + }; + + SymHandle defineSym(const char *name, SegHandle seg, SegOffset offset); + SymHandle externSym(const char *name); + + SegOffset write(SegHandle seg, const void *data, unsigned nbytes); + SegOffset writestring(SegHandle seg, char *string); + SegOffset write8(SegHandle seg, unsigned b); + SegOffset write16(SegHandle seg, unsigned w); + SegOffset write32(SegHandle seg, unsigned long v); + SegOffset write64(SegHandle seg, unsigned long long v); + SegOffset fill0(SegHandle seg, unsigned nbytes); + SegOffset align(SegHandle seg, unsigned size); + SegOffset writefixup(SegHandle seg, SymHandle sym, unsigned value, int selfrelative); + + // Non-binding hint as to how big seg will grow + void reserve(SegHandle seg, SegOffset size); + + // Set actual size + void setSize(SegHandle seg, SegOffset size); + + // Get/set offset for subsequent writes + void setOffset(SegHandle seg, SegOffset offset); + SegOffset getOffset(SegHandle seg); + + SegHandle createSeg(const char *name); +}; + +#endif diff --git a/dmd2/opover.c b/dmd2/opover.c index 66b8d2ae..338019c0 100644 --- a/dmd2/opover.c +++ b/dmd2/opover.c @@ -1,789 +1,1444 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include -#if _MSC_VER -#include -#else -#include -#endif - -#ifdef __APPLE__ -#define integer_t dmd_integer_t -#endif - -#include "rmem.h" - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "id.h" -#include "declaration.h" -#include "aggregate.h" -#include "template.h" -#include "scope.h" - -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Arguments *arguments); -static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Arguments *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments); -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); - -/******************************** Expression **************************/ - - -/*********************************** - * Determine if operands of binary op can be reversed - * to fit operator overload. - */ - -int Expression::isCommutative() -{ - return FALSE; // default is no reverse -} - -/*********************************** - * Get Identifier for operator overload. - */ - -Identifier *Expression::opId() -{ - assert(0); - return NULL; -} - -/*********************************** - * Get Identifier for reverse operator overload, - * NULL if not supported for this operator. - */ - -Identifier *Expression::opId_r() -{ - return NULL; -} - -/************************* Operators *****************************/ - -Identifier *UAddExp::opId() { return Id::uadd; } - -Identifier *NegExp::opId() { return Id::neg; } - -Identifier *ComExp::opId() { return Id::com; } - -Identifier *CastExp::opId() { return Id::cast; } - -Identifier *InExp::opId() { return Id::opIn; } -Identifier *InExp::opId_r() { return Id::opIn_r; } - -Identifier *PostExp::opId() { return (op == TOKplusplus) - ? Id::postinc - : Id::postdec; } - -int AddExp::isCommutative() { return TRUE; } -Identifier *AddExp::opId() { return Id::add; } -Identifier *AddExp::opId_r() { return Id::add_r; } - -Identifier *MinExp::opId() { return Id::sub; } -Identifier *MinExp::opId_r() { return Id::sub_r; } - -int MulExp::isCommutative() { return TRUE; } -Identifier *MulExp::opId() { return Id::mul; } -Identifier *MulExp::opId_r() { return Id::mul_r; } - -Identifier *DivExp::opId() { return Id::div; } -Identifier *DivExp::opId_r() { return Id::div_r; } - -Identifier *ModExp::opId() { return Id::mod; } -Identifier *ModExp::opId_r() { return Id::mod_r; } - -Identifier *ShlExp::opId() { return Id::shl; } -Identifier *ShlExp::opId_r() { return Id::shl_r; } - -Identifier *ShrExp::opId() { return Id::shr; } -Identifier *ShrExp::opId_r() { return Id::shr_r; } - -Identifier *UshrExp::opId() { return Id::ushr; } -Identifier *UshrExp::opId_r() { return Id::ushr_r; } - -int AndExp::isCommutative() { return TRUE; } -Identifier *AndExp::opId() { return Id::iand; } -Identifier *AndExp::opId_r() { return Id::iand_r; } - -int OrExp::isCommutative() { return TRUE; } -Identifier *OrExp::opId() { return Id::ior; } -Identifier *OrExp::opId_r() { return Id::ior_r; } - -int XorExp::isCommutative() { return TRUE; } -Identifier *XorExp::opId() { return Id::ixor; } -Identifier *XorExp::opId_r() { return Id::ixor_r; } - -Identifier *CatExp::opId() { return Id::cat; } -Identifier *CatExp::opId_r() { return Id::cat_r; } - -Identifier * AssignExp::opId() { return Id::assign; } -Identifier * AddAssignExp::opId() { return Id::addass; } -Identifier * MinAssignExp::opId() { return Id::subass; } -Identifier * MulAssignExp::opId() { return Id::mulass; } -Identifier * DivAssignExp::opId() { return Id::divass; } -Identifier * ModAssignExp::opId() { return Id::modass; } -Identifier * AndAssignExp::opId() { return Id::andass; } -Identifier * OrAssignExp::opId() { return Id::orass; } -Identifier * XorAssignExp::opId() { return Id::xorass; } -Identifier * ShlAssignExp::opId() { return Id::shlass; } -Identifier * ShrAssignExp::opId() { return Id::shrass; } -Identifier *UshrAssignExp::opId() { return Id::ushrass; } -Identifier * CatAssignExp::opId() { return Id::catass; } - -int EqualExp::isCommutative() { return TRUE; } -Identifier *EqualExp::opId() { return Id::eq; } - -int CmpExp::isCommutative() { return TRUE; } -Identifier *CmpExp::opId() { return Id::cmp; } - -Identifier *ArrayExp::opId() { return Id::index; } -Identifier *PtrExp::opId() { return Id::opStar; } - -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Return NULL if not an operator overload. - */ - -Expression *UnaExp::op_overload(Scope *sc) -{ - //printf("UnaExp::op_overload() (%s)\n", toChars()); - AggregateDeclaration *ad; - Dsymbol *fd; - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - } - else if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - - L1: - fd = search_function(ad, opId()); - if (fd) - { - if (op == TOKarray) - { - /* Rewrite op e1[arguments] as: - * e1.fd(arguments) - */ - Expression *e = new DotIdExp(loc, e1, fd->ident); - ArrayExp *ae = (ArrayExp *)this; - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite +e1 as e1.add() - return build_overload(loc, sc, e1, NULL, fd->ident); - } - } - -#if DMDV2 - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } -#endif - } - return NULL; -} - - -Expression *BinExp::op_overload(Scope *sc) -{ - //printf("BinExp::op_overload() (%s)\n", toChars()); - - AggregateDeclaration *ad; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Identifier *id = opId(); - Identifier *id_r = opId_r(); - - Match m; - Expressions args1; - Expressions args2; - int argsset = 0; - - AggregateDeclaration *ad1; - if (t1->ty == Tclass) - ad1 = ((TypeClass *)t1)->sym; - else if (t1->ty == Tstruct) - ad1 = ((TypeStruct *)t1)->sym; - else - ad1 = NULL; - - AggregateDeclaration *ad2; - if (t2->ty == Tclass) - ad2 = ((TypeClass *)t2)->sym; - else if (t2->ty == Tstruct) - ad2 = ((TypeStruct *)t2)->sym; - else - ad2 = NULL; - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - FuncDeclaration *fd = NULL; - TemplateDeclaration *td = NULL; - if (ad1 && id) - { - s = search_function(ad1, id); - } - if (ad2 && id_r) - { - s_r = search_function(ad2, id_r); - } - - if (s || s_r) - { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. - */ - Expression *e; - FuncDeclaration *lastf; - - args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - argsset = 1; - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - - lastf = m.lastf; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - if (op == TOKplusplus || op == TOKminusminus) - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - e = build_overload(loc, sc, e1, NULL, id); - else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, id); - else - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, id_r); - return e; - } - - if (isCommutative()) - { - s = NULL; - s_r = NULL; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - } - - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - - if (!argsset) - { args1.setDim(1); - args1.data[0] = (void*) e1; - args2.setDim(1); - args2.data[0] = (void*) e2; - } - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s_r) - { - fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args2); - } - } - FuncDeclaration *lastf = m.lastf; - - if (s) - { - fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, NULL, NULL, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - Expression *e; - if (lastf && m.lastf == lastf || - id_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - e = build_overload(loc, sc, e1, e2, id_r); - else - // Rewrite (e1 op e2) as e2.opfunc(e1) - e = build_overload(loc, sc, e2, e1, id); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // These are symmetric - case TOKunord: - case TOKlg: - case TOKleg: - case TOKue: - break; - } - - return e; - } - } - -#if DMDV2 - // Try alias this on first operand - if (ad1 && ad1->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->semantic(sc); - return e; - } - - // Try alias this on second operand - if (ad2 && ad2->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->semantic(sc); - return e; - } -#endif - return NULL; -} - -/*********************************** - * Utility to build a function call out of this reference and argument. - */ - -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Identifier *id) -{ - Expression *e; - - //printf("build_overload(id = '%s')\n", id->toChars()); - //earg->print(); - //earg->type->print(); - e = new DotIdExp(loc, ethis, id); - - if (earg) - e = new CallExp(loc, e, earg); - else - e = new CallExp(loc, e); - - e = e->semantic(sc); - return e; -} - -/*************************************** - * Search for function funcid in aggregate ad. - */ - -Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) -{ - Dsymbol *s; - FuncDeclaration *fd; - TemplateDeclaration *td; - - s = ad->search(0, funcid, 0); - if (s) - { Dsymbol *s2; - - //printf("search_function: s = '%s'\n", s->kind()); - s2 = s->toAlias(); - //printf("search_function: s2 = '%s'\n", s2->kind()); - fd = s2->isFuncDeclaration(); - if (fd && fd->type->ty == Tfunction) - return fd; - - td = s2->isTemplateDeclaration(); - if (td) - return td; - } - return NULL; -} - - -/***************************************** - * Given array of arguments and an aggregate type, - * if any of the argument types are missing, attempt to infer - * them from the aggregate type. - */ - -void inferApplyArgTypes(enum TOK op, Arguments *arguments, Expression *aggr, Module* from) -{ - if (!arguments || !arguments->dim) - return; - - /* Return if no arguments need types. - */ - for (size_t u = 0; 1; u++) - { if (u == arguments->dim) - return; - Argument *arg = (Argument *)arguments->data[u]; - if (!arg->type) - break; - } - - AggregateDeclaration *ad; - - Argument *arg = (Argument *)arguments->data[0]; - Type *taggr = aggr->type; - if (!taggr) - return; - Type *tab = taggr->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = Type::tsize_t; // key type - arg = (Argument *)arguments->data[1]; - } - if (!arg->type && tab->ty != Ttuple) - arg->type = tab->nextOf(); // value type - break; - - case Taarray: - { TypeAArray *taa = (TypeAArray *)tab; - - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = taa->index; // key type - arg = (Argument *)arguments->data[1]; - } - if (!arg->type) - arg->type = taa->next; // value type - break; - } - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: - if (arguments->dim == 1) - { - if (!arg->type) - { - /* Look for a head() or rear() overload - */ - Identifier *id = (op == TOKforeach) ? Id::Fhead : Id::Ftoe; - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - { if (s && s->isTemplateDeclaration()) - break; - goto Lapply; - } - arg->type = fd->type->nextOf(); - } - break; - } - - Lapply: - { /* Look for an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - Dsymbol *s = search_function(ad, - (op == TOKforeach_reverse) ? Id::applyReverse - : Id::apply); - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { inferApplyArgTypesX(from, fd, arguments); - break; - } -#if 0 - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { inferApplyArgTypesZ(td, arguments); - break; - } -#endif - } - break; - } - - case Tdelegate: - { - if (0 && aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - - FuncDeclaration *fd = de->func->isFuncDeclaration(); - if (fd) - inferApplyArgTypesX(from, fd, arguments); - } - else - { - inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); - } - break; - } - - default: - break; // ignore error, caught later - } -} - -/******************************** - * Recursive helper function, - * analogous to func.overloadResolveX(). - */ - -int fp3(void *param, FuncDeclaration *f) -{ - Arguments *arguments = (Arguments *)param; - TypeFunction *tf = (TypeFunction *)f->type; - if (inferApplyArgTypesY(tf, arguments) == 1) - return 0; - if (arguments->dim == 0) - return 1; - return 0; -} - -static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Arguments *arguments) -{ - overloadApply(from, fstart, &fp3, arguments); -} - -/****************************** - * Infer arguments from type of function. - * Returns: - * 0 match for this function - * 1 no match for this function - */ - -static int inferApplyArgTypesY(TypeFunction *tf, Arguments *arguments) -{ size_t nparams; - Argument *p; - - if (Argument::dim(tf->parameters) != 1) - goto Lnomatch; - p = Argument::getNth(tf->parameters, 0); - if (p->type->ty != Tdelegate) - goto Lnomatch; - tf = (TypeFunction *)p->type->nextOf(); - assert(tf->ty == Tfunction); - - /* We now have tf, the type of the delegate. Match it against - * the arguments, filling in missing argument types. - */ - nparams = Argument::dim(tf->parameters); - if (nparams == 0 || tf->varargs) - goto Lnomatch; // not enough parameters - if (arguments->dim != nparams) - goto Lnomatch; // not enough parameters - - for (size_t u = 0; u < nparams; u++) - { - Argument *arg = (Argument *)arguments->data[u]; - Argument *param = Argument::getNth(tf->parameters, u); - if (arg->type) - { if (!arg->type->equals(param->type)) - { - /* Cannot resolve argument types. Indicate an - * error by setting the number of arguments to 0. - */ - arguments->dim = 0; - goto Lmatch; - } - continue; - } - arg->type = param->type; - } - Lmatch: - return 0; - - Lnomatch: - return 1; -} - -/******************************************* - * Infer foreach arg types from a template function opApply which looks like: - * int opApply(alias int func(ref uint))() { ... } - */ - -#if 0 -void inferApplyArgTypesZ(TemplateDeclaration *tstart, Arguments *arguments) -{ - for (TemplateDeclaration *td = tstart; td; td = td->overnext) - { - if (!td->scope) - { - error("forward reference to template %s", td->toChars()); - return; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - return; - } - if (!td->parameters || td->parameters->dim != 1) - continue; - TemplateParameter *tp = (TemplateParameter *)td->parameters->data[0]; - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - if (!tap || !tap->specType || tap->specType->ty != Tfunction) - continue; - TypeFunction *tf = (TypeFunction *)tap->specType; - if (inferApplyArgTypesY(tf, arguments) == 0) // found it - return; - } -} -#endif - -/************************************** - */ - -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) -{ - FuncDeclaration *fd; - - assert(td); - fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include +#include +#if _MSC_VER +#include +#else +#include +#endif + +#ifdef __APPLE__ +#define integer_t dmd_integer_t +#endif + +#include "rmem.h" + +//#include "port.h" +#include "mtype.h" +#include "init.h" +#include "expression.h" +#include "id.h" +#include "declaration.h" +#include "aggregate.h" +#include "template.h" +#include "scope.h" + +static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments); +static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments); +static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments); +static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); + +/******************************** Expression **************************/ + + +/*********************************** + * Determine if operands of binary op can be reversed + * to fit operator overload. + */ + +int Expression::isCommutative() +{ + return FALSE; // default is no reverse +} + +/*********************************** + * Get Identifier for operator overload. + */ + +Identifier *Expression::opId() +{ + assert(0); + return NULL; +} + +/*********************************** + * Get Identifier for reverse operator overload, + * NULL if not supported for this operator. + */ + +Identifier *Expression::opId_r() +{ + return NULL; +} + +/************************* Operators *****************************/ + +Identifier *UAddExp::opId() { return Id::uadd; } + +Identifier *NegExp::opId() { return Id::neg; } + +Identifier *ComExp::opId() { return Id::com; } + +Identifier *CastExp::opId() { return Id::cast; } + +Identifier *InExp::opId() { return Id::opIn; } +Identifier *InExp::opId_r() { return Id::opIn_r; } + +Identifier *PostExp::opId() { return (op == TOKplusplus) + ? Id::postinc + : Id::postdec; } + +int AddExp::isCommutative() { return TRUE; } +Identifier *AddExp::opId() { return Id::add; } +Identifier *AddExp::opId_r() { return Id::add_r; } + +Identifier *MinExp::opId() { return Id::sub; } +Identifier *MinExp::opId_r() { return Id::sub_r; } + +int MulExp::isCommutative() { return TRUE; } +Identifier *MulExp::opId() { return Id::mul; } +Identifier *MulExp::opId_r() { return Id::mul_r; } + +Identifier *DivExp::opId() { return Id::div; } +Identifier *DivExp::opId_r() { return Id::div_r; } + +Identifier *ModExp::opId() { return Id::mod; } +Identifier *ModExp::opId_r() { return Id::mod_r; } + +#if DMDV2 +Identifier *PowExp::opId() { return Id::pow; } +Identifier *PowExp::opId_r() { return Id::pow_r; } +#endif + +Identifier *ShlExp::opId() { return Id::shl; } +Identifier *ShlExp::opId_r() { return Id::shl_r; } + +Identifier *ShrExp::opId() { return Id::shr; } +Identifier *ShrExp::opId_r() { return Id::shr_r; } + +Identifier *UshrExp::opId() { return Id::ushr; } +Identifier *UshrExp::opId_r() { return Id::ushr_r; } + +int AndExp::isCommutative() { return TRUE; } +Identifier *AndExp::opId() { return Id::iand; } +Identifier *AndExp::opId_r() { return Id::iand_r; } + +int OrExp::isCommutative() { return TRUE; } +Identifier *OrExp::opId() { return Id::ior; } +Identifier *OrExp::opId_r() { return Id::ior_r; } + +int XorExp::isCommutative() { return TRUE; } +Identifier *XorExp::opId() { return Id::ixor; } +Identifier *XorExp::opId_r() { return Id::ixor_r; } + +Identifier *CatExp::opId() { return Id::cat; } +Identifier *CatExp::opId_r() { return Id::cat_r; } + +Identifier * AssignExp::opId() { return Id::assign; } +Identifier * AddAssignExp::opId() { return Id::addass; } +Identifier * MinAssignExp::opId() { return Id::subass; } +Identifier * MulAssignExp::opId() { return Id::mulass; } +Identifier * DivAssignExp::opId() { return Id::divass; } +Identifier * ModAssignExp::opId() { return Id::modass; } +Identifier * AndAssignExp::opId() { return Id::andass; } +Identifier * OrAssignExp::opId() { return Id::orass; } +Identifier * XorAssignExp::opId() { return Id::xorass; } +Identifier * ShlAssignExp::opId() { return Id::shlass; } +Identifier * ShrAssignExp::opId() { return Id::shrass; } +Identifier *UshrAssignExp::opId() { return Id::ushrass; } +Identifier * CatAssignExp::opId() { return Id::catass; } +Identifier * PowAssignExp::opId() { return Id::powass; } + +int EqualExp::isCommutative() { return TRUE; } +Identifier *EqualExp::opId() { return Id::eq; } + +int CmpExp::isCommutative() { return TRUE; } +Identifier *CmpExp::opId() { return Id::cmp; } + +Identifier *ArrayExp::opId() { return Id::index; } +Identifier *PtrExp::opId() { return Id::opStar; } + +/************************************ + * If type is a class or struct, return the symbol for it, + * else NULL + */ +AggregateDeclaration *isAggregate(Type *t) +{ + t = t->toBasetype(); + if (t->ty == Tclass) + { + return ((TypeClass *)t)->sym; + } + else if (t->ty == Tstruct) + { + return ((TypeStruct *)t)->sym; + } + return NULL; +} + +/******************************************* + * Helper function to turn operator into template argument list + */ +Objects *opToArg(Scope *sc, enum TOK op) +{ + /* Remove the = from op= + */ + switch (op) + { + case TOKaddass: op = TOKadd; break; + case TOKminass: op = TOKmin; break; + case TOKmulass: op = TOKmul; break; + case TOKdivass: op = TOKdiv; break; + case TOKmodass: op = TOKmod; break; + case TOKandass: op = TOKand; break; + case TOKorass: op = TOKor; break; + case TOKxorass: op = TOKxor; break; + case TOKshlass: op = TOKshl; break; + case TOKshrass: op = TOKshr; break; + case TOKushrass: op = TOKushr; break; + case TOKcatass: op = TOKcat; break; + case TOKpowass: op = TOKpow; break; + } + Expression *e = new StringExp(0, (char *)Token::toChars(op)); + e = e->semantic(sc); + Objects *targsi = new Objects(); + targsi->push(e); + return targsi; +} + +/************************************ + * Operator overload. + * Check for operator overload, if so, replace + * with function call. + * Return NULL if not an operator overload. + */ + +Expression *UnaExp::op_overload(Scope *sc) +{ + //printf("UnaExp::op_overload() (%s)\n", toChars()); + +#if DMDV2 + if (e1->op == TOKarray) + { + ArrayExp *ae = (ArrayExp *)e1; + ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); + + AggregateDeclaration *ad = isAggregate(ae->e1->type); + if (ad) + { + /* Rewrite as: + * a.opIndexUnary!("+")(args); + */ + Dsymbol *fd = search_function(ad, Id::opIndexUnary); + if (fd) + { + Objects *targsi = opToArg(sc, op); + Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); + e = new CallExp(loc, e, ae->arguments); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(a[arguments]) as: + * op(a.aliasthis[arguments]) + */ + Expression *e1 = ae->copy(); + ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + } + else if (e1->op == TOKslice) + { + SliceExp *se = (SliceExp *)e1; + se->e1 = se->e1->semantic(sc); + se->e1 = resolveProperties(sc, se->e1); + + AggregateDeclaration *ad = isAggregate(se->e1->type); + if (ad) + { + /* Rewrite as: + * a.opSliceUnary!("+")(lwr, upr); + */ + Dsymbol *fd = search_function(ad, Id::opSliceUnary); + if (fd) + { + Expressions *a = new Expressions(); + if (se->lwr) + { a->push(se->lwr); + a->push(se->upr); + } + + Objects *targsi = opToArg(sc, op); + Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(a[lwr..upr]) as: + * op(a.aliasthis[lwr..upr]) + */ + Expression *e1 = se->copy(); + ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + } +#endif + + e1 = e1->semantic(sc); + e1 = resolveProperties(sc, e1); + + AggregateDeclaration *ad = isAggregate(e1->type); + if (ad) + { + Dsymbol *fd = NULL; +#if 1 // Old way, kept for compatibility with D1 + if (op != TOKpreplusplus && op != TOKpreminusminus) + { fd = search_function(ad, opId()); + if (fd) + { + if (op == TOKarray) + { + /* Rewrite op e1[arguments] as: + * e1.fd(arguments) + */ + Expression *e = new DotIdExp(loc, e1, fd->ident); + ArrayExp *ae = (ArrayExp *)this; + e = new CallExp(loc, e, ae->arguments); + e = e->semantic(sc); + return e; + } + else + { + // Rewrite +e1 as e1.add() + return build_overload(loc, sc, e1, NULL, fd->ident); + } + } + } +#endif + +#if DMDV2 + /* Rewrite as: + * e1.opUnary!("+")(); + */ + fd = search_function(ad, Id::opUnary); + if (fd) + { + Objects *targsi = opToArg(sc, op); + Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi); + e = new CallExp(loc, e); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } +#endif + } + return NULL; +} + +Expression *ArrayExp::op_overload(Scope *sc) +{ + //printf("ArrayExp::op_overload() (%s)\n", toChars()); + AggregateDeclaration *ad = isAggregate(e1->type); + if (ad) + { + Dsymbol *fd = search_function(ad, opId()); + if (fd) + { + /* Rewrite op e1[arguments] as: + * e1.opIndex(arguments) + */ + Expression *e = new DotIdExp(loc, e1, fd->ident); + e = new CallExp(loc, e, arguments); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + return NULL; +} + +/*********************************************** + * This is mostly the same as UnaryExp::op_overload(), but has + * a different rewrite. + */ +Expression *CastExp::op_overload(Scope *sc) +{ + //printf("CastExp::op_overload() (%s)\n", toChars()); + AggregateDeclaration *ad = isAggregate(e1->type); + if (ad) + { + Dsymbol *fd = NULL; + /* Rewrite as: + * e1.opCast!(T)(); + */ + fd = search_function(ad, Id::cast); + if (fd) + { +#if 1 // Backwards compatibility with D1 if opCast is a function, not a template + if (fd->isFuncDeclaration()) + { // Rewrite as: e1.opCast() + return build_overload(loc, sc, e1, NULL, fd->ident); + } +#endif + Objects *targsi = new Objects(); + targsi->push(to); + Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi); + e = new CallExp(loc, e); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite op(e1) as: + * op(e1.aliasthis) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + return NULL; +} + +Expression *BinExp::op_overload(Scope *sc) +{ + //printf("BinExp::op_overload() (%s)\n", toChars()); + + Identifier *id = opId(); + Identifier *id_r = opId_r(); + + Expressions args1; + Expressions args2; + int argsset = 0; + + AggregateDeclaration *ad1 = isAggregate(e1->type); + AggregateDeclaration *ad2 = isAggregate(e2->type); + + Dsymbol *s = NULL; + Dsymbol *s_r = NULL; + +#if 1 // the old D1 scheme + if (ad1 && id) + { + s = search_function(ad1, id); + } + if (ad2 && id_r) + { + s_r = search_function(ad2, id_r); + } +#endif + + Objects *targsi = NULL; +#if DMDV2 + if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign) + { /* Try the new D2 scheme, opBinary and opBinaryRight + */ + if (ad1) + s = search_function(ad1, Id::opBinary); + if (ad2) + s_r = search_function(ad2, Id::opBinaryRight); + + // Set targsi, the template argument list, which will be the operator string + if (s || s_r) + { + id = Id::opBinary; + id_r = Id::opBinaryRight; + targsi = opToArg(sc, op); + } + } +#endif + + if (s || s_r) + { + /* Try: + * a.opfunc(b) + * b.opfunc_r(a) + * and see which is better. + */ + + args1.setDim(1); + args1.data[0] = (void*) e1; + args2.setDim(1); + args2.data[0] = (void*) e2; + argsset = 1; + + Match m; + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args2, sc->module); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args2); + } + } + + FuncDeclaration *lastf = m.lastf; + + if (s_r) + { + FuncDeclaration *fd = s_r->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args1, sc->module); + } + else + { TemplateDeclaration *td = s_r->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + if (targsi) + goto L1; + } + + Expression *e; + if (op == TOKplusplus || op == TOKminusminus) + // Kludge because operator overloading regards e++ and e-- + // as unary, but it's implemented as a binary. + // Rewrite (e1 ++ e2) as e1.postinc() + // Rewrite (e1 -- e2) as e1.postdec() + e = build_overload(loc, sc, e1, NULL, id); + else if (lastf && m.lastf == lastf || m.last == MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc(e2) + e = build_overload(loc, sc, e1, e2, id, targsi); + else + // Rewrite (e1 op e2) as e2.opfunc_r(e1) + e = build_overload(loc, sc, e2, e1, id_r, targsi); + return e; + } + +L1: +#if 1 // Retained for D1 compatibility + if (isCommutative() && !targsi) + { + s = NULL; + s_r = NULL; + if (ad1 && id_r) + { + s_r = search_function(ad1, id_r); + } + if (ad2 && id) + { + s = search_function(ad2, id); + } + + if (s || s_r) + { + /* Try: + * a.opfunc_r(b) + * b.opfunc(a) + * and see which is better. + */ + + if (!argsset) + { args1.setDim(1); + args1.data[0] = (void*) e1; + args2.setDim(1); + args2.data[0] = (void*) e2; + } + + Match m; + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (s_r) + { + FuncDeclaration *fd = s_r->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args2, sc->module); + } + else + { TemplateDeclaration *td = s_r->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args2); + } + } + FuncDeclaration *lastf = m.lastf; + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args1, sc->module); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args1); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + } + + Expression *e; + if (lastf && m.lastf == lastf || + id_r && m.last == MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc_r(e2) + e = build_overload(loc, sc, e1, e2, id_r, targsi); + else + // Rewrite (e1 op e2) as e2.opfunc(e1) + e = build_overload(loc, sc, e2, e1, id, targsi); + + // When reversing operands of comparison operators, + // need to reverse the sense of the op + switch (op) + { + case TOKlt: op = TOKgt; break; + case TOKgt: op = TOKlt; break; + case TOKle: op = TOKge; break; + case TOKge: op = TOKle; break; + + // Floating point compares + case TOKule: op = TOKuge; break; + case TOKul: op = TOKug; break; + case TOKuge: op = TOKule; break; + case TOKug: op = TOKul; break; + + // These are symmetric + case TOKunord: + case TOKlg: + case TOKleg: + case TOKue: + break; + } + + return e; + } + } +#endif + +#if DMDV2 + // Try alias this on first operand + if (ad1 && ad1->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1.aliasthis op e2) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + + // Try alias this on second operand + if (ad2 && ad2->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1 op e2.aliasthis) + */ + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->semantic(sc); + return e; + } +#endif + return NULL; +} + +/****************************************** + * Common code for overloading of EqualExp and CmpExp + */ +Expression *BinExp::compare_overload(Scope *sc, Identifier *id) +{ + //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars()); + + AggregateDeclaration *ad1 = isAggregate(e1->type); + AggregateDeclaration *ad2 = isAggregate(e2->type); + + Dsymbol *s = NULL; + Dsymbol *s_r = NULL; + + if (ad1) + { + s = search_function(ad1, id); + } + if (ad2) + { + s_r = search_function(ad2, id); + if (s == s_r) + s_r = NULL; + } + + Objects *targsi = NULL; + + if (s || s_r) + { + /* Try: + * a.opEquals(b) + * b.opEquals(a) + * and see which is better. + */ + + Expressions args1; + Expressions args2; + + args1.setDim(1); + args1.data[0] = (void*) e1; + args2.setDim(1); + args2.data[0] = (void*) e2; + + Match m; + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (0 && s && s_r) + { + printf("s : %s\n", s->toPrettyChars()); + printf("s_r: %s\n", s_r->toPrettyChars()); + } + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args2, sc->module); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args2); + } + } + + FuncDeclaration *lastf = m.lastf; + int count = m.count; + + if (s_r) + { + FuncDeclaration *fd = s_r->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args1, sc->module); + } + else + { TemplateDeclaration *td = s_r->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args1); + } + } + + if (m.count > 1) + { + /* The following if says "not ambiguous" if there's one match + * from s and one from s_r, in which case we pick s. + * This doesn't follow the spec, but is a workaround for the case + * where opEquals was generated from templates and we cannot figure + * out if both s and s_r came from the same declaration or not. + * The test case is: + * import std.typecons; + * void main() { + * assert(tuple("has a", 2u) == tuple("has a", 1)); + * } + */ + if (!(m.lastf == lastf && m.count == 2 && count == 1)) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + } + + Expression *e; + if (lastf && m.lastf == lastf || m.last == MATCHnomatch) + // Rewrite (e1 op e2) as e1.opfunc(e2) + e = build_overload(loc, sc, e1, e2, id, targsi); + else + { // Rewrite (e1 op e2) as e2.opfunc_r(e1) + e = build_overload(loc, sc, e2, e1, id, targsi); + + // When reversing operands of comparison operators, + // need to reverse the sense of the op + switch (op) + { + case TOKlt: op = TOKgt; break; + case TOKgt: op = TOKlt; break; + case TOKle: op = TOKge; break; + case TOKge: op = TOKle; break; + + // Floating point compares + case TOKule: op = TOKuge; break; + case TOKul: op = TOKug; break; + case TOKuge: op = TOKule; break; + case TOKug: op = TOKul; break; + + // The rest are symmetric + default: + break; + } + } + + return e; + } + + // Try alias this on first operand + if (ad1 && ad1->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1.aliasthis op e2) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + + // Try alias this on second operand + if (ad2 && ad2->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1 op e2.aliasthis) + */ + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->semantic(sc); + return e; + } + + return NULL; +} + +Expression *EqualExp::op_overload(Scope *sc) +{ + //printf("EqualExp::op_overload() (%s)\n", toChars()); + + Type *t1 = e1->type->toBasetype(); + Type *t2 = e2->type->toBasetype(); + if (t1->ty == Tclass && t2->ty == Tclass) + { + /* Rewrite as: + * .object.opEquals(e1, e2) + */ + Expression *e = new IdentifierExp(loc, Id::empty); + e = new DotIdExp(loc, e, Id::object); + e = new DotIdExp(loc, e, Id::eq); + e = new CallExp(loc, e, e1, e2); + e = e->semantic(sc); + return e; + } + + return compare_overload(sc, Id::eq); +} + +Expression *CmpExp::op_overload(Scope *sc) +{ + //printf("CmpExp::op_overload() (%s)\n", toChars()); + + return compare_overload(sc, Id::cmp); +} + +/********************************* + * Operator overloading for op= + */ +Expression *BinAssignExp::op_overload(Scope *sc) +{ + //printf("BinAssignExp::op_overload() (%s)\n", toChars()); + +#if DMDV2 + if (e1->op == TOKarray) + { + ArrayExp *ae = (ArrayExp *)e1; + ae->e1 = ae->e1->semantic(sc); + ae->e1 = resolveProperties(sc, ae->e1); + + AggregateDeclaration *ad = isAggregate(ae->e1->type); + if (ad) + { + /* Rewrite a[args]+=e2 as: + * a.opIndexOpAssign!("+")(e2, args); + */ + Dsymbol *fd = search_function(ad, Id::opIndexOpAssign); + if (fd) + { + Expressions *a = new Expressions(); + a->push(e2); + for (int i = 0; i < ae->arguments->dim; i++) + a->push(ae->arguments->data[i]); + + Objects *targsi = opToArg(sc, op); + Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite a[arguments] op= e2 as: + * a.aliasthis[arguments] op= e2 + */ + Expression *e1 = ae->copy(); + ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + } + else if (e1->op == TOKslice) + { + SliceExp *se = (SliceExp *)e1; + se->e1 = se->e1->semantic(sc); + se->e1 = resolveProperties(sc, se->e1); + + AggregateDeclaration *ad = isAggregate(se->e1->type); + if (ad) + { + /* Rewrite a[lwr..upr]+=e2 as: + * a.opSliceOpAssign!("+")(e2, lwr, upr); + */ + Dsymbol *fd = search_function(ad, Id::opSliceOpAssign); + if (fd) + { + Expressions *a = new Expressions(); + a->push(e2); + if (se->lwr) + { a->push(se->lwr); + a->push(se->upr); + } + + Objects *targsi = opToArg(sc, op); + Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi); + e = new CallExp(loc, e, a); + e = e->semantic(sc); + return e; + } + + // Didn't find it. Forward to aliasthis + if (ad->aliasthis) + { + /* Rewrite a[lwr..upr] op= e2 as: + * a.aliasthis[lwr..upr] op= e2 + */ + Expression *e1 = se->copy(); + ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); + Expression *e = copy(); + ((UnaExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + } + } +#endif + + BinExp::semantic(sc); + e2 = resolveProperties(sc, e2); + + Identifier *id = opId(); + + Expressions args2; + + AggregateDeclaration *ad1 = isAggregate(e1->type); + + Dsymbol *s = NULL; + +#if 1 // the old D1 scheme + if (ad1 && id) + { + s = search_function(ad1, id); + } +#endif + + Objects *targsi = NULL; +#if DMDV2 + if (!s) + { /* Try the new D2 scheme, opOpAssign + */ + if (ad1) + s = search_function(ad1, Id::opOpAssign); + + // Set targsi, the template argument list, which will be the operator string + if (s) + { + id = Id::opOpAssign; + targsi = opToArg(sc, op); + } + } +#endif + + if (s) + { + /* Try: + * a.opOpAssign(b) + */ + + args2.setDim(1); + args2.data[0] = (void*) e2; + + Match m; + memset(&m, 0, sizeof(m)); + m.last = MATCHnomatch; + + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { + overloadResolveX(&m, fd, NULL, &args2, sc->module); + } + else + { TemplateDeclaration *td = s->isTemplateDeclaration(); + templateResolve(&m, td, sc, loc, targsi, NULL, &args2); + } + } + + if (m.count > 1) + { + // Error, ambiguous + error("overloads %s and %s both match argument list for %s", + m.lastf->type->toChars(), + m.nextf->type->toChars(), + m.lastf->toChars()); + } + else if (m.last == MATCHnomatch) + { + m.lastf = m.anyf; + if (targsi) + goto L1; + } + + Expression *e; + // Rewrite (e1 op e2) as e1.opOpAssign(e2) + e = build_overload(loc, sc, e1, e2, id, targsi); + return e; + } + +L1: + +#if DMDV2 + // Try alias this on first operand + if (ad1 && ad1->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1.aliasthis op e2) + */ + Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e1 = e1; + e = e->semantic(sc); + return e; + } + + // Try alias this on second operand + AggregateDeclaration *ad2 = isAggregate(e2->type); + if (ad2 && ad2->aliasthis) + { + /* Rewrite (e1 op e2) as: + * (e1 op e2.aliasthis) + */ + Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); + Expression *e = copy(); + ((BinExp *)e)->e2 = e2; + e = e->semantic(sc); + return e; + } +#endif + return NULL; +} + +/*********************************** + * Utility to build a function call out of this reference and argument. + */ + +Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, + Identifier *id, Objects *targsi) +{ + Expression *e; + + //printf("build_overload(id = '%s')\n", id->toChars()); + //earg->print(); + //earg->type->print(); + if (targsi) + e = new DotTemplateInstanceExp(loc, ethis, id, targsi); + else + e = new DotIdExp(loc, ethis, id); + + if (earg) + e = new CallExp(loc, e, earg); + else + e = new CallExp(loc, e); + + e = e->semantic(sc); + return e; +} + +/*************************************** + * Search for function funcid in aggregate ad. + */ + +Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) +{ + Dsymbol *s; + FuncDeclaration *fd; + TemplateDeclaration *td; + + s = ad->search(0, funcid, 0); + if (s) + { Dsymbol *s2; + + //printf("search_function: s = '%s'\n", s->kind()); + s2 = s->toAlias(); + //printf("search_function: s2 = '%s'\n", s2->kind()); + fd = s2->isFuncDeclaration(); + if (fd && fd->type->ty == Tfunction) + return fd; + + td = s2->isTemplateDeclaration(); + if (td) + return td; + } + return NULL; +} + + +/***************************************** + * Given array of arguments and an aggregate type, + * if any of the argument types are missing, attempt to infer + * them from the aggregate type. + */ + +void inferApplyArgTypes(enum TOK op, Parameters *arguments, Expression *aggr, Module* from) +{ + if (!arguments || !arguments->dim) + return; + + /* Return if no arguments need types. + */ + for (size_t u = 0; 1; u++) + { if (u == arguments->dim) + return; + Parameter *arg = (Parameter *)arguments->data[u]; + if (!arg->type) + break; + } + + Dsymbol *s; + AggregateDeclaration *ad; + + Parameter *arg = (Parameter *)arguments->data[0]; + Type *taggr = aggr->type; + if (!taggr) + return; + Type *tab = taggr->toBasetype(); + switch (tab->ty) + { + case Tarray: + case Tsarray: + case Ttuple: + if (arguments->dim == 2) + { + if (!arg->type) + arg->type = Type::tsize_t; // key type + arg = (Parameter *)arguments->data[1]; + } + if (!arg->type && tab->ty != Ttuple) + arg->type = tab->nextOf(); // value type + break; + + case Taarray: + { TypeAArray *taa = (TypeAArray *)tab; + + if (arguments->dim == 2) + { + if (!arg->type) + arg->type = taa->index; // key type + arg = (Parameter *)arguments->data[1]; + } + if (!arg->type) + arg->type = taa->next; // value type + break; + } + + case Tclass: + ad = ((TypeClass *)tab)->sym; + goto Laggr; + + case Tstruct: + ad = ((TypeStruct *)tab)->sym; + goto Laggr; + + Laggr: + s = search_function(ad, + (op == TOKforeach_reverse) ? Id::applyReverse + : Id::apply); + if (s) + goto Lapply; // prefer opApply + + if (arguments->dim == 1) + { + if (!arg->type) + { + /* Look for a head() or rear() overload + */ + Identifier *id = (op == TOKforeach) ? Id::Fhead : Id::Ftoe; + Dsymbol *s = search_function(ad, id); + FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; + if (!fd) + { if (s && s->isTemplateDeclaration()) + break; + goto Lapply; + } + arg->type = fd->type->nextOf(); + } + break; + } + + Lapply: + { /* Look for an + * int opApply(int delegate(ref Type [, ...]) dg); + * overload + */ + if (s) + { + FuncDeclaration *fd = s->isFuncDeclaration(); + if (fd) + { inferApplyArgTypesX(from, fd, arguments); + break; + } +#if 0 + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td) + { inferApplyArgTypesZ(td, arguments); + break; + } +#endif + } + break; + } + + case Tdelegate: + { + if (0 && aggr->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)aggr; + + FuncDeclaration *fd = de->func->isFuncDeclaration(); + if (fd) + inferApplyArgTypesX(from, fd, arguments); + } + else + { + inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments); + } + break; + } + + default: + break; // ignore error, caught later + } +} + +/******************************** + * Recursive helper function, + * analogous to func.overloadResolveX(). + */ + +int fp3(void *param, FuncDeclaration *f) +{ + Parameters *arguments = (Parameters *)param; + TypeFunction *tf = (TypeFunction *)f->type; + if (inferApplyArgTypesY(tf, arguments) == 1) + return 0; + if (arguments->dim == 0) + return 1; + return 0; +} + +static void inferApplyArgTypesX(Module* from, FuncDeclaration *fstart, Parameters *arguments) +{ + overloadApply(from, fstart, &fp3, arguments); +} + +/****************************** + * Infer arguments from type of function. + * Returns: + * 0 match for this function + * 1 no match for this function + */ + +static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments) +{ size_t nparams; + Parameter *p; + + if (Parameter::dim(tf->parameters) != 1) + goto Lnomatch; + p = Parameter::getNth(tf->parameters, 0); + if (p->type->ty != Tdelegate) + goto Lnomatch; + tf = (TypeFunction *)p->type->nextOf(); + assert(tf->ty == Tfunction); + + /* We now have tf, the type of the delegate. Match it against + * the arguments, filling in missing argument types. + */ + nparams = Parameter::dim(tf->parameters); + if (nparams == 0 || tf->varargs) + goto Lnomatch; // not enough parameters + if (arguments->dim != nparams) + goto Lnomatch; // not enough parameters + + for (size_t u = 0; u < nparams; u++) + { + Parameter *arg = (Parameter *)arguments->data[u]; + Parameter *param = Parameter::getNth(tf->parameters, u); + if (arg->type) + { if (!arg->type->equals(param->type)) + { + /* Cannot resolve argument types. Indicate an + * error by setting the number of arguments to 0. + */ + arguments->dim = 0; + goto Lmatch; + } + continue; + } + arg->type = param->type; + } + Lmatch: + return 0; + + Lnomatch: + return 1; +} + +/******************************************* + * Infer foreach arg types from a template function opApply which looks like: + * int opApply(alias int func(ref uint))() { ... } + */ + +#if 0 +void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) +{ + for (TemplateDeclaration *td = tstart; td; td = td->overnext) + { + if (!td->scope) + { + error("forward reference to template %s", td->toChars()); + return; + } + if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + { + error("is not a function template"); + return; + } + if (!td->parameters || td->parameters->dim != 1) + continue; + TemplateParameter *tp = (TemplateParameter *)td->parameters->data[0]; + TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); + if (!tap || !tap->specType || tap->specType->ty != Tfunction) + continue; + TypeFunction *tf = (TypeFunction *)tap->specType; + if (inferApplyArgTypesY(tf, arguments) == 0) // found it + return; + } +} +#endif + +/************************************** + */ + +static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) +{ + FuncDeclaration *fd; + + assert(td); + fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments, 1); + if (!fd) + return; + m->anyf = fd; + if (m->last >= MATCHexact) + { + m->nextf = fd; + m->count++; + } + else + { + m->last = MATCHexact; + m->lastf = fd; + m->count = 1; + } +} + diff --git a/dmd2/optimize.c b/dmd2/optimize.c index 2581b5ff..c38fc705 100644 --- a/dmd2/optimize.c +++ b/dmd2/optimize.c @@ -1,1000 +1,1039 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "lexer.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "aggregate.h" -#include "init.h" - - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - - -/************************************* - * If variable has a const initializer, - * return that initializer. - */ - -Expression *expandVar(int result, VarDeclaration *v) -{ - //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null"); - - Expression *e = NULL; - if (!v) - return e; - - if (v->isConst() || v->isInvariant() || v->storage_class & STCmanifest) - { - if (!v->type) - { - //error("ICE"); - return e; - } - - Type *tb = v->type->toBasetype(); - if (result & WANTinterpret || - v->storage_class & STCmanifest || - (tb->ty != Tsarray && tb->ty != Tstruct) - ) - { - if (v->init) - { - if (v->inuse) - { if (v->storage_class & STCmanifest) - v->error("recursive initialization of constant"); - goto L1; - } - Expression *ei = v->init->toExpression(); - if (!ei) - goto L1; - if (ei->op == TOKconstruct || ei->op == TOKblit) - { AssignExp *ae = (AssignExp *)ei; - ei = ae->e2; - if (ei->isConst() != 1 && ei->op != TOKstring) - goto L1; - if (ei->type != v->type) - goto L1; - } - if (v->scope) - { - v->inuse++; - e = ei->syntaxCopy(); - e = e->semantic(v->scope); - e = e->implicitCastTo(v->scope, v->type); - // enabling this line causes test22 in test suite to fail - //ei->type = e->type; - v->scope = NULL; - v->inuse--; - } - else if (!ei->type) - { - goto L1; - } - else - // Should remove the copy() operation by - // making all mods to expressions copy-on-write - e = ei->copy(); - } - else - { -#if 1 - goto L1; -#else - // BUG: what if const is initialized in constructor? - e = v->type->defaultInit(); - e->loc = e1->loc; -#endif - } - if (e->type != v->type) - { - e = e->castTo(NULL, v->type); - } - v->inuse++; - e = e->optimize(result); - v->inuse--; - } - } -L1: - //if (e) printf("\te = %s, e->type = %s\n", e->toChars(), e->type->toChars()); - return e; -} - - -Expression *fromConstInitializer(int result, Expression *e1) -{ - //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); - //static int xx; if (xx++ == 10) assert(0); - Expression *e = e1; - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - e = expandVar(result, v); - if (e) - { if (e->type != e1->type) - { // Type 'paint' operation - e = e->copy(); - e->type = e1->type; - } - } - else - e = e1; - } - return e; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - return fromConstInitializer(result, this); -} - -Expression *TupleExp::optimize(int result) -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (Expression *)exps->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->data[i] = (void *)e; - } - return this; -} - -Expression *ArrayLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *AssocArrayLiteralExp::optimize(int result) -{ - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = (Expression *)keys->data[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - keys->data[i] = (void *)e; - - e = (Expression *)values->data[i]; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - values->data[i] = (void *)e; - } - return this; -} - -Expression *StructLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (Expression *)elements->data[i]; - if (!e) - continue; - e = e->optimize(WANTvalue | (result & WANTinterpret)); - elements->data[i] = (void *)e; - } - } - return this; -} - -Expression *TypeExp::optimize(int result) -{ - return this; -} - -Expression *UnaExp::optimize(int result) -{ - e1 = e1->optimize(result); - return this; -} - -Expression *NegExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Neg(type, e1); - } - else - e = this; - return e; -} - -Expression *ComExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Com(type, e1); - } - else - e = this; - return e; -} - -Expression *NotExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Not(type, e1); - } - else - e = this; - return e; -} - -Expression *BoolExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - if (e1->isConst() == 1) - { - e = Bool(type, e1); - } - else - e = this; - return e; -} - -Expression *AddrExp::optimize(int result) -{ Expression *e; - - //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); - - /* Rewrite &(a,b) as (a,&b) - */ - if (e1->op == TOKcomma) - { CommaExp *ce = (CommaExp *)e1; - AddrExp *ae = new AddrExp(loc, ce->e2); - ae->type = type; - e = new CommaExp(ce->loc, ce->e1, ae); - e->type = type; - return e->optimize(result); - } - - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (ve->var->storage_class & STCmanifest) - e1 = e1->optimize(result); - } - else - e1 = e1->optimize(result); - - // Convert &*ex to ex - if (e1->op == TOKstar) - { Expression *ex; - - ex = ((PtrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } -#if !IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); - se->type = type; - return se; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - dinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); - e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); - e->type = type; - return e; - } - } - } -#endif - return this; -} - -Expression *PtrExp::optimize(int result) -{ - //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - // Convert *&ex to ex - if (e1->op == TOKaddress) - { Expression *e; - Expression *ex; - - ex = ((AddrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { - Expression *e; - e = Ptr(type, e1); - if (e != EXP_CANT_INTERPRET) - return e; - } - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - VarDeclaration *v = se->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - e = sle->getField(type, se->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - return this; -} - -Expression *DotVarExp::optimize(int result) -{ - //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - } - else if (e1->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e1; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - Expression *e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - - return this; -} - -Expression *NewExp::optimize(int result) -{ - if (thisexp) - thisexp = thisexp->optimize(WANTvalue); - - // Optimize parameters - if (newargs) - { - for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = (Expression *)newargs->data[i]; - - e = e->optimize(WANTvalue); - newargs->data[i] = (void *)e; - } - } - - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - e = e->optimize(WANTvalue); - arguments->data[i] = (void *)e; - } - } - return this; -} - -Expression *CallExp::optimize(int result) -{ - //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e = this; - - // Optimize parameters - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = (Expression *)arguments->data[i]; - - e = e->optimize(WANTvalue); - arguments->data[i] = (void *)e; - } - } - - e1 = e1->optimize(result); - if (e1->op == TOKvar) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { - enum BUILTIN b = fd->isBuiltin(); - if (b) - { - e = eval_builtin(b, arguments); - if (!e) // failed - e = this; // evaluate at runtime - } - else if (result & WANTinterpret) - { - Expression *eresult = fd->interpret(NULL, arguments); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - return e; -} - - -Expression *CastExp::optimize(int result) -{ - //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); - //printf("from %s to %s\n", type->toChars(), to->toChars()); - //printf("from %s\n", type->toChars()); - //printf("e1->type %s\n", e1->type->toChars()); - //printf("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; -#define X 0 - - Expression *e1old = e1; - e1 = e1->optimize(result); - e1 = fromConstInitializer(result, e1); - - if (e1 == e1old && - e1->op == TOKarrayliteral && - type->toBasetype()->ty == Tpointer && - e1->type->toBasetype()->ty != Tsarray) - { - // Casting this will result in the same expression, and - // infinite loop because of Expression::implicitCastTo() - return this; // no change - } - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - e1->type->nextOf()->size() == type->nextOf()->size() - ) - { - Expression *e = e1->castTo(NULL, type); - if (X) printf(" returning1 %s\n", e->toChars()); - return e; - } - - if (e1->op == TOKstructliteral && - e1->type->implicitConvTo(type) >= MATCHconst) - { - e1->type = type; - if (X) printf(" returning2 %s\n", e1->toChars()); - return e1; - } - - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) - return e1->castTo(NULL, to); - if (e1->op == TOKnull && - (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray)) - { - e1->type = type; - if (X) printf(" returning3 %s\n", e1->toChars()); - return e1; - } - - if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom; - ClassDeclaration *cdto; - int offset; - - cdfrom = e1->type->isClassHandle(); - cdto = type->isClassHandle(); - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - e1->type = type; - if (X) printf(" returning4 %s\n", e1->toChars()); - return e1; - } - } - - // We can convert 'head const' to mutable - if (to->constOf()->equals(e1->type->constOf())) -// if (to->constConv(e1->type) >= MATCHconst) - { - e1->type = type; - if (X) printf(" returning5 %s\n", e1->toChars()); - return e1; - } - - Expression *e; - - if (e1->isConst()) - { - if (e1->op == TOKsymoff) - { - if (type->size() == e1->type->size() && - type->toBasetype()->ty != Tsarray) - { - e1->type = type; - return e1; - } - return this; - } - if (to->toBasetype()->ty == Tvoid) - e = this; - else - e = Cast(type, to, e1); - } - else - e = this; - if (X) printf(" returning6 %s\n", e->toChars()); - return e; -#undef X -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - dinteger_t i2 = e2->toInteger(); - d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { error("shift assign by %jd is outside the range 0..%zu", i2, sz); - e2 = new IntegerExp(0); - } - } - } - return this; -} - -Expression *AddExp::optimize(int result) -{ Expression *e; - - //printf("AddExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e1->op == TOKsymoff && e2->op == TOKsymoff) - return this; - e = Add(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MinExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e2->op == TOKsymoff) - return this; - e = Min(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MulExp::optimize(int result) -{ Expression *e; - - //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mul(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *DivExp::optimize(int result) -{ Expression *e; - - //printf("DivExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Div(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *ModExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mod(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) -{ Expression *ex = e; - - e->e1 = e->e1->optimize(result); - e->e2 = e->e2->optimize(result); - if (e->e2->isConst() == 1) - { - dinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { e->error("shift by %jd is outside the range 0..%zu", i2, sz); - e->e2 = new IntegerExp(0); - } - if (e->e1->isConst() == 1) - ex = (*shift)(e->type, e->e1, e->e2); - } - return ex; -} - -Expression *ShlExp::optimize(int result) -{ - //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shl); -} - -Expression *ShrExp::optimize(int result) -{ - //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Shr); -} - -Expression *UshrExp::optimize(int result) -{ - //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); - return shift_optimize(result, this, Ushr); -} - -Expression *AndExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = And(type, e1, e2); - else - e = this; - return e; -} - -Expression *OrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Or(type, e1, e2); - else - e = this; - return e; -} - -Expression *XorExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - e = Xor(type, e1, e2); - else - e = this; - return e; -} - -Expression *CommaExp::optimize(int result) -{ Expression *e; - - //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result & WANTinterpret); - e2 = e2->optimize(result); - if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) - { - e = e2; - if (e) - e->type = type; - } - else - e = this; - //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); - return e; -} - -Expression *ArrayLengthExp::optimize(int result) -{ Expression *e; - - //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - return e; -} - -Expression *EqualExp::optimize(int result) -{ Expression *e; - - //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - Expression *e1 = fromConstInitializer(result, this->e1); - Expression *e2 = fromConstInitializer(result, this->e2); - - e = Equal(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *IdentityExp::optimize(int result) -{ Expression *e; - - //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - if ((this->e1->isConst() && this->e2->isConst()) || - (this->e1->op == TOKnull && this->e2->op == TOKnull)) - { - e = Identity(op, type, this->e1, this->e2); - } - return e; -} - -Expression *IndexExp::optimize(int result) -{ Expression *e; - - //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); - e1 = fromConstInitializer(result, e1); - if (this->e1->op == TOKvar) - { VarExp *ve = (VarExp *)this->e1; - if (ve->var->storage_class & STCmanifest) - { /* We generally don't want to have more than one copy of an - * array literal, but if it's an enum we have to because the - * enum isn't stored elsewhere. See Bugzilla 2559 - */ - this->e1 = e1; - } - } - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = Index(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *SliceExp::optimize(int result) -{ Expression *e; - - //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); - e = this; - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - if (!lwr) - { if (e1->op == TOKstring) - { // Convert slice of string literal into dynamic array - Type *t = e1->type->toBasetype(); - if (t->nextOf()) - e = e1->castTo(NULL, t->nextOf()->arrayOf()); - } - return e; - } - e1 = fromConstInitializer(result, e1); - lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); - upr = upr->optimize(WANTvalue | (result & WANTinterpret)); - e = Slice(type, e1, lwr, upr); - if (e == EXP_CANT_INTERPRET) - e = this; - //printf("-SliceExp::optimize() %s\n", e->toChars()); - return e; -} - -Expression *AndAndExp::optimize(int result) -{ Expression *e; - - //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(FALSE)) - { - e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); - e->type = type; - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 && n2, type); - } - else if (e1->isBool(TRUE)) - e = new BoolExp(loc, e2, type); - } - } - return e; -} - -Expression *OrOrExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(TRUE)) - { // Replace with (e1, 1) - e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); - e->type = type; - e = e->optimize(result); - } - else - { - e2 = e2->optimize(WANTflags | (result & WANTinterpret)); - if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) - error("void has no value"); - if (e1->isConst()) - { - if (e2->isConst()) - { int n1 = e1->isBool(1); - int n2 = e2->isBool(1); - - e = new IntegerExp(loc, n1 || n2, type); - } - else if (e1->isBool(FALSE)) - e = new BoolExp(loc, e2, type); - } - } - return e; -} - -Expression *CmpExp::optimize(int result) -{ Expression *e; - - //printf("CmpExp::optimize() %s\n", toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - - Expression *e1 = fromConstInitializer(result, this->e1); - Expression *e2 = fromConstInitializer(result, this->e2); - - e = Cmp(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *CatExp::optimize(int result) -{ Expression *e; - - //printf("CatExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = Cat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *CondExp::optimize(int result) -{ Expression *e; - - econd = econd->optimize(WANTflags | (result & WANTinterpret)); - if (econd->isBool(TRUE)) - e = e1->optimize(result); - else if (econd->isBool(FALSE)) - e = e2->optimize(result); - else - { e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = this; - } - return e; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include +#include + +#if __DMC__ +#include +#endif + +#include "lexer.h" +#include "mtype.h" +#include "expression.h" +#include "declaration.h" +#include "aggregate.h" +#include "init.h" + + +#ifdef IN_GCC +#include "d-gcc-real.h" + +/* %% fix? */ +extern "C" bool real_isnan (const real_t *); +#endif + +static real_t zero; // work around DMC bug for now + + +/************************************* + * If variable has a const initializer, + * return that initializer. + */ + +Expression *expandVar(int result, VarDeclaration *v) +{ + //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null"); + + Expression *e = NULL; + if (!v) + return e; + if (!v->originalType && v->scope) // semantic() not yet run + v->semantic (v->scope); + + if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) + { + if (!v->type) + { + //error("ICE"); + return e; + } + + Type *tb = v->type->toBasetype(); + if (result & WANTinterpret || + v->storage_class & STCmanifest || + (tb->ty != Tsarray && tb->ty != Tstruct) + ) + { + if (v->init) + { + if (v->inuse) + { if (v->storage_class & STCmanifest) + v->error("recursive initialization of constant"); + goto L1; + } + Expression *ei = v->init->toExpression(); + if (!ei) + goto L1; + if (ei->op == TOKconstruct || ei->op == TOKblit) + { AssignExp *ae = (AssignExp *)ei; + ei = ae->e2; + if (ei->isConst() != 1 && ei->op != TOKstring) + goto L1; + if (ei->type != v->type) + goto L1; + } + if (v->scope) + { + v->inuse++; + e = ei->syntaxCopy(); + e = e->semantic(v->scope); + e = e->implicitCastTo(v->scope, v->type); + // enabling this line causes test22 in test suite to fail + //ei->type = e->type; + v->scope = NULL; + v->inuse--; + } + else if (!ei->type) + { + goto L1; + } + else + // Should remove the copy() operation by + // making all mods to expressions copy-on-write + e = ei->copy(); + } + else + { +#if 1 + goto L1; +#else + // BUG: what if const is initialized in constructor? + e = v->type->defaultInit(); + e->loc = e1->loc; +#endif + } + if (e->type != v->type) + { + e = e->castTo(NULL, v->type); + } + v->inuse++; + e = e->optimize(result); + v->inuse--; + } + } +L1: + //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars()); + return e; +} + + +Expression *fromConstInitializer(int result, Expression *e1) +{ + //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); + //static int xx; if (xx++ == 10) assert(0); + Expression *e = e1; + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + int fwdref = (v && !v->originalType && v->scope); + e = expandVar(result, v); + if (e) + { if (e->type != e1->type && e1->type && e1->type->ty != Tident) + { // Type 'paint' operation + e = e->copy(); + e->type = e1->type; + } + e->loc = e1->loc; + } + else + e = e1; + } + return e; +} + + +Expression *Expression::optimize(int result) +{ + //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); + return this; +} + +Expression *VarExp::optimize(int result) +{ + return fromConstInitializer(result, this); +} + +Expression *TupleExp::optimize(int result) +{ + for (size_t i = 0; i < exps->dim; i++) + { Expression *e = (Expression *)exps->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + exps->data[i] = (void *)e; + } + return this; +} + +Expression *ArrayLiteralExp::optimize(int result) +{ + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + elements->data[i] = (void *)e; + } + } + return this; +} + +Expression *AssocArrayLiteralExp::optimize(int result) +{ + assert(keys->dim == values->dim); + for (size_t i = 0; i < keys->dim; i++) + { Expression *e = (Expression *)keys->data[i]; + + e = e->optimize(WANTvalue | (result & WANTinterpret)); + keys->data[i] = (void *)e; + + e = (Expression *)values->data[i]; + e = e->optimize(WANTvalue | (result & WANTinterpret)); + values->data[i] = (void *)e; + } + return this; +} + +Expression *StructLiteralExp::optimize(int result) +{ + if (elements) + { + for (size_t i = 0; i < elements->dim; i++) + { Expression *e = (Expression *)elements->data[i]; + if (!e) + continue; + e = e->optimize(WANTvalue | (result & WANTinterpret)); + elements->data[i] = (void *)e; + } + } + return this; +} + +Expression *TypeExp::optimize(int result) +{ + return this; +} + +Expression *UnaExp::optimize(int result) +{ + e1 = e1->optimize(result); + return this; +} + +Expression *NegExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Neg(type, e1); + } + else + e = this; + return e; +} + +Expression *ComExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Com(type, e1); + } + else + e = this; + return e; +} + +Expression *NotExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Not(type, e1); + } + else + e = this; + return e; +} + +Expression *BoolExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + if (e1->isConst() == 1) + { + e = Bool(type, e1); + } + else + e = this; + return e; +} + +Expression *AddrExp::optimize(int result) +{ Expression *e; + + //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); + + /* Rewrite &(a,b) as (a,&b) + */ + if (e1->op == TOKcomma) + { CommaExp *ce = (CommaExp *)e1; + AddrExp *ae = new AddrExp(loc, ce->e2); + ae->type = type; + e = new CommaExp(ce->loc, ce->e1, ae); + e->type = type; + return e->optimize(result); + } + + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + if (ve->var->storage_class & STCmanifest) + e1 = e1->optimize(result); + } + else + e1 = e1->optimize(result); + + // Convert &*ex to ex + if (e1->op == TOKstar) + { Expression *ex; + + ex = ((PtrExp *)e1)->e1; + if (type->equals(ex->type)) + e = ex; + else + { + e = ex->copy(); + e->type = type; + } + return e; + } +#if !IN_LLVM + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + if (!ve->var->isOut() && !ve->var->isRef() && + !ve->var->isImportedSymbol()) + { + SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); + se->type = type; + return se; + } + } + if (e1->op == TOKindex) + { // Convert &array[n] to &array+n + IndexExp *ae = (IndexExp *)e1; + + if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) + { + dinteger_t index = ae->e2->toInteger(); + VarExp *ve = (VarExp *)ae->e1; + if (ve->type->ty == Tsarray + && !ve->var->isImportedSymbol()) + { + TypeSArray *ts = (TypeSArray *)ve->type; + dinteger_t dim = ts->dim->toInteger(); + if (index < 0 || index >= dim) + error("array index %jd is out of bounds [0..%jd]", index, dim); + e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); + e->type = type; + return e; + } + } + } +#endif + return this; +} + +Expression *PtrExp::optimize(int result) +{ + //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); + e1 = e1->optimize(result); + // Convert *&ex to ex + if (e1->op == TOKaddress) + { Expression *e; + Expression *ex; + + ex = ((AddrExp *)e1)->e1; + if (type->equals(ex->type)) + e = ex; + else + { + e = ex->copy(); + e->type = type; + } + return e; + } + // Constant fold *(&structliteral + offset) + if (e1->op == TOKadd) + { + Expression *e; + e = Ptr(type, e1); + if (e != EXP_CANT_INTERPRET) + return e; + } + + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + VarDeclaration *v = se->var->isVarDeclaration(); + Expression *e = expandVar(result, v); + if (e && e->op == TOKstructliteral) + { StructLiteralExp *sle = (StructLiteralExp *)e; + e = sle->getField(type, se->offset); + if (e && e != EXP_CANT_INTERPRET) + return e; + } + } + return this; +} + +Expression *DotVarExp::optimize(int result) +{ + //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); + e1 = e1->optimize(result); + + Expression *e = e1; + + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + e = expandVar(result, v); + } + + if (e && e->op == TOKstructliteral) + { StructLiteralExp *sle = (StructLiteralExp *)e; + VarDeclaration *vf = var->isVarDeclaration(); + if (vf) + { + Expression *e = sle->getField(type, vf->offset); + if (e && e != EXP_CANT_INTERPRET) + return e; + } + } + + return this; +} + +Expression *NewExp::optimize(int result) +{ + if (thisexp) + thisexp = thisexp->optimize(WANTvalue); + + // Optimize parameters + if (newargs) + { + for (size_t i = 0; i < newargs->dim; i++) + { Expression *e = (Expression *)newargs->data[i]; + + e = e->optimize(WANTvalue); + newargs->data[i] = (void *)e; + } + } + + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + e = e->optimize(WANTvalue); + arguments->data[i] = (void *)e; + } + } + return this; +} + +Expression *CallExp::optimize(int result) +{ + //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); + Expression *e = this; + + // Optimize parameters + if (arguments) + { + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + e = e->optimize(WANTvalue); + arguments->data[i] = (void *)e; + } + } + + e1 = e1->optimize(result); +#if 1 + if (result & WANTinterpret) + { + Expression *eresult = interpret(NULL); + if (eresult == EXP_CANT_INTERPRET) + return e; + if (eresult && eresult != EXP_VOID_INTERPRET) + e = eresult; + else + error("cannot evaluate %s at compile time", toChars()); + } +#else + if (e1->op == TOKvar) + { + FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); + if (fd) + { + enum BUILTIN b = fd->isBuiltin(); + if (b) + { + e = eval_builtin(b, arguments); + if (!e) // failed + e = this; // evaluate at runtime + } + else if (result & WANTinterpret) + { + Expression *eresult = fd->interpret(NULL, arguments); + if (eresult && eresult != EXP_VOID_INTERPRET) + e = eresult; + else + error("cannot evaluate %s at compile time", toChars()); + } + } + } + else if (e1->op == TOKdotvar && result & WANTinterpret) + { DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *fd = dve->var->isFuncDeclaration(); + if (fd) + { + Expression *eresult = fd->interpret(NULL, arguments, dve->e1); + if (eresult && eresult != EXP_VOID_INTERPRET) + e = eresult; + else + error("cannot evaluate %s at compile time", toChars()); + } + } +#endif + return e; +} + + +Expression *CastExp::optimize(int result) +{ + //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); + //printf("from %s to %s\n", type->toChars(), to->toChars()); + //printf("from %s\n", type->toChars()); + //printf("e1->type %s\n", e1->type->toChars()); + //printf("type = %p\n", type); + assert(type); + enum TOK op1 = e1->op; +#define X 0 + + Expression *e1old = e1; + e1 = e1->optimize(result); + e1 = fromConstInitializer(result, e1); + + if (e1 == e1old && + e1->op == TOKarrayliteral && + type->toBasetype()->ty == Tpointer && + e1->type->toBasetype()->ty != Tsarray) + { + // Casting this will result in the same expression, and + // infinite loop because of Expression::implicitCastTo() + return this; // no change + } + + if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && + (type->ty == Tpointer || type->ty == Tarray) && + e1->type->nextOf()->size() == type->nextOf()->size() + ) + { + Expression *e = e1->castTo(NULL, type); + if (X) printf(" returning1 %s\n", e->toChars()); + return e; + } + + if (e1->op == TOKstructliteral && + e1->type->implicitConvTo(type) >= MATCHconst) + { + e1->type = type; + if (X) printf(" returning2 %s\n", e1->toChars()); + return e1; + } + + /* The first test here is to prevent infinite loops + */ + if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) + return e1->castTo(NULL, to); + if (e1->op == TOKnull && + (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray)) + { + e1->type = type; + if (X) printf(" returning3 %s\n", e1->toChars()); + return e1; + } + + if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) + { + // See if we can remove an unnecessary cast + ClassDeclaration *cdfrom; + ClassDeclaration *cdto; + int offset; + + cdfrom = e1->type->isClassHandle(); + cdto = type->isClassHandle(); + if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) + { + e1->type = type; + if (X) printf(" returning4 %s\n", e1->toChars()); + return e1; + } + } + + // We can convert 'head const' to mutable + if (to->constOf()->equals(e1->type->constOf())) +// if (to->constConv(e1->type) >= MATCHconst) + { + e1->type = type; + if (X) printf(" returning5 %s\n", e1->toChars()); + return e1; + } + + Expression *e; + + if (e1->isConst()) + { + if (e1->op == TOKsymoff) + { + if (type->size() == e1->type->size() && + type->toBasetype()->ty != Tsarray) + { + e1->type = type; + return e1; + } + return this; + } + if (to->toBasetype()->ty == Tvoid) + e = this; + else + e = Cast(type, to, e1); + } + else + e = this; + if (X) printf(" returning6 %s\n", e->toChars()); + return e; +#undef X +} + +Expression *BinExp::optimize(int result) +{ + //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); + if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (op == TOKshlass || op == TOKshrass || op == TOKushrass) + { + if (e2->isConst() == 1) + { + dinteger_t i2 = e2->toInteger(); + d_uns64 sz = e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { error("shift assign by %jd is outside the range 0..%zu", i2, sz); + e2 = new IntegerExp(0); + } + } + } + return this; +} + +Expression *AddExp::optimize(int result) +{ Expression *e; + + //printf("AddExp::optimize(%s)\n", toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() && e2->isConst()) + { + if (e1->op == TOKsymoff && e2->op == TOKsymoff) + return this; + e = Add(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *MinExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() && e2->isConst()) + { + if (e2->op == TOKsymoff) + return this; + e = Min(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *MulExp::optimize(int result) +{ Expression *e; + + //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Mul(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *DivExp::optimize(int result) +{ Expression *e; + + //printf("DivExp::optimize(%s)\n", toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Div(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *ModExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Mod(type, e1, e2); + } + else + e = this; + return e; +} + +Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) +{ Expression *ex = e; + + e->e1 = e->e1->optimize(result); + e->e2 = e->e2->optimize(result); + if (e->e2->isConst() == 1) + { + dinteger_t i2 = e->e2->toInteger(); + d_uns64 sz = e->e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { e->error("shift by %jd is outside the range 0..%zu", i2, sz); + e->e2 = new IntegerExp(0); + } + if (e->e1->isConst() == 1) + ex = (*shift)(e->type, e->e1, e->e2); + } + return ex; +} + +Expression *ShlExp::optimize(int result) +{ + //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Shl); +} + +Expression *ShrExp::optimize(int result) +{ + //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Shr); +} + +Expression *UshrExp::optimize(int result) +{ + //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); + return shift_optimize(result, this, Ushr); +} + +Expression *AndExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = And(type, e1, e2); + else + e = this; + return e; +} + +Expression *OrExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = Or(type, e1, e2); + else + e = this; + return e; +} + +Expression *XorExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + e = Xor(type, e1, e2); + else + e = this; + return e; +} + +Expression *CommaExp::optimize(int result) +{ Expression *e; + + //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); + // Comma needs special treatment, because it may + // contain compiler-generated declarations. We can interpret them, but + // otherwise we must NOT attempt to constant-fold them. + // In particular, if the comma returns a temporary variable, it needs + // to be an lvalue (this is particularly important for struct constructors) + + if (result & WANTinterpret) + { // Interpreting comma needs special treatment, because it may + // contain compiler-generated declarations. + e = interpret(NULL); + return (e == EXP_CANT_INTERPRET) ? this : e; + } + // Don't constant fold if it is a compiler-generated temporary. + if (e1->op == TOKdeclaration) + return this; + + e1 = e1->optimize(result & WANTinterpret); + e2 = e2->optimize(result); + if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) + { + e = e2; + if (e) + e->type = type; + } + else + e = this; + //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); + return e; +} + +Expression *ArrayLengthExp::optimize(int result) +{ Expression *e; + + //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e = this; + if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) + { + e = ArrayLength(type, e1); + } + return e; +} + +Expression *EqualExp::optimize(int result) +{ Expression *e; + + //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e = this; + + Expression *e1 = fromConstInitializer(result, this->e1); + Expression *e2 = fromConstInitializer(result, this->e2); + + e = Equal(op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + +Expression *IdentityExp::optimize(int result) +{ + //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + Expression *e = this; + + if ((this->e1->isConst() && this->e2->isConst()) || + (this->e1->op == TOKnull && this->e2->op == TOKnull)) + { + e = Identity(op, type, this->e1, this->e2); + if (e == EXP_CANT_INTERPRET) + e = this; + } + return e; +} + +Expression *IndexExp::optimize(int result) +{ Expression *e; + + //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); + Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); + e1 = fromConstInitializer(result, e1); + if (this->e1->op == TOKvar) + { VarExp *ve = (VarExp *)this->e1; + if (ve->var->storage_class & STCmanifest) + { /* We generally don't want to have more than one copy of an + * array literal, but if it's an enum we have to because the + * enum isn't stored elsewhere. See Bugzilla 2559 + */ + this->e1 = e1; + } + } + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + e = Index(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + +Expression *SliceExp::optimize(int result) +{ Expression *e; + + //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); + e = this; + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + if (!lwr) + { if (e1->op == TOKstring) + { // Convert slice of string literal into dynamic array + Type *t = e1->type->toBasetype(); + if (t->nextOf()) + e = e1->castTo(NULL, t->nextOf()->arrayOf()); + } + return e; + } + e1 = fromConstInitializer(result, e1); + lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); + upr = upr->optimize(WANTvalue | (result & WANTinterpret)); + e = Slice(type, e1, lwr, upr); + if (e == EXP_CANT_INTERPRET) + e = this; + //printf("-SliceExp::optimize() %s\n", e->toChars()); + return e; +} + +Expression *AndAndExp::optimize(int result) +{ Expression *e; + + //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); + e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e = this; + if (e1->isBool(FALSE)) + { + e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); + e->type = type; + e = e->optimize(result); + } + else + { + e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + error("void has no value"); + if (e1->isConst()) + { + if (e2->isConst()) + { int n1 = e1->isBool(1); + int n2 = e2->isBool(1); + + e = new IntegerExp(loc, n1 && n2, type); + } + else if (e1->isBool(TRUE)) + e = new BoolExp(loc, e2, type); + } + } + return e; +} + +Expression *OrOrExp::optimize(int result) +{ Expression *e; + + e1 = e1->optimize(WANTflags | (result & WANTinterpret)); + e = this; + if (e1->isBool(TRUE)) + { // Replace with (e1, 1) + e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); + e->type = type; + e = e->optimize(result); + } + else + { + e2 = e2->optimize(WANTflags | (result & WANTinterpret)); + if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) + error("void has no value"); + if (e1->isConst()) + { + if (e2->isConst()) + { int n1 = e1->isBool(1); + int n2 = e2->isBool(1); + + e = new IntegerExp(loc, n1 || n2, type); + } + else if (e1->isBool(FALSE)) + e = new BoolExp(loc, e2, type); + } + } + return e; +} + +Expression *CmpExp::optimize(int result) +{ Expression *e; + + //printf("CmpExp::optimize() %s\n", toChars()); + e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); + e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); + + Expression *e1 = fromConstInitializer(result, this->e1); + Expression *e2 = fromConstInitializer(result, this->e2); + + e = Cmp(op, type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + +Expression *CatExp::optimize(int result) +{ Expression *e; + + //printf("CatExp::optimize(%d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + e = Cat(type, e1, e2); + if (e == EXP_CANT_INTERPRET) + e = this; + return e; +} + + +Expression *CondExp::optimize(int result) +{ Expression *e; + + econd = econd->optimize(WANTflags | (result & WANTinterpret)); + if (econd->isBool(TRUE)) + e = e1->optimize(result); + else if (econd->isBool(FALSE)) + e = e2->optimize(result); + else + { e1 = e1->optimize(result); + e2 = e2->optimize(result); + e = this; + } + return e; +} + + diff --git a/dmd2/parse.c b/dmd2/parse.c index 344d0307..4f11e221 100644 --- a/dmd2/parse.c +++ b/dmd2/parse.c @@ -1,6008 +1,6395 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -// This is the D parser - -#include -#include - -#include "rmem.h" -#include "lexer.h" -#include "parse.h" -#include "init.h" -#include "attrib.h" -#include "cond.h" -#include "mtype.h" -#include "template.h" -#include "staticassert.h" -#include "expression.h" -#include "statement.h" -#include "module.h" -#include "dsymbol.h" -#include "import.h" -#include "declaration.h" -#include "aggregate.h" -#include "enum.h" -#include "id.h" -#include "version.h" -#include "aliasthis.h" - -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -#define CDECLSYNTAX 0 - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - - -Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) -{ - //printf("Parser::Parser()\n"); - md = NULL; - linkage = LINKd; - endloc = 0; - inBrackets = 0; - //nextToken(); // start up the scanner -} - -Array *Parser::parseModule() -{ - Array *decldefs; - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - unsigned char *comment = token.blockComment; - bool safe = FALSE; - - nextToken(); -#if DMDV2 - if (token.value == TOKlparen) - { - nextToken(); - if (token.value != TOKidentifier) - { error("module (system) identifier expected"); - goto Lerr; - } - Identifier *id = token.ident; - - if (id == Id::system) - safe = TRUE; - else - error("(safe) expected, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - } -#endif - - if (token.value != TOKidentifier) - { error("Identifier expected following module"); - goto Lerr; - } - else - { - Array *a = NULL; - Identifier *id; - - id = token.ident; - while (nextToken() == TOKdot) - { - if (!a) - a = new Array(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following package"); - goto Lerr; - } - id = token.ident; - } - - md = new ModuleDeclaration(a, id, safe); - - if (token.value != TOKsemicolon) - error("';' expected following module declaration instead of %s", token.toChars()); - nextToken(); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { error("unrecognized declaration"); - goto Lerr; - } - return decldefs; - -Lerr: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - return new Array(); -} - -Array *Parser::parseDeclDefs(int once) -{ Dsymbol *s; - Array *decldefs; - Array *a; - Array *aelse; - enum PROT prot; - enum STC stc; - unsigned storageClass; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Array(); - do - { - comment = token.blockComment; - storageClass = STCundefined; - switch (token.value) - { - case TOKenum: - { /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - s = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - s = parseEnum(); - else - goto Ldeclaration; - } - break; - } - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - s = parseAggregate(); - break; - - case TOKimport: - s = parseImport(decldefs, 0); - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(); - break; - - case TOKmixin: - { Loc loc = this->loc; - if (peek(&token)->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileDeclaration(loc, e); - break; - } - s = parseMixin(); - break; - } - - CASE_BASIC_TYPES: - case TOKalias: - case TOKtypedef: - case TOKidentifier: - case TOKtypeof: - case TOKdot: - Ldeclaration: - a = parseDeclarations(STCundefined); - decldefs->append(a); - continue; - - case TOKthis: - s = parseCtor(); - break; - -#if 0 // dead end, use this(this){} instead - case TOKassign: - s = parsePostBlit(); - break; -#endif - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: - { Token *t; - t = peek(&token); - if (t->value == TOKlparen) - { - if (peek(t)->value == TOKrparen) - // invariant() forms start of class invariant - s = parseInvariant(); - else - // invariant(type) - goto Ldeclaration; - } - else - { - stc = STCimmutable; - goto Lstc; - } - break; - } - - case TOKunittest: - s = parseUnitTest(); - break; - - case TOKnew: - s = parseNew(); - break; - - case TOKdelete: - s = parseDelete(); - break; - - case TOKeof: - case TOKrcurly: - return decldefs; - - case TOKstatic: - nextToken(); - if (token.value == TOKthis) - s = parseStaticCtor(); - else if (token.value == TOKtilde) - s = parseStaticDtor(); - else if (token.value == TOKassert) - s = parseStaticAssert(); - else if (token.value == TOKif) - { condition = parseStaticIfCondition(); - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new StaticIfDeclaration(condition, a, aelse); - break; - } - else if (token.value == TOKimport) - { - s = parseImport(decldefs, 1); - } - else - { stc = STCstatic; - goto Lstc2; - } - break; - - case TOKconst: - if (peek(&token)->value == TOKlparen) - goto Ldeclaration; - stc = STCconst; - goto Lstc; - - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - goto Ldeclaration; - stc = STCimmutable; - goto Lstc; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - goto Ldeclaration; - stc = STCshared; - goto Lstc; - - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; -#endif - - Lstc: - if (storageClass & stc) - error("redundant storage class %s", Token::toChars(token.value)); - composeStorageClass(storageClass | stc); - nextToken(); - Lstc2: - storageClass |= stc; - switch (token.value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - // If followed by a (, it is not a storage class - if (peek(&token)->value == TOKlparen) - break; - if (token.value == TOKconst) - stc = STCconst; - else if (token.value == TOKshared) - stc = STCshared; - else - stc = STCimmutable; - goto Lstc; - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - a = parseAutoDeclarations(storageClass, comment); - decldefs->append(a); - continue; - } - - /* Look for return type inference for template functions. - */ - Token *tk; - if (token.value == TOKidentifier && - (tk = peek(&token))->value == TOKlparen && - skipParens(tk, &tk) && - (peek(tk)->value == TOKlparen || - peek(tk)->value == TOKlcurly) - ) - { - a = parseDeclarations(storageClass); - decldefs->append(a); - continue; - } - a = parseBlock(); - s = new StorageClassDeclaration(storageClass, a); - break; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto Lstc; - } - { - enum LINK linksave = linkage; - linkage = parseLinkage(); - a = parseBlock(); - s = new LinkDeclaration(linkage, a); - linkage = linksave; - break; - } - case TOKprivate: prot = PROTprivate; goto Lprot; - case TOKpackage: prot = PROTpackage; goto Lprot; - case TOKprotected: prot = PROTprotected; goto Lprot; - case TOKpublic: prot = PROTpublic; goto Lprot; - case TOKexport: prot = PROTexport; goto Lprot; - - Lprot: - nextToken(); - switch (token.value) - { - case TOKprivate: - case TOKpackage: - case TOKprotected: - case TOKpublic: - case TOKexport: - error("redundant protection attribute"); - break; - } - a = parseBlock(); - s = new ProtDeclaration(prot, a); - break; - - case TOKalign: - { unsigned n; - - // LDC better align code locations - Loc alignloc = loc; - - s = NULL; - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKint32v) - n = (unsigned)token.uns64value; - else - { error("integer expected, not %s", token.toChars()); - n = 1; - } - nextToken(); - check(TOKrparen); - } - else - n = global.structalign; // default - - a = parseBlock(); - s = new AlignDeclaration(alignloc, n, a); - break; - } - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...) - else - check(TOKrparen); // pragma(identifier) - - if (token.value == TOKsemicolon) - a = NULL; - else - a = parseBlock(); - s = new PragmaDeclaration(loc, ident, args, a); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new DebugSymbol(loc, token.ident); - else if (token.value == TOKint32v) - s = new DebugSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new VersionSymbol(loc, token.ident); - else if (token.value == TOKint32v) - s = new VersionSymbol(loc, (unsigned)token.uns64value); - else - { error("identifier or integer expected, not %s", token.toChars()); - s = NULL; - } - nextToken(); - if (token.value != TOKsemicolon) - error("semicolon expected"); - nextToken(); - break; - } - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - a = parseBlock(); - aelse = NULL; - if (token.value == TOKelse) - { nextToken(); - aelse = parseBlock(); - } - s = new ConditionalDeclaration(condition, a, aelse); - break; - - case TOKsemicolon: // empty declaration - nextToken(); - continue; - - default: - error("Declaration expected, not '%s'",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - if (s) - { decldefs->push(s); - addComment(s, comment); - } - } while (!once); - return decldefs; -} - -/********************************************* - * Give error on conflicting storage classes. - */ - -void Parser::composeStorageClass(unsigned stc) -{ - unsigned u = stc; - u &= STCconst | STCimmutable | STCmanifest; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCgshared | STCshared | STCtls; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); -} - -/******************************************** - * Parse declarations after an align, protection, or extern decl. - */ - -Array *Parser::parseBlock() -{ - Array *a = NULL; - Dsymbol *s; - - //printf("parseBlock()\n"); - switch (token.value) - { - case TOKsemicolon: - error("declaration expected following attribute, not ';'"); - nextToken(); - break; - - case TOKeof: - error("declaration expected following attribute, not EOF"); - break; - - case TOKlcurly: - nextToken(); - a = parseDeclDefs(0); - if (token.value != TOKrcurly) - { /* { */ - error("matching '}' expected, not %s", token.toChars()); - } - else - nextToken(); - break; - - case TOKcolon: - nextToken(); -#if 0 - a = NULL; -#else - a = parseDeclDefs(0); // grab declarations up to closing curly bracket -#endif - break; - - default: - a = parseDeclDefs(1); - break; - } - return a; -} - -/********************************** - * Parse a static assertion. - */ - -StaticAssert *Parser::parseStaticAssert() -{ - Loc loc = this->loc; - Expression *exp; - Expression *msg = NULL; - - //printf("parseStaticAssert()\n"); - nextToken(); - check(TOKlparen); - exp = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - check(TOKsemicolon); - return new StaticAssert(loc, exp, msg); -} - -/*********************************** - * Parse typeof(expression). - * Current token is on the 'typeof'. - */ - -#if DMDV2 -TypeQualified *Parser::parseTypeof() -{ TypeQualified *t; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - if (token.value == TOKreturn) // typeof(return) - { - nextToken(); - t = new TypeReturn(loc); - } - else - { Expression *exp = parseExpression(); // typeof(expression) - t = new TypeTypeof(loc, exp); - } - check(TOKrparen); - return t; -} -#endif - -/*********************************** - * Parse extern (linkage) - * The parser is on the 'extern' token. - */ - -enum LINK Parser::parseLinkage() -{ - enum LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::Pascal) - link = LINKpascal; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { link = LINKcpp; - nextToken(); - } - } - else if (id == Id::System) - { - // LDC we configure target at runtime - if (global.params.os == OSWindows) - link = LINKwindows; - else - link = LINKc; - } - else - { - error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - return link; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v) - level = (unsigned)token.uns64value; - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - c = new DebugCondition(mod, level, id); - } - else - c = new DebugCondition(mod, 1, NULL); - return c; - -} - -/************************************** - * Parse a version conditional - */ - -Condition *Parser::parseVersionCondition() -{ - Condition *c; - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v) - level = (unsigned)token.uns64value; -#if DMDV2 - /* Allow: - * version (unittest) - * even though unittest is a keyword - */ - else if (token.value == TOKunittest) - id = Lexer::idPool(Token::toChars(TOKunittest)); -#endif - else - error("identifier or integer expected, not %s", token.toChars()); - nextToken(); - check(TOKrparen); - - } - else - error("(condition) expected following version"); - c = new VersionCondition(mod, level, id); - return c; - -} - -/*********************************************** - * static if (expression) - * body - * else - * body - */ - -Condition *Parser::parseStaticIfCondition() -{ Expression *exp; - Condition *condition; - Array *aif; - Array *aelse; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { error("(expression) expected following static if"); - exp = NULL; - } - condition = new StaticIfCondition(loc, exp); - return condition; -} - - -/***************************************** - * Parse a constructor definition: - * this(parameters) { body } - * or postblit: - * this(this) { body } - * or constructor template: - * this(templateparameters)(parameters) { body } - * Current token is 'this'. - */ - -Dsymbol *Parser::parseCtor() -{ - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen && peek(&token)->value == TOKthis) - { // this(this) { ... } - nextToken(); - nextToken(); - check(TOKrparen); - PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0); - parseContracts(f); - return f; - } - - /* Look ahead to see if: - * this(...)(...) - * which is a constructor template - */ - TemplateParameters *tpl = NULL; - if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) - { tpl = parseTemplateParameterList(); - - int varargs; - Arguments *arguments = parseParameters(&varargs); - - Expression *constraint = NULL; - if (tpl) - constraint = parseConstraint(); - - CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - - // Wrap a template around it - Array *decldefs = new Array(); - decldefs->push(f); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs); - return tempdecl; - } - - /* Just a regular constructor - */ - int varargs; - Arguments *arguments = parseParameters(&varargs); - CtorDeclaration *f = new CtorDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a postblit definition: - * =this() { body } - * Current token is '='. - */ - -PostBlitDeclaration *Parser::parsePostBlit() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -DtorDeclaration *Parser::parseDtor() -{ - DtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - f = new DtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static constructor definition: - * static this() { body } - * Current token is 'this'. - */ - -StaticCtorDeclaration *Parser::parseStaticCtor() -{ - StaticCtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - check(TOKrparen); - - f = new StaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is '~'. - */ - -StaticDtorDeclaration *Parser::parseStaticDtor() -{ - StaticDtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - f = new StaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse an invariant definition: - * invariant() { body } - * Current token is 'invariant'. - */ - -InvariantDeclaration *Parser::parseInvariant() -{ - InvariantDeclaration *f; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) // optional () - { - nextToken(); - check(TOKrparen); - } - - f = new InvariantDeclaration(loc, 0); - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -UnitTestDeclaration *Parser::parseUnitTest() -{ - UnitTestDeclaration *f; - Statement *body; - Loc loc = this->loc; - - nextToken(); - - body = parseStatement(PScurly); - - f = new UnitTestDeclaration(loc, this->loc); - f->fbody = body; - return f; -} - -/***************************************** - * Parse a new definition: - * new(arguments) { body } - * Current token is 'new'. - */ - -NewDeclaration *Parser::parseNew() -{ - NewDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a delete definition: - * delete(arguments) { body } - * Current token is 'delete'. - */ - -DeleteDeclaration *Parser::parseDelete() -{ - DeleteDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - if (varargs) - error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, 0, arguments); - parseContracts(f); - return f; -} - -/********************************************** - * Parse parameter list. - */ - -Arguments *Parser::parseParameters(int *pvarargs) -{ - Arguments *arguments = new Arguments(); - int varargs = 0; - int hasdefault = 0; - - check(TOKlparen); - while (1) - { Type *tb; - Identifier *ai = NULL; - Type *at; - Argument *a; - unsigned storageClass = 0; - unsigned stc; - Expression *ae; - - for (;1; nextToken()) - { - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKconst: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCconst; - goto L2; - - case TOKinvariant: - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCimmutable; - goto L2; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCshared; - goto L2; - - case TOKin: stc = STCin; goto L2; - case TOKout: stc = STCout; goto L2; - case TOKinout: - case TOKref: stc = STCref; goto L2; - case TOKlazy: stc = STClazy; goto L2; - case TOKscope: stc = STCscope; goto L2; - case TOKfinal: stc = STCfinal; goto L2; - L2: - if (storageClass & stc || - (storageClass & STCin && stc & (STCconst | STCscope)) || - (stc & STCin && storageClass & (STCconst | STCscope)) - ) - error("redundant storage class %s", Token::toChars(token.value)); - storageClass |= stc; - composeStorageClass(storageClass); - continue; - -#if 0 - case TOKstatic: stc = STCstatic; goto L2; - case TOKauto: storageClass = STCauto; goto L4; - case TOKalias: storageClass = STCalias; goto L4; - L4: - nextToken(); - if (token.value == TOKidentifier) - { ai = token.ident; - nextToken(); - } - else - ai = NULL; - at = NULL; // no type - ae = NULL; // no default argument - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for alias %s", - ai ? ai->toChars() : ""); - } - goto L3; -#endif - - default: - Ldefault: - stc = storageClass & (STCin | STCout | STCref | STClazy); - if (stc & (stc - 1)) // if stc is not a power of 2 - error("incompatible parameter storage classes"); - if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) - error("out cannot be const"); - if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout)) - error("out cannot be immutable"); - if ((storageClass & STCscope) && - (storageClass & (STCref | STCout))) - error("scope cannot be ref or out"); - at = parseType(&ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = 2; - a = new Argument(storageClass, at, ai, ae); - arguments->push(a); - nextToken(); - break; - } - L3: - a = new Argument(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - goto L1; - } - break; - } - break; - } - break; - - L1: ; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *memtype; - Loc loc = this->loc; - - //printf("Parser::parseEnum()\n"); - nextToken(); - if (token.value == TOKidentifier) - { id = token.ident; - nextToken(); - } - else - id = NULL; - - if (token.value == TOKcolon) - { - nextToken(); - memtype = parseBasicType(); - memtype = parseDeclarator(memtype, NULL, NULL); - } - else - memtype = NULL; - - e = new EnumDeclaration(loc, id, memtype); - if (token.value == TOKsemicolon && id) - nextToken(); - else if (token.value == TOKlcurly) - { - //printf("enum definition\n"); - e->members = new Array(); - nextToken(); - unsigned char *comment = token.blockComment; - while (token.value != TOKrcurly) - { - /* Can take the following forms: - * 1. ident - * 2. ident = value - * 3. type ident = value - */ - - loc = this->loc; - - Type *type = NULL; - Identifier *ident; - Token *tp = peek(&token); - if (token.value == TOKidentifier && - (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly)) - { - ident = token.ident; - type = NULL; - nextToken(); - } - else - { - type = parseType(&ident, NULL); - if (id || memtype) - error("type only allowed if anonymous enum and no enum type"); - } - - Expression *value; - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - else - { value = NULL; - if (type) - error("if type, there must be an initializer"); - } - - EnumMember *em = new EnumMember(loc, ident, value, type); - e->members->push(em); - - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma); - } - addComment(em, comment); - comment = token.blockComment; - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * Parse struct, union, interface, class. - */ - -Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; - int anon = 0; - enum TOK tok; - Identifier *id; - TemplateParameters *tpl = NULL; - Expression *constraint = NULL; - - //printf("Parser::parseAggregate()\n"); - tok = token.value; - nextToken(); - if (token.value != TOKidentifier) - { id = NULL; - } - else - { id = token.ident; - nextToken(); - - if (token.value == TOKlparen) - { // Class template declaration. - - // Gather template parameter list - tpl = parseTemplateParameterList(); - constraint = parseConstraint(); - } - } - - Loc loc = this->loc; - switch (tok) - { case TOKclass: - case TOKinterface: - { - if (!id) - error("anonymous classes not allowed"); - - // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (token.value != TOKlcurly) - error("members expected"); - } - - if (tok == TOKclass) - a = new ClassDeclaration(loc, id, baseclasses); - else - a = new InterfaceDeclaration(loc, id, baseclasses); - break; - } - - case TOKstruct: - if (id) - a = new StructDeclaration(loc, id); - else - anon = 1; - break; - - case TOKunion: - if (id) - a = new UnionDeclaration(loc, id); - else - anon = 2; - break; - - default: - assert(0); - break; - } - if (a && token.value == TOKsemicolon) - { nextToken(); - } - else if (token.value == TOKlcurly) - { - //printf("aggregate definition\n"); - nextToken(); - Array *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); - nextToken(); - if (anon) - { - /* Anonymous structs/unions are more like attributes. - */ - return new AnonDeclaration(loc, anon - 1, decl); - } - else - a->members = decl; - } - else - { - error("{ } expected following aggregate declaration"); - a = new StructDeclaration(loc, NULL); - } - - if (tpl) - { // Wrap a template around the aggregate declaration - - Array *decldefs = new Array(); - decldefs->push(a); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, id, tpl, constraint, decldefs); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - enum PROT protection = PROTpublic; - switch (token.value) - { - case TOKprivate: - protection = PROTprivate; - nextToken(); - break; - case TOKpackage: - protection = PROTpackage; - nextToken(); - break; - case TOKprotected: - protection = PROTprotected; - nextToken(); - break; - case TOKpublic: - protection = PROTpublic; - nextToken(); - break; - } - if (token.value == TOKidentifier) - { - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - } - else - { - error("base classes expected instead of %s", token.toChars()); - return NULL; - } - } - return baseclasses; -} - -/************************************** - * Parse constraint. - * Constraint is of the form: - * if ( ConstraintExpression ) - */ - -#if DMDV2 -Expression *Parser::parseConstraint() -{ Expression *e = NULL; - - if (token.value == TOKif) - { - nextToken(); // skip over 'if' - check(TOKlparen); - e = parseExpression(); - check(TOKrparen); - } - return e; -} -#endif - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration() -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Array *decldefs; - Expression *constraint = NULL; - Loc loc = this->loc; - - nextToken(); - if (token.value != TOKidentifier) - { error("TemplateIdentifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - constraint = parseConstraint(); - - if (token.value != TOKlcurly) - { error("members of template declaration expected"); - goto Lerr; - } - else - { - nextToken(); - decldefs = parseDeclDefs(0); - if (token.value != TOKrcurly) - { error("template member expected"); - goto Lerr; - } - nextToken(); - } - - tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - * Input: - * flag 0: parsing "( list )" - * 1: parsing non-empty "list )" - */ - -TemplateParameters *Parser::parseTemplateParameterList(int flag) -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (!flag && token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (flag || token.value != TOKrparen) - { int isvariadic = 0; - - while (1) - { TemplateParameter *tp; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - Type *spectype = NULL; - if (isDeclaration(&token, 2, TOKreserved, NULL)) - { - spectype = parseType(&tp_ident); - } - else - { - if (token.value != TOKidentifier) - { error("identifier expected for template alias parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - } - Object *spec = NULL; - if (token.value == TOKcolon) // : Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - spec = parseType(); - else - spec = parseCondExp(); - } - Object *def = NULL; - if (token.value == TOKassign) // = Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - def = parseType(); - else - def = parseCondExp(); - } - tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("identifier expected for template type parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } -#if DMDV2 - else if (token.value == TOKthis) - { // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } -#endif - else - { // ValueParameter - tp_valtype = parseType(&tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = new Identifier("error", TOKidentifier); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseDefaultInitExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Type *tqual; - Objects *tiargs; - Array *idents; - - //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { - tqual = parseTypeof(); - check(TOKdot); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - id = Id::empty; - } - else - id = token.ident; - nextToken(); - } - - idents = new Array(); - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - nextToken(); - if (token.value == TOKlparen) - tiargs = parseTemplateArgumentList(); - else - tiargs = parseTemplateArgument(); - } - - if (token.value != TOKdot) - break; - - if (tiargs) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - id = (Identifier *)tempinst; - tiargs = NULL; - } - idents->push(id); - - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - } - idents->push(id); - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(loc, id, tqual, idents, tiargs); - if (token.value != TOKsemicolon) - error("';' expected after mixin"); - nextToken(); - - return tm; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - if (token.value != TOKlparen && token.value != TOKlcurly) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return new Objects(); - } - return parseTemplateArgumentList2(); -} - -Objects *Parser::parseTemplateArgumentList2() -{ - //printf("Parser::parseTemplateArgumentList2()\n"); - Objects *tiargs = new Objects(); - enum TOK endtok = TOKrparen; - nextToken(); - - // Get TemplateArgumentList - if (token.value != endtok) - { - while (1) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Template argument is a type - Type *ta = parseType(); - tiargs->push(ta); - } - else - { // Template argument is an expression - Expression *ea = parseAssignExp(); - - if (ea->op == TOKfunction) - { FuncLiteralDeclaration *fd = ((FuncExp *)ea)->fd; - if (fd->type->ty == Tfunction) - { - TypeFunction *tf = (TypeFunction *)fd->type; - /* If there are parameters that consist of only an identifier, - * rather than assuming the identifier is a type, as we would - * for regular function declarations, assume the identifier - * is the parameter name, and we're building a template with - * a deduced type. - */ - TemplateParameters *tpl = NULL; - for (int i = 0; i < tf->parameters->dim; i++) - { Argument *param = (Argument *)tf->parameters->data[i]; - if (param->ident == NULL && - param->type && - param->type->ty == Tident && - ((TypeIdentifier *)param->type)->idents.dim == 0 - ) - { - /* Switch parameter type to parameter identifier, - * parameterize with template type parameter _T - */ - TypeIdentifier *pt = (TypeIdentifier *)param->type; - param->ident = pt->ident; - Identifier *id = Lexer::uniqueId("__T"); - param->type = new TypeIdentifier(pt->loc, id); - TemplateParameter *tp = new TemplateTypeParameter(fd->loc, id, NULL, NULL); - if (!tpl) - tpl = new TemplateParameters(); - tpl->push(tp); - } - } - - if (tpl) - { // Wrap a template around function fd - Array *decldefs = new Array(); - decldefs->push(fd); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs); - tempdecl->literal = 1; // it's a template 'literal' - tiargs->push(tempdecl); - goto L1; - } - } - } - - tiargs->push(ea); - } - L1: - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(endtok, "template argument list"); - return tiargs; -} - -/***************************** - * Parse single template argument, to support the syntax: - * foo!arg - * Input: - * current token is the arg - */ - -Objects *Parser::parseTemplateArgument() -{ - //printf("parseTemplateArgument()\n"); - Objects *tiargs = new Objects(); - Type *ta; - switch (token.value) - { - case TOKidentifier: - ta = new TypeIdentifier(loc, token.ident); - goto LabelX; - - CASE_BASIC_TYPES_X(ta): - tiargs->push(ta); - nextToken(); - break; - - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKfile: - case TOKline: - { // Template argument is an expression - Expression *ea = parsePrimaryExp(); - tiargs->push(ea); - break; - } - - default: - error("template argument expected following !"); - break; - } - if (token.value == TOKnot) - error("multiple ! arguments are not allowed"); - return tiargs; -} - -Import *Parser::parseImport(Array *decldefs, int isstatic) -{ Import *s; - Identifier *id; - Identifier *aliasid = NULL; - Array *a; - Loc loc; - - //printf("Parser::parseImport()\n"); - do - { - L1: - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following import"); - break; - } - - loc = this->loc; - a = NULL; - id = token.ident; - nextToken(); - if (!aliasid && token.value == TOKassign) - { - aliasid = id; - goto L1; - } - while (token.value == TOKdot) - { - if (!a) - a = new Array(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following package"); - break; - } - id = token.ident; - nextToken(); - } - - s = new Import(loc, a, id, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { Identifier *name; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following :"); - break; - } - Identifier *alias = token.ident; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following %s=", alias->toChars()); - break; - } - name = token.ident; - nextToken(); - } - else - { name = alias; - alias = NULL; - } - s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form - } - - aliasid = NULL; - } while (token.value == TOKcomma); - - if (token.value == TOKsemicolon) - nextToken(); - else - { - error("';' expected"); - nextToken(); - } - - return NULL; -} - -#if DMDV2 -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) -{ Type *t; - - /* Take care of the storage class prefixes that - * serve as type attributes: - * const shared, shared const, const, invariant, shared - */ - if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared const type - */ - t = parseType(pident, tpl); - t = t->makeSharedConst(); - return t; - } - else if (token.value == TOKconst && peekNext() != TOKlparen) - { - nextToken(); - /* const type - */ - t = parseType(pident, tpl); - t = t->makeConst(); - return t; - } - else if ((token.value == TOKinvariant || token.value == TOKimmutable) && - peekNext() != TOKlparen) - { - nextToken(); - /* invariant type - */ - t = parseType(pident, tpl); - t = t->makeInvariant(); - return t; - } - else if (token.value == TOKshared && peekNext() != TOKlparen) - { - nextToken(); - /* shared type - */ - t = parseType(pident, tpl); - t = t->makeShared(); - return t; - } - else - t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); - return t; -} -#endif - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - - //printf("parseBasicType()\n"); - switch (token.value) - { - CASE_BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { // ident!(template_arguments) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - tid = new TypeInstance(loc, tempinst); - goto Lident2; - } - Lident: - tid = new TypeIdentifier(loc, id); - Lident2: - while (token.value == TOKdot) - { nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - // Leading . as in .foo - id = Id::empty; - goto Lident; - - case TOKtypeof: - // typeof(expression) - tid = parseTypeof(); - goto Lident2; - - case TOKconst: - // const(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - if (t->isShared()) - t = t->makeSharedConst(); - else - t = t->makeConst(); - break; - - case TOKinvariant: - case TOKimmutable: - // invariant(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - t = t->makeInvariant(); - break; - - case TOKshared: - // shared(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - if (t->isConst()) - t = t->makeSharedConst(); - else - t = t->makeShared(); - break; - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's type[expression]\n"); - inBrackets++; - Expression *e = parseExpression(); // [ expression ] - if (token.value == TOKslice) - { - nextToken(); - Expression *e2 = parseExpression(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) nothrow pure - // t function(parameter list) nothrow pure - Arguments *arguments; - int varargs; - bool ispure = false; - bool isnothrow = false; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - while (1) - { // Postfixes - if (token.value == TOKpure) - ispure = true; - else if (token.value == TOKnothrow) - isnothrow = true; - else - break; - nextToken(); - } - TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage); - tf->ispure = ispure; - tf->isnothrow = isnothrow; - if (save == TOKdelegate) - t = new TypeDelegate(tf); - else - t = new TypePointer(tf); // pointer to function - continue; - } - - default: - return t; - } - assert(0); - } - assert(0); - return NULL; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) -{ Type *ts; - - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - switch (token.value) - { - - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifer '%s' in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - - default: - ts = t; - break; - } - - // parse DeclaratorSuffixes - while (1) - { - switch (token.value) - { -#if CARRAYDECL - /* Support C style array syntax: - * int ident[] - * as opposed to D-style: - * int[] ident - */ - case TOKlbracket: - { // This is the old C-style post [] syntax. - TypeNext *ta; - nextToken(); - if (token.value == TOKrbracket) - { // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array - - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("It's a static array\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { - if (tpl) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - if (peekPastParen(&token)->value == TOKlparen) - { - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - } - - int varargs; - Arguments *arguments = parseParameters(&varargs); - Type *tf = new TypeFunction(arguments, t, varargs, linkage); - - /* Parse const/invariant/nothrow/pure postfix - */ - while (1) - { - switch (token.value) - { - case TOKconst: - if (tf->isShared()) - tf = tf->makeSharedConst(); - else - tf = tf->makeConst(); - nextToken(); - continue; - - case TOKinvariant: - case TOKimmutable: - tf = tf->makeInvariant(); - nextToken(); - continue; - - case TOKshared: - if (tf->isConst()) - tf = tf->makeSharedConst(); - else - tf = tf->makeShared(); - nextToken(); - continue; - - case TOKnothrow: - ((TypeFunction *)tf)->isnothrow = 1; - nextToken(); - continue; - - case TOKpure: - ((TypeFunction *)tf)->ispure = 1; - nextToken(); - continue; - - case TOKat: - nextToken(); - if (token.value != TOKidentifier) - { error("attribute identifier expected"); - nextToken(); - continue; - } - Identifier *id = token.ident; - if (id == Id::property) - ((TypeFunction *)tf)->ispure = 1; - else - error("valid attribute identifiers are property, not %s", id->toChars()); - nextToken(); - continue; - - } - break; - } - - /* Insert tf into - * ts -> ... -> t - * so that - * ts -> ... -> tf -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) - ; - *pt = tf; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Array *Parser::parseDeclarations(unsigned storage_class) -{ - enum STC stc; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Array *a; - enum TOK tok = TOKreserved; - unsigned char *comment = token.blockComment; - enum LINK link = linkage; - - //printf("parseDeclarations() %s\n", token.toChars()); - if (storage_class) - { ts = NULL; // infer type - goto L2; - } - - switch (token.value) - { - case TOKalias: - /* Look for: - * alias identifier this; - */ - tok = token.value; - nextToken(); - if (token.value == TOKidentifier && peek(&token)->value == TOKthis) - { - AliasThis *s = new AliasThis(this->loc, token.ident); - nextToken(); - check(TOKthis); - check(TOKsemicolon); - a = new Array(); - a->push(s); - addComment(s, comment); - return a; - } - break; - case TOKtypedef: - tok = token.value; - nextToken(); - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: - if (peek(&token)->value == TOKlparen) - break; // const as type constructor - stc = STCconst; // const as storage class - goto L1; - - case TOKinvariant: - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - break; - stc = STCimmutable; - goto L1; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - break; - stc = STCshared; - goto L1; - - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto L1; - case TOKpure: stc = STCpure; goto L1; - case TOKref: stc = STCref; goto L1; - case TOKtls: stc = STCtls; goto L1; - case TOKgshared: stc = STCgshared; goto L1; - case TOKenum: stc = STCmanifest; goto L1; -#endif - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = (STC) (storage_class | stc); - composeStorageClass(storage_class); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - return parseAutoDeclarations(storage_class, comment); - } - - if (token.value == TOKclass) - { - AggregateDeclaration *s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - a = new Array(); - a->push(s); - addComment(s, comment); - return a; - } - - /* Look for return type inference for template functions. - */ - { - Token *tk; - if (storage_class && - token.value == TOKidentifier && - (tk = peek(&token))->value == TOKlparen && - skipParens(tk, &tk) && - peek(tk)->value == TOKlparen) - { - ts = NULL; - } - else - { - ts = parseBasicType(); - ts = parseBasicType2(ts); - } - } - -L2: - tfirst = NULL; - a = new Array(); - - while (1) - { - Loc loc = this->loc; - TemplateParameters *tpl = NULL; - - ident = NULL; - t = parseDeclarator(ts, &ident, &tpl); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - if (!ident) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKtypedef || tok == TOKalias) - { Declaration *v; - Initializer *init = NULL; - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (tok == TOKtypedef) - v = new TypedefDeclaration(loc, ident, t, init); - else - { if (init) - error("alias cannot have initializer"); - v = new AliasDeclaration(loc, ident, t); - } - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Array *ax = new Array(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { - TypeFunction *tf = (TypeFunction *)t; - Expression *constraint = NULL; -#if 0 - if (Argument::isTPL(tf->parameters)) - { - if (!tpl) - tpl = new TemplateParameters(); - } -#endif - FuncDeclaration *f = - new FuncDeclaration(loc, 0, ident, (enum STC)storage_class, t); - addComment(f, comment); - if (tpl) - constraint = parseConstraint(); - parseContracts(f); - addComment(f, NULL); - Dsymbol *s; - if (link == linkage) - { - s = f; - } - else - { - Array *ax = new Array(); - ax->push(f); - s = new LinkDeclaration(link, ax); - } - /* A template parameter list means it's a function template - */ - if (tpl) - { - // Wrap a template around the function declaration - Array *decldefs = new Array(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Array *ax = new Array(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected, not '%s'", token.toChars()); - break; - } - } - break; - } - return a; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -#if DMDV2 -Array *Parser::parseAutoDeclarations(unsigned storageClass, unsigned char *comment) -{ - Array *a = new Array; - - while (1) - { - Identifier *ident = token.ident; - nextToken(); // skip over ident - assert(token.value == TOKassign); - nextToken(); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - addComment(v, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - return a; -} -#endif - -/***************************************** - * Parse contracts following function declaration. - */ - -void Parser::parseContracts(FuncDeclaration *f) -{ - Type *tb; - enum LINK linksave = linkage; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage -L1: - switch (token.value) - { - case TOKlcurly: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKbody: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKsemicolon: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - nextToken(); - break; - -#if 0 // Do we want this for function declarations, so we can do: - // int x, y, foo(), z; - case TOKcomma: - nextToken(); - continue; -#endif - -#if 0 // Dumped feature - case TOKthrow: - if (!f->fthrows) - f->fthrows = new Array(); - nextToken(); - check(TOKlparen); - while (1) - { - tb = parseBasicType(); - f->fthrows->push(tb); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKrparen); - goto L1; -#endif - - case TOKin: - nextToken(); - if (f->frequire) - error("redundant 'in' statement"); - f->frequire = parseStatement(PScurly | PSscope); - goto L1; - - case TOKout: - // parse: out (identifier) { statement } - nextToken(); - if (token.value != TOKlcurly) - { - check(TOKlparen); - if (token.value != TOKidentifier) - error("(identifier) following 'out' expected, not %s", token.toChars()); - f->outId = token.ident; - nextToken(); - check(TOKrparen); - } - if (f->fensure) - error("redundant 'out' statement"); - f->fensure = parseStatement(PScurly | PSscope); - goto L1; - - default: - error("semicolon expected following function declaration"); - break; - } - linkage = linksave; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = this->loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 0; - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (comma == 1) - error("comma expected separating field initializers"); - t = peek(&token); - if (t->value == TOKcolon) - { - id = token.ident; - nextToken(); - nextToken(); // skip over ':' - } - else - { id = NULL; - } - value = parseInitializer(); - is->addInit(id, value); - comma = 1; - continue; - - case TOKcomma: - nextToken(); - comma = 2; - continue; - - case TOKrcurly: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found EOF instead of initializer"); - break; - - default: - value = parseInitializer(); - is->addInit(NULL, value); - comma = 1; - continue; - //error("found '%s' instead of field initializer", token.toChars()); - //break; - } - break; - } - return is; - - case TOKlbracket: - /* Scan ahead to see if it is an array initializer or - * an expression. - * If it ends with a ';' ',' or '}', it is an array initializer. - */ - brackets = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brackets++; - continue; - - case TOKrbracket: - if (--brackets == 0) - { t = peek(t); - if (t->value != TOKsemicolon && - t->value != TOKcomma && - t->value != TOKrcurly) - goto Lexpression; - break; - } - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - ia = new ArrayInitializer(loc); - nextToken(); - comma = 0; - while (1) - { - switch (token.value) - { - default: - if (comma == 1) - { error("comma expected separating array initializers, not %s", token.toChars()); - nextToken(); - break; - } - e = parseAssignExp(); - if (!e) - break; - if (token.value == TOKcolon) - { - nextToken(); - value = parseInitializer(); - } - else - { value = new ExpInitializer(e->loc, e); - e = NULL; - } - ia->addInit(e, value); - comma = 1; - continue; - - case TOKlcurly: - case TOKlbracket: - if (comma == 1) - error("comma expected separating array initializers, not %s", token.toChars()); - value = parseInitializer(); - ia->addInit(NULL, value); - comma = 1; - continue; - - case TOKcomma: - nextToken(); - comma = 2; - continue; - - case TOKrbracket: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found '%s' instead of array initializer", token.toChars()); - break; - } - break; - } - return ia; - - case TOKvoid: - t = peek(&token); - if (t->value == TOKsemicolon || t->value == TOKcomma) - { - nextToken(); - return new VoidInitializer(loc); - } - goto Lexpression; - - default: - Lexpression: - e = parseAssignExp(); - ie = new ExpInitializer(loc, e); - return ie; - } -} - -/***************************************** - * Parses default argument initializer expression that is an assign expression, - * with special handling for __FILE__ and __LINE__. - */ - -#if DMDV2 -Expression *Parser::parseDefaultInitExp() -{ - if (token.value == TOKfile || - token.value == TOKline) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKrparen) - { Expression *e; - - if (token.value == TOKfile) - e = new FileInitExp(loc); - else - e = new LineInitExp(loc); - nextToken(); - return e; - } - } - - Expression *e = parseAssignExp(); - return e; -} -#endif - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - bool isfinal; - Loc loc = this->loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - - Identifier *ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi); - s = new LabelStatement(loc, ident, s); - break; - } - // fallthrough to TOKdot - case TOKdot: - case TOKtypeof: - if (isDeclaration(&token, 2, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: -#if DMDV2 - case TOKtraits: - case TOKfile: - case TOKline: -#endif - Lexp: - { Expression *exp; - - exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - Token *t; - - t = peek(&token); - if (t->value == TOKassert) - { - nextToken(); - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - nextToken(); - condition = parseStaticIfCondition(); - goto Lcondition; - } - goto Ldeclaration; - } - - case TOKfinal: - if (peekNext() == TOKswitch) - { - nextToken(); - isfinal = TRUE; - goto Lswitch; - } - goto Ldeclaration; - - CASE_BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKinvariant: -#if DMDV2 - case TOKimmutable: - case TOKshared: - case TOKnothrow: - case TOKpure: - case TOKtls: - case TOKgshared: -#endif -// case TOKtypeof: - Ldeclaration: - { Array *a; - - a = parseDeclarations(STCundefined); - if (a->dim > 1) - { - Statements *as = new Statements(); - as->reserve(a->dim); - for (int i = 0; i < a->dim; i++) - { - Dsymbol *d = (Dsymbol *)a->data[i]; - s = new DeclarationStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->dim == 1) - { - Dsymbol *d = (Dsymbol *)a->data[0]; - s = new DeclarationStatement(loc, d); - } - else - assert(0); - if (flags & PSscope) - s = new ScopeStatement(loc, s); - break; - } - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - { Dsymbol *d; - - d = parseAggregate(); - s = new DeclarationStatement(loc, d); - break; - } - - case TOKenum: - { /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Dsymbol *d; - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - d = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - d = parseEnum(); - else - goto Ldeclaration; - } - s = new DeclarationStatement(loc, d); - break; - } - - case TOKmixin: - { t = peek(&token); - if (t->value == TOKlparen) - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileStatement(loc, e); - break; - } - Dsymbol *d = parseMixin(); - s = new DeclarationStatement(loc, d); - break; - } - - case TOKlcurly: - { Statements *statements; - - nextToken(); - statements = new Statements(); - while (token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - endloc = this->loc; - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s); - nextToken(); - break; - } - - case TOKwhile: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WhileStatement(loc, condition, body); - break; - } - - case TOKsemicolon: - if (!(flags & PSsemi)) - error("use '{ }' for an empty statement, not a ';'"); - nextToken(); - s = new ExpStatement(loc, NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - body = parseStatement(PSscope); - check(TOKwhile); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - s = new DoStatement(loc, body, condition); - break; - } - - case TOKfor: - { - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value == TOKsemicolon) - { init = NULL; - nextToken(); - } - else - { init = parseStatement(0); - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - enum TOK op = token.value; - Arguments *arguments; - - Statement *d; - Statement *body; - Expression *aggr; - - nextToken(); - check(TOKlparen); - - arguments = new Arguments(); - - while (1) - { - Type *tb; - Identifier *ai = NULL; - Type *at; - unsigned storageClass; - Argument *a; - - storageClass = 0; - if (token.value == TOKinout || token.value == TOKref) - { storageClass = STCref; - nextToken(); - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - at = parseType(&ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - a = new Argument(storageClass, at, ai, NULL); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon); - - aggr = parseExpression(); - if (token.value == TOKslice && arguments->dim == 1) - { - Argument *a = (Argument *)arguments->data[0]; - delete arguments; - nextToken(); - Expression *upr = parseExpression(); - check(TOKrparen); - body = parseStatement(0); - s = new ForeachRangeStatement(loc, op, a, aggr, upr, body); - } - else - { - check(TOKrparen); - body = parseStatement(0); - s = new ForeachStatement(loc, op, arguments, aggr, body); - } - break; - } - - case TOKif: - { Argument *arg = NULL; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - nextToken(); - check(TOKlparen); - - if (token.value == TOKauto) - { - nextToken(); - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKassign) - { - arg = new Argument(0, NULL, token.ident, NULL); - nextToken(); - nextToken(); - } - else - { error("= expected following auto identifier"); - goto Lerror; - } - } - else - { error("identifier expected following auto"); - goto Lerror; - } - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Type *at; - Identifier *ai; - - at = parseType(&ai); - check(TOKassign); - arg = new Argument(0, at, ai, NULL); - } - - // Check for " ident;" - else if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { - arg = new Argument(0, NULL, token.ident, NULL); - nextToken(); - nextToken(); - if (1 || !global.params.useDeprecated) - error("if (v; e) is deprecated, use if (auto v = e)"); - } - } - - condition = parseExpression(); - check(TOKrparen); - ifbody = parseStatement(PSscope); - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(PSscope); - } - else - elsebody = NULL; - s = new IfStatement(loc, arg, condition, ifbody, elsebody); - break; - } - - case TOKscope: - if (peek(&token)->value != TOKlparen) - goto Ldeclaration; // scope used as storage class - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("scope identifier expected"); - goto Lerror; - } - else - { TOK t = TOKon_scope_exit; - Identifier *id = token.ident; - - if (id == Id::exit) - t = TOKon_scope_exit; - else if (id == Id::failure) - t = TOKon_scope_failure; - else if (id == Id::success) - t = TOKon_scope_success; - else - error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - Statement *st = parseStatement(PScurlyscope); - s = new OnScopeStatement(loc, t, st); - break; - } - - case TOKdebug: - nextToken(); - condition = parseDebugCondition(); - goto Lcondition; - - case TOKversion: - nextToken(); - condition = parseVersionCondition(); - goto Lcondition; - - Lcondition: - ifbody = parseStatement(0 /*PSsemi*/); - elsebody = NULL; - if (token.value == TOKelse) - { - nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); - } - s = new ConditionalStatement(loc, condition, ifbody, elsebody); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - isfinal = FALSE; - goto Lswitch; - - Lswitch: - { - nextToken(); - check(TOKlparen); - Expression *condition = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body, isfinal); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Array cases; // array of Expression's - Expression *last = NULL; - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon); - -#if DMDV2 - /* case exp: .. case last: - */ - if (token.value == TOKslice) - { - if (cases.dim > 1) - error("only one case allowed for start of case range"); - nextToken(); - check(TOKcase); - last = parseAssignExp(); - check(TOKcolon); - } -#endif - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - -#if DMDV2 - if (last) - { - s = new CaseRangeStatement(loc, exp, last, s); - } - else -#endif - { - // Keep cases in order by building the case statements backwards - for (int i = cases.dim; i; i--) - { - exp = (Expression *)cases.data[i - 1]; - s = new CaseStatement(loc, exp, s); - } - } - break; - } - - case TOKdefault: - { - Statements *statements; - - nextToken(); - check(TOKcolon); - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - s = new DefaultStatement(loc, s); - break; - } - - case TOKreturn: - { Expression *exp; - - nextToken(); - if (token.value == TOKsemicolon) - exp = NULL; - else - exp = parseExpression(); - check(TOKsemicolon, "return statement"); - s = new ReturnStatement(loc, exp); - break; - } - - case TOKbreak: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "break statement"); - s = new BreakStatement(loc, ident); - break; - } - - case TOKcontinue: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "continue statement"); - s = new ContinueStatement(loc, ident); - break; - } - - case TOKgoto: - { Identifier *ident; - - nextToken(); - if (token.value == TOKdefault) - { - nextToken(); - s = new GotoDefaultStatement(loc); - } - else if (token.value == TOKcase) - { - Expression *exp = NULL; - - nextToken(); - if (token.value != TOKsemicolon) - exp = parseExpression(); - s = new GotoCaseStatement(loc, exp); - } - else - { - if (token.value != TOKidentifier) - { error("Identifier expected following goto"); - ident = NULL; - } - else - { ident = token.ident; - nextToken(); - } - s = new GotoStatement(loc, ident); - } - check(TOKsemicolon, "goto statement"); - break; - } - - case TOKsynchronized: - { Expression *exp; - Statement *body; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseExpression(); - check(TOKrparen); - } - else - exp = NULL; - body = parseStatement(PSscope); - s = new SynchronizedStatement(loc, exp, body); - break; - } - - case TOKwith: - { Expression *exp; - Statement *body; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WithStatement(loc, exp, body); - break; - } - - case TOKtry: - { Statement *body; - Array *catches = NULL; - Statement *finalbody = NULL; - - nextToken(); - body = parseStatement(PSscope); - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlcurly) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen); - id = NULL; - t = parseType(&id); - check(TOKrparen); - } - handler = parseStatement(0); - c = new Catch(loc, t, id, handler); - if (!catches) - catches = new Array(); - catches->push(c); - } - - if (token.value == TOKfinally) - { nextToken(); - finalbody = parseStatement(0); - } - - s = body; - if (!catches && !finalbody) - error("catch or finally expected following try"); - else - { if (catches) - s = new TryCatchStatement(loc, body, catches); - if (finalbody) - s = new TryFinallyStatement(loc, s, finalbody); - } - break; - } - - case TOKthrow: - { Expression *exp; - - nextToken(); - exp = parseExpression(); - check(TOKsemicolon, "throw statement"); - s = new ThrowStatement(loc, exp); - break; - } - - case TOKvolatile: - nextToken(); - s = parseStatement(PSsemi | PScurlyscope); -#if DMDV2 - if (!global.params.useDeprecated) - error("volatile statements deprecated; used synchronized statements instead"); -#endif - s = new VolatileStatement(loc, s); - break; - - case TOKasm: - { Statements *statements; - Identifier *label; - Loc labelloc; - Token *toklist; - Token **ptoklist; - - // Parse the asm block into a sequence of AsmStatements, - // each AsmStatement is one instruction. - // Separate out labels. - // Defer parsing of AsmStatements until semantic processing. - - nextToken(); - check(TOKlcurly); - toklist = NULL; - ptoklist = &toklist; - label = NULL; - statements = new Statements(); - while (1) - { - switch (token.value) - { - case TOKidentifier: - if (!toklist) - { - // Look ahead to see if it is a label - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - label = token.ident; - labelloc = this->loc; - nextToken(); - nextToken(); - continue; - } - } - goto Ldefault; - - case TOKrcurly: - if (toklist || label) - { - error("asm statements must end in ';'"); - } - break; - - case TOKsemicolon: - s = NULL; - if (toklist || label) - { // Create AsmStatement from list of tokens we've saved - s = new AsmStatement(this->loc, toklist); - toklist = NULL; - ptoklist = &toklist; - if (label) - { s = new LabelStatement(labelloc, label, s); - label = NULL; - } - statements->push(s); - } - nextToken(); - continue; - - case TOKeof: - /* { */ - error("matching '}' expected, not end of file"); - break; - - default: - Ldefault: - *ptoklist = new Token(); - memcpy(*ptoklist, &token, sizeof(Token)); - ptoklist = &(*ptoklist)->next; - *ptoklist = NULL; - - nextToken(); - continue; - } - break; - } - s = new AsmBlockStatement(loc, statements); - nextToken(); - break; - } - - default: - error("found '%s' instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - - return s; -} - -void Parser::check(enum TOK value) -{ - check(loc, value); -} - -void Parser::check(Loc loc, enum TOK value) -{ - if (token.value != value) - error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(enum TOK value, const char *string) -{ - if (token.value != value) - error("found '%s' when expecting '%s' following '%s'", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - * Output: - * if *pt is not NULL, it is set to the ending token, which would be endtok - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - -#if DMDV2 - if ((t->value == TOKconst || - t->value == TOKinvariant || - t->value == TOKimmutable || - t->value == TOKshared) && - peek(t)->value != TOKlparen) - { /* const type - * immutable type - * shared type - */ - t = peek(t); - } -#endif - - if (!isBasicType(&t)) - { - goto Lisnot; - } - if (!isDeclarator(&t, &haveId, endtok)) - goto Lisnot; - if ( needId == 1 || - (needId == 0 && !haveId) || - (needId == 2 && haveId)) - { if (pt) - *pt = t; - goto Lis; - } - else - goto Lisnot; - -Lis: - //printf("\tis declaration, t = %s\n", t->toChars()); - return TRUE; - -Lisnot: - //printf("\tis not declaration\n"); - return FALSE; -} - -int Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - Token *t2; - int parens; - int haveId = 0; - - switch (t->value) - { - CASE_BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - L5: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - /* Seen a ! - * Look for: - * !( args ), !identifier, etc. - */ - t = peek(t); - switch (t->value) - { case TOKidentifier: - goto L5; - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - break; - CASE_BASIC_TYPES: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKfile: - case TOKline: - goto L2; - default: - goto Lfalse; - } - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - /* typeof(exp).identifier... - */ - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - goto L2; - - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - // const(type) or immutable(type) or shared(type) - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - { - goto Lfalse; - } - t = peek(t); - break; - - default: - goto Lfalse; - } - *pt = t; - //printf("is\n"); - return TRUE; - -Lfalse: - //printf("is not\n"); - return FALSE; -} - -int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) -{ // This code parallels parseDeclarator() - Token *t = *pt; - int parens; - - //printf("Parser::isDeclarator()\n"); - //t->print(); - if (t->value == TOKassign) - return FALSE; - - while (1) - { - parens = FALSE; - switch (t->value) - { - case TOKmul: - //case TOKand: - t = peek(t); - continue; - - case TOKlbracket: - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - // [ expression .. expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value == TOKslice) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; - - case TOKidentifier: - if (*haveId) - return FALSE; - *haveId = TRUE; - t = peek(t); - break; - - case TOKlparen: - t = peek(t); - - if (t->value == TOKrparen) - return FALSE; // () is not a declarator - - /* Regard ( identifier ) as not a declarator - * BUG: what about ( *identifier ) in - * f(*p)(x); - * where f is a class instance with overloaded () ? - * Should we just disallow C-style function pointer declarations? - */ - if (t->value == TOKidentifier) - { Token *t2 = peek(t); - if (t2->value == TOKrparen) - return FALSE; - } - - - if (!isDeclarator(&t, haveId, TOKrparen)) - return FALSE; - t = peek(t); - parens = TRUE; - break; - - case TOKdelegate: - case TOKfunction: - t = peek(t); - if (!isParameters(&t)) - return FALSE; - continue; - } - break; - } - - while (1) - { - switch (t->value) - { -#if CARRAYDECL - case TOKlbracket: - parens = FALSE; - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; -#endif - - case TOKlparen: - parens = FALSE; - if (!isParameters(&t)) - return FALSE; -#if DMDV2 - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKpure: - case TOKnothrow: - t = peek(t); - continue; - case TOKat: - t = peek(t); // skip '@' - t = peek(t); // skip identifier - continue; - default: - break; - } - break; - } -#endif - continue; - - // Valid tokens that follow a declaration - case TOKrparen: - case TOKrbracket: - case TOKassign: - case TOKcomma: - case TOKsemicolon: - case TOKlcurly: - case TOKin: - // The !parens is to disallow unnecessary parentheses - if (!parens && (endtok == TOKreserved || endtok == t->value)) - { *pt = t; - return TRUE; - } - return FALSE; - - default: - return FALSE; - } - } -} - - -int Parser::isParameters(Token **pt) -{ // This code parallels parseParameters() - Token *t = *pt; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - for (;1; t = peek(t)) - { - L1: - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKinout: - case TOKref: - case TOKlazy: - case TOKfinal: - continue; - - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - t = peek(t); - if (t->value == TOKlparen) - { - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - return FALSE; - t = peek(t); // skip past closing ')' - goto L2; - } - goto L1; - -#if 0 - case TOKstatic: - continue; - case TOKauto: - case TOKalias: - t = peek(t); - if (t->value == TOKidentifier) - t = peek(t); - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - goto L3; -#endif - - default: - { if (!isBasicType(&t)) - return FALSE; - L2: - int tmp = FALSE; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, TOKreserved)) - return FALSE; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - } - L3: - if (t->value == TOKcomma) - { - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return FALSE; - t = peek(t); - *pt = t; - return TRUE; -} - -int Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - int curlynest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - return FALSE; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - return FALSE; - - case TOKeof: - return FALSE; - - default: - continue; - } - break; - } - - *pt = t; - return TRUE; -} - -/********************************************** - * Skip over - * instance foo.bar(parameters...) - * Output: - * if (pt), *pt is set to the token following the closing ) - * Returns: - * 1 it's valid instance syntax - * 0 invalid instance syntax - */ - -int Parser::isTemplateInstance(Token *t, Token **pt) -{ - t = peek(t); - if (t->value != TOKdot) - { - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - while (t->value == TOKdot) - { - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - if (t->value != TOKlparen) - goto Lfalse; - - // Skip over the template arguments - while (1) - { - while (1) - { - t = peek(t); - switch (t->value) - { - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - continue; - case TOKrparen: - break; - case TOKcomma: - break; - case TOKeof: - case TOKsemicolon: - goto Lfalse; - default: - continue; - } - break; - } - - if (t->value != TOKcomma) - break; - } - if (t->value != TOKrparen) - goto Lfalse; - t = peek(t); - if (pt) - *pt = t; - return 1; - -Lfalse: - return 0; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipParens(Token *t, Token **pt) -{ - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - case TOKsemicolon: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lfalse: - return 0; -} - -/********************************* Expression Parser ***************************/ - -Expression *Parser::parsePrimaryExp() -{ Expression *e; - Type *t; - Identifier *id; - enum TOK save; - Loc loc = this->loc; - - //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); - switch (token.value) - { - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot && peekNext() != TOKis) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - - case TOKdollar: - if (!inBrackets) - error("'$' is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); - nextToken(); - break; - - case TOKint64v: - e = new IntegerExp(loc, token.int64value, Type::tint64); - nextToken(); - break; - - case TOKuns64v: - e = new IntegerExp(loc, token.uns64value, Type::tuns64); - nextToken(); - break; - - case TOKfloat32v: - e = new RealExp(loc, token.float80value, Type::tfloat32); - nextToken(); - break; - - case TOKfloat64v: - e = new RealExp(loc, token.float80value, Type::tfloat64); - nextToken(); - break; - - case TOKfloat80v: - e = new RealExp(loc, token.float80value, Type::tfloat80); - nextToken(); - break; - - case TOKimaginary32v: - e = new RealExp(loc, token.float80value, Type::timaginary32); - nextToken(); - break; - - case TOKimaginary64v: - e = new RealExp(loc, token.float80value, Type::timaginary64); - nextToken(); - break; - - case TOKimaginary80v: - e = new RealExp(loc, token.float80value, Type::timaginary80); - nextToken(); - break; - - case TOKnull: - e = new NullExp(loc); - nextToken(); - break; - -#if DMDV2 - case TOKfile: - { const char *s = loc.filename ? loc.filename : mod->ident->toChars(); - e = new StringExp(loc, (char *)s, strlen(s), 0); - nextToken(); - break; - } - - case TOKline: - e = new IntegerExp(loc, loc.linnum, Type::tint32); - nextToken(); - break; -#endif - - case TOKtrue: - e = new IntegerExp(loc, 1, Type::tbool); - nextToken(); - break; - - case TOKfalse: - e = new IntegerExp(loc, 0, Type::tbool); - nextToken(); - break; - - case TOKcharv: - e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); - nextToken(); - break; - - case TOKstring: - { unsigned char *s; - unsigned len; - unsigned char postfix; - - // cat adjacent strings - s = token.ustring; - len = token.len; - postfix = token.postfix; - while (1) - { - nextToken(); - if (token.value == TOKstring) - { unsigned len1; - unsigned len2; - unsigned char *s2; - - if (token.postfix) - { if (token.postfix != postfix) - error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); - postfix = token.postfix; - } - - len1 = len; - len2 = token.len; - len = len1 + len2; - s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); - memcpy(s2, s, len1 * sizeof(unsigned char)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); - s = s2; - } - else - break; - } - e = new StringExp(loc, s, len, postfix); - break; - } - - CASE_BASIC_TYPES_X(t): - nextToken(); - L1: - check(TOKdot, t->toChars()); - if (token.value != TOKidentifier) - { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars()); - goto Lerr; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { - t = parseTypeof(); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { Type *t; - - nextToken(); - check(TOKlparen, "typeid"); - t = parseType(); // ( type ) - check(TOKrparen); - e = new TypeidExp(loc, t); - break; - } - -#if DMDV2 - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList2(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } -#endif - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - TemplateParameters *tpl = NULL; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseType(&ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKtypedef || - token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || -#if DMDV2 - token.value == TOKconst && peek(&token)->value == TOKrparen || - token.value == TOKinvariant && peek(&token)->value == TOKrparen || - token.value == TOKimmutable && peek(&token)->value == TOKrparen || - token.value == TOKshared && peek(&token)->value == TOKrparen || -#endif - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseType(); - } - } - if (ident && tspec) - { - if (token.value == TOKcomma) - tpl = parseTemplateParameterList(1); - else - { tpl = new TemplateParameters(); - check(TOKrparen); - } - TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL); - tpl->insert(0, tp); - } - else - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - nextToken(); - check(TOKlparen, "mixin"); - e = parseAssignExp(); - check(TOKrparen); - e = new CompileExp(loc, e); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new FileExp(loc, e); - break; - } - - case TOKlparen: - if (peekPastParen(&token)->value == TOKlcurly) - { // (arguments) { statements... } - save = TOKdelegate; - goto case_delegate; - } - // ( expression ) - nextToken(); - e = parseExpression(); - check(loc, TOKrparen); - break; - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - if (token.value != TOKrbracket) - { - while (token.value != TOKeof) - { - Expression *e = parseAssignExp(); - if (token.value == TOKcolon && (keys || values->dim == 0)) - { nextToken(); - if (!keys) - keys = new Expressions(); - keys->push(e); - e = parseAssignExp(); - } - else if (keys) - { error("'key:value' expected for associative array literal"); - delete keys; - keys = NULL; - } - values->push(e); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - } - check(TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, values); - break; - } - - case TOKlcurly: - // { statements... } - save = TOKdelegate; - goto case_delegate; - - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - case_delegate: - { - /* function type(parameters) { body } pure nothrow - * delegate type(parameters) { body } pure nothrow - * (parameters) { body } - * { body } - */ - Arguments *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; - bool isnothrow = false; - bool ispure = false; - - if (token.value == TOKlcurly) - { - t = NULL; - varargs = 0; - arguments = new Arguments(); - } - else - { - if (token.value == TOKlparen) - t = NULL; - else - { - t = parseBasicType(); - t = parseBasicType2(t); // function return type - } - arguments = parseParameters(&varargs); - while (1) - { - if (token.value == TOKpure) - ispure = true; - else if (token.value == TOKnothrow) - isnothrow = true; - else - break; - nextToken(); - } - } - - TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage); - tf->ispure = ispure; - tf->isnothrow = isnothrow; - fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); - parseContracts(fd); - e = new FuncExp(loc, fd); - break; - } - - default: - error("expression expected, not '%s'", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return e; -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = this->loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peekNext() != TOKis) - { // identifier!(template-argument-list) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - e = new DotTemplateInstanceExp(loc, e, tempinst); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following '.', not '%s'", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - - inBrackets++; - nextToken(); - if (token.value == TOKrbracket) - { // array[] - e = new SliceExp(loc, e, NULL, NULL); - nextToken(); - } - else - { - index = parseAssignExp(); - if (token.value == TOKslice) - { // array[lwr .. upr] - nextToken(); - upr = parseAssignExp(); - e = new SliceExp(loc, e, index, upr); - } - else - { // array[index, i2, i3, i4, ...] - Expressions *arguments = new Expressions(); - arguments->push(index); - if (token.value == TOKcomma) - { - nextToken(); - while (1) - { Expression *arg; - - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - } - e = new ArrayExp(loc, e, arguments); - } - check(TOKrbracket); - inBrackets--; - } - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e); - break; - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKcast: // cast(type) expression - { - nextToken(); - check(TOKlparen); - /* Look for cast(), cast(const), cast(immutable), - * cast(shared), cast(shared const) - */ - unsigned m; - if (token.value == TOKrparen) - { - m = 0; - goto Lmod1; - } - else if (token.value == TOKconst && peekNext() == TOKrparen) - { - m = MODconst; - goto Lmod2; - } - else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen) - { - m = MODinvariant; - goto Lmod2; - } - else if (token.value == TOKshared && peekNext() == TOKrparen) - { - m = MODshared; - goto Lmod2; - } - else if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() == TOKrparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() == TOKrparen) - { - m = MODshared | MODconst; - nextToken(); - Lmod2: - nextToken(); - Lmod1: - nextToken(); - e = parseUnaryExp(); - e = new CastExp(loc, e, m); - } - else - { - Type *t = parseType(); // ( type ) - check(TOKrparen); - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - } - break; - } - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis) // !is - break; - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: -#if 0 - case TOKtilde: - case TOKand: - case TOKmul: - case TOKmin: - case TOKadd: -#endif - case TOKfunction: - case TOKdelegate: - case TOKtypeof: -#if DMDV2 - case TOKfile: - case TOKline: -#endif - CASE_BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseType(); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - } - } -#endif - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - default: - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - assert(e); - return e; -} - -Expression *Parser::parseMulExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseRelExp() -{ Expression *e; - Expression *e2; - enum TOK op; - Loc loc = this->loc; - - e = parseShiftExp(); - while (1) - { - switch (token.value) - { - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - op = token.value; - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - continue; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseEqualExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseRelExp(); - while (1) - { enum TOK value = token.value; - - switch (value) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseRelExp(); - e = new EqualExp(value, loc, e, e2); - continue; - - case TOKidentity: - error("'===' is no longer legal, use 'is' instead"); - goto L1; - - case TOKnotidentity: - error("'!==' is no longer legal, use '!is' instead"); - goto L1; - - case TOKis: - value = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - value = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseRelExp(); - e = new IdentityExp(value, loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseCmpExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseShiftExp(); - enum TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - if (global.params.Dversion == 1) - { - e = parseEqualExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseEqualExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - else - { - e = parseCmpExp(); - while (token.value == TOKand) - { - nextToken(); - e2 = parseCmpExp(); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - } - return e; -} - -Expression *Parser::parseXorExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndExp(); - while (token.value == TOKxor) - { - nextToken(); - e2 = parseAndExp(); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseXorExp(); - while (token.value == TOKor) - { - nextToken(); - e2 = parseXorExp(); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new AndAndExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new OrOrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ Expression *e; - Expression *e1; - Expression *e2; - Loc loc = this->loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = this->loc; - switch (token.value) - { -#define X(tok,ector) \ - case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; - - X(TOKassign, AssignExp); - X(TOKaddass, AddAssignExp); - X(TOKminass, MinAssignExp); - X(TOKmulass, MulAssignExp); - X(TOKdivass, DivAssignExp); - X(TOKmodass, ModAssignExp); - X(TOKandass, AndAssignExp); - X(TOKorass, OrAssignExp); - X(TOKxorass, XorAssignExp); - X(TOKshlass, ShlAssignExp); - X(TOKshrass, ShrAssignExp); - X(TOKushrass, UshrAssignExp); - X(TOKcatass, CatAssignExp); - -#undef X - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2); - loc = this->loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is ',', '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - enum TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - if (token.value != endtok) - { - while (1) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma); - } - } - check(endtok); - } - return arguments; -} - -/******************************************* - */ - -Expression *Parser::parseNewExp(Expression *thisexp) -{ Type *t; - Expressions *newargs; - Expressions *arguments = NULL; - Expression *e; - Loc loc = this->loc; - - nextToken(); - newargs = NULL; - if (token.value == TOKlparen) - { - newargs = parseArguments(); - } - - // An anonymous nested class starts with "class" - if (token.value == TOKclass) - { - nextToken(); - if (token.value == TOKlparen) - arguments = parseArguments(); - - BaseClasses *baseclasses = NULL; - if (token.value != TOKlcurly) - baseclasses = parseBaseClasses(); - - Identifier *id = NULL; - ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); - - if (token.value != TOKlcurly) - { error("{ members } expected for anonymous class"); - cd->members = NULL; - } - else - { - nextToken(); - Array *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("class member expected"); - nextToken(); - cd->members = decl; - } - - e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); - - return e; - } - - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { TypeAArray *taa = (TypeAArray *)t; - Type *index = taa->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(taa->next); - } - else - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - } - else if (t->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)t; - Expression *e = tsa->dim; - - arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(tsa->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - token.lineComment = NULL; -} - - -/********************************* ***************************/ - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +// This is the D parser + +#include +#include + +#include "rmem.h" +#include "lexer.h" +#include "parse.h" +#include "init.h" +#include "attrib.h" +#include "cond.h" +#include "mtype.h" +#include "template.h" +#include "staticassert.h" +#include "expression.h" +#include "statement.h" +#include "module.h" +#include "dsymbol.h" +#include "import.h" +#include "declaration.h" +#include "aggregate.h" +#include "enum.h" +#include "id.h" +#include "version.h" +#include "aliasthis.h" + +// How multiple declarations are parsed. +// If 1, treat as C. +// If 0, treat: +// int *p, i; +// as: +// int* p; +// int* i; +#define CDECLSYNTAX 0 + +// Support C cast syntax: +// (type)(expression) +#define CCASTSYNTAX 1 + +// Support postfix C array declarations, such as +// int a[3][4]; +#define CARRAYDECL 1 + +// Support D1 inout +#define D1INOUT 0 + +Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) + : Lexer(module, base, 0, length, doDocComment, 0) +{ + //printf("Parser::Parser()\n"); + md = NULL; + linkage = LINKd; + endloc = 0; + inBrackets = 0; + //nextToken(); // start up the scanner +} + +Dsymbols *Parser::parseModule() +{ + Dsymbols *decldefs; + + // ModuleDeclation leads off + if (token.value == TOKmodule) + { + unsigned char *comment = token.blockComment; + bool safe = FALSE; + + nextToken(); +#if 0 && DMDV2 + if (token.value == TOKlparen) + { + nextToken(); + if (token.value != TOKidentifier) + { error("module (system) identifier expected"); + goto Lerr; + } + Identifier *id = token.ident; + + if (id == Id::system) + safe = TRUE; + else + error("(safe) expected, not %s", id->toChars()); + nextToken(); + check(TOKrparen); + } +#endif + + if (token.value != TOKidentifier) + { error("Identifier expected following module"); + goto Lerr; + } + else + { + Array *a = NULL; + Identifier *id; + + id = token.ident; + while (nextToken() == TOKdot) + { + if (!a) + a = new Array(); + a->push(id); + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following package"); + goto Lerr; + } + id = token.ident; + } + + md = new ModuleDeclaration(a, id, safe); + + if (token.value != TOKsemicolon) + error("';' expected following module declaration instead of %s", token.toChars()); + nextToken(); + addComment(mod, comment); + } + } + + decldefs = parseDeclDefs(0); + if (token.value != TOKeof) + { error("unrecognized declaration"); + goto Lerr; + } + return decldefs; + +Lerr: + while (token.value != TOKsemicolon && token.value != TOKeof) + nextToken(); + nextToken(); + return new Dsymbols(); +} + +Dsymbols *Parser::parseDeclDefs(int once) +{ Dsymbol *s; + Dsymbols *decldefs; + Dsymbols *a; + Dsymbols *aelse; + enum PROT prot; + StorageClass stc; + StorageClass storageClass; + Condition *condition; + unsigned char *comment; + + //printf("Parser::parseDeclDefs()\n"); + decldefs = new Dsymbols(); + do + { + comment = token.blockComment; + storageClass = STCundefined; + switch (token.value) + { + case TOKenum: + { /* Determine if this is a manifest constant declaration, + * or a conventional enum. + */ + Token *t = peek(&token); + if (t->value == TOKlcurly || t->value == TOKcolon) + s = parseEnum(); + else if (t->value != TOKidentifier) + goto Ldeclaration; + else + { + t = peek(t); + if (t->value == TOKlcurly || t->value == TOKcolon || + t->value == TOKsemicolon) + s = parseEnum(); + else + goto Ldeclaration; + } + break; + } + + case TOKstruct: + case TOKunion: + case TOKclass: + case TOKinterface: + s = parseAggregate(); + break; + + case TOKimport: + s = parseImport(decldefs, 0); + break; + + case TOKtemplate: + s = (Dsymbol *)parseTemplateDeclaration(0); + break; + + case TOKmixin: + { Loc loc = this->loc; + switch (peekNext()) + { + case TOKlparen: + { // mixin(string) + nextToken(); + check(TOKlparen, "mixin"); + Expression *e = parseAssignExp(); + check(TOKrparen); + check(TOKsemicolon); + s = new CompileDeclaration(loc, e); + break; + } + case TOKtemplate: + // mixin template + nextToken(); + s = (Dsymbol *)parseTemplateDeclaration(1); + break; + + default: + s = parseMixin(); + break; + } + break; + } + + case BASIC_TYPES: + case TOKalias: + case TOKtypedef: + case TOKidentifier: + case TOKtypeof: + case TOKdot: + Ldeclaration: + a = parseDeclarations(STCundefined); + decldefs->append(a); + continue; + + case TOKthis: + s = parseCtor(); + break; + +#if 0 // dead end, use this(this){} instead + case TOKassign: + s = parsePostBlit(); + break; +#endif + case TOKtilde: + s = parseDtor(); + break; + + case TOKinvariant: + { Token *t; + t = peek(&token); + if (t->value == TOKlparen) + { + if (peek(t)->value == TOKrparen) + // invariant() forms start of class invariant + s = parseInvariant(); + else + // invariant(type) + goto Ldeclaration; + } + else + { + stc = STCimmutable; + goto Lstc; + } + break; + } + + case TOKunittest: + s = parseUnitTest(); + break; + + case TOKnew: + s = parseNew(); + break; + + case TOKdelete: + s = parseDelete(); + break; + + case TOKeof: + case TOKrcurly: + return decldefs; + + case TOKstatic: + nextToken(); + if (token.value == TOKthis) + s = parseStaticCtor(); + else if (token.value == TOKtilde) + s = parseStaticDtor(); + else if (token.value == TOKassert) + s = parseStaticAssert(); + else if (token.value == TOKif) + { condition = parseStaticIfCondition(); + a = parseBlock(); + aelse = NULL; + if (token.value == TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new StaticIfDeclaration(condition, a, aelse); + break; + } + else if (token.value == TOKimport) + { + s = parseImport(decldefs, 1); + } + else + { stc = STCstatic; + goto Lstc2; + } + break; + + case TOKconst: + if (peekNext() == TOKlparen) + goto Ldeclaration; + stc = STCconst; + goto Lstc; + + case TOKimmutable: + if (peekNext() == TOKlparen) + goto Ldeclaration; + stc = STCimmutable; + goto Lstc; + + case TOKshared: + { TOK next = peekNext(); + if (next == TOKlparen) + goto Ldeclaration; + if (next == TOKstatic) + { TOK next2 = peekNext2(); + if (next2 == TOKthis) + { s = parseSharedStaticCtor(); + break; + } + if (next2 == TOKtilde) + { s = parseSharedStaticDtor(); + break; + } + } + stc = STCshared; + goto Lstc; + } + + case TOKwild: + if (peekNext() == TOKlparen) + goto Ldeclaration; + stc = STCwild; + goto Lstc; + + case TOKfinal: stc = STCfinal; goto Lstc; + case TOKauto: stc = STCauto; goto Lstc; + case TOKscope: stc = STCscope; goto Lstc; + case TOKoverride: stc = STCoverride; goto Lstc; + case TOKabstract: stc = STCabstract; goto Lstc; + case TOKsynchronized: stc = STCsynchronized; goto Lstc; + case TOKdeprecated: stc = STCdeprecated; goto Lstc; +#if DMDV2 + case TOKnothrow: stc = STCnothrow; goto Lstc; + case TOKpure: stc = STCpure; goto Lstc; + case TOKref: stc = STCref; goto Lstc; + case TOKtls: stc = STCtls; goto Lstc; + case TOKgshared: stc = STCgshared; goto Lstc; + //case TOKmanifest: stc = STCmanifest; goto Lstc; + case TOKat: stc = parseAttribute(); goto Lstc; +#endif + + Lstc: + if (storageClass & stc) + error("redundant storage class %s", Token::toChars(token.value)); + composeStorageClass(storageClass | stc); + nextToken(); + Lstc2: + storageClass |= stc; + switch (token.value) + { + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + case TOKwild: + // If followed by a (, it is not a storage class + if (peek(&token)->value == TOKlparen) + break; + if (token.value == TOKconst) + stc = STCconst; + else if (token.value == TOKshared) + stc = STCshared; + else if (token.value == TOKwild) + stc = STCwild; + else + stc = STCimmutable; + goto Lstc; + case TOKfinal: stc = STCfinal; goto Lstc; + case TOKauto: stc = STCauto; goto Lstc; + case TOKscope: stc = STCscope; goto Lstc; + case TOKoverride: stc = STCoverride; goto Lstc; + case TOKabstract: stc = STCabstract; goto Lstc; + case TOKsynchronized: stc = STCsynchronized; goto Lstc; + case TOKdeprecated: stc = STCdeprecated; goto Lstc; + case TOKnothrow: stc = STCnothrow; goto Lstc; + case TOKpure: stc = STCpure; goto Lstc; + case TOKref: stc = STCref; goto Lstc; + case TOKtls: stc = STCtls; goto Lstc; + case TOKgshared: stc = STCgshared; goto Lstc; + //case TOKmanifest: stc = STCmanifest; goto Lstc; + case TOKat: stc = parseAttribute(); goto Lstc; + default: + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + a = parseAutoDeclarations(storageClass, comment); + decldefs->append(a); + continue; + } + + /* Look for return type inference for template functions. + */ + Token *tk; + if (token.value == TOKidentifier && + (tk = peek(&token))->value == TOKlparen && + skipParens(tk, &tk) && + (peek(tk)->value == TOKlparen || + peek(tk)->value == TOKlcurly) + ) + { + a = parseDeclarations(storageClass); + decldefs->append(a); + continue; + } + a = parseBlock(); + s = new StorageClassDeclaration(storageClass, a); + break; + + case TOKextern: + if (peek(&token)->value != TOKlparen) + { stc = STCextern; + goto Lstc; + } + { + enum LINK linksave = linkage; + linkage = parseLinkage(); + a = parseBlock(); + s = new LinkDeclaration(linkage, a); + linkage = linksave; + break; + } + case TOKprivate: prot = PROTprivate; goto Lprot; + case TOKpackage: prot = PROTpackage; goto Lprot; + case TOKprotected: prot = PROTprotected; goto Lprot; + case TOKpublic: prot = PROTpublic; goto Lprot; + case TOKexport: prot = PROTexport; goto Lprot; + + Lprot: + nextToken(); + switch (token.value) + { + case TOKprivate: + case TOKpackage: + case TOKprotected: + case TOKpublic: + case TOKexport: + error("redundant protection attribute"); + break; + } + a = parseBlock(); + s = new ProtDeclaration(prot, a); + break; + + case TOKalign: + { unsigned n; + + // LDC better align code locations + Loc alignloc = loc; + + s = NULL; + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + if (token.value == TOKint32v) + n = (unsigned)token.uns64value; + else + { error("integer expected, not %s", token.toChars()); + n = 1; + } + nextToken(); + check(TOKrparen); + } + else + n = global.structalign; // default + + a = parseBlock(); + s = new AlignDeclaration(alignloc, n, a); + break; + } + + case TOKpragma: + { Identifier *ident; + Expressions *args = NULL; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma && peekNext() != TOKrparen) + args = parseArguments(); // pragma(identifier, args...) + else + check(TOKrparen); // pragma(identifier) + + if (token.value == TOKsemicolon) + a = NULL; + else + a = parseBlock(); + s = new PragmaDeclaration(loc, ident, args, a); + break; + } + + case TOKdebug: + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value == TOKidentifier) + s = new DebugSymbol(loc, token.ident); + else if (token.value == TOKint32v) + s = new DebugSymbol(loc, (unsigned)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = NULL; + } + nextToken(); + if (token.value != TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + + condition = parseDebugCondition(); + goto Lcondition; + + case TOKversion: + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value == TOKidentifier) + s = new VersionSymbol(loc, token.ident); + else if (token.value == TOKint32v) + s = new VersionSymbol(loc, (unsigned)token.uns64value); + else + { error("identifier or integer expected, not %s", token.toChars()); + s = NULL; + } + nextToken(); + if (token.value != TOKsemicolon) + error("semicolon expected"); + nextToken(); + break; + } + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + a = parseBlock(); + aelse = NULL; + if (token.value == TOKelse) + { nextToken(); + aelse = parseBlock(); + } + s = new ConditionalDeclaration(condition, a, aelse); + break; + + case TOKsemicolon: // empty declaration + //error("empty declaration"); + nextToken(); + continue; + + default: + error("Declaration expected, not '%s'",token.toChars()); + Lerror: + while (token.value != TOKsemicolon && token.value != TOKeof) + nextToken(); + nextToken(); + s = NULL; + continue; + } + if (s) + { decldefs->push(s); + addComment(s, comment); + } + } while (!once); + return decldefs; +} + +/********************************************* + * Give error on conflicting storage classes. + */ + +#if DMDV2 +void Parser::composeStorageClass(StorageClass stc) +{ + StorageClass u = stc; + u &= STCconst | STCimmutable | STCmanifest; + if (u & (u - 1)) + error("conflicting storage class %s", Token::toChars(token.value)); + u = stc; + u &= STCgshared | STCshared | STCtls; + if (u & (u - 1)) + error("conflicting storage class %s", Token::toChars(token.value)); + u = stc; + u &= STCsafe | STCsystem | STCtrusted; + if (u & (u - 1)) + error("conflicting attribute @%s", token.toChars()); +} +#endif + +/*********************************************** + * Parse storage class, lexer is on '@' + */ + +#if DMDV2 +StorageClass Parser::parseAttribute() +{ + nextToken(); + StorageClass stc = 0; + if (token.value != TOKidentifier) + { + error("identifier expected after @, not %s", token.toChars()); + } + else if (token.ident == Id::property) + stc = STCproperty; + else if (token.ident == Id::safe) + stc = STCsafe; + else if (token.ident == Id::trusted) + stc = STCtrusted; + else if (token.ident == Id::system) + stc = STCsystem; + else if (token.ident == Id::disable) + stc = STCdisable; + else + error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars()); + return stc; +} +#endif + +/*********************************************** + * Parse const/immutable/shared/inout/nothrow/pure postfix + */ + +StorageClass Parser::parsePostfix() +{ + StorageClass stc = 0; + + while (1) + { + switch (token.value) + { + case TOKconst: stc |= STCconst; break; + case TOKinvariant: + if (!global.params.useDeprecated) + error("use of 'invariant' rather than 'immutable' is deprecated"); + case TOKimmutable: stc |= STCimmutable; break; + case TOKshared: stc |= STCshared; break; + case TOKwild: stc |= STCwild; break; + case TOKnothrow: stc |= STCnothrow; break; + case TOKpure: stc |= STCpure; break; + case TOKat: stc |= parseAttribute(); break; + + default: + composeStorageClass(stc); + return stc; + } + nextToken(); + } +} + +/******************************************** + * Parse declarations after an align, protection, or extern decl. + */ + +Dsymbols *Parser::parseBlock() +{ + Dsymbols *a = NULL; + Dsymbol *s; + + //printf("parseBlock()\n"); + switch (token.value) + { + case TOKsemicolon: + error("declaration expected following attribute, not ';'"); + nextToken(); + break; + + case TOKeof: + error("declaration expected following attribute, not EOF"); + break; + + case TOKlcurly: + nextToken(); + a = parseDeclDefs(0); + if (token.value != TOKrcurly) + { /* { */ + error("matching '}' expected, not %s", token.toChars()); + } + else + nextToken(); + break; + + case TOKcolon: + nextToken(); +#if 0 + a = NULL; +#else + a = parseDeclDefs(0); // grab declarations up to closing curly bracket +#endif + break; + + default: + a = parseDeclDefs(1); + break; + } + return a; +} + +/********************************** + * Parse a static assertion. + */ + +StaticAssert *Parser::parseStaticAssert() +{ + Loc loc = this->loc; + Expression *exp; + Expression *msg = NULL; + + //printf("parseStaticAssert()\n"); + nextToken(); + check(TOKlparen); + exp = parseAssignExp(); + if (token.value == TOKcomma) + { nextToken(); + msg = parseAssignExp(); + } + check(TOKrparen); + check(TOKsemicolon); + return new StaticAssert(loc, exp, msg); +} + +/*********************************** + * Parse typeof(expression). + * Current token is on the 'typeof'. + */ + +#if DMDV2 +TypeQualified *Parser::parseTypeof() +{ TypeQualified *t; + Loc loc = this->loc; + + nextToken(); + check(TOKlparen); + if (token.value == TOKreturn) // typeof(return) + { + nextToken(); + t = new TypeReturn(loc); + } + else + { Expression *exp = parseExpression(); // typeof(expression) + t = new TypeTypeof(loc, exp); + } + check(TOKrparen); + return t; +} +#endif + +/*********************************** + * Parse extern (linkage) + * The parser is on the 'extern' token. + */ + +enum LINK Parser::parseLinkage() +{ + enum LINK link = LINKdefault; + nextToken(); + assert(token.value == TOKlparen); + nextToken(); + if (token.value == TOKidentifier) + { Identifier *id = token.ident; + + nextToken(); + if (id == Id::Windows) + link = LINKwindows; + else if (id == Id::Pascal) + link = LINKpascal; + else if (id == Id::D) + link = LINKd; + else if (id == Id::C) + { + link = LINKc; + if (token.value == TOKplusplus) + { link = LINKcpp; + nextToken(); + } + } + else if (id == Id::System) + { + // LDC we configure target at runtime + if (global.params.os == OSWindows) + link = LINKwindows; + else + link = LINKc; + } + else + { + error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); + link = LINKd; + } + } + else + { + link = LINKd; // default + } + check(TOKrparen); + return link; +} + +/************************************** + * Parse a debug conditional + */ + +Condition *Parser::parseDebugCondition() +{ + Condition *c; + + if (token.value == TOKlparen) + { + nextToken(); + unsigned level = 1; + Identifier *id = NULL; + + if (token.value == TOKidentifier) + id = token.ident; + else if (token.value == TOKint32v) + level = (unsigned)token.uns64value; + else + error("identifier or integer expected, not %s", token.toChars()); + nextToken(); + check(TOKrparen); + c = new DebugCondition(mod, level, id); + } + else + c = new DebugCondition(mod, 1, NULL); + return c; + +} + +/************************************** + * Parse a version conditional + */ + +Condition *Parser::parseVersionCondition() +{ + Condition *c; + unsigned level = 1; + Identifier *id = NULL; + + if (token.value == TOKlparen) + { + nextToken(); + if (token.value == TOKidentifier) + id = token.ident; + else if (token.value == TOKint32v) + level = (unsigned)token.uns64value; +#if DMDV2 + /* Allow: + * version (unittest) + * even though unittest is a keyword + */ + else if (token.value == TOKunittest) + id = Lexer::idPool(Token::toChars(TOKunittest)); +#endif + else + error("identifier or integer expected, not %s", token.toChars()); + nextToken(); + check(TOKrparen); + + } + else + error("(condition) expected following version"); + c = new VersionCondition(mod, level, id); + return c; + +} + +/*********************************************** + * static if (expression) + * body + * else + * body + */ + +Condition *Parser::parseStaticIfCondition() +{ Expression *exp; + Condition *condition; + Array *aif; + Array *aelse; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + exp = parseAssignExp(); + check(TOKrparen); + } + else + { error("(expression) expected following static if"); + exp = NULL; + } + condition = new StaticIfCondition(loc, exp); + return condition; +} + + +/***************************************** + * Parse a constructor definition: + * this(parameters) { body } + * or postblit: + * this(this) { body } + * or constructor template: + * this(templateparameters)(parameters) { body } + * Current token is 'this'. + */ + +Dsymbol *Parser::parseCtor() +{ + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen && peek(&token)->value == TOKthis) + { // this(this) { ... } + nextToken(); + nextToken(); + check(TOKrparen); + PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0); + parseContracts(f); + return f; + } + + /* Look ahead to see if: + * this(...)(...) + * which is a constructor template + */ + TemplateParameters *tpl = NULL; + if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) + { tpl = parseTemplateParameterList(); + + int varargs; + Parameters *parameters = parseParameters(&varargs); + StorageClass stc = parsePostfix(); + + Expression *constraint = tpl ? parseConstraint() : NULL; + + CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc); + parseContracts(f); + + // Wrap a template around it + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(f); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs, 0); + return tempdecl; + } + + /* Just a regular constructor + */ + int varargs; + Parameters *parameters = parseParameters(&varargs); + StorageClass stc = parsePostfix(); + CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a postblit definition: + * =this() { body } + * Current token is '='. + */ + +PostBlitDeclaration *Parser::parsePostBlit() +{ + Loc loc = this->loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a destructor definition: + * ~this() { body } + * Current token is '~'. + */ + +DtorDeclaration *Parser::parseDtor() +{ + DtorDeclaration *f; + Loc loc = this->loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + f = new DtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a static constructor definition: + * static this() { body } + * Current token is 'this'. + */ + +StaticCtorDeclaration *Parser::parseStaticCtor() +{ + Loc loc = this->loc; + + nextToken(); + check(TOKlparen); + check(TOKrparen); + + StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a shared static constructor definition: + * shared static this() { body } + * Current token is 'shared'. + */ + +SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() +{ + Loc loc = this->loc; + + nextToken(); + nextToken(); + nextToken(); + check(TOKlparen); + check(TOKrparen); + + SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a static destructor definition: + * static ~this() { body } + * Current token is '~'. + */ + +StaticDtorDeclaration *Parser::parseStaticDtor() +{ + Loc loc = this->loc; + + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a shared static destructor definition: + * shared static ~this() { body } + * Current token is 'shared'. + */ + +SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() +{ + Loc loc = this->loc; + + nextToken(); + nextToken(); + nextToken(); + check(TOKthis); + check(TOKlparen); + check(TOKrparen); + + SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0); + parseContracts(f); + return f; +} + +/***************************************** + * Parse an invariant definition: + * invariant() { body } + * Current token is 'invariant'. + */ + +InvariantDeclaration *Parser::parseInvariant() +{ + InvariantDeclaration *f; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) // optional () + { + nextToken(); + check(TOKrparen); + } + + f = new InvariantDeclaration(loc, 0); + f->fbody = parseStatement(PScurly); + return f; +} + +/***************************************** + * Parse a unittest definition: + * unittest { body } + * Current token is 'unittest'. + */ + +UnitTestDeclaration *Parser::parseUnitTest() +{ + UnitTestDeclaration *f; + Statement *body; + Loc loc = this->loc; + + nextToken(); + + body = parseStatement(PScurly); + + f = new UnitTestDeclaration(loc, this->loc); + f->fbody = body; + return f; +} + +/***************************************** + * Parse a new definition: + * new(arguments) { body } + * Current token is 'new'. + */ + +NewDeclaration *Parser::parseNew() +{ + NewDeclaration *f; + Parameters *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + f = new NewDeclaration(loc, 0, arguments, varargs); + parseContracts(f); + return f; +} + +/***************************************** + * Parse a delete definition: + * delete(arguments) { body } + * Current token is 'delete'. + */ + +DeleteDeclaration *Parser::parseDelete() +{ + DeleteDeclaration *f; + Parameters *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + if (varargs) + error("... not allowed in delete function parameter list"); + f = new DeleteDeclaration(loc, 0, arguments); + parseContracts(f); + return f; +} + +/********************************************** + * Parse parameter list. + */ + +Parameters *Parser::parseParameters(int *pvarargs) +{ + Parameters *arguments = new Parameters(); + int varargs = 0; + int hasdefault = 0; + + check(TOKlparen); + while (1) + { Type *tb; + Identifier *ai = NULL; + Type *at; + Parameter *a; + StorageClass storageClass = 0; + StorageClass stc; + Expression *ae; + + for (;1; nextToken()) + { + switch (token.value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + varargs = 1; + nextToken(); + break; + + case TOKconst: + if (peek(&token)->value == TOKlparen) + goto Ldefault; + stc = STCconst; + goto L2; + + case TOKinvariant: + case TOKimmutable: + if (peek(&token)->value == TOKlparen) + goto Ldefault; + stc = STCimmutable; + goto L2; + + case TOKshared: + if (peek(&token)->value == TOKlparen) + goto Ldefault; + stc = STCshared; + goto L2; + + case TOKwild: + if (peek(&token)->value == TOKlparen) + goto Ldefault; + stc = STCwild; + goto L2; + + case TOKin: stc = STCin; goto L2; + case TOKout: stc = STCout; goto L2; +#if D1INOUT + case TOKinout: +#endif + case TOKref: stc = STCref; goto L2; + case TOKlazy: stc = STClazy; goto L2; + case TOKscope: stc = STCscope; goto L2; + case TOKfinal: stc = STCfinal; goto L2; + case TOKauto: stc = STCauto; goto L2; + L2: + if (storageClass & stc || + (storageClass & STCin && stc & (STCconst | STCscope)) || + (stc & STCin && storageClass & (STCconst | STCscope)) + ) + error("redundant storage class %s", Token::toChars(token.value)); + storageClass |= stc; + composeStorageClass(storageClass); + continue; + +#if 0 + case TOKstatic: stc = STCstatic; goto L2; + case TOKauto: storageClass = STCauto; goto L4; + case TOKalias: storageClass = STCalias; goto L4; + L4: + nextToken(); + if (token.value == TOKidentifier) + { ai = token.ident; + nextToken(); + } + else + ai = NULL; + at = NULL; // no type + ae = NULL; // no default argument + if (token.value == TOKassign) // = defaultArg + { nextToken(); + ae = parseDefaultInitExp(); + hasdefault = 1; + } + else + { if (hasdefault) + error("default argument expected for alias %s", + ai ? ai->toChars() : ""); + } + goto L3; +#endif + + default: + Ldefault: + stc = storageClass & (STCin | STCout | STCref | STClazy); + if (stc & (stc - 1)) // if stc is not a power of 2 + error("incompatible parameter storage classes"); + if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) + error("out cannot be const"); + if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout)) + error("out cannot be immutable"); + if ((storageClass & STCscope) && + (storageClass & (STCref | STCout))) + error("scope cannot be ref or out"); + at = parseType(&ai); + ae = NULL; + if (token.value == TOKassign) // = defaultArg + { nextToken(); + ae = parseDefaultInitExp(); + hasdefault = 1; + } + else + { if (hasdefault) + error("default argument expected for %s", + ai ? ai->toChars() : at->toChars()); + } + if (token.value == TOKdotdotdot) + { /* This is: + * at ai ... + */ + + if (storageClass & (STCout | STCref)) + error("variadic argument cannot be out or ref"); + varargs = 2; + a = new Parameter(storageClass, at, ai, ae); + arguments->push(a); + nextToken(); + break; + } + L3: + a = new Parameter(storageClass, at, ai, ae); + arguments->push(a); + if (token.value == TOKcomma) + { nextToken(); + goto L1; + } + break; + } + break; + } + break; + + L1: ; + } + check(TOKrparen); + *pvarargs = varargs; + return arguments; +} + + +/************************************* + */ + +EnumDeclaration *Parser::parseEnum() +{ EnumDeclaration *e; + Identifier *id; + Type *memtype; + Loc loc = this->loc; + + //printf("Parser::parseEnum()\n"); + nextToken(); + if (token.value == TOKidentifier) + { id = token.ident; + nextToken(); + } + else + id = NULL; + + if (token.value == TOKcolon) + { + nextToken(); + memtype = parseBasicType(); + memtype = parseDeclarator(memtype, NULL, NULL); + } + else + memtype = NULL; + + e = new EnumDeclaration(loc, id, memtype); + if (token.value == TOKsemicolon && id) + nextToken(); + else if (token.value == TOKlcurly) + { + //printf("enum definition\n"); + e->members = new Dsymbols(); + nextToken(); + unsigned char *comment = token.blockComment; + while (token.value != TOKrcurly) + { + /* Can take the following forms: + * 1. ident + * 2. ident = value + * 3. type ident = value + */ + + loc = this->loc; + + Type *type = NULL; + Identifier *ident; + Token *tp = peek(&token); + if (token.value == TOKidentifier && + (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly)) + { + ident = token.ident; + type = NULL; + nextToken(); + } + else + { + type = parseType(&ident, NULL); + if (id || memtype) + error("type only allowed if anonymous enum and no enum type"); + } + + Expression *value; + if (token.value == TOKassign) + { + nextToken(); + value = parseAssignExp(); + } + else + { value = NULL; + if (type) + error("if type, there must be an initializer"); + } + + EnumMember *em = new EnumMember(loc, ident, value, type); + e->members->push(em); + + if (token.value == TOKrcurly) + ; + else + { addComment(em, comment); + comment = NULL; + check(TOKcomma); + } + addComment(em, comment); + comment = token.blockComment; + } + nextToken(); + } + else + error("enum declaration is invalid"); + + //printf("-parseEnum() %s\n", e->toChars()); + return e; +} + +/******************************** + * Parse struct, union, interface, class. + */ + +Dsymbol *Parser::parseAggregate() +{ AggregateDeclaration *a = NULL; + int anon = 0; + enum TOK tok; + Identifier *id; + TemplateParameters *tpl = NULL; + Expression *constraint = NULL; + + //printf("Parser::parseAggregate()\n"); + tok = token.value; + nextToken(); + if (token.value != TOKidentifier) + { id = NULL; + } + else + { id = token.ident; + nextToken(); + + if (token.value == TOKlparen) + { // Class template declaration. + + // Gather template parameter list + tpl = parseTemplateParameterList(); + constraint = parseConstraint(); + } + } + + Loc loc = this->loc; + switch (tok) + { case TOKclass: + case TOKinterface: + { + if (!id) + error("anonymous classes not allowed"); + + // Collect base class(es) + BaseClasses *baseclasses = NULL; + if (token.value == TOKcolon) + { + nextToken(); + baseclasses = parseBaseClasses(); + + if (token.value != TOKlcurly) + error("members expected"); + } + + if (tok == TOKclass) + a = new ClassDeclaration(loc, id, baseclasses); + else + a = new InterfaceDeclaration(loc, id, baseclasses); + break; + } + + case TOKstruct: + if (id) + a = new StructDeclaration(loc, id); + else + anon = 1; + break; + + case TOKunion: + if (id) + a = new UnionDeclaration(loc, id); + else + anon = 2; + break; + + default: + assert(0); + break; + } + if (a && token.value == TOKsemicolon) + { nextToken(); + } + else if (token.value == TOKlcurly) + { + //printf("aggregate definition\n"); + nextToken(); + Dsymbols *decl = parseDeclDefs(0); + if (token.value != TOKrcurly) + error("} expected following member declarations in aggregate"); + nextToken(); + if (anon) + { + /* Anonymous structs/unions are more like attributes. + */ + return new AnonDeclaration(loc, anon - 1, decl); + } + else + a->members = decl; + } + else + { + error("{ } expected following aggregate declaration"); + a = new StructDeclaration(loc, NULL); + } + + if (tpl) + { // Wrap a template around the aggregate declaration + + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(a); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(loc, id, tpl, constraint, decldefs, 0); + return tempdecl; + } + + return a; +} + +/******************************************* + */ + +BaseClasses *Parser::parseBaseClasses() +{ + BaseClasses *baseclasses = new BaseClasses(); + + for (; 1; nextToken()) + { + enum PROT protection = PROTpublic; + switch (token.value) + { + case TOKprivate: + protection = PROTprivate; + nextToken(); + break; + case TOKpackage: + protection = PROTpackage; + nextToken(); + break; + case TOKprotected: + protection = PROTprotected; + nextToken(); + break; + case TOKpublic: + protection = PROTpublic; + nextToken(); + break; + } + if (token.value == TOKidentifier) + { + BaseClass *b = new BaseClass(parseBasicType(), protection); + baseclasses->push(b); + if (token.value != TOKcomma) + break; + } + else + { + error("base classes expected instead of %s", token.toChars()); + return NULL; + } + } + return baseclasses; +} + +/************************************** + * Parse constraint. + * Constraint is of the form: + * if ( ConstraintExpression ) + */ + +#if DMDV2 +Expression *Parser::parseConstraint() +{ Expression *e = NULL; + + if (token.value == TOKif) + { + nextToken(); // skip over 'if' + check(TOKlparen); + e = parseExpression(); + check(TOKrparen); + } + return e; +} +#endif + +/************************************** + * Parse a TemplateDeclaration. + */ + +TemplateDeclaration *Parser::parseTemplateDeclaration(int ismixin) +{ + TemplateDeclaration *tempdecl; + Identifier *id; + TemplateParameters *tpl; + Dsymbols *decldefs; + Expression *constraint = NULL; + Loc loc = this->loc; + + nextToken(); + if (token.value != TOKidentifier) + { error("TemplateIdentifier expected following template"); + goto Lerr; + } + id = token.ident; + nextToken(); + tpl = parseTemplateParameterList(); + if (!tpl) + goto Lerr; + + constraint = parseConstraint(); + + if (token.value != TOKlcurly) + { error("members of template declaration expected"); + goto Lerr; + } + else + { + nextToken(); + decldefs = parseDeclDefs(0); + if (token.value != TOKrcurly) + { error("template member expected"); + goto Lerr; + } + nextToken(); + } + + tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin); + return tempdecl; + +Lerr: + return NULL; +} + +/****************************************** + * Parse template parameter list. + * Input: + * flag 0: parsing "( list )" + * 1: parsing non-empty "list )" + */ + +TemplateParameters *Parser::parseTemplateParameterList(int flag) +{ + TemplateParameters *tpl = new TemplateParameters(); + + if (!flag && token.value != TOKlparen) + { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); + goto Lerr; + } + nextToken(); + + // Get array of TemplateParameters + if (flag || token.value != TOKrparen) + { int isvariadic = 0; + + while (token.value != TOKrparen) + { TemplateParameter *tp; + Identifier *tp_ident = NULL; + Type *tp_spectype = NULL; + Type *tp_valtype = NULL; + Type *tp_defaulttype = NULL; + Expression *tp_specvalue = NULL; + Expression *tp_defaultvalue = NULL; + Token *t; + + // Get TemplateParameter + + // First, look ahead to see if it is a TypeParameter or a ValueParameter + t = peek(&token); + if (token.value == TOKalias) + { // AliasParameter + nextToken(); + Type *spectype = NULL; + if (isDeclaration(&token, 2, TOKreserved, NULL)) + { + spectype = parseType(&tp_ident); + } + else + { + if (token.value != TOKidentifier) + { error("identifier expected for template alias parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + } + Object *spec = NULL; + if (token.value == TOKcolon) // : Type + { + nextToken(); + if (isDeclaration(&token, 0, TOKreserved, NULL)) + spec = parseType(); + else + spec = parseCondExp(); + } + Object *def = NULL; + if (token.value == TOKassign) // = Type + { + nextToken(); + if (isDeclaration(&token, 0, TOKreserved, NULL)) + def = parseType(); + else + def = parseCondExp(); + } + tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); + } + else if (t->value == TOKcolon || t->value == TOKassign || + t->value == TOKcomma || t->value == TOKrparen) + { // TypeParameter + if (token.value != TOKidentifier) + { error("identifier expected for template type parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseType(); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseType(); + } + tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } + else if (token.value == TOKidentifier && t->value == TOKdotdotdot) + { // ident... + if (isvariadic) + error("variadic template parameter must be last"); + isvariadic = 1; + tp_ident = token.ident; + nextToken(); + nextToken(); + tp = new TemplateTupleParameter(loc, tp_ident); + } +#if DMDV2 + else if (token.value == TOKthis) + { // ThisParameter + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected for template this parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseType(); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseType(); + } + tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } +#endif + else + { // ValueParameter + tp_valtype = parseType(&tp_ident); + if (!tp_ident) + { + error("identifier expected for template value parameter"); + tp_ident = new Identifier("error", TOKidentifier); + } + if (token.value == TOKcolon) // : CondExpression + { + nextToken(); + tp_specvalue = parseCondExp(); + } + if (token.value == TOKassign) // = CondExpression + { + nextToken(); + tp_defaultvalue = parseDefaultInitExp(); + } + tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); + } + tpl->push(tp); + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(TOKrparen); +Lerr: + return tpl; +} + +/****************************************** + * Parse template mixin. + * mixin Foo; + * mixin Foo!(args); + * mixin a.b.c!(args).Foo!(args); + * mixin Foo!(args) identifier; + * mixin typeof(expr).identifier!(args); + */ + +Dsymbol *Parser::parseMixin() +{ + TemplateMixin *tm; + Identifier *id; + Type *tqual; + Objects *tiargs; + Array *idents; + + //printf("parseMixin()\n"); + nextToken(); + tqual = NULL; + if (token.value == TOKdot) + { + id = Id::empty; + } + else + { + if (token.value == TOKtypeof) + { + tqual = parseTypeof(); + check(TOKdot); + } + if (token.value != TOKidentifier) + { + error("identifier expected, not %s", token.toChars()); + id = Id::empty; + } + else + id = token.ident; + nextToken(); + } + + idents = new Array(); + while (1) + { + tiargs = NULL; + if (token.value == TOKnot) + { + nextToken(); + if (token.value == TOKlparen) + tiargs = parseTemplateArgumentList(); + else + tiargs = parseTemplateArgument(); + } + + if (token.value != TOKdot) + break; + + if (tiargs) + { TemplateInstance *tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = tiargs; + id = (Identifier *)tempinst; + tiargs = NULL; + } + idents->push(id); + + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected following '.' instead of '%s'", token.toChars()); + break; + } + id = token.ident; + nextToken(); + } + idents->push(id); + + if (token.value == TOKidentifier) + { + id = token.ident; + nextToken(); + } + else + id = NULL; + + tm = new TemplateMixin(loc, id, tqual, idents, tiargs); + if (token.value != TOKsemicolon) + error("';' expected after mixin"); + nextToken(); + + return tm; +} + +/****************************************** + * Parse template argument list. + * Input: + * current token is opening '(' + * Output: + * current token is one after closing ')' + */ + +Objects *Parser::parseTemplateArgumentList() +{ + //printf("Parser::parseTemplateArgumentList()\n"); + if (token.value != TOKlparen && token.value != TOKlcurly) + { error("!(TemplateArgumentList) expected following TemplateIdentifier"); + return new Objects(); + } + return parseTemplateArgumentList2(); +} + +Objects *Parser::parseTemplateArgumentList2() +{ + //printf("Parser::parseTemplateArgumentList2()\n"); + Objects *tiargs = new Objects(); + enum TOK endtok = TOKrparen; + nextToken(); + + // Get TemplateArgumentList + while (token.value != endtok) + { + // See if it is an Expression or a Type + if (isDeclaration(&token, 0, TOKreserved, NULL)) + { // Template argument is a type + Type *ta = parseType(); + tiargs->push(ta); + } + else + { // Template argument is an expression + Expression *ea = parseAssignExp(); + + if (ea->op == TOKfunction) + { FuncLiteralDeclaration *fd = ((FuncExp *)ea)->fd; + if (fd->type->ty == Tfunction) + { + TypeFunction *tf = (TypeFunction *)fd->type; + /* If there are parameters that consist of only an identifier, + * rather than assuming the identifier is a type, as we would + * for regular function declarations, assume the identifier + * is the parameter name, and we're building a template with + * a deduced type. + */ + TemplateParameters *tpl = NULL; + for (int i = 0; i < tf->parameters->dim; i++) + { Parameter *param = (Parameter *)tf->parameters->data[i]; + if (param->ident == NULL && + param->type && + param->type->ty == Tident && + ((TypeIdentifier *)param->type)->idents.dim == 0 + ) + { + /* Switch parameter type to parameter identifier, + * parameterize with template type parameter _T + */ + TypeIdentifier *pt = (TypeIdentifier *)param->type; + param->ident = pt->ident; + Identifier *id = Lexer::uniqueId("__T"); + param->type = new TypeIdentifier(pt->loc, id); + TemplateParameter *tp = new TemplateTypeParameter(fd->loc, id, NULL, NULL); + if (!tpl) + tpl = new TemplateParameters(); + tpl->push(tp); + } + } + + if (tpl) + { // Wrap a template around function fd + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(fd); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0); + tempdecl->literal = 1; // it's a template 'literal' + tiargs->push(tempdecl); + goto L1; + } + } + } + + tiargs->push(ea); + } + L1: + if (token.value != TOKcomma) + break; + nextToken(); + } + check(endtok, "template argument list"); + return tiargs; +} + +/***************************** + * Parse single template argument, to support the syntax: + * foo!arg + * Input: + * current token is the arg + */ + +Objects *Parser::parseTemplateArgument() +{ + //printf("parseTemplateArgument()\n"); + Objects *tiargs = new Objects(); + Type *ta; + switch (token.value) + { + case TOKidentifier: + ta = new TypeIdentifier(loc, token.ident); + goto LabelX; + + case BASIC_TYPES_X(ta): + tiargs->push(ta); + nextToken(); + break; + + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKstring: + case TOKfile: + case TOKline: + { // Template argument is an expression + Expression *ea = parsePrimaryExp(); + tiargs->push(ea); + break; + } + + default: + error("template argument expected following !"); + break; + } + if (token.value == TOKnot) + error("multiple ! arguments are not allowed"); + return tiargs; +} + +Import *Parser::parseImport(Dsymbols *decldefs, int isstatic) +{ Import *s; + Identifier *id; + Identifier *aliasid = NULL; + Array *a; + Loc loc; + + //printf("Parser::parseImport()\n"); + do + { + L1: + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following import"); + break; + } + + loc = this->loc; + a = NULL; + id = token.ident; + nextToken(); + if (!aliasid && token.value == TOKassign) + { + aliasid = id; + goto L1; + } + while (token.value == TOKdot) + { + if (!a) + a = new Array(); + a->push(id); + nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected following package"); + break; + } + id = token.ident; + nextToken(); + } + + s = new Import(loc, a, id, aliasid, isstatic); + decldefs->push(s); + + /* Look for + * : alias=name, alias=name; + * syntax. + */ + if (token.value == TOKcolon) + { + do + { Identifier *name; + + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following :"); + break; + } + Identifier *alias = token.ident; + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following %s=", alias->toChars()); + break; + } + name = token.ident; + nextToken(); + } + else + { name = alias; + alias = NULL; + } + s->addAlias(name, alias); + } while (token.value == TOKcomma); + break; // no comma-separated imports of this form + } + + aliasid = NULL; + } while (token.value == TOKcomma); + + if (token.value == TOKsemicolon) + nextToken(); + else + { + error("';' expected"); + nextToken(); + } + + return NULL; +} + +#if DMDV2 +Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) +{ Type *t; + + /* Take care of the storage class prefixes that + * serve as type attributes: + * const shared, shared const, const, invariant, shared + */ + if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || + token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) + { + nextToken(); + nextToken(); + /* shared const type + */ + t = parseType(pident, tpl); + t = t->makeSharedConst(); + return t; + } + else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen || + token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen) + { + nextToken(); + nextToken(); + /* shared wild type + */ + t = parseType(pident, tpl); + t = t->makeSharedWild(); + return t; + } + else if (token.value == TOKconst && peekNext() != TOKlparen) + { + nextToken(); + /* const type + */ + t = parseType(pident, tpl); + t = t->makeConst(); + return t; + } + else if ((token.value == TOKinvariant || token.value == TOKimmutable) && + peekNext() != TOKlparen) + { + nextToken(); + /* invariant type + */ + t = parseType(pident, tpl); + t = t->makeInvariant(); + return t; + } + else if (token.value == TOKshared && peekNext() != TOKlparen) + { + nextToken(); + /* shared type + */ + t = parseType(pident, tpl); + t = t->makeShared(); + return t; + } + else if (token.value == TOKwild && peekNext() != TOKlparen) + { + nextToken(); + /* wild type + */ + t = parseType(pident, tpl); + t = t->makeWild(); + return t; + } + else + t = parseBasicType(); + t = parseDeclarator(t, pident, tpl); + return t; +} +#endif + +Type *Parser::parseBasicType() +{ Type *t; + Identifier *id; + TypeQualified *tid; + + //printf("parseBasicType()\n"); + switch (token.value) + { + case BASIC_TYPES_X(t): + nextToken(); + break; + + case TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOKnot) + { // ident!(template_arguments) + TemplateInstance *tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOKlparen) + // ident!(template_arguments) + tempinst->tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst->tiargs = parseTemplateArgument(); + tid = new TypeInstance(loc, tempinst); + goto Lident2; + } + Lident: + tid = new TypeIdentifier(loc, id); + Lident2: + while (token.value == TOKdot) + { nextToken(); + if (token.value != TOKidentifier) + { error("identifier expected following '.' instead of '%s'", token.toChars()); + break; + } + id = token.ident; + nextToken(); + if (token.value == TOKnot) + { + TemplateInstance *tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOKlparen) + // ident!(template_arguments) + tempinst->tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst->tiargs = parseTemplateArgument(); + tid->addIdent((Identifier *)tempinst); + } + else + tid->addIdent(id); + } + t = tid; + break; + + case TOKdot: + // Leading . as in .foo + id = Id::empty; + goto Lident; + + case TOKtypeof: + // typeof(expression) + tid = parseTypeof(); + goto Lident2; + + case TOKconst: + // const(type) + nextToken(); + check(TOKlparen); + t = parseType(); + check(TOKrparen); + if (t->isShared()) + t = t->makeSharedConst(); + else + t = t->makeConst(); + break; + + case TOKinvariant: + if (!global.params.useDeprecated) + error("use of 'invariant' rather than 'immutable' is deprecated"); + case TOKimmutable: + // invariant(type) + nextToken(); + check(TOKlparen); + t = parseType(); + check(TOKrparen); + t = t->makeInvariant(); + break; + + case TOKshared: + // shared(type) + nextToken(); + check(TOKlparen); + t = parseType(); + check(TOKrparen); + if (t->isConst()) + t = t->makeSharedConst(); + else if (t->isWild()) + t = t->makeSharedWild(); + else + t = t->makeShared(); + break; + + case TOKwild: + // wild(type) + nextToken(); + check(TOKlparen); + t = parseType(); + check(TOKrparen); + if (t->isShared()) + t = t->makeSharedWild(); + else + t = t->makeWild(); + break; + + default: + error("basic type expected, not %s", token.toChars()); + t = Type::tint32; + break; + } + return t; +} + +/****************************************** + * Parse things that follow the initial type t. + * t * + * t [] + * t [type] + * t [expression] + * t [expression .. expression] + * t function + * t delegate + */ + +Type *Parser::parseBasicType2(Type *t) +{ + //printf("parseBasicType2()\n"); + while (1) + { + switch (token.value) + { + case TOKmul: + t = new TypePointer(t); + nextToken(); + continue; + + case TOKlbracket: + // Handle []. Make sure things like + // int[3][1] a; + // is (array[1] of array[3] of int) + nextToken(); + if (token.value == TOKrbracket) + { + t = new TypeDArray(t); // [] + nextToken(); + } + else if (token.value == TOKnew && peekNext() == TOKrbracket) + { + t = new TypeNewArray(t); // [new] + nextToken(); + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array declaration + + //printf("it's an associative array\n"); + Type *index = parseType(); // [ type ] + t = new TypeAArray(t, index); + check(TOKrbracket); + } + else + { + //printf("it's type[expression]\n"); + inBrackets++; + Expression *e = parseAssignExp(); // [ expression ] + if (token.value == TOKslice) + { + nextToken(); + Expression *e2 = parseAssignExp(); // [ exp .. exp ] + t = new TypeSlice(t, e, e2); + } + else + t = new TypeSArray(t,e); + inBrackets--; + check(TOKrbracket); + } + continue; + + case TOKdelegate: + case TOKfunction: + { // Handle delegate declaration: + // t delegate(parameter list) nothrow pure + // t function(parameter list) nothrow pure + Parameters *arguments; + int varargs; + enum TOK save = token.value; + + nextToken(); + arguments = parseParameters(&varargs); + + StorageClass stc = parsePostfix(); + if (stc & (STCconst | STCimmutable | STCshared | STCwild)) + error("const/immutable/shared/inout attributes are only valid for non-static member functions"); + + TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc); + + if (save == TOKdelegate) + t = new TypeDelegate(tf); + else + t = new TypePointer(tf); // pointer to function + continue; + } + + default: + return t; + } + assert(0); + } + assert(0); + return NULL; +} + +Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) +{ Type *ts; + + //printf("parseDeclarator(tpl = %p)\n", tpl); + t = parseBasicType2(t); + + switch (token.value) + { + + case TOKidentifier: + if (pident) + *pident = token.ident; + else + error("unexpected identifer '%s' in declarator", token.ident->toChars()); + ts = t; + nextToken(); + break; + + case TOKlparen: + /* Parse things with parentheses around the identifier, like: + * int (*ident[3])[] + * although the D style would be: + * int[]*[3] ident + */ + nextToken(); + ts = parseDeclarator(t, pident); + check(TOKrparen); + break; + + default: + ts = t; + break; + } + + // parse DeclaratorSuffixes + while (1) + { + switch (token.value) + { +#if CARRAYDECL + /* Support C style array syntax: + * int ident[] + * as opposed to D-style: + * int[] ident + */ + case TOKlbracket: + { // This is the old C-style post [] syntax. + TypeNext *ta; + nextToken(); + if (token.value == TOKrbracket) + { // It's a dynamic array + ta = new TypeDArray(t); // [] + nextToken(); + } + else if (token.value == TOKnew && peekNext() == TOKrbracket) + { + t = new TypeNewArray(t); // [new] + nextToken(); + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array + + //printf("it's an associative array\n"); + Type *index = parseType(); // [ type ] + check(TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("It's a static array\n"); + Expression *e = parseAssignExp(); // [ expression ] + ta = new TypeSArray(t, e); + check(TOKrbracket); + } + + /* Insert ta into + * ts -> ... -> t + * so that + * ts -> ... -> ta -> t + */ + Type **pt; + for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) + ; + *pt = ta; + continue; + } +#endif + case TOKlparen: + { + if (tpl) + { + /* Look ahead to see if this is (...)(...), + * i.e. a function template declaration + */ + if (peekPastParen(&token)->value == TOKlparen) + { + //printf("function template declaration\n"); + + // Gather template parameter list + *tpl = parseTemplateParameterList(); + } + } + + int varargs; + Parameters *arguments = parseParameters(&varargs); + + /* Parse const/immutable/shared/inout/nothrow/pure postfix + */ + StorageClass stc = parsePostfix(); + Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc); + + if (stc & STCconst) + { if (tf->isShared()) + tf = tf->makeSharedConst(); + else + tf = tf->makeConst(); + } + if (stc & STCimmutable) + tf = tf->makeInvariant(); + if (stc & STCshared) + { if (tf->isConst()) + tf = tf->makeSharedConst(); + else + tf = tf->makeShared(); + } + if (stc & STCwild) + { if (tf->isShared()) + tf = tf->makeSharedWild(); + else + tf = tf->makeWild(); + } + + /* Insert tf into + * ts -> ... -> t + * so that + * ts -> ... -> tf -> t + */ + Type **pt; + for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) + ; + *pt = tf; + break; + } + } + break; + } + + return ts; +} + +/********************************** + * Parse Declarations. + * These can be: + * 1. declarations at global/class level + * 2. declarations at statement level + * Return array of Declaration *'s. + */ + +Dsymbols *Parser::parseDeclarations(StorageClass storage_class) +{ + StorageClass stc; + Type *ts; + Type *t; + Type *tfirst; + Identifier *ident; + Dsymbols *a; + enum TOK tok = TOKreserved; + unsigned char *comment = token.blockComment; + enum LINK link = linkage; + + //printf("parseDeclarations() %s\n", token.toChars()); + if (storage_class) + { ts = NULL; // infer type + goto L2; + } + + switch (token.value) + { + case TOKalias: + /* Look for: + * alias identifier this; + */ + tok = token.value; + nextToken(); + if (token.value == TOKidentifier && peek(&token)->value == TOKthis) + { + AliasThis *s = new AliasThis(this->loc, token.ident); + nextToken(); + check(TOKthis); + check(TOKsemicolon); + a = new Dsymbols(); + a->push(s); + addComment(s, comment); + return a; + } + break; + case TOKtypedef: + tok = token.value; + nextToken(); + break; + } + + storage_class = STCundefined; + while (1) + { + switch (token.value) + { + case TOKconst: + if (peek(&token)->value == TOKlparen) + break; // const as type constructor + stc = STCconst; // const as storage class + goto L1; + + case TOKinvariant: + case TOKimmutable: + if (peek(&token)->value == TOKlparen) + break; + stc = STCimmutable; + goto L1; + + case TOKshared: + if (peek(&token)->value == TOKlparen) + break; + stc = STCshared; + goto L1; + + case TOKwild: + if (peek(&token)->value == TOKlparen) + break; + stc = STCwild; + goto L1; + + case TOKstatic: stc = STCstatic; goto L1; + case TOKfinal: stc = STCfinal; goto L1; + case TOKauto: stc = STCauto; goto L1; + case TOKscope: stc = STCscope; goto L1; + case TOKoverride: stc = STCoverride; goto L1; + case TOKabstract: stc = STCabstract; goto L1; + case TOKsynchronized: stc = STCsynchronized; goto L1; + case TOKdeprecated: stc = STCdeprecated; goto L1; +#if DMDV2 + case TOKnothrow: stc = STCnothrow; goto L1; + case TOKpure: stc = STCpure; goto L1; + case TOKref: stc = STCref; goto L1; + case TOKtls: stc = STCtls; goto L1; + case TOKgshared: stc = STCgshared; goto L1; + case TOKenum: stc = STCmanifest; goto L1; + case TOKat: stc = parseAttribute(); goto L1; +#endif + L1: + if (storage_class & stc) + error("redundant storage class '%s'", token.toChars()); + storage_class = storage_class | stc; + composeStorageClass(storage_class); + nextToken(); + continue; + + case TOKextern: + if (peek(&token)->value != TOKlparen) + { stc = STCextern; + goto L1; + } + + link = parseLinkage(); + continue; + + default: + break; + } + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (storage_class && + token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + return parseAutoDeclarations(storage_class, comment); + } + + if (token.value == TOKclass) + { + AggregateDeclaration *s = (AggregateDeclaration *)parseAggregate(); + s->storage_class |= storage_class; + Dsymbols *a = new Dsymbols(); + a->push(s); + addComment(s, comment); + return a; + } + + /* Look for return type inference for template functions. + */ + { + Token *tk; + if (storage_class && + token.value == TOKidentifier && + (tk = peek(&token))->value == TOKlparen && + skipParens(tk, &tk) && + peek(tk)->value == TOKlparen) + { + ts = NULL; + } + else + { + ts = parseBasicType(); + ts = parseBasicType2(ts); + } + } + +L2: + tfirst = NULL; + a = new Dsymbols(); + + while (1) + { + Loc loc = this->loc; + TemplateParameters *tpl = NULL; + + ident = NULL; + t = parseDeclarator(ts, &ident, &tpl); + assert(t); + if (!tfirst) + tfirst = t; + else if (t != tfirst) + error("multiple declarations must have the same type, not %s and %s", + tfirst->toChars(), t->toChars()); + if (!ident) + error("no identifier for declarator %s", t->toChars()); + + if (tok == TOKtypedef || tok == TOKalias) + { Declaration *v; + Initializer *init = NULL; + + if (token.value == TOKassign) + { + nextToken(); + init = parseInitializer(); + } + if (tok == TOKtypedef) + v = new TypedefDeclaration(loc, ident, t, init); + else + { if (init) + error("alias cannot have initializer"); + v = new AliasDeclaration(loc, ident, t); + } + v->storage_class = storage_class; + if (link == linkage) + a->push(v); + else + { + Dsymbols *ax = new Dsymbols(); + ax->push(v); + Dsymbol *s = new LinkDeclaration(link, ax); + a->push(s); + } + switch (token.value) + { case TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected to close %s declaration", Token::toChars(tok)); + break; + } + } + else if (t->ty == Tfunction) + { + TypeFunction *tf = (TypeFunction *)t; + Expression *constraint = NULL; +#if 0 + if (Parameter::isTPL(tf->parameters)) + { + if (!tpl) + tpl = new TemplateParameters(); + } +#endif + FuncDeclaration *f = + new FuncDeclaration(loc, 0, ident, storage_class, t); + addComment(f, comment); + if (tpl) + constraint = parseConstraint(); + parseContracts(f); + addComment(f, NULL); + Dsymbol *s; + if (link == linkage) + { + s = f; + } + else + { + Dsymbols *ax = new Dsymbols(); + ax->push(f); + s = new LinkDeclaration(link, ax); + } + /* A template parameter list means it's a function template + */ + if (tpl) + { + // Wrap a template around the function declaration + Dsymbols *decldefs = new Dsymbols(); + decldefs->push(s); + TemplateDeclaration *tempdecl = + new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs, 0); + s = tempdecl; + } + addComment(s, comment); + a->push(s); + } + else + { + Initializer *init = NULL; + if (token.value == TOKassign) + { + nextToken(); + init = parseInitializer(); + } + + VarDeclaration *v = new VarDeclaration(loc, t, ident, init); + v->storage_class = storage_class; + if (link == linkage) + a->push(v); + else + { + Dsymbols *ax = new Dsymbols(); + ax->push(v); + Dsymbol *s = new LinkDeclaration(link, ax); + a->push(s); + } + switch (token.value) + { case TOKsemicolon: + nextToken(); + addComment(v, comment); + break; + + case TOKcomma: + nextToken(); + addComment(v, comment); + continue; + + default: + error("semicolon expected, not '%s'", token.toChars()); + break; + } + } + break; + } + return a; +} + +/***************************************** + * Parse auto declarations of the form: + * storageClass ident = init, ident = init, ... ; + * and return the array of them. + * Starts with token on the first ident. + * Ends with scanner past closing ';' + */ + +#if DMDV2 +Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment) +{ + Dsymbols *a = new Dsymbols; + + while (1) + { + Identifier *ident = token.ident; + nextToken(); // skip over ident + assert(token.value == TOKassign); + nextToken(); // skip over '=' + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = storageClass; + a->push(v); + if (token.value == TOKsemicolon) + { + nextToken(); + addComment(v, comment); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + addComment(v, comment); + continue; + } + else + error("Identifier expected following comma"); + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; + } + return a; +} +#endif + +/***************************************** + * Parse contracts following function declaration. + */ + +void Parser::parseContracts(FuncDeclaration *f) +{ + enum LINK linksave = linkage; + + // The following is irrelevant, as it is overridden by sc->linkage in + // TypeFunction::semantic + linkage = LINKd; // nested functions have D linkage +L1: + switch (token.value) + { + case TOKlcurly: + if (f->frequire || f->fensure) + error("missing body { ... } after in or out"); + f->fbody = parseStatement(PSsemi); + f->endloc = endloc; + break; + + case TOKbody: + nextToken(); + f->fbody = parseStatement(PScurly); + f->endloc = endloc; + break; + + case TOKsemicolon: + if (f->frequire || f->fensure) + error("missing body { ... } after in or out"); + nextToken(); + break; + +#if 0 // Do we want this for function declarations, so we can do: + // int x, y, foo(), z; + case TOKcomma: + nextToken(); + continue; +#endif + +#if 0 // Dumped feature + case TOKthrow: + if (!f->fthrows) + f->fthrows = new Array(); + nextToken(); + check(TOKlparen); + while (1) + { + Type *tb = parseBasicType(); + f->fthrows->push(tb); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOKrparen); + goto L1; +#endif + + case TOKin: + nextToken(); + if (f->frequire) + error("redundant 'in' statement"); + f->frequire = parseStatement(PScurly | PSscope); + goto L1; + + case TOKout: + // parse: out (identifier) { statement } + nextToken(); + if (token.value != TOKlcurly) + { + check(TOKlparen); + if (token.value != TOKidentifier) + error("(identifier) following 'out' expected, not %s", token.toChars()); + f->outId = token.ident; + nextToken(); + check(TOKrparen); + } + if (f->fensure) + error("redundant 'out' statement"); + f->fensure = parseStatement(PScurly | PSscope); + goto L1; + + default: + if (!f->frequire && !f->fensure) // allow these even with no body + error("semicolon expected following function declaration"); + break; + } + linkage = linksave; +} + +/***************************************** + * Parse initializer for variable declaration. + */ + +Initializer *Parser::parseInitializer() +{ + StructInitializer *is; + ArrayInitializer *ia; + ExpInitializer *ie; + Expression *e; + Identifier *id; + Initializer *value; + int comma; + Loc loc = this->loc; + Token *t; + int braces; + int brackets; + + switch (token.value) + { + case TOKlcurly: + /* Scan ahead to see if it is a struct initializer or + * a function literal. + * If it contains a ';', it is a function literal. + * Treat { } as a struct initializer. + */ + braces = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t->value) + { + case TOKsemicolon: + case TOKreturn: + goto Lexpression; + + case TOKlcurly: + braces++; + continue; + + case TOKrcurly: + if (--braces == 0) + break; + continue; + + case TOKeof: + break; + + default: + continue; + } + break; + } + + is = new StructInitializer(loc); + nextToken(); + comma = 0; + while (1) + { + switch (token.value) + { + case TOKidentifier: + if (comma == 1) + error("comma expected separating field initializers"); + t = peek(&token); + if (t->value == TOKcolon) + { + id = token.ident; + nextToken(); + nextToken(); // skip over ':' + } + else + { id = NULL; + } + value = parseInitializer(); + is->addInit(id, value); + comma = 1; + continue; + + case TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOKrcurly: // allow trailing comma's + nextToken(); + break; + + case TOKeof: + error("found EOF instead of initializer"); + break; + + default: + value = parseInitializer(); + is->addInit(NULL, value); + comma = 1; + continue; + //error("found '%s' instead of field initializer", token.toChars()); + //break; + } + break; + } + return is; + + case TOKlbracket: + /* Scan ahead to see if it is an array initializer or + * an expression. + * If it ends with a ';' ',' or '}', it is an array initializer. + */ + brackets = 1; + for (t = peek(&token); 1; t = peek(t)) + { + switch (t->value) + { + case TOKlbracket: + brackets++; + continue; + + case TOKrbracket: + if (--brackets == 0) + { t = peek(t); + if (t->value != TOKsemicolon && + t->value != TOKcomma && + t->value != TOKrbracket && + t->value != TOKrcurly) + goto Lexpression; + break; + } + continue; + + case TOKeof: + break; + + default: + continue; + } + break; + } + + ia = new ArrayInitializer(loc); + nextToken(); + comma = 0; + while (1) + { + switch (token.value) + { + default: + if (comma == 1) + { error("comma expected separating array initializers, not %s", token.toChars()); + nextToken(); + break; + } + e = parseAssignExp(); + if (!e) + break; + if (token.value == TOKcolon) + { + nextToken(); + value = parseInitializer(); + } + else + { value = new ExpInitializer(e->loc, e); + e = NULL; + } + ia->addInit(e, value); + comma = 1; + continue; + + case TOKlcurly: + case TOKlbracket: + if (comma == 1) + error("comma expected separating array initializers, not %s", token.toChars()); + value = parseInitializer(); + ia->addInit(NULL, value); + comma = 1; + continue; + + case TOKcomma: + nextToken(); + comma = 2; + continue; + + case TOKrbracket: // allow trailing comma's + nextToken(); + break; + + case TOKeof: + error("found '%s' instead of array initializer", token.toChars()); + break; + } + break; + } + return ia; + + case TOKvoid: + t = peek(&token); + if (t->value == TOKsemicolon || t->value == TOKcomma) + { + nextToken(); + return new VoidInitializer(loc); + } + goto Lexpression; + + default: + Lexpression: + e = parseAssignExp(); + ie = new ExpInitializer(loc, e); + return ie; + } +} + +/***************************************** + * Parses default argument initializer expression that is an assign expression, + * with special handling for __FILE__ and __LINE__. + */ + +#if DMDV2 +Expression *Parser::parseDefaultInitExp() +{ + if (token.value == TOKfile || + token.value == TOKline) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKrparen) + { Expression *e; + + if (token.value == TOKfile) + e = new FileInitExp(loc); + else + e = new LineInitExp(loc); + nextToken(); + return e; + } + } + + Expression *e = parseAssignExp(); + return e; +} +#endif + +/***************************************** + * Input: + * flags PSxxxx + */ + +Statement *Parser::parseStatement(int flags) +{ Statement *s; + Token *t; + Condition *condition; + Statement *ifbody; + Statement *elsebody; + bool isfinal; + Loc loc = this->loc; + + //printf("parseStatement()\n"); + + if (flags & PScurly && token.value != TOKlcurly) + error("statement expected to be { }, not %s", token.toChars()); + + switch (token.value) + { + case TOKidentifier: + /* A leading identifier can be a declaration, label, or expression. + * The easiest case to check first is label: + */ + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + + Identifier *ident = token.ident; + nextToken(); + nextToken(); + s = parseStatement(PSsemi); + s = new LabelStatement(loc, ident, s); + break; + } + // fallthrough to TOKdot + case TOKdot: + case TOKtypeof: + if (isDeclaration(&token, 2, TOKreserved, NULL)) + goto Ldeclaration; + else + goto Lexp; + break; + + case TOKassert: + case TOKthis: + case TOKsuper: + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKstring: + case TOKlparen: + case TOKcast: + case TOKmul: + case TOKmin: + case TOKadd: + case TOKtilde: + case TOKnot: + case TOKplusplus: + case TOKminusminus: + case TOKnew: + case TOKdelete: + case TOKdelegate: + case TOKfunction: + case TOKtypeid: + case TOKis: + case TOKlbracket: +#if DMDV2 + case TOKtraits: + case TOKfile: + case TOKline: +#endif + Lexp: + { + Expression *exp = parseExpression(); + check(TOKsemicolon, "statement"); + s = new ExpStatement(loc, exp); + break; + } + + case TOKstatic: + { // Look ahead to see if it's static assert() or static if() + Token *t; + + t = peek(&token); + if (t->value == TOKassert) + { + nextToken(); + s = new StaticAssertStatement(parseStaticAssert()); + break; + } + if (t->value == TOKif) + { + nextToken(); + condition = parseStaticIfCondition(); + goto Lcondition; + } + if (t->value == TOKstruct || t->value == TOKunion || t->value == TOKclass) + { + nextToken(); + Dsymbols *a = parseBlock(); + Dsymbol *d = new StorageClassDeclaration(STCstatic, a); + s = new DeclarationStatement(loc, d); + if (flags & PSscope) + s = new ScopeStatement(loc, s); + break; + } + goto Ldeclaration; + } + + case TOKfinal: + if (peekNext() == TOKswitch) + { + nextToken(); + isfinal = TRUE; + goto Lswitch; + } + goto Ldeclaration; + + case BASIC_TYPES: + case TOKtypedef: + case TOKalias: + case TOKconst: + case TOKauto: + case TOKextern: + case TOKinvariant: +#if DMDV2 + case TOKimmutable: + case TOKshared: + case TOKwild: + case TOKnothrow: + case TOKpure: + case TOKtls: + case TOKgshared: + case TOKat: +#endif +// case TOKtypeof: + Ldeclaration: + { Array *a; + + a = parseDeclarations(STCundefined); + if (a->dim > 1) + { + Statements *as = new Statements(); + as->reserve(a->dim); + for (int i = 0; i < a->dim; i++) + { + Dsymbol *d = (Dsymbol *)a->data[i]; + s = new DeclarationStatement(loc, d); + as->push(s); + } + s = new CompoundDeclarationStatement(loc, as); + } + else if (a->dim == 1) + { + Dsymbol *d = (Dsymbol *)a->data[0]; + s = new DeclarationStatement(loc, d); + } + else + assert(0); + if (flags & PSscope) + s = new ScopeStatement(loc, s); + break; + } + + case TOKstruct: + case TOKunion: + case TOKclass: + case TOKinterface: + { Dsymbol *d; + + d = parseAggregate(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOKenum: + { /* Determine if this is a manifest constant declaration, + * or a conventional enum. + */ + Dsymbol *d; + Token *t = peek(&token); + if (t->value == TOKlcurly || t->value == TOKcolon) + d = parseEnum(); + else if (t->value != TOKidentifier) + goto Ldeclaration; + else + { + t = peek(t); + if (t->value == TOKlcurly || t->value == TOKcolon || + t->value == TOKsemicolon) + d = parseEnum(); + else + goto Ldeclaration; + } + s = new DeclarationStatement(loc, d); + break; + } + + case TOKmixin: + { t = peek(&token); + if (t->value == TOKlparen) + { // mixin(string) + nextToken(); + check(TOKlparen, "mixin"); + Expression *e = parseAssignExp(); + check(TOKrparen); + check(TOKsemicolon); + s = new CompileStatement(loc, e); + break; + } + Dsymbol *d = parseMixin(); + s = new DeclarationStatement(loc, d); + break; + } + + case TOKlcurly: + { + nextToken(); + //if (token.value == TOKsemicolon) + //error("use '{ }' for an empty statement, not a ';'"); + Statements *statements = new Statements(); + while (token.value != TOKrcurly && token.value != TOKeof) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + endloc = this->loc; + s = new CompoundStatement(loc, statements); + if (flags & (PSscope | PScurlyscope)) + s = new ScopeStatement(loc, s); + check(TOKrcurly, "compound statement"); + break; + } + + case TOKwhile: + { Expression *condition; + Statement *body; + + nextToken(); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new WhileStatement(loc, condition, body); + break; + } + + case TOKsemicolon: + if (!(flags & PSsemi)) + error("use '{ }' for an empty statement, not a ';'"); + nextToken(); + s = new ExpStatement(loc, NULL); + break; + + case TOKdo: + { Statement *body; + Expression *condition; + + nextToken(); + body = parseStatement(PSscope); + check(TOKwhile); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + s = new DoStatement(loc, body, condition); + break; + } + + case TOKfor: + { + Statement *init; + Expression *condition; + Expression *increment; + Statement *body; + + nextToken(); + check(TOKlparen); + if (token.value == TOKsemicolon) + { init = NULL; + nextToken(); + } + else + { init = parseStatement(0); + } + if (token.value == TOKsemicolon) + { + condition = NULL; + nextToken(); + } + else + { + condition = parseExpression(); + check(TOKsemicolon, "for condition"); + } + if (token.value == TOKrparen) + { increment = NULL; + nextToken(); + } + else + { increment = parseExpression(); + check(TOKrparen); + } + body = parseStatement(PSscope); + s = new ForStatement(loc, init, condition, increment, body); + if (init) + s = new ScopeStatement(loc, s); + break; + } + + case TOKforeach: + case TOKforeach_reverse: + { + enum TOK op = token.value; + + nextToken(); + check(TOKlparen); + + Parameters *arguments = new Parameters(); + + while (1) + { + Identifier *ai = NULL; + Type *at; + + StorageClass storageClass = 0; + if (token.value == TOKref +#if D1INOUT + || token.value == TOKinout +#endif + ) + { storageClass = STCref; + nextToken(); + } + if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKsemicolon) + { ai = token.ident; + at = NULL; // infer argument type + nextToken(); + goto Larg; + } + } + at = parseType(&ai); + if (!ai) + error("no identifier for declarator %s", at->toChars()); + Larg: + Parameter *a = new Parameter(storageClass, at, ai, NULL); + arguments->push(a); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + check(TOKsemicolon); + + Expression *aggr = parseExpression(); + if (token.value == TOKslice && arguments->dim == 1) + { + Parameter *a = (Parameter *)arguments->data[0]; + delete arguments; + nextToken(); + Expression *upr = parseExpression(); + check(TOKrparen); + Statement *body = parseStatement(0); + s = new ForeachRangeStatement(loc, op, a, aggr, upr, body); + } + else + { + check(TOKrparen); + Statement *body = parseStatement(0); + s = new ForeachStatement(loc, op, arguments, aggr, body); + } + break; + } + + case TOKif: + { Parameter *arg = NULL; + Expression *condition; + Statement *ifbody; + Statement *elsebody; + + nextToken(); + check(TOKlparen); + + if (token.value == TOKauto) + { + nextToken(); + if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKassign) + { + arg = new Parameter(0, NULL, token.ident, NULL); + nextToken(); + nextToken(); + } + else + { error("= expected following auto identifier"); + goto Lerror; + } + } + else + { error("identifier expected following auto"); + goto Lerror; + } + } + else if (isDeclaration(&token, 2, TOKassign, NULL)) + { + Type *at; + Identifier *ai; + + at = parseType(&ai); + check(TOKassign); + arg = new Parameter(0, at, ai, NULL); + } + + // Check for " ident;" + else if (token.value == TOKidentifier) + { + Token *t = peek(&token); + if (t->value == TOKcomma || t->value == TOKsemicolon) + { + arg = new Parameter(0, NULL, token.ident, NULL); + nextToken(); + nextToken(); + if (1 || !global.params.useDeprecated) + error("if (v; e) is deprecated, use if (auto v = e)"); + } + } + + condition = parseExpression(); + check(TOKrparen); + ifbody = parseStatement(PSscope); + if (token.value == TOKelse) + { + nextToken(); + elsebody = parseStatement(PSscope); + } + else + elsebody = NULL; + s = new IfStatement(loc, arg, condition, ifbody, elsebody); + break; + } + + case TOKscope: + if (peek(&token)->value != TOKlparen) + goto Ldeclaration; // scope used as storage class + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("scope identifier expected"); + goto Lerror; + } + else + { TOK t = TOKon_scope_exit; + Identifier *id = token.ident; + + if (id == Id::exit) + t = TOKon_scope_exit; + else if (id == Id::failure) + t = TOKon_scope_failure; + else if (id == Id::success) + t = TOKon_scope_success; + else + error("valid scope identifiers are exit, failure, or success, not %s", id->toChars()); + nextToken(); + check(TOKrparen); + Statement *st = parseStatement(PScurlyscope); + s = new OnScopeStatement(loc, t, st); + break; + } + + case TOKdebug: + nextToken(); + condition = parseDebugCondition(); + goto Lcondition; + + case TOKversion: + nextToken(); + condition = parseVersionCondition(); + goto Lcondition; + + Lcondition: + ifbody = parseStatement(0 /*PSsemi*/); + elsebody = NULL; + if (token.value == TOKelse) + { + nextToken(); + elsebody = parseStatement(0 /*PSsemi*/); + } + s = new ConditionalStatement(loc, condition, ifbody, elsebody); + break; + + case TOKpragma: + { Identifier *ident; + Expressions *args = NULL; + Statement *body; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("pragma(identifier expected"); + goto Lerror; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma && peekNext() != TOKrparen) + args = parseArguments(); // pragma(identifier, args...); + else + check(TOKrparen); // pragma(identifier); + if (token.value == TOKsemicolon) + { nextToken(); + body = NULL; + } + else + body = parseStatement(PSsemi); + s = new PragmaStatement(loc, ident, args, body); + break; + } + + case TOKswitch: + isfinal = FALSE; + goto Lswitch; + + Lswitch: + { + nextToken(); + check(TOKlparen); + Expression *condition = parseExpression(); + check(TOKrparen); + Statement *body = parseStatement(PSscope); + s = new SwitchStatement(loc, condition, body, isfinal); + break; + } + + case TOKcase: + { Expression *exp; + Statements *statements; + Array cases; // array of Expression's + Expression *last = NULL; + + while (1) + { + nextToken(); + exp = parseAssignExp(); + cases.push(exp); + if (token.value != TOKcomma) + break; + } + check(TOKcolon); + +#if DMDV2 + /* case exp: .. case last: + */ + if (token.value == TOKslice) + { + if (cases.dim > 1) + error("only one case allowed for start of case range"); + nextToken(); + check(TOKcase); + last = parseAssignExp(); + check(TOKcolon); + } +#endif + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKeof && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + +#if DMDV2 + if (last) + { + s = new CaseRangeStatement(loc, exp, last, s); + } + else +#endif + { + // Keep cases in order by building the case statements backwards + for (int i = cases.dim; i; i--) + { + exp = (Expression *)cases.data[i - 1]; + s = new CaseStatement(loc, exp, s); + } + } + break; + } + + case TOKdefault: + { + Statements *statements; + + nextToken(); + check(TOKcolon); + + statements = new Statements(); + while (token.value != TOKcase && + token.value != TOKdefault && + token.value != TOKeof && + token.value != TOKrcurly) + { + statements->push(parseStatement(PSsemi | PScurlyscope)); + } + s = new CompoundStatement(loc, statements); + s = new ScopeStatement(loc, s); + s = new DefaultStatement(loc, s); + break; + } + + case TOKreturn: + { Expression *exp; + + nextToken(); + if (token.value == TOKsemicolon) + exp = NULL; + else + exp = parseExpression(); + check(TOKsemicolon, "return statement"); + s = new ReturnStatement(loc, exp); + break; + } + + case TOKbreak: + { Identifier *ident; + + nextToken(); + if (token.value == TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = NULL; + check(TOKsemicolon, "break statement"); + s = new BreakStatement(loc, ident); + break; + } + + case TOKcontinue: + { Identifier *ident; + + nextToken(); + if (token.value == TOKidentifier) + { ident = token.ident; + nextToken(); + } + else + ident = NULL; + check(TOKsemicolon, "continue statement"); + s = new ContinueStatement(loc, ident); + break; + } + + case TOKgoto: + { Identifier *ident; + + nextToken(); + if (token.value == TOKdefault) + { + nextToken(); + s = new GotoDefaultStatement(loc); + } + else if (token.value == TOKcase) + { + Expression *exp = NULL; + + nextToken(); + if (token.value != TOKsemicolon) + exp = parseExpression(); + s = new GotoCaseStatement(loc, exp); + } + else + { + if (token.value != TOKidentifier) + { error("Identifier expected following goto"); + ident = NULL; + } + else + { ident = token.ident; + nextToken(); + } + s = new GotoStatement(loc, ident); + } + check(TOKsemicolon, "goto statement"); + break; + } + + case TOKsynchronized: + { Expression *exp; + Statement *body; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + exp = parseExpression(); + check(TOKrparen); + } + else + exp = NULL; + body = parseStatement(PSscope); + s = new SynchronizedStatement(loc, exp, body); + break; + } + + case TOKwith: + { Expression *exp; + Statement *body; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new WithStatement(loc, exp, body); + break; + } + + case TOKtry: + { Statement *body; + Array *catches = NULL; + Statement *finalbody = NULL; + + nextToken(); + body = parseStatement(PSscope); + while (token.value == TOKcatch) + { + Statement *handler; + Catch *c; + Type *t; + Identifier *id; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlcurly) + { + t = NULL; + id = NULL; + } + else + { + check(TOKlparen); + id = NULL; + t = parseType(&id); + check(TOKrparen); + } + handler = parseStatement(0); + c = new Catch(loc, t, id, handler); + if (!catches) + catches = new Array(); + catches->push(c); + } + + if (token.value == TOKfinally) + { nextToken(); + finalbody = parseStatement(0); + } + + s = body; + if (!catches && !finalbody) + error("catch or finally expected following try"); + else + { if (catches) + s = new TryCatchStatement(loc, body, catches); + if (finalbody) + s = new TryFinallyStatement(loc, s, finalbody); + } + break; + } + + case TOKthrow: + { Expression *exp; + + nextToken(); + exp = parseExpression(); + check(TOKsemicolon, "throw statement"); + s = new ThrowStatement(loc, exp); + break; + } + + case TOKvolatile: + nextToken(); + s = parseStatement(PSsemi | PScurlyscope); +#if DMDV2 + if (!global.params.useDeprecated) + error("volatile statements deprecated; used synchronized statements instead"); +#endif + s = new VolatileStatement(loc, s); + break; + + case TOKasm: + { Statements *statements; + Identifier *label; + Loc labelloc; + Token *toklist; + Token **ptoklist; + + // Parse the asm block into a sequence of AsmStatements, + // each AsmStatement is one instruction. + // Separate out labels. + // Defer parsing of AsmStatements until semantic processing. + + nextToken(); + check(TOKlcurly); + toklist = NULL; + ptoklist = &toklist; + label = NULL; + statements = new Statements(); + while (1) + { + switch (token.value) + { + case TOKidentifier: + if (!toklist) + { + // Look ahead to see if it is a label + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + label = token.ident; + labelloc = this->loc; + nextToken(); + nextToken(); + continue; + } + } + goto Ldefault; + + case TOKrcurly: + if (toklist || label) + { + error("asm statements must end in ';'"); + } + break; + + case TOKsemicolon: + s = NULL; + if (toklist || label) + { // Create AsmStatement from list of tokens we've saved + s = new AsmStatement(this->loc, toklist); + toklist = NULL; + ptoklist = &toklist; + if (label) + { s = new LabelStatement(labelloc, label, s); + label = NULL; + } + statements->push(s); + } + nextToken(); + continue; + + case TOKeof: + /* { */ + error("matching '}' expected, not end of file"); + break; + + default: + Ldefault: + *ptoklist = new Token(); + memcpy(*ptoklist, &token, sizeof(Token)); + ptoklist = &(*ptoklist)->next; + *ptoklist = NULL; + + nextToken(); + continue; + } + break; + } + s = new AsmBlockStatement(loc, statements); + nextToken(); + break; + } + + default: + error("found '%s' instead of statement", token.toChars()); + goto Lerror; + + Lerror: + while (token.value != TOKrcurly && + token.value != TOKsemicolon && + token.value != TOKeof) + nextToken(); + if (token.value == TOKsemicolon) + nextToken(); + s = NULL; + break; + } + + return s; +} + +void Parser::check(enum TOK value) +{ + check(loc, value); +} + +void Parser::check(Loc loc, enum TOK value) +{ + if (token.value != value) + error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); + nextToken(); +} + +void Parser::check(enum TOK value, const char *string) +{ + if (token.value != value) + error("found '%s' when expecting '%s' following %s", + token.toChars(), Token::toChars(value), string); + nextToken(); +} + +void Parser::checkParens(enum TOK value, Expression *e) +{ + if (precedence[e->op] == PREC_rel && !e->parens) + error(loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value)); +} + +/************************************ + * Determine if the scanner is sitting on the start of a declaration. + * Input: + * needId 0 no identifier + * 1 identifier optional + * 2 must have identifier + * Output: + * if *pt is not NULL, it is set to the ending token, which would be endtok + */ + +int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) +{ + //printf("isDeclaration(needId = %d)\n", needId); + int haveId = 0; + +#if DMDV2 + if ((t->value == TOKconst || + t->value == TOKinvariant || + t->value == TOKimmutable || + t->value == TOKwild || + t->value == TOKshared) && + peek(t)->value != TOKlparen) + { /* const type + * immutable type + * shared type + * wild type + */ + t = peek(t); + } +#endif + + if (!isBasicType(&t)) + { + goto Lisnot; + } + if (!isDeclarator(&t, &haveId, endtok)) + goto Lisnot; + if ( needId == 1 || + (needId == 0 && !haveId) || + (needId == 2 && haveId)) + { if (pt) + *pt = t; + goto Lis; + } + else + goto Lisnot; + +Lis: + //printf("\tis declaration, t = %s\n", t->toChars()); + return TRUE; + +Lisnot: + //printf("\tis not declaration\n"); + return FALSE; +} + +int Parser::isBasicType(Token **pt) +{ + // This code parallels parseBasicType() + Token *t = *pt; + Token *t2; + int parens; + int haveId = 0; + + switch (t->value) + { + case BASIC_TYPES: + t = peek(t); + break; + + case TOKidentifier: + L5: + t = peek(t); + if (t->value == TOKnot) + { + goto L4; + } + goto L3; + while (1) + { + L2: + t = peek(t); + L3: + if (t->value == TOKdot) + { + Ldot: + t = peek(t); + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + if (t->value != TOKnot) + goto L3; + L4: + /* Seen a ! + * Look for: + * !( args ), !identifier, etc. + */ + t = peek(t); + switch (t->value) + { case TOKidentifier: + goto L5; + case TOKlparen: + if (!skipParens(t, &t)) + goto Lfalse; + break; + case BASIC_TYPES: + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKstring: + case TOKfile: + case TOKline: + goto L2; + default: + goto Lfalse; + } + } + else + break; + } + break; + + case TOKdot: + goto Ldot; + + case TOKtypeof: + /* typeof(exp).identifier... + */ + t = peek(t); + if (t->value != TOKlparen) + goto Lfalse; + if (!skipParens(t, &t)) + goto Lfalse; + goto L2; + + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + case TOKwild: + // const(type) or immutable(type) or shared(type) or wild(type) + t = peek(t); + if (t->value != TOKlparen) + goto Lfalse; + t = peek(t); + if (!isDeclaration(t, 0, TOKrparen, &t)) + { + goto Lfalse; + } + t = peek(t); + break; + + default: + goto Lfalse; + } + *pt = t; + //printf("is\n"); + return TRUE; + +Lfalse: + //printf("is not\n"); + return FALSE; +} + +int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) +{ // This code parallels parseDeclarator() + Token *t = *pt; + int parens; + + //printf("Parser::isDeclarator()\n"); + //t->print(); + if (t->value == TOKassign) + return FALSE; + + while (1) + { + parens = FALSE; + switch (t->value) + { + case TOKmul: + //case TOKand: + t = peek(t); + continue; + + case TOKlbracket: + t = peek(t); + if (t->value == TOKrbracket) + { + t = peek(t); + } + else if (t->value == TOKnew && peek(t)->value == TOKrbracket) + { + t = peek(t); + t = peek(t); + } + else if (isDeclaration(t, 0, TOKrbracket, &t)) + { // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + // [ expression .. expression ] + if (!isExpression(&t)) + return FALSE; + if (t->value == TOKslice) + { t = peek(t); + if (!isExpression(&t)) + return FALSE; + } + if (t->value != TOKrbracket) + return FALSE; + t = peek(t); + } + continue; + + case TOKidentifier: + if (*haveId) + return FALSE; + *haveId = TRUE; + t = peek(t); + break; + + case TOKlparen: + t = peek(t); + + if (t->value == TOKrparen) + return FALSE; // () is not a declarator + + /* Regard ( identifier ) as not a declarator + * BUG: what about ( *identifier ) in + * f(*p)(x); + * where f is a class instance with overloaded () ? + * Should we just disallow C-style function pointer declarations? + */ + if (t->value == TOKidentifier) + { Token *t2 = peek(t); + if (t2->value == TOKrparen) + return FALSE; + } + + + if (!isDeclarator(&t, haveId, TOKrparen)) + return FALSE; + t = peek(t); + parens = TRUE; + break; + + case TOKdelegate: + case TOKfunction: + t = peek(t); + if (!isParameters(&t)) + return FALSE; + continue; + } + break; + } + + while (1) + { + switch (t->value) + { +#if CARRAYDECL + case TOKlbracket: + parens = FALSE; + t = peek(t); + if (t->value == TOKrbracket) + { + t = peek(t); + } + else if (isDeclaration(t, 0, TOKrbracket, &t)) + { // It's an associative array declaration + t = peek(t); + } + else + { + // [ expression ] + if (!isExpression(&t)) + return FALSE; + if (t->value != TOKrbracket) + return FALSE; + t = peek(t); + } + continue; +#endif + + case TOKlparen: + parens = FALSE; + if (!isParameters(&t)) + return FALSE; +#if DMDV2 + while (1) + { + switch (t->value) + { + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + case TOKwild: + case TOKpure: + case TOKnothrow: + t = peek(t); + continue; + case TOKat: + t = peek(t); // skip '@' + t = peek(t); // skip identifier + continue; + default: + break; + } + break; + } +#endif + continue; + + // Valid tokens that follow a declaration + case TOKrparen: + case TOKrbracket: + case TOKassign: + case TOKcomma: + case TOKsemicolon: + case TOKlcurly: + case TOKin: + // The !parens is to disallow unnecessary parentheses + if (!parens && (endtok == TOKreserved || endtok == t->value)) + { *pt = t; + return TRUE; + } + return FALSE; + + default: + return FALSE; + } + } +} + + +int Parser::isParameters(Token **pt) +{ // This code parallels parseParameters() + Token *t = *pt; + + //printf("isParameters()\n"); + if (t->value != TOKlparen) + return FALSE; + + t = peek(t); + for (;1; t = peek(t)) + { + L1: + switch (t->value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + t = peek(t); + break; + +#if D1INOUT + case TOKinout: +#endif + case TOKin: + case TOKout: + case TOKref: + case TOKlazy: + case TOKfinal: + case TOKauto: + continue; + + case TOKconst: + case TOKinvariant: + case TOKimmutable: + case TOKshared: + case TOKwild: + t = peek(t); + if (t->value == TOKlparen) + { + t = peek(t); + if (!isDeclaration(t, 0, TOKrparen, &t)) + return FALSE; + t = peek(t); // skip past closing ')' + goto L2; + } + goto L1; + +#if 0 + case TOKstatic: + continue; + case TOKauto: + case TOKalias: + t = peek(t); + if (t->value == TOKidentifier) + t = peek(t); + if (t->value == TOKassign) + { t = peek(t); + if (!isExpression(&t)) + return FALSE; + } + goto L3; +#endif + + default: + { if (!isBasicType(&t)) + return FALSE; + L2: + int tmp = FALSE; + if (t->value != TOKdotdotdot && + !isDeclarator(&t, &tmp, TOKreserved)) + return FALSE; + if (t->value == TOKassign) + { t = peek(t); + if (!isExpression(&t)) + return FALSE; + } + if (t->value == TOKdotdotdot) + { + t = peek(t); + break; + } + } + L3: + if (t->value == TOKcomma) + { + continue; + } + break; + } + break; + } + if (t->value != TOKrparen) + return FALSE; + t = peek(t); + *pt = t; + return TRUE; +} + +int Parser::isExpression(Token **pt) +{ + // This is supposed to determine if something is an expression. + // What it actually does is scan until a closing right bracket + // is found. + + Token *t = *pt; + int brnest = 0; + int panest = 0; + int curlynest = 0; + + for (;; t = peek(t)) + { + switch (t->value) + { + case TOKlbracket: + brnest++; + continue; + + case TOKrbracket: + if (--brnest >= 0) + continue; + break; + + case TOKlparen: + panest++; + continue; + + case TOKcomma: + if (brnest || panest) + continue; + break; + + case TOKrparen: + if (--panest >= 0) + continue; + break; + + case TOKlcurly: + curlynest++; + continue; + + case TOKrcurly: + if (--curlynest >= 0) + continue; + return FALSE; + + case TOKslice: + if (brnest) + continue; + break; + + case TOKsemicolon: + if (curlynest) + continue; + return FALSE; + + case TOKeof: + return FALSE; + + default: + continue; + } + break; + } + + *pt = t; + return TRUE; +} + +/********************************************** + * Skip over + * instance foo.bar(parameters...) + * Output: + * if (pt), *pt is set to the token following the closing ) + * Returns: + * 1 it's valid instance syntax + * 0 invalid instance syntax + */ + +int Parser::isTemplateInstance(Token *t, Token **pt) +{ + t = peek(t); + if (t->value != TOKdot) + { + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + } + while (t->value == TOKdot) + { + t = peek(t); + if (t->value != TOKidentifier) + goto Lfalse; + t = peek(t); + } + if (t->value != TOKlparen) + goto Lfalse; + + // Skip over the template arguments + while (1) + { + while (1) + { + t = peek(t); + switch (t->value) + { + case TOKlparen: + if (!skipParens(t, &t)) + goto Lfalse; + continue; + case TOKrparen: + break; + case TOKcomma: + break; + case TOKeof: + case TOKsemicolon: + goto Lfalse; + default: + continue; + } + break; + } + + if (t->value != TOKcomma) + break; + } + if (t->value != TOKrparen) + goto Lfalse; + t = peek(t); + if (pt) + *pt = t; + return 1; + +Lfalse: + return 0; +} + +/******************************************* + * Skip parens, brackets. + * Input: + * t is on opening ( + * Output: + * *pt is set to closing token, which is ')' on success + * Returns: + * !=0 successful + * 0 some parsing error + */ + +int Parser::skipParens(Token *t, Token **pt) +{ + int parens = 0; + + while (1) + { + switch (t->value) + { + case TOKlparen: + parens++; + break; + + case TOKrparen: + parens--; + if (parens < 0) + goto Lfalse; + if (parens == 0) + goto Ldone; + break; + + case TOKeof: + case TOKsemicolon: + goto Lfalse; + + default: + break; + } + t = peek(t); + } + + Ldone: + if (*pt) + *pt = t; + return 1; + + Lfalse: + return 0; +} + +/********************************* Expression Parser ***************************/ + +Expression *Parser::parsePrimaryExp() +{ Expression *e; + Type *t; + Identifier *id; + enum TOK save; + Loc loc = this->loc; + + //printf("parsePrimaryExp(): loc = %d\n", loc.linnum); + switch (token.value) + { + case TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin) + { // identifier!(template-argument-list) + TemplateInstance *tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + if (token.value == TOKlparen) + // ident!(template_arguments) + tempinst->tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tempinst->tiargs = parseTemplateArgument(); + e = new ScopeExp(loc, tempinst); + } + else + e = new IdentifierExp(loc, id); + break; + + case TOKdollar: + if (!inBrackets) + error("'$' is valid only inside [] of index or slice"); + e = new DollarExp(loc); + nextToken(); + break; + + case TOKdot: + // Signal global scope '.' operator with "" identifier + e = new IdentifierExp(loc, Id::empty); + break; + + case TOKthis: + e = new ThisExp(loc); + nextToken(); + break; + + case TOKsuper: + e = new SuperExp(loc); + nextToken(); + break; + + case TOKint32v: + e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); + nextToken(); + break; + + case TOKuns32v: + e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); + nextToken(); + break; + + case TOKint64v: + e = new IntegerExp(loc, token.int64value, Type::tint64); + nextToken(); + break; + + case TOKuns64v: + e = new IntegerExp(loc, token.uns64value, Type::tuns64); + nextToken(); + break; + + case TOKfloat32v: + e = new RealExp(loc, token.float80value, Type::tfloat32); + nextToken(); + break; + + case TOKfloat64v: + e = new RealExp(loc, token.float80value, Type::tfloat64); + nextToken(); + break; + + case TOKfloat80v: + e = new RealExp(loc, token.float80value, Type::tfloat80); + nextToken(); + break; + + case TOKimaginary32v: + e = new RealExp(loc, token.float80value, Type::timaginary32); + nextToken(); + break; + + case TOKimaginary64v: + e = new RealExp(loc, token.float80value, Type::timaginary64); + nextToken(); + break; + + case TOKimaginary80v: + e = new RealExp(loc, token.float80value, Type::timaginary80); + nextToken(); + break; + + case TOKnull: + e = new NullExp(loc); + nextToken(); + break; + +#if DMDV2 + case TOKfile: + { const char *s = loc.filename ? loc.filename : mod->ident->toChars(); + e = new StringExp(loc, (char *)s, strlen(s), 0); + nextToken(); + break; + } + + case TOKline: + e = new IntegerExp(loc, loc.linnum, Type::tint32); + nextToken(); + break; +#endif + + case TOKtrue: + e = new IntegerExp(loc, 1, Type::tbool); + nextToken(); + break; + + case TOKfalse: + e = new IntegerExp(loc, 0, Type::tbool); + nextToken(); + break; + + case TOKcharv: + e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); + nextToken(); + break; + + case TOKwcharv: + e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); + nextToken(); + break; + + case TOKdcharv: + e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); + nextToken(); + break; + + case TOKstring: + { unsigned char *s; + unsigned len; + unsigned char postfix; + + // cat adjacent strings + s = token.ustring; + len = token.len; + postfix = token.postfix; + while (1) + { + nextToken(); + if (token.value == TOKstring) + { unsigned len1; + unsigned len2; + unsigned char *s2; + + if (token.postfix) + { if (token.postfix != postfix) + error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); + postfix = token.postfix; + } + + len1 = len; + len2 = token.len; + len = len1 + len2; + s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); + memcpy(s2, s, len1 * sizeof(unsigned char)); + memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); + s = s2; + } + else + break; + } + e = new StringExp(loc, s, len, postfix); + break; + } + + case BASIC_TYPES_X(t): + nextToken(); + L1: + check(TOKdot, t->toChars()); + if (token.value != TOKidentifier) + { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars()); + goto Lerr; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + break; + + case TOKtypeof: + { + t = parseTypeof(); + e = new TypeExp(loc, t); + break; + } + + case TOKtypeid: + { + nextToken(); + check(TOKlparen, "typeid"); + Object *o; + if (isDeclaration(&token, 0, TOKreserved, NULL)) + { // argument is a type + o = parseType(); + } + else + { // argument is an expression + o = parseAssignExp(); + } + check(TOKrparen); + e = new TypeidExp(loc, o); + break; + } + +#if DMDV2 + case TOKtraits: + { /* __traits(identifier, args...) + */ + Identifier *ident; + Objects *args = NULL; + + nextToken(); + check(TOKlparen); + if (token.value != TOKidentifier) + { error("__traits(identifier, args...) expected"); + goto Lerr; + } + ident = token.ident; + nextToken(); + if (token.value == TOKcomma) + args = parseTemplateArgumentList2(); // __traits(identifier, args...) + else + check(TOKrparen); // __traits(identifier) + + e = new TraitsExp(loc, ident, args); + break; + } +#endif + + case TOKis: + { Type *targ; + Identifier *ident = NULL; + Type *tspec = NULL; + enum TOK tok = TOKreserved; + enum TOK tok2 = TOKreserved; + TemplateParameters *tpl = NULL; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + targ = parseType(&ident); + if (token.value == TOKcolon || token.value == TOKequal) + { + tok = token.value; + nextToken(); + if (tok == TOKequal && + (token.value == TOKtypedef || + token.value == TOKstruct || + token.value == TOKunion || + token.value == TOKclass || + token.value == TOKsuper || + token.value == TOKenum || + token.value == TOKinterface || +#if DMDV2 + token.value == TOKconst && peek(&token)->value == TOKrparen || + token.value == TOKinvariant && peek(&token)->value == TOKrparen || + token.value == TOKimmutable && peek(&token)->value == TOKrparen || + token.value == TOKshared && peek(&token)->value == TOKrparen || + token.value == TOKwild && peek(&token)->value == TOKrparen || +#endif + token.value == TOKfunction || + token.value == TOKdelegate || + token.value == TOKreturn)) + { + tok2 = token.value; + nextToken(); + } + else + { + tspec = parseType(); + } + } + if (ident && tspec) + { + if (token.value == TOKcomma) + tpl = parseTemplateParameterList(1); + else + { tpl = new TemplateParameters(); + check(TOKrparen); + } + TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL); + tpl->insert(0, tp); + } + else + check(TOKrparen); + } + else + { error("(type identifier : specialization) expected following is"); + goto Lerr; + } + e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl); + break; + } + + case TOKassert: + { Expression *msg = NULL; + + nextToken(); + check(TOKlparen, "assert"); + e = parseAssignExp(); + if (token.value == TOKcomma) + { nextToken(); + msg = parseAssignExp(); + } + check(TOKrparen); + e = new AssertExp(loc, e, msg); + break; + } + + case TOKmixin: + { + nextToken(); + check(TOKlparen, "mixin"); + e = parseAssignExp(); + check(TOKrparen); + e = new CompileExp(loc, e); + break; + } + + case TOKimport: + { + nextToken(); + check(TOKlparen, "import"); + e = parseAssignExp(); + check(TOKrparen); + e = new FileExp(loc, e); + break; + } + + case TOKlparen: + if (peekPastParen(&token)->value == TOKlcurly) + { // (arguments) { statements... } + save = TOKdelegate; + goto case_delegate; + } + // ( expression ) + nextToken(); + e = parseExpression(); + e->parens = 1; + check(loc, TOKrparen); + break; + + case TOKlbracket: + { /* Parse array literals and associative array literals: + * [ value, value, value ... ] + * [ key:value, key:value, key:value ... ] + */ + Expressions *values = new Expressions(); + Expressions *keys = NULL; + + nextToken(); + while (token.value != TOKrbracket && token.value != TOKeof) + { + Expression *e = parseAssignExp(); + if (token.value == TOKcolon && (keys || values->dim == 0)) + { nextToken(); + if (!keys) + keys = new Expressions(); + keys->push(e); + e = parseAssignExp(); + } + else if (keys) + { error("'key:value' expected for associative array literal"); + delete keys; + keys = NULL; + } + values->push(e); + if (token.value == TOKrbracket) + break; + check(TOKcomma); + } + check(loc, TOKrbracket); + + if (keys) + e = new AssocArrayLiteralExp(loc, keys, values); + else + e = new ArrayLiteralExp(loc, values); + break; + } + + case TOKlcurly: + // { statements... } + save = TOKdelegate; + goto case_delegate; + + case TOKfunction: + case TOKdelegate: + save = token.value; + nextToken(); + case_delegate: + { + /* function type(parameters) { body } pure nothrow + * delegate type(parameters) { body } pure nothrow + * (parameters) { body } + * { body } + */ + Parameters *arguments; + int varargs; + FuncLiteralDeclaration *fd; + Type *t; + StorageClass stc = 0; + + if (token.value == TOKlcurly) + { + t = NULL; + varargs = 0; + arguments = new Parameters(); + } + else + { + if (token.value == TOKlparen) + t = NULL; + else + { + t = parseBasicType(); + t = parseBasicType2(t); // function return type + } + arguments = parseParameters(&varargs); + stc = parsePostfix(); + if (stc & (STCconst | STCimmutable | STCshared | STCwild)) + error("const/immutable/shared/inout attributes are only valid for non-static member functions"); + } + + TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc); + + fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); + parseContracts(fd); + e = new FuncExp(loc, fd); + break; + } + + default: + error("expression expected, not '%s'", token.toChars()); + Lerr: + // Anything for e, as long as it's not NULL + e = new IntegerExp(loc, 0, Type::tint32); + nextToken(); + break; + } + return e; +} + +Expression *Parser::parsePostExp(Expression *e) +{ + Loc loc; + + while (1) + { + loc = this->loc; + switch (token.value) + { + case TOKdot: + nextToken(); + if (token.value == TOKidentifier) + { Identifier *id = token.ident; + + nextToken(); + if (token.value == TOKnot && peekNext() != TOKis) + { // identifier!(template-argument-list) + TemplateInstance *tempinst = new TemplateInstance(loc, id); + Objects *tiargs; + nextToken(); + if (token.value == TOKlparen) + // ident!(template_arguments) + tiargs = parseTemplateArgumentList(); + else + // ident!template_argument + tiargs = parseTemplateArgument(); + e = new DotTemplateInstanceExp(loc, e, id, tiargs); + } + else + e = new DotIdExp(loc, e, id); + continue; + } + else if (token.value == TOKnew) + { + e = parseNewExp(e); + continue; + } + else + error("identifier expected following '.', not '%s'", token.toChars()); + break; + + case TOKplusplus: + e = new PostExp(TOKplusplus, loc, e); + break; + + case TOKminusminus: + e = new PostExp(TOKminusminus, loc, e); + break; + + case TOKlparen: + e = new CallExp(loc, e, parseArguments()); + continue; + + case TOKlbracket: + { // array dereferences: + // array[index] + // array[] + // array[lwr .. upr] + Expression *index; + Expression *upr; + + inBrackets++; + nextToken(); + if (token.value == TOKrbracket) + { // array[] + e = new SliceExp(loc, e, NULL, NULL); + nextToken(); + } + else + { + index = parseAssignExp(); + if (token.value == TOKslice) + { // array[lwr .. upr] + nextToken(); + upr = parseAssignExp(); + e = new SliceExp(loc, e, index, upr); + } + else + { // array[index, i2, i3, i4, ...] + Expressions *arguments = new Expressions(); + arguments->push(index); + if (token.value == TOKcomma) + { + nextToken(); + while (token.value != TOKrbracket && token.value != TOKeof) + { + Expression *arg = parseAssignExp(); + arguments->push(arg); + if (token.value == TOKrbracket) + break; + check(TOKcomma); + } + } + e = new ArrayExp(loc, e, arguments); + } + check(TOKrbracket); + inBrackets--; + } + continue; + } + + default: + return e; + } + nextToken(); + } +} + +Expression *Parser::parseUnaryExp() +{ Expression *e; + Loc loc = this->loc; + + switch (token.value) + { + case TOKand: + nextToken(); + e = parseUnaryExp(); + e = new AddrExp(loc, e); + break; + + case TOKplusplus: + nextToken(); + e = parseUnaryExp(); + //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); + e = new PreExp(TOKpreplusplus, loc, e); + break; + + case TOKminusminus: + nextToken(); + e = parseUnaryExp(); + //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); + e = new PreExp(TOKpreminusminus, loc, e); + break; + + case TOKmul: + nextToken(); + e = parseUnaryExp(); + e = new PtrExp(loc, e); + break; + + case TOKmin: + nextToken(); + e = parseUnaryExp(); + e = new NegExp(loc, e); + break; + + case TOKadd: + nextToken(); + e = parseUnaryExp(); + e = new UAddExp(loc, e); + break; + + case TOKnot: + nextToken(); + e = parseUnaryExp(); + e = new NotExp(loc, e); + break; + + case TOKtilde: + nextToken(); + e = parseUnaryExp(); + e = new ComExp(loc, e); + break; + + case TOKdelete: + nextToken(); + e = parseUnaryExp(); + e = new DeleteExp(loc, e); + break; + + case TOKnew: + e = parseNewExp(NULL); + break; + + case TOKcast: // cast(type) expression + { + nextToken(); + check(TOKlparen); + /* Look for cast(), cast(const), cast(immutable), + * cast(shared), cast(shared const), cast(wild), cast(shared wild) + */ + unsigned m; + if (token.value == TOKrparen) + { + m = 0; + goto Lmod1; + } + else if (token.value == TOKconst && peekNext() == TOKrparen) + { + m = MODconst; + goto Lmod2; + } + else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen) + { + m = MODimmutable; + goto Lmod2; + } + else if (token.value == TOKshared && peekNext() == TOKrparen) + { + m = MODshared; + goto Lmod2; + } + else if (token.value == TOKwild && peekNext() == TOKrparen) + { + m = MODwild; + goto Lmod2; + } + else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() == TOKrparen || + token.value == TOKshared && peekNext() == TOKwild && peekNext2() == TOKrparen) + { + m = MODshared | MODwild; + goto Lmod3; + } + else if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() == TOKrparen || + token.value == TOKshared && peekNext() == TOKconst && peekNext2() == TOKrparen) + { + m = MODshared | MODconst; + Lmod3: + nextToken(); + Lmod2: + nextToken(); + Lmod1: + nextToken(); + e = parseUnaryExp(); + e = new CastExp(loc, e, m); + } + else + { + Type *t = parseType(); // ( type ) + check(TOKrparen); + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + } + break; + } + + case TOKwild: + case TOKshared: + case TOKconst: + case TOKinvariant: + case TOKimmutable: // immutable(type)(arguments) + { + Type *t = parseBasicType(); + if (token.value != TOKlparen) + error("(arguments) expected following type"); + e = new TypeExp(loc, t); + e = new CallExp(loc, e, parseArguments()); + break; + } + + + case TOKlparen: + { Token *tk; + + tk = peek(&token); +#if CCASTSYNTAX + // If cast + if (isDeclaration(tk, 0, TOKrparen, &tk)) + { + tk = peek(tk); // skip over right parenthesis + switch (tk->value) + { + case TOKnot: + tk = peek(tk); + if (tk->value == TOKis || tk->value == TOKin) // !is or !in + break; + case TOKdot: + case TOKplusplus: + case TOKminusminus: + case TOKdelete: + case TOKnew: + case TOKlparen: + case TOKidentifier: + case TOKthis: + case TOKsuper: + case TOKint32v: + case TOKuns32v: + case TOKint64v: + case TOKuns64v: + case TOKfloat32v: + case TOKfloat64v: + case TOKfloat80v: + case TOKimaginary32v: + case TOKimaginary64v: + case TOKimaginary80v: + case TOKnull: + case TOKtrue: + case TOKfalse: + case TOKcharv: + case TOKwcharv: + case TOKdcharv: + case TOKstring: +#if 0 + case TOKtilde: + case TOKand: + case TOKmul: + case TOKmin: + case TOKadd: +#endif + case TOKfunction: + case TOKdelegate: + case TOKtypeof: +#if DMDV2 + case TOKfile: + case TOKline: +#endif + case BASIC_TYPES: // (type)int.size + { // (type) una_exp + Type *t; + + nextToken(); + t = parseType(); + check(TOKrparen); + + // if .identifier + if (token.value == TOKdot) + { + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following (type)."); + return NULL; + } + e = typeDotIdExp(loc, t, token.ident); + nextToken(); + e = parsePostExp(e); + } + else + { + e = parseUnaryExp(); + e = new CastExp(loc, e, t); + error("C style cast illegal, use %s", e->toChars()); + } + return e; + } + } + } +#endif + e = parsePrimaryExp(); + e = parsePostExp(e); + break; + } + default: + e = parsePrimaryExp(); + e = parsePostExp(e); + break; + } + assert(e); + + // ^^ is right associative and has higher precedence than the unary operators + while (token.value == TOKpow) + { + nextToken(); + Expression *e2 = parseUnaryExp(); + e = new PowExp(loc, e, e2); + } + + return e; +} + +Expression *Parser::parseMulExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseUnaryExp(); + while (1) + { + switch (token.value) + { + case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; + case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; + case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseAddExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseMulExp(); + while (1) + { + switch (token.value) + { + case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; + case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; + case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseShiftExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseAddExp(); + while (1) + { + switch (token.value) + { + case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; + case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; + case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; + + default: + break; + } + break; + } + return e; +} + +#if DMDV1 +Expression *Parser::parseRelExp() +{ Expression *e; + Expression *e2; + enum TOK op; + Loc loc = this->loc; + + e = parseShiftExp(); + while (1) + { + switch (token.value) + { + case TOKlt: + case TOKle: + case TOKgt: + case TOKge: + case TOKunord: + case TOKlg: + case TOKleg: + case TOKule: + case TOKul: + case TOKuge: + case TOKug: + case TOKue: + op = token.value; + nextToken(); + e2 = parseShiftExp(); + e = new CmpExp(op, loc, e, e2); + continue; + + case TOKnot: // could be !in + if (peekNext() == TOKin) + { + nextToken(); + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + e = new NotExp(loc, e); + continue; + } + break; + + case TOKin: + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + continue; + + default: + break; + } + break; + } + return e; +} +#endif + +#if DMDV1 +Expression *Parser::parseEqualExp() +{ Expression *e; + Expression *e2; + Token *t; + Loc loc = this->loc; + + e = parseRelExp(); + while (1) + { enum TOK value = token.value; + + switch (value) + { + case TOKequal: + case TOKnotequal: + nextToken(); + e2 = parseRelExp(); + e = new EqualExp(value, loc, e, e2); + continue; + + case TOKidentity: + error("'===' is no longer legal, use 'is' instead"); + goto L1; + + case TOKnotidentity: + error("'!==' is no longer legal, use '!is' instead"); + goto L1; + + case TOKis: + value = TOKidentity; + goto L1; + + case TOKnot: + // Attempt to identify '!is' + t = peek(&token); + if (t->value != TOKis) + break; + nextToken(); + value = TOKnotidentity; + goto L1; + + L1: + nextToken(); + e2 = parseRelExp(); + e = new IdentityExp(value, loc, e, e2); + continue; + + default: + break; + } + break; + } + return e; +} +#endif + +Expression *Parser::parseCmpExp() +{ Expression *e; + Expression *e2; + Token *t; + Loc loc = this->loc; + + e = parseShiftExp(); + enum TOK op = token.value; + + switch (op) + { + case TOKequal: + case TOKnotequal: + nextToken(); + e2 = parseShiftExp(); + e = new EqualExp(op, loc, e, e2); + break; + + case TOKis: + op = TOKidentity; + goto L1; + + case TOKnot: + // Attempt to identify '!is' + t = peek(&token); + if (t->value == TOKin) + { + nextToken(); + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + e = new NotExp(loc, e); + break; + } + if (t->value != TOKis) + break; + nextToken(); + op = TOKnotidentity; + goto L1; + + L1: + nextToken(); + e2 = parseShiftExp(); + e = new IdentityExp(op, loc, e, e2); + break; + + case TOKlt: + case TOKle: + case TOKgt: + case TOKge: + case TOKunord: + case TOKlg: + case TOKleg: + case TOKule: + case TOKul: + case TOKuge: + case TOKug: + case TOKue: + nextToken(); + e2 = parseShiftExp(); + e = new CmpExp(op, loc, e, e2); + break; + + case TOKin: + nextToken(); + e2 = parseShiftExp(); + e = new InExp(loc, e, e2); + break; + + default: + break; + } + return e; +} + +Expression *Parser::parseAndExp() +{ + Loc loc = this->loc; + + Expression *e = parseCmpExp(); + while (token.value == TOKand) + { + checkParens(TOKand, e); + nextToken(); + Expression *e2 = parseCmpExp(); + checkParens(TOKand, e2); + e = new AndExp(loc,e,e2); + loc = this->loc; + } + return e; +} + +Expression *Parser::parseXorExp() +{ + Loc loc = this->loc; + + Expression *e = parseAndExp(); + while (token.value == TOKxor) + { + checkParens(TOKxor, e); + nextToken(); + Expression *e2 = parseAndExp(); + checkParens(TOKxor, e2); + e = new XorExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseOrExp() +{ + Loc loc = this->loc; + + Expression *e = parseXorExp(); + while (token.value == TOKor) + { + checkParens(TOKor, e); + nextToken(); + Expression *e2 = parseXorExp(); + checkParens(TOKor, e2); + e = new OrExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseAndAndExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseOrExp(); + while (token.value == TOKandand) + { + nextToken(); + e2 = parseOrExp(); + e = new AndAndExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseOrOrExp() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + e = parseAndAndExp(); + while (token.value == TOKoror) + { + nextToken(); + e2 = parseAndAndExp(); + e = new OrOrExp(loc, e, e2); + } + return e; +} + +Expression *Parser::parseCondExp() +{ Expression *e; + Expression *e1; + Expression *e2; + Loc loc = this->loc; + + e = parseOrOrExp(); + if (token.value == TOKquestion) + { + nextToken(); + e1 = parseExpression(); + check(TOKcolon); + e2 = parseCondExp(); + e = new CondExp(loc, e, e1, e2); + } + return e; +} + +Expression *Parser::parseAssignExp() +{ Expression *e; + Expression *e2; + Loc loc; + + e = parseCondExp(); + while (1) + { + loc = this->loc; + switch (token.value) + { +#define X(tok,ector) \ + case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; + + X(TOKassign, AssignExp); + X(TOKaddass, AddAssignExp); + X(TOKminass, MinAssignExp); + X(TOKmulass, MulAssignExp); + X(TOKdivass, DivAssignExp); + X(TOKmodass, ModAssignExp); + X(TOKpowass, PowAssignExp); + X(TOKandass, AndAssignExp); + X(TOKorass, OrAssignExp); + X(TOKxorass, XorAssignExp); + X(TOKshlass, ShlAssignExp); + X(TOKshrass, ShrAssignExp); + X(TOKushrass, UshrAssignExp); + X(TOKcatass, CatAssignExp); + +#undef X + default: + break; + } + break; + } + return e; +} + +Expression *Parser::parseExpression() +{ Expression *e; + Expression *e2; + Loc loc = this->loc; + + //printf("Parser::parseExpression() loc = %d\n", loc.linnum); + e = parseAssignExp(); + while (token.value == TOKcomma) + { + nextToken(); + e2 = parseAssignExp(); + e = new CommaExp(loc, e, e2); + loc = this->loc; + } + return e; +} + + +/************************* + * Collect argument list. + * Assume current token is ',', '(' or '['. + */ + +Expressions *Parser::parseArguments() +{ // function call + Expressions *arguments; + Expression *arg; + enum TOK endtok; + + arguments = new Expressions(); + if (token.value == TOKlbracket) + endtok = TOKrbracket; + else + endtok = TOKrparen; + + { + nextToken(); + while (token.value != endtok) + { + arg = parseAssignExp(); + arguments->push(arg); + if (token.value == endtok) + break; + check(TOKcomma); + } + check(endtok); + } + return arguments; +} + +/******************************************* + */ + +Expression *Parser::parseNewExp(Expression *thisexp) +{ Type *t; + Expressions *newargs; + Expressions *arguments = NULL; + Expression *e; + Loc loc = this->loc; + + nextToken(); + newargs = NULL; + if (token.value == TOKlparen) + { + newargs = parseArguments(); + } + + // An anonymous nested class starts with "class" + if (token.value == TOKclass) + { + nextToken(); + if (token.value == TOKlparen) + arguments = parseArguments(); + + BaseClasses *baseclasses = NULL; + if (token.value != TOKlcurly) + baseclasses = parseBaseClasses(); + + Identifier *id = NULL; + ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); + + if (token.value != TOKlcurly) + { error("{ members } expected for anonymous class"); + cd->members = NULL; + } + else + { + nextToken(); + Dsymbols *decl = parseDeclDefs(0); + if (token.value != TOKrcurly) + error("class member expected"); + nextToken(); + cd->members = decl; + } + + e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); + + return e; + } + + t = parseBasicType(); + t = parseBasicType2(t); + if (t->ty == Taarray) + { TypeAArray *taa = (TypeAArray *)t; + Type *index = taa->index; + + Expression *e = index->toExpression(); + if (e) + { arguments = new Expressions(); + arguments->push(e); + t = new TypeDArray(taa->next); + } + else + { + error("need size of rightmost array, not type %s", index->toChars()); + return new NullExp(loc); + } + } + else if (t->ty == Tsarray) + { + TypeSArray *tsa = (TypeSArray *)t; + Expression *e = tsa->dim; + + arguments = new Expressions(); + arguments->push(e); + t = new TypeDArray(tsa->next); + } + else if (token.value == TOKlparen) + { + arguments = parseArguments(); + } + e = new NewExp(loc, thisexp, newargs, t, arguments); + return e; +} + +/********************************************** + */ + +void Parser::addComment(Dsymbol *s, unsigned char *blockComment) +{ + s->addComment(combineComments(blockComment, token.lineComment)); + token.lineComment = NULL; +} + + +/********************************** + * Set operator precedence for each operator. + */ + +enum PREC precedence[TOKMAX]; + +void initPrecedence() +{ + for (int i = 0; i < TOKMAX; i++) + precedence[i] = PREC_zero; + + precedence[TOKtype] = PREC_expr; + precedence[TOKerror] = PREC_expr; + + precedence[TOKtypeof] = PREC_primary; + precedence[TOKmixin] = PREC_primary; + + precedence[TOKdotvar] = PREC_primary; + precedence[TOKimport] = PREC_primary; + precedence[TOKidentifier] = PREC_primary; + precedence[TOKthis] = PREC_primary; + precedence[TOKsuper] = PREC_primary; + precedence[TOKint64] = PREC_primary; + precedence[TOKfloat64] = PREC_primary; + precedence[TOKnull] = PREC_primary; + precedence[TOKstring] = PREC_primary; + precedence[TOKarrayliteral] = PREC_primary; + precedence[TOKtypeid] = PREC_primary; + precedence[TOKis] = PREC_primary; + precedence[TOKassert] = PREC_primary; + precedence[TOKfunction] = PREC_primary; + precedence[TOKvar] = PREC_primary; + precedence[TOKsymoff] = PREC_primary; + precedence[TOKstructliteral] = PREC_primary; + precedence[TOKarraylength] = PREC_primary; + precedence[TOKtuple] = PREC_primary; +#if DMDV2 + precedence[TOKtraits] = PREC_primary; + precedence[TOKdefault] = PREC_primary; +#endif + + // post + precedence[TOKdotti] = PREC_primary; + precedence[TOKdot] = PREC_primary; + precedence[TOKdottd] = PREC_primary; +// precedence[TOKarrow] = PREC_primary; + precedence[TOKplusplus] = PREC_primary; + precedence[TOKminusminus] = PREC_primary; + precedence[TOKpreplusplus] = PREC_primary; + precedence[TOKpreminusminus] = PREC_primary; + precedence[TOKcall] = PREC_primary; + precedence[TOKslice] = PREC_primary; + precedence[TOKarray] = PREC_primary; + precedence[TOKindex] = PREC_primary; + + precedence[TOKaddress] = PREC_unary; + precedence[TOKstar] = PREC_unary; + precedence[TOKneg] = PREC_unary; + precedence[TOKuadd] = PREC_unary; + precedence[TOKnot] = PREC_unary; + precedence[TOKtobool] = PREC_add; + precedence[TOKtilde] = PREC_unary; + precedence[TOKdelete] = PREC_unary; + precedence[TOKnew] = PREC_unary; + precedence[TOKcast] = PREC_unary; + + precedence[TOKpow] = PREC_pow; + + precedence[TOKmul] = PREC_mul; + precedence[TOKdiv] = PREC_mul; + precedence[TOKmod] = PREC_mul; + precedence[TOKpow] = PREC_mul; + + precedence[TOKadd] = PREC_add; + precedence[TOKmin] = PREC_add; + precedence[TOKcat] = PREC_add; + + precedence[TOKshl] = PREC_shift; + precedence[TOKshr] = PREC_shift; + precedence[TOKushr] = PREC_shift; + + precedence[TOKlt] = PREC_rel; + precedence[TOKle] = PREC_rel; + precedence[TOKgt] = PREC_rel; + precedence[TOKge] = PREC_rel; + precedence[TOKunord] = PREC_rel; + precedence[TOKlg] = PREC_rel; + precedence[TOKleg] = PREC_rel; + precedence[TOKule] = PREC_rel; + precedence[TOKul] = PREC_rel; + precedence[TOKuge] = PREC_rel; + precedence[TOKug] = PREC_rel; + precedence[TOKue] = PREC_rel; + precedence[TOKin] = PREC_rel; + +#if 0 + precedence[TOKequal] = PREC_equal; + precedence[TOKnotequal] = PREC_equal; + precedence[TOKidentity] = PREC_equal; + precedence[TOKnotidentity] = PREC_equal; +#else + /* Note that we changed precedence, so that < and != have the same + * precedence. This change is in the parser, too. + */ + precedence[TOKequal] = PREC_rel; + precedence[TOKnotequal] = PREC_rel; + precedence[TOKidentity] = PREC_rel; + precedence[TOKnotidentity] = PREC_rel; +#endif + + precedence[TOKand] = PREC_and; + + precedence[TOKxor] = PREC_xor; + + precedence[TOKor] = PREC_or; + + precedence[TOKandand] = PREC_andand; + + precedence[TOKoror] = PREC_oror; + + precedence[TOKquestion] = PREC_cond; + + precedence[TOKassign] = PREC_assign; + precedence[TOKconstruct] = PREC_assign; + precedence[TOKblit] = PREC_assign; + precedence[TOKaddass] = PREC_assign; + precedence[TOKminass] = PREC_assign; + precedence[TOKcatass] = PREC_assign; + precedence[TOKmulass] = PREC_assign; + precedence[TOKdivass] = PREC_assign; + precedence[TOKmodass] = PREC_assign; + precedence[TOKpowass] = PREC_assign; + precedence[TOKshlass] = PREC_assign; + precedence[TOKshrass] = PREC_assign; + precedence[TOKushrass] = PREC_assign; + precedence[TOKandass] = PREC_assign; + precedence[TOKorass] = PREC_assign; + precedence[TOKxorass] = PREC_assign; + + precedence[TOKcomma] = PREC_expr; + precedence[TOKdeclaration] = PREC_expr; +} + + diff --git a/dmd2/parse.h b/dmd2/parse.h index c426b269..2dbf9773 100644 --- a/dmd2/parse.h +++ b/dmd2/parse.h @@ -1,146 +1,182 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_PARSE_H -#define DMD_PARSE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" -#include "lexer.h" -#include "enum.h" - -struct Type; -struct TypeQualified; -struct Expression; -struct Declaration; -struct Statement; -struct Import; -struct Initializer; -struct FuncDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct ConditionalDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct Condition; -struct Module; -struct ModuleDeclaration; -struct TemplateDeclaration; -struct TemplateInstance; -struct StaticAssert; - -/************************************ - * These control how parseStatement() works. - */ - -enum ParseStatementFlags -{ - PSsemi = 1, // empty ';' statements are allowed - PSscope = 2, // start a new scope - PScurly = 4, // { } statement is required - PScurlyscope = 8, // { } starts a new scope -}; - - -struct Parser : Lexer -{ - ModuleDeclaration *md; - enum LINK linkage; - Loc endloc; // set to location of last right curly - int inBrackets; // inside [] of array index or slice - - Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); - - Array *parseModule(); - Array *parseDeclDefs(int once); - Array *parseAutoDeclarations(unsigned storageClass, unsigned char *comment); - Array *parseBlock(); - void composeStorageClass(unsigned stc); - Expression *parseConstraint(); - TemplateDeclaration *parseTemplateDeclaration(); - TemplateParameters *parseTemplateParameterList(int flag = 0); - Dsymbol *parseMixin(); - Objects *parseTemplateArgumentList(); - Objects *parseTemplateArgumentList2(); - Objects *parseTemplateArgument(); - StaticAssert *parseStaticAssert(); - TypeQualified *parseTypeof(); - enum LINK parseLinkage(); - Condition *parseDebugCondition(); - Condition *parseVersionCondition(); - Condition *parseStaticIfCondition(); - Dsymbol *parseCtor(); - PostBlitDeclaration *parsePostBlit(); - DtorDeclaration *parseDtor(); - StaticCtorDeclaration *parseStaticCtor(); - StaticDtorDeclaration *parseStaticDtor(); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); - Arguments *parseParameters(int *pvarargs); - EnumDeclaration *parseEnum(); - Dsymbol *parseAggregate(); - BaseClasses *parseBaseClasses(); - Import *parseImport(Array *decldefs, int isstatic); - Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); - Type *parseBasicType(); - Type *parseBasicType2(Type *t); - Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); - Array *parseDeclarations(unsigned storage_class); - void parseContracts(FuncDeclaration *f); - Statement *parseStatement(int flags); - Initializer *parseInitializer(); - Expression *parseDefaultInitExp(); - void check(Loc loc, enum TOK value); - void check(enum TOK value); - void check(enum TOK value, const char *string); - int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); - int isBasicType(Token **pt); - int isDeclarator(Token **pt, int *haveId, enum TOK endtok); - int isParameters(Token **pt); - int isExpression(Token **pt); - int isTemplateInstance(Token *t, Token **pt); - int skipParens(Token *t, Token **pt); - - Expression *parseExpression(); - Expression *parsePrimaryExp(); - Expression *parseUnaryExp(); - Expression *parsePostExp(Expression *e); - Expression *parseMulExp(); - Expression *parseAddExp(); - Expression *parseShiftExp(); - Expression *parseRelExp(); - Expression *parseEqualExp(); - Expression *parseCmpExp(); - Expression *parseAndExp(); - Expression *parseXorExp(); - Expression *parseOrExp(); - Expression *parseAndAndExp(); - Expression *parseOrOrExp(); - Expression *parseCondExp(); - Expression *parseAssignExp(); - - Expressions *parseArguments(); - - Expression *parseNewExp(Expression *thisexp); - - void addComment(Dsymbol *s, unsigned char *blockComment); -}; - -#endif /* DMD_PARSE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2009 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. + +#ifndef DMD_PARSE_H +#define DMD_PARSE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "arraytypes.h" +#include "lexer.h" +#include "enum.h" + +struct Type; +struct TypeQualified; +struct Expression; +struct Declaration; +struct Statement; +struct Import; +struct Initializer; +struct FuncDeclaration; +struct CtorDeclaration; +struct PostBlitDeclaration; +struct DtorDeclaration; +struct StaticCtorDeclaration; +struct StaticDtorDeclaration; +struct SharedStaticCtorDeclaration; +struct SharedStaticDtorDeclaration; +struct ConditionalDeclaration; +struct InvariantDeclaration; +struct UnitTestDeclaration; +struct NewDeclaration; +struct DeleteDeclaration; +struct Condition; +struct Module; +struct ModuleDeclaration; +struct TemplateDeclaration; +struct TemplateInstance; +struct StaticAssert; + +/************************************ + * These control how parseStatement() works. + */ + +enum ParseStatementFlags +{ + PSsemi = 1, // empty ';' statements are allowed + PSscope = 2, // start a new scope + PScurly = 4, // { } statement is required + PScurlyscope = 8, // { } starts a new scope +}; + + +struct Parser : Lexer +{ + ModuleDeclaration *md; + enum LINK linkage; + Loc endloc; // set to location of last right curly + int inBrackets; // inside [] of array index or slice + + Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); + + Dsymbols *parseModule(); + Dsymbols *parseDeclDefs(int once); + Dsymbols *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); + Dsymbols *parseBlock(); + void composeStorageClass(StorageClass stc); + StorageClass parseAttribute(); + StorageClass parsePostfix(); + Expression *parseConstraint(); + TemplateDeclaration *parseTemplateDeclaration(int ismixin); + TemplateParameters *parseTemplateParameterList(int flag = 0); + Dsymbol *parseMixin(); + Objects *parseTemplateArgumentList(); + Objects *parseTemplateArgumentList2(); + Objects *parseTemplateArgument(); + StaticAssert *parseStaticAssert(); + TypeQualified *parseTypeof(); + enum LINK parseLinkage(); + Condition *parseDebugCondition(); + Condition *parseVersionCondition(); + Condition *parseStaticIfCondition(); + Dsymbol *parseCtor(); + PostBlitDeclaration *parsePostBlit(); + DtorDeclaration *parseDtor(); + StaticCtorDeclaration *parseStaticCtor(); + StaticDtorDeclaration *parseStaticDtor(); + SharedStaticCtorDeclaration *parseSharedStaticCtor(); + SharedStaticDtorDeclaration *parseSharedStaticDtor(); + InvariantDeclaration *parseInvariant(); + UnitTestDeclaration *parseUnitTest(); + NewDeclaration *parseNew(); + DeleteDeclaration *parseDelete(); + Parameters *parseParameters(int *pvarargs); + EnumDeclaration *parseEnum(); + Dsymbol *parseAggregate(); + BaseClasses *parseBaseClasses(); + Import *parseImport(Dsymbols *decldefs, int isstatic); + Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); + Type *parseBasicType(); + Type *parseBasicType2(Type *t); + Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL); + Dsymbols *parseDeclarations(StorageClass storage_class); + void parseContracts(FuncDeclaration *f); + Statement *parseStatement(int flags); + Initializer *parseInitializer(); + Expression *parseDefaultInitExp(); + void check(Loc loc, enum TOK value); + void check(enum TOK value); + void check(enum TOK value, const char *string); + void checkParens(enum TOK value, Expression *e); + int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); + int isBasicType(Token **pt); + int isDeclarator(Token **pt, int *haveId, enum TOK endtok); + int isParameters(Token **pt); + int isExpression(Token **pt); + int isTemplateInstance(Token *t, Token **pt); + int skipParens(Token *t, Token **pt); + + Expression *parseExpression(); + Expression *parsePrimaryExp(); + Expression *parseUnaryExp(); + Expression *parsePostExp(Expression *e); + Expression *parseMulExp(); + Expression *parseAddExp(); + Expression *parseShiftExp(); +#if DMDV1 + Expression *parseRelExp(); + Expression *parseEqualExp(); +#endif + Expression *parseCmpExp(); + Expression *parseAndExp(); + Expression *parseXorExp(); + Expression *parseOrExp(); + Expression *parseAndAndExp(); + Expression *parseOrOrExp(); + Expression *parseCondExp(); + Expression *parseAssignExp(); + + Expressions *parseArguments(); + + Expression *parseNewExp(Expression *thisexp); + + void addComment(Dsymbol *s, unsigned char *blockComment); +}; + +// Operator precedence - greater values are higher precedence + +enum PREC +{ + PREC_zero, + PREC_expr, + PREC_assign, + PREC_cond, + PREC_oror, + PREC_andand, + PREC_or, + PREC_xor, + PREC_and, + PREC_equal, + PREC_rel, + PREC_shift, + PREC_add, + PREC_mul, + PREC_pow, + PREC_unary, + PREC_primary, +}; + +extern enum PREC precedence[TOKMAX]; + +void initPrecedence(); + +#endif /* DMD_PARSE_H */ diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c new file mode 100644 index 00000000..a4873bc7 --- /dev/null +++ b/dmd2/root/aav.c @@ -0,0 +1,188 @@ +/** + * Implementation of associative arrays. + * + */ + +#include +#include +#include + +#include "aav.h" + +static const size_t prime_list[] = { + 31UL, + 97UL, 389UL, + 1543UL, 6151UL, + 24593UL, 98317UL, + 393241UL, 1572869UL, + 6291469UL, 25165843UL, + 100663319UL, 402653189UL, + 1610612741UL, 4294967291UL, +}; + +struct aaA +{ + aaA *next; + Key key; + Value value; +}; + +struct AA +{ + aaA* *b; + size_t b_length; + size_t nodes; // total number of aaA nodes + aaA* binit[4]; // initial value of b[] +}; + +static const AA bbinit = { NULL, }; + +/**************************************************** + * Determine number of entries in associative array. + */ + +size_t _aaLen(AA* aa) +{ + return aa ? aa->nodes : 0; +} + + +/************************************************* + * Get pointer to value in associative array indexed by key. + * Add entry for key if it is not already there. + */ + +Value* _aaGet(AA** paa, Key key) +{ + //printf("paa = %p\n", paa); + + if (!*paa) + { AA *a = new AA(); + *a = bbinit; + a->b = a->binit; + a->b_length = sizeof(a->binit) / sizeof(a->binit[0]); + *paa = a; + assert((*paa)->b_length == 4); + } + //printf("paa = %p, *paa = %p\n", paa, *paa); + + assert((*paa)->b_length); + size_t i = (size_t)key % (*paa)->b_length; + aaA** pe = &(*paa)->b[i]; + aaA *e; + while ((e = *pe) != NULL) + { + if (key == e->key) + return &e->value; + pe = &e->next; + } + + // Not found, create new elem + //printf("create new one\n"); + e = new aaA(); + e->next = NULL; + e->key = key; + e->value = NULL; + *pe = e; + + size_t nodes = ++(*paa)->nodes; + //printf("length = %d, nodes = %d\n", paa.a.b.length, nodes); + if (nodes > (*paa)->b_length * 4) + { + //printf("rehash\n"); + _aaRehash(paa); + } + + return &e->value; +} + + +/************************************************* + * Get value in associative array indexed by key. + * Returns NULL if it is not already there. + */ + +Value _aaGetRvalue(AA* aa, Key key) +{ + //printf("_aaGetRvalue(key = %p)\n", key); + if (!aa) + return NULL; + + size_t len = aa->b_length; + + if (len) + { + size_t i = (size_t)key % len; + aaA* e = aa->b[i]; + while (e) + { + if (key == e->key) + return e->value; + e = e->next; + } + } + return NULL; // not found +} + + +/******************************************** + * Rehash an array. + */ + +void _aaRehash(AA** paa) +{ + //printf("Rehash\n"); + if (*paa) + { + AA newb = bbinit; + AA *aa = *paa; + size_t len = _aaLen(*paa); + if (len) + { size_t i; + + for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++) + { + if (len <= prime_list[i]) + break; + } + len = prime_list[i]; + newb.b = new aaA*[len]; + memset(newb.b, 0, len * sizeof(aaA*)); + newb.b_length = len; + + for (size_t k = 0; k < aa->b_length; k++) + { aaA *e = aa->b[k]; + while (e) + { aaA* enext = e->next; + size_t j = (size_t)e->key % len; + e->next = newb.b[j]; + newb.b[j] = e; + e = enext; + } + } + if (aa->b != aa->binit) + delete aa->b; + + newb.nodes = aa->nodes; + } + + **paa = newb; + } +} + + +#if UNITTEST + +void unittest_aa() +{ + AA* aa = NULL; + Value v = _aaGetRvalue(aa, NULL); + assert(!v); + Value *pv = _aaGet(&aa, NULL); + assert(pv); + *pv = (void *)3; + v = _aaGetRvalue(aa, NULL); + assert(v == (void *)3); +} + +#endif diff --git a/dmd2/root/aav.h b/dmd2/root/aav.h new file mode 100644 index 00000000..266b5a83 --- /dev/null +++ b/dmd2/root/aav.h @@ -0,0 +1,11 @@ + +typedef void* Value; +typedef void* Key; + +struct AA; + +size_t _aaLen(AA* aa); +Value* _aaGet(AA** aa, Key key); +Value _aaGetRvalue(AA* aa, Key key); +void _aaRehash(AA** paa); + diff --git a/dmd2/root/array.c b/dmd2/root/array.c index 9ec8784d..affdcff5 100644 --- a/dmd2/root/array.c +++ b/dmd2/root/array.c @@ -1,224 +1,254 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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 -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER || __MINGW32__ -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#if _WIN32 -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "dchar.h" -#include "rmem.h" - - -/********************************* Array ****************************/ - -Array::Array() -{ - data = NULL; - dim = 0; - allocdim = 0; -} - -Array::~Array() -{ - mem.free(data); -} - -void Array::mark() -{ unsigned u; - - mem.mark(data); - for (u = 0; u < dim; u++) - mem.mark(data[u]); // BUG: what if arrays of Object's? -} - -void Array::reserve(unsigned nentries) -{ - //printf("Array::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); - if (allocdim - dim < nentries) - { - allocdim = dim + nentries; - data = (void **)mem.realloc(data, allocdim * sizeof(*data)); - } -} - -void Array::setDim(unsigned newdim) -{ - if (dim < newdim) - { - reserve(newdim - dim); - } - dim = newdim; -} - -void Array::fixDim() -{ - if (dim != allocdim) - { data = (void **)mem.realloc(data, dim * sizeof(*data)); - allocdim = dim; - } -} - -void Array::push(void *ptr) -{ - reserve(1); - data[dim++] = ptr; -} - -void *Array::pop() -{ - return data[--dim]; -} - -void Array::shift(void *ptr) -{ - reserve(1); - memmove(data + 1, data, dim * sizeof(*data)); - data[0] = ptr; - dim++; -} - -void Array::insert(unsigned index, void *ptr) -{ - reserve(1); - memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); - data[index] = ptr; - dim++; -} - - -void Array::insert(unsigned index, Array *a) -{ - if (a) - { unsigned d; - - d = a->dim; - reserve(d); - if (dim != index) - memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); - memcpy(data + index, a->data, d * sizeof(*data)); - dim += d; - } -} - - -/*********************************** - * Append array a to this array. - */ - -void Array::append(Array *a) -{ - insert(dim, a); -} - -void Array::remove(unsigned i) -{ - memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); - dim--; -} - -char *Array::toChars() -{ - unsigned len; - unsigned u; - char **buf; - char *str; - char *p; - - buf = (char **)alloca(dim * sizeof(char *)); - len = 2; - for (u = 0; u < dim; u++) - { - buf[u] = ((Object *)data[u])->toChars(); - len += strlen(buf[u]) + 1; - } - str = (char *)mem.malloc(len); - - str[0] = '['; - p = str + 1; - for (u = 0; u < dim; u++) - { - if (u) - *p++ = ','; - len = strlen(buf[u]); - memcpy(p,buf[u],len); - p += len; - } - *p++ = ']'; - *p = 0; - return str; -} - -void Array::zero() -{ - memset(data,0,dim * sizeof(data[0])); -} - -void *Array::tos() -{ - return dim ? data[dim - 1] : NULL; -} - -int -#if _WIN32 - __cdecl -#endif - Array_sort_compare(const void *x, const void *y) -{ - Object *ox = *(Object **)x; - Object *oy = *(Object **)y; - - return ox->compare(oy); -} - -void Array::sort() -{ - if (dim) - { - qsort(data, dim, sizeof(Object *), Array_sort_compare); - } -} - -Array *Array::copy() -{ - Array *a = new Array(); - - a->setDim(dim); - memcpy(a->data, data, dim * sizeof(void *)); - return a; -} - + +// Copyright (c) 1999-2010 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 +#include +#include +#include +#include + +#if (defined (__SVR4) && defined (__sun)) +#include +#endif + +#if _MSC_VER || __MINGW32__ +#include +#endif + +#if IN_GCC +#include "gdc_alloca.h" +#endif + +#if _WIN32 +#include +#endif + +#ifndef _WIN32 +#include +#include +#include +#include +#include +#include +#endif + +#include "port.h" +#include "root.h" +#include "dchar.h" +#include "rmem.h" + + +/********************************* Array ****************************/ + +Array::Array() +{ + data = SMALLARRAYCAP ? &smallarray[0] : NULL; + dim = 0; + allocdim = SMALLARRAYCAP; +} + +Array::~Array() +{ + if (data != &smallarray[0]) + mem.free(data); +} + +void Array::mark() +{ unsigned u; + + mem.mark(data); + for (u = 0; u < dim; u++) + mem.mark(data[u]); // BUG: what if arrays of Object's? +} + +void Array::reserve(unsigned nentries) +{ + //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", dim, allocdim, nentries); + if (allocdim - dim < nentries) + { + if (allocdim == 0) + { // Not properly initialized, someone memset it to zero + if (nentries <= SMALLARRAYCAP) + { allocdim = SMALLARRAYCAP; + data = SMALLARRAYCAP ? &smallarray[0] : NULL; + } + else + { allocdim = nentries; + data = (void **)mem.malloc(allocdim * sizeof(*data)); + } + } + else if (allocdim == SMALLARRAYCAP) + { + allocdim = dim + nentries; + data = (void **)mem.malloc(allocdim * sizeof(*data)); + memcpy(data, &smallarray[0], dim * sizeof(*data)); + } + else + { allocdim = dim + nentries; + data = (void **)mem.realloc(data, allocdim * sizeof(*data)); + } + } +} + +void Array::setDim(unsigned newdim) +{ + if (dim < newdim) + { + reserve(newdim - dim); + } + dim = newdim; +} + +void Array::fixDim() +{ + if (dim != allocdim) + { + if (allocdim >= SMALLARRAYCAP) + { + if (dim <= SMALLARRAYCAP) + { + memcpy(&smallarray[0], data, dim * sizeof(*data)); + mem.free(data); + } + else + data = (void **)mem.realloc(data, dim * sizeof(*data)); + } + allocdim = dim; + } +} + +void Array::push(void *ptr) +{ + reserve(1); + data[dim++] = ptr; +} + +void *Array::pop() +{ + return data[--dim]; +} + +void Array::shift(void *ptr) +{ + reserve(1); + memmove(data + 1, data, dim * sizeof(*data)); + data[0] = ptr; + dim++; +} + +void Array::insert(unsigned index, void *ptr) +{ + reserve(1); + memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); + data[index] = ptr; + dim++; +} + + +void Array::insert(unsigned index, Array *a) +{ + if (a) + { unsigned d; + + d = a->dim; + reserve(d); + if (dim != index) + memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); + memcpy(data + index, a->data, d * sizeof(*data)); + dim += d; + } +} + + +/*********************************** + * Append array a to this array. + */ + +void Array::append(Array *a) +{ + insert(dim, a); +} + +void Array::remove(unsigned i) +{ + memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); + dim--; +} + +char *Array::toChars() +{ + unsigned len; + unsigned u; + char **buf; + char *str; + char *p; + + buf = (char **)alloca(dim * sizeof(char *)); + len = 2; + for (u = 0; u < dim; u++) + { + buf[u] = ((Object *)data[u])->toChars(); + len += strlen(buf[u]) + 1; + } + str = (char *)mem.malloc(len); + + str[0] = '['; + p = str + 1; + for (u = 0; u < dim; u++) + { + if (u) + *p++ = ','; + len = strlen(buf[u]); + memcpy(p,buf[u],len); + p += len; + } + *p++ = ']'; + *p = 0; + return str; +} + +void Array::zero() +{ + memset(data,0,dim * sizeof(data[0])); +} + +void *Array::tos() +{ + return dim ? data[dim - 1] : NULL; +} + +int +#if _WIN32 + __cdecl +#endif + Array_sort_compare(const void *x, const void *y) +{ + Object *ox = *(Object **)x; + Object *oy = *(Object **)y; + + return ox->compare(oy); +} + +void Array::sort() +{ + if (dim) + { + qsort(data, dim, sizeof(Object *), Array_sort_compare); + } +} + +Array *Array::copy() +{ + Array *a = new Array(); + + a->setDim(dim); + memcpy(a->data, data, dim * sizeof(void *)); + return a; +} + diff --git a/dmd2/root/async.c b/dmd2/root/async.c index 7230f386..c6112f4f 100644 --- a/dmd2/root/async.c +++ b/dmd2/root/async.c @@ -8,7 +8,6 @@ #if _WIN32 #include -#include #include #include @@ -43,7 +42,7 @@ struct AsyncRead AsyncRead *AsyncRead::create(size_t nfiles) { AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); + (nfiles - 1) * sizeof(FileData)); aw->filesmax = nfiles; return aw; } @@ -64,22 +63,22 @@ void AsyncRead::start() //printf("aw->filesdim = %p %d\n", this, filesdim); if (filesdim) { - unsigned threadaddr; - hThread = (HANDLE) _beginthreadex(NULL, - 0, - &startthread, - this, - 0, - (unsigned *)&threadaddr); + unsigned threadaddr; + hThread = (HANDLE) _beginthreadex(NULL, + 0, + &startthread, + this, + 0, + (unsigned *)&threadaddr); - if (hThread) - { - SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); - } - else - { - assert(0); - } + if (hThread) + { + SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); + } + else + { + assert(0); + } } } @@ -87,7 +86,7 @@ int AsyncRead::read(size_t i) { FileData *f = &files[i]; WaitForSingleObject(f->event, INFINITE); - Sleep(0); // give up time slice + Sleep(0); // give up time slice return f->result; } @@ -104,13 +103,160 @@ unsigned __stdcall startthread(void *p) //printf("aw->filesdim = %p %d\n", aw, aw->filesdim); for (size_t i = 0; i < aw->filesdim; i++) - { FileData *f = &aw->files[i]; + { FileData *f = &aw->files[i]; - f->result = f->file->read(); - SetEvent(f->event); + f->result = f->file->read(); + SetEvent(f->event); } _endthreadex(EXIT_SUCCESS); - return EXIT_SUCCESS; // if skidding + return EXIT_SUCCESS; // if skidding +} + +#elif linux // Posix + +#include +#include +#include + +#include "root.h" +#include "rmem.h" + +void *startthread(void *arg); + +void err_abort(int status, const char *msg) +{ + fprintf(stderr, "fatal error = %d, %s\n", status, msg); + exit(EXIT_FAILURE); +} + +struct FileData +{ + File *file; + int result; + + pthread_mutex_t mutex; + pthread_cond_t cond; + int value; +}; + +struct AsyncRead +{ + static AsyncRead *create(size_t nfiles); + void addFile(File *file); + void start(); + int read(size_t i); + static void dispose(AsyncRead *); + + size_t filesdim; + size_t filesmax; + FileData files[1]; +}; + + +AsyncRead *AsyncRead::create(size_t nfiles) +{ + AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + + (nfiles - 1) * sizeof(FileData)); + aw->filesmax = nfiles; + return aw; +} + +void AsyncRead::addFile(File *file) +{ + //printf("addFile(file = %p)\n", file); + //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); + assert(filesdim < filesmax); + FileData *f = &files[filesdim]; + f->file = file; + + int status = pthread_mutex_init(&f->mutex, NULL); + if (status != 0) + err_abort(status, "init mutex"); + status = pthread_cond_init(&f->cond, NULL); + if (status != 0) + err_abort(status, "init cond"); + + filesdim++; +} + +void AsyncRead::start() +{ + //printf("aw->filesdim = %p %d\n", this, filesdim); + if (filesdim) + { + pthread_t thread_id; + int status = pthread_create(&thread_id, + NULL, + &startthread, + this); + if (status != 0) + err_abort(status, "create thread"); + } +} + +int AsyncRead::read(size_t i) +{ + FileData *f = &files[i]; + + // Wait for the event + int status = pthread_mutex_lock(&f->mutex); + if (status != 0) + err_abort(status, "lock mutex"); + while (f->value == 0) + { + status = pthread_cond_wait(&f->cond, &f->mutex); + if (status != 0) + err_abort(status, "wait on condition"); + } + status = pthread_mutex_unlock(&f->mutex); + if (status != 0) + err_abort(status, "unlock mutex"); + + return f->result; +} + +void AsyncRead::dispose(AsyncRead *aw) +{ + //printf("AsyncRead::dispose()\n"); + for (int i = 0; i < aw->filesdim; i++) + { + FileData *f = &aw->files[i]; + int status = pthread_cond_destroy(&f->cond); + if (status != 0) + err_abort(status, "cond destroy"); + status = pthread_mutex_destroy(&f->mutex); + if (status != 0) + err_abort(status, "mutex destroy"); + } + delete aw; +} + + +void *startthread(void *p) +{ + AsyncRead *aw = (AsyncRead *)p; + + //printf("startthread: aw->filesdim = %p %d\n", aw, aw->filesdim); + size_t dim = aw->filesdim; + for (size_t i = 0; i < dim; i++) + { FileData *f = &aw->files[i]; + + f->result = f->file->read(); + + // Set event + int status = pthread_mutex_lock(&f->mutex); + if (status != 0) + err_abort(status, "lock mutex"); + f->value = 1; + status = pthread_cond_signal(&f->cond); + if (status != 0) + err_abort(status, "signal condition"); + status = pthread_mutex_unlock(&f->mutex); + if (status != 0) + err_abort(status, "unlock mutex"); + } + + return NULL; // end thread } #else @@ -147,7 +293,7 @@ struct AsyncRead AsyncRead *AsyncRead::create(size_t nfiles) { AsyncRead *aw = (AsyncRead *)mem.calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); + (nfiles - 1) * sizeof(FileData)); aw->filesmax = nfiles; return aw; } diff --git a/dmd2/root/async.h b/dmd2/root/async.h index cbecd25e..6f25f367 100644 --- a/dmd2/root/async.h +++ b/dmd2/root/async.h @@ -1,33 +1,33 @@ - -// Copyright (c) 2009-2009 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. - -#ifndef ASYNC_H -#define ASYNC_H - -#if __DMC__ -#pragma once -#endif - - -/******************* - * Simple interface to read files asynchronously in another - * thread. - */ - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); -}; - - -#endif + +// Copyright (c) 2009-2009 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. + +#ifndef ASYNC_H +#define ASYNC_H + +#if __DMC__ +#pragma once +#endif + + +/******************* + * Simple interface to read files asynchronously in another + * thread. + */ + +struct AsyncRead +{ + static AsyncRead *create(size_t nfiles); + void addFile(File *file); + void start(); + int read(size_t i); + static void dispose(AsyncRead *); +}; + + +#endif diff --git a/dmd2/root/dchar.c b/dmd2/root/dchar.c index 94d97d1e..c9462197 100644 --- a/dmd2/root/dchar.c +++ b/dmd2/root/dchar.c @@ -1,482 +1,482 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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 -#include -#include -#include - -#include "dchar.h" -#include "rmem.h" - -#if M_UNICODE - -// Converts a char string to Unicode - -dchar *Dchar::dup(char *p) -{ - dchar *s; - size_t len; - - if (!p) - return NULL; - len = strlen(p); - s = (dchar *)mem.malloc((len + 1) * sizeof(dchar)); - for (unsigned i = 0; i < len; i++) - { - s[i] = (dchar)(p[i] & 0xFF); - } - s[len] = 0; - return s; -} - -dchar *Dchar::memchr(dchar *p, int c, int count) -{ - int u; - - for (u = 0; u < count; u++) - { - if (p[u] == c) - return p + u; - } - return NULL; -} - -#if _WIN32 && __DMC__ -__declspec(naked) -unsigned Dchar::calcHash(const dchar *str, unsigned len) -{ - __asm - { - mov ECX,4[ESP] - mov EDX,8[ESP] - xor EAX,EAX - test EDX,EDX - je L92 - -LC8: cmp EDX,1 - je L98 - cmp EDX,2 - je LAE - - add EAX,[ECX] -// imul EAX,EAX,025h - lea EAX,[EAX][EAX*8] - add ECX,4 - sub EDX,2 - jmp LC8 - -L98: mov DX,[ECX] - and EDX,0FFFFh - add EAX,EDX - ret - -LAE: add EAX,[ECX] -L92: ret - } -} -#else -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - unsigned hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str; - return hash; - - case 2: - hash += *(const uint32_t *)str; - return hash; - - default: - hash += *(const uint32_t *)str; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} -#endif - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str | 0x20; - return hash; - - case 2: - hash += *(const uint32_t *)str | 0x200020; - return hash; - - default: - hash += *(const uint32_t *)str | 0x200020; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} - -#elif MCBS - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -#elif UTF8 - -// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 - -char Dchar::mblen[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1, -}; - -dchar *Dchar::dec(dchar *pstart, dchar *p) -{ - while ((p[-1] & 0xC0) == 0x80) - p--; - return p; -} - -int Dchar::get(dchar *p) -{ - unsigned c; - unsigned char *q = (unsigned char *)p; - - c = q[0]; - switch (mblen[c]) - { - case 2: - c = ((c - 0xC0) << 6) | - (q[1] - 0x80); - break; - - case 3: - c = ((c - 0xE0) << 12) | - ((q[1] - 0x80) << 6) | - (q[2] - 0x80); - break; - - case 4: - c = ((c - 0xF0) << 18) | - ((q[1] - 0x80) << 12) | - ((q[2] - 0x80) << 6) | - (q[3] - 0x80); - break; - - case 5: - c = ((c - 0xF8) << 24) | - ((q[1] - 0x80) << 18) | - ((q[2] - 0x80) << 12) | - ((q[3] - 0x80) << 6) | - (q[4] - 0x80); - break; - - case 6: - c = ((c - 0xFC) << 30) | - ((q[1] - 0x80) << 24) | - ((q[2] - 0x80) << 18) | - ((q[3] - 0x80) << 12) | - ((q[4] - 0x80) << 6) | - (q[5] - 0x80); - break; - } - return c; -} - -dchar *Dchar::put(dchar *p, unsigned c) -{ - if (c <= 0x7F) - { - *p++ = c; - } - else if (c <= 0x7FF) - { - p[0] = 0xC0 + (c >> 6); - p[1] = 0x80 + (c & 0x3F); - p += 2; - } - else if (c <= 0xFFFF) - { - p[0] = 0xE0 + (c >> 12); - p[1] = 0x80 + ((c >> 6) & 0x3F); - p[2] = 0x80 + (c & 0x3F); - p += 3; - } - else if (c <= 0x1FFFFF) - { - p[0] = 0xF0 + (c >> 18); - p[1] = 0x80 + ((c >> 12) & 0x3F); - p[2] = 0x80 + ((c >> 6) & 0x3F); - p[3] = 0x80 + (c & 0x3F); - p += 4; - } - else if (c <= 0x3FFFFFF) - { - p[0] = 0xF8 + (c >> 24); - p[1] = 0x80 + ((c >> 18) & 0x3F); - p[2] = 0x80 + ((c >> 12) & 0x3F); - p[3] = 0x80 + ((c >> 6) & 0x3F); - p[4] = 0x80 + (c & 0x3F); - p += 5; - } - else if (c <= 0x7FFFFFFF) - { - p[0] = 0xFC + (c >> 30); - p[1] = 0x80 + ((c >> 24) & 0x3F); - p[2] = 0x80 + ((c >> 18) & 0x3F); - p[3] = 0x80 + ((c >> 12) & 0x3F); - p[4] = 0x80 + ((c >> 6) & 0x3F); - p[5] = 0x80 + (c & 0x3F); - p += 6; - } - else - assert(0); // not a UCS-4 character - return p; -} - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if __I86__ - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if __I86__ - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if __I86__ - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - - str += 4; - len -= 4; - break; - } - } -} - -#else // ascii - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if __I86__ - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if __I86__ - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if __I86__ - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - str += 4; - len -= 4; - break; - } - } -} - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]) | 0x202020; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str | 0x20202020; - str += 4; - len -= 4; - break; - } - } -} - -#endif - -#if 0 -#include - -void main() -{ - // Print out values to hardcode into Dchar::mblen[] - int c; - int s; - - for (c = 0; c < 256; c++) - { - s = 1; - if (c >= 0xC0 && c <= 0xDF) - s = 2; - if (c >= 0xE0 && c <= 0xEF) - s = 3; - if (c >= 0xF0 && c <= 0xF7) - s = 4; - if (c >= 0xF8 && c <= 0xFB) - s = 5; - if (c >= 0xFC && c <= 0xFD) - s = 6; - - printf("%d", s); - if ((c & 15) == 15) - printf(",\n"); - else - printf(","); - } -} -#endif + +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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 +#include +#include +#include + +#include "dchar.h" +#include "rmem.h" + +#if M_UNICODE + +// Converts a char string to Unicode + +dchar *Dchar::dup(char *p) +{ + dchar *s; + size_t len; + + if (!p) + return NULL; + len = strlen(p); + s = (dchar *)mem.malloc((len + 1) * sizeof(dchar)); + for (unsigned i = 0; i < len; i++) + { + s[i] = (dchar)(p[i] & 0xFF); + } + s[len] = 0; + return s; +} + +dchar *Dchar::memchr(dchar *p, int c, int count) +{ + int u; + + for (u = 0; u < count; u++) + { + if (p[u] == c) + return p + u; + } + return NULL; +} + +#if _WIN32 && __DMC__ +__declspec(naked) +unsigned Dchar::calcHash(const dchar *str, unsigned len) +{ + __asm + { + mov ECX,4[ESP] + mov EDX,8[ESP] + xor EAX,EAX + test EDX,EDX + je L92 + +LC8: cmp EDX,1 + je L98 + cmp EDX,2 + je LAE + + add EAX,[ECX] +// imul EAX,EAX,025h + lea EAX,[EAX][EAX*8] + add ECX,4 + sub EDX,2 + jmp LC8 + +L98: mov DX,[ECX] + and EDX,0FFFFh + add EAX,EDX + ret + +LAE: add EAX,[ECX] +L92: ret + } +} +#else +hash_t Dchar::calcHash(const dchar *str, size_t len) +{ + unsigned hash = 0; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash += *(const uint16_t *)str; + return hash; + + case 2: + hash += *(const uint32_t *)str; + return hash; + + default: + hash += *(const uint32_t *)str; + hash *= 37; + str += 2; + len -= 2; + break; + } + } +} +#endif + +hash_t Dchar::icalcHash(const dchar *str, size_t len) +{ + hash_t hash = 0; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash += *(const uint16_t *)str | 0x20; + return hash; + + case 2: + hash += *(const uint32_t *)str | 0x200020; + return hash; + + default: + hash += *(const uint32_t *)str | 0x200020; + hash *= 37; + str += 2; + len -= 2; + break; + } + } +} + +#elif MCBS + +hash_t Dchar::calcHash(const dchar *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str; + return hash; + + case 2: + hash *= 37; + hash += *(const uint16_t *)str; + return hash; + + case 3: + hash *= 37; + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; + return hash; + + default: + hash *= 37; + hash += *(const uint32_t *)str; + str += 4; + len -= 4; + break; + } + } +} + +#elif UTF8 + +// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 + +char Dchar::mblen[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1, +}; + +dchar *Dchar::dec(dchar *pstart, dchar *p) +{ + while ((p[-1] & 0xC0) == 0x80) + p--; + return p; +} + +int Dchar::get(dchar *p) +{ + unsigned c; + unsigned char *q = (unsigned char *)p; + + c = q[0]; + switch (mblen[c]) + { + case 2: + c = ((c - 0xC0) << 6) | + (q[1] - 0x80); + break; + + case 3: + c = ((c - 0xE0) << 12) | + ((q[1] - 0x80) << 6) | + (q[2] - 0x80); + break; + + case 4: + c = ((c - 0xF0) << 18) | + ((q[1] - 0x80) << 12) | + ((q[2] - 0x80) << 6) | + (q[3] - 0x80); + break; + + case 5: + c = ((c - 0xF8) << 24) | + ((q[1] - 0x80) << 18) | + ((q[2] - 0x80) << 12) | + ((q[3] - 0x80) << 6) | + (q[4] - 0x80); + break; + + case 6: + c = ((c - 0xFC) << 30) | + ((q[1] - 0x80) << 24) | + ((q[2] - 0x80) << 18) | + ((q[3] - 0x80) << 12) | + ((q[4] - 0x80) << 6) | + (q[5] - 0x80); + break; + } + return c; +} + +dchar *Dchar::put(dchar *p, unsigned c) +{ + if (c <= 0x7F) + { + *p++ = c; + } + else if (c <= 0x7FF) + { + p[0] = 0xC0 + (c >> 6); + p[1] = 0x80 + (c & 0x3F); + p += 2; + } + else if (c <= 0xFFFF) + { + p[0] = 0xE0 + (c >> 12); + p[1] = 0x80 + ((c >> 6) & 0x3F); + p[2] = 0x80 + (c & 0x3F); + p += 3; + } + else if (c <= 0x1FFFFF) + { + p[0] = 0xF0 + (c >> 18); + p[1] = 0x80 + ((c >> 12) & 0x3F); + p[2] = 0x80 + ((c >> 6) & 0x3F); + p[3] = 0x80 + (c & 0x3F); + p += 4; + } + else if (c <= 0x3FFFFFF) + { + p[0] = 0xF8 + (c >> 24); + p[1] = 0x80 + ((c >> 18) & 0x3F); + p[2] = 0x80 + ((c >> 12) & 0x3F); + p[3] = 0x80 + ((c >> 6) & 0x3F); + p[4] = 0x80 + (c & 0x3F); + p += 5; + } + else if (c <= 0x7FFFFFFF) + { + p[0] = 0xFC + (c >> 30); + p[1] = 0x80 + ((c >> 24) & 0x3F); + p[2] = 0x80 + ((c >> 18) & 0x3F); + p[3] = 0x80 + ((c >> 12) & 0x3F); + p[4] = 0x80 + ((c >> 6) & 0x3F); + p[5] = 0x80 + (c & 0x3F); + p += 6; + } + else + assert(0); // not a UCS-4 character + return p; +} + +hash_t Dchar::calcHash(const dchar *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str; + return hash; + + case 2: + hash *= 37; +#if __I86__ + hash += *(const uint16_t *)str; +#else + hash += str[0] * 256 + str[1]; +#endif + return hash; + + case 3: + hash *= 37; +#if __I86__ + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; +#else + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif + return hash; + + default: + hash *= 37; +#if __I86__ + hash += *(const uint32_t *)str; +#else + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif + + str += 4; + len -= 4; + break; + } + } +} + +#else // ascii + +hash_t Dchar::calcHash(const dchar *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str; + return hash; + + case 2: + hash *= 37; +#if __I86__ + hash += *(const uint16_t *)str; +#else + hash += str[0] * 256 + str[1]; +#endif + return hash; + + case 3: + hash *= 37; +#if __I86__ + hash += (*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]; +#else + hash += (str[0] * 256 + str[1]) * 256 + str[2]; +#endif + return hash; + + default: + hash *= 37; +#if __I86__ + hash += *(const uint32_t *)str; +#else + hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; +#endif + str += 4; + len -= 4; + break; + } + } +} + +hash_t Dchar::icalcHash(const dchar *str, size_t len) +{ + hash_t hash = 0; + + while (1) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(const uint8_t *)str | 0x20; + return hash; + + case 2: + hash *= 37; + hash += *(const uint16_t *)str | 0x2020; + return hash; + + case 3: + hash *= 37; + hash += ((*(const uint16_t *)str << 8) + + ((const uint8_t *)str)[2]) | 0x202020; + return hash; + + default: + hash *= 37; + hash += *(const uint32_t *)str | 0x20202020; + str += 4; + len -= 4; + break; + } + } +} + +#endif + +#if 0 +#include + +void main() +{ + // Print out values to hardcode into Dchar::mblen[] + int c; + int s; + + for (c = 0; c < 256; c++) + { + s = 1; + if (c >= 0xC0 && c <= 0xDF) + s = 2; + if (c >= 0xE0 && c <= 0xEF) + s = 3; + if (c >= 0xF0 && c <= 0xF7) + s = 4; + if (c >= 0xF8 && c <= 0xFB) + s = 5; + if (c >= 0xFC && c <= 0xFD) + s = 6; + + printf("%d", s); + if ((c & 15) == 15) + printf(",\n"); + else + printf(","); + } +} +#endif diff --git a/dmd2/root/dchar.h b/dmd2/root/dchar.h index 4aa8413d..d578373f 100644 --- a/dmd2/root/dchar.h +++ b/dmd2/root/dchar.h @@ -1,194 +1,194 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - - -#ifndef DCHAR_H -#define DCHAR_H - -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -#if _MSC_VER - // Disable useless warnings about unreferenced functions - #pragma warning (disable : 4514) -#endif - -//#include "root.h" -typedef size_t hash_t; - -#undef TEXT - -// NOTE: All functions accepting pointer arguments must not be NULL - -#if M_UNICODE - -#include -#include - -typedef wchar_t dchar; -#define TEXT(x) L##x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } - static int len(const dchar *p) { return wcslen(p); } - static dchar get(dchar *p) { return *p; } - static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; } - static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) - { -#if __DMC__ - if (!*s1 && !*s2) // wcscmp is broken - return 0; -#endif - return wcscmp(s1, s2); -#if 0 - return (*s1 == *s2) - ? wcscmp(s1, s2) - : ((int)*s1 - (int)*s2); -#endif - } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return iswalpha(c); } - static int isUpper(dchar c) { return iswupper(c); } - static int isLower(dchar c) { return iswlower(c); } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; } - static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory? - static dchar *dup(char *p); - static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); } - static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); } - static dchar *memchr(dchar *p, int c, int count); - static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#elif MCBS - -#include -#include - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax MB_LEN_MAX - -#elif UTF8 - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 6 - -struct Dchar -{ - static char mblen[256]; - - static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; } - static dchar *dec(dchar *pstart, dchar *p); - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p); - static int getprev(dchar *pstart, dchar *p) - { return *dec(pstart, p) & 0xFF; } - static dchar *put(dchar *p, unsigned c); - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; } - static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; } - static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); } -}; - -#else - -#include - -#ifndef GCC_SAFE_DMD -#include -#endif - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { return p - 1; } - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p) { return *p & 0xFF; } - static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; } - static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } -#ifndef GCC_SAFE_DMD - static int isAlpha(dchar c) { return isalpha(c); } - static int isUpper(dchar c) { return isupper(c); } - static int isLower(dchar c) { return islower(c); } - static int isLocaleUpper(dchar c) { return isupper(c); } - static int isLocaleLower(dchar c) { return islower(c); } - static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? -#endif - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions -#ifdef __GNUC__ - static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); } -#else - static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); } -#endif - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#endif -#endif - + +// Copyright (c) 1999-2006 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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. + + +#ifndef DCHAR_H +#define DCHAR_H + +#if __GNUC__ && !_WIN32 +#include "gnuc.h" +#endif + +#if _MSC_VER + // Disable useless warnings about unreferenced functions + #pragma warning (disable : 4514) +#endif + +//#include "root.h" +typedef size_t hash_t; + +#undef TEXT + +// NOTE: All functions accepting pointer arguments must not be NULL + +#if M_UNICODE + +#include +#include + +typedef wchar_t dchar; +#define TEXT(x) L##x + +#define Dchar_mbmax 1 + +struct Dchar +{ + static dchar *inc(dchar *p) { return p + 1; } + static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } + static int len(const dchar *p) { return wcslen(p); } + static dchar get(dchar *p) { return *p; } + static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; } + static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; } + static int cmp(dchar *s1, dchar *s2) + { +#if __DMC__ + if (!*s1 && !*s2) // wcscmp is broken + return 0; +#endif + return wcscmp(s1, s2); +#if 0 + return (*s1 == *s2) + ? wcscmp(s1, s2) + : ((int)*s1 - (int)*s2); +#endif + } + static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); } + static int isDigit(dchar c) { return '0' <= c && c <= '9'; } + static int isAlpha(dchar c) { return iswalpha(c); } + static int isUpper(dchar c) { return iswupper(c); } + static int isLower(dchar c) { return iswlower(c); } + static int isLocaleUpper(dchar c) { return isUpper(c); } + static int isLocaleLower(dchar c) { return isLower(c); } + static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; } + static int toLower(dchar *p) { return toLower(*p); } + static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; } + static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory? + static dchar *dup(char *p); + static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); } + static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); } + static dchar *memchr(dchar *p, int c, int count); + static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); } + static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); } + static hash_t calcHash(const dchar *str, size_t len); + + // Case insensitive versions + static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); } + static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); } + static hash_t icalcHash(const dchar *str, size_t len); +}; + +#elif MCBS + +#include +#include + +typedef char dchar; +#define TEXT(x) x + +#define Dchar_mbmax MB_LEN_MAX + +#elif UTF8 + +typedef char dchar; +#define TEXT(x) x + +#define Dchar_mbmax 6 + +struct Dchar +{ + static char mblen[256]; + + static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; } + static dchar *dec(dchar *pstart, dchar *p); + static int len(const dchar *p) { return strlen(p); } + static int get(dchar *p); + static int getprev(dchar *pstart, dchar *p) + { return *dec(pstart, p) & 0xFF; } + static dchar *put(dchar *p, unsigned c); + static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } + static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } + static int isDigit(dchar c) { return '0' <= c && c <= '9'; } + static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; } + static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; } + static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; } + static int isLocaleUpper(dchar c) { return isUpper(c); } + static int isLocaleLower(dchar c) { return isLower(c); } + static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; } + static int toLower(dchar *p) { return toLower(*p); } + static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; } + static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? + static dchar *chr(dchar *p, int c) { return strchr(p, c); } + static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } + static dchar *memchr(dchar *p, int c, int count) + { return (dchar *)::memchr(p, c, count); } + static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } + static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } + static hash_t calcHash(const dchar *str, size_t len); + + // Case insensitive versions + static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); } + static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); } +}; + +#else + +#include + +#ifndef GCC_SAFE_DMD +#include +#endif + +typedef char dchar; +#define TEXT(x) x + +#define Dchar_mbmax 1 + +struct Dchar +{ + static dchar *inc(dchar *p) { return p + 1; } + static dchar *dec(dchar *pstart, dchar *p) { return p - 1; } + static int len(const dchar *p) { return strlen(p); } + static int get(dchar *p) { return *p & 0xFF; } + static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; } + static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; } + static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } + static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } + static int isDigit(dchar c) { return '0' <= c && c <= '9'; } +#ifndef GCC_SAFE_DMD + static int isAlpha(dchar c) { return isalpha(c); } + static int isUpper(dchar c) { return isupper(c); } + static int isLower(dchar c) { return islower(c); } + static int isLocaleUpper(dchar c) { return isupper(c); } + static int isLocaleLower(dchar c) { return islower(c); } + static int toLower(dchar c) { return isupper(c) ? tolower(c) : c; } + static int toLower(dchar *p) { return toLower(*p); } + static int toUpper(dchar c) { return islower(c) ? toupper(c) : c; } + static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? +#endif + static dchar *chr(dchar *p, int c) { return strchr(p, c); } + static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } + static dchar *memchr(dchar *p, int c, int count) + { return (dchar *)::memchr(p, c, count); } + static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } + static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } + static hash_t calcHash(const dchar *str, size_t len); + + // Case insensitive versions +#ifdef __GNUC__ + static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); } +#else + static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); } +#endif + static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); } + static hash_t icalcHash(const dchar *str, size_t len); +}; + +#endif +#endif + diff --git a/dmd2/root/gnuc.c b/dmd2/root/gnuc.c index 849d1e4d..8f33d839 100644 --- a/dmd2/root/gnuc.c +++ b/dmd2/root/gnuc.c @@ -8,20 +8,20 @@ int memicmp(const char *s1, const char *s2, int n) int result = 0; for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; + { char c1 = s1[i]; + char c2 = s2[i]; - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } + result = c1 - c2; + if (result) + { + if ('A' <= c1 && c1 <= 'Z') + c1 += 'a' - 'A'; + if ('A' <= c2 && c2 <= 'Z') + c2 += 'a' - 'A'; + result = c1 - c2; + if (result) + break; + } } return result; } @@ -31,24 +31,24 @@ int stricmp(const char *s1, const char *s2) int result = 0; for (;;) - { char c1 = *s1; - char c2 = *s2; + { char c1 = *s1; + char c2 = *s2; - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - if (!c1) - break; - s1++; - s2++; + result = c1 - c2; + if (result) + { + if ('A' <= c1 && c1 <= 'Z') + c1 += 'a' - 'A'; + if ('A' <= c2 && c2 <= 'Z') + c2 += 'a' - 'A'; + result = c1 - c2; + if (result) + break; + } + if (!c1) + break; + s1++; + s2++; } return result; } diff --git a/dmd2/root/lstring.c b/dmd2/root/lstring.c index b222450e..a4e41ed5 100644 --- a/dmd2/root/lstring.c +++ b/dmd2/root/lstring.c @@ -1,63 +1,63 @@ -// lstring.c - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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 - -#include "dchar.h" -#include "rmem.h" -#include "lstring.h" - -#ifdef _MSC_VER // prevent compiler internal crash -Lstring Lstring::zero; -#else -Lstring Lstring::zero = LSTRING_EMPTY(); -#endif - -Lstring *Lstring::ctor(const dchar *p, unsigned length) -{ - Lstring *s; - - s = alloc(length); - memcpy(s->string, p, length * sizeof(dchar)); - return s; -} - -Lstring *Lstring::alloc(unsigned length) -{ - Lstring *s; - - s = (Lstring *)mem.malloc(size(length)); - s->length = length; - s->string[length] = 0; - return s; -} - -Lstring *Lstring::append(const Lstring *s) -{ - Lstring *t; - - if (!s->length) - return this; - t = alloc(length + s->length); - memcpy(t->string, string, length * sizeof(dchar)); - memcpy(t->string + length, s->string, s->length * sizeof(dchar)); - return t; -} - -Lstring *Lstring::substring(int start, int end) -{ - Lstring *t; - - if (start == end) - return &zero; - t = alloc(end - start); - memcpy(t->string, string + start, (end - start) * sizeof(dchar)); - return t; -} +// lstring.c + +// Copyright (c) 1999-2002 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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 + +#include "dchar.h" +#include "rmem.h" +#include "lstring.h" + +#ifdef _MSC_VER // prevent compiler internal crash +Lstring Lstring::zero; +#else +Lstring Lstring::zero = LSTRING_EMPTY(); +#endif + +Lstring *Lstring::ctor(const dchar *p, unsigned length) +{ + Lstring *s; + + s = alloc(length); + memcpy(s->string, p, length * sizeof(dchar)); + return s; +} + +Lstring *Lstring::alloc(unsigned length) +{ + Lstring *s; + + s = (Lstring *)mem.malloc(size(length)); + s->length = length; + s->string[length] = 0; + return s; +} + +Lstring *Lstring::append(const Lstring *s) +{ + Lstring *t; + + if (!s->length) + return this; + t = alloc(length + s->length); + memcpy(t->string, string, length * sizeof(dchar)); + memcpy(t->string + length, s->string, s->length * sizeof(dchar)); + return t; +} + +Lstring *Lstring::substring(int start, int end) +{ + Lstring *t; + + if (start == end) + return &zero; + t = alloc(end - start); + memcpy(t->string, string + start, (end - start) * sizeof(dchar)); + return t; +} diff --git a/dmd2/root/lstring.h b/dmd2/root/lstring.h index 665fe547..17a8e447 100644 --- a/dmd2/root/lstring.h +++ b/dmd2/root/lstring.h @@ -1,72 +1,72 @@ - -// lstring.h -// length-prefixed strings - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -#ifndef LSTRING_H -#define LSTRING_H 1 - -#include "dchar.h" - -struct Lstring -{ - unsigned length; - - // Disable warning about nonstandard extension - #pragma warning (disable : 4200) - dchar string[]; - - static Lstring zero; // 0 length string - - // No constructors because we want to be able to statically - // initialize Lstring's, and Lstrings are of variable size. - - #if M_UNICODE - #define LSTRING(p,length) { length, L##p } - #else - #define LSTRING(p,length) { length, p } - #endif - -#if __GNUC__ - #define LSTRING_EMPTY() { 0 } -#else - #define LSTRING_EMPTY() LSTRING("", 0) -#endif - - static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); } - static Lstring *ctor(const dchar *p, unsigned length); - static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); } - static Lstring *alloc(unsigned length); - Lstring *clone(); - - unsigned len() { return length; } - - dchar *toDchars() { return string; } - - hash_t hash() { return Dchar::calcHash(string, length); } - hash_t ihash() { return Dchar::icalcHash(string, length); } - - static int cmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length); - } - - static int icmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length); - } - - Lstring *append(const Lstring *s); - Lstring *substring(int start, int end); -}; - -#endif + +// lstring.h +// length-prefixed strings + +// Copyright (c) 1999-2002 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// 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. + +#ifndef LSTRING_H +#define LSTRING_H 1 + +#include "dchar.h" + +struct Lstring +{ + unsigned length; + + // Disable warning about nonstandard extension + #pragma warning (disable : 4200) + dchar string[]; + + static Lstring zero; // 0 length string + + // No constructors because we want to be able to statically + // initialize Lstring's, and Lstrings are of variable size. + + #if M_UNICODE + #define LSTRING(p,length) { length, L##p } + #else + #define LSTRING(p,length) { length, p } + #endif + +#if __GNUC__ + #define LSTRING_EMPTY() { 0 } +#else + #define LSTRING_EMPTY() LSTRING("", 0) +#endif + + static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); } + static Lstring *ctor(const dchar *p, unsigned length); + static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); } + static Lstring *alloc(unsigned length); + Lstring *clone(); + + unsigned len() { return length; } + + dchar *toDchars() { return string; } + + hash_t hash() { return Dchar::calcHash(string, length); } + hash_t ihash() { return Dchar::icalcHash(string, length); } + + static int cmp(const Lstring *s1, const Lstring *s2) + { + int c = s2->length - s1->length; + return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length); + } + + static int icmp(const Lstring *s1, const Lstring *s2) + { + int c = s2->length - s1->length; + return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length); + } + + Lstring *append(const Lstring *s); + Lstring *substring(int start, int end); +}; + +#endif diff --git a/dmd2/root/man.c b/dmd2/root/man.c index 5c804601..ad0d3c74 100644 --- a/dmd2/root/man.c +++ b/dmd2/root/man.c @@ -1,100 +1,100 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2008-2009 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 -#include -#include -#include - -#if _WIN32 - -#include - -#pragma comment(lib,"shell32.lib") - -void browse(const char *url) -{ - ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); -} - -#endif - -#if linux || __FreeBSD__ || __sun&&__SVR4 - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[3]; - - char *browser = getenv("BROWSER"); - if (browser) - browser = strdup(browser); - else - browser = "x-www-browser"; - - args[0] = browser; - args[1] = url; - args[2] = NULL; - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - -#if __APPLE__ - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[5]; - - char *browser = getenv("BROWSER"); - if (browser) - { browser = strdup(browser); - args[0] = browser; - args[1] = url; - args[2] = NULL; - } - else - { - //browser = "/Applications/Safari.app/Contents/MacOS/Safari"; - args[0] = "open"; - args[1] = "-a"; - args[2] = "/Applications/Safari.app"; - args[3] = url; - args[4] = NULL; - } - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - - + +// Compiler implementation of the D programming language +// Copyright (c) 2008-2009 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 +#include +#include +#include + +#if _WIN32 + +#include + +#pragma comment(lib,"shell32.lib") + +void browse(const char *url) +{ + ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); +} + +#endif + +#if linux || __FreeBSD__ || __sun&&__SVR4 + +#include +#include +#include + +void browse(const char *url) +{ + pid_t childpid; + const char *args[3]; + + const char *browser = getenv("BROWSER"); + if (browser) + browser = strdup(browser); + else + browser = "x-www-browser"; + + args[0] = browser; + args[1] = url; + args[2] = NULL; + + childpid = fork(); + if (childpid == 0) + { + execvp(args[0], (char**)args); + perror(args[0]); // failed to execute + return; + } +} + +#endif + +#if __APPLE__ + +#include +#include +#include + +void browse(const char *url) +{ + pid_t childpid; + const char *args[5]; + + char *browser = getenv("BROWSER"); + if (browser) + { browser = strdup(browser); + args[0] = browser; + args[1] = url; + args[2] = NULL; + } + else + { + //browser = "/Applications/Safari.app/Contents/MacOS/Safari"; + args[0] = "open"; + args[1] = "-a"; + args[2] = "/Applications/Safari.app"; + args[3] = url; + args[4] = NULL; + } + + childpid = fork(); + if (childpid == 0) + { + execvp(args[0], (char**)args); + perror(args[0]); // failed to execute + return; + } +} + +#endif + + diff --git a/dmd2/root/port.c b/dmd2/root/port.c index 2e225a62..49794cc8 100644 --- a/dmd2/root/port.c +++ b/dmd2/root/port.c @@ -1,759 +1,766 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#include "port.h" -#if __DMC__ -#include -#include -#include -#include -#include -#include - -double Port::nan = NAN; -double Port::infinity = INFINITY; -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; - -int Port::isNan(double r) -{ - return ::isnan(r); -} - -int Port::isNan(long double r) -{ - return ::isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -int Port::isFinite(double r) -{ - return ::isfinite(r); -} - -int Port::isInfinity(double r) -{ - return (::fpclassify(r) == FP_INFINITE); -} - -int Port::Signbit(double r) -{ - return ::signbit(r); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if _MSC_VER - -// Disable useless warnings about unreferenced functions -#pragma warning (disable : 4514) - -#include -#include -#include -#include -#include -#include -#include -#include // for std::numeric_limits - -static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; -//static unsigned long nanarray[2] = {0,0x7FF80000 }; -double Port::nan = (*(double *)nanarray); - -//static unsigned long infinityarray[2] = {0,0x7FF00000 }; -static double zero = 0; -double Port::infinity = 1 / zero; - -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = std::numeric_limits::infinity(); -} - -int Port::isNan(double r) -{ - return ::_isnan(r); -} - -int Port::isNan(long double r) -{ - return ::_isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* MSVC doesn't have 80 bit long doubles - */ - return isSignallingNan((double) r); -} - -int Port::isFinite(double r) -{ - return ::_finite(r); -} - -int Port::isInfinity(double r) -{ - return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); -} - -int Port::Signbit(double r) -{ - return (long)(((long *)&(r))[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - if (y == 0) - return 1; // even if x is NAN - return ::pow(x, y); -} - -unsigned _int64 Port::strtoull(const char *p, char **pend, int base) -{ - unsigned _int64 number = 0; - int c; - int error; - #define ULLONG_MAX ((unsigned _int64)~0I64) - - while (isspace(*p)) /* skip leading white space */ - p++; - if (*p == '+') - p++; - switch (base) - { case 0: - base = 10; /* assume decimal base */ - if (*p == '0') - { base = 8; /* could be octal */ - p++; - switch (*p) - { case 'x': - case 'X': - base = 16; /* hex */ - p++; - break; -#if BINARY - case 'b': - case 'B': - base = 2; /* binary */ - p++; - break; -#endif - } - } - break; - case 16: /* skip over '0x' and '0X' */ - if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) - p += 2; - break; -#if BINARY - case 2: /* skip over '0b' and '0B' */ - if (*p == '0' && (p[1] == 'b' || p[1] == 'B')) - p += 2; - break; -#endif - } - error = 0; - for (;;) - { c = *p; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c = (c & ~0x20) - ('A' - 10); - else /* unrecognized character */ - break; - if (c >= base) /* not in number base */ - break; - if ((ULLONG_MAX - c) / base < number) - error = 1; - number = number * base + c; - p++; - } - if (pend) - *pend = (char *)p; - if (error) - { number = ULLONG_MAX; - errno = ERANGE; - } - return number; -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - _ui64toa(ull, buffer, 10); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - _ui64tow(ull, buffer, 10); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ double d; - - if ((__int64) ull < 0) - { - // MSVC doesn't implement the conversion - d = (double) (__int64)(ull - 0x8000000000000000i64); - d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0; - } - else - d = (double)(__int64)ull; - return d; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if linux || __APPLE__ || __FreeBSD__ - -#include -#if linux -#include -#include -#endif -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile long double foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; - -#if __FreeBSD__ - // LDBL_MAX comes out as infinity. Fix. - static unsigned char x[sizeof(long double)] = - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; - Port::ldbl_max = *(long double *)&x[0]; -#endif -} - -#undef isnan -int Port::isNan(double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#else - return ::isnan(r); -#endif -} - -int Port::isNan(long double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#else - return ::isnan(r); -#endif -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#undef isinf -int Port::isInfinity(double r) -{ -#if __APPLE__ - return fpclassify(r) == FP_INFINITE; -#else - return ::isinf(r); -#endif -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - -#if __sun&&__SVR4 - -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile long double foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; -} - -int Port::isNan(double r) -{ - return isnan(r); -} - -int Port::isNan(long double r) -{ - return isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return finite(r); -} - -int Port::isInfinity(double r) -{ - return isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - -#if IN_GCC - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -#include "d-gcc-real.h" -extern "C" bool real_isnan (const real_t *); - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = real_t::getinfinity(); - Port::nan = real_t::getnan(real_t::LongDouble); -} - -#undef isnan -int Port::isNan(double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#else - return ::isnan(r); -#endif -} - -int Port::isNan(long double r) -{ - return real_isnan(&r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#undef isinf -int Port::isInfinity(double r) -{ - return ::isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - + +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com + +#include "port.h" +#if __DMC__ +#include +#include +#include +#include +#include +#include + +double Port::nan = NAN; +double Port::infinity = INFINITY; +double Port::dbl_max = DBL_MAX; +double Port::dbl_min = DBL_MIN; +long double Port::ldbl_max = LDBL_MAX; + +int Port::isNan(double r) +{ + return ::isnan(r); +} + +int Port::isNan(long double r) +{ + return ::isnan(r); +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(long double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); +} + +int Port::isFinite(double r) +{ + return ::isfinite(r); +} + +int Port::isInfinity(double r) +{ + return (::fpclassify(r) == FP_INFINITE); +} + +int Port::Signbit(double r) +{ + return ::signbit(r); +} + +double Port::floor(double d) +{ + return ::floor(d); +} + +double Port::pow(double x, double y) +{ + return ::pow(x, y); +} + +unsigned long long Port::strtoull(const char *p, char **pend, int base) +{ + return ::strtoull(p, pend, base); +} + +char *Port::ull_to_string(char *buffer, ulonglong ull) +{ + sprintf(buffer, "%llu", ull); + return buffer; +} + +wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) +{ + swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); + return buffer; +} + +double Port::ull_to_double(ulonglong ull) +{ + return (double) ull; +} + +const char *Port::list_separator() +{ + // LOCALE_SLIST for Windows + return ","; +} + +const wchar_t *Port::wlist_separator() +{ + // LOCALE_SLIST for Windows + return L","; +} + +char *Port::strupr(char *s) +{ + return ::strupr(s); +} + +#endif + +#if _MSC_VER + +// Disable useless warnings about unreferenced functions +#pragma warning (disable : 4514) + +#include +#include +#include +#include +#include +#include +#include +#include // for std::numeric_limits + +static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; +//static unsigned long nanarray[2] = {0,0x7FF80000 }; +double Port::nan = (*(double *)nanarray); + +//static unsigned long infinityarray[2] = {0,0x7FF00000 }; +static double zero = 0; +double Port::infinity = 1 / zero; + +double Port::dbl_max = DBL_MAX; +double Port::dbl_min = DBL_MIN; +long double Port::ldbl_max = LDBL_MAX; + +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + Port::infinity = std::numeric_limits::infinity(); +} + +int Port::isNan(double r) +{ + return ::_isnan(r); +} + +int Port::isNan(long double r) +{ + return ::_isnan(r); +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(long double r) +{ + /* MSVC doesn't have 80 bit long doubles + */ + return isSignallingNan((double) r); +} + +int Port::isFinite(double r) +{ + return ::_finite(r); +} + +int Port::isInfinity(double r) +{ + return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); +} + +int Port::Signbit(double r) +{ + return (long)(((long *)&(r))[1] & 0x80000000); +} + +double Port::floor(double d) +{ + return ::floor(d); +} + +double Port::pow(double x, double y) +{ + if (y == 0) + return 1; // even if x is NAN + return ::pow(x, y); +} + +unsigned _int64 Port::strtoull(const char *p, char **pend, int base) +{ + unsigned _int64 number = 0; + int c; + int error; + #define ULLONG_MAX ((unsigned _int64)~0I64) + + while (isspace(*p)) /* skip leading white space */ + p++; + if (*p == '+') + p++; + switch (base) + { case 0: + base = 10; /* assume decimal base */ + if (*p == '0') + { base = 8; /* could be octal */ + p++; + switch (*p) + { case 'x': + case 'X': + base = 16; /* hex */ + p++; + break; +#if BINARY + case 'b': + case 'B': + base = 2; /* binary */ + p++; + break; +#endif + } + } + break; + case 16: /* skip over '0x' and '0X' */ + if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) + p += 2; + break; +#if BINARY + case 2: /* skip over '0b' and '0B' */ + if (*p == '0' && (p[1] == 'b' || p[1] == 'B')) + p += 2; + break; +#endif + } + error = 0; + for (;;) + { c = *p; + if (isdigit(c)) + c -= '0'; + else if (isalpha(c)) + c = (c & ~0x20) - ('A' - 10); + else /* unrecognized character */ + break; + if (c >= base) /* not in number base */ + break; + if ((ULLONG_MAX - c) / base < number) + error = 1; + number = number * base + c; + p++; + } + if (pend) + *pend = (char *)p; + if (error) + { number = ULLONG_MAX; + errno = ERANGE; + } + return number; +} + +char *Port::ull_to_string(char *buffer, ulonglong ull) +{ + _ui64toa(ull, buffer, 10); + return buffer; +} + +wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) +{ + _ui64tow(ull, buffer, 10); + return buffer; +} + +double Port::ull_to_double(ulonglong ull) +{ double d; + + if ((__int64) ull < 0) + { + // MSVC doesn't implement the conversion + d = (double) (__int64)(ull - 0x8000000000000000i64); + d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0; + } + else + d = (double)(__int64)ull; + return d; +} + +const char *Port::list_separator() +{ + // LOCALE_SLIST for Windows + return ","; +} + +const wchar_t *Port::wlist_separator() +{ + // LOCALE_SLIST for Windows + return L","; +} + +char *Port::strupr(char *s) +{ + return ::strupr(s); +} + +#endif + +#if linux || __APPLE__ || __FreeBSD__ + +#include +#if linux +#include +#include +#endif +#if __FreeBSD__ && __i386__ +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +static double zero = 0; +double Port::nan = NAN; +double Port::infinity = 1 / zero; +double Port::dbl_max = 1.7976931348623157e308; +double Port::dbl_min = 5e-324; +long double Port::ldbl_max = LDBL_MAX; + +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + // gcc nan's have the sign bit set by default, so turn it off + // Need the volatile to prevent gcc from doing incorrect + // constant folding. + volatile long double foo; + foo = NAN; + if (signbit(foo)) // signbit sometimes, not always, set + foo = -foo; // turn off sign bit + Port::nan = foo; + +#if __FreeBSD__ && __i386__ + // LDBL_MAX comes out as infinity. Fix. + static unsigned char x[sizeof(long double)] = + { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; + Port::ldbl_max = *(long double *)&x[0]; + // FreeBSD defaults to double precision. Switch to extended precision. + fpsetprec(FP_PE); +#endif +} + +#undef isnan +int Port::isNan(double r) +{ +#if __APPLE__ + return __inline_isnan(r); +#else + return ::isnan(r); +#endif +} + +int Port::isNan(long double r) +{ +#if __APPLE__ + return __inline_isnan(r); +#else + return ::isnan(r); +#endif +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(long double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); +} + +#undef isfinite +int Port::isFinite(double r) +{ + return ::finite(r); +} + +#undef isinf +int Port::isInfinity(double r) +{ +#if __APPLE__ + return fpclassify(r) == FP_INFINITE; +#else + return ::isinf(r); +#endif +} + +#undef signbit +int Port::Signbit(double r) +{ + union { double d; long long ll; } u; + u.d = r; + return u.ll < 0; +} + +double Port::floor(double d) +{ + return ::floor(d); +} + +double Port::pow(double x, double y) +{ + return ::pow(x, y); +} + +unsigned long long Port::strtoull(const char *p, char **pend, int base) +{ + return ::strtoull(p, pend, base); +} + +char *Port::ull_to_string(char *buffer, ulonglong ull) +{ + sprintf(buffer, "%llu", ull); + return buffer; +} + +wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) +{ + swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); + return buffer; +} + +double Port::ull_to_double(ulonglong ull) +{ + return (double) ull; +} + +const char *Port::list_separator() +{ + return ","; +} + +const wchar_t *Port::wlist_separator() +{ + return L","; +} + +char *Port::strupr(char *s) +{ + char *t = s; + + while (*s) + { + *s = toupper(*s); + s++; + } + + return t; +} + +#endif + +#if __sun&&__SVR4 + +#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static double zero = 0; +double Port::nan = NAN; +double Port::infinity = 1 / zero; +double Port::dbl_max = 1.7976931348623157e308; +double Port::dbl_min = 5e-324; +long double Port::ldbl_max = LDBL_MAX; + +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + // gcc nan's have the sign bit set by default, so turn it off + // Need the volatile to prevent gcc from doing incorrect + // constant folding. + volatile long double foo; + foo = NAN; + if (signbit(foo)) // signbit sometimes, not always, set + foo = -foo; // turn off sign bit + Port::nan = foo; +} + +int Port::isNan(double r) +{ + return isnan(r); +} + +int Port::isNan(long double r) +{ + return isnan(r); +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(long double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); +} + +#undef isfinite +int Port::isFinite(double r) +{ + return finite(r); +} + +int Port::isInfinity(double r) +{ + return isinf(r); +} + +#undef signbit +int Port::Signbit(double r) +{ + return (long)(((long *)&r)[1] & 0x80000000); +} + +double Port::floor(double d) +{ + return ::floor(d); +} + +double Port::pow(double x, double y) +{ + return ::pow(x, y); +} + +unsigned long long Port::strtoull(const char *p, char **pend, int base) +{ + return ::strtoull(p, pend, base); +} + +char *Port::ull_to_string(char *buffer, ulonglong ull) +{ + sprintf(buffer, "%llu", ull); + return buffer; +} + +wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) +{ + swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); + return buffer; +} + +double Port::ull_to_double(ulonglong ull) +{ + return (double) ull; +} + +const char *Port::list_separator() +{ + return ","; +} + +const wchar_t *Port::wlist_separator() +{ + return L","; +} + +char *Port::strupr(char *s) +{ + char *t = s; + + while (*s) + { + *s = toupper(*s); + s++; + } + + return t; +} + +#endif + +#if IN_GCC + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static double zero = 0; +double Port::nan = NAN; +double Port::infinity = 1 / zero; +double Port::dbl_max = 1.7976931348623157e308; +double Port::dbl_min = 5e-324; +long double Port::ldbl_max = LDBL_MAX; + +#include "d-gcc-real.h" +extern "C" bool real_isnan (const real_t *); + +struct PortInitializer +{ + PortInitializer(); +}; + +static PortInitializer portinitializer; + +PortInitializer::PortInitializer() +{ + Port::infinity = real_t::getinfinity(); + Port::nan = real_t::getnan(real_t::LongDouble); +} + +#undef isnan +int Port::isNan(double r) +{ +#if __APPLE__ + return __inline_isnan(r); +#else + return ::isnan(r); +#endif +} + +int Port::isNan(long double r) +{ + return real_isnan(&r); +} + +int Port::isSignallingNan(double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 51 of 0..63 for 64 bit doubles. + */ + return isNan(r) && !((((unsigned char*)&r)[6]) & 8); +} + +int Port::isSignallingNan(long double r) +{ + /* A signalling NaN is a NaN with 0 as the most significant bit of + * its significand, which is bit 62 of 0..79 for 80 bit reals. + */ + return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); +} + +#undef isfinite +int Port::isFinite(double r) +{ + return ::finite(r); +} + +#undef isinf +int Port::isInfinity(double r) +{ + return ::isinf(r); +} + +#undef signbit +int Port::Signbit(double r) +{ + return (long)(((long *)&r)[1] & 0x80000000); +} + +double Port::floor(double d) +{ + return ::floor(d); +} + +double Port::pow(double x, double y) +{ + return ::pow(x, y); +} + +unsigned long long Port::strtoull(const char *p, char **pend, int base) +{ + return ::strtoull(p, pend, base); +} + +char *Port::ull_to_string(char *buffer, ulonglong ull) +{ + sprintf(buffer, "%llu", ull); + return buffer; +} + +wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) +{ + swprintf(buffer, L"%llu", ull); + return buffer; +} + +double Port::ull_to_double(ulonglong ull) +{ + return (double) ull; +} + +const char *Port::list_separator() +{ + return ","; +} + +const wchar_t *Port::wlist_separator() +{ + return L","; +} + +char *Port::strupr(char *s) +{ + char *t = s; + + while (*s) + { + *s = toupper(*s); + s++; + } + + return t; +} + +#endif + diff --git a/dmd2/root/port.h b/dmd2/root/port.h index 37d33c70..d773c128 100644 --- a/dmd2/root/port.h +++ b/dmd2/root/port.h @@ -1,78 +1,78 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#ifndef PORT_H -#define PORT_H - -// Portable wrapper around compiler/system specific things. -// The idea is to minimize #ifdef's in the app code. - -#ifndef TYPEDEFS -#define TYPEDEFS - -#include - -#if _MSC_VER -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; - -// According to VC 8.0 docs, long double is the same as double -#define strtold strtod -#define strtof strtod - -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -typedef double d_time; - -struct Port -{ - static double nan; - static double infinity; - static double dbl_max; - static double dbl_min; - static long double ldbl_max; - -#if __GNUC__ - // These conflict with macros in math.h, should rename them - #undef isnan - #undef isfinite - #undef isinfinity - #undef signbit -#endif - static int isNan(double); - static int isNan(long double); - - static int isSignallingNan(double); - static int isSignallingNan(long double); - - static int isFinite(double); - static int isInfinity(double); - static int Signbit(double); - - static double floor(double); - static double pow(double x, double y); - - static ulonglong strtoull(const char *p, char **pend, int base); - - static char *ull_to_string(char *buffer, ulonglong ull); - static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); - - // Convert ulonglong to double - static double ull_to_double(ulonglong ull); - - // Get locale-dependent list separator - static const char *list_separator(); - static const wchar_t *wlist_separator(); - - static char *strupr(char *); -}; - -#endif + +// Copyright (c) 1999-2009 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com + +#ifndef PORT_H +#define PORT_H + +// Portable wrapper around compiler/system specific things. +// The idea is to minimize #ifdef's in the app code. + +#ifndef TYPEDEFS +#define TYPEDEFS + +#include + +#if _MSC_VER +typedef __int64 longlong; +typedef unsigned __int64 ulonglong; + +// According to VC 8.0 docs, long double is the same as double +#define strtold strtod +#define strtof strtod + +#else +typedef long long longlong; +typedef unsigned long long ulonglong; +#endif + +#endif + +typedef double d_time; + +struct Port +{ + static double nan; + static double infinity; + static double dbl_max; + static double dbl_min; + static long double ldbl_max; + +#if __GNUC__ + // These conflict with macros in math.h, should rename them + #undef isnan + #undef isfinite + #undef isinfinity + #undef signbit +#endif + static int isNan(double); + static int isNan(long double); + + static int isSignallingNan(double); + static int isSignallingNan(long double); + + static int isFinite(double); + static int isInfinity(double); + static int Signbit(double); + + static double floor(double); + static double pow(double x, double y); + + static ulonglong strtoull(const char *p, char **pend, int base); + + static char *ull_to_string(char *buffer, ulonglong ull); + static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); + + // Convert ulonglong to double + static double ull_to_double(ulonglong ull); + + // Get locale-dependent list separator + static const char *list_separator(); + static const wchar_t *wlist_separator(); + + static char *strupr(char *); +}; + +#endif diff --git a/dmd2/root/response.c b/dmd2/root/response.c index 14fb6a77..ff085199 100644 --- a/dmd2/root/response.c +++ b/dmd2/root/response.c @@ -1,275 +1,275 @@ -// Copyright (C) 1990-1998 by Symantec -// Copyright (C) 2000-2009 by Digital Mars -// All Rights Reserved -// http://www.digitalmars.com -// Written by Walter Bright -/* - * This source file is made available for personal use - * only. The license is in /dmd/src/dmd/backendlicense.txt - * For any other uses, please contact Digital Mars. - */ - -#include -#include -#include -#include - -#if _WIN32 -#include -#include -#endif - -#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 -#include -#include -#include -#include -#include -#include -#endif - -/********************************* - * #include - * int response_expand(int *pargc,char ***pargv); - * - * Expand any response files in command line. - * Response files are arguments that look like: - * @NAME - * The name is first searched for in the environment. If it is not - * there, it is searched for as a file name. - * Arguments are separated by spaces, tabs, or newlines. These can be - * imbedded within arguments by enclosing the argument in '' or "". - * Recursively expands nested response files. - * - * To use, put the line: - * response_expand(&argc,&argv); - * as the first executable statement in main(int argc, char **argv). - * argc and argv are adjusted to be the new command line arguments - * after response file expansion. - * - * Digital Mars's MAKE program can be notified that a program can accept - * long command lines via environment variables by preceding the rule - * line for the program with a *. - * - * Returns: - * 0 success - * !=0 failure (argc, argv unchanged) - */ - -struct Narg -{ - int argc; /* arg count */ - int argvmax; /* dimension of nargv[] */ - char **argv; -}; - -static int addargp(struct Narg *n, char *p) -{ - /* The 2 is to always allow room for a NULL argp at the end */ - if (n->argc + 2 >= n->argvmax) - { - n->argvmax = n->argc + 2; - n->argv = (char **) realloc(n->argv,n->argvmax * sizeof(char *)); - if (!n->argv) - return 1; - } - n->argv[n->argc++] = p; - return 0; -} - -int response_expand(int *pargc, char ***pargv) -{ - struct Narg n; - int i; - char *cp; - int recurse = 0; - - n.argc = 0; - n.argvmax = 0; /* dimension of n.argv[] */ - n.argv = NULL; - for(i=0; i<*pargc; ++i) - { - cp = (*pargv)[i]; - if (*cp == '@') - { - char *buffer; - char *bufend; - char *p; - - cp++; - p = getenv(cp); - if (p) - { - buffer = strdup(p); - if (!buffer) - goto noexpand; - bufend = buffer + strlen(buffer); - } - else - { - long length; - int fd; - int nread; - size_t len; - -#if __DMC__ - length = filesize(cp); -#else - struct stat statbuf; - if (stat(cp, &statbuf)) - goto noexpand; - length = statbuf.st_size; -#endif - if (length & 0xF0000000) /* error or file too big */ - goto noexpand; - len = length; - buffer = (char *)malloc(len + 1); - if (!buffer) - goto noexpand; - bufend = &buffer[len]; - /* Read file into buffer */ -#if _WIN32 - fd = open(cp,O_RDONLY|O_BINARY); -#else - fd = open(cp,O_RDONLY); -#endif - if (fd == -1) - goto noexpand; - nread = read(fd,buffer,len); - close(fd); - - if (nread != len) - goto noexpand; - } - - // The logic of this should match that in setargv() - - for (p = buffer; p < bufend; p++) - { - char *d; - char c,lastc; - unsigned char instring; - int num_slashes,non_slashes; - - switch (*p) - { - case 26: /* ^Z marks end of file */ - goto L2; - - case 0xD: - case 0: - case ' ': - case '\t': - case '\n': - continue; // scan to start of argument - - case '@': - recurse = 1; - default: /* start of new argument */ - if (addargp(&n,p)) - goto noexpand; - instring = 0; - c = 0; - num_slashes = 0; - for (d = p; 1; p++) - { - lastc = c; - if (p >= bufend) - goto Lend; - c = *p; - switch (c) - { - case '"': - /* - Yes this looks strange,but this is so that we are - MS Compatible, tests have shown that: - \\\\"foo bar" gets passed as \\foo bar - \\\\foo gets passed as \\\\foo - \\\"foo gets passed as \"foo - and \"foo gets passed as "foo in VC! - */ - non_slashes = num_slashes % 2; - num_slashes = num_slashes / 2; - for (; num_slashes > 0; num_slashes--) - { - d--; - *d = '\0'; - } - - if (non_slashes) - { - *(d-1) = c; - } - else - { - instring ^= 1; - } - break; - case 26: - Lend: - *d = 0; // terminate argument - goto L2; - - case 0xD: // CR - c = lastc; - continue; // ignore - - case '@': - recurse = 1; - goto Ladd; - - case ' ': - case '\t': - if (!instring) - { - case '\n': - case 0: - *d = 0; // terminate argument - goto Lnextarg; - } - default: - Ladd: - if (c == '\\') - num_slashes++; - else - num_slashes = 0; - *d++ = c; - break; - } -#ifdef _MBCS - if (_istlead (c)) { - *d++ = *++p; - if (*(d - 1) == '\0') { - d--; - goto Lnextarg; - } - } -#endif - } - break; - } - Lnextarg: - ; - } - L2: - ; - } - else if (addargp(&n,(*pargv)[i])) - goto noexpand; - } - n.argv[n.argc] = NULL; - if (recurse) - { - /* Recursively expand @filename */ - if (response_expand(&n.argc,&n.argv)) - goto noexpand; - } - *pargc = n.argc; - *pargv = n.argv; - return 0; /* success */ - -noexpand: /* error */ - free(n.argv); - /* BUG: any file buffers are not free'd */ - return 1; -} +// Copyright (C) 1990-1998 by Symantec +// Copyright (C) 2000-2009 by Digital Mars +// All Rights Reserved +// http://www.digitalmars.com +// Written by Walter Bright +/* + * This source file is made available for personal use + * only. The license is in /dmd/src/dmd/backendlicense.txt + * For any other uses, please contact Digital Mars. + */ + +#include +#include +#include +#include + +#if _WIN32 +#include +#include +#endif + +#if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4 +#include +#include +#include +#include +#include +#include +#endif + +/********************************* + * #include + * int response_expand(int *pargc,char ***pargv); + * + * Expand any response files in command line. + * Response files are arguments that look like: + * @NAME + * The name is first searched for in the environment. If it is not + * there, it is searched for as a file name. + * Arguments are separated by spaces, tabs, or newlines. These can be + * imbedded within arguments by enclosing the argument in '' or "". + * Recursively expands nested response files. + * + * To use, put the line: + * response_expand(&argc,&argv); + * as the first executable statement in main(int argc, char **argv). + * argc and argv are adjusted to be the new command line arguments + * after response file expansion. + * + * Digital Mars's MAKE program can be notified that a program can accept + * long command lines via environment variables by preceding the rule + * line for the program with a *. + * + * Returns: + * 0 success + * !=0 failure (argc, argv unchanged) + */ + +struct Narg +{ + int argc; /* arg count */ + int argvmax; /* dimension of nargv[] */ + char **argv; +}; + +static int addargp(struct Narg *n, char *p) +{ + /* The 2 is to always allow room for a NULL argp at the end */ + if (n->argc + 2 >= n->argvmax) + { + n->argvmax = n->argc + 2; + n->argv = (char **) realloc(n->argv,n->argvmax * sizeof(char *)); + if (!n->argv) + return 1; + } + n->argv[n->argc++] = p; + return 0; +} + +int response_expand(int *pargc, char ***pargv) +{ + struct Narg n; + int i; + char *cp; + int recurse = 0; + + n.argc = 0; + n.argvmax = 0; /* dimension of n.argv[] */ + n.argv = NULL; + for(i=0; i<*pargc; ++i) + { + cp = (*pargv)[i]; + if (*cp == '@') + { + char *buffer; + char *bufend; + char *p; + + cp++; + p = getenv(cp); + if (p) + { + buffer = strdup(p); + if (!buffer) + goto noexpand; + bufend = buffer + strlen(buffer); + } + else + { + long length; + int fd; + int nread; + size_t len; + +#if __DMC__ + length = filesize(cp); +#else + struct stat statbuf; + if (stat(cp, &statbuf)) + goto noexpand; + length = statbuf.st_size; +#endif + if (length & 0xF0000000) /* error or file too big */ + goto noexpand; + len = length; + buffer = (char *)malloc(len + 1); + if (!buffer) + goto noexpand; + bufend = &buffer[len]; + /* Read file into buffer */ +#if _WIN32 + fd = open(cp,O_RDONLY|O_BINARY); +#else + fd = open(cp,O_RDONLY); +#endif + if (fd == -1) + goto noexpand; + nread = read(fd,buffer,len); + close(fd); + + if (nread != len) + goto noexpand; + } + + // The logic of this should match that in setargv() + + for (p = buffer; p < bufend; p++) + { + char *d; + char c,lastc; + unsigned char instring; + int num_slashes,non_slashes; + + switch (*p) + { + case 26: /* ^Z marks end of file */ + goto L2; + + case 0xD: + case 0: + case ' ': + case '\t': + case '\n': + continue; // scan to start of argument + + case '@': + recurse = 1; + default: /* start of new argument */ + if (addargp(&n,p)) + goto noexpand; + instring = 0; + c = 0; + num_slashes = 0; + for (d = p; 1; p++) + { + lastc = c; + if (p >= bufend) + goto Lend; + c = *p; + switch (c) + { + case '"': + /* + Yes this looks strange,but this is so that we are + MS Compatible, tests have shown that: + \\\\"foo bar" gets passed as \\foo bar + \\\\foo gets passed as \\\\foo + \\\"foo gets passed as \"foo + and \"foo gets passed as "foo in VC! + */ + non_slashes = num_slashes % 2; + num_slashes = num_slashes / 2; + for (; num_slashes > 0; num_slashes--) + { + d--; + *d = '\0'; + } + + if (non_slashes) + { + *(d-1) = c; + } + else + { + instring ^= 1; + } + break; + case 26: + Lend: + *d = 0; // terminate argument + goto L2; + + case 0xD: // CR + c = lastc; + continue; // ignore + + case '@': + recurse = 1; + goto Ladd; + + case ' ': + case '\t': + if (!instring) + { + case '\n': + case 0: + *d = 0; // terminate argument + goto Lnextarg; + } + default: + Ladd: + if (c == '\\') + num_slashes++; + else + num_slashes = 0; + *d++ = c; + break; + } +#ifdef _MBCS + if (_istlead (c)) { + *d++ = *++p; + if (*(d - 1) == '\0') { + d--; + goto Lnextarg; + } + } +#endif + } + break; + } + Lnextarg: + ; + } + L2: + ; + } + else if (addargp(&n,(*pargv)[i])) + goto noexpand; + } + n.argv[n.argc] = NULL; + if (recurse) + { + /* Recursively expand @filename */ + if (response_expand(&n.argc,&n.argv)) + goto noexpand; + } + *pargc = n.argc; + *pargv = n.argv; + return 0; /* success */ + +noexpand: /* error */ + free(n.argv); + /* BUG: any file buffers are not free'd */ + return 1; +} diff --git a/dmd2/root/rmem.h b/dmd2/root/rmem.h index 61930209..85ebda62 100644 --- a/dmd2/root/rmem.h +++ b/dmd2/root/rmem.h @@ -1,51 +1,51 @@ -// Copyright (C) 2000-2001 by Chromium Communications -// All Rights Reserved - -#ifndef ROOT_MEM_H -#define ROOT_MEM_H - -#include // for size_t - -typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); - -struct GC; // thread specific allocator - -struct Mem -{ - GC *gc; // pointer to our thread specific allocator - Mem() { gc = NULL; } - - void init(); - - // Derive from Mem to get these storage allocators instead of global new/delete - void * operator new(size_t m_size); - void * operator new(size_t m_size, Mem *mem); - void * operator new(size_t m_size, GC *gc); - void operator delete(void *p); - - void * operator new[](size_t m_size); - void operator delete[](void *p); - - char *strdup(const char *s); - void *malloc(size_t size); - void *malloc_uncollectable(size_t size); - void *calloc(size_t size, size_t n); - void *realloc(void *p, size_t size); - void free(void *p); - void free_uncollectable(void *p); - void *mallocdup(void *o, size_t size); - void error(); - void check(void *p); // validate pointer - void fullcollect(); // do full garbage collection - void fullcollectNoStack(); // do full garbage collection, no scan stack - void mark(void *pointer); - void addroots(char* pStart, char* pEnd); - void removeroots(char* pStart); - void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); - void setStackBottom(void *bottom); - GC *getThreadGC(); // get apartment allocator for this thread -}; - -extern Mem mem; - -#endif /* ROOT_MEM_H */ +// Copyright (C) 2000-2001 by Chromium Communications +// All Rights Reserved + +#ifndef ROOT_MEM_H +#define ROOT_MEM_H + +#include // for size_t + +typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); + +struct GC; // thread specific allocator + +struct Mem +{ + GC *gc; // pointer to our thread specific allocator + Mem() { gc = NULL; } + + void init(); + + // Derive from Mem to get these storage allocators instead of global new/delete + void * operator new(size_t m_size); + void * operator new(size_t m_size, Mem *mem); + void * operator new(size_t m_size, GC *gc); + void operator delete(void *p); + + void * operator new[](size_t m_size); + void operator delete[](void *p); + + char *strdup(const char *s); + void *malloc(size_t size); + void *malloc_uncollectable(size_t size); + void *calloc(size_t size, size_t n); + void *realloc(void *p, size_t size); + void free(void *p); + void free_uncollectable(void *p); + void *mallocdup(void *o, size_t size); + void error(); + void check(void *p); // validate pointer + void fullcollect(); // do full garbage collection + void fullcollectNoStack(); // do full garbage collection, no scan stack + void mark(void *pointer); + void addroots(char* pStart, char* pEnd); + void removeroots(char* pStart); + void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); + void setStackBottom(void *bottom); + GC *getThreadGC(); // get apartment allocator for this thread +}; + +extern Mem mem; + +#endif /* ROOT_MEM_H */ diff --git a/dmd2/root/root.c b/dmd2/root/root.c index 2e9f8dc6..0ff5a461 100644 --- a/dmd2/root/root.c +++ b/dmd2/root/root.c @@ -1,1952 +1,2091 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -#ifndef POSIX -#define POSIX (linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4) -#endif - -#include -#include -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER ||__MINGW32__ -#include -#include -#endif - -#if _WIN32 -#include -#include -#endif - -#if POSIX -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "dchar.h" -#include "rmem.h" - -#if 0 //__SC__ //def DEBUG -extern "C" void __cdecl _assert(void *e, void *f, unsigned line) -{ - printf("Assert('%s','%s',%d)\n",e,f,line); - fflush(stdout); - *(char *)0 = 0; -} -#endif - - -/************************************* - * Convert wchar string to ascii string. - */ - -char *wchar2ascii(wchar_t *us) -{ - return wchar2ascii(us, wcslen(us)); -} - -char *wchar2ascii(wchar_t *us, unsigned len) -{ - unsigned i; - char *p; - - p = (char *)mem.malloc(len + 1); - for (i = 0; i <= len; i++) - p[i] = (char) us[i]; - return p; -} - -int wcharIsAscii(wchar_t *us) -{ - return wcharIsAscii(us, wcslen(us)); -} - -int wcharIsAscii(wchar_t *us, unsigned len) -{ - unsigned i; - - for (i = 0; i <= len; i++) - { - if (us[i] & ~0xFF) // if high bits set - return 0; // it's not ascii - } - return 1; -} - - -/*********************************** - * Compare length-prefixed strings (bstr). - */ - -int bstrcmp(unsigned char *b1, unsigned char *b2) -{ - return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; -} - -/*************************************** - * Convert bstr into a malloc'd string. - */ - -char *bstr2str(unsigned char *b) -{ - char *s; - unsigned len; - - len = *b; - s = (char *) mem.malloc(len + 1); - s[len] = 0; - return (char *)memcpy(s,b + 1,len); -} - -/************************************** - * Print error message and exit. - */ - -void error(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} - -#if M_UNICODE -void error(const dchar *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vwprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} -#endif - -void error_mem() -{ - error("out of memory"); -} - -/************************************** - * Print warning message. - */ - -void warning(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Warning: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); -} - -/****************************** Object ********************************/ - -int Object::equals(Object *o) -{ - return o == this; -} - -hash_t Object::hashCode() -{ - return (hash_t) this; -} - -int Object::compare(Object *obj) -{ - return this - obj; -} - -void Object::print() -{ - printf("%s %p\n", toChars(), this); -} - -char *Object::toChars() -{ - return (char *)"Object"; -} - -dchar *Object::toDchars() -{ -#if M_UNICODE - return L"Object"; -#else - return toChars(); -#endif -} - -int Object::dyncast() -{ - return 0; -} - -void Object::toBuffer(OutBuffer *b) -{ - b->writestring("Object"); -} - -void Object::mark() -{ -} - -/****************************** String ********************************/ - -String::String(char *str, int ref) -{ - this->str = ref ? str : mem.strdup(str); - this->ref = ref; -} - -String::~String() -{ - mem.free(str); -} - -void String::mark() -{ - mem.mark(str); -} - -hash_t String::calcHash(const char *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(uint16_t *)str << 8) + - ((uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -hash_t String::calcHash(const char *str) -{ - return calcHash(str, strlen(str)); -} - -hash_t String::hashCode() -{ - return calcHash(str, strlen(str)); -} - -unsigned String::len() -{ - return strlen(str); -} - -int String::equals(Object *obj) -{ - return strcmp(str,((String *)obj)->str) == 0; -} - -int String::compare(Object *obj) -{ - return strcmp(str,((String *)obj)->str); -} - -char *String::toChars() -{ - return str; -} - -void String::print() -{ - printf("String '%s'\n",str); -} - - -/****************************** FileName ********************************/ - -FileName::FileName(char *str, int ref) - : String(str,ref) -{ -} - -char *FileName::combine(const char *path, const char *name) -{ char *f; - size_t pathlen; - size_t namelen; - - if (!path || !*path) - return (char *)name; - pathlen = strlen(path); - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -FileName::FileName(char *path, char *name) - : String(combine(path,name),1) -{ -} - -// Split a path into an Array of paths -Array *FileName::splitPath(const char *path) -{ - char c = 0; // unnecessary initializer is for VC /W4 - const char *p; - OutBuffer buf; - Array *array; - - array = new Array(); - if (path) - { - p = path; - do - { char instring = 0; - - while (isspace(*p)) // skip leading whitespace - p++; - buf.reserve(strlen(p) + 1); // guess size of path - for (; ; p++) - { - c = *p; - switch (c) - { - case '"': - instring ^= 1; // toggle inside/outside of string - continue; - -#if MACINTOSH - case ',': -#endif -#if _WIN32 - case ';': -#endif -#if POSIX - case ':': -#endif - p++; - break; // note that ; cannot appear as part - // of a path, quotes won't protect it - - case 0x1A: // ^Z means end of file - case 0: - break; - - case '\r': - continue; // ignore carriage returns - -#if POSIX - case '~': - buf.writestring(getenv("HOME")); - continue; -#endif - -#if 0 - case ' ': - case '\t': // tabs in filenames? - if (!instring) // if not in string - break; // treat as end of path -#endif - default: - buf.writeByte(c); - continue; - } - break; - } - if (buf.offset) // if path is not empty - { - buf.writeByte(0); // to asciiz - array->push(buf.extractData()); - } - } while (c); - } - return array; -} - -hash_t FileName::hashCode() -{ -#if _WIN32 - // We need a different hashCode because it must be case-insensitive - size_t len = strlen(str); - hash_t hash = 0; - unsigned char *s = (unsigned char *)str; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)s | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)s | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(uint16_t *)s << 8) + - ((uint8_t *)s)[2]) | 0x202020; - break; - - default: - hash *= 37; - hash += *(uint32_t *)s | 0x20202020; - s += 4; - len -= 4; - break; - } - } -#else - // darwin HFS is case insensitive, though... - return String::hashCode(); -#endif -} - -int FileName::compare(Object *obj) -{ - return compare(str, ((FileName *)obj)->str); -} - -int FileName::compare(const char *name1, const char *name2) -{ -#if _WIN32 - return stricmp(name1, name2); -#else - return strcmp(name1, name2); -#endif -} - -int FileName::equals(Object *obj) -{ - return compare(obj) == 0; -} - -int FileName::equals(const char *name1, const char *name2) -{ - return compare(name1, name2) == 0; -} - -/************************************ - * Return !=0 if absolute path name. - */ - -int FileName::absolute(const char *name) -{ -#if _WIN32 - return (*name == '\\') || - (*name == '/') || - (*name && name[1] == ':'); -#elif POSIX - return (*name == '/'); -#else - assert(0); -#endif -} - -/******************************** - * Return filename extension (read-only). - * Points past '.' of extension. - * If there isn't one, return NULL. - */ - -char *FileName::ext(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { case '.': - return e + 1; -#if POSIX - case '/': - break; -#endif -#if _WIN32 - case '\\': - case ':': - case '/': - break; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return NULL; - } -} - -char *FileName::ext() -{ - return ext(str); -} - -/******************************** - * Return mem.malloc'd filename with extension removed. - */ - -char *FileName::removeExt(const char *str) -{ - const char *e = ext(str); - if (e) - { size_t len = (e - str) - 1; - char *n = (char *)mem.malloc(len + 1); - memcpy(n, str, len); - n[len] = 0; - return n; - } - return mem.strdup(str); -} - -/******************************** - * Return filename name excluding path (read-only). - */ - -char *FileName::name(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { -#if POSIX - case '/': - return e + 1; -#endif -#if _WIN32 - case '/': - case '\\': - return e + 1; - case ':': - /* The ':' is a drive letter only if it is the second - * character or the last character, - * otherwise it is an ADS (Alternate Data Stream) separator. - * Consider ADS separators as part of the file name. - */ - if (e == str + 1 || e == str + len - 1) - return e + 1; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return e; - } -} - -char *FileName::name() -{ - return name(str); -} - -/************************************** - * Return path portion of str. - * Path will does not include trailing path separator. - */ - -char *FileName::path(const char *str) -{ - char *n = name(str); - char *path; - size_t pathlen; - - if (n > str) - { -#if POSIX - if (n[-1] == '/') - n--; -#elif _WIN32 - if (n[-1] == '\\' || n[-1] == '/') - n--; -#else - assert(0); -#endif - } - pathlen = n - str; - path = (char *)mem.malloc(pathlen + 1); - memcpy(path, str, pathlen); - path[pathlen] = 0; - return path; -} - -/************************************** - * Replace filename portion of path. - */ - -const char *FileName::replaceName(const char *path, const char *name) -{ char *f; - char *n; - size_t pathlen; - size_t namelen; - - if (absolute(name)) - return name; - - n = FileName::name(path); - if (n == path) - return name; - pathlen = n - path; - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -/*************************** - */ - -FileName *FileName::defaultExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - return new FileName((char *)name, 0); - - len = strlen(name); - extlen = strlen(ext); - s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s,name,len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - return new FileName(s, 0); -} - -/*************************** - */ - -FileName *FileName::forceExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - { - len = e - name; - extlen = strlen(ext); - - s = (char *)alloca(len + extlen + 1); - memcpy(s,name,len); - memcpy(s + len, ext, extlen + 1); - return new FileName(s, 0); - } - else - return defaultExt(name, ext); // doesn't have one -} - -/****************************** - * Return !=0 if extensions match. - */ - -int FileName::equalsExt(const char *ext) -{ const char *e; - - e = FileName::ext(); - if (!e && !ext) - return 1; - if (!e || !ext) - return 0; -#if POSIX - return strcmp(e,ext) == 0; -#elif _WIN32 - return stricmp(e,ext) == 0; -#else - assert(0); -#endif -} - -/************************************* - * Copy file from this to to. - */ - -void FileName::CopyTo(FileName *to) -{ - File file(this); - -#if _WIN32 - file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time -#elif POSIX - file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time -#else - assert(0); -#endif - file.readv(); - file.name = to; - file.writev(); -} - -/************************************* - * Search Path for file. - * Input: - * cwd if !=0, search current directory before searching path - */ - -char *FileName::searchPath(Array *path, const char *name, int cwd) -{ - if (absolute(name)) - { - return exists(name) ? (char *)name : NULL; - } - if (cwd) - { - if (exists(name)) - return (char *)name; - } - if (path) - { unsigned i; - - for (i = 0; i < path->dim; i++) - { - char *p = (char *)path->data[i]; - char *n = combine(p, name); - - if (exists(n)) - return n; - } - } - return NULL; -} - -int FileName::exists(const char *name) -{ -#if POSIX - struct stat st; - - if (stat(name, &st) < 0) - return 0; - if (S_ISDIR(st.st_mode)) - return 2; - return 1; -#elif _WIN32 - DWORD dw; - int result; - - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void FileName::ensurePathExists(const char *path) -{ - //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); - if (path && *path) - { - if (!exists(path)) - { - char *p = FileName::path(path); - if (*p) - { -#if _WIN32 - size_t len = strlen(path); - if (len > 2 && p[-1] == ':' && path + 2 == p) - { mem.free(p); - return; - } -#endif - ensurePathExists(p); - mem.free(p); - } -#if _WIN32 - if (path[strlen(path) - 1] != '\\') -#endif -#if POSIX - if (path[strlen(path) - 1] != '\\') -#endif - { - //printf("mkdir(%s)\n", path); -#if _WIN32 - if (mkdir(path)) -#endif -#if POSIX - if (mkdir(path, 0777)) -#endif - error("cannot create directory %s", path); - } - } - } -} - -/****************************** File ********************************/ - -File::File(FileName *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = n; -} - -File::File(char *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = new FileName(n, 0); -} - -File::~File() -{ - if (buffer) - { - if (ref == 0) - mem.free(buffer); -#if _WIN32 - else if (ref == 2) - UnmapViewOfFile(buffer); -#endif - } - if (touchtime) - mem.free(touchtime); -} - -void File::mark() -{ - mem.mark(buffer); - mem.mark(touchtime); - mem.mark(name); -} - -/************************************* - */ - -int File::read() -{ -#if POSIX - off_t size; - ssize_t numread; - int fd; - struct stat buf; - int result = 0; - char *name; - - name = this->name->toChars(); - //printf("File::read('%s')\n",name); - fd = open(name, O_RDONLY); - if (fd == -1) - { result = errno; - //printf("\topen error, errno = %d\n",errno); - goto err1; - } - - if (!ref) - mem.free(buffer); - ref = 0; // we own the buffer now - - //printf("\tfile opened\n"); - if (fstat(fd, &buf)) - { - printf("\tfstat error, errno = %d\n",errno); - goto err2; - } - size = buf.st_size; - buffer = (unsigned char *) mem.malloc(size + 2); - if (!buffer) - { - printf("\tmalloc error, errno = %d\n",errno); - goto err2; - } - - numread = ::read(fd, buffer, size); - if (numread != size) - { - printf("\tread error, errno = %d\n",errno); - goto err2; - } - - if (touchtime) - memcpy(touchtime, &buf, sizeof(buf)); - - if (close(fd) == -1) - { - printf("\tclose error, errno = %d\n",errno); - goto err; - } - - len = size; - - // Always store a wchar ^Z past end of buffer so scanner has a sentinel - buffer[size] = 0; // ^Z is obsolete, use 0 - buffer[size + 1] = 0; - return 0; - -err2: - close(fd); -err: - mem.free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#elif _WIN32 - DWORD size; - DWORD numread; - HANDLE h; - int result = 0; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); - if (h == INVALID_HANDLE_VALUE) - goto err1; - - if (!ref) - mem.free(buffer); - ref = 0; - - size = GetFileSize(h,NULL); - buffer = (unsigned char *) mem.malloc(size + 2); - if (!buffer) - goto err2; - - if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) - goto err2; - - if (numread != size) - goto err2; - - if (touchtime) - { - if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) - goto err2; - } - - if (!CloseHandle(h)) - goto err; - - len = size; - - // Always store a wchar ^Z past end of buffer so scanner has a sentinel - buffer[size] = 0; // ^Z is obsolete, use 0 - buffer[size + 1] = 0; - return 0; - -err2: - CloseHandle(h); -err: - mem.free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#else - assert(0); -#endif -} - -/***************************** - * Read a file with memory mapped file I/O. - */ - -int File::mmread() -{ -#if POSIX - return read(); -#elif _WIN32 - HANDLE hFile; - HANDLE hFileMap; - DWORD size; - char *name; - - name = this->name->toChars(); - hFile = CreateFile(name, GENERIC_READ, - FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - goto Lerr; - size = GetFileSize(hFile, NULL); - //printf(" file created, size %d\n", size); - - hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); - if (CloseHandle(hFile) != TRUE) - goto Lerr; - - if (hFileMap == NULL) - goto Lerr; - - //printf(" mapping created\n"); - - if (!ref) - mem.free(buffer); - ref = 2; - buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); - if (CloseHandle(hFileMap) != TRUE) - goto Lerr; - if (buffer == NULL) // mapping view failed - goto Lerr; - - len = size; - //printf(" buffer = %p\n", buffer); - - return 0; - -Lerr: - return GetLastError(); // failure -#else - assert(0); -#endif -} - -/********************************************* - * Write a file. - * Returns: - * 0 success - */ - -int File::write() -{ -#if POSIX - int fd; - ssize_t numwritten; - char *name; - - name = this->name->toChars(); - fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (fd == -1) - goto err; - - numwritten = ::write(fd, buffer, len); - if (len != numwritten) - goto err2; - - if (close(fd) == -1) - goto err; - - if (touchtime) - { struct utimbuf ubuf; - - ubuf.actime = ((struct stat *)touchtime)->st_atime; - ubuf.modtime = ((struct stat *)touchtime)->st_mtime; - if (utime(name, &ubuf)) - goto err; - } - return 0; - -err2: - close(fd); - ::remove(name); -err: - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); - DeleteFileA(name); -err: - return 1; -#else - assert(0); -#endif -} - -/********************************************* - * Append to a file. - * Returns: - * 0 success - */ - -int File::append() -{ -#if POSIX - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - -#if 1 - SetFilePointer(h, 0, NULL, FILE_END); -#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition - if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - goto err; -#endif - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); -err: - return 1; -#else - assert(0); -#endif -} - -/************************************** - */ - -void File::readv() -{ - if (read()) - error("Error reading file '%s'\n",name->toChars()); -} - -/************************************** - */ - -void File::mmreadv() -{ - if (mmread()) - readv(); -} - -void File::writev() -{ - if (write()) - error("Error writing file '%s'\n",name->toChars()); -} - -void File::appendv() -{ - if (write()) - error("Error appending to file '%s'\n",name->toChars()); -} - -/******************************************* - * Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - -int File::exists() -{ -#if POSIX - return 0; -#elif _WIN32 - DWORD dw; - int result; - char *name; - - name = this->name->toChars(); - if (touchtime) - dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; - else - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void File::remove() -{ -#if POSIX - ::remove(this->name->toChars()); -#elif _WIN32 - DeleteFileA(this->name->toChars()); -#else - assert(0); -#endif -} - -Array *File::match(char *n) -{ - return match(new FileName(n, 0)); -} - -Array *File::match(FileName *n) -{ -#if POSIX - return NULL; -#elif _WIN32 - HANDLE h; - WIN32_FIND_DATAA fileinfo; - Array *a; - char *c; - char *name; - - a = new Array(); - c = n->toChars(); - name = n->name(); - h = FindFirstFileA(c,&fileinfo); - if (h != INVALID_HANDLE_VALUE) - { - do - { - // Glue path together with name - char *fn; - File *f; - - fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); - memcpy(fn, c, name - c); - strcpy(fn + (name - c), fileinfo.cFileName); - f = new File(fn); - f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); - memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); - a->push(f); - } while (FindNextFileA(h,&fileinfo) != FALSE); - FindClose(h); - } - return a; -#else - assert(0); -#endif -} - -int File::compareTime(File *f) -{ -#if POSIX - return 0; -#elif _WIN32 - if (!touchtime) - stat(); - if (!f->touchtime) - f->stat(); - return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); -#else - assert(0); -#endif -} - -void File::stat() -{ -#if POSIX - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(struct stat)); - } -#elif _WIN32 - HANDLE h; - - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); - } - h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); - if (h != INVALID_HANDLE_VALUE) - { - FindClose(h); - } -#else - assert(0); -#endif -} - -void File::checkoffset(size_t offset, size_t nbytes) -{ - if (offset > len || offset + nbytes > len) - error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset); -} - -char *File::toChars() -{ - return name->toChars(); -} - - -/************************* OutBuffer *************************/ - -OutBuffer::OutBuffer() -{ - data = NULL; - offset = 0; - size = 0; -} - -OutBuffer::~OutBuffer() -{ - mem.free(data); -} - -void *OutBuffer::extractData() -{ - void *p; - - p = (void *)data; - data = NULL; - offset = 0; - size = 0; - return p; -} - -void OutBuffer::mark() -{ - mem.mark(data); -} - -void OutBuffer::reserve(unsigned nbytes) -{ - //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); - if (size - offset < nbytes) - { - size = (offset + nbytes) * 2; - data = (unsigned char *)mem.realloc(data, size); - } -} - -void OutBuffer::reset() -{ - offset = 0; -} - -void OutBuffer::setsize(unsigned size) -{ - offset = size; -} - -void OutBuffer::write(const void *data, unsigned nbytes) -{ - reserve(nbytes); - memcpy(this->data + offset, data, nbytes); - offset += nbytes; -} - -void OutBuffer::writebstring(unsigned char *string) -{ - write(string,*string + 1); -} - -void OutBuffer::writestring(const char *string) -{ - write(string,strlen(string)); -} - -void OutBuffer::writedstring(const char *string) -{ -#if M_UNICODE - for (; *string; string++) - { - writedchar(*string); - } -#else - write(string,strlen(string)); -#endif -} - -void OutBuffer::writedstring(const wchar_t *string) -{ -#if M_UNICODE - write(string,wcslen(string) * sizeof(wchar_t)); -#else - for (; *string; string++) - { - writedchar(*string); - } -#endif -} - -void OutBuffer::prependstring(const char *string) -{ unsigned len; - - len = strlen(string); - reserve(len); - memmove(data + len, data, offset); - memcpy(data, string, len); - offset += len; -} - -void OutBuffer::writenl() -{ -#if _WIN32 -#if M_UNICODE - write4(0x000A000D); // newline is CR,LF on Microsoft OS's -#else - writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#endif -#else -#if M_UNICODE - writeword('\n'); -#else - writeByte('\n'); -#endif -#endif -} - -void OutBuffer::writeByte(unsigned b) -{ - reserve(1); - this->data[offset] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeUTF8(unsigned b) -{ - reserve(6); - if (b <= 0x7F) - { - this->data[offset] = (unsigned char)b; - offset++; - } - else if (b <= 0x7FF) - { - this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); - this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); - offset += 2; - } - else if (b <= 0xFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); - this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); - offset += 3; - } - else if (b <= 0x1FFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); - this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); - offset += 4; - } - else if (b <= 0x3FFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); - this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); - offset += 5; - } - else if (b <= 0x7FFFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); - this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); - offset += 6; - } - else - assert(0); -} - -void OutBuffer::writedchar(unsigned b) -{ - reserve(Dchar_mbmax * sizeof(dchar)); - offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - - this->data; -} - -void OutBuffer::prependbyte(unsigned b) -{ - reserve(1); - memmove(data + 1, data, offset); - data[0] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeword(unsigned w) -{ - reserve(2); - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; -} - -void OutBuffer::writeUTF16(unsigned w) -{ - reserve(4); - if (w <= 0xFFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; - } - else if (w <= 0x10FFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); - *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); - offset += 4; - } - else - assert(0); -} - -void OutBuffer::write4(unsigned w) -{ - reserve(4); - *(unsigned long *)(this->data + offset) = w; - offset += 4; -} - -void OutBuffer::write(OutBuffer *buf) -{ - if (buf) - { reserve(buf->offset); - memcpy(data + offset, buf->data, buf->offset); - offset += buf->offset; - } -} - -void OutBuffer::write(Object *obj) -{ - if (obj) - { - writestring(obj->toChars()); - } -} - -void OutBuffer::fill0(unsigned nbytes) -{ - reserve(nbytes); - memset(data + offset,0,nbytes); - offset += nbytes; -} - -void OutBuffer::align(unsigned size) -{ unsigned nbytes; - - nbytes = ((offset + size - 1) & ~(size - 1)) - offset; - fill0(nbytes); -} - - -//////////////////////////////////////////////////////////////// -// The compiler shipped with Visual Studio 2005 (and possible -// other versions) does not support C99 printf format specfiers -// such as %z and %j -#if _MSC_VER -using std::string; -using std::wstring; - -template -inline void -search_and_replace(S& str, const S& what, const S& replacement) -{ - assert(!what.empty()); - size_t pos = str.find(what); - while (pos != S::npos) - { - str.replace(pos, what.size(), replacement); - pos = str.find(what, pos + replacement.size()); - } -} -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \ - S tmp = f; \ - search_and_replace(fmt, S("%z"), S("%l")); \ - search_and_replace(fmt, S("%j"), S("%i")); \ - f = tmp.c_str(); -#else -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) -#endif - -void OutBuffer::vprintf(const char *format, va_list args) -{ - char buffer[128]; - char *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format); - - p = buffer; - psize = sizeof(buffer); - for (;;) - { -#if _WIN32 - count = _vsnprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); -/* - The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() - are equivalent to the functions printf(), fprintf(), sprintf(), - snprintf(), respectively, except that they are called with a - va_list instead of a variable number of arguments. These - functions do not call the va_end macro. Consequently, the value - of ap is undefined after the call. The application should call - va_end(ap) itself afterwards. - */ - count = vsnprintf(p,psize,format,va); - va_end(va); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (char *) alloca(psize); // buffer too small, try again with larger size - } - write(p,count); -} - -#if M_UNICODE -void OutBuffer::vprintf(const wchar_t *format, va_list args) -{ - dchar buffer[128]; - dchar *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format); - - p = buffer; - psize = sizeof(buffer) / sizeof(buffer[0]); - for (;;) - { -#if _WIN32 - count = _vsnwprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); - count = vsnwprintf(p,psize,format,va); - va_end(va); - - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size - } - write(p,count * 2); -} -#endif - -void OutBuffer::printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} - -#if M_UNICODE -void OutBuffer::printf(const wchar_t *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} -#endif - -void OutBuffer::bracket(char left, char right) -{ - reserve(2); - memmove(data + 1, data, offset); - data[0] = left; - data[offset + 1] = right; - offset += 2; -} - -/****************** - * Insert left at i, and right at j. - * Return index just past right. - */ - -unsigned OutBuffer::bracket(unsigned i, const char *left, unsigned j, const char *right) -{ - size_t leftlen = strlen(left); - size_t rightlen = strlen(right); - reserve(leftlen + rightlen); - insert(i, left, leftlen); - insert(j + leftlen, right, rightlen); - return j + leftlen + rightlen; -} - -void OutBuffer::spread(unsigned offset, unsigned nbytes) -{ - reserve(nbytes); - memmove(data + offset + nbytes, data + offset, - this->offset - offset); - this->offset += nbytes; -} - -/**************************************** - * Returns: offset + nbytes - */ - -unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) -{ - spread(offset, nbytes); - memmove(data + offset, p, nbytes); - return offset + nbytes; -} - -void OutBuffer::remove(unsigned offset, unsigned nbytes) -{ - memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); - this->offset -= nbytes; -} - -char *OutBuffer::toChars() -{ - writeByte(0); - return (char *)data; -} - -/********************************* Bits ****************************/ - -Bits::Bits() -{ - data = NULL; - bitdim = 0; - allocdim = 0; -} - -Bits::~Bits() -{ - mem.free(data); -} - -void Bits::mark() -{ - mem.mark(data); -} - -void Bits::resize(unsigned bitdim) -{ - unsigned allocdim; - unsigned mask; - - allocdim = (bitdim + 31) / 32; - data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); - if (this->allocdim < allocdim) - memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= ~mask; - - this->bitdim = bitdim; - this->allocdim = allocdim; -} - -void Bits::set(unsigned bitnum) -{ - data[bitnum / 32] |= 1 << (bitnum & 31); -} - -void Bits::clear(unsigned bitnum) -{ - data[bitnum / 32] &= ~(1 << (bitnum & 31)); -} - -int Bits::test(unsigned bitnum) -{ - return data[bitnum / 32] & (1 << (bitnum & 31)); -} - -void Bits::set() -{ unsigned mask; - - memset(data, ~0, allocdim * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= mask; -} - -void Bits::clear() -{ - memset(data, 0, allocdim * sizeof(data[0])); -} - -void Bits::copy(Bits *from) -{ - assert(bitdim == from->bitdim); - memcpy(data, from->data, allocdim * sizeof(data[0])); -} - -Bits *Bits::clone() -{ - Bits *b; - - b = new Bits(); - b->resize(bitdim); - b->copy(this); - return b; -} - -void Bits::sub(Bits *b) -{ - unsigned u; - - for (u = 0; u < allocdim; u++) - data[u] &= ~b->data[u]; -} - - - - - - - - - - - - - - - + +// Copyright (c) 1999-2010 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. + +#ifndef POSIX +#define POSIX (linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4) +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if (defined (__SVR4) && defined (__sun)) +#include +#endif + +#if _MSC_VER ||__MINGW32__ +#include +#include +#endif + +#if _WIN32 +#include +#include +#include +#endif + +#if POSIX +#include +#include +#include +#include +#include +#include +#endif + +#include "port.h" +#include "root.h" +#include "dchar.h" +#include "rmem.h" + +#if 0 //__SC__ //def DEBUG +extern "C" void __cdecl _assert(void *e, void *f, unsigned line) +{ + printf("Assert('%s','%s',%d)\n",e,f,line); + fflush(stdout); + *(char *)0 = 0; +} +#endif + + +/************************************* + * Convert wchar string to ascii string. + */ + +char *wchar2ascii(wchar_t *us) +{ + return wchar2ascii(us, wcslen(us)); +} + +char *wchar2ascii(wchar_t *us, unsigned len) +{ + unsigned i; + char *p; + + p = (char *)mem.malloc(len + 1); + for (i = 0; i <= len; i++) + p[i] = (char) us[i]; + return p; +} + +int wcharIsAscii(wchar_t *us) +{ + return wcharIsAscii(us, wcslen(us)); +} + +int wcharIsAscii(wchar_t *us, unsigned len) +{ + unsigned i; + + for (i = 0; i <= len; i++) + { + if (us[i] & ~0xFF) // if high bits set + return 0; // it's not ascii + } + return 1; +} + + +/*********************************** + * Compare length-prefixed strings (bstr). + */ + +int bstrcmp(unsigned char *b1, unsigned char *b2) +{ + return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; +} + +/*************************************** + * Convert bstr into a malloc'd string. + */ + +char *bstr2str(unsigned char *b) +{ + char *s; + unsigned len; + + len = *b; + s = (char *) mem.malloc(len + 1); + s[len] = 0; + return (char *)memcpy(s,b + 1,len); +} + +/************************************** + * Print error message and exit. + */ + +void error(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Error: "); + vprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); + + exit(EXIT_FAILURE); +} + +#if M_UNICODE +void error(const dchar *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Error: "); + vwprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); + + exit(EXIT_FAILURE); +} +#endif + +void error_mem() +{ + error("out of memory"); +} + +/************************************** + * Print warning message. + */ + +void warning(const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + printf("Warning: "); + vprintf(format, ap); + va_end( ap ); + printf("\n"); + fflush(stdout); +} + +/****************************** Object ********************************/ + +int Object::equals(Object *o) +{ + return o == this; +} + +hash_t Object::hashCode() +{ + return (hash_t) this; +} + +int Object::compare(Object *obj) +{ + return this - obj; +} + +void Object::print() +{ + printf("%s %p\n", toChars(), this); +} + +char *Object::toChars() +{ + return (char *)"Object"; +} + +dchar *Object::toDchars() +{ +#if M_UNICODE + return L"Object"; +#else + return toChars(); +#endif +} + +int Object::dyncast() +{ + return 0; +} + +void Object::toBuffer(OutBuffer *b) +{ + b->writestring("Object"); +} + +void Object::mark() +{ +} + +/****************************** String ********************************/ + +String::String(char *str, int ref) +{ + this->str = ref ? str : mem.strdup(str); + this->ref = ref; +} + +String::~String() +{ + mem.free(str); +} + +void String::mark() +{ + mem.mark(str); +} + +hash_t String::calcHash(const char *str, size_t len) +{ + hash_t hash = 0; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(uint8_t *)str; + return hash; + + case 2: + hash *= 37; + hash += *(uint16_t *)str; + return hash; + + case 3: + hash *= 37; + hash += (*(uint16_t *)str << 8) + + ((uint8_t *)str)[2]; + return hash; + + default: + hash *= 37; + hash += *(uint32_t *)str; + str += 4; + len -= 4; + break; + } + } +} + +hash_t String::calcHash(const char *str) +{ + return calcHash(str, strlen(str)); +} + +hash_t String::hashCode() +{ + return calcHash(str, strlen(str)); +} + +unsigned String::len() +{ + return strlen(str); +} + +int String::equals(Object *obj) +{ + return strcmp(str,((String *)obj)->str) == 0; +} + +int String::compare(Object *obj) +{ + return strcmp(str,((String *)obj)->str); +} + +char *String::toChars() +{ + return str; +} + +void String::print() +{ + printf("String '%s'\n",str); +} + + +/****************************** FileName ********************************/ + +FileName::FileName(char *str, int ref) + : String(str,ref) +{ +} + +char *FileName::combine(const char *path, const char *name) +{ char *f; + size_t pathlen; + size_t namelen; + + if (!path || !*path) + return (char *)name; + pathlen = strlen(path); + namelen = strlen(name); + f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + memcpy(f, path, pathlen); +#if POSIX + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#elif _WIN32 + if (path[pathlen - 1] != '\\' && + path[pathlen - 1] != '/' && + path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#else + assert(0); +#endif + memcpy(f + pathlen, name, namelen + 1); + return f; +} + +FileName::FileName(char *path, char *name) + : String(combine(path,name),1) +{ +} + +// Split a path into an Array of paths +Array *FileName::splitPath(const char *path) +{ + char c = 0; // unnecessary initializer is for VC /W4 + const char *p; + OutBuffer buf; + Array *array; + + array = new Array(); + if (path) + { + p = path; + do + { char instring = 0; + + while (isspace(*p)) // skip leading whitespace + p++; + buf.reserve(strlen(p) + 1); // guess size of path + for (; ; p++) + { + c = *p; + switch (c) + { + case '"': + instring ^= 1; // toggle inside/outside of string + continue; + +#if MACINTOSH + case ',': +#endif +#if _WIN32 + case ';': +#endif +#if POSIX + case ':': +#endif + p++; + break; // note that ; cannot appear as part + // of a path, quotes won't protect it + + case 0x1A: // ^Z means end of file + case 0: + break; + + case '\r': + continue; // ignore carriage returns + +#if POSIX + case '~': + buf.writestring(getenv("HOME")); + continue; +#endif + +#if 0 + case ' ': + case '\t': // tabs in filenames? + if (!instring) // if not in string + break; // treat as end of path +#endif + default: + buf.writeByte(c); + continue; + } + break; + } + if (buf.offset) // if path is not empty + { + buf.writeByte(0); // to asciiz + array->push(buf.extractData()); + } + } while (c); + } + return array; +} + +hash_t FileName::hashCode() +{ +#if _WIN32 + // We need a different hashCode because it must be case-insensitive + size_t len = strlen(str); + hash_t hash = 0; + unsigned char *s = (unsigned char *)str; + + for (;;) + { + switch (len) + { + case 0: + return hash; + + case 1: + hash *= 37; + hash += *(uint8_t *)s | 0x20; + return hash; + + case 2: + hash *= 37; + hash += *(uint16_t *)s | 0x2020; + return hash; + + case 3: + hash *= 37; + hash += ((*(uint16_t *)s << 8) + + ((uint8_t *)s)[2]) | 0x202020; + break; + + default: + hash *= 37; + hash += *(uint32_t *)s | 0x20202020; + s += 4; + len -= 4; + break; + } + } +#else + // darwin HFS is case insensitive, though... + return String::hashCode(); +#endif +} + +int FileName::compare(Object *obj) +{ + return compare(str, ((FileName *)obj)->str); +} + +int FileName::compare(const char *name1, const char *name2) +{ +#if _WIN32 + return stricmp(name1, name2); +#else + return strcmp(name1, name2); +#endif +} + +int FileName::equals(Object *obj) +{ + return compare(obj) == 0; +} + +int FileName::equals(const char *name1, const char *name2) +{ + return compare(name1, name2) == 0; +} + +/************************************ + * Return !=0 if absolute path name. + */ + +int FileName::absolute(const char *name) +{ +#if _WIN32 + return (*name == '\\') || + (*name == '/') || + (*name && name[1] == ':'); +#elif POSIX + return (*name == '/'); +#else + assert(0); +#endif +} + +/******************************** + * Return filename extension (read-only). + * Points past '.' of extension. + * If there isn't one, return NULL. + */ + +char *FileName::ext(const char *str) +{ + char *e; + size_t len = strlen(str); + + e = (char *)str + len; + for (;;) + { + switch (*e) + { case '.': + return e + 1; +#if POSIX + case '/': + break; +#endif +#if _WIN32 + case '\\': + case ':': + case '/': + break; +#endif + default: + if (e == str) + break; + e--; + continue; + } + return NULL; + } +} + +char *FileName::ext() +{ + return ext(str); +} + +/******************************** + * Return mem.malloc'd filename with extension removed. + */ + +char *FileName::removeExt(const char *str) +{ + const char *e = ext(str); + if (e) + { size_t len = (e - str) - 1; + char *n = (char *)mem.malloc(len + 1); + memcpy(n, str, len); + n[len] = 0; + return n; + } + return mem.strdup(str); +} + +/******************************** + * Return filename name excluding path (read-only). + */ + +char *FileName::name(const char *str) +{ + char *e; + size_t len = strlen(str); + + e = (char *)str + len; + for (;;) + { + switch (*e) + { +#if POSIX + case '/': + return e + 1; +#endif +#if _WIN32 + case '/': + case '\\': + return e + 1; + case ':': + /* The ':' is a drive letter only if it is the second + * character or the last character, + * otherwise it is an ADS (Alternate Data Stream) separator. + * Consider ADS separators as part of the file name. + */ + if (e == str + 1 || e == str + len - 1) + return e + 1; +#endif + default: + if (e == str) + break; + e--; + continue; + } + return e; + } +} + +char *FileName::name() +{ + return name(str); +} + +/************************************** + * Return path portion of str. + * Path will does not include trailing path separator. + */ + +char *FileName::path(const char *str) +{ + char *n = name(str); + char *path; + size_t pathlen; + + if (n > str) + { +#if POSIX + if (n[-1] == '/') + n--; +#elif _WIN32 + if (n[-1] == '\\' || n[-1] == '/') + n--; +#else + assert(0); +#endif + } + pathlen = n - str; + path = (char *)mem.malloc(pathlen + 1); + memcpy(path, str, pathlen); + path[pathlen] = 0; + return path; +} + +/************************************** + * Replace filename portion of path. + */ + +const char *FileName::replaceName(const char *path, const char *name) +{ char *f; + char *n; + size_t pathlen; + size_t namelen; + + if (absolute(name)) + return name; + + n = FileName::name(path); + if (n == path) + return name; + pathlen = n - path; + namelen = strlen(name); + f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + memcpy(f, path, pathlen); +#if POSIX + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#elif _WIN32 + if (path[pathlen - 1] != '\\' && + path[pathlen - 1] != '/' && + path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#else + assert(0); +#endif + memcpy(f + pathlen, name, namelen + 1); + return f; +} + +/*************************** + */ + +FileName *FileName::defaultExt(const char *name, const char *ext) +{ + char *e; + char *s; + size_t len; + size_t extlen; + + e = FileName::ext(name); + if (e) // if already has an extension + return new FileName((char *)name, 0); + + len = strlen(name); + extlen = strlen(ext); + s = (char *)alloca(len + 1 + extlen + 1); + memcpy(s,name,len); + s[len] = '.'; + memcpy(s + len + 1, ext, extlen + 1); + return new FileName(s, 0); +} + +/*************************** + */ + +FileName *FileName::forceExt(const char *name, const char *ext) +{ + char *e; + char *s; + size_t len; + size_t extlen; + + e = FileName::ext(name); + if (e) // if already has an extension + { + len = e - name; + extlen = strlen(ext); + + s = (char *)alloca(len + extlen + 1); + memcpy(s,name,len); + memcpy(s + len, ext, extlen + 1); + return new FileName(s, 0); + } + else + return defaultExt(name, ext); // doesn't have one +} + +/****************************** + * Return !=0 if extensions match. + */ + +int FileName::equalsExt(const char *ext) +{ const char *e; + + e = FileName::ext(); + if (!e && !ext) + return 1; + if (!e || !ext) + return 0; +#if POSIX + return strcmp(e,ext) == 0; +#elif _WIN32 + return stricmp(e,ext) == 0; +#else + assert(0); +#endif +} + +/************************************* + * Copy file from this to to. + */ + +void FileName::CopyTo(FileName *to) +{ + File file(this); + +#if _WIN32 + file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time +#elif POSIX + file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time +#else + assert(0); +#endif + file.readv(); + file.name = to; + file.writev(); +} + +/************************************* + * Search Path for file. + * Input: + * cwd if !=0, search current directory before searching path + */ + +char *FileName::searchPath(Array *path, const char *name, int cwd) +{ + if (absolute(name)) + { + return exists(name) ? (char *)name : NULL; + } + if (cwd) + { + if (exists(name)) + return (char *)name; + } + if (path) + { unsigned i; + + for (i = 0; i < path->dim; i++) + { + char *p = (char *)path->data[i]; + char *n = combine(p, name); + + if (exists(n)) + return n; + } + } + return NULL; +} + + +/************************************* + * Search Path for file in a safe manner. + * + * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory + * ('Path Traversal') attacks. + * http://cwe.mitre.org/data/definitions/22.html + * More info: + * https://www.securecoding.cert.org/confluence/display/seccode/FIO02-C.+Canonicalize+path+names+originating+from+untrusted+sources + * Returns: + * NULL file not found + * !=NULL mem.malloc'd file name + */ + +char *FileName::safeSearchPath(Array *path, const char *name) +{ +#if _WIN32 + /* Disallow % / \ : and .. in name characters + */ + for (const char *p = name; *p; p++) + { + char c = *p; + if (c == '\\' || c == '/' || c == ':' || c == '%' || + (c == '.' && p[1] == '.')) + { + return NULL; + } + } + + return FileName::searchPath(path, name, 0); +#elif POSIX + /* Even with realpath(), we must check for // and disallow it + */ + for (const char *p = name; *p; p++) + { + char c = *p; + if (c == '/' && p[1] == '/') + { + return NULL; + } + } + + if (path) + { unsigned i; + + /* Each path is converted to a cannonical name and then a check is done to see + * that the searched name is really a child one of the the paths searched. + */ + for (i = 0; i < path->dim; i++) + { + char *cname = NULL; + char *cpath = canonicalName((char *)path->data[i]); + //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", + // name, (char *)path->data[i], cpath); + if (cpath == NULL) + goto cont; + cname = canonicalName(combine(cpath, name)); + //printf("FileName::safeSearchPath(): cname=%s\n", cname); + if (cname == NULL) + goto cont; + //printf("FileName::safeSearchPath(): exists=%i " + // "strncmp(cpath, cname, %i)=%i\n", exists(cname), + // strlen(cpath), strncmp(cpath, cname, strlen(cpath))); + // exists and name is *really* a "child" of path + if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0) + { + free(cpath); + char *p = mem.strdup(cname); + free(cname); + return p; + } +cont: + if (cpath) + free(cpath); + if (cname) + free(cname); + } + } + return NULL; +#else + assert(0); +#endif +} + + +int FileName::exists(const char *name) +{ +#if POSIX + struct stat st; + + if (stat(name, &st) < 0) + return 0; + if (S_ISDIR(st.st_mode)) + return 2; + return 1; +#elif _WIN32 + DWORD dw; + int result; + + dw = GetFileAttributesA(name); + if (dw == -1L) + result = 0; + else if (dw & FILE_ATTRIBUTE_DIRECTORY) + result = 2; + else + result = 1; + return result; +#else + assert(0); +#endif +} + +void FileName::ensurePathExists(const char *path) +{ + //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); + if (path && *path) + { + if (!exists(path)) + { + char *p = FileName::path(path); + if (*p) + { +#if _WIN32 + size_t len = strlen(path); + if (len > 2 && p[-1] == ':' && path + 2 == p) + { mem.free(p); + return; + } +#endif + ensurePathExists(p); + mem.free(p); + } +#if _WIN32 + if (path[strlen(path) - 1] != '\\') +#endif +#if POSIX + if (path[strlen(path) - 1] != '\\') +#endif + { + //printf("mkdir(%s)\n", path); +#if _WIN32 + if (mkdir(path)) +#endif +#if POSIX + if (mkdir(path, 0777)) +#endif + { + /* Don't error out if another instance of dmd just created + * this directory + */ + if (errno != EEXIST) + error("cannot create directory %s", path); + } + } + } + } +} + + +/****************************************** + * Return canonical version of name in a malloc'd buffer. + * This code is high risk. + */ +char *FileName::canonicalName(const char *name) +{ +#if linux + // Lovely glibc extension to do it for us + return canonicalize_file_name(name); +#elif POSIX + #if _POSIX_VERSION >= 200809L || defined (linux) + // NULL destination buffer is allowed and preferred + return realpath(name, NULL); + #else + char *cname = NULL; + #if PATH_MAX + /* PATH_MAX must be defined as a constant in , + * otherwise using it is unsafe due to TOCTOU + */ + size_t path_max = (size_t)PATH_MAX; + if (path_max > 0) + { + /* Need to add one to PATH_MAX because of realpath() buffer overflow bug: + * http://isec.pl/vulnerabilities/isec-0011-wu-ftpd.txt + */ + cname = (char *)malloc(path_max + 1); + if (cname == NULL) + return NULL; + } + #endif + return realpath(name, cname); + #endif +#elif _WIN32 + /* Apparently, there is no good way to do this on Windows. + * GetFullPathName isn't it. + */ + assert(0); + return NULL; +#else + assert(0); + return NULL; +#endif +} + + +/****************************** File ********************************/ + +File::File(FileName *n) +{ + ref = 0; + buffer = NULL; + len = 0; + touchtime = NULL; + name = n; +} + +File::File(char *n) +{ + ref = 0; + buffer = NULL; + len = 0; + touchtime = NULL; + name = new FileName(n, 0); +} + +File::~File() +{ + if (buffer) + { + if (ref == 0) + mem.free(buffer); +#if _WIN32 + else if (ref == 2) + UnmapViewOfFile(buffer); +#endif + } + if (touchtime) + mem.free(touchtime); +} + +void File::mark() +{ + mem.mark(buffer); + mem.mark(touchtime); + mem.mark(name); +} + +/************************************* + */ + +int File::read() +{ +#if POSIX + off_t size; + ssize_t numread; + int fd; + struct stat buf; + int result = 0; + char *name; + + name = this->name->toChars(); + //printf("File::read('%s')\n",name); + fd = open(name, O_RDONLY); + if (fd == -1) + { result = errno; + //printf("\topen error, errno = %d\n",errno); + goto err1; + } + + if (!ref) + mem.free(buffer); + ref = 0; // we own the buffer now + + //printf("\tfile opened\n"); + if (fstat(fd, &buf)) + { + printf("\tfstat error, errno = %d\n",errno); + goto err2; + } + size = buf.st_size; + buffer = (unsigned char *) mem.malloc(size + 2); + if (!buffer) + { + printf("\tmalloc error, errno = %d\n",errno); + goto err2; + } + + numread = ::read(fd, buffer, size); + if (numread != size) + { + printf("\tread error, errno = %d\n",errno); + goto err2; + } + + if (touchtime) + memcpy(touchtime, &buf, sizeof(buf)); + + if (close(fd) == -1) + { + printf("\tclose error, errno = %d\n",errno); + goto err; + } + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + return 0; + +err2: + close(fd); +err: + mem.free(buffer); + buffer = NULL; + len = 0; + +err1: + result = 1; + return result; +#elif _WIN32 + DWORD size; + DWORD numread; + HANDLE h; + int result = 0; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); + if (h == INVALID_HANDLE_VALUE) + goto err1; + + if (!ref) + mem.free(buffer); + ref = 0; + + size = GetFileSize(h,NULL); + buffer = (unsigned char *) mem.malloc(size + 2); + if (!buffer) + goto err2; + + if (ReadFile(h,buffer,size,&numread,NULL) != TRUE) + goto err2; + + if (numread != size) + goto err2; + + if (touchtime) + { + if (!GetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime)) + goto err2; + } + + if (!CloseHandle(h)) + goto err; + + len = size; + + // Always store a wchar ^Z past end of buffer so scanner has a sentinel + buffer[size] = 0; // ^Z is obsolete, use 0 + buffer[size + 1] = 0; + return 0; + +err2: + CloseHandle(h); +err: + mem.free(buffer); + buffer = NULL; + len = 0; + +err1: + result = 1; + return result; +#else + assert(0); +#endif +} + +/***************************** + * Read a file with memory mapped file I/O. + */ + +int File::mmread() +{ +#if POSIX + return read(); +#elif _WIN32 + HANDLE hFile; + HANDLE hFileMap; + DWORD size; + char *name; + + name = this->name->toChars(); + hFile = CreateFile(name, GENERIC_READ, + FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto Lerr; + size = GetFileSize(hFile, NULL); + //printf(" file created, size %d\n", size); + + hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); + if (CloseHandle(hFile) != TRUE) + goto Lerr; + + if (hFileMap == NULL) + goto Lerr; + + //printf(" mapping created\n"); + + if (!ref) + mem.free(buffer); + ref = 2; + buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); + if (CloseHandle(hFileMap) != TRUE) + goto Lerr; + if (buffer == NULL) // mapping view failed + goto Lerr; + + len = size; + //printf(" buffer = %p\n", buffer); + + return 0; + +Lerr: + return GetLastError(); // failure +#else + assert(0); +#endif +} + +/********************************************* + * Write a file. + * Returns: + * 0 success + */ + +int File::write() +{ +#if POSIX + int fd; + ssize_t numwritten; + char *name; + + name = this->name->toChars(); + fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); + if (fd == -1) + goto err; + + numwritten = ::write(fd, buffer, len); + if (len != numwritten) + goto err2; + + if (close(fd) == -1) + goto err; + + if (touchtime) + { struct utimbuf ubuf; + + ubuf.actime = ((struct stat *)touchtime)->st_atime; + ubuf.modtime = ((struct stat *)touchtime)->st_mtime; + if (utime(name, &ubuf)) + goto err; + } + return 0; + +err2: + close(fd); + ::remove(name); +err: + return 1; +#elif _WIN32 + HANDLE h; + DWORD numwritten; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (h == INVALID_HANDLE_VALUE) + goto err; + + if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) + goto err2; + + if (len != numwritten) + goto err2; + + if (touchtime) { + SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); + } + if (!CloseHandle(h)) + goto err; + return 0; + +err2: + CloseHandle(h); + DeleteFileA(name); +err: + return 1; +#else + assert(0); +#endif +} + +/********************************************* + * Append to a file. + * Returns: + * 0 success + */ + +int File::append() +{ +#if POSIX + return 1; +#elif _WIN32 + HANDLE h; + DWORD numwritten; + char *name; + + name = this->name->toChars(); + h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (h == INVALID_HANDLE_VALUE) + goto err; + +#if 1 + SetFilePointer(h, 0, NULL, FILE_END); +#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition + if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) + goto err; +#endif + + if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) + goto err2; + + if (len != numwritten) + goto err2; + + if (touchtime) { + SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); + } + if (!CloseHandle(h)) + goto err; + return 0; + +err2: + CloseHandle(h); +err: + return 1; +#else + assert(0); +#endif +} + +/************************************** + */ + +void File::readv() +{ + if (read()) + error("Error reading file '%s'\n",name->toChars()); +} + +/************************************** + */ + +void File::mmreadv() +{ + if (mmread()) + readv(); +} + +void File::writev() +{ + if (write()) + error("Error writing file '%s'\n",name->toChars()); +} + +void File::appendv() +{ + if (write()) + error("Error appending to file '%s'\n",name->toChars()); +} + +/******************************************* + * Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + +int File::exists() +{ +#if POSIX + return 0; +#elif _WIN32 + DWORD dw; + int result; + char *name; + + name = this->name->toChars(); + if (touchtime) + dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; + else + dw = GetFileAttributesA(name); + if (dw == -1L) + result = 0; + else if (dw & FILE_ATTRIBUTE_DIRECTORY) + result = 2; + else + result = 1; + return result; +#else + assert(0); +#endif +} + +void File::remove() +{ +#if POSIX + ::remove(this->name->toChars()); +#elif _WIN32 + DeleteFileA(this->name->toChars()); +#else + assert(0); +#endif +} + +Array *File::match(char *n) +{ + return match(new FileName(n, 0)); +} + +Array *File::match(FileName *n) +{ +#if POSIX + return NULL; +#elif _WIN32 + HANDLE h; + WIN32_FIND_DATAA fileinfo; + Array *a; + char *c; + char *name; + + a = new Array(); + c = n->toChars(); + name = n->name(); + h = FindFirstFileA(c,&fileinfo); + if (h != INVALID_HANDLE_VALUE) + { + do + { + // Glue path together with name + char *fn; + File *f; + + fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); + memcpy(fn, c, name - c); + strcpy(fn + (name - c), fileinfo.cFileName); + f = new File(fn); + f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); + memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); + a->push(f); + } while (FindNextFileA(h,&fileinfo) != FALSE); + FindClose(h); + } + return a; +#else + assert(0); +#endif +} + +int File::compareTime(File *f) +{ +#if POSIX + return 0; +#elif _WIN32 + if (!touchtime) + stat(); + if (!f->touchtime) + f->stat(); + return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); +#else + assert(0); +#endif +} + +void File::stat() +{ +#if POSIX + if (!touchtime) + { + touchtime = mem.calloc(1, sizeof(struct stat)); + } +#elif _WIN32 + HANDLE h; + + if (!touchtime) + { + touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); + } + h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); + if (h != INVALID_HANDLE_VALUE) + { + FindClose(h); + } +#else + assert(0); +#endif +} + +void File::checkoffset(size_t offset, size_t nbytes) +{ + if (offset > len || offset + nbytes > len) + error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset); +} + +char *File::toChars() +{ + return name->toChars(); +} + + +/************************* OutBuffer *************************/ + +OutBuffer::OutBuffer() +{ + data = NULL; + offset = 0; + size = 0; +} + +OutBuffer::~OutBuffer() +{ + mem.free(data); +} + +void *OutBuffer::extractData() +{ + void *p; + + p = (void *)data; + data = NULL; + offset = 0; + size = 0; + return p; +} + +void OutBuffer::mark() +{ + mem.mark(data); +} + +void OutBuffer::reserve(unsigned nbytes) +{ + //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); + if (size - offset < nbytes) + { + size = (offset + nbytes) * 2; + data = (unsigned char *)mem.realloc(data, size); + } +} + +void OutBuffer::reset() +{ + offset = 0; +} + +void OutBuffer::setsize(unsigned size) +{ + offset = size; +} + +void OutBuffer::write(const void *data, unsigned nbytes) +{ + reserve(nbytes); + memcpy(this->data + offset, data, nbytes); + offset += nbytes; +} + +void OutBuffer::writebstring(unsigned char *string) +{ + write(string,*string + 1); +} + +void OutBuffer::writestring(const char *string) +{ + write(string,strlen(string)); +} + +void OutBuffer::writedstring(const char *string) +{ +#if M_UNICODE + for (; *string; string++) + { + writedchar(*string); + } +#else + write(string,strlen(string)); +#endif +} + +void OutBuffer::writedstring(const wchar_t *string) +{ +#if M_UNICODE + write(string,wcslen(string) * sizeof(wchar_t)); +#else + for (; *string; string++) + { + writedchar(*string); + } +#endif +} + +void OutBuffer::prependstring(const char *string) +{ unsigned len; + + len = strlen(string); + reserve(len); + memmove(data + len, data, offset); + memcpy(data, string, len); + offset += len; +} + +void OutBuffer::writenl() +{ +#if _WIN32 +#if M_UNICODE + write4(0x000A000D); // newline is CR,LF on Microsoft OS's +#else + writeword(0x0A0D); // newline is CR,LF on Microsoft OS's +#endif +#else +#if M_UNICODE + writeword('\n'); +#else + writeByte('\n'); +#endif +#endif +} + +void OutBuffer::writeByte(unsigned b) +{ + reserve(1); + this->data[offset] = (unsigned char)b; + offset++; +} + +void OutBuffer::writeUTF8(unsigned b) +{ + reserve(6); + if (b <= 0x7F) + { + this->data[offset] = (unsigned char)b; + offset++; + } + else if (b <= 0x7FF) + { + this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); + this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); + offset += 2; + } + else if (b <= 0xFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); + this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); + offset += 3; + } + else if (b <= 0x1FFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); + this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); + offset += 4; + } + else if (b <= 0x3FFFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); + this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); + offset += 5; + } + else if (b <= 0x7FFFFFFF) + { + this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); + this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); + this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); + this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); + this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); + this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); + offset += 6; + } + else + assert(0); +} + +void OutBuffer::writedchar(unsigned b) +{ + reserve(Dchar_mbmax * sizeof(dchar)); + offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - + this->data; +} + +void OutBuffer::prependbyte(unsigned b) +{ + reserve(1); + memmove(data + 1, data, offset); + data[0] = (unsigned char)b; + offset++; +} + +void OutBuffer::writeword(unsigned w) +{ + reserve(2); + *(unsigned short *)(this->data + offset) = (unsigned short)w; + offset += 2; +} + +void OutBuffer::writeUTF16(unsigned w) +{ + reserve(4); + if (w <= 0xFFFF) + { + *(unsigned short *)(this->data + offset) = (unsigned short)w; + offset += 2; + } + else if (w <= 0x10FFFF) + { + *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); + *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); + offset += 4; + } + else + assert(0); +} + +void OutBuffer::write4(unsigned w) +{ + reserve(4); + *(unsigned *)(this->data + offset) = w; + offset += 4; +} + +void OutBuffer::write(OutBuffer *buf) +{ + if (buf) + { reserve(buf->offset); + memcpy(data + offset, buf->data, buf->offset); + offset += buf->offset; + } +} + +void OutBuffer::write(Object *obj) +{ + if (obj) + { + writestring(obj->toChars()); + } +} + +void OutBuffer::fill0(unsigned nbytes) +{ + reserve(nbytes); + memset(data + offset,0,nbytes); + offset += nbytes; +} + +void OutBuffer::align(unsigned size) +{ unsigned nbytes; + + nbytes = ((offset + size - 1) & ~(size - 1)) - offset; + fill0(nbytes); +} + + +//////////////////////////////////////////////////////////////// +// The compiler shipped with Visual Studio 2005 (and possible +// other versions) does not support C99 printf format specfiers +// such as %z and %j +#if _MSC_VER +using std::string; +using std::wstring; + +template +inline void +search_and_replace(S& str, const S& what, const S& replacement) +{ + assert(!what.empty()); + size_t pos = str.find(what); + while (pos != S::npos) + { + str.replace(pos, what.size(), replacement); + pos = str.find(what, pos + replacement.size()); + } +} +#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \ + S tmp = f; \ + search_and_replace(fmt, S("%z"), S("%l")); \ + search_and_replace(fmt, S("%j"), S("%i")); \ + f = tmp.c_str(); +#else +#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) +#endif + +void OutBuffer::vprintf(const char *format, va_list args) +{ + char buffer[128]; + char *p; + unsigned psize; + int count; + + WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format); + + p = buffer; + psize = sizeof(buffer); + for (;;) + { +#if _WIN32 + count = _vsnprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#elif POSIX + va_list va; + va_copy(va, args); +/* + The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() + are equivalent to the functions printf(), fprintf(), sprintf(), + snprintf(), respectively, except that they are called with a + va_list instead of a variable number of arguments. These + functions do not call the va_end macro. Consequently, the value + of ap is undefined after the call. The application should call + va_end(ap) itself afterwards. + */ + count = vsnprintf(p,psize,format,va); + va_end(va); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#else + assert(0); +#endif + p = (char *) alloca(psize); // buffer too small, try again with larger size + } + write(p,count); +} + +#if M_UNICODE +void OutBuffer::vprintf(const wchar_t *format, va_list args) +{ + dchar buffer[128]; + dchar *p; + unsigned psize; + int count; + + WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format); + + p = buffer; + psize = sizeof(buffer) / sizeof(buffer[0]); + for (;;) + { +#if _WIN32 + count = _vsnwprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#elif POSIX + va_list va; + va_copy(va, args); + count = vsnwprintf(p,psize,format,va); + va_end(va); + + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#else + assert(0); +#endif + p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size + } + write(p,count * 2); +} +#endif + +void OutBuffer::printf(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format,ap); + va_end(ap); +} + +#if M_UNICODE +void OutBuffer::printf(const wchar_t *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format,ap); + va_end(ap); +} +#endif + +void OutBuffer::bracket(char left, char right) +{ + reserve(2); + memmove(data + 1, data, offset); + data[0] = left; + data[offset + 1] = right; + offset += 2; +} + +/****************** + * Insert left at i, and right at j. + * Return index just past right. + */ + +unsigned OutBuffer::bracket(unsigned i, const char *left, unsigned j, const char *right) +{ + size_t leftlen = strlen(left); + size_t rightlen = strlen(right); + reserve(leftlen + rightlen); + insert(i, left, leftlen); + insert(j + leftlen, right, rightlen); + return j + leftlen + rightlen; +} + +void OutBuffer::spread(unsigned offset, unsigned nbytes) +{ + reserve(nbytes); + memmove(data + offset + nbytes, data + offset, + this->offset - offset); + this->offset += nbytes; +} + +/**************************************** + * Returns: offset + nbytes + */ + +unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) +{ + spread(offset, nbytes); + memmove(data + offset, p, nbytes); + return offset + nbytes; +} + +void OutBuffer::remove(unsigned offset, unsigned nbytes) +{ + memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); + this->offset -= nbytes; +} + +char *OutBuffer::toChars() +{ + writeByte(0); + return (char *)data; +} + +/********************************* Bits ****************************/ + +Bits::Bits() +{ + data = NULL; + bitdim = 0; + allocdim = 0; +} + +Bits::~Bits() +{ + mem.free(data); +} + +void Bits::mark() +{ + mem.mark(data); +} + +void Bits::resize(unsigned bitdim) +{ + unsigned allocdim; + unsigned mask; + + allocdim = (bitdim + 31) / 32; + data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); + if (this->allocdim < allocdim) + memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); + + // Clear other bits in last word + mask = (1 << (bitdim & 31)) - 1; + if (mask) + data[allocdim - 1] &= ~mask; + + this->bitdim = bitdim; + this->allocdim = allocdim; +} + +void Bits::set(unsigned bitnum) +{ + data[bitnum / 32] |= 1 << (bitnum & 31); +} + +void Bits::clear(unsigned bitnum) +{ + data[bitnum / 32] &= ~(1 << (bitnum & 31)); +} + +int Bits::test(unsigned bitnum) +{ + return data[bitnum / 32] & (1 << (bitnum & 31)); +} + +void Bits::set() +{ unsigned mask; + + memset(data, ~0, allocdim * sizeof(data[0])); + + // Clear other bits in last word + mask = (1 << (bitdim & 31)) - 1; + if (mask) + data[allocdim - 1] &= mask; +} + +void Bits::clear() +{ + memset(data, 0, allocdim * sizeof(data[0])); +} + +void Bits::copy(Bits *from) +{ + assert(bitdim == from->bitdim); + memcpy(data, from->data, allocdim * sizeof(data[0])); +} + +Bits *Bits::clone() +{ + Bits *b; + + b = new Bits(); + b->resize(bitdim); + b->copy(this); + return b; +} + +void Bits::sub(Bits *b) +{ + unsigned u; + + for (u = 0; u < allocdim; u++) + data[u] &= ~b->data[u]; +} + + + + + + + + + + + + + + + diff --git a/dmd2/root/root.h b/dmd2/root/root.h index 1479b38f..a0b34cea 100644 --- a/dmd2/root/root.h +++ b/dmd2/root/root.h @@ -1,359 +1,367 @@ - - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// 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. - -#ifndef ROOT_H -#define ROOT_H - -#include -#include - -#if __DMC__ -#pragma once -#endif - -typedef size_t hash_t; - -#include "dchar.h" - -char *wchar2ascii(wchar_t *); -int wcharIsAscii(wchar_t *); -char *wchar2ascii(wchar_t *, unsigned len); -int wcharIsAscii(wchar_t *, unsigned len); - -int bstrcmp(unsigned char *s1, unsigned char *s2); -char *bstr2str(unsigned char *b); -void error(const char *format, ...); -void error(const wchar_t *format, ...); -void warning(const char *format, ...); - -#ifndef TYPEDEFS -#define TYPEDEFS - -#if _MSC_VER -#include // for _isnan -#include // for alloca -// According to VC 8.0 docs, long double is the same as double -#define strtold strtod -#define strtof strtod -#define isnan _isnan - -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -longlong randomx(); - -/* - * Root of our class library. - */ - -struct OutBuffer; -struct Array; - -struct Object -{ - Object() { } - virtual ~Object() { } - - virtual int equals(Object *o); - - /** - * Returns a hash code, useful for things like building hash tables of Objects. - */ - virtual hash_t hashCode(); - - /** - * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. - * Useful for sorting Objects. - */ - virtual int compare(Object *obj); - - /** - * Pretty-print an Object. Useful for debugging the old-fashioned way. - */ - virtual void print(); - - virtual char *toChars(); - virtual dchar *toDchars(); - virtual void toBuffer(OutBuffer *buf); - - /** - * Used as a replacement for dynamic_cast. Returns a unique number - * defined by the library user. For Object, the return value is 0. - */ - virtual int dyncast(); - - /** - * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap. - */ - /*virtual*/ // not used, disable for now - void mark(); -}; - -struct String : Object -{ - int ref; // != 0 if this is a reference to someone else's string - char *str; // the string itself - - String(char *str, int ref = 1); - - ~String(); - - static hash_t calcHash(const char *str, size_t len); - static hash_t calcHash(const char *str); - hash_t hashCode(); - unsigned len(); - int equals(Object *obj); - int compare(Object *obj); - char *toChars(); - void print(); - void mark(); -}; - -struct FileName : String -{ - FileName(char *str, int ref); - FileName(char *path, char *name); - hash_t hashCode(); - int equals(Object *obj); - static int equals(const char *name1, const char *name2); - int compare(Object *obj); - static int compare(const char *name1, const char *name2); - static int absolute(const char *name); - static char *ext(const char *); - char *ext(); - static char *removeExt(const char *str); - static char *name(const char *); - char *name(); - static char *path(const char *); - static const char *replaceName(const char *path, const char *name); - - static char *combine(const char *path, const char *name); - static Array *splitPath(const char *path); - static FileName *defaultExt(const char *name, const char *ext); - static FileName *forceExt(const char *name, const char *ext); - int equalsExt(const char *ext); - - void CopyTo(FileName *to); - static char *searchPath(Array *path, const char *name, int cwd); - static int exists(const char *name); - static void ensurePathExists(const char *path); -}; - -struct File : Object -{ - int ref; // != 0 if this is a reference to someone else's buffer - unsigned char *buffer; // data for our file - unsigned len; // amount of data in buffer[] - void *touchtime; // system time to use for file - - FileName *name; // name of our file - - File(char *); - File(FileName *); - ~File(); - - void mark(); - - char *toChars(); - - /* Read file, return !=0 if error - */ - - int read(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void readv(); - - /* Read file, return !=0 if error - */ - - int mmread(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void mmreadv(); - - /* Write file, return !=0 if error - */ - - int write(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void writev(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - /* Append to file, return !=0 if error - */ - - int append(); - - /* Append to file, either succeed or fail - * with error message & exit. - */ - - void appendv(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - int exists(); - - /* Given wildcard filespec, return an array of - * matching File's. - */ - - static Array *match(char *); - static Array *match(FileName *); - - // Compare file times. - // Return <0 this < f - // =0 this == f - // >0 this > f - int compareTime(File *f); - - // Read system file statistics - void stat(); - - /* Set buffer - */ - - void setbuffer(void *buffer, unsigned len) - { - this->buffer = (unsigned char *)buffer; - this->len = len; - } - - void checkoffset(size_t offset, size_t nbytes); - - void remove(); // delete file -}; - -struct OutBuffer : Object -{ - unsigned char *data; - unsigned offset; - unsigned size; - - OutBuffer(); - ~OutBuffer(); - void *extractData(); - void mark(); - - void reserve(unsigned nbytes); - void setsize(unsigned size); - void reset(); - void write(const void *data, unsigned nbytes); - void writebstring(unsigned char *string); - void writestring(const char *string); - void writedstring(const char *string); - void writedstring(const wchar_t *string); - void prependstring(const char *string); - void writenl(); // write newline - void writeByte(unsigned b); - void writebyte(unsigned b) { writeByte(b); } - void writeUTF8(unsigned b); - void writedchar(unsigned b); - void prependbyte(unsigned b); - void writeword(unsigned w); - void writeUTF16(unsigned w); - void write4(unsigned w); - void write(OutBuffer *buf); - void write(Object *obj); - void fill0(unsigned nbytes); - void align(unsigned size); - void vprintf(const char *format, va_list args); - void printf(const char *format, ...); -#if M_UNICODE - void vprintf(const unsigned short *format, va_list args); - void printf(const unsigned short *format, ...); -#endif - void bracket(char left, char right); - unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); - void spread(unsigned offset, unsigned nbytes); - unsigned insert(unsigned offset, const void *data, unsigned nbytes); - void remove(unsigned offset, unsigned nbytes); - char *toChars(); - char *extractString(); -}; - -struct Array : Object -{ - unsigned dim; - unsigned allocdim; - void **data; - - Array(); - ~Array(); - void mark(); - char *toChars(); - - void reserve(unsigned nentries); - void setDim(unsigned newdim); - void fixDim(); - void push(void *ptr); - void *pop(); - void shift(void *ptr); - void insert(unsigned index, void *ptr); - void insert(unsigned index, Array *a); - void append(Array *a); - void remove(unsigned i); - void zero(); - void *tos(); - void sort(); - Array *copy(); -}; - -struct Bits : Object -{ - unsigned bitdim; - unsigned allocdim; - unsigned *data; - - Bits(); - ~Bits(); - void mark(); - - void resize(unsigned bitdim); - - void set(unsigned bitnum); - void clear(unsigned bitnum); - int test(unsigned bitnum); - - void set(); - void clear(); - void copy(Bits *from); - Bits *clone(); - - void sub(Bits *b); -}; - -#endif + + +// Copyright (c) 1999-2010 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. + +#ifndef ROOT_H +#define ROOT_H + +#include +#include + +#if __DMC__ +#pragma once +#endif + +typedef size_t hash_t; + +#include "dchar.h" + +char *wchar2ascii(wchar_t *); +int wcharIsAscii(wchar_t *); +char *wchar2ascii(wchar_t *, unsigned len); +int wcharIsAscii(wchar_t *, unsigned len); + +int bstrcmp(unsigned char *s1, unsigned char *s2); +char *bstr2str(unsigned char *b); +void error(const char *format, ...); +void error(const wchar_t *format, ...); +void warning(const char *format, ...); + +#ifndef TYPEDEFS +#define TYPEDEFS + +#if _MSC_VER +#include // for _isnan +#include // for alloca +// According to VC 8.0 docs, long double is the same as double +#define strtold strtod +#define strtof strtod +#define isnan _isnan + +typedef __int64 longlong; +typedef unsigned __int64 ulonglong; +#else +typedef long long longlong; +typedef unsigned long long ulonglong; +#endif + +#endif + +longlong randomx(); + +/* + * Root of our class library. + */ + +struct OutBuffer; +struct Array; + +struct Object +{ + Object() { } + virtual ~Object() { } + + virtual int equals(Object *o); + + /** + * Returns a hash code, useful for things like building hash tables of Objects. + */ + virtual hash_t hashCode(); + + /** + * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. + * Useful for sorting Objects. + */ + virtual int compare(Object *obj); + + /** + * Pretty-print an Object. Useful for debugging the old-fashioned way. + */ + virtual void print(); + + virtual char *toChars(); + virtual dchar *toDchars(); + virtual void toBuffer(OutBuffer *buf); + + /** + * Used as a replacement for dynamic_cast. Returns a unique number + * defined by the library user. For Object, the return value is 0. + */ + virtual int dyncast(); + + /** + * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap. + */ + /*virtual*/ // not used, disable for now + void mark(); +}; + +struct String : Object +{ + int ref; // != 0 if this is a reference to someone else's string + char *str; // the string itself + + String(char *str, int ref = 1); + + ~String(); + + static hash_t calcHash(const char *str, size_t len); + static hash_t calcHash(const char *str); + hash_t hashCode(); + unsigned len(); + int equals(Object *obj); + int compare(Object *obj); + char *toChars(); + void print(); + void mark(); +}; + +struct FileName : String +{ + FileName(char *str, int ref); + FileName(char *path, char *name); + hash_t hashCode(); + int equals(Object *obj); + static int equals(const char *name1, const char *name2); + int compare(Object *obj); + static int compare(const char *name1, const char *name2); + static int absolute(const char *name); + static char *ext(const char *); + char *ext(); + static char *removeExt(const char *str); + static char *name(const char *); + char *name(); + static char *path(const char *); + static const char *replaceName(const char *path, const char *name); + + static char *combine(const char *path, const char *name); + static Array *splitPath(const char *path); + static FileName *defaultExt(const char *name, const char *ext); + static FileName *forceExt(const char *name, const char *ext); + int equalsExt(const char *ext); + + void CopyTo(FileName *to); + static char *searchPath(Array *path, const char *name, int cwd); + static char *safeSearchPath(Array *path, const char *name); + static int exists(const char *name); + static void ensurePathExists(const char *path); + static char *canonicalName(const char *name); +}; + +struct File : Object +{ + int ref; // != 0 if this is a reference to someone else's buffer + unsigned char *buffer; // data for our file + unsigned len; // amount of data in buffer[] + void *touchtime; // system time to use for file + + FileName *name; // name of our file + + File(char *); + File(FileName *); + ~File(); + + void mark(); + + char *toChars(); + + /* Read file, return !=0 if error + */ + + int read(); + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void readv(); + + /* Read file, return !=0 if error + */ + + int mmread(); + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void mmreadv(); + + /* Write file, return !=0 if error + */ + + int write(); + + /* Write file, either succeed or fail + * with error message & exit. + */ + + void writev(); + + /* Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + + /* Append to file, return !=0 if error + */ + + int append(); + + /* Append to file, either succeed or fail + * with error message & exit. + */ + + void appendv(); + + /* Return !=0 if file exists. + * 0: file doesn't exist + * 1: normal file + * 2: directory + */ + + int exists(); + + /* Given wildcard filespec, return an array of + * matching File's. + */ + + static Array *match(char *); + static Array *match(FileName *); + + // Compare file times. + // Return <0 this < f + // =0 this == f + // >0 this > f + int compareTime(File *f); + + // Read system file statistics + void stat(); + + /* Set buffer + */ + + void setbuffer(void *buffer, unsigned len) + { + this->buffer = (unsigned char *)buffer; + this->len = len; + } + + void checkoffset(size_t offset, size_t nbytes); + + void remove(); // delete file +}; + +struct OutBuffer : Object +{ + unsigned char *data; + unsigned offset; + unsigned size; + + OutBuffer(); + ~OutBuffer(); + void *extractData(); + void mark(); + + void reserve(unsigned nbytes); + void setsize(unsigned size); + void reset(); + void write(const void *data, unsigned nbytes); + void writebstring(unsigned char *string); + void writestring(const char *string); + void writedstring(const char *string); + void writedstring(const wchar_t *string); + void prependstring(const char *string); + void writenl(); // write newline + void writeByte(unsigned b); + void writebyte(unsigned b) { writeByte(b); } + void writeUTF8(unsigned b); + void writedchar(unsigned b); + void prependbyte(unsigned b); + void writeword(unsigned w); + void writeUTF16(unsigned w); + void write4(unsigned w); + void write(OutBuffer *buf); + void write(Object *obj); + void fill0(unsigned nbytes); + void align(unsigned size); + void vprintf(const char *format, va_list args); + void printf(const char *format, ...); +#if M_UNICODE + void vprintf(const unsigned short *format, va_list args); + void printf(const unsigned short *format, ...); +#endif + void bracket(char left, char right); + unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); + void spread(unsigned offset, unsigned nbytes); + unsigned insert(unsigned offset, const void *data, unsigned nbytes); + void remove(unsigned offset, unsigned nbytes); + char *toChars(); + char *extractString(); +}; + +struct Array : Object +{ + unsigned dim; + void **data; + + private: + unsigned allocdim; + #define SMALLARRAYCAP 1 + void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays + + public: + Array(); + ~Array(); + //Array(const Array&); + void mark(); + char *toChars(); + + void reserve(unsigned nentries); + void setDim(unsigned newdim); + void fixDim(); + void push(void *ptr); + void *pop(); + void shift(void *ptr); + void insert(unsigned index, void *ptr); + void insert(unsigned index, Array *a); + void append(Array *a); + void remove(unsigned i); + void zero(); + void *tos(); + void sort(); + Array *copy(); +}; + +struct Bits : Object +{ + unsigned bitdim; + unsigned allocdim; + unsigned *data; + + Bits(); + ~Bits(); + void mark(); + + void resize(unsigned bitdim); + + void set(unsigned bitnum); + void clear(unsigned bitnum); + int test(unsigned bitnum); + + void set(); + void clear(); + void copy(Bits *from); + Bits *clone(); + + void sub(Bits *b); +}; + +#endif diff --git a/dmd2/root/speller.c b/dmd2/root/speller.c new file mode 100644 index 00000000..5ea67db8 --- /dev/null +++ b/dmd2/root/speller.c @@ -0,0 +1,253 @@ + +#include +#include +#include +#include + +#include "speller.h" + +const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; + +/************************************************** + * Looks for correct spelling. + * Currently only looks a 'distance' of one from the seed[]. + * This does an exhaustive search, so can potentially be very slow. + * Input: + * seed wrongly spelled word + * fp search function + * fparg argument to search function + * charset character set + * Returns: + * NULL no correct spellings found + * void* value returned by fp() for first possible correct spelling + */ + +void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, + const char *charset, size_t index) +{ + if (!seedlen) + return NULL; + assert(seed[seedlen] == 0); + + char tmp[30]; + char *buf; + if (seedlen <= sizeof(tmp) - 2) + buf = tmp; + else + { + buf = (char *)alloca(seedlen + 2); // leave space for extra char + if (!buf) + return NULL; // no matches + } + + memcpy(buf, seed, index); + + /* Delete at seed[index] */ + if (index < seedlen) + { + memcpy(buf + index, seed + index + 1, seedlen - index); + assert(buf[seedlen - 1] == 0); + void *p = (*fp)(fparg, buf); + if (p) + return p; + } + + if (charset && *charset) + { + /* Substitutions */ + if (index < seedlen) + { + memcpy(buf, seed, seedlen + 1); + for (const char *s = charset; *s; s++) + { + buf[index] = *s; + + //printf("sub buf = '%s'\n", buf); + void *p = (*fp)(fparg, buf); + if (p) + return p; + } + assert(buf[seedlen] == 0); + } + + /* Insertions */ + memcpy (buf + index + 1, seed + index, seedlen + 1 - index); + + for (const char *s = charset; *s; s++) + { + buf[index] = *s; + + //printf("ins buf = '%s'\n", buf); + void *p = (*fp)(fparg, buf); + if (p) + return p; + } + assert(buf[seedlen + 1] == 0); + } + + return NULL; // didn't find any corrections +} + +void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, + const char *charset, int flag) +{ + if (!seedlen) + return NULL; + + char tmp[30]; + char *buf; + if (seedlen <= sizeof(tmp) - 2) + buf = tmp; + else + { + buf = (char *)alloca(seedlen + 2); // leave space for extra char + if (!buf) + return NULL; // no matches + } + + /* Deletions */ + memcpy(buf, seed + 1, seedlen); + for (int i = 0; i < seedlen; i++) + { + //printf("del buf = '%s'\n", buf); + void *p; + if (flag) + p = spellerY(buf, seedlen - 1, fp, fparg, charset, i); + else + p = (*fp)(fparg, buf); + if (p) + return p; + + buf[i] = seed[i]; + } + + /* Transpositions */ + if (!flag) + { + memcpy(buf, seed, seedlen + 1); + for (int i = 0; i + 1 < seedlen; i++) + { + // swap [i] and [i + 1] + buf[i] = seed[i + 1]; + buf[i + 1] = seed[i]; + + //printf("tra buf = '%s'\n", buf); + void *p = (*fp)(fparg, buf); + if (p) + return p; + + buf[i] = seed[i]; + } + } + + if (charset && *charset) + { + /* Substitutions */ + memcpy(buf, seed, seedlen + 1); + for (int i = 0; i < seedlen; i++) + { + for (const char *s = charset; *s; s++) + { + buf[i] = *s; + + //printf("sub buf = '%s'\n", buf); + void *p; + if (flag) + p = spellerY(buf, seedlen, fp, fparg, charset, i + 1); + else + p = (*fp)(fparg, buf); + if (p) + return p; + } + buf[i] = seed[i]; + } + + /* Insertions */ + memcpy(buf + 1, seed, seedlen + 1); + for (int i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations + { + for (const char *s = charset; *s; s++) + { + buf[i] = *s; + + //printf("ins buf = '%s'\n", buf); + void *p; + if (flag) + p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1); + else + p = (*fp)(fparg, buf); + if (p) + return p; + } + buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0 + } + } + + return NULL; // didn't find any corrections +} + +void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset) +{ + size_t seedlen = strlen(seed); + for (int distance = 0; distance < 2; distance++) + { void *p = spellerX(seed, seedlen, fp, fparg, charset, distance); + if (p) + return p; +// if (seedlen > 10) +// break; + } + return NULL; // didn't find it +} + + +#if UNITTEST + +#include +#include +#include + +void *speller_test(void *fparg, const char *s) +{ + //printf("speller_test(%s, %s)\n", fparg, s); + if (strcmp((char *)fparg, s) == 0) + return fparg; + return NULL; +} + +void unittest_speller() +{ + static const char *cases[][3] = + { + { "hello", "hell", "y" }, + { "hello", "hel", "y" }, + { "hello", "ello", "y" }, + { "hello", "llo", "y" }, + { "hello", "hellox", "y" }, + { "hello", "helloxy", "y" }, + { "hello", "xhello", "y" }, + { "hello", "xyhello", "y" }, + { "hello", "ehllo", "y" }, + { "hello", "helol", "y" }, + { "hello", "abcd", "n" }, + //{ "ehllo", "helol", "y" }, + { "hello", "helxxlo", "y" }, + { "hello", "ehlxxlo", "n" }, + { "hello", "heaao", "y" }, + { "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" }, + }; + //printf("unittest_speller()\n"); + const void *p = speller("hello", &speller_test, (void *)"hell", idchars); + assert(p != NULL); + for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) + { + //printf("case [%d]\n", i); + void *p = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars); + if (p) + assert(cases[i][2][0] == 'y'); + else + assert(cases[i][2][0] == 'n'); + } + //printf("unittest_speller() success\n"); +} + +#endif diff --git a/dmd2/root/speller.h b/dmd2/root/speller.h new file mode 100644 index 00000000..bfffb739 --- /dev/null +++ b/dmd2/root/speller.h @@ -0,0 +1,7 @@ + +typedef void *(fp_speller_t)(void *, const char *); + +extern const char idchars[]; + +void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset); + diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c index 0bc63034..54fe78f6 100644 --- a/dmd2/root/stringtable.c +++ b/dmd2/root/stringtable.c @@ -1,139 +1,139 @@ - -// Copyright (c) 1999-2008 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 -#include -#include - -#include "root.h" -#include "rmem.h" -#include "dchar.h" -#include "lstring.h" -#include "stringtable.h" - -StringTable::StringTable(unsigned size) -{ - table = (void **)mem.calloc(size, sizeof(void *)); - tabledim = size; - count = 0; -} - -StringTable::~StringTable() -{ - unsigned i; - - // Zero out dangling pointers to help garbage collector. - // Should zero out StringEntry's too. - for (i = 0; i < count; i++) - table[i] = NULL; - - mem.free(table); - table = NULL; -} - -struct StringEntry -{ - StringEntry *left; - StringEntry *right; - hash_t hash; - - StringValue value; - - static StringEntry *alloc(const dchar *s, unsigned len); -}; - -StringEntry *StringEntry::alloc(const dchar *s, unsigned len) -{ - StringEntry *se; - - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len)); - se->value.lstring.length = len; - se->hash = Dchar::calcHash(s,len); - memcpy(se->value.lstring.string, s, len * sizeof(dchar)); - return se; -} - -void **StringTable::search(const dchar *s, unsigned len) -{ - hash_t hash; - unsigned u; - int cmp; - StringEntry **se; - - //printf("StringTable::search(%p,%d)\n",s,len); - hash = Dchar::calcHash(s,len); - u = hash % tabledim; - se = (StringEntry **)&table[u]; - //printf("\thash = %d, u = %d\n",hash,u); - while (*se) - { - cmp = (*se)->hash - hash; - if (cmp == 0) - { - cmp = (*se)->value.lstring.len() - len; - if (cmp == 0) - { - cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len); - if (cmp == 0) - break; - } - } - if (cmp < 0) - se = &(*se)->left; - else - se = &(*se)->right; - } - //printf("\treturn %p, %p\n",se, (*se)); - return (void **)se; -} - -StringValue *StringTable::lookup(const dchar *s, unsigned len) -{ StringEntry *se; - - se = *(StringEntry **)search(s,len); - if (se) - return &se->value; - else - return NULL; -} - -StringValue *StringTable::update(const dchar *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (!se) // not in table: so create new entry - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} - -StringValue *StringTable::insert(const dchar *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (se) - return NULL; // error: already in table - else - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} - - - - + +// Copyright (c) 1999-2008 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 +#include +#include + +#include "root.h" +#include "rmem.h" +#include "dchar.h" +#include "lstring.h" +#include "stringtable.h" + +StringTable::StringTable(unsigned size) +{ + table = (void **)mem.calloc(size, sizeof(void *)); + tabledim = size; + count = 0; +} + +StringTable::~StringTable() +{ + unsigned i; + + // Zero out dangling pointers to help garbage collector. + // Should zero out StringEntry's too. + for (i = 0; i < count; i++) + table[i] = NULL; + + mem.free(table); + table = NULL; +} + +struct StringEntry +{ + StringEntry *left; + StringEntry *right; + hash_t hash; + + StringValue value; + + static StringEntry *alloc(const dchar *s, unsigned len); +}; + +StringEntry *StringEntry::alloc(const dchar *s, unsigned len) +{ + StringEntry *se; + + se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len)); + se->value.lstring.length = len; + se->hash = Dchar::calcHash(s,len); + memcpy(se->value.lstring.string, s, len * sizeof(dchar)); + return se; +} + +void **StringTable::search(const dchar *s, unsigned len) +{ + hash_t hash; + unsigned u; + int cmp; + StringEntry **se; + + //printf("StringTable::search(%p,%d)\n",s,len); + hash = Dchar::calcHash(s,len); + u = hash % tabledim; + se = (StringEntry **)&table[u]; + //printf("\thash = %d, u = %d\n",hash,u); + while (*se) + { + cmp = (*se)->hash - hash; + if (cmp == 0) + { + cmp = (*se)->value.lstring.len() - len; + if (cmp == 0) + { + cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len); + if (cmp == 0) + break; + } + } + if (cmp < 0) + se = &(*se)->left; + else + se = &(*se)->right; + } + //printf("\treturn %p, %p\n",se, (*se)); + return (void **)se; +} + +StringValue *StringTable::lookup(const dchar *s, unsigned len) +{ StringEntry *se; + + se = *(StringEntry **)search(s,len); + if (se) + return &se->value; + else + return NULL; +} + +StringValue *StringTable::update(const dchar *s, unsigned len) +{ StringEntry **pse; + StringEntry *se; + + pse = (StringEntry **)search(s,len); + se = *pse; + if (!se) // not in table: so create new entry + { + se = StringEntry::alloc(s, len); + *pse = se; + } + return &se->value; +} + +StringValue *StringTable::insert(const dchar *s, unsigned len) +{ StringEntry **pse; + StringEntry *se; + + pse = (StringEntry **)search(s,len); + se = *pse; + if (se) + return NULL; // error: already in table + else + { + se = StringEntry::alloc(s, len); + *pse = se; + } + return &se->value; +} + + + + diff --git a/dmd2/root/stringtable.h b/dmd2/root/stringtable.h index 51e59f83..f81b1914 100644 --- a/dmd2/root/stringtable.h +++ b/dmd2/root/stringtable.h @@ -1,48 +1,48 @@ -// Copyright (c) 1999-2008 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. - - -#ifndef STRINGTABLE_H -#define STRINGTABLE_H - -#if __SC__ -#pragma once -#endif - -#include "root.h" -#include "dchar.h" -#include "lstring.h" - -struct StringValue -{ - union - { int intvalue; - void *ptrvalue; - dchar *string; - }; - Lstring lstring; -}; - -struct StringTable : Object -{ - void **table; - unsigned count; - unsigned tabledim; - - StringTable(unsigned size = 37); - ~StringTable(); - - StringValue *lookup(const dchar *s, unsigned len); - StringValue *insert(const dchar *s, unsigned len); - StringValue *update(const dchar *s, unsigned len); - -private: - void **search(const dchar *s, unsigned len); -}; - -#endif +// Copyright (c) 1999-2008 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. + + +#ifndef STRINGTABLE_H +#define STRINGTABLE_H + +#if __SC__ +#pragma once +#endif + +#include "root.h" +#include "dchar.h" +#include "lstring.h" + +struct StringValue +{ + union + { int intvalue; + void *ptrvalue; + dchar *string; + }; + Lstring lstring; +}; + +struct StringTable : Object +{ + void **table; + unsigned count; + unsigned tabledim; + + StringTable(unsigned size = 37); + ~StringTable(); + + StringValue *lookup(const dchar *s, unsigned len); + StringValue *insert(const dchar *s, unsigned len); + StringValue *update(const dchar *s, unsigned len); + +private: + void **search(const dchar *s, unsigned len); +}; + +#endif diff --git a/dmd2/scope.c b/dmd2/scope.c index b3b865fe..bbabc0c9 100644 --- a/dmd2/scope.c +++ b/dmd2/scope.c @@ -1,363 +1,401 @@ - -// Copyright (c) 1999-2005 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 -#include - -#include "root.h" - -#include "mars.h" -#include "init.h" -#include "identifier.h" -#include "attrib.h" -#include "dsymbol.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" - -Scope *Scope::freelist = NULL; - -void *Scope::operator new(size_t size) -{ - if (freelist) - { - Scope *s = freelist; - freelist = s->enclosing; - //printf("freelist %p\n", s); - assert(s->flags & SCOPEfree); - s->flags &= ~SCOPEfree; - return s; - } - - void *p = ::operator new(size); - //printf("new %p\n", p); - return p; -} - -Scope::Scope() -{ // Create root scope - - //printf("Scope::Scope() %p\n", this); - this->module = NULL; - this->scopesym = NULL; - this->sd = NULL; - this->enclosing = NULL; - this->parent = NULL; - this->sw = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->tinst = NULL; - this->sbreak = NULL; - this->scontinue = NULL; - this->fes = NULL; - this->structalign = global.structalign; - this->func = NULL; - this->slabel = NULL; - this->linkage = LINKd; - this->protection = PROTpublic; - this->explicitProtection = 0; - this->stc = 0; - this->offset = 0; - this->inunion = 0; - this->incontract = 0; - this->nofree = 0; - this->noctor = 0; - this->noaccesscheck = 0; - this->mustsemantic = 0; - this->intypeof = 0; - this->parameterSpecialization = 0; - this->callSuper = 0; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = NULL; -} - -Scope::Scope(Scope *enclosing) -{ - //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); - assert(!(enclosing->flags & SCOPEfree)); - this->module = enclosing->module; - this->func = enclosing->func; - this->parent = enclosing->parent; - this->scopesym = NULL; - this->sd = NULL; - this->sw = enclosing->sw; - this->enclosingFinally = enclosing->enclosingFinally; - this->enclosingScopeExit = enclosing->enclosingScopeExit; - this->tinst = enclosing->tinst; - this->sbreak = enclosing->sbreak; - this->scontinue = enclosing->scontinue; - this->fes = enclosing->fes; - this->structalign = enclosing->structalign; - this->enclosing = enclosing; -#ifdef DEBUG - if (enclosing->enclosing) - assert(!(enclosing->enclosing->flags & SCOPEfree)); - if (this == enclosing->enclosing) - { - printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); - } - assert(this != enclosing->enclosing); -#endif - this->slabel = NULL; - this->linkage = enclosing->linkage; - this->protection = enclosing->protection; - this->explicitProtection = enclosing->explicitProtection; - this->stc = enclosing->stc; - this->offset = 0; - this->inunion = enclosing->inunion; - this->incontract = enclosing->incontract; - this->nofree = 0; - this->noctor = enclosing->noctor; - this->noaccesscheck = enclosing->noaccesscheck; - this->mustsemantic = enclosing->mustsemantic; - this->intypeof = enclosing->intypeof; - this->parameterSpecialization = enclosing->parameterSpecialization; - this->callSuper = enclosing->callSuper; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = enclosing->docbuf; - assert(this != enclosing); -} - -Scope *Scope::createGlobal(Module *module) -{ - Scope *sc; - - sc = new Scope(); - sc->module = module; - sc->scopesym = new ScopeDsymbol(); - sc->scopesym->symtab = new DsymbolTable(); - - // Add top level package as member of this global scope - Dsymbol *m = module; - while (m->parent) - m = m->parent; - m->addMember(NULL, sc->scopesym, 1); - m->parent = NULL; // got changed by addMember() - - // Create the module scope underneath the global scope - sc = sc->push(module); - sc->parent = module; - return sc; -} - -Scope *Scope::push() -{ - //printf("Scope::push()\n"); - Scope *s = new Scope(this); - assert(this != s); - return s; -} - -Scope *Scope::push(ScopeDsymbol *ss) -{ - //printf("Scope::push(%s)\n", ss->toChars()); - Scope *s = push(); - s->scopesym = ss; - return s; -} - -Scope *Scope::pop() -{ - //printf("Scope::pop() %p nofree = %d\n", this, nofree); - Scope *enc = enclosing; - - if (enclosing) - enclosing->callSuper |= callSuper; - - if (!nofree) - { enclosing = freelist; - freelist = this; - flags |= SCOPEfree; - } - - return enc; -} - -void Scope::mergeCallSuper(Loc loc, unsigned cs) -{ - // This does a primitive flow analysis to support the restrictions - // regarding when and how constructors can appear. - // It merges the results of two paths. - // The two paths are callSuper and cs; the result is merged into callSuper. - - if (cs != callSuper) - { int a; - int b; - - callSuper |= cs & (CSXany_ctor | CSXlabel); - if (cs & CSXreturn) - { - } - else if (callSuper & CSXreturn) - { - callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); - } - else - { - a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; - b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; - if (a != b) - error(loc, "one path skips constructor"); - callSuper |= cs; - } - } -} - -Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) -{ Dsymbol *s; - Scope *sc; - - //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); - if (ident == Id::empty) - { - // Look for module scope - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - s = sc->scopesym->isModule(); - if (s) - { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - return NULL; - } - - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - s = sc->scopesym->search(loc, ident, 0); - if (s) - { - if ((global.params.warnings || - global.params.Dversion > 1) && - ident == Id::length && - sc->scopesym->isArrayScopeSymbol() && - sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) - { - warning(s->loc, "array 'length' hides other 'length' name in outer scope"); - } - - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - - return NULL; -} - -Dsymbol *Scope::insert(Dsymbol *s) -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - if (sc->scopesym) - { - //printf("\t\tsc->scopesym = %p\n", sc->scopesym); - if (!sc->scopesym->symtab) - sc->scopesym->symtab = new DsymbolTable(); - return sc->scopesym->symtab->insert(s); - } - } - assert(0); - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -ClassDeclaration *Scope::getClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - ClassDeclaration *cd; - - if (sc->scopesym) - { - cd = sc->scopesym->isClassDeclaration(); - if (cd) - return cd; - } - } - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -AggregateDeclaration *Scope::getStructClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - AggregateDeclaration *ad; - - if (sc->scopesym) - { - ad = sc->scopesym->isClassDeclaration(); - if (ad) - return ad; - else - { ad = sc->scopesym->isStructDeclaration(); - if (ad) - return ad; - } - } - } - return NULL; -} - -/******************************************* - * For TemplateDeclarations, we need to remember the Scope - * where it was declared. So mark the Scope as not - * to be free'd. - */ - -void Scope::setNoFree() -{ Scope *sc; - //int i = 0; - - //printf("Scope::setNoFree(this = %p)\n", this); - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - sc->nofree = 1; - - assert(!(flags & SCOPEfree)); - //assert(sc != sc->enclosing); - //assert(!sc->enclosing || sc != sc->enclosing->enclosing); - //if (++i == 10) - //assert(0); - } -} + +// Copyright (c) 1999-2010 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 +#include + +#include "root.h" +#include "speller.h" + +#include "mars.h" +#include "init.h" +#include "identifier.h" +#include "attrib.h" +#include "dsymbol.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "module.h" +#include "id.h" +#include "lexer.h" + +Scope *Scope::freelist = NULL; + +void *Scope::operator new(size_t size) +{ + if (freelist) + { + Scope *s = freelist; + freelist = s->enclosing; + //printf("freelist %p\n", s); + assert(s->flags & SCOPEfree); + s->flags &= ~SCOPEfree; + return s; + } + + void *p = ::operator new(size); + //printf("new %p\n", p); + return p; +} + +Scope::Scope() +{ // Create root scope + + //printf("Scope::Scope() %p\n", this); + this->module = NULL; + this->scopesym = NULL; + this->sd = NULL; + this->enclosing = NULL; + this->parent = NULL; + this->sw = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; + this->tinst = NULL; + this->sbreak = NULL; + this->scontinue = NULL; + this->fes = NULL; + this->structalign = global.structalign; + this->func = NULL; + this->slabel = NULL; + this->linkage = LINKd; + this->protection = PROTpublic; + this->explicitProtection = 0; + this->stc = 0; + this->offset = 0; + this->inunion = 0; + this->incontract = 0; + this->nofree = 0; + this->noctor = 0; + this->noaccesscheck = 0; + this->mustsemantic = 0; + this->intypeof = 0; + this->parameterSpecialization = 0; + this->callSuper = 0; + this->flags = 0; + this->anonAgg = NULL; + this->lastdc = NULL; + this->lastoffset = 0; + this->docbuf = NULL; +} + +Scope::Scope(Scope *enclosing) +{ + //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); + assert(!(enclosing->flags & SCOPEfree)); + this->module = enclosing->module; + this->func = enclosing->func; + this->parent = enclosing->parent; + this->scopesym = NULL; + this->sd = NULL; + this->sw = enclosing->sw; + this->enclosingFinally = enclosing->enclosingFinally; + this->enclosingScopeExit = enclosing->enclosingScopeExit; + this->tinst = enclosing->tinst; + this->sbreak = enclosing->sbreak; + this->scontinue = enclosing->scontinue; + this->fes = enclosing->fes; + this->structalign = enclosing->structalign; + this->enclosing = enclosing; +#ifdef DEBUG + if (enclosing->enclosing) + assert(!(enclosing->enclosing->flags & SCOPEfree)); + if (this == enclosing->enclosing) + { + printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); + } + assert(this != enclosing->enclosing); +#endif + this->slabel = NULL; + this->linkage = enclosing->linkage; + this->protection = enclosing->protection; + this->explicitProtection = enclosing->explicitProtection; + this->stc = enclosing->stc; + this->offset = 0; + this->inunion = enclosing->inunion; + this->incontract = enclosing->incontract; + this->nofree = 0; + this->noctor = enclosing->noctor; + this->noaccesscheck = enclosing->noaccesscheck; + this->mustsemantic = enclosing->mustsemantic; + this->intypeof = enclosing->intypeof; + this->parameterSpecialization = enclosing->parameterSpecialization; + this->callSuper = enclosing->callSuper; + this->flags = 0; + this->anonAgg = NULL; + this->lastdc = NULL; + this->lastoffset = 0; + this->docbuf = enclosing->docbuf; + assert(this != enclosing); +} + +Scope *Scope::createGlobal(Module *module) +{ + Scope *sc; + + sc = new Scope(); + sc->module = module; + sc->scopesym = new ScopeDsymbol(); + sc->scopesym->symtab = new DsymbolTable(); + + // Add top level package as member of this global scope + Dsymbol *m = module; + while (m->parent) + m = m->parent; + m->addMember(NULL, sc->scopesym, 1); + m->parent = NULL; // got changed by addMember() + + // Create the module scope underneath the global scope + sc = sc->push(module); + sc->parent = module; + return sc; +} + +Scope *Scope::push() +{ + //printf("Scope::push()\n"); + Scope *s = new Scope(this); + assert(this != s); + return s; +} + +Scope *Scope::push(ScopeDsymbol *ss) +{ + //printf("Scope::push(%s)\n", ss->toChars()); + Scope *s = push(); + s->scopesym = ss; + return s; +} + +Scope *Scope::pop() +{ + //printf("Scope::pop() %p nofree = %d\n", this, nofree); + Scope *enc = enclosing; + + if (enclosing) + enclosing->callSuper |= callSuper; + + if (!nofree) + { enclosing = freelist; + freelist = this; + flags |= SCOPEfree; + } + + return enc; +} + +void Scope::mergeCallSuper(Loc loc, unsigned cs) +{ + // This does a primitive flow analysis to support the restrictions + // regarding when and how constructors can appear. + // It merges the results of two paths. + // The two paths are callSuper and cs; the result is merged into callSuper. + + if (cs != callSuper) + { int a; + int b; + + callSuper |= cs & (CSXany_ctor | CSXlabel); + if (cs & CSXreturn) + { + } + else if (callSuper & CSXreturn) + { + callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); + } + else + { + a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; + b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; + if (a != b) + error(loc, "one path skips constructor"); + callSuper |= cs; + } + } +} + +Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) +{ Dsymbol *s; + Scope *sc; + + //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); + if (ident == Id::empty) + { + // Look for module scope + for (sc = this; sc; sc = sc->enclosing) + { + assert(sc != sc->enclosing); + if (sc->scopesym) + { + s = sc->scopesym->isModule(); + if (s) + { + //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; + } + } + } + return NULL; + } + + for (sc = this; sc; sc = sc->enclosing) + { + assert(sc != sc->enclosing); + if (sc->scopesym) + { + //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); + s = sc->scopesym->search(loc, ident, 0); + if (s) + { + if ((global.params.warnings || + global.params.Dversion > 1) && + ident == Id::length && + sc->scopesym->isArrayScopeSymbol() && + sc->enclosing && + sc->enclosing->search(loc, ident, NULL)) + { + warning(s->loc, "array 'length' hides other 'length' name in outer scope"); + } + + //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); + if (pscopesym) + *pscopesym = sc->scopesym; + return s; + } + } + } + + return NULL; +} + +Dsymbol *Scope::insert(Dsymbol *s) +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + //printf("\tsc = %p\n", sc); + if (sc->scopesym) + { + //printf("\t\tsc->scopesym = %p\n", sc->scopesym); + if (!sc->scopesym->symtab) + sc->scopesym->symtab = new DsymbolTable(); + return sc->scopesym->symtabInsert(s); + } + } + assert(0); + return NULL; +} + +/******************************************** + * Search enclosing scopes for ClassDeclaration. + */ + +ClassDeclaration *Scope::getClassScope() +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + ClassDeclaration *cd; + + if (sc->scopesym) + { + cd = sc->scopesym->isClassDeclaration(); + if (cd) + return cd; + } + } + return NULL; +} + +/******************************************** + * Search enclosing scopes for ClassDeclaration. + */ + +AggregateDeclaration *Scope::getStructClassScope() +{ Scope *sc; + + for (sc = this; sc; sc = sc->enclosing) + { + AggregateDeclaration *ad; + + if (sc->scopesym) + { + ad = sc->scopesym->isClassDeclaration(); + if (ad) + return ad; + else + { ad = sc->scopesym->isStructDeclaration(); + if (ad) + return ad; + } + } + } + return NULL; +} + +/******************************************* + * For TemplateDeclarations, we need to remember the Scope + * where it was declared. So mark the Scope as not + * to be free'd. + */ + +void Scope::setNoFree() +{ Scope *sc; + //int i = 0; + + //printf("Scope::setNoFree(this = %p)\n", this); + for (sc = this; sc; sc = sc->enclosing) + { + //printf("\tsc = %p\n", sc); + sc->nofree = 1; + + assert(!(flags & SCOPEfree)); + //assert(sc != sc->enclosing); + //assert(!sc->enclosing || sc != sc->enclosing->enclosing); + //if (++i == 10) + //assert(0); + } +} + + +/************************************************ + * Given the failed search attempt, try to find + * one with a close spelling. + */ + +void *scope_search_fp(void *arg, const char *seed) +{ + //printf("scope_search_fp('%s')\n", seed); + + /* If not in the lexer's string table, it certainly isn't in the symbol table. + * Doing this first is a lot faster. + */ + size_t len = strlen(seed); + if (!len) + return NULL; + StringValue *sv = Lexer::stringtable.lookup(seed, len); + if (!sv) + return NULL; + Identifier *id = (Identifier *)sv->ptrvalue; + assert(id); + + Scope *sc = (Scope *)arg; + Module::clearCache(); + Dsymbol *s = sc->search(0, id, NULL); + return s; +} + +Dsymbol *Scope::search_correct(Identifier *ident) +{ + if (global.gag) + return NULL; // don't do it for speculative compiles; too time consuming + + return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars); +} diff --git a/dmd2/scope.h b/dmd2/scope.h index 331f0e0a..184109e8 100644 --- a/dmd2/scope.h +++ b/dmd2/scope.h @@ -1,126 +1,127 @@ - -// Copyright (c) 1999-2009 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. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif - -struct Dsymbol; -struct ScopeDsymbol; -struct Array; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; -struct FuncDeclaration; -struct DocComment; -struct TemplateInstance; - -#if IN_LLVM -struct EnclosingHandler; -struct AnonDeclaration; -#endif - -#if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" // PROT -#include "mars.h" // LINK -#else -enum LINK; -enum PROT; -#endif - -struct Scope -{ - Scope *enclosing; // enclosing Scope - - Module *module; // Root module - ScopeDsymbol *scopesym; // current symbol - ScopeDsymbol *sd; // if in static if, and declaring new symbols, - // sd gets the addMember() - FuncDeclaration *func; // function we are in - Dsymbol *parent; // parent to use - LabelStatement *slabel; // enclosing labelled statement - SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block - TemplateInstance *tinst; // enclosing template instance - Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - int mustsemantic; // cannot defer semantic() - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - unsigned structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions - - enum PROT protection; // protection for class members - int explicitProtection; // set if in an explicit protection attribute - - unsigned stc; // storage class - - unsigned flags; -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list - - AnonymousAggregateDeclaration *anonAgg; // for temporary analysis - - DocComment *lastdc; // documentation comment for last symbol at this scope - unsigned lastoffset; // offset in docbuf of where to insert next dec - OutBuffer *docbuf; // buffer for documentation output - - static Scope *freelist; - static void *operator new(size_t sz); - static Scope *createGlobal(Module *module); - - Scope(); - Scope(Module *module); - Scope(Scope *enclosing); - - Scope *push(); - Scope *push(ScopeDsymbol *ss); - Scope *pop(); - - void mergeCallSuper(Loc loc, unsigned cs); - - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); - Dsymbol *insert(Dsymbol *s); - - ClassDeclaration *getClassScope(); - AggregateDeclaration *getStructClassScope(); - void setNoFree(); -}; - -#endif /* DMD_SCOPE_H */ + +// Copyright (c) 1999-2009 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. + +#ifndef DMD_SCOPE_H +#define DMD_SCOPE_H + +#ifdef __DMC__ +#pragma once +#endif + +struct Dsymbol; +struct ScopeDsymbol; +struct Array; +struct Identifier; +struct Module; +struct Statement; +struct SwitchStatement; +struct TryFinallyStatement; +struct LabelStatement; +struct ForeachStatement; +struct ClassDeclaration; +struct AggregateDeclaration; +struct AnonymousAggregateDeclaration; +struct FuncDeclaration; +struct DocComment; +struct TemplateInstance; + +#if IN_LLVM +struct EnclosingHandler; +struct AnonDeclaration; +#endif + +#if __GNUC__ +// Requires a full definition for PROT and LINK +#include "dsymbol.h" // PROT +#include "mars.h" // LINK +#else +enum LINK; +enum PROT; +#endif + +struct Scope +{ + Scope *enclosing; // enclosing Scope + + Module *module; // Root module + ScopeDsymbol *scopesym; // current symbol + ScopeDsymbol *sd; // if in static if, and declaring new symbols, + // sd gets the addMember() + FuncDeclaration *func; // function we are in + Dsymbol *parent; // parent to use + LabelStatement *slabel; // enclosing labelled statement + SwitchStatement *sw; // enclosing switch statement + TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block + TemplateInstance *tinst; // enclosing template instance + Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit + Statement *sbreak; // enclosing statement that supports "break" + Statement *scontinue; // enclosing statement that supports "continue" + ForeachStatement *fes; // if nested function for ForeachStatement, this is it + unsigned offset; // next offset to use in aggregate + int inunion; // we're processing members of a union + int incontract; // we're inside contract code + int nofree; // set if shouldn't free it + int noctor; // set if constructor calls aren't allowed + int intypeof; // in typeof(exp) + int parameterSpecialization; // if in template parameter specialization + int noaccesscheck; // don't do access checks + int mustsemantic; // cannot defer semantic() + + unsigned callSuper; // primitive flow analysis for constructors +#define CSXthis_ctor 1 // called this() +#define CSXsuper_ctor 2 // called super() +#define CSXthis 4 // referenced this +#define CSXsuper 8 // referenced super +#define CSXlabel 0x10 // seen a label +#define CSXreturn 0x20 // seen a return statement +#define CSXany_ctor 0x40 // either this() or super() was called + + unsigned structalign; // alignment for struct members + enum LINK linkage; // linkage for external functions + + enum PROT protection; // protection for class members + int explicitProtection; // set if in an explicit protection attribute + + StorageClass stc; // storage class + + unsigned flags; +#define SCOPEctor 1 // constructor type +#define SCOPEstaticif 2 // inside static if +#define SCOPEfree 4 // is on free list + + AnonymousAggregateDeclaration *anonAgg; // for temporary analysis + + DocComment *lastdc; // documentation comment for last symbol at this scope + unsigned lastoffset; // offset in docbuf of where to insert next dec + OutBuffer *docbuf; // buffer for documentation output + + static Scope *freelist; + static void *operator new(size_t sz); + static Scope *createGlobal(Module *module); + + Scope(); + Scope(Module *module); + Scope(Scope *enclosing); + + Scope *push(); + Scope *push(ScopeDsymbol *ss); + Scope *pop(); + + void mergeCallSuper(Loc loc, unsigned cs); + + Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); + Dsymbol *search_correct(Identifier *ident); + Dsymbol *insert(Dsymbol *s); + + ClassDeclaration *getClassScope(); + AggregateDeclaration *getStructClassScope(); + void setNoFree(); +}; + +#endif /* DMD_SCOPE_H */ diff --git a/dmd2/statement.c b/dmd2/statement.c index 0e6c391f..541e5fb9 100644 --- a/dmd2/statement.c +++ b/dmd2/statement.c @@ -1,4711 +1,4843 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "hdrgen.h" -#include "parse.h" -#include "template.h" -#include "attrib.h" - -#if IN_LLVM -// sizes based on those from tollvm.cpp:DtoMutexType() -int os_critsecsize() -{ - if (global.params.os == OSWindows) - return 68; - else if (global.params.os == OSFreeBSD) - return sizeof(size_t); - else - return sizeof(pthread_mutex_t); -} -#elif IN_DMD -extern int os_critsecsize(); -#endif - -/******************************** Statement ***************************/ - -Statement::Statement(Loc loc) - : loc(loc) -{ -#ifdef _DH - // If this is an in{} contract scope statement (skip for determining - // inlineStatus of a function body for header content) - incontract = 0; -#endif -} - -Statement *Statement::syntaxCopy() -{ - assert(0); - return NULL; -} - -void Statement::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Statement::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("Statement::toCBuffer()"); - buf->writenl(); -} - -Statement *Statement::semantic(Scope *sc) -{ - return this; -} - -// Same as semantic(), but do create a new scope - -Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) -{ Scope *scd; - Statement *s; - - scd = sc->push(); - if (sbreak) - scd->sbreak = sbreak; - if (scontinue) - scd->scontinue = scontinue; - s = semantic(scd); - scd->pop(); - return s; -} - -void Statement::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Statement::warning(const char *format, ...) -{ - if (global.params.warnings && !global.gag) - { - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); - } -} - -int Statement::hasBreak() -{ - //printf("Statement::hasBreak()\n"); - return FALSE; -} - -int Statement::hasContinue() -{ - return FALSE; -} - -// TRUE if statement uses exception handling - -int Statement::usesEH() -{ - return FALSE; -} - -/* Only valid after semantic analysis - */ -int Statement::blockExit() -{ - printf("Statement::blockExit(%p)\n", this); - printf("%s\n", toChars()); - assert(0); - return BEany; -} - -// TRUE if statement 'comes from' somewhere else, like a goto - -int Statement::comeFrom() -{ - //printf("Statement::comeFrom()\n"); - return FALSE; -} - -// Return TRUE if statement has no code in it -int Statement::isEmpty() -{ - //printf("Statement::isEmpty()\n"); - return FALSE; -} - -/**************************************** - * If this statement has code that needs to run in a finally clause - * at the end of the current scope, return that code in the form of - * a Statement. - * Output: - * *sentry code executed upon entry to the scope - * *sexception code executed upon exit from the scope via exception - * *sfinally code executed in finally block - */ - -void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("Statement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; -} - -/********************************* - * Flatten out the scope by presenting the statement - * as an array of statements. - * Returns NULL if no flattening necessary. - */ - -Statements *Statement::flatten(Scope *sc) -{ - return NULL; -} - - -/******************************** PeelStatement ***************************/ - -PeelStatement::PeelStatement(Statement *s) - : Statement(s->loc) -{ - this->s = s; -} - -Statement *PeelStatement::semantic(Scope *sc) -{ - /* "peel" off this wrapper, and don't run semantic() - * on the result. - */ - return s; -} - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; -} - -void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statement *ExpStatement::semantic(Scope *sc) -{ - if (exp) - { - //printf("ExpStatement::semantic() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp->checkSideEffect(0); - exp = exp->optimize(0); - if (exp->op == TOKdeclaration && !isDeclarationStatement()) - { Statement *s = new DeclarationStatement(loc, exp); - return s; - } - //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); - } - return this; -} - -int ExpStatement::blockExit() -{ int result = BEfallthru; - - if (exp) - { - if (exp->op == TOKhalt) - return BEhalt; - if (exp->op == TOKassert) - { AssertExp *a = (AssertExp *)exp; - - if (a->e1->isBool(FALSE)) // if it's an assert(0) - return BEhalt; - } - if (exp->canThrow()) - result |= BEthrow; - } - return result; -} - - -/******************************** CompileStatement ***************************/ - -CompileStatement::CompileStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *CompileStatement::syntaxCopy() -{ - Expression *e = exp->syntaxCopy(); - CompileStatement *es = new CompileStatement(loc, e); - return es; -} - -void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statements *CompileStatement::flatten(Scope *sc) -{ - //printf("CompileStatement::flatten() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op != TOKstring) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return NULL; - } - StringExp *se = (StringExp *)exp; - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - - Statements *a = new Statements(); - while (p.token.value != TOKeof) - { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - a->push(s); - } - return a; -} - -Statement *CompileStatement::semantic(Scope *sc) -{ - //printf("CompileStatement::semantic() %s\n", exp->toChars()); - Statements *a = flatten(sc); - if (!a) - return NULL; - Statement *s = new CompoundStatement(loc, a); - return s->semantic(sc); -} - - -/******************************** DeclarationStatement ***************************/ - -DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) - : ExpStatement(loc, new DeclarationExp(loc, declaration)) -{ -} - -DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) - : ExpStatement(loc, exp) -{ -} - -Statement *DeclarationStatement::syntaxCopy() -{ - DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); - return ds; -} - -void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("DeclarationStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v) - { Expression *e; - - e = v->callAutoDtor(sc); - if (e) - { - //printf("dtor is: "); e->print(); -#if 0 - if (v->type->toBasetype()->ty == Tstruct) - { /* Need a 'gate' to turn on/off destruction, - * in case v gets moved elsewhere. - */ - Identifier *id = Lexer::uniqueId("__runDtor"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); - VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, rd); - v->rundtor = rd; - - /* Rewrite e as: - * rundtor && e - */ - Expression *ve = new VarExp(loc, v->rundtor); - e = new AndAndExp(loc, ve, e); - e->type = Type::tbool; - } -#endif - *sfinally = new ExpStatement(loc, e); - } - } - } - } -} - -void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - -/******************************** CompoundStatement ***************************/ - -CompoundStatement::CompoundStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) - : Statement(loc) -{ - statements = new Statements(); - statements->reserve(2); - statements->push(s1); - statements->push(s2); -} - -Statement *CompoundStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - - for (size_t i = 0; i < statements->dim; ) - { - s = (Statement *) statements->data[i]; - if (s) - { Statements *a = s->flatten(sc); - - if (a) - { - statements->remove(i); - statements->insert(i, a); - continue; - } - s = s->semantic(sc); - statements->data[i] = s; - if (s) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - s->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - if (s->isDeclarationStatement()) - { statements->insert(i, sentry); - i++; - } - else - statements->data[i] = sentry; - } - if (sexception) - { - if (i + 1 == statements->dim && !sfinally) - { -#if 1 - sexception = sexception->semantic(sc); -#else - statements->push(sexception); - if (sfinally) - // Assume sexception does not throw - statements->push(sfinally); -#endif - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; - * try { s1; s2; } - * catch (Object __o) - * { sexception; throw __o; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - body = new ScopeStatement(0, body); - - Identifier *id = Lexer::uniqueId("__o"); - - Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); - - Array *catches = new Array(); - Catch *ctch = new Catch(0, NULL, id, handler); - catches->push(ctch); - s = new TryCatchStatement(0, body, catches); - - if (sfinally) - s = new TryFinallyStatement(0, s, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - else if (sfinally) - { - if (0 && i + 1 == statements->dim) - { - statements->push(sfinally); - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; try { s1; s2; } finally { sfinally; } - */ - Statement *body; - Statements *a = new Statements(); - - for (int j = i + 1; j < statements->dim; j++) - { - a->push(statements->data[j]); - } - body = new CompoundStatement(0, a); - s = new TryFinallyStatement(0, body, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - } - } - i++; - } - if (statements->dim == 1 && !isAsmBlockStatement()) - { - return (Statement *)statements->data[0]; - } - return this; -} - -Statements *CompoundStatement::flatten(Scope *sc) -{ - return statements; -} - -ReturnStatement *CompoundStatement::isReturnStatement() -{ - ReturnStatement *rs = NULL; - - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - rs = s->isReturnStatement(); - if (rs) - break; - } - } - return rs; -} - -void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } -} - -int CompoundStatement::usesEH() -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int CompoundStatement::blockExit() -{ - //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { -//printf("result = x%x\n", result); -//printf("%s\n", s->toChars()); - if (!(result & BEfallthru) && !s->comeFrom()) - { - if (s->blockExit() != BEhalt) - s->warning("statement is not reachable"); - } - - result &= ~BEfallthru; - result |= s->blockExit(); - } - } - return result; -} - -int CompoundStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("CompoundStatement::comeFrom()\n"); - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - -int CompoundStatement::isEmpty() -{ - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s && !s->isEmpty()) - return FALSE; - } - return TRUE; -} - - -/******************************** CompoundDeclarationStatement ***************************/ - -CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s) - : CompoundStatement(loc, s) -{ - statements = s; -} - -Statement *CompoundDeclarationStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); - return cs; -} - -void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int nwritten = 0; - for (int i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { DeclarationStatement *ds = s->isDeclarationStatement(); - assert(ds); - DeclarationExp *de = (DeclarationExp *)ds->exp; - assert(de->op == TOKdeclaration); - Declaration *d = de->declaration->isDeclaration(); - assert(d); - VarDeclaration *v = d->isVarDeclaration(); - if (v) - { - /* This essentially copies the part of VarDeclaration::toCBuffer() - * that does not print the type. - * Should refactor this. - */ - if (nwritten) - { - buf->writeByte(','); - buf->writestring(v->ident->toChars()); - } - else - { - StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); - if (v->type) - v->type->toCBuffer(buf, v->ident, hgs); - else - buf->writestring(v->ident->toChars()); - } - - if (v->init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - v->init->toCBuffer(buf, hgs); - } - } - else - d->toCBuffer(buf, hgs); - nwritten++; - } - } - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - if (s) - s = s->syntaxCopy(); - a->data[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (Statement *) statements->data[i]; - if (s) - { - s = s->semantic(scd); - statements->data[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; - if (s) - s->toCBuffer(buf, hgs); - } - - buf->writeByte('}'); - buf->writenl(); -} - -int UnrolledLoopStatement::hasBreak() -{ - return TRUE; -} - -int UnrolledLoopStatement::hasContinue() -{ - return TRUE; -} - -int UnrolledLoopStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int UnrolledLoopStatement::blockExit() -{ - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *) statements->data[i]; - if (s) - { - int r = s->blockExit(); - result |= r & ~(BEbreak | BEcontinue); - } - } - return result; -} - - -int UnrolledLoopStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("UnrolledLoopStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (Statement *)statements->data[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/******************************** ScopeStatement ***************************/ - -ScopeStatement::ScopeStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -} - -Statement *ScopeStatement::syntaxCopy() -{ - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; -} - - -Statement *ScopeStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("ScopeStatement::semantic(sc = %p)\n", sc); - if (statement) - { Statements *a; - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - a = statement->flatten(sc); - if (a) - { - statement = new CompoundStatement(loc, a); - } - - statement = statement->semantic(sc); - if (statement) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - statement->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sfinally) - { - //printf("adding sfinally\n"); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::blockExit() -{ - //printf("ScopeStatement::blockExit(%p)\n", statement); - return statement ? statement->blockExit() : BEfallthru; -} - - -int ScopeStatement::comeFrom() -{ - //printf("ScopeStatement::comeFrom()\n"); - return statement ? statement->comeFrom() : FALSE; -} - -int ScopeStatement::isEmpty() -{ - //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); - return statement ? statement->isEmpty() : TRUE; -} - -void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('{'); - buf->writenl(); - - if (statement) - statement->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); -} - -/******************************** WhileStatement ***************************/ - -WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; -} - -Statement *WhileStatement::syntaxCopy() -{ - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - - -Statement *WhileStatement::semantic(Scope *sc) -{ - /* Rewrite as a for(;condition;) loop - */ - - Statement *s = new ForStatement(loc, NULL, condition, NULL, body); - s = s->semantic(sc); - return s; -} - -int WhileStatement::hasBreak() -{ - return TRUE; -} - -int WhileStatement::hasContinue() -{ - return TRUE; -} - -int WhileStatement::usesEH() -{ - assert(0); - return body ? body->usesEH() : 0; -} - -int WhileStatement::blockExit() -{ - assert(0); - //printf("WhileStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (body) - { result |= body->blockExit(); - if (result & BEbreak) - result |= BEfallthru; - } - } - else if (condition->isBool(FALSE)) - { - result |= BEfallthru; - } - else - { - if (body) - result |= body->blockExit(); - result |= BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int WhileStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); -} - -/******************************** DoStatement ***************************/ - -DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) - : Statement(loc) -{ - body = b; - condition = c; -} - -Statement *DoStatement::syntaxCopy() -{ - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; -} - - -Statement *DoStatement::semantic(Scope *sc) -{ - sc->noctor++; - if (body) - body = body->semanticScope(sc, this, this); - sc->noctor--; - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - - condition = condition->checkToBoolean(); - - return this; -} - -int DoStatement::hasBreak() -{ - return TRUE; -} - -int DoStatement::hasContinue() -{ - return TRUE; -} - -int DoStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int DoStatement::blockExit() -{ int result; - - if (body) - { result = body->blockExit(); - if (result == BEbreak) - return BEfallthru; - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { if (condition->canThrow()) - result |= BEthrow; - if (!(result & BEbreak) && condition->isBool(TRUE)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int DoStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("do"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); -} - -/******************************** ForStatement ***************************/ - -ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) - : Statement(loc) -{ - this->init = init; - this->condition = condition; - this->increment = increment; - this->body = body; -} - -Statement *ForStatement::syntaxCopy() -{ - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; -} - -Statement *ForStatement::semantic(Scope *sc) -{ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); - sc->noctor++; - if (condition) - { - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(); - } - if (increment) - { increment = increment->semantic(sc); - increment = resolveProperties(sc, increment); - } - - sc->sbreak = this; - sc->scontinue = this; - if (body) - body = body->semantic(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); -} - -int ForStatement::hasBreak() -{ - //printf("ForStatement::hasBreak()\n"); - return TRUE; -} - -int ForStatement::hasContinue() -{ - return TRUE; -} - -int ForStatement::usesEH() -{ - return (init && init->usesEH()) || body->usesEH(); -} - -int ForStatement::blockExit() -{ int result = BEfallthru; - - if (init) - { result = init->blockExit(); - if (!(result & BEfallthru)) - return result; - } - if (condition) - { if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - result &= ~BEfallthru; - else if (condition->isBool(FALSE)) - return result; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (body) - { int r = body->blockExit(); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (increment && increment->canThrow()) - result |= BEthrow; - return result; -} - - -int ForStatement::comeFrom() -{ - //printf("ForStatement::comeFrom()\n"); - if (body) - { int result = body->comeFrom(); - //printf("result = %d\n", result); - return result; - } - return FALSE; -} - -void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("for ("); - if (init) - { - hgs->FLinit.init++; - init->toCBuffer(buf, hgs); - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - Arguments *args = Argument::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachStatement::semantic(Scope *sc) -{ - //printf("ForeachStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - size_t dim = arguments->dim; - TypeAArray *taa = NULL; - - Type *tn = NULL; - Type *tnv = NULL; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - - inferApplyArgTypes(op, arguments, aggr, sc->module); - - /* Check for inference errors - */ - if (dim != arguments->dim) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - } - else if (aggr->op == TOKtype) // type tuple - { - n = Argument::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (Expression *)te->exps->data[k]; - else - t = Argument::getNth(tuple->arguments, k)->type; - Argument *arg = (Argument *)arguments->data[0]; - Statements *st = new Statements(); - - if (dim == 2) - { // Declare key - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); - TY keyty = arg->type->ty; - if (keyty != Tint32 && keyty != Tuns32) - { - if (global.params.is64bit) - { - if (keyty != Tint64 && keyty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); - } - else - error("foreach: key type must be int or uint, not %s", arg->type->toChars()); - } - Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); - VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); - var->storage_class |= STCmanifest; - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - arg = (Argument *)arguments->data[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { Type *tb = e->type->toBasetype(); - if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - var = new AliasDeclaration(loc, arg->ident, ve->var); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (e->isConst()) - v->storage_class |= STCconst; - var = v; - } - } - else - { - var = new AliasDeclaration(loc, arg->ident, t); - } - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - - st->push(body->syntaxCopy()); - s = new CompoundStatement(loc, st); - s = new ScopeStatement(loc, s); - statements->push(s); - } - - s = new UnrolledLoopStatement(loc, statements); - s = s->semantic(sc); - return s; - } - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - switch (tab->ty) - { - case Tarray: - case Tsarray: - if (!checkForArgTypes()) - return this; - - if (dim < 1 || dim > 2) - { - error("only one or two arguments for array foreach"); - break; - } - - /* Look for special case of parsing char types out of char type - * array. - */ - tn = tab->nextOf()->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { Argument *arg; - - int i = (dim == 1) ? 0 : 1; // index of value - arg = (Argument *)arguments->data[i]; - arg->type = arg->type->semantic(loc, sc); - tnv = arg->type->toBasetype(); - if (tnv->ty != tn->ty && - (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) - { - if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); - if (dim == 2) - { arg = (Argument *)arguments->data[0]; - if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); - } - goto Lapply; - } - } - - for (size_t i = 0; i < dim; i++) - { // Declare args - Argument *arg = (Argument *)arguments->data[i]; - Type *argtype = arg->type->semantic(loc, sc); - VarDeclaration *var; - - var = new VarDeclaration(loc, argtype, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - if (var->storage_class & (STCref | STCout)) - var->storage_class |= STCnodtor; - if (dim == 2 && i == 0) - { key = var; - //var->storage_class |= STCfinal; - } - else - { - value = var; - /* Reference to immutable data should be marked as const - */ - if (var->storage_class & STCref && !tn->isMutable()) - { - var->storage_class |= STCconst; - } - } -#if 0 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#endif - } - -#if 1 - { - /* Convert to a ForStatement - * foreach (key, value; a) body => - * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) - * { T value = tmp[k]; body } - * - * foreach_reverse (key, value; a) body => - * for (T[] tmp = a[], size_t key = tmp.length; key--; ) - * { T value = tmp[k]; body } - */ - Identifier *id = Lexer::uniqueId("__aggr"); - ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); - VarDeclaration *tmp = new VarDeclaration(loc, aggr->type->nextOf()->arrayOf(), id, ie); - - Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); - - if (!key) - { - Identifier *id = Lexer::uniqueId("__key"); - key = new VarDeclaration(loc, Type::tsize_t, id, NULL); - } - if (op == TOKforeach_reverse) - key->init = new ExpInitializer(loc, tmp_length); - else - key->init = new ExpInitializer(loc, new IntegerExp(0)); - - Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - // key-- - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - else - // key < tmp.length - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - // T value = tmp[key]; - value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); - Statement *ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); - - body = new CompoundStatement(loc, ds, body); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - break; - } -#else - if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst) - { - if (aggr->op == TOKstring) - aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); - else - error("foreach: %s is not an array of %s", - tab->toChars(), value->type->toChars()); - } - - if (key) - { - if (global.params.is64bit) - { - if (key->type->ty != Tint64 && key->type->ty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); - } - - if (key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - break; -#endif - - case Taarray: - if (!checkForArgTypes()) - return this; - - taa = (TypeAArray *)tab; - if (dim < 1 || dim > 2) - { - error("only one or two arguments for associative array foreach"); - break; - } - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; - - case Tclass: - case Tstruct: -#if DMDV2 - { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear - * foreach (e; aggr) { ... } - * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; - * ... - * } - */ - if (dim != 1) // only one argument allowed with ranges - goto Lapply; - AggregateDeclaration *ad = (tab->ty == Tclass) - ? (AggregateDeclaration *)((TypeClass *)tab)->sym - : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; - if (op == TOKforeach) - { idhead = Id::Fhead; - idnext = Id::Fnext; - } - else - { idhead = Id::Ftoe; - idnext = Id::Fretreat; - } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) - goto Lapply; - - /* Generate a temporary __r and initialize it with the aggregate. - */ - Identifier *id = Identifier::generateId("__r"); - Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); - rinit = rinit->trySemantic(sc); - if (!rinit) // if application of [] failed - rinit = aggr; - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); -// r->semantic(sc); -//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); - Statement *init = new DeclarationStatement(loc, r); -//printf("init: %s\n", init->toChars()); - - // !__r.empty - Expression *e = new VarExp(loc, r); - e = new DotIdExp(loc, e, Id::Fempty); - Expression *condition = new NotExp(loc, e); - - // __r.next - e = new VarExp(loc, r); - Expression *increment = new DotIdExp(loc, e, idnext); - - /* Declaration statement for e: - * auto e = __r.idhead; - */ - e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); -// einit = einit->semantic(sc); - Argument *arg = (Argument *)arguments->data[0]; - VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); - ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - - DeclarationExp *de = new DeclarationExp(loc, ve); - - Statement *body = new CompoundStatement(loc, - new DeclarationStatement(loc, de), this->body); - - s = new ForStatement(loc, init, condition, increment, body); -#if 0 - printf("init: %s\n", init->toChars()); - printf("condition: %s\n", condition->toChars()); - printf("increment: %s\n", increment->toChars()); - printf("body: %s\n", body->toChars()); -#endif - s = s->semantic(sc); - break; - } -#endif - case Tdelegate: - Lapply: - { FuncDeclaration *fdapply; - Arguments *args; - Expression *ec; - Expression *e; - FuncLiteralDeclaration *fld; - Argument *a; - Type *t; - Expression *flde; - Identifier *id; - Type *tret; - TypeDelegate* dgty; - TypeDelegate* dgty2; - TypeDelegate* fldeTy; - - if (!checkForArgTypes()) - { body = body->semantic(sc); - return this; - } - - tret = func->type->nextOf(); - - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { VarDeclaration *v; - - v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - - /* Turn body into the function literal: - * int delegate(ref T arg) { body } - */ - args = new Arguments(); - for (size_t i = 0; i < dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - - arg->type = arg->type->semantic(loc, sc); - if (arg->storageClass & STCref) - id = arg->ident; - else - { // Make a copy of the ref argument so it isn't - // a reference. - VarDeclaration *v; - Initializer *ie; - - id = Lexer::uniqueId("__applyArg", i); - - ie = new ExpInitializer(0, new IdentifierExp(0, id)); - v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new DeclarationStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - a = new Argument(STCref, arg->type, id, NULL); - args->push(a); - } - t = new TypeFunction(args, Type::tint32, 0, LINKd); - fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); - fld->fbody = body; - flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - fld->tookAddressOf = 0; - - // Resolve any forward referenced goto's - for (int i = 0; i < gotos.dim; i++) - { CompoundStatement *cs = (CompoundStatement *)gotos.data[i]; - GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; - - if (!gs->label->statement) - { // 'Promote' it to this scope, and replace with a return - cases.push(gs); - s = new ReturnStatement(0, new IntegerExp(cases.dim + 1)); - cs->statements->data[0] = (void *)s; - } - } - - if (tab->ty == Taarray) - { - // Check types - Argument *arg = (Argument *)arguments->data[0]; - if (dim == 2) - { - if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); - if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (Argument *)arguments->data[1]; - } - if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - - /* Call: - * _aaApply(aggr, keysize, flde) - */ - //LDC: Build arguments. - static FuncDeclaration *aaApply2_fd = NULL; - static TypeDelegate* aaApply2_dg; - if(!aaApply2_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, aaApply2_dg, NULL, NULL)); - aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2"); - } - static FuncDeclaration *aaApply_fd = NULL; - static TypeDelegate* aaApply_dg; - if(!aaApply_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, aaApply_dg, NULL, NULL)); - aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply"); - } - if (dim == 2) { - fdapply = aaApply2_fd; - fldeTy = aaApply2_dg; - } else { - fdapply = aaApply_fd; - fldeTy = aaApply_dg; - } - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - exps->push(aggr); - size_t keysize = taa->index->size(); - keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - -#if IN_LLVM - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; - } -#endif - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tarray || tab->ty == Tsarray) - { - /* Call: - * _aApply(aggr, flde) - */ - static char fntab[9][3] = - { "cc","cw","cd", - "wc","cc","wd", - "dc","dw","dd" - }; - char fdname[7+1+2+ sizeof(dim)*3 + 1]; - int flag; - - switch (tn->ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: assert(0); - } - switch (tnv->ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: assert(0); - } - const char *r = (op == TOKforeach_reverse) ? "R" : ""; -#ifdef __MINGW32__ - int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); -#else - int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); -#endif - assert(j < sizeof(fdname)); - //LDC: Build arguments. - Arguments* args = new Arguments; - args->push(new Argument(STCin, tn->arrayOf(), NULL, NULL)); - if (dim == 2) { - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); - } else { - Arguments* dgargs = new Arguments; - dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); - args->push(new Argument(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); - } - - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - if (tab->ty == Tsarray) - aggr = aggr->castTo(sc, tn->arrayOf()); - exps->push(aggr); - - // LDC paint delegate argument to the type runtime expects - if (!dgty->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = dgty; - } - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tindex; // don't run semantic() on e - } - else if (tab->ty == Tdelegate) - { - /* Call: - * aggr(flde) - */ - Expressions *exps = new Expressions(); - exps->push(flde); - e = new CallExp(loc, aggr, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - else - { - assert(tab->ty == Tstruct || tab->ty == Tclass); - Identifier *idapply = (op == TOKforeach_reverse) - ? Id::applyReverse : Id::apply; - Dsymbol *sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); - Expressions *exps = new Expressions(); -#if 0 - TemplateDeclaration *td; - if (sapply && - (td = sapply->isTemplateDeclaration()) != NULL) - { /* Call: - * aggr.apply!(fld)() - */ - TemplateInstance *ti = new TemplateInstance(loc, idapply); - Objects *tiargs = new Objects(); - tiargs->push(fld); - ti->tiargs = tiargs; - ec = new DotTemplateInstanceExp(loc, aggr, ti); - } - else -#endif - { - /* Call: - * aggr.apply(flde) - */ - ec = new DotIdExp(loc, aggr, idapply); - exps->push(flde); - } - e = new CallExp(loc, ec, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - - if (!cases.dim) - // Easy case, a clean exit from the loop - s = new ExpStatement(loc, e); - else - { // Construct a switch statement around the return value - // of the apply function. - Statements *a = new Statements(); - - // default: break; takes care of cases 0 and 1 - s = new BreakStatement(0, NULL); - s = new DefaultStatement(0, s); - a->push(s); - - // cases 2... - for (int i = 0; i < cases.dim; i++) - { - s = (Statement *)cases.data[i]; - s = new CaseStatement(0, new IntegerExp(i + 2), s); - a->push(s); - } - - s = new CompoundStatement(loc, a); - s = new SwitchStatement(loc, e, s, FALSE); - s = s->semantic(sc); - } - break; - } - - default: - error("foreach: %s is not an aggregate type", aggr->type->toChars()); - s = NULL; // error recovery - break; - } - sc->noctor--; - sc->pop(); - return s; -} - -bool ForeachStatement::checkForArgTypes() -{ bool result = TRUE; - - for (size_t i = 0; i < arguments->dim; i++) - { Argument *arg = (Argument *)arguments->data[i]; - if (!arg->type) - { - error("cannot infer type for %s", arg->ident->toChars()); - arg->type = Type::terror; - result = FALSE; - } - } - return result; -} - -int ForeachStatement::hasBreak() -{ - return TRUE; -} - -int ForeachStatement::hasContinue() -{ - return TRUE; -} - -int ForeachStatement::usesEH() -{ - return body->usesEH(); -} - -int ForeachStatement::blockExit() -{ int result = BEfallthru; - - if (aggr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit() & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - for (int i = 0; i < arguments->dim; i++) - { - Argument *a = (Argument *)arguments->data[i]; - if (i) - buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); - if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); - else - buf->writestring(a->ident->toChars()); - } - buf->writestring("; "); - aggr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/**************************** ForeachRangeStatement ***************************/ - -#if DMDV2 - -ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, - Expression *lwr, Expression *upr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arg = arg; - this->lwr = lwr; - this->upr = upr; - this->body = body; - - this->key = NULL; -} - -Statement *ForeachRangeStatement::syntaxCopy() -{ - ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, - arg->syntaxCopy(), - lwr->syntaxCopy(), - upr->syntaxCopy(), - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachRangeStatement::semantic(Scope *sc) -{ - //printf("ForeachRangeStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - - lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->optimize(WANTvalue); - if (!lwr->type) - { - error("invalid range lower bound %s", lwr->toChars()); - return this; - } - - upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->optimize(WANTvalue); - if (!upr->type) - { - error("invalid range upper bound %s", upr->toChars()); - return this; - } - - if (arg->type) - { - arg->type = arg->type->semantic(loc, sc); - lwr = lwr->implicitCastTo(sc, arg->type); - upr = upr->implicitCastTo(sc, arg->type); - } - else - { - /* Must infer types from lwr and upr - */ - AddExp ea(loc, lwr, upr); - ea.typeCombine(sc); - arg->type = ea.type->mutableOf(); - lwr = ea.e1; - upr = ea.e2; - } -#if 1 - /* Convert to a for loop: - * foreach (key; lwr .. upr) => - * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) - * - * foreach_reverse (key; lwr .. upr) => - * for (auto tmp = lwr, auto key = upr; key-- > tmp;) - */ - - ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); - key = new VarDeclaration(loc, arg->type, arg->ident, ie); - - Identifier *id = Lexer::uniqueId("__limit"); - ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); - VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie); - - Statements *cs = new Statements(); - // Keep order of evaluation as lwr, then upr - if (op == TOKforeach) - { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - } - else - { - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); - } - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - { // key-- > tmp - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); - } - else - // key < tmp - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - return s; -#else - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -#endif -} - -int ForeachRangeStatement::hasBreak() -{ - return TRUE; -} - -int ForeachRangeStatement::hasContinue() -{ - return TRUE; -} - -int ForeachRangeStatement::usesEH() -{ - assert(0); - return body->usesEH(); -} - -int ForeachRangeStatement::blockExit() -{ - assert(0); - int result = BEfallthru; - - if (lwr && lwr->canThrow()) - result |= BEthrow; - else if (upr && upr->canThrow()) - result |= BEthrow; - - if (body) - { - result |= body->blockExit() & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachRangeStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - buf->writestring(arg->ident->toChars()); - - buf->writestring("; "); - lwr->toCBuffer(buf, hgs); - buf->writestring(" .. "); - upr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -#endif - -/******************************** IfStatement ***************************/ - -IfStatement::IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->arg = arg; - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; - this->match = NULL; -} - -Statement *IfStatement::syntaxCopy() -{ - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Argument *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; -} - -Statement *IfStatement::semantic(Scope *sc) -{ - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->checkToBoolean(); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - Type *t = arg->type ? arg->type : condition->type; - match = new VarDeclaration(loc, t, arg->ident, NULL); - match->noauto = 1; - match->semantic(scd); - if (!scd->insert(match)) - assert(0); - match->parent = sc->func; - - /* Generate: - * (arg = condition) - */ - VarExp *v = new VarExp(0, match); - condition = new AssignExp(loc, v, condition); - condition = condition->semantic(scd); - } - else - scd = sc->push(); - ifbody = ifbody->semantic(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::blockExit() -{ - //printf("IfStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (ifbody) - result |= ifbody->blockExit(); - else - result |= BEfallthru; - } - else if (condition->isBool(FALSE)) - { - if (elsebody) - result |= elsebody->blockExit(); - else - result |= BEfallthru; - } - else - { - if (ifbody) - result |= ifbody->blockExit(); - else - result |= BEfallthru; - if (elsebody) - result |= elsebody->blockExit(); - else - result |= BEfallthru; - } - //printf("IfStatement::blockExit(%p) = x%x\n", this, result); - return result; -} - - -void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("if ("); - if (arg) - { - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - { buf->writestring("auto "); - buf->writestring(arg->ident->toChars()); - } - buf->writestring(" = "); - } - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - ifbody->toCBuffer(buf, hgs); - if (elsebody) - { buf->writestring("else"); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - } -} - -/******************************** ConditionalStatement ***************************/ - -ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; -} - -Statement *ConditionalStatement::syntaxCopy() -{ - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - ConditionalStatement *s = new ConditionalStatement(loc, - condition->syntaxCopy(), ifbody->syntaxCopy(), e); - return s; -} - -Statement *ConditionalStatement::semantic(Scope *sc) -{ - //printf("ConditionalStatement::semantic()\n"); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - if (condition->include(sc, NULL)) - { - ifbody = ifbody->semantic(sc); - return ifbody; - } - else - { - if (elsebody) - elsebody = elsebody->semantic(sc); - return elsebody; - } -} - -Statements *ConditionalStatement::flatten(Scope *sc) -{ - Statement *s; - - if (condition->include(sc, NULL)) - s = ifbody; - else - s = elsebody; - - Statements *a = new Statements(); - a->push(s); - return a; -} - -int ConditionalStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int ConditionalStatement::blockExit() -{ - int result = ifbody->blockExit(); - if (elsebody) - result |= elsebody->blockExit(); - return result; -} - -void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (ifbody) - ifbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - if (elsebody) - { - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - } - buf->writenl(); -} - - -/******************************** PragmaStatement ***************************/ - -PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) - : Statement(loc) -{ - this->ident = ident; - this->args = args; - this->body = body; -} - -Statement *PragmaStatement::syntaxCopy() -{ - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; -} - -Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration - //printf("PragmaStatement::semantic() %s\n", toChars()); - //printf("body = %p\n", body); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (Expression *)args->data[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKstring) - { - StringExp *se = (StringExp *)e; - fprintf(stdmsg, "%.*s", (int)se->len, (char*)se->string); - } - else - error("string expected for message, not '%s'", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - } - else if (ident == Id::lib) - { -#if 1 - /* Should this be allowed? - */ - error("pragma(lib) not allowed as statement"); -#else - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (Expression *)args->data[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - if (e->op != TOKstring) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } -#endif - } - - // LDC - else if (ident == Id::allow_inline) - { - sc->func->allowInlining = true; - } -#if DMDV2 - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (Expression *)args->data[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->data[0] = (void *)e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - if (body) - { - body = body->semantic(sc); - } - return this; - } - } -#endif - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (body) - { - body = body->semantic(sc); - } - return body; -} - -int PragmaStatement::usesEH() -{ - return body && body->usesEH(); -} - -int PragmaStatement::blockExit() -{ - int result = BEfallthru; -#if 0 // currently, no code is generated for Pragma's, so it's just fallthru - if (arrayExpressionCanThrow(args)) - result |= BEthrow; - if (body) - result |= body->blockExit(); -#endif - return result; -} - - -void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("pragma ("); - buf->writestring(ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - if (body) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - - body->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - - -/******************************** StaticAssertStatement ***************************/ - -StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) - : Statement(sa->loc) -{ - this->sa = sa; -} - -Statement *StaticAssertStatement::syntaxCopy() -{ - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; -} - -Statement *StaticAssertStatement::semantic(Scope *sc) -{ - sa->semantic2(sc); - return NULL; -} - -void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - sa->toCBuffer(buf, hgs); -} - - -/******************************** SwitchStatement ***************************/ - -SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal) - : Statement(loc) -{ - this->condition = c; - this->body = b; - this->isFinal = isFinal; - sdefault = NULL; - cases = NULL; - hasNoDefault = 0; - hasVars = 0; -#if IN_LLVM - enclosingScopeExit = NULL; -#endif -} - -Statement *SwitchStatement::syntaxCopy() -{ - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy(), isFinal); - return s; -} - -Statement *SwitchStatement::semantic(Scope *sc) -{ - //printf("SwitchStatement::semantic(%p)\n", this); - assert(!cases); // ensure semantic() is only run once - -#if IN_LLVM - enclosingScopeExit = sc->enclosingScopeExit; -#endif - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - if (condition->type->isString()) - { - // If it's not an array, cast it to one - if (condition->type->ty != Tarray) - { - condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); - } - condition->type = condition->type->constOf(); - } - else - { condition = condition->integralPromotions(sc); - condition->checkIntegral(); - } - condition = condition->optimize(WANTvalue); - - sc = sc->push(); - sc->sbreak = this; - sc->sw = this; - - cases = new Array(); - sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead - body = body->semantic(sc); - sc->noctor--; - - // Resolve any goto case's with exp - for (int i = 0; i < gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->error("no case statement following goto case;"); - break; - } - - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (!scx->sw) - continue; - for (int j = 0; j < scx->sw->cases->dim; j++) - { - CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; - - if (cs->exp->equals(gcs->exp)) - { - gcs->cs = cs; - goto Lfoundcase; - } - } - } - gcs->error("case %s not found", gcs->exp->toChars()); - - Lfoundcase: - ; - } - - if (!sc->sw->sdefault && !isFinal) - { hasNoDefault = 1; - - warning("switch statement has no default"); - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(4); - a->push(body); - - // LDC needs semantic to be run on break - Statement *breakstmt = new BreakStatement(loc, NULL); - breakstmt->semantic(sc); - a->push(breakstmt); - - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - cs = new CompoundStatement(loc, a); - body = cs; - } - -#if DMDV2 - if (isFinal) - { Type *t = condition->type; - while (t->ty == Ttypedef) - { // Don't use toBasetype() because that will skip past enums - t = ((TypeTypedef *)t)->sym->basetype; - } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; - EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); - assert(ed); - size_t dim = ed->members->dim; - for (size_t i = 0; i < dim; i++) - { - EnumMember *em = ((Dsymbol *)ed->members->data[i])->isEnumMember(); - if (em) - { - for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = (CaseStatement *)cases->data[j]; - if (cs->exp->equals(em->value)) - goto L1; - } - error("enum member %s not represented in final switch", em->toChars()); - } - L1: - ; - } - } - } -#endif - - sc->pop(); - return this; -} - -int SwitchStatement::hasBreak() -{ - return TRUE; -} - -int SwitchStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int SwitchStatement::blockExit() -{ int result = BEnone; - if (condition->canThrow()) - result |= BEthrow; - - if (body) - { result |= body->blockExit(); - if (result & BEbreak) - { result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - - return result; -} - - -void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("switch ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - { - if (!body->isScopeStatement()) - { buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { - body->toCBuffer(buf, hgs); - } - } -} - -/******************************** CaseStatement ***************************/ - -CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) - : Statement(loc) -{ - this->exp = exp; - this->statement = s; - index = 0; - cblock = NULL; - bodyBB = NULL; - llvmIdx = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *CaseStatement::syntaxCopy() -{ - CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseStatement::semantic() %s\n", toChars()); - exp = exp->semantic(sc); - if (sw) - { -#if IN_LLVM - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sw->enclosingScopeExit) - { - error("case must be inside the same try, synchronized or volatile level as switch"); - } -#endif - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue | WANTinterpret); - - /* This is where variables are allowed as case expressions. - */ - if (exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - Type *t = exp->type->toBasetype(); - if (v && (t->isintegral() || t->ty == Tclass)) - { /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw->hasVars = 1; - if (sw->isFinal) - error("case variables not allowed in final switch statements"); - goto L1; - } - } - - if (exp->op != TOKstring && exp->op != TOKint64) - { - error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); - } - - L1: - for (int i = 0; i < sw->cases->dim; i++) - { - CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; - - //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); - if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); - break; - } - } - - sw->cases->push(this); - - // Resolve any goto case's with no exp to this case statement - for (int i = 0; i < sw->gotoCases.dim; i++) - { - GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; - - if (!gcs->exp) - { - gcs->cs = this; - sw->gotoCases.remove(i); // remove from array - } - } -#if IN_DMD - if (sc->sw->tf != sc->tf) - error("switch and case are in different finally blocks"); -#endif - } - else - error("case not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int CaseStatement::compare(Object *obj) -{ - // Sort cases so we can do an efficient lookup - CaseStatement *cs2 = (CaseStatement *)(obj); - - return exp->compare(cs2->exp); -} - -int CaseStatement::usesEH() -{ - return statement->usesEH(); -} - -int CaseStatement::blockExit() -{ - return statement->blockExit(); -} - - -int CaseStatement::comeFrom() -{ - return TRUE; -} - -void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - exp->toCBuffer(buf, hgs); - buf->writebyte(':'); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -/******************************** CaseRangeStatement ***************************/ - -#if DMDV2 - -CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, - Expression *last, Statement *s) - : Statement(loc) -{ - this->first = first; - this->last = last; - this->statement = s; -} - -Statement *CaseRangeStatement::syntaxCopy() -{ - CaseRangeStatement *s = new CaseRangeStatement(loc, - first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseRangeStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseRangeStatement::semantic() %s\n", toChars()); - if (sw->isFinal) - error("case ranges not allowed in final switch"); - - first = first->semantic(sc); - first = first->implicitCastTo(sc, sw->condition->type); - first = first->optimize(WANTvalue | WANTinterpret); - dinteger_t fval = first->toInteger(); - - last = last->semantic(sc); - last = last->implicitCastTo(sc, sw->condition->type); - last = last->optimize(WANTvalue | WANTinterpret); - dinteger_t lval = last->toInteger(); - - if (lval - fval > 256) - { error("more than 256 cases in case range"); - lval = fval + 256; - } - - /* This works by replacing the CaseRange with an array of Case's. - * - * case a: .. case b: s; - * => - * case a: - * [...] - * case b: - * s; - */ - - Statements *statements = new Statements(); - for (dinteger_t i = fval; i <= lval; i++) - { - Statement *s = statement; - if (i != lval) - s = new ExpStatement(loc, NULL); - Expression *e = new IntegerExp(loc, i, first->type); - Statement *cs = new CaseStatement(loc, e, s); - statements->push(cs); - } - Statement *s = new CompoundStatement(loc, statements); - s = s->semantic(sc); - return s; -} - -void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - first->toCBuffer(buf, hgs); - buf->writestring(": .. case "); - last->toCBuffer(buf, hgs); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -#endif - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - //printf("DefaultStatement::semantic()\n"); - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - -#if IN_LLVM - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sc->sw->enclosingScopeExit) - { - error("default must be inside the same try, synchronized or volatile level as switch"); - } - - if (sc->sw->isFinal) - { - error("default statement not allowed in final switch statement"); - } -#endif - } - else - error("default not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int DefaultStatement::usesEH() -{ - return statement->usesEH(); -} - -int DefaultStatement::blockExit() -{ - return statement->blockExit(); -} - - -int DefaultStatement::comeFrom() -{ - return TRUE; -} - -void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("default:\n"); - statement->toCBuffer(buf, hgs); -} - -/******************************** GotoDefaultStatement ***************************/ - -GotoDefaultStatement::GotoDefaultStatement(Loc loc) - : Statement(loc) -{ - sw = NULL; -} - -Statement *GotoDefaultStatement::syntaxCopy() -{ - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; -} - -Statement *GotoDefaultStatement::semantic(Scope *sc) -{ - sw = sc->sw; - if (!sw) - error("goto default not in switch statement"); - return this; -} - -int GotoDefaultStatement::blockExit() -{ - return BEgoto; -} - - -void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto default;\n"); -} - -/******************************** GotoCaseStatement ***************************/ - -GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - cs = NULL; - this->exp = exp; - sw = NULL; -} - -Statement *GotoCaseStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; -} - -Statement *GotoCaseStatement::semantic(Scope *sc) -{ - if (exp) - exp = exp->semantic(sc); - - if (!sc->sw) - error("goto case not in switch statement"); - else - { - sw = sc->sw; - sc->sw->gotoCases.push(this); - if (exp) - { - exp = exp->implicitCastTo(sc, sc->sw->condition->type); - exp = exp->optimize(WANTvalue); - } - } - return this; -} - -int GotoCaseStatement::blockExit() -{ - return BEgoto; -} - - -void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto case"); - if (exp) - { buf->writebyte(' '); - exp->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SwitchErrorStatement ***************************/ - -SwitchErrorStatement::SwitchErrorStatement(Loc loc) - : Statement(loc) -{ -} - -int SwitchErrorStatement::blockExit() -{ - return BEthrow; -} - - -void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("SwitchErrorStatement::toCBuffer()"); - buf->writenl(); -} - -/******************************** ReturnStatement ***************************/ - -ReturnStatement::ReturnStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ReturnStatement::syntaxCopy() -{ - Expression *e = NULL; - if (exp) - e = exp->syntaxCopy(); - ReturnStatement *s = new ReturnStatement(loc, e); - return s; -} - -Statement *ReturnStatement::semantic(Scope *sc) -{ - //printf("ReturnStatement::semantic() %s\n", toChars()); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - Scope *scx = sc; - int implicit0 = 0; - - if (sc->fes) - { - // Find scope of function foreach is in - for (; 1; scx = scx->enclosing) - { - assert(scx); - if (scx->func != fd) - { fd = scx->func; // fd is now function enclosing foreach - break; - } - } - } - - Type *tret = fd->type->nextOf(); - if (fd->tintro) - /* We'll be implicitly casting the return expression to tintro - */ - tret = fd->tintro->nextOf(); - Type *tbret = NULL; - - if (tret) - tbret = tret->toBasetype(); - - // main() returns 0, even if it returns void - if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) - { implicit0 = 1; - exp = new IntegerExp(0); - } - - if (sc->incontract || scx->incontract) - error("return statements cannot be in contracts"); - if (sc->enclosingFinally || scx->enclosingFinally) - error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); - - if (fd->isCtorDeclaration()) - { - // Constructors implicitly do: - // return this; - if (exp && exp->op != TOKthis) - error("cannot return expression from constructor"); - exp = new ThisExp(0); - } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) - { - fd->hasReturnExp |= 1; - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue); - - if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (((TypeFunction *)fd->type)->isref) - // Function returns a reference - fd->nrvo_can = 0; - else if (!v || v->isOut() || v->isRef()) - fd->nrvo_can = 0; - else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor) - // Struct being returned has destructors - fd->nrvo_can = 0; - else if (fd->nrvo_var == NULL) - { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) - { //printf("Setting nrvo to %s\n", v->toChars()); - fd->nrvo_var = v; - } - else - fd->nrvo_can = 0; - } - else if (fd->nrvo_var != v) - fd->nrvo_can = 0; - } - else - fd->nrvo_can = 0; - - if (fd->returnLabel && tbret->ty != Tvoid) - { - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (!exp->type->equals(fd->type->nextOf())) - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), fd->type->nextOf()->toChars()); - } - else - { - ((TypeFunction *)fd->type)->next = exp->type; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - } - else if (tbret->ty != Tvoid) - { - exp = exp->implicitCastTo(sc, tret); - exp = exp->optimize(WANTvalue); - } - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (fd->type->nextOf()->ty != Tvoid) - error("mismatched function return type inference of void and %s", - fd->type->nextOf()->toChars()); - } - else - { - ((TypeFunction *)fd->type)->next = Type::tvoid; - fd->type = fd->type->semantic(loc, sc); - if (!fd->tintro) - { tret = Type::tvoid; - tbret = tret; - } - } - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases.push(this); - // Construct: return cases.dim+1; - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(0, NULL); - sc->fes->cases.push(s); - - // Construct: { exp; return cases.dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { // Declare vresult - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noauto = 1; - v->semantic(scx); - if (!scx->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - s = new ReturnStatement(0, new VarExp(0, fd->vresult)); - sc->fes->cases.push(s); - - // Construct: { vresult = exp; return cases.dim + 1; } - exp = new AssignExp(loc, new VarExp(0, fd->vresult), exp); - exp->op = TOKconstruct; - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (fd->returnLabel && tbret->ty != Tvoid) - { - assert(fd->vresult); - VarExp *v = new VarExp(0, fd->vresult); - - exp = new AssignExp(loc, v, exp); - exp->op = TOKconstruct; - exp = exp->semantic(sc); - } - - if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) - { // Function returns a reference - if (tbret->isMutable()) - exp = exp->modifiableLvalue(sc, exp); - else - exp = exp->toLvalue(sc, exp); - - if (exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && !v->isDataseg() && !(v->storage_class & (STCref | STCout))) - error("escaping reference to local variable %s", v->toChars()); - } - } - - //exp->dump(0); - //exp->print(); - exp->checkEscape(); - } - - /* BUG: need to issue an error on: - * this - * { if (x) return; - * super(); - * } - */ - - if (sc->callSuper & CSXany_ctor && - !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) - error("return without calling constructor"); - - sc->callSuper |= CSXreturn; - - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) - { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) - { /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !fd->isMain()) - { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - loc = 0; - exp = NULL; - return new CompoundStatement(loc, s, this); - } - - return this; -} - -int ReturnStatement::blockExit() -{ int result = BEreturn; - - if (exp && exp->canThrow()) - result |= BEthrow; - return result; -} - - -void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("return "); - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** BreakStatement ***************************/ - -BreakStatement::BreakStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - //printf("BreakStatement::semantic()\n"); - // If: - // break Identifier; - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases.push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - return s; - } - break; // can't break to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasBreak()) - error("label '%s' has no break", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot break out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for break not found", ident->toChars()); - } - else if (!sc->sbreak) - { - if (sc->fes) - { Statement *s; - - // Replace break; with return 1; - s = new ReturnStatement(0, new IntegerExp(1)); - return s; - } - error("break is not inside a loop or switch"); - } - return this; -} - -int BreakStatement::blockExit() -{ - //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); - return ident ? BEgoto : BEbreak; -} - - -void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("break"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** ContinueStatement ***************************/ - -ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *ContinueStatement::syntaxCopy() -{ - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; -} - -Statement *ContinueStatement::semantic(Scope *sc) -{ - //printf("ContinueStatement::semantic() %p\n", this); - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - for (; scx; scx = scx->enclosing) - { - ls = scx->slabel; - if (ls && ls->ident == ident && ls->statement == sc->fes) - { - // Replace continue ident; with return 0; - return new ReturnStatement(0, new IntegerExp(0)); - } - } - - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases.push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases.dim + 1)); - return s; - } - break; // can't continue to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasContinue()) - error("label '%s' has no continue", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot continue out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for continue not found", ident->toChars()); - } - else if (!sc->scontinue) - { - if (sc->fes) - { Statement *s; - - // Replace continue; with return 0; - s = new ReturnStatement(0, new IntegerExp(0)); - return s; - } - error("continue is not inside a loop"); - } - return this; -} - -int ContinueStatement::blockExit() -{ - return ident ? BEgoto : BEcontinue; -} - - -void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("continue"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SynchronizedStatement ***************************/ - -SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - this->esync = NULL; - // LDC - this->llsync = NULL; -} - -SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) - : Statement(loc) -{ - this->exp = NULL; - this->body = body; - this->esync = esync; - // LDC - this->llsync = NULL; -} - -Statement *SynchronizedStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *SynchronizedStatement::semantic(Scope *sc) -{ - if (exp) - { - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - ClassDeclaration *cd = exp->type->isClassHandle(); - if (!cd) - error("can only synchronize on class objects, not '%s'", exp->type->toChars()); - else if (cd->isInterfaceDeclaration()) - { /* Cast the interface to an object, as the object has the monitor, - * not the interface. - */ - Type *t = new TypeIdentifier(0, Id::Object); - - t = t->semantic(0, sc); - exp = new CastExp(loc, exp, t); - exp = exp->semantic(sc); - } - -#if 1 - /* Rewrite as: - * auto tmp = exp; - * _d_monitorenter(tmp); - * try { body } finally { _d_monitorexit(tmp); } - */ - Identifier *id = Lexer::uniqueId("__sync"); - ExpInitializer *ie = new ExpInitializer(loc, exp); - VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); - - Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - -#if IN_LLVM - // LDC: Build args - Arguments* args = new Arguments; - args->push(new Argument(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter); -#endif - Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - -#if IN_LLVM - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorexit); -#endif - e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); -#endif - } -#if 1 - else - { /* Generate our own critical section, then rewrite as: - * __gshared byte[CriticalSection.sizeof] critsec; - * _d_criticalenter(critsec.ptr); - * try { body } finally { _d_criticalexit(critsec.ptr); } - */ - Identifier *id = Lexer::uniqueId("__critsec"); - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); - VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); - tmp->storage_class |= STCgshared | STCstatic; - - Statements *cs = new Statements(); - cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); - -#if IN_LLVM - // LDC: Build args - Arguments* args = new Arguments; - args->push(new Argument(STCin, t->pointerTo(), NULL, NULL)); - - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter); -#endif - Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdenter), e); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - -#if IN_LLVM - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit); -#endif - e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdexit), e); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); - } -#endif - if (body) - { - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - body = body->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - } - return this; -} - -int SynchronizedStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::usesEH() -{ - return TRUE; -} - -int SynchronizedStatement::blockExit() -{ - return body ? body->blockExit() : BEfallthru; -} - - -void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("synchronized"); - if (exp) - { buf->writebyte('('); - exp->toCBuffer(buf, hgs); - buf->writebyte(')'); - } - if (body) - { - buf->writebyte(' '); - body->toCBuffer(buf, hgs); - } -} - -/******************************** WithStatement ***************************/ - -WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - wthis = NULL; -} - -Statement *WithStatement::syntaxCopy() -{ - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - Initializer *init; - - //printf("WithStatement::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKimport) - { ScopeExp *es = (ScopeExp *)exp; - - sym = es->sds; - } - else if (exp->op == TOKtype) - { TypeExp *es = (TypeExp *)exp; - - sym = es->type->toDsymbol(sc)->isScopeDsymbol(); - if (!sym) - { error("%s has no members", es->toChars()); - body = body->semantic(sc); - return this; - } - } - else - { Type *t = exp->type; - - assert(t); - t = t->toBasetype(); - if (t->isClassHandle()) - { - init = new ExpInitializer(loc, exp); - wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); - wthis->semantic(sc); - - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else if (t->ty == Tstruct) - { - Expression *e = exp->addressOf(sc); - init = new ExpInitializer(loc, e); - wthis = new VarDeclaration(loc, e->type, Id::withSym, init); - wthis->semantic(sc); - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); - return NULL; - } - } - sc = sc->push(sym); - - if (body) - body = body->semantic(sc); - - sc->pop(); - - return this; -} - -void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("with ("); - exp->toCBuffer(buf, hgs); - buf->writestring(")\n"); - if (body) - body->toCBuffer(buf, hgs); -} - -int WithStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WithStatement::blockExit() -{ - int result = BEnone; - if (exp->canThrow()) - result = BEthrow; - if (body) - result |= body->blockExit(); - else - result |= BEfallthru; - return result; -} - - -/******************************** TryCatchStatement ***************************/ - -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) - : Statement(loc) -{ - this->body = body; - this->catches = catches; -} - -Statement *TryCatchStatement::syntaxCopy() -{ - Array *a = new Array(); - a->setDim(catches->dim); - for (int i = 0; i < a->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; - c = c->syntaxCopy(); - a->data[i] = c; - } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; -} - -Statement *TryCatchStatement::semantic(Scope *sc) -{ - body = body->semanticScope(sc, NULL /*this*/, NULL); - - /* Even if body is NULL, still do semantic analysis on catches - */ - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (Catch *)catches->data[i]; - c->semantic(sc); - - // Determine if current catch 'hides' any previous catches - for (size_t j = 0; j < i; j++) - { Catch *cj = (Catch *)catches->data[j]; - char *si = c->loc.toChars(); - char *sj = cj->loc.toChars(); - - if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) - error("catch at %s hides catch at %s", sj, si); - } - } - - if (!body || body->isEmpty()) - { - return NULL; - } - return this; -} - -int TryCatchStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryCatchStatement::usesEH() -{ - return TRUE; -} - -int TryCatchStatement::blockExit() -{ - assert(body); - int result = body->blockExit(); - - int catchresult = 0; - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (Catch *)catches->data[i]; - catchresult |= c->blockExit(); - - /* If we're catching Object, then there is no throwing - */ - Identifier *id = c->type->toBasetype()->isClassHandle()->ident; - if (i == 0 && - (id == Id::Object || id == Id::Throwable || id == Id::Exception)) - { - result &= ~BEthrow; - } - } - return result | catchresult; -} - - -void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("try"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (Catch *)catches->data[i]; - c->toCBuffer(buf, hgs); - } -} - -/******************************** Catch ***************************/ - -Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) -{ - //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); - this->loc = loc; - this->type = t; - this->ident = id; - this->handler = handler; - var = NULL; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - return c; -} - -void Catch::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("Catch::semantic(%s)\n", ident->toChars()); - -#ifndef IN_GCC - if (sc->enclosingFinally) - { - /* This is because the _d_local_unwind() gets the stack munged - * up on this. The workaround is to place any try-catches into - * a separate function, and call that. - * To fix, have the compiler automatically convert the finally - * body into a nested function. - */ - error(loc, "cannot put catch statement inside finally block"); - } -#endif - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Object); - type = type->semantic(loc, sc); - if (!type->toBasetype()->isClassHandle()) - error("can only catch class objects, not '%s'", type->toChars()); - else if (ident) - { - var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; - sc->insert(var); - } - handler = handler->semantic(sc); - - sc->pop(); -} - -int Catch::blockExit() -{ - return handler ? handler->blockExit() : BEfallthru; -} - -void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("catch"); - if (type) - { buf->writebyte('('); - type->toCBuffer(buf, ident, hgs); - buf->writebyte(')'); - } - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (handler) - handler->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/****************************** TryFinallyStatement ***************************/ - -TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) - : Statement(loc) -{ - this->body = body; - this->finalbody = finalbody; -} - -Statement *TryFinallyStatement::syntaxCopy() -{ - TryFinallyStatement *s = new TryFinallyStatement(loc, - body->syntaxCopy(), finalbody->syntaxCopy()); - return s; -} - -Statement *TryFinallyStatement::semantic(Scope *sc) -{ - //printf("TryFinallyStatement::semantic()\n"); - - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - body = body->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - - sc = sc->push(); - sc->enclosingFinally = this; - sc->sbreak = NULL; - sc->scontinue = NULL; // no break or continue out of finally block - finalbody = finalbody->semantic(sc); - sc->pop(); - if (!body) - return finalbody; - if (!finalbody) - return body; - if (body->blockExit() == BEfallthru) - { Statement *s = new CompoundStatement(loc, body, finalbody); - return s; - } - return this; -} - -void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("try\n{\n"); - body->toCBuffer(buf, hgs); - buf->printf("}\nfinally\n{\n"); - finalbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); -} - -int TryFinallyStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::usesEH() -{ - return TRUE; -} - -int TryFinallyStatement::blockExit() -{ - if (body) - return body->blockExit(); - return BEfallthru; -} - - -/****************************** OnScopeStatement ***************************/ - -OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) - : Statement(loc) -{ - this->tok = tok; - this->statement = statement; -} - -Statement *OnScopeStatement::syntaxCopy() -{ - OnScopeStatement *s = new OnScopeStatement(loc, - tok, statement->syntaxCopy()); - return s; -} - -Statement *OnScopeStatement::semantic(Scope *sc) -{ - /* semantic is called on results of scopeCode() */ - return this; -} - -int OnScopeStatement::blockExit() -{ // At this point, this statement is just an empty placeholder - return BEfallthru; -} - -void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(tok)); - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); -} - -int OnScopeStatement::usesEH() -{ - return 1; -} - -void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("OnScopeStatement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - switch (tok) - { - case TOKon_scope_exit: - *sfinally = statement; - break; - - case TOKon_scope_failure: - *sexception = statement; - break; - - case TOKon_scope_success: - { - /* Create: - * sentry: int x = 0; - * sexception: x = 1; - * sfinally: if (!x) statement; - */ - Identifier *id = Lexer::uniqueId("__os"); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); - VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new DeclarationStatement(loc, v); - - Expression *e = new IntegerExp(1); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - - if (sc->incontract) - error("Throw statements cannot be in contracts"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (!exp->type->toBasetype()->isClassHandle()) - error("can only throw class objects, not type %s", exp->type->toChars()); - return this; -} - -int ThrowStatement::blockExit() -{ - return BEthrow; // obviously -} - - -void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("throw "); - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** VolatileStatement **************************/ - -VolatileStatement::VolatileStatement(Loc loc, Statement *statement) - : Statement(loc) -{ - this->statement = statement; -} - -Statement *VolatileStatement::syntaxCopy() -{ - VolatileStatement *s = new VolatileStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; -} - -Statement *VolatileStatement::semantic(Scope *sc) -{ - if (statement) - { - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - statement = statement->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - } - return this; -} - -Statements *VolatileStatement::flatten(Scope *sc) -{ - Statements *a; - - a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (int i = 0; i < a->dim; i++) - { Statement *s = (Statement *)a->data[i]; - - s = new VolatileStatement(loc, s); - a->data[i] = s; - } - } - - return a; -} - -int VolatileStatement::blockExit() -{ - return statement ? statement->blockExit() : BEfallthru; -} - - -void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("volatile"); - if (statement) - { if (statement->isScopeStatement()) - buf->writenl(); - else - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); - } -} - - -/******************************** GotoStatement ***************************/ - -GotoStatement::GotoStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->label = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; -} - -Statement *GotoStatement::syntaxCopy() -{ - GotoStatement *s = new GotoStatement(loc, ident); - return s; -} - -Statement *GotoStatement::semantic(Scope *sc) -{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("GotoStatement::semantic()\n"); - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - label = fd->searchLabel(ident); - if (!label->statement && sc->fes) - { - /* Either the goto label is forward referenced or it - * is in the function that the enclosing foreach is in. - * Can't know yet, so wrap the goto in a compound statement - * so we can patch it later, and add it to a 'look at this later' - * list. - */ - Statements *a = new Statements(); - Statement *s; - - a->push(this); - s = new CompoundStatement(loc, a); - sc->fes->gotos.push(s); // 'look at this later' list - return s; - } - if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) - error("cannot goto in or out of finally block"); - return this; -} - -int GotoStatement::blockExit() -{ - //printf("GotoStatement::blockExit(%p)\n", this); - return BEgoto; -} - - -void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto "); - buf->writestring(ident->toChars()); - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** LabelStatement ***************************/ - -LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) - : Statement(loc) -{ - this->ident = ident; - this->statement = statement; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->lblock = NULL; - this->isReturnLabel = 0; - this->asmLabel = false; -} - -Statement *LabelStatement::syntaxCopy() -{ - LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); - return s; -} - -Statement *LabelStatement::semantic(Scope *sc) -{ LabelDsymbol *ls; - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("LabelStatement::semantic()\n"); - ls = fd->searchLabel(ident); - if (ls->statement) - error("Label '%s' already defined", ls->toChars()); - else - ls->statement = this; - - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - sc = sc->push(); - sc->scopesym = sc->enclosing->scopesym; - sc->callSuper |= CSXlabel; - sc->slabel = this; - if (statement) - statement = statement->semantic(sc); - sc->pop(); - - // LDC put in labmap - fd->labmap[ident->toChars()] = this; - - return this; -} - -Statements *LabelStatement::flatten(Scope *sc) -{ - Statements *a = NULL; - - if (statement) - { - a = statement->flatten(sc); - if (a) - { - if (!a->dim) - { - a->push(new ExpStatement(loc, NULL)); - } - Statement *s = (Statement *)a->data[0]; - - s = new LabelStatement(loc, ident, s); - a->data[0] = s; - } - } - - return a; -} - - -int LabelStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int LabelStatement::blockExit() -{ - //printf("LabelStatement::blockExit(%p)\n", this); - return statement ? statement->blockExit() : BEfallthru; -} - - -int LabelStatement::comeFrom() -{ - //printf("LabelStatement::comeFrom()\n"); - return TRUE; -} - -void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writebyte(':'); - buf->writenl(); - if (statement) - statement->toCBuffer(buf, hgs); -} - - -/******************************** LabelDsymbol ***************************/ - -LabelDsymbol::LabelDsymbol(Identifier *ident) - : Dsymbol(ident) -{ - statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif -} - -LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? -{ - return this; -} + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include + +#include "rmem.h" + +#include "statement.h" +#include "expression.h" +#include "cond.h" +#include "init.h" +#include "staticassert.h" +#include "mtype.h" +#include "scope.h" +#include "declaration.h" +#include "aggregate.h" +#include "id.h" +#include "hdrgen.h" +#include "parse.h" +#include "template.h" +#include "attrib.h" + +#if IN_LLVM +// sizes based on those from tollvm.cpp:DtoMutexType() +int os_critsecsize() +{ + if (global.params.os == OSWindows) + return 68; + else if (global.params.os == OSFreeBSD) + return sizeof(size_t); + else + return sizeof(pthread_mutex_t); +} +#elif IN_DMD +extern int os_critsecsize(); +#endif + +/******************************** Statement ***************************/ + +Statement::Statement(Loc loc) + : loc(loc) +{ +#ifdef _DH + // If this is an in{} contract scope statement (skip for determining + // inlineStatus of a function body for header content) + incontract = 0; +#endif +} + +Statement *Statement::syntaxCopy() +{ + assert(0); + return NULL; +} + +void Statement::print() +{ + fprintf(stdmsg, "%s\n", toChars()); + fflush(stdmsg); +} + +char *Statement::toChars() +{ OutBuffer *buf; + HdrGenState hgs; + + buf = new OutBuffer(); + toCBuffer(buf, &hgs); + return buf->toChars(); +} + +void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("Statement::toCBuffer()"); + buf->writenl(); +} + +Statement *Statement::semantic(Scope *sc) +{ + return this; +} + +Statement *Statement::semanticNoScope(Scope *sc) +{ + //printf("Statement::semanticNoScope() %s\n", toChars()); + Statement *s = this; + if (!s->isCompoundStatement() && !s->isScopeStatement()) + { + s = new CompoundStatement(loc, this); // so scopeCode() gets called + } + s = s->semantic(sc); + return s; +} + +// Same as semanticNoScope(), but do create a new scope + +Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) +{ + Scope *scd = sc->push(); + if (sbreak) + scd->sbreak = sbreak; + if (scontinue) + scd->scontinue = scontinue; + Statement *s = semanticNoScope(scd); + scd->pop(); + return s; +} + +void Statement::error(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::verror(loc, format, ap); + va_end( ap ); +} + +void Statement::warning(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + ::vwarning(loc, format, ap); + va_end( ap ); +} + +int Statement::hasBreak() +{ + //printf("Statement::hasBreak()\n"); + return FALSE; +} + +int Statement::hasContinue() +{ + return FALSE; +} + +// TRUE if statement uses exception handling + +int Statement::usesEH() +{ + return FALSE; +} + +/* Only valid after semantic analysis + */ +int Statement::blockExit() +{ + printf("Statement::blockExit(%p)\n", this); + printf("%s\n", toChars()); + assert(0); + return BEany; +} + +// TRUE if statement 'comes from' somewhere else, like a goto + +int Statement::comeFrom() +{ + //printf("Statement::comeFrom()\n"); + return FALSE; +} + +// Return TRUE if statement has no code in it +int Statement::isEmpty() +{ + //printf("Statement::isEmpty()\n"); + return FALSE; +} + +/**************************************** + * If this statement has code that needs to run in a finally clause + * at the end of the current scope, return that code in the form of + * a Statement. + * Output: + * *sentry code executed upon entry to the scope + * *sexception code executed upon exit from the scope via exception + * *sfinally code executed in finally block + */ + +void Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("Statement::scopeCode()\n"); + //print(); + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; +} + +/********************************* + * Flatten out the scope by presenting the statement + * as an array of statements. + * Returns NULL if no flattening necessary. + */ + +Statements *Statement::flatten(Scope *sc) +{ + return NULL; +} + + +/******************************** PeelStatement ***************************/ + +PeelStatement::PeelStatement(Statement *s) + : Statement(s->loc) +{ + this->s = s; +} + +Statement *PeelStatement::semantic(Scope *sc) +{ + /* "peel" off this wrapper, and don't run semantic() + * on the result. + */ + return s; +} + +/******************************** ExpStatement ***************************/ + +ExpStatement::ExpStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ExpStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + ExpStatement *es = new ExpStatement(loc, e); + return es; +} + +void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + if (exp) + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); +} + +Statement *ExpStatement::semantic(Scope *sc) +{ + if (exp) + { + //printf("ExpStatement::semantic() %s\n", exp->toChars()); + +#if 0 // Doesn't work because of difficulty dealing with things like a.b.c!(args).Foo!(args) + // See if this should be rewritten as a TemplateMixin + if (exp->op == TOKdeclaration) + { DeclarationExp *de = (DeclarationExp *)exp; + Dsymbol *s = de->declaration; + + printf("s: %s %s\n", s->kind(), s->toChars()); + VarDeclaration *v = s->isVarDeclaration(); + if (v) + { + printf("%s, %d\n", v->type->toChars(), v->type->ty); + } + } +#endif + + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp->checkSideEffect(0); + exp = exp->optimize(0); + if (exp->op == TOKdeclaration && !isDeclarationStatement()) + { Statement *s = new DeclarationStatement(loc, exp); + return s; + } + //exp = exp->optimize(isDeclarationStatement() ? WANTvalue : 0); + } + return this; +} + +int ExpStatement::blockExit() +{ int result = BEfallthru; + + if (exp) + { + if (exp->op == TOKhalt) + return BEhalt; + if (exp->op == TOKassert) + { AssertExp *a = (AssertExp *)exp; + + if (a->e1->isBool(FALSE)) // if it's an assert(0) + return BEhalt; + } + if (exp->canThrow()) + result |= BEthrow; + } + return result; +} + +int ExpStatement::isEmpty() +{ + return exp == NULL; +} + + +/******************************** CompileStatement ***************************/ + +CompileStatement::CompileStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *CompileStatement::syntaxCopy() +{ + Expression *e = exp->syntaxCopy(); + CompileStatement *es = new CompileStatement(loc, e); + return es; +} + +void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin("); + exp->toCBuffer(buf, hgs); + buf->writestring(");"); + if (!hgs->FLinit.init) + buf->writenl(); +} + +Statements *CompileStatement::flatten(Scope *sc) +{ + //printf("CompileStatement::flatten() %s\n", exp->toChars()); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue | WANTinterpret); + if (exp->op != TOKstring) + { error("argument to mixin must be a string, not (%s)", exp->toChars()); + return NULL; + } + StringExp *se = (StringExp *)exp; + se = se->toUTF8(sc); + Parser p(sc->module, (unsigned char *)se->string, se->len, 0); + p.loc = loc; + p.nextToken(); + + Statements *a = new Statements(); + while (p.token.value != TOKeof) + { + Statement *s = p.parseStatement(PSsemi | PScurlyscope); + a->push(s); + } + return a; +} + +Statement *CompileStatement::semantic(Scope *sc) +{ + //printf("CompileStatement::semantic() %s\n", exp->toChars()); + Statements *a = flatten(sc); + if (!a) + return NULL; + Statement *s = new CompoundStatement(loc, a); + return s->semantic(sc); +} + + +/******************************** DeclarationStatement ***************************/ + +DeclarationStatement::DeclarationStatement(Loc loc, Dsymbol *declaration) + : ExpStatement(loc, new DeclarationExp(loc, declaration)) +{ +} + +DeclarationStatement::DeclarationStatement(Loc loc, Expression *exp) + : ExpStatement(loc, exp) +{ +} + +Statement *DeclarationStatement::syntaxCopy() +{ + DeclarationStatement *ds = new DeclarationStatement(loc, exp->syntaxCopy()); + return ds; +} + +void DeclarationStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("DeclarationStatement::scopeCode()\n"); + //print(); + + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + + if (exp) + { + if (exp->op == TOKdeclaration) + { + DeclarationExp *de = (DeclarationExp *)(exp); + VarDeclaration *v = de->declaration->isVarDeclaration(); + if (v) + { Expression *e; + + e = v->callScopeDtor(sc); + if (e) + { + //printf("dtor is: "); e->print(); +#if 0 + if (v->type->toBasetype()->ty == Tstruct) + { /* Need a 'gate' to turn on/off destruction, + * in case v gets moved elsewhere. + */ + Identifier *id = Lexer::uniqueId("__runDtor"); + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); + VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new DeclarationStatement(loc, rd); + v->rundtor = rd; + + /* Rewrite e as: + * rundtor && e + */ + Expression *ve = new VarExp(loc, v->rundtor); + e = new AndAndExp(loc, ve, e); + e->type = Type::tbool; + } +#endif + *sfinally = new ExpStatement(loc, e); + } + } + } + } +} + +void DeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + exp->toCBuffer(buf, hgs); +} + + +/******************************** CompoundStatement ***************************/ + +CompoundStatement::CompoundStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) + : Statement(loc) +{ + statements = new Statements(); + statements->reserve(2); + statements->push(s1); + statements->push(s2); +} + +CompoundStatement::CompoundStatement(Loc loc, Statement *s1) + : Statement(loc) +{ + statements = new Statements(); + statements->push(s1); +} + +Statement *CompoundStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + CompoundStatement *cs = new CompoundStatement(loc, a); + return cs; +} + + +Statement *CompoundStatement::semantic(Scope *sc) +{ Statement *s; + + //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); + + for (size_t i = 0; i < statements->dim; ) + { + s = (Statement *) statements->data[i]; + if (s) + { Statements *a = s->flatten(sc); + + if (a) + { + statements->remove(i); + statements->insert(i, a); + continue; + } + s = s->semantic(sc); + statements->data[i] = s; + if (s) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + s->scopeCode(sc, &sentry, &sexception, &sfinally); + if (sentry) + { + sentry = sentry->semantic(sc); + if (s->isDeclarationStatement()) + { statements->insert(i, sentry); + i++; + } + else + statements->data[i] = sentry; + } + if (sexception) + { + if (i + 1 == statements->dim && !sfinally) + { +#if 1 + sexception = sexception->semantic(sc); +#else + statements->push(sexception); + if (sfinally) + // Assume sexception does not throw + statements->push(sfinally); +#endif + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; + * try { s1; s2; } + * catch (Object __o) + * { sexception; throw __o; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + body = new ScopeStatement(0, body); + + Identifier *id = Lexer::uniqueId("__o"); + + Statement *handler = new ThrowStatement(0, new IdentifierExp(0, id)); + handler = new CompoundStatement(0, sexception, handler); + + Array *catches = new Array(); + Catch *ctch = new Catch(0, NULL, id, handler); + catches->push(ctch); + s = new TryCatchStatement(0, body, catches); + + if (sfinally) + s = new TryFinallyStatement(0, s, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + else if (sfinally) + { + if (0 && i + 1 == statements->dim) + { + statements->push(sfinally); + } + else + { + /* Rewrite: + * s; s1; s2; + * As: + * s; try { s1; s2; } finally { sfinally; } + */ + Statement *body; + Statements *a = new Statements(); + + for (int j = i + 1; j < statements->dim; j++) + { + a->push(statements->data[j]); + } + body = new CompoundStatement(0, a); + s = new TryFinallyStatement(0, body, sfinally); + s = s->semantic(sc); + statements->setDim(i + 1); + statements->push(s); + break; + } + } + } + } + i++; + } + if (statements->dim == 1 && !isAsmBlockStatement()) + { + return (Statement *)statements->data[0]; + } + return this; +} + +Statements *CompoundStatement::flatten(Scope *sc) +{ + return statements; +} + +ReturnStatement *CompoundStatement::isReturnStatement() +{ + ReturnStatement *rs = NULL; + + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + rs = s->isReturnStatement(); + if (rs) + break; + } + } + return rs; +} + +void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } +} + +int CompoundStatement::usesEH() +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int CompoundStatement::blockExit() +{ + //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); + int result = BEfallthru; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { +//printf("result = x%x\n", result); +//printf("%s\n", s->toChars()); + if (!(result & BEfallthru) && !s->comeFrom()) + { + if (s->blockExit() != BEhalt && !s->isEmpty()) + s->warning("statement is not reachable"); + } + else + { + result &= ~BEfallthru; + result |= s->blockExit(); + } + } + } + return result; +} + +int CompoundStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("CompoundStatement::comeFrom()\n"); + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + +int CompoundStatement::isEmpty() +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && !s->isEmpty()) + return FALSE; + } + return TRUE; +} + + +/******************************** CompoundDeclarationStatement ***************************/ + +CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s) + : CompoundStatement(loc, s) +{ + statements = s; +} + +Statement *CompoundDeclarationStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); + return cs; +} + +void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + int nwritten = 0; + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { DeclarationStatement *ds = s->isDeclarationStatement(); + assert(ds); + DeclarationExp *de = (DeclarationExp *)ds->exp; + assert(de->op == TOKdeclaration); + Declaration *d = de->declaration->isDeclaration(); + assert(d); + VarDeclaration *v = d->isVarDeclaration(); + if (v) + { + /* This essentially copies the part of VarDeclaration::toCBuffer() + * that does not print the type. + * Should refactor this. + */ + if (nwritten) + { + buf->writeByte(','); + buf->writestring(v->ident->toChars()); + } + else + { + StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); + if (v->type) + v->type->toCBuffer(buf, v->ident, hgs); + else + buf->writestring(v->ident->toChars()); + } + + if (v->init) + { buf->writestring(" = "); +#if DMDV2 + ExpInitializer *ie = v->init->isExpInitializer(); + if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) + ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); + else +#endif + v->init->toCBuffer(buf, hgs); + } + } + else + d->toCBuffer(buf, hgs); + nwritten++; + } + } + buf->writeByte(';'); + if (!hgs->FLinit.init) + buf->writenl(); +} + +/**************************** UnrolledLoopStatement ***************************/ + +UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) + : Statement(loc) +{ + statements = s; +} + +Statement *UnrolledLoopStatement::syntaxCopy() +{ + Statements *a = new Statements(); + a->setDim(statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + if (s) + s = s->syntaxCopy(); + a->data[i] = s; + } + UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); + return cs; +} + + +Statement *UnrolledLoopStatement::semantic(Scope *sc) +{ + //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); + + sc->noctor++; + Scope *scd = sc->push(); + scd->sbreak = this; + scd->scontinue = this; + + for (size_t i = 0; i < statements->dim; i++) + { + Statement *s = (Statement *) statements->data[i]; + if (s) + { + //printf("[%d]: %s\n", i, s->toChars()); + s = s->semantic(scd); + statements->data[i] = s; + } + } + + scd->pop(); + sc->noctor--; + return this; +} + +void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("unrolled {"); + buf->writenl(); + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s; + + s = (Statement *) statements->data[i]; + if (s) + s->toCBuffer(buf, hgs); + } + + buf->writeByte('}'); + buf->writenl(); +} + +int UnrolledLoopStatement::hasBreak() +{ + return TRUE; +} + +int UnrolledLoopStatement::hasContinue() +{ + return TRUE; +} + +int UnrolledLoopStatement::usesEH() +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s && s->usesEH()) + return TRUE; + } + return FALSE; +} + +int UnrolledLoopStatement::blockExit() +{ + int result = BEfallthru; + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + int r = s->blockExit(); + result |= r & ~(BEbreak | BEcontinue); + } + } + return result; +} + + +int UnrolledLoopStatement::comeFrom() +{ int comefrom = FALSE; + + //printf("UnrolledLoopStatement::comeFrom()\n"); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *)statements->data[i]; + + if (!s) + continue; + + comefrom |= s->comeFrom(); + } + return comefrom; +} + + +/******************************** ScopeStatement ***************************/ + +ScopeStatement::ScopeStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +} + +Statement *ScopeStatement::syntaxCopy() +{ + Statement *s; + + s = statement ? statement->syntaxCopy() : NULL; + s = new ScopeStatement(loc, s); + return s; +} + + +Statement *ScopeStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("ScopeStatement::semantic(sc = %p)\n", sc); + if (statement) + { Statements *a; + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + a = statement->flatten(sc); + if (a) + { + statement = new CompoundStatement(loc, a); + } + + statement = statement->semantic(sc); + if (statement) + { + Statement *sentry; + Statement *sexception; + Statement *sfinally; + + statement->scopeCode(sc, &sentry, &sexception, &sfinally); + if (sfinally) + { + //printf("adding sfinally\n"); + sfinally = sfinally->semantic(sc); + statement = new CompoundStatement(loc, statement, sfinally); + } + } + + sc->pop(); + } + return this; +} + +int ScopeStatement::hasBreak() +{ + //printf("ScopeStatement::hasBreak() %s\n", toChars()); + return statement ? statement->hasBreak() : FALSE; +} + +int ScopeStatement::hasContinue() +{ + return statement ? statement->hasContinue() : FALSE; +} + +int ScopeStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int ScopeStatement::blockExit() +{ + //printf("ScopeStatement::blockExit(%p)\n", statement); + return statement ? statement->blockExit() : BEfallthru; +} + + +int ScopeStatement::comeFrom() +{ + //printf("ScopeStatement::comeFrom()\n"); + return statement ? statement->comeFrom() : FALSE; +} + +int ScopeStatement::isEmpty() +{ + //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); + return statement ? statement->isEmpty() : TRUE; +} + +void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writeByte('{'); + buf->writenl(); + + if (statement) + statement->toCBuffer(buf, hgs); + + buf->writeByte('}'); + buf->writenl(); +} + +/******************************** WhileStatement ***************************/ + +WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) + : Statement(loc) +{ + condition = c; + body = b; +} + +Statement *WhileStatement::syntaxCopy() +{ + WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + + +Statement *WhileStatement::semantic(Scope *sc) +{ + /* Rewrite as a for(;condition;) loop + */ + + Statement *s = new ForStatement(loc, NULL, condition, NULL, body); + s = s->semantic(sc); + return s; +} + +int WhileStatement::hasBreak() +{ + return TRUE; +} + +int WhileStatement::hasContinue() +{ + return TRUE; +} + +int WhileStatement::usesEH() +{ + assert(0); + return body ? body->usesEH() : 0; +} + +int WhileStatement::blockExit() +{ + assert(0); + //printf("WhileStatement::blockExit(%p)\n", this); + + int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + if (condition->isBool(TRUE)) + { + if (body) + { result |= body->blockExit(); + if (result & BEbreak) + result |= BEfallthru; + } + } + else if (condition->isBool(FALSE)) + { + result |= BEfallthru; + } + else + { + if (body) + result |= body->blockExit(); + result |= BEfallthru; + } + result &= ~(BEbreak | BEcontinue); + return result; +} + + +int WhileStatement::comeFrom() +{ + assert(0); + if (body) + return body->comeFrom(); + return FALSE; +} + +void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("while ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); +} + +/******************************** DoStatement ***************************/ + +DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) + : Statement(loc) +{ + body = b; + condition = c; +} + +Statement *DoStatement::syntaxCopy() +{ + DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); + return s; +} + + +Statement *DoStatement::semantic(Scope *sc) +{ + sc->noctor++; + if (body) + body = body->semanticScope(sc, this, this); + sc->noctor--; + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + + condition = condition->checkToBoolean(sc); + + return this; +} + +int DoStatement::hasBreak() +{ + return TRUE; +} + +int DoStatement::hasContinue() +{ + return TRUE; +} + +int DoStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int DoStatement::blockExit() +{ int result; + + if (body) + { result = body->blockExit(); + if (result == BEbreak) + return BEfallthru; + if (result & BEcontinue) + result |= BEfallthru; + } + else + result = BEfallthru; + if (result & BEfallthru) + { + if (condition->canThrow()) + result |= BEthrow; + if (!(result & BEbreak) && condition->isBool(TRUE)) + result &= ~BEfallthru; + } + result &= ~(BEbreak | BEcontinue); + return result; +} + + +int DoStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("do"); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writestring("while ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); +} + +/******************************** ForStatement ***************************/ + +ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) + : Statement(loc) +{ + this->init = init; + this->condition = condition; + this->increment = increment; + this->body = body; +} + +Statement *ForStatement::syntaxCopy() +{ + Statement *i = NULL; + if (init) + i = init->syntaxCopy(); + Expression *c = NULL; + if (condition) + c = condition->syntaxCopy(); + Expression *inc = NULL; + if (increment) + inc = increment->syntaxCopy(); + ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); + return s; +} + +Statement *ForStatement::semantic(Scope *sc) +{ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + if (init) + init = init->semantic(sc); + sc->noctor++; + if (condition) + { + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->optimize(WANTvalue); + condition = condition->checkToBoolean(sc); + } + if (increment) + { increment = increment->semantic(sc); + increment = resolveProperties(sc, increment); + increment = increment->optimize(0); + } + + sc->sbreak = this; + sc->scontinue = this; + if (body) + body = body->semanticNoScope(sc); + sc->noctor--; + + sc->pop(); + return this; +} + +void ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("ForStatement::scopeCode()\n"); + //print(); + if (init) + init->scopeCode(sc, sentry, sexception, sfinally); + else + Statement::scopeCode(sc, sentry, sexception, sfinally); +} + +int ForStatement::hasBreak() +{ + //printf("ForStatement::hasBreak()\n"); + return TRUE; +} + +int ForStatement::hasContinue() +{ + return TRUE; +} + +int ForStatement::usesEH() +{ + return (init && init->usesEH()) || body->usesEH(); +} + +int ForStatement::blockExit() +{ int result = BEfallthru; + + if (init) + { result = init->blockExit(); + if (!(result & BEfallthru)) + return result; + } + if (condition) + { if (condition->canThrow()) + result |= BEthrow; + if (condition->isBool(TRUE)) + result &= ~BEfallthru; + else if (condition->isBool(FALSE)) + return result; + } + else + result &= ~BEfallthru; // the body must do the exiting + if (body) + { int r = body->blockExit(); + if (r & (BEbreak | BEgoto)) + result |= BEfallthru; + result |= r & ~(BEfallthru | BEbreak | BEcontinue); + } + if (increment && increment->canThrow()) + result |= BEthrow; + return result; +} + + +int ForStatement::comeFrom() +{ + //printf("ForStatement::comeFrom()\n"); + if (body) + { int result = body->comeFrom(); + //printf("result = %d\n", result); + return result; + } + return FALSE; +} + +void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("for ("); + if (init) + { + hgs->FLinit.init++; + init->toCBuffer(buf, hgs); + hgs->FLinit.init--; + } + else + buf->writebyte(';'); + if (condition) + { buf->writebyte(' '); + condition->toCBuffer(buf, hgs); + } + buf->writebyte(';'); + if (increment) + { buf->writebyte(' '); + increment->toCBuffer(buf, hgs); + } + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/******************************** ForeachStatement ***************************/ + +ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, + Expression *aggr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arguments = arguments; + this->aggr = aggr; + this->body = body; + + this->key = NULL; + this->value = NULL; + + this->func = NULL; + + this->cases = NULL; + this->gotos = NULL; +} + +Statement *ForeachStatement::syntaxCopy() +{ + Parameters *args = Parameter::arraySyntaxCopy(arguments); + Expression *exp = aggr->syntaxCopy(); + ForeachStatement *s = new ForeachStatement(loc, op, args, exp, + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachStatement::semantic(Scope *sc) +{ + //printf("ForeachStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + size_t dim = arguments->dim; + TypeAArray *taa = NULL; + Dsymbol *sapply = NULL; + + Type *tn = NULL; + Type *tnv = NULL; + + func = sc->func; + if (func->fes) + func = func->fes->func; + + aggr = aggr->semantic(sc); + aggr = resolveProperties(sc, aggr); + aggr = aggr->optimize(WANTvalue); + if (!aggr->type) + { + error("invalid foreach aggregate %s", aggr->toChars()); + return this; + } + + inferApplyArgTypes(op, arguments, aggr, sc->module); + + /* Check for inference errors + */ + if (dim != arguments->dim) + { + //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); + error("cannot uniquely infer foreach argument types"); + return this; + } + + Type *tab = aggr->type->toBasetype(); + + if (tab->ty == Ttuple) // don't generate new scope for tuple loops + { + if (dim < 1 || dim > 2) + { + error("only one (value) or two (key,value) arguments for tuple foreach"); + return s; + } + + TypeTuple *tuple = (TypeTuple *)tab; + Statements *statements = new Statements(); + //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); + size_t n; + TupleExp *te = NULL; + if (aggr->op == TOKtuple) // expression tuple + { te = (TupleExp *)aggr; + n = te->exps->dim; + } + else if (aggr->op == TOKtype) // type tuple + { + n = Parameter::dim(tuple->arguments); + } + else + assert(0); + for (size_t j = 0; j < n; j++) + { size_t k = (op == TOKforeach) ? j : n - 1 - j; + Expression *e; + Type *t; + if (te) + e = (Expression *)te->exps->data[k]; + else + t = Parameter::getNth(tuple->arguments, k)->type; + Parameter *arg = (Parameter *)arguments->data[0]; + Statements *st = new Statements(); + + if (dim == 2) + { // Declare key + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for key %s", arg->ident->toChars()); + TY keyty = arg->type->ty; + if (keyty != Tint32 && keyty != Tuns32) + { + if (global.params.is64bit) + { + if (keyty != Tint64 && keyty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); + } + else + error("foreach: key type must be int or uint, not %s", arg->type->toChars()); + } + Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); + VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); + var->storage_class |= STCmanifest; + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + arg = (Parameter *)arguments->data[1]; // value + } + // Declare value + if (arg->storageClass & (STCout | STCref | STClazy)) + error("no storage class for value %s", arg->ident->toChars()); + Dsymbol *var; + if (te) + { Type *tb = e->type->toBasetype(); + if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) + { VarExp *ve = (VarExp *)e; + var = new AliasDeclaration(loc, arg->ident, ve->var); + } + else + { + arg->type = e->type; + Initializer *ie = new ExpInitializer(0, e); + VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); + if (e->isConst() || e->op == TOKstring) + v->storage_class |= STCconst; + var = v; + } + } + else + { + var = new AliasDeclaration(loc, arg->ident, t); + } + DeclarationExp *de = new DeclarationExp(loc, var); + st->push(new ExpStatement(loc, de)); + + st->push(body->syntaxCopy()); + s = new CompoundStatement(loc, st); + s = new ScopeStatement(loc, s); + statements->push(s); + } + + s = new UnrolledLoopStatement(loc, statements); + s = s->semantic(sc); + return s; + } + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + sc->noctor++; + +Lagain: + Identifier *idapply = (op == TOKforeach_reverse) + ? Id::applyReverse : Id::apply; + sapply = NULL; + switch (tab->ty) + { + case Tarray: + case Tsarray: + if (!checkForArgTypes()) + return this; + + if (dim < 1 || dim > 2) + { + error("only one or two arguments for array foreach"); + break; + } + + /* Look for special case of parsing char types out of char type + * array. + */ + tn = tab->nextOf()->toBasetype(); + if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) + { Parameter *arg; + + int i = (dim == 1) ? 0 : 1; // index of value + arg = (Parameter *)arguments->data[i]; + arg->type = arg->type->semantic(loc, sc); + tnv = arg->type->toBasetype(); + if (tnv->ty != tn->ty && + (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) + { + if (arg->storageClass & STCref) + error("foreach: value of UTF conversion cannot be ref"); + if (dim == 2) + { arg = (Parameter *)arguments->data[0]; + if (arg->storageClass & STCref) + error("foreach: key cannot be ref"); + } + goto Lapply; + } + } + + for (size_t i = 0; i < dim; i++) + { // Declare args + Parameter *arg = (Parameter *)arguments->data[i]; + Type *argtype = arg->type->semantic(loc, sc); + VarDeclaration *var; + + var = new VarDeclaration(loc, argtype, arg->ident, NULL); + var->storage_class |= STCforeach; + var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + if (var->storage_class & (STCref | STCout)) + var->storage_class |= STCnodtor; + if (dim == 2 && i == 0) + { key = var; + //var->storage_class |= STCfinal; + } + else + { + value = var; + /* Reference to immutable data should be marked as const + */ + if (var->storage_class & STCref && !tn->isMutable()) + { + var->storage_class |= STCconst; + } + } +#if 0 + DeclarationExp *de = new DeclarationExp(loc, var); + de->semantic(sc); +#endif + } + +#if 1 + { + /* Convert to a ForStatement + * foreach (key, value; a) body => + * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) + * { T value = tmp[k]; body } + * + * foreach_reverse (key, value; a) body => + * for (T[] tmp = a[], size_t key = tmp.length; key--; ) + * { T value = tmp[k]; body } + */ + Identifier *id = Lexer::uniqueId("__aggr"); + ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); + VarDeclaration *tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie); + + Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); + + if (!key) + { + Identifier *id = Lexer::uniqueId("__key"); + key = new VarDeclaration(loc, Type::tsize_t, id, NULL); + } + if (op == TOKforeach_reverse) + key->init = new ExpInitializer(loc, tmp_length); + else + key->init = new ExpInitializer(loc, new IntegerExp(0)); + + Statements *cs = new Statements(); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + Statement *forinit = new CompoundDeclarationStatement(loc, cs); + + Expression *cond; + if (op == TOKforeach_reverse) + // key-- + cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); + else + // key < tmp.length + cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length); + + Expression *increment = NULL; + if (op == TOKforeach) + // key += 1 + increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + + // T value = tmp[key]; + value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); + Statement *ds = new DeclarationStatement(loc, new DeclarationExp(loc, value)); + + body = new CompoundStatement(loc, ds, body); + + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); + s = fs->semantic(sc); + break; + } +#else + if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst) + { + if (aggr->op == TOKstring) + aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); + else + error("foreach: %s is not an array of %s", + tab->toChars(), value->type->toChars()); + } + + if (key) + { + if (key->type->ty != Tint32 && key->type->ty != Tuns32) + { + if (global.params.isX86_64) + { + if (key->type->ty != Tint64 && key->type->ty != Tuns64) + error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); + } + else + error("foreach: key type must be int or uint, not %s", key->type->toChars()); + } + + if (key->storage_class & (STCout | STCref)) + error("foreach: key cannot be out or ref"); + } + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + break; +#endif + + case Taarray: + if (!checkForArgTypes()) + return this; + + taa = (TypeAArray *)tab; + if (dim < 1 || dim > 2) + { + error("only one or two arguments for associative array foreach"); + break; + } +#if SARRAYVALUE + /* This only works if Key or Value is a static array. + */ + tab = taa->getImpl()->type; + goto Lagain; +#else + if (op == TOKforeach_reverse) + { + error("no reverse iteration on associative arrays"); + } + goto Lapply; +#endif + case Tclass: + case Tstruct: +#if DMDV2 + /* Prefer using opApply, if it exists + */ + if (dim != 1) // only one argument allowed with ranges + goto Lapply; + + sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); + if (sapply) + goto Lapply; + + { /* Look for range iteration, i.e. the properties + * .empty, .next, .retreat, .head and .rear + * foreach (e; aggr) { ... } + * translates to: + * for (auto __r = aggr[]; !__r.empty; __r.next) + * { auto e = __r.head; + * ... + * } + */ + AggregateDeclaration *ad = (tab->ty == Tclass) + ? (AggregateDeclaration *)((TypeClass *)tab)->sym + : (AggregateDeclaration *)((TypeStruct *)tab)->sym; + Identifier *idhead; + Identifier *idnext; + if (op == TOKforeach) + { idhead = Id::Fhead; + idnext = Id::Fnext; + } + else + { idhead = Id::Ftoe; + idnext = Id::Fretreat; + } + Dsymbol *shead = search_function(ad, idhead); + if (!shead) + goto Lapply; + + /* Generate a temporary __r and initialize it with the aggregate. + */ + Identifier *id = Identifier::generateId("__r"); + Expression *rinit = new SliceExp(loc, aggr, NULL, NULL); + rinit = rinit->trySemantic(sc); + if (!rinit) // if application of [] failed + rinit = aggr; + VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, rinit)); +// r->semantic(sc); +//printf("r: %s, init: %s\n", r->toChars(), r->init->toChars()); + Statement *init = new DeclarationStatement(loc, r); +//printf("init: %s\n", init->toChars()); + + // !__r.empty + Expression *e = new VarExp(loc, r); + e = new DotIdExp(loc, e, Id::Fempty); + Expression *condition = new NotExp(loc, e); + + // __r.next + e = new VarExp(loc, r); + Expression *increment = new DotIdExp(loc, e, idnext); + + /* Declaration statement for e: + * auto e = __r.idhead; + */ + e = new VarExp(loc, r); + Expression *einit = new DotIdExp(loc, e, idhead); +// einit = einit->semantic(sc); + Parameter *arg = (Parameter *)arguments->data[0]; + VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); + ve->storage_class |= STCforeach; + ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); + + DeclarationExp *de = new DeclarationExp(loc, ve); + + Statement *body = new CompoundStatement(loc, + new DeclarationStatement(loc, de), this->body); + + s = new ForStatement(loc, init, condition, increment, body); +#if 0 + printf("init: %s\n", init->toChars()); + printf("condition: %s\n", condition->toChars()); + printf("increment: %s\n", increment->toChars()); + printf("body: %s\n", body->toChars()); +#endif + s = s->semantic(sc); + break; + } +#endif + case Tdelegate: + Lapply: + { + FuncDeclaration *fdapply; + Expression *ec; + Expression *e; + Parameter *a; + TypeDelegate* dgty; + TypeDelegate* dgty2; + TypeDelegate* fldeTy; + + if (!checkForArgTypes()) + { body = body->semanticNoScope(sc); + return this; + } + + Type *tret = func->type->nextOf(); + + // Need a variable to hold value from any return statements in body. + if (!sc->func->vresult && tret && tret != Type::tvoid) + { + VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noscope = 1; + v->semantic(sc); + if (!sc->insert(v)) + assert(0); + v->parent = sc->func; + sc->func->vresult = v; + } + + /* Turn body into the function literal: + * int delegate(ref T arg) { body } + */ + Parameters *args = new Parameters(); + for (size_t i = 0; i < dim; i++) + { Parameter *arg = (Parameter *)arguments->data[i]; + Identifier *id; + + arg->type = arg->type->semantic(loc, sc); + if (arg->storageClass & STCref) + id = arg->ident; + else + { // Make a copy of the ref argument so it isn't + // a reference. + + id = Lexer::uniqueId("__applyArg", i); + Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); + VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); + s = new DeclarationStatement(0, v); + body = new CompoundStatement(loc, s, body); + } + a = new Parameter(STCref, arg->type, id, NULL); + args->push(a); + } + Type *t = new TypeFunction(args, Type::tint32, 0, LINKd); + cases = new Array(); + gotos = new Array(); + FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, t, TOKdelegate, this); + fld->fbody = body; + Expression *flde = new FuncExp(loc, fld); + flde = flde->semantic(sc); + fld->tookAddressOf = 0; + + // Resolve any forward referenced goto's + for (size_t i = 0; i < gotos->dim; i++) + { CompoundStatement *cs = (CompoundStatement *)gotos->data[i]; + GotoStatement *gs = (GotoStatement *)cs->statements->data[0]; + + if (!gs->label->statement) + { // 'Promote' it to this scope, and replace with a return + cases->push(gs); + s = new ReturnStatement(0, new IntegerExp(cases->dim + 1)); + cs->statements->data[0] = (void *)s; + } + } + + if (tab->ty == Taarray) + { + // Check types + Parameter *arg = (Parameter *)arguments->data[0]; + if (dim == 2) + { + if (arg->storageClass & STCref) + error("foreach: index cannot be ref"); + if (!arg->type->equals(taa->index)) + error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); + arg = (Parameter *)arguments->data[1]; + } + if (!arg->type->equals(taa->nextOf())) + error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); + + /* Call: + * _aaApply(aggr, keysize, flde) + */ + //LDC: Build arguments. + static FuncDeclaration *aaApply2_fd = NULL; + static TypeDelegate* aaApply2_dg; + if(!aaApply2_fd) { + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); + args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); + Parameters* dgargs = new Parameters; + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Parameter(STCin, aaApply2_dg, NULL, NULL)); + aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2"); + } + static FuncDeclaration *aaApply_fd = NULL; + static TypeDelegate* aaApply_dg; + if(!aaApply_fd) { + Parameters* args = new Parameters; + args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); + args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); + Parameters* dgargs = new Parameters; + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Parameter(STCin, aaApply_dg, NULL, NULL)); + aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply"); + } + if (dim == 2) { + fdapply = aaApply2_fd; + fldeTy = aaApply2_dg; + } else { + fdapply = aaApply_fd; + fldeTy = aaApply_dg; + } + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + exps->push(aggr); + size_t keysize = taa->index->size(); + keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); + exps->push(new IntegerExp(0, keysize, Type::tsize_t)); + +#if IN_LLVM + // LDC paint delegate argument to the type runtime expects + if (!fldeTy->equals(flde->type)) + { + flde = new CastExp(loc, flde, flde->type); + flde->type = fldeTy; + } +#endif + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tarray || tab->ty == Tsarray) + { + /* Call: + * _aApply(aggr, flde) + */ + static char fntab[9][3] = + { "cc","cw","cd", + "wc","cc","wd", + "dc","dw","dd" + }; + char fdname[7+1+2+ sizeof(dim)*3 + 1]; + int flag; + + switch (tn->ty) + { + case Tchar: flag = 0; break; + case Twchar: flag = 3; break; + case Tdchar: flag = 6; break; + default: assert(0); + } + switch (tnv->ty) + { + case Tchar: flag += 0; break; + case Twchar: flag += 1; break; + case Tdchar: flag += 2; break; + default: assert(0); + } + const char *r = (op == TOKforeach_reverse) ? "R" : ""; +#ifdef __MINGW32__ + int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); +#else + int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); +#endif + assert(j < sizeof(fdname)); + //LDC: Build arguments. + Parameters* args = new Parameters; + args->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL)); + if (dim == 2) { + Parameters* dgargs = new Parameters; + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Parameter(STCin, dgty, NULL, NULL)); + fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); + } else { + Parameters* dgargs = new Parameters; + dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); + dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd)); + args->push(new Parameter(STCin, dgty, NULL, NULL)); + fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname); + } + + ec = new VarExp(0, fdapply); + Expressions *exps = new Expressions(); + if (tab->ty == Tsarray) + aggr = aggr->castTo(sc, tn->arrayOf()); + exps->push(aggr); + + // LDC paint delegate argument to the type runtime expects + if (!dgty->equals(flde->type)) + { + flde = new CastExp(loc, flde, flde->type); + flde->type = dgty; + } + exps->push(flde); + e = new CallExp(loc, ec, exps); + e->type = Type::tindex; // don't run semantic() on e + } + else if (tab->ty == Tdelegate) + { + /* Call: + * aggr(flde) + */ + Expressions *exps = new Expressions(); + exps->push(flde); + if (aggr->op == TOKdelegate && + ((DelegateExp *)aggr)->func->isNested()) + // See Bugzilla 3560 + e = new CallExp(loc, ((DelegateExp *)aggr)->e1, exps); + else + e = new CallExp(loc, aggr, exps); + e = e->semantic(sc); + if (e->type != Type::tint32) + error("opApply() function for %s must return an int", tab->toChars()); + } + else + { + assert(tab->ty == Tstruct || tab->ty == Tclass); + Expressions *exps = new Expressions(); + if (!sapply) + sapply = search_function((AggregateDeclaration *)tab->toDsymbol(sc), idapply); +#if 0 + TemplateDeclaration *td; + if (sapply && + (td = sapply->isTemplateDeclaration()) != NULL) + { /* Call: + * aggr.apply!(fld)() + */ + Objects *tiargs = new Objects(); + tiargs->push(fld); + ec = new DotTemplateInstanceExp(loc, aggr, idapply, tiargs); + } + else +#endif + { + /* Call: + * aggr.apply(flde) + */ + ec = new DotIdExp(loc, aggr, idapply); + exps->push(flde); + } + e = new CallExp(loc, ec, exps); + e = e->semantic(sc); + if (e->type != Type::tint32) + error("opApply() function for %s must return an int", tab->toChars()); + } + + if (!cases->dim) + // Easy case, a clean exit from the loop + s = new ExpStatement(loc, e); + else + { // Construct a switch statement around the return value + // of the apply function. + Statements *a = new Statements(); + + // default: break; takes care of cases 0 and 1 + s = new BreakStatement(0, NULL); + s = new DefaultStatement(0, s); + a->push(s); + + // cases 2... + for (int i = 0; i < cases->dim; i++) + { + s = (Statement *)cases->data[i]; + s = new CaseStatement(0, new IntegerExp(i + 2), s); + a->push(s); + } + + s = new CompoundStatement(loc, a); + s = new SwitchStatement(loc, e, s, FALSE); + s = s->semantic(sc); + } + break; + } + + default: + error("foreach: %s is not an aggregate type", aggr->type->toChars()); + s = NULL; // error recovery + break; + } + sc->noctor--; + sc->pop(); + return s; +} + +bool ForeachStatement::checkForArgTypes() +{ bool result = TRUE; + + for (size_t i = 0; i < arguments->dim; i++) + { Parameter *arg = (Parameter *)arguments->data[i]; + if (!arg->type) + { + error("cannot infer type for %s", arg->ident->toChars()); + arg->type = Type::terror; + result = FALSE; + } + } + return result; +} + +int ForeachStatement::hasBreak() +{ + return TRUE; +} + +int ForeachStatement::hasContinue() +{ + return TRUE; +} + +int ForeachStatement::usesEH() +{ + return body->usesEH(); +} + +int ForeachStatement::blockExit() +{ int result = BEfallthru; + + if (aggr->canThrow()) + result |= BEthrow; + + if (body) + { + result |= body->blockExit() & ~(BEbreak | BEcontinue); + } + return result; +} + + +int ForeachStatement::comeFrom() +{ + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + for (int i = 0; i < arguments->dim; i++) + { + Parameter *a = (Parameter *)arguments->data[i]; + if (i) + buf->writestring(", "); + if (a->storageClass & STCref) + buf->writestring((global.params.Dversion == 1) + ? (char*)"inout " : (char*)"ref "); + if (a->type) + a->type->toCBuffer(buf, a->ident, hgs); + else + buf->writestring(a->ident->toChars()); + } + buf->writestring("; "); + aggr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/**************************** ForeachRangeStatement ***************************/ + +#if DMDV2 + +ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, + Expression *lwr, Expression *upr, Statement *body) + : Statement(loc) +{ + this->op = op; + this->arg = arg; + this->lwr = lwr; + this->upr = upr; + this->body = body; + + this->key = NULL; +} + +Statement *ForeachRangeStatement::syntaxCopy() +{ + ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, + arg->syntaxCopy(), + lwr->syntaxCopy(), + upr->syntaxCopy(), + body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *ForeachRangeStatement::semantic(Scope *sc) +{ + //printf("ForeachRangeStatement::semantic() %p\n", this); + ScopeDsymbol *sym; + Statement *s = this; + + lwr = lwr->semantic(sc); + lwr = resolveProperties(sc, lwr); + lwr = lwr->optimize(WANTvalue); + if (!lwr->type) + { + error("invalid range lower bound %s", lwr->toChars()); + return this; + } + + upr = upr->semantic(sc); + upr = resolveProperties(sc, upr); + upr = upr->optimize(WANTvalue); + if (!upr->type) + { + error("invalid range upper bound %s", upr->toChars()); + return this; + } + + if (arg->type) + { + arg->type = arg->type->semantic(loc, sc); + lwr = lwr->implicitCastTo(sc, arg->type); + upr = upr->implicitCastTo(sc, arg->type); + } + else + { + /* Must infer types from lwr and upr + */ + Type *tlwr = lwr->type->toBasetype(); + if (tlwr->ty == Tstruct || tlwr->ty == Tclass) + { + /* Just picking the first really isn't good enough. + */ + arg->type = lwr->type->mutableOf(); + } + else + { + AddExp ea(loc, lwr, upr); + Expression *e = ea.typeCombine(sc); + arg->type = ea.type->mutableOf(); + lwr = ea.e1; + upr = ea.e2; + } + } +#if 1 + /* Convert to a for loop: + * foreach (key; lwr .. upr) => + * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) + * + * foreach_reverse (key; lwr .. upr) => + * for (auto tmp = lwr, auto key = upr; key-- > tmp;) + */ + + ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); + key = new VarDeclaration(loc, arg->type, arg->ident, ie); + + Identifier *id = Lexer::uniqueId("__limit"); + ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); + VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie); + + Statements *cs = new Statements(); + // Keep order of evaluation as lwr, then upr + if (op == TOKforeach) + { + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + } + else + { + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, key))); + } + Statement *forinit = new CompoundDeclarationStatement(loc, cs); + + Expression *cond; + if (op == TOKforeach_reverse) + { + cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); + if (arg->type->isscalar()) + // key-- > tmp + cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); + else + // key-- != tmp + cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp)); + } + else + { + if (arg->type->isscalar()) + // key < tmp + cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); + else + // key != tmp + cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, key), new VarExp(loc, tmp)); + } + + Expression *increment = NULL; + if (op == TOKforeach) + // key += 1 + //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); + increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, key)); + + ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); + s = fs->semantic(sc); + return s; +#else + if (!arg->type->isscalar()) + error("%s is not a scalar type", arg->type->toChars()); + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + sc->noctor++; + + key = new VarDeclaration(loc, arg->type, arg->ident, NULL); + DeclarationExp *de = new DeclarationExp(loc, key); + de->semantic(sc); + + if (key->storage_class) + error("foreach range: key cannot have storage class"); + + sc->sbreak = this; + sc->scontinue = this; + body = body->semantic(sc); + + sc->noctor--; + sc->pop(); + return s; +#endif +} + +int ForeachRangeStatement::hasBreak() +{ + return TRUE; +} + +int ForeachRangeStatement::hasContinue() +{ + return TRUE; +} + +int ForeachRangeStatement::usesEH() +{ + assert(0); + return body->usesEH(); +} + +int ForeachRangeStatement::blockExit() +{ + assert(0); + int result = BEfallthru; + + if (lwr && lwr->canThrow()) + result |= BEthrow; + else if (upr && upr->canThrow()) + result |= BEthrow; + + if (body) + { + result |= body->blockExit() & ~(BEbreak | BEcontinue); + } + return result; +} + + +int ForeachRangeStatement::comeFrom() +{ + assert(0); + if (body) + return body->comeFrom(); + return FALSE; +} + +void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(op)); + buf->writestring(" ("); + + if (arg->type) + arg->type->toCBuffer(buf, arg->ident, hgs); + else + buf->writestring(arg->ident->toChars()); + + buf->writestring("; "); + lwr->toCBuffer(buf, hgs); + buf->writestring(" .. "); + upr->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +#endif + +/******************************** IfStatement ***************************/ + +IfStatement::IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody) + : Statement(loc) +{ + this->arg = arg; + this->condition = condition; + this->ifbody = ifbody; + this->elsebody = elsebody; + this->match = NULL; +} + +Statement *IfStatement::syntaxCopy() +{ + Statement *i = NULL; + if (ifbody) + i = ifbody->syntaxCopy(); + + Statement *e = NULL; + if (elsebody) + e = elsebody->syntaxCopy(); + + Parameter *a = arg ? arg->syntaxCopy() : NULL; + IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); + return s; +} + +Statement *IfStatement::semantic(Scope *sc) +{ + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + condition = condition->checkToBoolean(sc); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + condition = condition->optimize(WANTflags); + + // Evaluate at runtime + unsigned cs0 = sc->callSuper; + unsigned cs1; + + Scope *scd; + if (arg) + { /* Declare arg, which we will set to be the + * result of condition. + */ + ScopeDsymbol *sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + scd = sc->push(sym); + + Type *t = arg->type ? arg->type : condition->type; + match = new VarDeclaration(loc, t, arg->ident, NULL); + match->noscope = 1; + match->semantic(scd); + if (!scd->insert(match)) + assert(0); + match->parent = sc->func; + + /* Generate: + * (arg = condition) + */ + VarExp *v = new VarExp(0, match); + condition = new AssignExp(loc, v, condition); + condition = condition->semantic(scd); + } + else + scd = sc->push(); + + ifbody = ifbody->semanticNoScope(scd); + scd->pop(); + + cs1 = sc->callSuper; + sc->callSuper = cs0; + if (elsebody) + elsebody = elsebody->semanticScope(sc, NULL, NULL); + sc->mergeCallSuper(loc, cs1); + + return this; +} + +int IfStatement::usesEH() +{ + return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); +} + +int IfStatement::blockExit() +{ + //printf("IfStatement::blockExit(%p)\n", this); + + int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + if (condition->isBool(TRUE)) + { + if (ifbody) + result |= ifbody->blockExit(); + else + result |= BEfallthru; + } + else if (condition->isBool(FALSE)) + { + if (elsebody) + result |= elsebody->blockExit(); + else + result |= BEfallthru; + } + else + { + if (ifbody) + result |= ifbody->blockExit(); + else + result |= BEfallthru; + if (elsebody) + result |= elsebody->blockExit(); + else + result |= BEfallthru; + } + //printf("IfStatement::blockExit(%p) = x%x\n", this, result); + return result; +} + + +void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("if ("); + if (arg) + { + if (arg->type) + arg->type->toCBuffer(buf, arg->ident, hgs); + else + { buf->writestring("auto "); + buf->writestring(arg->ident->toChars()); + } + buf->writestring(" = "); + } + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + ifbody->toCBuffer(buf, hgs); + if (elsebody) + { buf->writestring("else"); + buf->writenl(); + elsebody->toCBuffer(buf, hgs); + } +} + +/******************************** ConditionalStatement ***************************/ + +ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) + : Statement(loc) +{ + this->condition = condition; + this->ifbody = ifbody; + this->elsebody = elsebody; +} + +Statement *ConditionalStatement::syntaxCopy() +{ + Statement *e = NULL; + if (elsebody) + e = elsebody->syntaxCopy(); + ConditionalStatement *s = new ConditionalStatement(loc, + condition->syntaxCopy(), ifbody->syntaxCopy(), e); + return s; +} + +Statement *ConditionalStatement::semantic(Scope *sc) +{ + //printf("ConditionalStatement::semantic()\n"); + + // If we can short-circuit evaluate the if statement, don't do the + // semantic analysis of the skipped code. + // This feature allows a limited form of conditional compilation. + if (condition->include(sc, NULL)) + { + ifbody = ifbody->semantic(sc); + return ifbody; + } + else + { + if (elsebody) + elsebody = elsebody->semantic(sc); + return elsebody; + } +} + +Statements *ConditionalStatement::flatten(Scope *sc) +{ + Statement *s; + + if (condition->include(sc, NULL)) + s = ifbody; + else + s = elsebody; + + Statements *a = new Statements(); + a->push(s); + return a; +} + +int ConditionalStatement::usesEH() +{ + return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); +} + +int ConditionalStatement::blockExit() +{ + int result = ifbody->blockExit(); + if (elsebody) + result |= elsebody->blockExit(); + return result; +} + +void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + condition->toCBuffer(buf, hgs); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + if (ifbody) + ifbody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); + if (elsebody) + { + buf->writestring("else"); + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + elsebody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); + } + buf->writenl(); +} + + +/******************************** PragmaStatement ***************************/ + +PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) + : Statement(loc) +{ + this->ident = ident; + this->args = args; + this->body = body; +} + +Statement *PragmaStatement::syntaxCopy() +{ + Statement *b = NULL; + if (body) + b = body->syntaxCopy(); + PragmaStatement *s = new PragmaStatement(loc, + ident, Expression::arraySyntaxCopy(args), b); + return s; +} + +Statement *PragmaStatement::semantic(Scope *sc) +{ // Should be merged with PragmaDeclaration + //printf("PragmaStatement::semantic() %s\n", toChars()); + //printf("body = %p\n", body); + if (ident == Id::msg) + { + if (args) + { + for (size_t i = 0; i < args->dim; i++) + { + Expression *e = (Expression *)args->data[i]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKstring) + { + StringExp *se = (StringExp *)e; + fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); + } + else + fprintf(stdmsg, "%s", e->toChars()); + } + fprintf(stdmsg, "\n"); + } + } + else if (ident == Id::lib) + { +#if 1 + /* Should this be allowed? + */ + error("pragma(lib) not allowed as statement"); +#else + if (!args || args->dim != 1) + error("string expected for library name"); + else + { + Expression *e = (Expression *)args->data[0]; + + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + if (e->op != TOKstring) + error("string expected for library name, not '%s'", e->toChars()); + else if (global.params.verbose) + { + StringExp *se = (StringExp *)e; + char *name = (char *)mem.malloc(se->len + 1); + memcpy(name, se->string, se->len); + name[se->len] = 0; + printf("library %s\n", name); + mem.free(name); + } + } +#endif + } + + // LDC + else if (ident == Id::allow_inline) + { + sc->func->allowInlining = true; + } +#if DMDV2 + else if (ident == Id::startaddress) + { + if (!args || args->dim != 1) + error("function name expected for start address"); + else + { + Expression *e = (Expression *)args->data[0]; + e = e->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + args->data[0] = (void *)e; + Dsymbol *sa = getDsymbol(e); + if (!sa || !sa->isFuncDeclaration()) + error("function name expected for start address, not '%s'", e->toChars()); + if (body) + { + body = body->semantic(sc); + } + return this; + } + } +#endif + else + error("unrecognized pragma(%s)", ident->toChars()); + + if (body) + { + body = body->semantic(sc); + } + return body; +} + +int PragmaStatement::usesEH() +{ + return body && body->usesEH(); +} + +int PragmaStatement::blockExit() +{ + int result = BEfallthru; +#if 0 // currently, no code is generated for Pragma's, so it's just fallthru + if (arrayExpressionCanThrow(args)) + result |= BEthrow; + if (body) + result |= body->blockExit(); +#endif + return result; +} + + +void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("pragma ("); + buf->writestring(ident->toChars()); + if (args && args->dim) + { + buf->writestring(", "); + argsToCBuffer(buf, args, hgs); + } + buf->writeByte(')'); + if (body) + { + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + + body->toCBuffer(buf, hgs); + + buf->writeByte('}'); + buf->writenl(); + } + else + { + buf->writeByte(';'); + buf->writenl(); + } +} + + +/******************************** StaticAssertStatement ***************************/ + +StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) + : Statement(sa->loc) +{ + this->sa = sa; +} + +Statement *StaticAssertStatement::syntaxCopy() +{ + StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); + return s; +} + +Statement *StaticAssertStatement::semantic(Scope *sc) +{ + sa->semantic2(sc); + return NULL; +} + +int StaticAssertStatement::blockExit() +{ + return BEfallthru; +} + +void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + sa->toCBuffer(buf, hgs); +} + + +/******************************** SwitchStatement ***************************/ + +SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal) + : Statement(loc) +{ + this->condition = c; + this->body = b; + this->isFinal = isFinal; + sdefault = NULL; + cases = NULL; + hasNoDefault = 0; + hasVars = 0; +#if IN_LLVM + enclosingScopeExit = NULL; +#endif +} + +Statement *SwitchStatement::syntaxCopy() +{ + SwitchStatement *s = new SwitchStatement(loc, + condition->syntaxCopy(), body->syntaxCopy(), isFinal); + return s; +} + +Statement *SwitchStatement::semantic(Scope *sc) +{ + //printf("SwitchStatement::semantic(%p)\n", this); + assert(!cases); // ensure semantic() is only run once + +#if IN_LLVM + enclosingScopeExit = sc->enclosingScopeExit; +#endif + + condition = condition->semantic(sc); + condition = resolveProperties(sc, condition); + if (condition->type->isString()) + { + // If it's not an array, cast it to one + if (condition->type->ty != Tarray) + { + condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); + } + condition->type = condition->type->constOf(); + } + else + { condition = condition->integralPromotions(sc); + condition->checkIntegral(); + } + condition = condition->optimize(WANTvalue); + + sc = sc->push(); + sc->sbreak = this; + sc->sw = this; + + cases = new Array(); + sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead + body = body->semantic(sc); + sc->noctor--; + + // Resolve any goto case's with exp + for (int i = 0; i < gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->error("no case statement following goto case;"); + break; + } + + for (Scope *scx = sc; scx; scx = scx->enclosing) + { + if (!scx->sw) + continue; + for (int j = 0; j < scx->sw->cases->dim; j++) + { + CaseStatement *cs = (CaseStatement *)scx->sw->cases->data[j]; + + if (cs->exp->equals(gcs->exp)) + { + gcs->cs = cs; + goto Lfoundcase; + } + } + } + gcs->error("case %s not found", gcs->exp->toChars()); + + Lfoundcase: + ; + } + + if (!sc->sw->sdefault && !isFinal) + { hasNoDefault = 1; + + warning("switch statement has no default"); + + // Generate runtime error if the default is hit + Statements *a = new Statements(); + CompoundStatement *cs; + Statement *s; + + if (global.params.useSwitchError) + s = new SwitchErrorStatement(loc); + else + { Expression *e = new HaltExp(loc); + s = new ExpStatement(loc, e); + } + + a->reserve(4); + a->push(body); + + // LDC needs semantic to be run on break + Statement *breakstmt = new BreakStatement(loc, NULL); + breakstmt->semantic(sc); + a->push(breakstmt); + + sc->sw->sdefault = new DefaultStatement(loc, s); + a->push(sc->sw->sdefault); + cs = new CompoundStatement(loc, a); + body = cs; + } + +#if DMDV2 + if (isFinal) + { Type *t = condition->type; + while (t->ty == Ttypedef) + { // Don't use toBasetype() because that will skip past enums + t = ((TypeTypedef *)t)->sym->basetype; + } + if (condition->type->ty == Tenum) + { TypeEnum *te = (TypeEnum *)condition->type; + EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); + assert(ed); + size_t dim = ed->members->dim; + for (size_t i = 0; i < dim; i++) + { + EnumMember *em = ((Dsymbol *)ed->members->data[i])->isEnumMember(); + if (em) + { + for (size_t j = 0; j < cases->dim; j++) + { CaseStatement *cs = (CaseStatement *)cases->data[j]; + if (cs->exp->equals(em->value)) + goto L1; + } + error("enum member %s not represented in final switch", em->toChars()); + } + L1: + ; + } + } + } +#endif + + sc->pop(); + return this; +} + +int SwitchStatement::hasBreak() +{ + return TRUE; +} + +int SwitchStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int SwitchStatement::blockExit() +{ int result = BEnone; + if (condition->canThrow()) + result |= BEthrow; + + if (body) + { result |= body->blockExit(); + if (result & BEbreak) + { result |= BEfallthru; + result &= ~BEbreak; + } + } + else + result |= BEfallthru; + + return result; +} + + +void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("switch ("); + condition->toCBuffer(buf, hgs); + buf->writebyte(')'); + buf->writenl(); + if (body) + { + if (!body->isScopeStatement()) + { buf->writebyte('{'); + buf->writenl(); + body->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); + } + else + { + body->toCBuffer(buf, hgs); + } + } +} + +/******************************** CaseStatement ***************************/ + +CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) + : Statement(loc) +{ + this->exp = exp; + this->statement = s; + index = 0; + cblock = NULL; + bodyBB = NULL; + llvmIdx = NULL; + // LDC + enclosingScopeExit = NULL; +} + +Statement *CaseStatement::syntaxCopy() +{ + CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); + return s; +} + +Statement *CaseStatement::semantic(Scope *sc) +{ SwitchStatement *sw = sc->sw; + + //printf("CaseStatement::semantic() %s\n", toChars()); + exp = exp->semantic(sc); + if (sw) + { +#if IN_LLVM + enclosingScopeExit = sc->enclosingScopeExit; + if (enclosingScopeExit != sw->enclosingScopeExit) + { + error("case must be inside the same try, synchronized or volatile level as switch"); + } +#endif + exp = exp->implicitCastTo(sc, sw->condition->type); + exp = exp->optimize(WANTvalue | WANTinterpret); + + /* This is where variables are allowed as case expressions. + */ + if (exp->op == TOKvar) + { VarExp *ve = (VarExp *)exp; + VarDeclaration *v = ve->var->isVarDeclaration(); + Type *t = exp->type->toBasetype(); + if (v && (t->isintegral() || t->ty == Tclass)) + { /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw->hasVars = 1; + if (sw->isFinal) + error("case variables not allowed in final switch statements"); + goto L1; + } + } + + if (exp->op != TOKstring && exp->op != TOKint64) + { + error("case must be a string or an integral constant, not %s", exp->toChars()); + exp = new IntegerExp(0); + } + + L1: + for (int i = 0; i < sw->cases->dim; i++) + { + CaseStatement *cs = (CaseStatement *)sw->cases->data[i]; + + //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); + if (cs->exp->equals(exp)) + { error("duplicate case %s in switch statement", exp->toChars()); + break; + } + } + + sw->cases->push(this); + + // Resolve any goto case's with no exp to this case statement + for (int i = 0; i < sw->gotoCases.dim; i++) + { + GotoCaseStatement *gcs = (GotoCaseStatement *)sw->gotoCases.data[i]; + + if (!gcs->exp) + { + gcs->cs = this; + sw->gotoCases.remove(i); // remove from array + } + } +#if IN_DMD + if (sc->sw->tf != sc->tf) + error("switch and case are in different finally blocks"); +#endif + } + else + error("case not in switch statement"); + statement = statement->semantic(sc); + return this; +} + +int CaseStatement::compare(Object *obj) +{ + // Sort cases so we can do an efficient lookup + CaseStatement *cs2 = (CaseStatement *)(obj); + + return exp->compare(cs2->exp); +} + +int CaseStatement::usesEH() +{ + return statement->usesEH(); +} + +int CaseStatement::blockExit() +{ + return statement->blockExit(); +} + + +int CaseStatement::comeFrom() +{ + return TRUE; +} + +void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("case "); + exp->toCBuffer(buf, hgs); + buf->writebyte(':'); + buf->writenl(); + statement->toCBuffer(buf, hgs); +} + +/******************************** CaseRangeStatement ***************************/ + +#if DMDV2 + +CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, + Expression *last, Statement *s) + : Statement(loc) +{ + this->first = first; + this->last = last; + this->statement = s; +} + +Statement *CaseRangeStatement::syntaxCopy() +{ + CaseRangeStatement *s = new CaseRangeStatement(loc, + first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); + return s; +} + +Statement *CaseRangeStatement::semantic(Scope *sc) +{ SwitchStatement *sw = sc->sw; + + //printf("CaseRangeStatement::semantic() %s\n", toChars()); + if (sw->isFinal) + error("case ranges not allowed in final switch"); + + first = first->semantic(sc); + first = first->implicitCastTo(sc, sw->condition->type); + first = first->optimize(WANTvalue | WANTinterpret); + uinteger_t fval = first->toInteger(); + + last = last->semantic(sc); + last = last->implicitCastTo(sc, sw->condition->type); + last = last->optimize(WANTvalue | WANTinterpret); + uinteger_t lval = last->toInteger(); + + if ( (first->type->isunsigned() && fval > lval) || + (!first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval)) + { + error("first case %s is greater than last case %s", + first->toChars(), last->toChars()); + lval = fval; + } + + if (lval - fval > 256) + { error("had %llu cases which is more than 256 cases in case range", lval - fval); + lval = fval + 256; + } + + /* This works by replacing the CaseRange with an array of Case's. + * + * case a: .. case b: s; + * => + * case a: + * [...] + * case b: + * s; + */ + + Statements *statements = new Statements(); + for (uinteger_t i = fval; i != lval + 1; i++) + { + Statement *s = statement; + if (i != lval) // if not last case + s = new ExpStatement(loc, NULL); + Expression *e = new IntegerExp(loc, i, first->type); + Statement *cs = new CaseStatement(loc, e, s); + statements->push(cs); + } + Statement *s = new CompoundStatement(loc, statements); + s = s->semantic(sc); + return s; +} + +void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("case "); + first->toCBuffer(buf, hgs); + buf->writestring(": .. case "); + last->toCBuffer(buf, hgs); + buf->writebyte(':'); + buf->writenl(); + statement->toCBuffer(buf, hgs); +} + +#endif + +/******************************** DefaultStatement ***************************/ + +DefaultStatement::DefaultStatement(Loc loc, Statement *s) + : Statement(loc) +{ + this->statement = s; +#if IN_GCC ++ cblock = NULL; +#endif + bodyBB = NULL; + // LDC + enclosingScopeExit = NULL; +} + +Statement *DefaultStatement::syntaxCopy() +{ + DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); + return s; +} + +Statement *DefaultStatement::semantic(Scope *sc) +{ + //printf("DefaultStatement::semantic()\n"); + if (sc->sw) + { + if (sc->sw->sdefault) + { + error("switch statement already has a default"); + } + sc->sw->sdefault = this; + +#if IN_LLVM + enclosingScopeExit = sc->enclosingScopeExit; + if (enclosingScopeExit != sc->sw->enclosingScopeExit) + { + error("default must be inside the same try, synchronized or volatile level as switch"); + } + + if (sc->sw->isFinal) + { + error("default statement not allowed in final switch statement"); + } +#endif + } + else + error("default not in switch statement"); + statement = statement->semantic(sc); + return this; +} + +int DefaultStatement::usesEH() +{ + return statement->usesEH(); +} + +int DefaultStatement::blockExit() +{ + return statement->blockExit(); +} + + +int DefaultStatement::comeFrom() +{ + return TRUE; +} + +void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("default:\n"); + statement->toCBuffer(buf, hgs); +} + +/******************************** GotoDefaultStatement ***************************/ + +GotoDefaultStatement::GotoDefaultStatement(Loc loc) + : Statement(loc) +{ + sw = NULL; +} + +Statement *GotoDefaultStatement::syntaxCopy() +{ + GotoDefaultStatement *s = new GotoDefaultStatement(loc); + return s; +} + +Statement *GotoDefaultStatement::semantic(Scope *sc) +{ + sw = sc->sw; + if (!sw) + error("goto default not in switch statement"); + return this; +} + +int GotoDefaultStatement::blockExit() +{ + return BEgoto; +} + + +void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto default;\n"); +} + +/******************************** GotoCaseStatement ***************************/ + +GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + cs = NULL; + this->exp = exp; + sw = NULL; +} + +Statement *GotoCaseStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + GotoCaseStatement *s = new GotoCaseStatement(loc, e); + return s; +} + +Statement *GotoCaseStatement::semantic(Scope *sc) +{ + if (exp) + exp = exp->semantic(sc); + + if (!sc->sw) + error("goto case not in switch statement"); + else + { + sw = sc->sw; + sc->sw->gotoCases.push(this); + if (exp) + { + exp = exp->implicitCastTo(sc, sc->sw->condition->type); + exp = exp->optimize(WANTvalue); + } + } + return this; +} + +int GotoCaseStatement::blockExit() +{ + return BEgoto; +} + + +void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto case"); + if (exp) + { buf->writebyte(' '); + exp->toCBuffer(buf, hgs); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** SwitchErrorStatement ***************************/ + +SwitchErrorStatement::SwitchErrorStatement(Loc loc) + : Statement(loc) +{ +} + +int SwitchErrorStatement::blockExit() +{ + return BEthrow; +} + + +void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("SwitchErrorStatement::toCBuffer()"); + buf->writenl(); +} + +/******************************** ReturnStatement ***************************/ + +ReturnStatement::ReturnStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ReturnStatement::syntaxCopy() +{ + Expression *e = NULL; + if (exp) + e = exp->syntaxCopy(); + ReturnStatement *s = new ReturnStatement(loc, e); + return s; +} + +Statement *ReturnStatement::semantic(Scope *sc) +{ + //printf("ReturnStatement::semantic() %s\n", toChars()); + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + Scope *scx = sc; + int implicit0 = 0; + + if (sc->fes) + { + // Find scope of function foreach is in + for (; 1; scx = scx->enclosing) + { + assert(scx); + if (scx->func != fd) + { fd = scx->func; // fd is now function enclosing foreach + break; + } + } + } + + Type *tret = fd->type->nextOf(); + if (fd->tintro) + /* We'll be implicitly casting the return expression to tintro + */ + tret = fd->tintro->nextOf(); + Type *tbret = NULL; + + if (tret) + tbret = tret->toBasetype(); + + // main() returns 0, even if it returns void + if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) + { implicit0 = 1; + exp = new IntegerExp(0); + } + + if (sc->incontract || scx->incontract) + error("return statements cannot be in contracts"); + if (sc->enclosingFinally || scx->enclosingFinally) + error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); + + if (fd->isCtorDeclaration()) + { + // Constructors implicitly do: + // return this; + if (exp && exp->op != TOKthis) + error("cannot return expression from constructor"); + exp = new ThisExp(0); + exp->type = tret; + } + + if (!exp) + fd->nrvo_can = 0; + + if (exp) + { + fd->hasReturnExp |= 1; + + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + exp = exp->optimize(WANTvalue); + + if (fd->nrvo_can && exp->op == TOKvar) + { VarExp *ve = (VarExp *)exp; + VarDeclaration *v = ve->var->isVarDeclaration(); + + if (((TypeFunction *)fd->type)->isref) + // Function returns a reference + fd->nrvo_can = 0; + else if (!v || v->isOut() || v->isRef()) + fd->nrvo_can = 0; + else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor) + // Struct being returned has destructors + fd->nrvo_can = 0; + else if (fd->nrvo_var == NULL) + { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) + { //printf("Setting nrvo to %s\n", v->toChars()); + fd->nrvo_var = v; + } + else + fd->nrvo_can = 0; + } + else if (fd->nrvo_var != v) + fd->nrvo_can = 0; + } + else + fd->nrvo_can = 0; + + if (fd->returnLabel && tbret->ty != Tvoid) + { + } + else if (fd->inferRetType) + { TypeFunction *tf = (TypeFunction *)fd->type; + assert(tf->ty == Tfunction); + Type *tfret = tf->nextOf(); + if (tfret) + { + if (!exp->type->equals(tfret)) + error("mismatched function return type inference of %s and %s", + exp->type->toChars(), tfret->toChars()); + + /* The "refness" is determined by the first return statement, + * not all of them. This means: + * return 3; return x; // ok, x can be a value + * return x; return 3; // error, 3 is not an lvalue + */ + } + else + { + if (tf->isref) + { /* Determine "refness" of function return: + * if it's an lvalue, return by ref, else return by value + */ + if (exp->isLvalue()) + { + /* Return by ref + * (but first ensure it doesn't fail the "check for + * escaping reference" test) + */ + unsigned errors = global.errors; + global.gag++; + exp->checkEscapeRef(); + global.gag--; + if (errors != global.errors) + { tf->isref = FALSE; // return by value + global.errors = errors; + } + } + else + tf->isref = FALSE; // return by value + } + tf->next = exp->type; + fd->type = tf->semantic(loc, sc); + if (!fd->tintro) + { tret = fd->type->nextOf(); + tbret = tret->toBasetype(); + } + } + } + else if (tbret->ty != Tvoid) + { + exp = exp->implicitCastTo(sc, tret); + exp = exp->optimize(WANTvalue); + } + } + else if (fd->inferRetType) + { + if (fd->type->nextOf()) + { + if (fd->type->nextOf()->ty != Tvoid) + error("mismatched function return type inference of void and %s", + fd->type->nextOf()->toChars()); + } + else + { + ((TypeFunction *)fd->type)->next = Type::tvoid; + fd->type = fd->type->semantic(loc, sc); + if (!fd->tintro) + { tret = Type::tvoid; + tbret = tret; + } + } + } + else if (tbret->ty != Tvoid) // if non-void return + error("return expression expected"); + + if (sc->fes) + { + Statement *s; + + if (exp && !implicit0) + { + exp = exp->implicitCastTo(sc, tret); + } + if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || + exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || + exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || + exp->op == TOKstring) + { + sc->fes->cases->push(this); + // Construct: return cases->dim+1; + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); + } + else if (fd->type->nextOf()->toBasetype() == Type::tvoid) + { + s = new ReturnStatement(0, NULL); + sc->fes->cases->push(s); + + // Construct: { exp; return cases->dim + 1; } + Statement *s1 = new ExpStatement(loc, exp); + Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + else + { + // Construct: return vresult; + if (!fd->vresult) + { // Declare vresult + VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); + v->noscope = 1; + v->storage_class |= STCresult; + v->semantic(scx); + if (!scx->insert(v)) + assert(0); + v->parent = fd; + fd->vresult = v; + } + + s = new ReturnStatement(0, new VarExp(0, fd->vresult)); + sc->fes->cases->push(s); + + // Construct: { vresult = exp; return cases->dim + 1; } + exp = new ConstructExp(loc, new VarExp(0, fd->vresult), exp); + exp = exp->semantic(sc); + Statement *s1 = new ExpStatement(loc, exp); + Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); + s = new CompoundStatement(loc, s1, s2); + } + return s; + } + + if (exp) + { + if (fd->returnLabel && tbret->ty != Tvoid) + { + assert(fd->vresult); + VarExp *v = new VarExp(0, fd->vresult); + + exp = new ConstructExp(loc, v, exp); + exp = exp->semantic(sc); + } + + if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) + { // Function returns a reference + if (tbret->isMutable()) + exp = exp->modifiableLvalue(sc, exp); + else + exp = exp->toLvalue(sc, exp); + + exp->checkEscapeRef(); + } + else + { + //exp->dump(0); + //exp->print(); + exp->checkEscape(); + } + } + + /* BUG: need to issue an error on: + * this + * { if (x) return; + * super(); + * } + */ + + if (sc->callSuper & CSXany_ctor && + !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) + error("return without calling constructor"); + + sc->callSuper |= CSXreturn; + + // See if all returns are instead to be replaced with a goto returnLabel; + if (fd->returnLabel) + { + GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); + + gs->label = fd->returnLabel; + if (exp) + { /* Replace: return exp; + * with: exp; goto returnLabel; + */ + Statement *s = new ExpStatement(0, exp); + return new CompoundStatement(loc, s, gs); + } + return gs; + } + + if (exp && tbret->ty == Tvoid && !implicit0) + { + /* Replace: + * return exp; + * with: + * exp; return; + */ + Statement *s = new ExpStatement(loc, exp); + exp = NULL; + s = s->semantic(sc); + return new CompoundStatement(loc, s, this); + } + + return this; +} + +int ReturnStatement::blockExit() +{ int result = BEreturn; + + if (exp && exp->canThrow()) + result |= BEthrow; + return result; +} + + +void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("return "); + if (exp) + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + buf->writenl(); +} + +/******************************** BreakStatement ***************************/ + +BreakStatement::BreakStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; +} + +Statement *BreakStatement::syntaxCopy() +{ + BreakStatement *s = new BreakStatement(loc, ident); + return s; +} + +Statement *BreakStatement::semantic(Scope *sc) +{ + //printf("BreakStatement::semantic()\n"); + // If: + // break Identifier; + if (ident) + { + Scope *scx; + FuncDeclaration *thisfunc = sc->func; + + for (scx = sc; scx; scx = scx->enclosing) + { + LabelStatement *ls; + + if (scx->func != thisfunc) // if in enclosing function + { + if (sc->fes) // if this is the body of a foreach + { + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement *s; + sc->fes->cases->push(this); + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); + return s; + } + break; // can't break to it + } + + ls = scx->slabel; + if (ls && ls->ident == ident) + { + Statement *s = ls->statement; + + if (!s->hasBreak()) + error("label '%s' has no break", ident->toChars()); + if (ls->enclosingFinally != sc->enclosingFinally) + error("cannot break out of finally block"); + + this->target = ls; + return this; + } + } + error("enclosing label '%s' for break not found", ident->toChars()); + } + else if (!sc->sbreak) + { + if (sc->fes) + { Statement *s; + + // Replace break; with return 1; + s = new ReturnStatement(0, new IntegerExp(1)); + return s; + } + error("break is not inside a loop or switch"); + } + return this; +} + +int BreakStatement::blockExit() +{ + //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); + return ident ? BEgoto : BEbreak; +} + + +void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("break"); + if (ident) + { buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** ContinueStatement ***************************/ + +ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; +} + +Statement *ContinueStatement::syntaxCopy() +{ + ContinueStatement *s = new ContinueStatement(loc, ident); + return s; +} + +Statement *ContinueStatement::semantic(Scope *sc) +{ + //printf("ContinueStatement::semantic() %p\n", this); + if (ident) + { + Scope *scx; + FuncDeclaration *thisfunc = sc->func; + + for (scx = sc; scx; scx = scx->enclosing) + { + LabelStatement *ls; + + if (scx->func != thisfunc) // if in enclosing function + { + if (sc->fes) // if this is the body of a foreach + { + for (; scx; scx = scx->enclosing) + { + ls = scx->slabel; + if (ls && ls->ident == ident && ls->statement == sc->fes) + { + // Replace continue ident; with return 0; + return new ReturnStatement(0, new IntegerExp(0)); + } + } + + /* Post this statement to the fes, and replace + * it with a return value that caller will put into + * a switch. Caller will figure out where the break + * label actually is. + * Case numbers start with 2, not 0, as 0 is continue + * and 1 is break. + */ + Statement *s; + sc->fes->cases->push(this); + s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); + return s; + } + break; // can't continue to it + } + + ls = scx->slabel; + if (ls && ls->ident == ident) + { + Statement *s = ls->statement; + + if (!s->hasContinue()) + error("label '%s' has no continue", ident->toChars()); + if (ls->enclosingFinally != sc->enclosingFinally) + error("cannot continue out of finally block"); + + this->target = ls; + return this; + } + } + error("enclosing label '%s' for continue not found", ident->toChars()); + } + else if (!sc->scontinue) + { + if (sc->fes) + { Statement *s; + + // Replace continue; with return 0; + s = new ReturnStatement(0, new IntegerExp(0)); + return s; + } + error("continue is not inside a loop"); + } + return this; +} + +int ContinueStatement::blockExit() +{ + return ident ? BEgoto : BEcontinue; +} + + +void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("continue"); + if (ident) + { buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** SynchronizedStatement ***************************/ + +SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) + : Statement(loc) +{ + this->exp = exp; + this->body = body; + this->esync = NULL; + // LDC + this->llsync = NULL; +} + +SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) + : Statement(loc) +{ + this->exp = NULL; + this->body = body; + this->esync = esync; + // LDC + this->llsync = NULL; +} + +Statement *SynchronizedStatement::syntaxCopy() +{ + Expression *e = exp ? exp->syntaxCopy() : NULL; + SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *SynchronizedStatement::semantic(Scope *sc) +{ + if (exp) + { + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + ClassDeclaration *cd = exp->type->isClassHandle(); + if (!cd) + error("can only synchronize on class objects, not '%s'", exp->type->toChars()); + else if (cd->isInterfaceDeclaration()) + { /* Cast the interface to an object, as the object has the monitor, + * not the interface. + */ + Type *t = new TypeIdentifier(0, Id::Object); + + t = t->semantic(0, sc); + exp = new CastExp(loc, exp, t); + exp = exp->semantic(sc); + } + +#if 1 + /* Rewrite as: + * auto tmp = exp; + * _d_monitorenter(tmp); + * try { body } finally { _d_monitorexit(tmp); } + */ + Identifier *id = Lexer::uniqueId("__sync"); + ExpInitializer *ie = new ExpInitializer(loc, exp); + VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); + + Statements *cs = new Statements(); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + +#if IN_LLVM + // LDC: Build args + Parameters* args = new Parameters; + args->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); +#else + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter); +#endif + Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); + e->type = Type::tvoid; // do not run semantic on e + cs->push(new ExpStatement(loc, e)); + +#if IN_LLVM + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit); +#else + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorexit); +#endif + e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); + e->type = Type::tvoid; // do not run semantic on e + Statement *s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body, s); + cs->push(s); + + s = new CompoundStatement(loc, cs); + return s->semantic(sc); +#endif + } +#if 1 + else + { /* Generate our own critical section, then rewrite as: + * __gshared byte[CriticalSection.sizeof] critsec; + * _d_criticalenter(critsec.ptr); + * try { body } finally { _d_criticalexit(critsec.ptr); } + */ + Identifier *id = Lexer::uniqueId("__critsec"); + Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); + VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); + tmp->storage_class |= STCgshared | STCstatic; + + Statements *cs = new Statements(); + cs->push(new DeclarationStatement(loc, new DeclarationExp(loc, tmp))); + +#if IN_LLVM + // LDC: Build args + Parameters* args = new Parameters; + args->push(new Parameter(STCin, t->pointerTo(), NULL, NULL)); + + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter); +#else + FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter); +#endif + Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); + e = e->semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdenter), e); + e->type = Type::tvoid; // do not run semantic on e + cs->push(new ExpStatement(loc, e)); + +#if IN_LLVM + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit); +#else + FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit); +#endif + e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); + e = e->semantic(sc); + e = new CallExp(loc, new VarExp(loc, fdexit), e); + e->type = Type::tvoid; // do not run semantic on e + Statement *s = new ExpStatement(loc, e); + s = new TryFinallyStatement(loc, body, s); + cs->push(s); + + s = new CompoundStatement(loc, cs); + return s->semantic(sc); + } +#endif + if (body) + { + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + body = body->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + } + return this; +} + +int SynchronizedStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int SynchronizedStatement::hasContinue() +{ + return FALSE; //TRUE; +} + +int SynchronizedStatement::usesEH() +{ + return TRUE; +} + +int SynchronizedStatement::blockExit() +{ + return body ? body->blockExit() : BEfallthru; +} + + +void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("synchronized"); + if (exp) + { buf->writebyte('('); + exp->toCBuffer(buf, hgs); + buf->writebyte(')'); + } + if (body) + { + buf->writebyte(' '); + body->toCBuffer(buf, hgs); + } +} + +/******************************** WithStatement ***************************/ + +WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) + : Statement(loc) +{ + this->exp = exp; + this->body = body; + wthis = NULL; +} + +Statement *WithStatement::syntaxCopy() +{ + WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); + return s; +} + +Statement *WithStatement::semantic(Scope *sc) +{ ScopeDsymbol *sym; + Initializer *init; + + //printf("WithStatement::semantic()\n"); + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (exp->op == TOKimport) + { ScopeExp *es = (ScopeExp *)exp; + + sym = es->sds; + } + else if (exp->op == TOKtype) + { TypeExp *es = (TypeExp *)exp; + + Dsymbol *s = es->type->toDsymbol(sc); + sym = s ? s->isScopeDsymbol() : NULL; + if (!sym) + { error("with type %s has no members", es->toChars()); + if (body) + body = body->semantic(sc); + return this; + } + } + else + { Type *t = exp->type; + + assert(t); + t = t->toBasetype(); + if (t->isClassHandle()) + { + init = new ExpInitializer(loc, exp); + wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); + wthis->semantic(sc); + + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else if (t->ty == Tstruct) + { + Expression *e = exp->addressOf(sc); + init = new ExpInitializer(loc, e); + wthis = new VarDeclaration(loc, e->type, Id::withSym, init); + wthis->semantic(sc); + sym = new WithScopeSymbol(this); + sym->parent = sc->scopesym; + } + else + { error("with expressions must be class objects, not '%s'", exp->type->toChars()); + return NULL; + } + } + sc = sc->push(sym); + + if (body) + body = body->semantic(sc); + + sc->pop(); + + return this; +} + +void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("with ("); + exp->toCBuffer(buf, hgs); + buf->writestring(")\n"); + if (body) + body->toCBuffer(buf, hgs); +} + +int WithStatement::usesEH() +{ + return body ? body->usesEH() : 0; +} + +int WithStatement::blockExit() +{ + int result = BEnone; + if (exp->canThrow()) + result = BEthrow; + if (body) + result |= body->blockExit(); + else + result |= BEfallthru; + return result; +} + + +/******************************** TryCatchStatement ***************************/ + +TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Array *catches) + : Statement(loc) +{ + this->body = body; + this->catches = catches; +} + +Statement *TryCatchStatement::syntaxCopy() +{ + Array *a = new Array(); + a->setDim(catches->dim); + for (int i = 0; i < a->dim; i++) + { Catch *c; + + c = (Catch *)catches->data[i]; + c = c->syntaxCopy(); + a->data[i] = c; + } + TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); + return s; +} + +Statement *TryCatchStatement::semantic(Scope *sc) +{ + body = body->semanticScope(sc, NULL /*this*/, NULL); + + /* Even if body is NULL, still do semantic analysis on catches + */ + for (size_t i = 0; i < catches->dim; i++) + { Catch *c = (Catch *)catches->data[i]; + c->semantic(sc); + + // Determine if current catch 'hides' any previous catches + for (size_t j = 0; j < i; j++) + { Catch *cj = (Catch *)catches->data[j]; + char *si = c->loc.toChars(); + char *sj = cj->loc.toChars(); + + if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) + error("catch at %s hides catch at %s", sj, si); + } + } + + if (!body || body->isEmpty()) + { + return NULL; + } + return this; +} + +int TryCatchStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int TryCatchStatement::usesEH() +{ + return TRUE; +} + +int TryCatchStatement::blockExit() +{ + assert(body); + int result = body->blockExit(); + + int catchresult = 0; + for (size_t i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + catchresult |= c->blockExit(); + + /* If we're catching Object, then there is no throwing + */ + Identifier *id = c->type->toBasetype()->isClassHandle()->ident; + if (i == 0 && + (id == Id::Object || id == Id::Throwable || id == Id::Exception)) + { + result &= ~BEthrow; + } + } + return result | catchresult; +} + + +void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("try"); + buf->writenl(); + if (body) + body->toCBuffer(buf, hgs); + for (size_t i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + c->toCBuffer(buf, hgs); + } +} + +/******************************** Catch ***************************/ + +Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) +{ + //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); + this->loc = loc; + this->type = t; + this->ident = id; + this->handler = handler; + var = NULL; +} + +Catch *Catch::syntaxCopy() +{ + Catch *c = new Catch(loc, + (type ? type->syntaxCopy() : NULL), + ident, + (handler ? handler->syntaxCopy() : NULL)); + return c; +} + +void Catch::semantic(Scope *sc) +{ ScopeDsymbol *sym; + + //printf("Catch::semantic(%s)\n", ident->toChars()); + +#ifndef IN_GCC + if (sc->enclosingFinally) + { + /* This is because the _d_local_unwind() gets the stack munged + * up on this. The workaround is to place any try-catches into + * a separate function, and call that. + * To fix, have the compiler automatically convert the finally + * body into a nested function. + */ + error(loc, "cannot put catch statement inside finally block"); + } +#endif + + sym = new ScopeDsymbol(); + sym->parent = sc->scopesym; + sc = sc->push(sym); + + if (!type) + type = new TypeIdentifier(0, Id::Object); + type = type->semantic(loc, sc); + if (!type->toBasetype()->isClassHandle()) + error(loc, "can only catch class objects, not '%s'", type->toChars()); + else if (ident) + { + var = new VarDeclaration(loc, type, ident, NULL); + var->parent = sc->parent; + sc->insert(var); + } + handler = handler->semantic(sc); + + sc->pop(); +} + +int Catch::blockExit() +{ + return handler ? handler->blockExit() : BEfallthru; +} + +void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("catch"); + if (type) + { buf->writebyte('('); + type->toCBuffer(buf, ident, hgs); + buf->writebyte(')'); + } + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + if (handler) + handler->toCBuffer(buf, hgs); + buf->writebyte('}'); + buf->writenl(); +} + +/****************************** TryFinallyStatement ***************************/ + +TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) + : Statement(loc) +{ + this->body = body; + this->finalbody = finalbody; +} + +Statement *TryFinallyStatement::syntaxCopy() +{ + TryFinallyStatement *s = new TryFinallyStatement(loc, + body->syntaxCopy(), finalbody->syntaxCopy()); + return s; +} + +Statement *TryFinallyStatement::semantic(Scope *sc) +{ + //printf("TryFinallyStatement::semantic()\n"); + + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + body = body->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + + sc = sc->push(); + sc->enclosingFinally = this; + sc->sbreak = NULL; + sc->scontinue = NULL; // no break or continue out of finally block + finalbody = finalbody->semanticNoScope(sc); + sc->pop(); + if (!body) + return finalbody; + if (!finalbody) + return body; + if (body->blockExit() == BEfallthru) + { Statement *s = new CompoundStatement(loc, body, finalbody); + return s; + } + return this; +} + +void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("try\n{\n"); + body->toCBuffer(buf, hgs); + buf->printf("}\nfinally\n{\n"); + finalbody->toCBuffer(buf, hgs); + buf->writeByte('}'); + buf->writenl(); +} + +int TryFinallyStatement::hasBreak() +{ + return FALSE; //TRUE; +} + +int TryFinallyStatement::hasContinue() +{ + return FALSE; //TRUE; +} + +int TryFinallyStatement::usesEH() +{ + return TRUE; +} + +int TryFinallyStatement::blockExit() +{ + if (body) + return body->blockExit(); + return BEfallthru; +} + + +/****************************** OnScopeStatement ***************************/ + +OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) + : Statement(loc) +{ + this->tok = tok; + this->statement = statement; +} + +Statement *OnScopeStatement::syntaxCopy() +{ + OnScopeStatement *s = new OnScopeStatement(loc, + tok, statement->syntaxCopy()); + return s; +} + +Statement *OnScopeStatement::semantic(Scope *sc) +{ + /* semantic is called on results of scopeCode() */ + return this; +} + +int OnScopeStatement::blockExit() +{ // At this point, this statement is just an empty placeholder + return BEfallthru; +} + +void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(Token::toChars(tok)); + buf->writebyte(' '); + statement->toCBuffer(buf, hgs); +} + +int OnScopeStatement::usesEH() +{ + return 1; +} + +void OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) +{ + //printf("OnScopeStatement::scopeCode()\n"); + //print(); + *sentry = NULL; + *sexception = NULL; + *sfinally = NULL; + switch (tok) + { + case TOKon_scope_exit: + *sfinally = statement; + break; + + case TOKon_scope_failure: + *sexception = statement; + break; + + case TOKon_scope_success: + { + /* Create: + * sentry: int x = 0; + * sexception: x = 1; + * sfinally: if (!x) statement; + */ + Identifier *id = Lexer::uniqueId("__os"); + + ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0)); + VarDeclaration *v = new VarDeclaration(loc, Type::tint32, id, ie); + *sentry = new DeclarationStatement(loc, v); + + Expression *e = new IntegerExp(1); + e = new AssignExp(0, new VarExp(0, v), e); + *sexception = new ExpStatement(0, e); + + e = new VarExp(0, v); + e = new NotExp(0, e); + *sfinally = new IfStatement(0, NULL, e, statement, NULL); + + break; + } + + default: + assert(0); + } +} + +/******************************** ThrowStatement ***************************/ + +ThrowStatement::ThrowStatement(Loc loc, Expression *exp) + : Statement(loc) +{ + this->exp = exp; +} + +Statement *ThrowStatement::syntaxCopy() +{ + ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); + return s; +} + +Statement *ThrowStatement::semantic(Scope *sc) +{ + //printf("ThrowStatement::semantic()\n"); + + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + fd->hasReturnExp |= 2; + +#if DMDV1 + // See bugzilla 3388. Should this be or not? + if (sc->incontract) + error("Throw statements cannot be in contracts"); +#endif + exp = exp->semantic(sc); + exp = resolveProperties(sc, exp); + if (!exp->type->toBasetype()->isClassHandle()) + error("can only throw class objects, not type %s", exp->type->toChars()); + return this; +} + +int ThrowStatement::blockExit() +{ + return BEthrow; // obviously +} + + +void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->printf("throw "); + exp->toCBuffer(buf, hgs); + buf->writeByte(';'); + buf->writenl(); +} + +/******************************** VolatileStatement **************************/ + +VolatileStatement::VolatileStatement(Loc loc, Statement *statement) + : Statement(loc) +{ + this->statement = statement; +} + +Statement *VolatileStatement::syntaxCopy() +{ + VolatileStatement *s = new VolatileStatement(loc, + statement ? statement->syntaxCopy() : NULL); + return s; +} + +Statement *VolatileStatement::semantic(Scope *sc) +{ + if (statement) + { + Statement* oldScopeExit = sc->enclosingScopeExit; + sc->enclosingScopeExit = this; + statement = statement->semantic(sc); + sc->enclosingScopeExit = oldScopeExit; + } + return this; +} + +Statements *VolatileStatement::flatten(Scope *sc) +{ + Statements *a; + + a = statement ? statement->flatten(sc) : NULL; + if (a) + { for (int i = 0; i < a->dim; i++) + { Statement *s = (Statement *)a->data[i]; + + s = new VolatileStatement(loc, s); + a->data[i] = s; + } + } + + return a; +} + +int VolatileStatement::blockExit() +{ + return statement ? statement->blockExit() : BEfallthru; +} + + +void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("volatile"); + if (statement) + { if (statement->isScopeStatement()) + buf->writenl(); + else + buf->writebyte(' '); + statement->toCBuffer(buf, hgs); + } +} + + +/******************************** GotoStatement ***************************/ + +GotoStatement::GotoStatement(Loc loc, Identifier *ident) + : Statement(loc) +{ + this->ident = ident; + this->label = NULL; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; +} + +Statement *GotoStatement::syntaxCopy() +{ + GotoStatement *s = new GotoStatement(loc, ident); + return s; +} + +Statement *GotoStatement::semantic(Scope *sc) +{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + + //printf("GotoStatement::semantic()\n"); + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + + label = fd->searchLabel(ident); + if (!label->statement && sc->fes) + { + /* Either the goto label is forward referenced or it + * is in the function that the enclosing foreach is in. + * Can't know yet, so wrap the goto in a compound statement + * so we can patch it later, and add it to a 'look at this later' + * list. + */ + Statements *a = new Statements(); + Statement *s; + + a->push(this); + s = new CompoundStatement(loc, a); + sc->fes->gotos->push(s); // 'look at this later' list + return s; + } + if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) + error("cannot goto in or out of finally block"); + return this; +} + +int GotoStatement::blockExit() +{ + //printf("GotoStatement::blockExit(%p)\n", this); + return BEgoto; +} + + +void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("goto "); + buf->writestring(ident->toChars()); + buf->writebyte(';'); + buf->writenl(); +} + +/******************************** LabelStatement ***************************/ + +LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) + : Statement(loc) +{ + this->ident = ident; + this->statement = statement; + this->enclosingFinally = NULL; + this->enclosingScopeExit = NULL; + this->lblock = NULL; + this->fwdrefs = NULL; + this->asmLabel = false; +} + +Statement *LabelStatement::syntaxCopy() +{ + LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); + return s; +} + +Statement *LabelStatement::semantic(Scope *sc) +{ LabelDsymbol *ls; + FuncDeclaration *fd = sc->parent->isFuncDeclaration(); + + //printf("LabelStatement::semantic()\n"); + ls = fd->searchLabel(ident); + if (ls->statement) + error("Label '%s' already defined", ls->toChars()); + else + ls->statement = this; + + enclosingFinally = sc->enclosingFinally; + enclosingScopeExit = sc->enclosingScopeExit; + + sc = sc->push(); + sc->scopesym = sc->enclosing->scopesym; + sc->callSuper |= CSXlabel; + sc->slabel = this; + if (statement) + statement = statement->semanticNoScope(sc); + sc->pop(); + + // LDC put in labmap + fd->labmap[ident->toChars()] = this; + + return this; +} + +Statements *LabelStatement::flatten(Scope *sc) +{ + Statements *a = NULL; + + if (statement) + { + a = statement->flatten(sc); + if (a) + { + if (!a->dim) + { + a->push(new ExpStatement(loc, NULL)); + } + Statement *s = (Statement *)a->data[0]; + + s = new LabelStatement(loc, ident, s); + a->data[0] = s; + } + } + + return a; +} + + +int LabelStatement::usesEH() +{ + return statement ? statement->usesEH() : FALSE; +} + +int LabelStatement::blockExit() +{ + //printf("LabelStatement::blockExit(%p)\n", this); + return statement ? statement->blockExit() : BEfallthru; +} + + +int LabelStatement::comeFrom() +{ + //printf("LabelStatement::comeFrom()\n"); + return TRUE; +} + +void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writebyte(':'); + buf->writenl(); + if (statement) + statement->toCBuffer(buf, hgs); +} + + +/******************************** LabelDsymbol ***************************/ + +LabelDsymbol::LabelDsymbol(Identifier *ident) + : Dsymbol(ident) +{ + statement = NULL; +#if IN_GCC + asmLabelNum = 0; +#endif +} + +LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? +{ + return this; +} diff --git a/dmd2/statement.h b/dmd2/statement.h index 8b894ddd..72716a29 100644 --- a/dmd2/statement.h +++ b/dmd2/statement.h @@ -1,952 +1,963 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 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. - -#ifndef DMD_STATEMENT_H -#define DMD_STATEMENT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "arraytypes.h" -#include "dsymbol.h" -#include "lexer.h" - -struct OutBuffer; -struct Scope; -struct Expression; -struct LabelDsymbol; -struct Identifier; -struct IfStatement; -struct DeclarationStatement; -struct DefaultStatement; -struct VarDeclaration; -struct Condition; -struct Module; -struct Token; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct ReturnStatement; -struct CompoundStatement; -struct Argument; -struct StaticAssert; -struct AsmStatement; -#if IN_LLVM -struct AsmBlockStatement; -#endif -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct HdrGenState; -struct InterState; -#if IN_LLVM -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; -#endif - -enum TOK; - -#if IN_LLVM -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} -#endif - -// Back end -struct IRState; -struct Blockx; -#if IN_LLVM -struct DValue; -typedef DValue elem; -#endif - -#if IN_GCC -union tree_node; typedef union tree_node block; -//union tree_node; typedef union tree_node elem; -#else -struct block; -//struct elem; -#endif -struct code; - -/* How a statement exits; this is returned by blockExit() - */ -enum BE -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -}; - -struct Statement : Object -{ - Loc loc; - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual TryCatchStatement *isTryCatchStatement() { return NULL; } - virtual GotoStatement *isGotoStatement() { return NULL; } - virtual AsmStatement *isAsmStatement() { return NULL; } - virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } -#if IN_LLVM - virtual LabelStatement *isLabelStatement() { return NULL; } -#endif -#ifdef _DH - int incontract; -#endif - virtual ScopeStatement *isScopeStatement() { return NULL; } - virtual Statement *semantic(Scope *sc); - Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); - virtual int hasBreak(); - virtual int hasContinue(); - virtual int usesEH(); - virtual int blockExit(); - virtual int comeFrom(); - virtual int isEmpty(); - virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - virtual Statements *flatten(Scope *sc); - virtual Expression *interpret(InterState *istate); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Statement *inlineScan(InlineScanState *iss); - - // Back end - virtual void toIR(IRState *irs); - - // Avoid dynamic_cast - virtual DeclarationStatement *isDeclarationStatement() { return NULL; } - virtual CompoundStatement *isCompoundStatement() { return NULL; } - virtual ReturnStatement *isReturnStatement() { return NULL; } - virtual IfStatement *isIfStatement() { return NULL; } - virtual CaseStatement* isCaseStatement() { return NULL; } - -#if IN_LLVM - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -#endif -}; - -struct PeelStatement : Statement -{ - Statement *s; - - PeelStatement(Statement *s); - Statement *semantic(Scope *sc); -}; - -struct ExpStatement : Statement -{ - Expression *exp; - - ExpStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - void toNakedIR(IRState *irs); -#endif -}; - -struct CompileStatement : Statement -{ - Expression *exp; - - CompileStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statements *flatten(Scope *sc); - Statement *semantic(Scope *sc); -}; - -struct DeclarationStatement : ExpStatement -{ - // Doing declarations as an expression, rather than a statement, - // makes inlining functions much easier. - - DeclarationStatement(Loc loc, Dsymbol *s); - DeclarationStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - DeclarationStatement *isDeclarationStatement() { return this; } -}; - -struct CompoundStatement : Statement -{ - Statements *statements; - - CompoundStatement(Loc loc, Statements *s); - CompoundStatement(Loc loc, Statement *s1, Statement *s2); - virtual Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - int isEmpty(); - virtual Statements *flatten(Scope *sc); - ReturnStatement *isReturnStatement(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - virtual void toIR(IRState *irs); - -#if IN_LLVM - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -#endif - - virtual CompoundStatement *isCompoundStatement() { return this; } -}; - -struct CompoundDeclarationStatement : CompoundStatement -{ - CompoundDeclarationStatement(Loc loc, Statements *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/* The purpose of this is so that continue will go to the next - * of the statements, and break will go to the end of the statements. - */ -struct UnrolledLoopStatement : Statement -{ - Statements *statements; - - UnrolledLoopStatement(Loc loc, Statements *statements); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ScopeStatement : Statement -{ - Statement *statement; - - ScopeStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - ScopeStatement *isScopeStatement() { return this; } - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - int isEmpty(); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct WhileStatement : Statement -{ - Expression *condition; - Statement *body; - - WhileStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct DoStatement : Statement -{ - Statement *body; - Expression *condition; - - DoStatement(Loc loc, Statement *b, Expression *c); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForStatement : Statement -{ - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForeachStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Arguments *arguments; // array of Argument*'s - Expression *aggr; - Statement *body; - - VarDeclaration *key; - VarDeclaration *value; - - FuncDeclaration *func; // function we're lexically in - - Array cases; // put breaks, continues, gotos and returns here - Array gotos; // forward referenced goto's go here - - ForeachStatement(Loc loc, enum TOK op, Arguments *arguments, Expression *aggr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - bool checkForArgTypes(); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -#if DMDV2 -struct ForeachRangeStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Argument *arg; // loop index variable - Expression *lwr; - Expression *upr; - Statement *body; - - VarDeclaration *key; - - ForeachRangeStatement(Loc loc, enum TOK op, Argument *arg, - Expression *lwr, Expression *upr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; -#endif - -struct IfStatement : Statement -{ - Argument *arg; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - VarDeclaration *match; // for MatchExpression results - - IfStatement(Loc loc, Argument *arg, Expression *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(); - IfStatement *isIfStatement() { return this; } - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ConditionalStatement : Statement -{ - Condition *condition; - Statement *ifbody; - Statement *elsebody; - - ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct PragmaStatement : Statement -{ - Identifier *ident; - Expressions *args; // array of Expression's - Statement *body; - - PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct StaticAssertStatement : Statement -{ - StaticAssert *sa; - - StaticAssertStatement(StaticAssert *sa); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct SwitchStatement : Statement -{ - Expression *condition; - Statement *body; - bool isFinal; - - DefaultStatement *sdefault; - - Array gotoCases; // array of unresolved GotoCaseStatement's - Array *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - int hasVars; // !=0 if has variable case values - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct CaseStatement : Statement -{ - Expression *exp; - Statement *statement; - - int index; // which case it is (since we sort this) - block *cblock; // back end: label for the block - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - CaseStatement(Loc loc, Expression *exp, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int compare(Object *obj); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - CaseStatement* isCaseStatement() { return this; } - -#if IN_LLVM - llvm::BasicBlock* bodyBB; - llvm::ConstantInt* llvmIdx; -#endif -}; - -#if DMDV2 - -struct CaseRangeStatement : Statement -{ - Expression *first; - Expression *last; - Statement *statement; - - CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif - -struct DefaultStatement : Statement -{ - Statement *statement; -#if IN_GCC - block *cblock; // back end: label for the block -#endif - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - DefaultStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - llvm::BasicBlock* bodyBB; -#endif -}; - -struct GotoDefaultStatement : Statement -{ - SwitchStatement *sw; - - GotoDefaultStatement(Loc loc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct GotoCaseStatement : Statement -{ - Expression *exp; // NULL, or which case to goto - CaseStatement *cs; // case statement it resolves to - SwitchStatement *sw; - - GotoCaseStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct SwitchErrorStatement : Statement -{ - SwitchErrorStatement(Loc loc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct ReturnStatement : Statement -{ - Expression *exp; - - ReturnStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int blockExit(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - ReturnStatement *isReturnStatement() { return this; } -}; - -struct BreakStatement : Statement -{ - Identifier *ident; - - BreakStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - -#if IN_LLVM - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -#endif -}; - -struct ContinueStatement : Statement -{ - Identifier *ident; - - ContinueStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - -#if IN_LLVM - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -#endif -}; - -struct SynchronizedStatement : Statement -{ - Expression *exp; - Statement *body; - - SynchronizedStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - -// Back end - elem *esync; - SynchronizedStatement(Loc loc, elem *esync, Statement *body); - void toIR(IRState *irs); -#if IN_LLVM - llvm::Value* llsync; -#endif -}; - -struct WithStatement : Statement -{ - Expression *exp; - Statement *body; - VarDeclaration *wthis; - - WithStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct TryCatchStatement : Statement -{ - Statement *body; - Array *catches; - - TryCatchStatement(Loc loc, Statement *body, Array *catches); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - TryCatchStatement *isTryCatchStatement() { return this; } -}; - -struct Catch : Object -{ - Loc loc; - Type *type; - Identifier *ident; - VarDeclaration *var; - Statement *handler; - - Catch(Loc loc, Type *t, Identifier *id, Statement *handler); - Catch *syntaxCopy(); - void semantic(Scope *sc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TryFinallyStatement : Statement -{ - Statement *body; - Statement *finalbody; - - TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct OnScopeStatement : Statement -{ - TOK tok; - Statement *statement; - - OnScopeStatement(Loc loc, TOK tok, Statement *statement); - Statement *syntaxCopy(); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int usesEH(); - void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - void toIR(IRState *irs); -}; - -struct ThrowStatement : Statement -{ - Expression *exp; - - ThrowStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct VolatileStatement : Statement -{ - Statement *statement; - - VolatileStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int blockExit(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct GotoStatement : Statement -{ - Identifier *ident; - LabelDsymbol *label; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - - GotoStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - GotoStatement *isGotoStatement() { return this; } -}; - -struct LabelStatement : Statement -{ - Identifier *ident; - Statement *statement; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - block *lblock; // back end - int isReturnLabel; - - LabelStatement(Loc loc, Identifier *ident, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - bool asmLabel; // for labels inside inline assembler - void toNakedIR(IRState *irs); - virtual LabelStatement *isLabelStatement() { return this; } -#endif -}; - -struct LabelDsymbol : Dsymbol -{ - LabelStatement *statement; -#if IN_GCC - unsigned asmLabelNum; // GCC-specific -#endif - - LabelDsymbol(Identifier *ident); - LabelDsymbol *isLabel(); -}; - -struct AsmStatement : Statement -{ - Token *tokens; - code *asmcode; - unsigned asmalign; // alignment of this statement - unsigned refparam; // !=0 if function parameter is referenced - unsigned naked; // !=0 if function is to be naked - unsigned regs; // mask of registers modified - - AsmStatement(Loc loc, Token *tokens); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(); - int comeFrom(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmStatement *isAsmStatement() { return this; } - - void toIR(IRState *irs); - -#if IN_LLVM - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; - - void toNakedIR(IRState *irs); -#endif -}; - -struct AsmBlockStatement : CompoundStatement -{ - TryFinallyStatement* enclosingFinally; - Statement* enclosingScopeExit; - - AsmBlockStatement(Loc loc, Statements *s); - Statements *flatten(Scope *sc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - CompoundStatement *isCompoundStatement() { return NULL; } - AsmBlockStatement *isAsmBlockStatement() { return this; } - - void toIR(IRState *irs); - void toNakedIR(IRState *irs); - AsmBlockStatement* endsWithAsm(); - - llvm::Value* abiret; -}; - -#endif /* DMD_STATEMENT_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_STATEMENT_H +#define DMD_STATEMENT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "root.h" + +#include "arraytypes.h" +#include "dsymbol.h" +#include "lexer.h" + +struct OutBuffer; +struct Scope; +struct Expression; +struct LabelDsymbol; +struct Identifier; +struct IfStatement; +struct DeclarationStatement; +struct DefaultStatement; +struct VarDeclaration; +struct Condition; +struct Module; +struct Token; +struct InlineCostState; +struct InlineDoState; +struct InlineScanState; +struct ReturnStatement; +struct CompoundStatement; +struct Parameter; +struct StaticAssert; +struct AsmStatement; +#if IN_LLVM +struct AsmBlockStatement; +#endif +struct GotoStatement; +struct ScopeStatement; +struct TryCatchStatement; +struct TryFinallyStatement; +struct HdrGenState; +struct InterState; +#if IN_LLVM +struct CaseStatement; +struct LabelStatement; +struct VolatileStatement; +struct SynchronizedStatement; +#endif + +enum TOK; + +#if IN_LLVM +namespace llvm +{ + class Value; + class BasicBlock; + class ConstantInt; +} +#endif + +// Back end +struct IRState; +struct Blockx; +#if IN_LLVM +struct DValue; +typedef DValue elem; +#endif + +#if IN_GCC +union tree_node; typedef union tree_node block; +//union tree_node; typedef union tree_node elem; +#else +struct block; +//struct elem; +#endif +struct code; + +/* How a statement exits; this is returned by blockExit() + */ +enum BE +{ + BEnone = 0, + BEfallthru = 1, + BEthrow = 2, + BEreturn = 4, + BEgoto = 8, + BEhalt = 0x10, + BEbreak = 0x20, + BEcontinue = 0x40, + BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), +}; + +struct Statement : Object +{ + Loc loc; + + Statement(Loc loc); + virtual Statement *syntaxCopy(); + + void print(); + char *toChars(); + + void error(const char *format, ...) IS_PRINTF(2); + void warning(const char *format, ...) IS_PRINTF(2); + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual TryCatchStatement *isTryCatchStatement() { return NULL; } + virtual GotoStatement *isGotoStatement() { return NULL; } + virtual AsmStatement *isAsmStatement() { return NULL; } + virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } +#if IN_LLVM + virtual LabelStatement *isLabelStatement() { return NULL; } +#endif +#ifdef _DH + int incontract; +#endif + virtual ScopeStatement *isScopeStatement() { return NULL; } + virtual Statement *semantic(Scope *sc); + Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); + Statement *semanticNoScope(Scope *sc); + virtual int hasBreak(); + virtual int hasContinue(); + virtual int usesEH(); + virtual int blockExit(); + virtual int comeFrom(); + virtual int isEmpty(); + virtual void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + virtual Statements *flatten(Scope *sc); + virtual Expression *interpret(InterState *istate); + + virtual int inlineCost(InlineCostState *ics); + virtual Expression *doInline(InlineDoState *ids); + virtual Statement *inlineScan(InlineScanState *iss); + + // Back end + virtual void toIR(IRState *irs); + + // Avoid dynamic_cast + virtual DeclarationStatement *isDeclarationStatement() { return NULL; } + virtual CompoundStatement *isCompoundStatement() { return NULL; } + virtual ReturnStatement *isReturnStatement() { return NULL; } + virtual IfStatement *isIfStatement() { return NULL; } + virtual CaseStatement* isCaseStatement() { return NULL; } + +#if IN_LLVM + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); +#endif +}; + +struct PeelStatement : Statement +{ + Statement *s; + + PeelStatement(Statement *s); + Statement *semantic(Scope *sc); +}; + +struct ExpStatement : Statement +{ + Expression *exp; + + ExpStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int isEmpty(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + +#if IN_LLVM + void toNakedIR(IRState *irs); +#endif +}; + +struct CompileStatement : Statement +{ + Expression *exp; + + CompileStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statements *flatten(Scope *sc); + Statement *semantic(Scope *sc); +}; + +struct DeclarationStatement : ExpStatement +{ + // Doing declarations as an expression, rather than a statement, + // makes inlining functions much easier. + + DeclarationStatement(Loc loc, Dsymbol *s); + DeclarationStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + + DeclarationStatement *isDeclarationStatement() { return this; } +}; + +struct CompoundStatement : Statement +{ + Statements *statements; + + CompoundStatement(Loc loc, Statements *s); + CompoundStatement(Loc loc, Statement *s1); + CompoundStatement(Loc loc, Statement *s1, Statement *s2); + virtual Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + int isEmpty(); + virtual Statements *flatten(Scope *sc); + ReturnStatement *isReturnStatement(); + Expression *interpret(InterState *istate); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + virtual void toIR(IRState *irs); + +#if IN_LLVM + virtual void toNakedIR(IRState *irs); + virtual AsmBlockStatement* endsWithAsm(); +#endif + + virtual CompoundStatement *isCompoundStatement() { return this; } +}; + +struct CompoundDeclarationStatement : CompoundStatement +{ + CompoundDeclarationStatement(Loc loc, Statements *s); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +/* The purpose of this is so that continue will go to the next + * of the statements, and break will go to the end of the statements. + */ +struct UnrolledLoopStatement : Statement +{ + Statements *statements; + + UnrolledLoopStatement(Loc loc, Statements *statements); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ScopeStatement : Statement +{ + Statement *statement; + + ScopeStatement(Loc loc, Statement *s); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + ScopeStatement *isScopeStatement() { return this; } + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + int isEmpty(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct WhileStatement : Statement +{ + Expression *condition; + Statement *body; + + WhileStatement(Loc loc, Expression *c, Statement *b); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct DoStatement : Statement +{ + Statement *body; + Expression *condition; + + DoStatement(Loc loc, Statement *b, Expression *c); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ForStatement : Statement +{ + Statement *init; + Expression *condition; + Expression *increment; + Statement *body; + + ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ForeachStatement : Statement +{ + enum TOK op; // TOKforeach or TOKforeach_reverse + Parameters *arguments; // array of Parameter*'s + Expression *aggr; + Statement *body; + + VarDeclaration *key; + VarDeclaration *value; + + FuncDeclaration *func; // function we're lexically in + + Array *cases; // put breaks, continues, gotos and returns here + Array *gotos; // forward referenced goto's go here + + ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + bool checkForArgTypes(); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +#if DMDV2 +struct ForeachRangeStatement : Statement +{ + enum TOK op; // TOKforeach or TOKforeach_reverse + Parameter *arg; // loop index variable + Expression *lwr; + Expression *upr; + Statement *body; + + VarDeclaration *key; + + ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, + Expression *lwr, Expression *upr, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; +#endif + +struct IfStatement : Statement +{ + Parameter *arg; + Expression *condition; + Statement *ifbody; + Statement *elsebody; + + VarDeclaration *match; // for MatchExpression results + + IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int usesEH(); + int blockExit(); + IfStatement *isIfStatement() { return this; } + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct ConditionalStatement : Statement +{ + Condition *condition; + Statement *ifbody; + Statement *elsebody; + + ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int usesEH(); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct PragmaStatement : Statement +{ + Identifier *ident; + Expressions *args; // array of Expression's + Statement *body; + + PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct StaticAssertStatement : Statement +{ + StaticAssert *sa; + + StaticAssertStatement(StaticAssert *sa); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct SwitchStatement : Statement +{ + Expression *condition; + Statement *body; + bool isFinal; + + DefaultStatement *sdefault; + + Array gotoCases; // array of unresolved GotoCaseStatement's + Array *cases; // array of CaseStatement's + int hasNoDefault; // !=0 if no default statement + int hasVars; // !=0 if has variable case values + +#if IN_LLVM + Statement *enclosingScopeExit; +#endif + + SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int usesEH(); + int blockExit(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct CaseStatement : Statement +{ + Expression *exp; + Statement *statement; + + int index; // which case it is (since we sort this) + block *cblock; // back end: label for the block + +#if IN_LLVM + Statement *enclosingScopeExit; +#endif + + CaseStatement(Loc loc, Expression *exp, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int compare(Object *obj); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + CaseStatement* isCaseStatement() { return this; } + +#if IN_LLVM + llvm::BasicBlock* bodyBB; + llvm::ConstantInt* llvmIdx; +#endif +}; + +#if DMDV2 + +struct CaseRangeStatement : Statement +{ + Expression *first; + Expression *last; + Statement *statement; + + CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#endif + +struct DefaultStatement : Statement +{ + Statement *statement; +#if IN_GCC + block *cblock; // back end: label for the block +#endif + +#if IN_LLVM + Statement *enclosingScopeExit; +#endif + + DefaultStatement(Loc loc, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + +#if IN_LLVM + llvm::BasicBlock* bodyBB; +#endif +}; + +struct GotoDefaultStatement : Statement +{ + SwitchStatement *sw; + + GotoDefaultStatement(Loc loc); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct GotoCaseStatement : Statement +{ + Expression *exp; // NULL, or which case to goto + CaseStatement *cs; // case statement it resolves to + SwitchStatement *sw; + + GotoCaseStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct SwitchErrorStatement : Statement +{ + SwitchErrorStatement(Loc loc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct ReturnStatement : Statement +{ + Expression *exp; + + ReturnStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int blockExit(); + Expression *interpret(InterState *istate); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + ReturnStatement *isReturnStatement() { return this; } +}; + +struct BreakStatement : Statement +{ + Identifier *ident; + + BreakStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + +#if IN_LLVM + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +#endif +}; + +struct ContinueStatement : Statement +{ + Identifier *ident; + + ContinueStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + +#if IN_LLVM + // LDC: only set if ident is set: label statement to jump to + LabelStatement *target; +#endif +}; + +struct SynchronizedStatement : Statement +{ + Expression *exp; + Statement *body; + + SynchronizedStatement(Loc loc, Expression *exp, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + +// Back end + elem *esync; + SynchronizedStatement(Loc loc, elem *esync, Statement *body); + void toIR(IRState *irs); +#if IN_LLVM + llvm::Value* llsync; +#endif +}; + +struct WithStatement : Statement +{ + Expression *exp; + Statement *body; + VarDeclaration *wthis; + + WithStatement(Loc loc, Expression *exp, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int usesEH(); + int blockExit(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct TryCatchStatement : Statement +{ + Statement *body; + Array *catches; + + TryCatchStatement(Loc loc, Statement *body, Array *catches); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int usesEH(); + int blockExit(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + TryCatchStatement *isTryCatchStatement() { return this; } +}; + +struct Catch : Object +{ + Loc loc; + Type *type; + Identifier *ident; + VarDeclaration *var; + Statement *handler; + + Catch(Loc loc, Type *t, Identifier *id, Statement *handler); + Catch *syntaxCopy(); + void semantic(Scope *sc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +struct TryFinallyStatement : Statement +{ + Statement *body; + Statement *finalbody; + + TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct OnScopeStatement : Statement +{ + TOK tok; + Statement *statement; + + OnScopeStatement(Loc loc, TOK tok, Statement *statement); + Statement *syntaxCopy(); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int usesEH(); + void scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); + Expression *interpret(InterState *istate); + + void toIR(IRState *irs); +}; + +struct ThrowStatement : Statement +{ + Expression *exp; + + ThrowStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + int blockExit(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct VolatileStatement : Statement +{ + Statement *statement; + + VolatileStatement(Loc loc, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int blockExit(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct GotoStatement : Statement +{ + Identifier *ident; + LabelDsymbol *label; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; + + GotoStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + Expression *interpret(InterState *istate); + + void toIR(IRState *irs); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + GotoStatement *isGotoStatement() { return this; } +}; + +struct LabelStatement : Statement +{ + Identifier *ident; + Statement *statement; + TryFinallyStatement *enclosingFinally; + Statement* enclosingScopeExit; + block *lblock; // back end + + Array *fwdrefs; // forward references to this LabelStatement + + LabelStatement(Loc loc, Identifier *ident, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int usesEH(); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + +#if IN_LLVM + bool asmLabel; // for labels inside inline assembler + void toNakedIR(IRState *irs); + virtual LabelStatement *isLabelStatement() { return this; } +#endif +}; + +struct LabelDsymbol : Dsymbol +{ + LabelStatement *statement; +#if IN_GCC + unsigned asmLabelNum; // GCC-specific +#endif + + LabelDsymbol(Identifier *ident); + LabelDsymbol *isLabel(); +}; + +struct AsmStatement : Statement +{ + Token *tokens; + code *asmcode; + unsigned asmalign; // alignment of this statement + unsigned refparam; // !=0 if function parameter is referenced + unsigned naked; // !=0 if function is to be naked + unsigned regs; // mask of registers modified + + AsmStatement(Loc loc, Token *tokens); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + int comeFrom(); + Expression *interpret(InterState *istate); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + virtual AsmStatement *isAsmStatement() { return this; } + + void toIR(IRState *irs); + +#if IN_LLVM + // non-zero if this is a branch, contains the target labels identifier + Identifier* isBranchToLabel; + + void toNakedIR(IRState *irs); +#endif +}; + +struct AsmBlockStatement : CompoundStatement +{ + TryFinallyStatement* enclosingFinally; + Statement* enclosingScopeExit; + + AsmBlockStatement(Loc loc, Statements *s); + Statements *flatten(Scope *sc); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + + CompoundStatement *isCompoundStatement() { return NULL; } + AsmBlockStatement *isAsmBlockStatement() { return this; } + + void toIR(IRState *irs); + void toNakedIR(IRState *irs); + AsmBlockStatement* endsWithAsm(); + + llvm::Value* abiret; +}; + +#endif /* DMD_STATEMENT_H */ diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c index 7576924f..e80e4603 100644 --- a/dmd2/staticassert.c +++ b/dmd2/staticassert.c @@ -1,120 +1,116 @@ - -// 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 -#include -#include - -#include "dsymbol.h" -#include "staticassert.h" -#include "expression.h" -#include "id.h" -#include "hdrgen.h" -#include "scope.h" -#include "template.h" - - -/********************************* AttribDeclaration ****************************/ - -StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg) - : Dsymbol(Id::empty) -{ - this->loc = loc; - this->exp = exp; - this->msg = msg; -} - -Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s) -{ - StaticAssert *sa; - - assert(!s); - sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); - return sa; -} - -int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - return 0; // we didn't add anything -} - -void StaticAssert::semantic(Scope *sc) -{ -} - -#include "scope.h" -#include "template.h" -#include "declaration.h" - -void StaticAssert::semantic2(Scope *sc) -{ - Expression *e; - - //printf("StaticAssert::semantic2() %s\n", toChars()); - e = exp->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(FALSE)) - { - if (msg) - { HdrGenState hgs; - OutBuffer buf; - - msg = msg->semantic(sc); - msg = msg->optimize(WANTvalue | WANTinterpret); - hgs.console = 1; - msg->toCBuffer(&buf, &hgs); - error("%s", buf.toChars()); - } - else - error("(%s) is false", exp->toChars()); - if(sc->tinst) - sc->tinst->printInstantiationTrace(); - if (!global.gag) { - fatal(); - } - } - else if (!e->isBool(TRUE)) - { - error("(%s) is not evaluatable at compile time", exp->toChars()); - } -} - -int StaticAssert::oneMember(Dsymbol **ps) -{ - //printf("StaticAssert::oneMember())\n"); - *ps = NULL; - return TRUE; -} - -void StaticAssert::inlineScan() -{ -} - -void StaticAssert::toObjFile(int multiobj) -{ -} - -const char *StaticAssert::kind() -{ - return "static assert"; -} - -void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte('('); - exp->toCBuffer(buf, hgs); - if (msg) - { - buf->writeByte(','); - msg->toCBuffer(buf, hgs); - } - buf->writestring(");"); - buf->writenl(); -} + +// 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 +#include +#include + +#include "dsymbol.h" +#include "staticassert.h" +#include "expression.h" +#include "id.h" +#include "hdrgen.h" +#include "scope.h" +#include "template.h" +#include "declaration.h" + + +/********************************* AttribDeclaration ****************************/ + +StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg) + : Dsymbol(Id::empty) +{ + this->loc = loc; + this->exp = exp; + this->msg = msg; +} + +Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s) +{ + StaticAssert *sa; + + assert(!s); + sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); + return sa; +} + +int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + return 0; // we didn't add anything +} + +void StaticAssert::semantic(Scope *sc) +{ +} + +void StaticAssert::semantic2(Scope *sc) +{ + Expression *e; + + //printf("StaticAssert::semantic2() %s\n", toChars()); + e = exp->semantic(sc); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->isBool(FALSE)) + { + if (msg) + { HdrGenState hgs; + OutBuffer buf; + + msg = msg->semantic(sc); + msg = msg->optimize(WANTvalue | WANTinterpret); + hgs.console = 1; + msg->toCBuffer(&buf, &hgs); + error("%s", buf.toChars()); + } + else + error("(%s) is false", exp->toChars()); + if (sc->tinst) + sc->tinst->printInstantiationTrace(); + if (!global.gag) + fatal(); + } + else if (!e->isBool(TRUE)) + { + error("(%s) is not evaluatable at compile time", exp->toChars()); + } +} + +int StaticAssert::oneMember(Dsymbol **ps) +{ + //printf("StaticAssert::oneMember())\n"); + *ps = NULL; + return TRUE; +} + +void StaticAssert::inlineScan() +{ +} + +void StaticAssert::toObjFile(int multiobj) +{ +} + +const char *StaticAssert::kind() +{ + return "static assert"; +} + +void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(kind()); + buf->writeByte('('); + exp->toCBuffer(buf, hgs); + if (msg) + { + buf->writeByte(','); + msg->toCBuffer(buf, hgs); + } + buf->writestring(");"); + buf->writenl(); +} diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h index 22bf0c57..632c1e90 100644 --- a/dmd2/staticassert.h +++ b/dmd2/staticassert.h @@ -1,43 +1,43 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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. - -#ifndef DMD_STATICASSERT_H -#define DMD_STATICASSERT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -#ifdef _DH -struct HdrGenState; -#endif - -struct StaticAssert : Dsymbol -{ - Expression *exp; - Expression *msg; - - StaticAssert(Loc loc, Expression *exp, Expression *msg); - - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void inlineScan(); - int oneMember(Dsymbol **ps); - void toObjFile(int multiobj); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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. + +#ifndef DMD_STATICASSERT_H +#define DMD_STATICASSERT_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + +struct Expression; +#ifdef _DH +struct HdrGenState; +#endif + +struct StaticAssert : Dsymbol +{ + Expression *exp; + Expression *msg; + + StaticAssert(Loc loc, Expression *exp, Expression *msg); + + Dsymbol *syntaxCopy(Dsymbol *s); + int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void inlineScan(); + int oneMember(Dsymbol **ps); + void toObjFile(int multiobj); + const char *kind(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +#endif diff --git a/dmd2/struct.c b/dmd2/struct.c index 8ed3991d..881d2288 100644 --- a/dmd2/struct.c +++ b/dmd2/struct.c @@ -1,588 +1,686 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "statement.h" -#include "template.h" - -/********************************* AggregateDeclaration ****************************/ - -AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) - : ScopeDsymbol(id) -{ - this->loc = loc; - - storage_class = 0; - protection = PROTpublic; - type = NULL; - handle = NULL; - structsize = 0; // size of struct - alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect - hasUnions = 0; - sizeok = 0; // size not determined yet - isdeprecated = 0; - inv = NULL; - aggNew = NULL; - aggDelete = NULL; - -#if IN_DMD - stag = NULL; - sinit = NULL; -#endif - isnested = 0; - vthis = NULL; - -#if DMDV2 - ctor = NULL; - defaultCtor = NULL; - aliasthis = NULL; -#endif - dtor = NULL; - -#if IN_LLVM - availableExternally = true; // assume this unless proven otherwise -#endif -} - -enum PROT AggregateDeclaration::prot() -{ - return protection; -} - -void AggregateDeclaration::semantic2(Scope *sc) -{ - //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); - if (scope && members) - { error("has forward references"); - return; - } - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic2(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::semantic3(Scope *sc) -{ int i; - -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif - - //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); - if (members) - { - sc = sc->push(this); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic3(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::inlineScan() -{ int i; - - //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); - if (members) - { - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("inline scan aggregate symbol '%s'\n", s->toChars()); - s->inlineScan(); - } - } -} - -unsigned AggregateDeclaration::size(Loc loc) -{ - //printf("AggregateDeclaration::size() = %d\n", structsize); - if (!members) - error(loc, "unknown size"); - if (sizeok != 1) - { error(loc, "no size yet for forward reference"); - //*(char*)0=0; - } - return structsize; -} - -Type *AggregateDeclaration::getType() -{ - return type; -} - -int AggregateDeclaration::isDeprecated() -{ - return isdeprecated; -} - -/**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - */ - -void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field - unsigned *poffset) -{ - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign > 1) - { - assert(size != 3); - int sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); - } - //printf("result = %d\n",offset); -} - - -void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) -{ - unsigned memsize; // size of member - unsigned memalignsize; // size of member for alignment purposes - unsigned xalign; // alignment boundaries - - //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); - assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls))); - - // Check for forward referenced types which will fail the size() call - Type *t = v->type->toBasetype(); - if (v->storage_class & STCref) - { // References are the size of a pointer - t = Type::tvoidptr; - } - if (t->ty == Tstruct /*&& isStructDeclaration()*/) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == this) - { - error("cannot have field %s with same struct type", v->toChars()); - } -#endif - - if (ts->sym->sizeok != 1) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - - memsize = t->size(loc); - memalignsize = t->alignsize(); - xalign = t->memalign(sc->structalign); - alignmember(xalign, memalignsize, &sc->offset); - v->offset = sc->offset; - sc->offset += memsize; - if (sc->offset > structsize) - structsize = sc->offset; - if (sc->structalign < memalignsize) - memalignsize = sc->structalign; - if (alignsize < memalignsize) - alignsize = memalignsize; - //printf("\talignsize = %d\n", alignsize); - - v->storage_class |= STCfield; - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); - fields.push(v); -} - - -/**************************************** - * Returns !=0 if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing aggregate or function) - */ - -int AggregateDeclaration::isNested() -{ - return isnested; -} - - -/********************************* StructDeclaration ****************************/ - -StructDeclaration::StructDeclaration(Loc loc, Identifier *id) - : AggregateDeclaration(loc, id) -{ - zeroInit = 0; // assume false until we do semantic processing -#if DMDV2 - hasIdentityAssign = 0; - cpctor = NULL; - postblit = NULL; -#endif - - // For forward references - type = new TypeStruct(this); -} - -Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) -{ - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; -} - -void StructDeclaration::semantic(Scope *sc) -{ int i; - Scope *sc2; - - //printf("+StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - //static int count; if (++count == 20) *(char*)0=0; - - assert(type); - if (!members) // if forward reference - return; - - if (symtab) - { if (!scope) - return; // semantic() already completed - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - parent = sc->parent; - type = type->semantic(loc, sc); -#if STRUCTTHISREF - handle = type; -#else - handle = type->pointerTo(); -#endif - structalign = sc->structalign; - protection = sc->protection; - storage_class |= sc->stc; - if (sc->stc & STCdeprecated) - isdeprecated = 1; - assert(!isAnonymous()); - if (sc->stc & STCabstract) - error("structs, unions cannot be abstract"); -#if DMDV2 - if (storage_class & STCimmutable) - type = type->invariantOf(); - else if (storage_class & STCconst) - type = type->constOf(); - else if (storage_class & STCshared) - type = type->sharedOf(); -#endif - - if (sizeok == 0) // if not already done the addMember step - { - int hasfunctions = 0; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); - s->addMember(sc, this, 1); - if (s->isFuncDeclaration()) - hasfunctions = 1; - } - - // If nested struct, add in hidden 'this' pointer to outer scope - if (hasfunctions && !(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - AggregateDeclaration *ad = s->isAggregateDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - TemplateInstance *ti; - if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd) - { isnested = 1; - Type *t; - if (ad) - t = ad->handle; - else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; - else - t = Type::tvoidptr; - } - else - assert(0); - if (t->ty == Tstruct) - t = Type::tvoidptr; // t should not be a ref type - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - //vthis->storage_class |= STCref; - members->push(vthis); - } - } - } - } - - sizeok = 0; - sc2 = sc->push(this); - sc2->stc &= storage_class & STC_TYPECTOR; - sc2->parent = this; - if (isUnionDeclaration()) - sc2->inunion = 1; - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - - int members_dim = members->dim; - for (i = 0; i < members_dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc2); - if (isUnionDeclaration()) - sc2->offset = 0; -#if 0 - if (sizeok == 2) - { //printf("forward reference\n"); - break; - } -#endif - Type *t; - if (s->isDeclaration() && - (t = s->isDeclaration()->type) != NULL && - t->toBasetype()->ty == Tstruct) - { StructDeclaration *sd = (StructDeclaration *)t->toDsymbol(sc); - if (sd->isnested) - error("inner struct %s cannot be a field", sd->toChars()); - } - } - - /* The TypeInfo_Struct is expecting an opEquals and opCmp with - * a parameter that is a pointer to the struct. But if there - * isn't one, but is an opEquals or opCmp with a value, write - * another that is a shell around the value: - * int opCmp(struct *p) { return opCmp(*p); } - */ - - TypeFunction *tfeqptr; - { - Arguments *arguments = new Arguments; - Argument *arg = new Argument(STCin, handle, Id::p, NULL); - - arguments->push(arg); - tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); - } - - TypeFunction *tfeq; - { - Arguments *arguments = new Arguments; - Argument *arg = new Argument(STCin, type, NULL, NULL); - - arguments->push(arg); - tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeq = (TypeFunction *)tfeq->semantic(0, sc); - } - - Identifier *id = Id::eq; - for (int i = 0; i < 2; i++) - { - Dsymbol *s = search_function(this, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); - if (!fd) - { fd = fdx->overloadExactMatch(tfeq, getModule()); - if (fd) - { // Create the thunk, fdptr - FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); - Expression *e = new IdentifierExp(loc, Id::p); - e = new PtrExp(loc, e); - Expressions *args = new Expressions(); - args->push(e); - e = new IdentifierExp(loc, id); - e = new CallExp(loc, e, args); - fdptr->fbody = new ReturnStatement(loc, e); - ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); - assert(s); - s->members->push(fdptr); - fdptr->addMember(sc, s, 1); - fdptr->semantic(sc2); - } - } - } - - id = Id::cmp; - } -#if DMDV2 - dtor = buildDtor(sc2); - postblit = buildPostBlit(sc2); - cpctor = buildCpCtor(sc2); - buildOpAssign(sc2); -#endif - - sc2->pop(); - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - //printf("\tdeferring %s\n", toChars()); - return; - } - - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = 1; - Module::dprogress++; - - //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - // Determine if struct is all zeros or not - zeroInit = 1; - for (i = 0; i < fields.dim; i++) - { - Dsymbol *s = (Dsymbol *)fields.data[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd && !vd->isDataseg()) - { - if (vd->init) - { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; - } - else - { - if (!vd->type->isZeroInit(loc)) - { - zeroInit = 0; - break; - } - } - } - } - - /* Look for special member functions. - */ -#if DMDV2 - ctor = search(0, Id::ctor, 0); -#endif - inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - if (sc->func) - { - semantic2(sc); - semantic3(sc); - } -} - -void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - buf->printf("%s ", kind()); - if (!isAnonymous()) - buf->writestring(toChars()); - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - buf->writenl(); -} - - -const char *StructDeclaration::kind() -{ - return "struct"; -} - -/********************************* UnionDeclaration ****************************/ - -UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) - : StructDeclaration(loc, id) -{ -} - -Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) -{ - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; -} - - -const char *UnionDeclaration::kind() -{ - return "union"; -} - - + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include + +#include "root.h" +#include "aggregate.h" +#include "scope.h" +#include "mtype.h" +#include "declaration.h" +#include "module.h" +#include "id.h" +#include "statement.h" +#include "template.h" + +/********************************* AggregateDeclaration ****************************/ + +AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) + : ScopeDsymbol(id) +{ + this->loc = loc; + + storage_class = 0; + protection = PROTpublic; + type = NULL; + handle = NULL; + structsize = 0; // size of struct + alignsize = 0; // size of struct for alignment purposes + structalign = 0; // struct member alignment in effect + hasUnions = 0; + sizeok = 0; // size not determined yet + isdeprecated = 0; + inv = NULL; + aggNew = NULL; + aggDelete = NULL; + +#if IN_DMD + stag = NULL; + sinit = NULL; +#endif + isnested = 0; + vthis = NULL; + +#if DMDV2 + ctor = NULL; + defaultCtor = NULL; + aliasthis = NULL; +#endif + dtor = NULL; + +#if IN_LLVM + availableExternally = true; // assume this unless proven otherwise +#endif +} + +enum PROT AggregateDeclaration::prot() +{ + return protection; +} + +void AggregateDeclaration::semantic2(Scope *sc) +{ + //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); + if (scope && members) + { error("has forward references"); + return; + } + if (members) + { + sc = sc->push(this); + for (size_t i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic2(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::semantic3(Scope *sc) +{ int i; + +#if IN_LLVM + if (!global.params.useAvailableExternally) + availableExternally = false; +#endif + + //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); + if (members) + { + sc = sc->push(this); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc->pop(); + } +} + +void AggregateDeclaration::inlineScan() +{ int i; + + //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); + if (members) + { + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("inline scan aggregate symbol '%s'\n", s->toChars()); + s->inlineScan(); + } + } +} + +unsigned AggregateDeclaration::size(Loc loc) +{ + //printf("AggregateDeclaration::size() = %d\n", structsize); + if (!members) + error(loc, "unknown size"); + if (sizeok != 1 && scope) + semantic(NULL); + if (sizeok != 1) + { error(loc, "no size yet for forward reference"); + //*(char*)0=0; + } + return structsize; +} + +Type *AggregateDeclaration::getType() +{ + return type; +} + +int AggregateDeclaration::isDeprecated() +{ + return isdeprecated; +} + +/**************************** + * Do byte or word alignment as necessary. + * Align sizes of 0, as we may not know array sizes yet. + */ + +void AggregateDeclaration::alignmember( + unsigned salign, // struct alignment that is in effect + unsigned size, // alignment requirement of field + unsigned *poffset) +{ + //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); + if (salign > 1) + { + assert(size != 3); + int sa = size; + if (sa == 0 || salign < sa) + sa = salign; + *poffset = (*poffset + sa - 1) & ~(sa - 1); + } + //printf("result = %d\n",offset); +} + + +void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) +{ + unsigned memsize; // size of member + unsigned memalignsize; // size of member for alignment purposes + unsigned xalign; // alignment boundaries + + //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); + assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls))); + + // Check for forward referenced types which will fail the size() call + Type *t = v->type->toBasetype(); + if (v->storage_class & STCref) + { // References are the size of a pointer + t = Type::tvoidptr; + } + if (t->ty == Tstruct /*&& isStructDeclaration()*/) + { TypeStruct *ts = (TypeStruct *)t; +#if DMDV2 + if (ts->sym == this) + { + error("cannot have field %s with same struct type", v->toChars()); + } +#endif + + if (ts->sym->sizeok != 1 && ts->sym->scope) + ts->sym->semantic(NULL); + if (ts->sym->sizeok != 1) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + } + if (t->ty == Tident) + { + sizeok = 2; // cannot finish; flag as forward referenced + return; + } + + memsize = t->size(loc); + memalignsize = t->alignsize(); + xalign = t->memalign(sc->structalign); +#if 0 + alignmember(xalign, memalignsize, &sc->offset); + v->offset = sc->offset; + sc->offset += memsize; + if (sc->offset > structsize) + structsize = sc->offset; +#else + unsigned ofs = sc->offset; + alignmember(xalign, memalignsize, &ofs); + v->offset = ofs; + ofs += memsize; + if (ofs > structsize) + structsize = ofs; + if (!isUnionDeclaration()) + sc->offset = ofs; +#endif + if (sc->structalign < memalignsize) + memalignsize = sc->structalign; + if (alignsize < memalignsize) + alignsize = memalignsize; + //printf("\talignsize = %d\n", alignsize); + + v->storage_class |= STCfield; + //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); + fields.push(v); +} + + +/**************************************** + * Returns !=0 if there's an extra member which is the 'this' + * pointer to the enclosing context (enclosing aggregate or function) + */ + +int AggregateDeclaration::isNested() +{ + return isnested; +} + + +/********************************* StructDeclaration ****************************/ + +StructDeclaration::StructDeclaration(Loc loc, Identifier *id) + : AggregateDeclaration(loc, id) +{ + zeroInit = 0; // assume false until we do semantic processing +#if DMDV2 + hasIdentityAssign = 0; + cpctor = NULL; + postblit = NULL; + eq = NULL; +#endif + + // For forward references + type = new TypeStruct(this); +} + +Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) +{ + StructDeclaration *sd; + + if (s) + sd = (StructDeclaration *)s; + else + sd = new StructDeclaration(loc, ident); + ScopeDsymbol::syntaxCopy(sd); + return sd; +} + +void StructDeclaration::semantic(Scope *sc) +{ + Scope *sc2; + + //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, toChars(), sizeok); + + //static int count; if (++count == 20) halt(); + + assert(type); + if (!members) // if forward reference + return; + + if (symtab) + { if (sizeok == 1 || !scope) + { //printf("already completed\n"); + scope = NULL; + return; // semantic() already completed + } + } + else + symtab = new DsymbolTable(); + + Scope *scx = NULL; + if (scope) + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; + } + + unsigned dprogress_save = Module::dprogress; + + parent = sc->parent; + type = type->semantic(loc, sc); +#if STRUCTTHISREF + handle = type; +#else + handle = type->pointerTo(); +#endif + structalign = sc->structalign; + protection = sc->protection; + storage_class |= sc->stc; + if (sc->stc & STCdeprecated) + isdeprecated = 1; + assert(!isAnonymous()); + if (sc->stc & STCabstract) + error("structs, unions cannot be abstract"); +#if DMDV2 + if (storage_class & STCimmutable) + type = type->invariantOf(); + else if (storage_class & STCconst) + type = type->constOf(); + else if (storage_class & STCshared) + type = type->sharedOf(); +#endif + + if (sizeok == 0) // if not already done the addMember step + { + int hasfunctions = 0; + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); + s->addMember(sc, this, 1); + if (s->isFuncDeclaration()) + hasfunctions = 1; + } + + // If nested struct, add in hidden 'this' pointer to outer scope + if (hasfunctions && !(storage_class & STCstatic)) + { Dsymbol *s = toParent2(); + if (s) + { + AggregateDeclaration *ad = s->isAggregateDeclaration(); + FuncDeclaration *fd = s->isFuncDeclaration(); + + TemplateInstance *ti; + if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd) + { isnested = 1; + Type *t; + if (ad) + t = ad->handle; + else if (fd) + { AggregateDeclaration *ad = fd->isMember2(); + if (ad) + t = ad->handle; + else + t = Type::tvoidptr; + } + else + assert(0); + if (t->ty == Tstruct) + t = Type::tvoidptr; // t should not be a ref type + assert(!vthis); + vthis = new ThisDeclaration(loc, t); + //vthis->storage_class |= STCref; + members->push(vthis); + } + } + } + } + + sizeok = 0; + sc2 = sc->push(this); + sc2->stc &= storage_class & STC_TYPECTOR; + sc2->parent = this; + if (isUnionDeclaration()) + sc2->inunion = 1; + sc2->protection = PROTpublic; + sc2->explicitProtection = 0; + + int members_dim = members->dim; + + /* Set scope so if there are forward references, we still might be able to + * resolve individual members like enums. + */ + for (int i = 0; i < members_dim; i++) + { Dsymbol *s = (Dsymbol *)members->data[i]; + /* There are problems doing this in the general case because + * Scope keeps track of things like 'offset' + */ + if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) + { + //printf("setScope %s %s\n", s->kind(), s->toChars()); + s->setScope(sc2); + } + } + + for (int i = 0; i < members_dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc2); +#if 0 + if (sizeok == 2) + { //printf("forward reference\n"); + break; + } +#endif + +#if 0 /* Decided to allow this because if the field is initialized by copying it from + * a correctly initialized struct, it will work. + */ + Type *t; + if (s->isDeclaration() && + (t = s->isDeclaration()->type) != NULL && + t->toBasetype()->ty == Tstruct) + { StructDeclaration *sd = (StructDeclaration *)t->toDsymbol(sc); + if (sd->isnested) + error("inner struct %s cannot be the type for field %s as it must embed a reference to its enclosing %s", + sd->toChars(), s->toChars(), sd->toParent2()->toPrettyChars()); + } +#endif + } + +#if DMDV1 + /* This doesn't work for DMDV2 because (ref S) and (S) parameter + * lists will overload the same. + */ + /* The TypeInfo_Struct is expecting an opEquals and opCmp with + * a parameter that is a pointer to the struct. But if there + * isn't one, but is an opEquals or opCmp with a value, write + * another that is a shell around the value: + * int opCmp(struct *p) { return opCmp(*p); } + */ + + TypeFunction *tfeqptr; + { + Parameters *arguments = new Parameters; + Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); + + arguments->push(arg); + tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); + } + + TypeFunction *tfeq; + { + Parameters *arguments = new Parameters; + Parameter *arg = new Parameter(STCin, type, NULL, NULL); + + arguments->push(arg); + tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); + tfeq = (TypeFunction *)tfeq->semantic(0, sc); + } + + Identifier *id = Id::eq; + for (int i = 0; i < 2; i++) + { + Dsymbol *s = search_function(this, id); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); + if (!fd) + { fd = fdx->overloadExactMatch(tfeq, getModule()); + if (fd) + { // Create the thunk, fdptr + FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); + Expression *e = new IdentifierExp(loc, Id::p); + e = new PtrExp(loc, e); + Expressions *args = new Expressions(); + args->push(e); + e = new IdentifierExp(loc, id); + e = new CallExp(loc, e, args); + fdptr->fbody = new ReturnStatement(loc, e); + ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); + assert(s); + s->members->push(fdptr); + fdptr->addMember(sc, s, 1); + fdptr->semantic(sc2); + } + } + } + + id = Id::cmp; + } +#endif +#if DMDV2 + /* Try to find the opEquals function. Build it if necessary. + */ + TypeFunction *tfeqptr; + { // bool opEquals(const T*) const; + Parameters *parameters = new Parameters; +#if STRUCTTHISREF + // bool opEquals(ref const T) const; + Parameter *param = new Parameter(STCref, type->constOf(), NULL, NULL); +#else + // bool opEquals(const T*) const; + Parameter *param = new Parameter(STCin, type->pointerTo(), NULL, NULL); +#endif + + parameters->push(param); + tfeqptr = new TypeFunction(parameters, Type::tbool, 0, LINKd); + tfeqptr->mod = MODconst; + tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc2); + + Dsymbol *s = search_function(this, Id::eq); + FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; + if (fdx) + { + eq = fdx->overloadExactMatch(tfeqptr, getModule()); + if (!eq) + fdx->error("type signature should be %s not %s", tfeqptr->toChars(), fdx->type->toChars()); + } + + TemplateDeclaration *td = s ? s->isTemplateDeclaration() : NULL; + // BUG: should also check that td is a function template, not just a template + + if (!eq && !td) + eq = buildOpEquals(sc2); + } + + dtor = buildDtor(sc2); + postblit = buildPostBlit(sc2); + cpctor = buildCpCtor(sc2); + buildOpAssign(sc2); +#endif + + sc2->pop(); + + if (sizeok == 2) + { // semantic() failed because of forward references. + // Unwind what we did, and defer it for later + fields.setDim(0); + structsize = 0; + alignsize = 0; + structalign = 0; + + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + + Module::dprogress = dprogress_save; + //printf("\tdeferring %s\n", toChars()); + return; + } + + // 0 sized struct's are set to 1 byte + if (structsize == 0) + { + structsize = 1; + alignsize = 1; + } + + // Round struct size up to next alignsize boundary. + // This will ensure that arrays of structs will get their internals + // aligned properly. + structsize = (structsize + alignsize - 1) & ~(alignsize - 1); + + sizeok = 1; + Module::dprogress++; + + //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); + + // Determine if struct is all zeros or not + zeroInit = 1; + for (int i = 0; i < fields.dim; i++) + { + Dsymbol *s = (Dsymbol *)fields.data[i]; + VarDeclaration *vd = s->isVarDeclaration(); + if (vd && !vd->isDataseg()) + { + if (vd->init) + { + // Should examine init to see if it is really all 0's + zeroInit = 0; + break; + } + else + { + if (!vd->type->isZeroInit(loc)) + { + zeroInit = 0; + break; + } + } + } + } + + /* Look for special member functions. + */ +#if DMDV2 + ctor = search(0, Id::ctor, 0); +#endif + inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); + aggNew = (NewDeclaration *)search(0, Id::classNew, 0); + aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); + + if (sc->func) + { + semantic2(sc); + semantic3(sc); + } +} + +Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) +{ + //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); + + if (scope) + semantic(scope); + + if (!members || !symtab) + { + error("is forward referenced when looking for '%s'", ident->toChars()); + return NULL; + } + + return ScopeDsymbol::search(loc, ident, flags); +} + +void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ int i; + + buf->printf("%s ", kind()); + if (!isAnonymous()) + buf->writestring(toChars()); + if (!members) + { + buf->writeByte(';'); + buf->writenl(); + return; + } + buf->writenl(); + buf->writeByte('{'); + buf->writenl(); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + + buf->writestring(" "); + s->toCBuffer(buf, hgs); + } + buf->writeByte('}'); + buf->writenl(); +} + + +const char *StructDeclaration::kind() +{ + return "struct"; +} + +/********************************* UnionDeclaration ****************************/ + +UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) + : StructDeclaration(loc, id) +{ +} + +Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) +{ + UnionDeclaration *ud; + + if (s) + ud = (UnionDeclaration *)s; + else + ud = new UnionDeclaration(loc, ident); + StructDeclaration::syntaxCopy(ud); + return ud; +} + + +const char *UnionDeclaration::kind() +{ + return "union"; +} + + diff --git a/dmd2/template.c b/dmd2/template.c index c505ac4d..ebd9ad5d 100644 --- a/dmd2/template.c +++ b/dmd2/template.c @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars +// Copyright (c) 1999-2010 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -28,13 +28,14 @@ #include "declaration.h" #include "dsymbol.h" #include "hdrgen.h" +#include "id.h" #if WINDOWS_SEH #include long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); #endif -#define LOG 0 +#define LOG 0 /******************************************** * These functions substitute for dynamic_cast. dynamic_cast does not work @@ -45,7 +46,7 @@ Expression *isExpression(Object *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; + return NULL; return (Expression *)o; } @@ -53,7 +54,7 @@ Dsymbol *isDsymbol(Object *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; + return NULL; return (Dsymbol *)o; } @@ -61,7 +62,7 @@ Type *isType(Object *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; + return NULL; return (Type *)o; } @@ -69,10 +70,40 @@ Tuple *isTuple(Object *o) { //return dynamic_cast(o); if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; + return NULL; return (Tuple *)o; } +/************************************** + * Is this Object an error? + */ +int isError(Object *o) +{ + Type *t = isType(o); + if (t) + return (t->ty == Terror); + Expression *e = isExpression(o); + if (e) + return (e->op == TOKerror); + Tuple *v = isTuple(o); + if (v) + return arrayObjectIsError(&v->objects); + return 0; +} + +/************************************** + * Are any of the Objects an error? + */ +int arrayObjectIsError(Objects *args) +{ + for (size_t i = 0; i < args->dim; i++) + { + Object *o = (Object *)args->data[i]; + if (isError(o)) + return 1; + } + return 0; +} /*********************** * Try to get arg as a type. @@ -83,8 +114,8 @@ Type *getType(Object *o) Type *t = isType(o); if (!t) { Expression *e = isExpression(o); - if (e) - t = e->type; + if (e) + t = e->type; } return t; } @@ -95,20 +126,20 @@ Dsymbol *getDsymbol(Object *oarg) Expression *ea = isExpression(oarg); if (ea) { // Try to convert Expression to symbol - if (ea->op == TOKvar) - sa = ((VarExp *)ea)->var; - else if (ea->op == TOKfunction) - sa = ((FuncExp *)ea)->fd; - else - sa = NULL; + if (ea->op == TOKvar) + sa = ((VarExp *)ea)->var; + else if (ea->op == TOKfunction) + sa = ((FuncExp *)ea)->fd; + else + sa = NULL; } else { // Try to convert Type to symbol - Type *ta = isType(oarg); - if (ta) - sa = ta->toDsymbol(NULL); - else - sa = isDsymbol(oarg); // if already a symbol + Type *ta = isType(oarg); + if (ta) + sa = ta->toDsymbol(NULL); + else + sa = isDsymbol(oarg); // if already a symbol } return sa; } @@ -138,84 +169,105 @@ int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) if (t1) { - /* if t1 is an instance of ti, then give error - * about recursive expansions. - */ - Dsymbol *s = t1->toDsymbol(sc); - if (s && s->parent) - { TemplateInstance *ti1 = s->parent->isTemplateInstance(); - if (ti1 && ti1->tempdecl == tempdecl) - { - for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) - { - if (sc1->scopesym == ti1) - { - error("recursive template expansion for template argument %s", t1->toChars()); - return 1; // fake a match - } - } - } - } + /* if t1 is an instance of ti, then give error + * about recursive expansions. + */ + Dsymbol *s = t1->toDsymbol(sc); + if (s && s->parent) + { TemplateInstance *ti1 = s->parent->isTemplateInstance(); + if (ti1 && ti1->tempdecl == tempdecl) + { + for (Scope *sc1 = sc; sc1; sc1 = sc1->enclosing) + { + if (sc1->scopesym == ti1) + { + error("recursive template expansion for template argument %s", t1->toChars()); + return 1; // fake a match + } + } + } + } - //printf("t1 = %s\n", t1->toChars()); - //printf("t2 = %s\n", t2->toChars()); - if (!t2 || !t1->equals(t2)) - goto Lnomatch; + //printf("t1 = %s\n", t1->toChars()); + //printf("t2 = %s\n", t2->toChars()); + if (!t2 || !t1->equals(t2)) + goto Lnomatch; } else if (e1) { #if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - e1->type->print(); - e2->type->print(); - } + if (e1 && e2) + { + printf("match %d\n", e1->equals(e2)); + e1->print(); + e2->print(); + e1->type->print(); + e2->type->print(); + } #endif - if (!e2) - goto Lnomatch; - if (!e1->equals(e2)) - goto Lnomatch; + if (!e2) + goto Lnomatch; + if (!e1->equals(e2)) + goto Lnomatch; } else if (s1) { - //printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - { - goto Lnomatch; - } + //printf("%p %s, %p %s\n", s1, s1->toChars(), s2, s2->toChars()); + if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) + { + goto Lnomatch; + } #if DMDV2 - VarDeclaration *v1 = s1->isVarDeclaration(); - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v1 && v2 && v1->storage_class & v2->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei1 && ei2 && !ei1->exp->equals(ei2->exp)) - goto Lnomatch; - } + VarDeclaration *v1 = s1->isVarDeclaration(); + VarDeclaration *v2 = s2->isVarDeclaration(); + if (v1 && v2 && v1->storage_class & v2->storage_class & STCmanifest) + { ExpInitializer *ei1 = v1->init->isExpInitializer(); + ExpInitializer *ei2 = v2->init->isExpInitializer(); + if (ei1 && ei2 && !ei1->exp->equals(ei2->exp)) + goto Lnomatch; + } #endif } else if (v1) { - if (!v2) - goto Lnomatch; - if (v1->objects.dim != v2->objects.dim) - goto Lnomatch; - for (size_t i = 0; i < v1->objects.dim; i++) - { - if (!match((Object *)v1->objects.data[i], - (Object *)v2->objects.data[i], - tempdecl, sc)) - goto Lnomatch; - } + if (!v2) + goto Lnomatch; + if (v1->objects.dim != v2->objects.dim) + goto Lnomatch; + for (size_t i = 0; i < v1->objects.dim; i++) + { + if (!match((Object *)v1->objects.data[i], + (Object *)v2->objects.data[i], + tempdecl, sc)) + goto Lnomatch; + } } //printf("match\n"); - return 1; // match + return 1; // match Lnomatch: //printf("nomatch\n"); - return 0; // nomatch; + return 0; // nomatch; +} + + +/************************************ + * Match an array of them. + */ +int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) +{ + if (oa1 == oa2) + return 1; + if (oa1->dim != oa2->dim) + return 0; + for (size_t j = 0; j < oa1->dim; j++) + { Object *o1 = (Object *)oa1->data[j]; + Object *o2 = (Object *)oa2->data[j]; + if (!match(o1, o2, tempdecl, sc)) + { + return 0; + } + } + return 1; } /**************************************** @@ -229,37 +281,37 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) Dsymbol *s = isDsymbol(oarg); Tuple *v = isTuple(oarg); if (t) - { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); + { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); + t->toCBuffer(buf, NULL, hgs); } else if (e) - e->toCBuffer(buf, hgs); + e->toCBuffer(buf, hgs); else if (s) { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); } else if (v) { - Objects *args = &v->objects; - for (size_t i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *o = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, o); - } + Objects *args = &v->objects; + for (size_t i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *o = (Object *)args->data[i]; + ObjectToCBuffer(buf, hgs, o); + } } else if (!oarg) { - buf->writestring("NULL"); + buf->writestring("NULL"); } else { #ifdef DEBUG - printf("bad Object = %p\n", oarg); + printf("bad Object = %p\n", oarg); #endif - assert(0); + assert(0); } } @@ -267,13 +319,13 @@ void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) Object *objectSyntaxCopy(Object *o) { if (!o) - return NULL; + return NULL; Type *t = isType(o); if (t) - return t->syntaxCopy(); + return t->syntaxCopy(); Expression *e = isExpression(o); if (e) - return e->syntaxCopy(); + return e->syntaxCopy(); return o; } #endif @@ -282,7 +334,7 @@ Object *objectSyntaxCopy(Object *o) /* ======================== TemplateDeclaration ============================= */ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Array *decldefs) + TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) : ScopeDsymbol(id) { #if LOG @@ -290,16 +342,16 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, #endif #if 0 if (parameters) - for (int i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - //printf("\tparameter[%d] = %p\n", i, tp); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + for (int i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + //printf("\tparameter[%d] = %p\n", i, tp); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - { - printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); - } - } + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); + } + } #endif this->loc = loc; this->parameters = parameters; @@ -311,6 +363,8 @@ TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, this->semanticRun = 0; this->onemember = NULL; this->literal = 0; + this->ismixin = ismixin; + this->previous = NULL; } Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) @@ -318,23 +372,22 @@ Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) //printf("TemplateDeclaration::syntaxCopy()\n"); TemplateDeclaration *td; TemplateParameters *p; - Array *d; p = NULL; if (parameters) { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (int i = 0; i < p->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - p->data[i] = (void *)tp->syntaxCopy(); - } + p = new TemplateParameters(); + p->setDim(parameters->dim); + for (int i = 0; i < p->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + p->data[i] = (void *)tp->syntaxCopy(); + } } Expression *e = NULL; if (constraint) - e = constraint->syntaxCopy(); - d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d); + e = constraint->syntaxCopy(); + Dsymbols *d = Dsymbol::arraySyntaxCopy(members); + td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); #if IN_LLVM td->intrinsicName = intrinsicName; @@ -347,22 +400,28 @@ void TemplateDeclaration::semantic(Scope *sc) { #if LOG printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); + printf("sc->stc = %llx\n", sc->stc); + printf("sc->module = %s\n", sc->module->toChars()); #endif if (semanticRun) - return; // semantic() already run + return; // semantic() already run semanticRun = 1; + if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) + { Type::associativearray = this; + } + if (sc->func) { #if DMDV1 - error("cannot declare template at function scope %s", sc->func->toChars()); + error("cannot declare template at function scope %s", sc->func->toChars()); #endif } if (/*global.params.useArrayBounds &&*/ sc->module) { - // Generate this function as it may be used - // when template is instantiated in other modules + // Generate this function as it may be used + // when template is instantiated in other modules // FIXME: LDC //sc->module->toModuleArray(); @@ -370,8 +429,8 @@ void TemplateDeclaration::semantic(Scope *sc) if (/*global.params.useAssert &&*/ sc->module) { - // Generate this function as it may be used - // when template is instantiated in other modules + // Generate this function as it may be used + // when template is instantiated in other modules // FIXME: LDC //sc->module->toModuleAssert(); @@ -391,60 +450,60 @@ void TemplateDeclaration::semantic(Scope *sc) paramscope->stc = 0; if (!parent) - parent = sc->parent; + parent = sc->parent; if (global.params.doDocComments) { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (int i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - origParameters->data[i] = (void *)tp->syntaxCopy(); - } + origParameters = new TemplateParameters(); + origParameters->setDim(parameters->dim); + for (int i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + origParameters->data[i] = (void *)tp->syntaxCopy(); + } } for (int i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->declareParameter(paramscope); + tp->declareParameter(paramscope); } for (int i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - error("template tuple parameter must be last one"); + tp->semantic(paramscope); + if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) + error("template tuple parameter must be last one"); } paramscope->pop(); if (members) { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s)) - { - if (s && s->ident && s->ident->equals(ident)) - { - onemember = s; - s->parent = this; - } - } + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s)) + { + if (s && s->ident && s->ident->equals(ident)) + { + onemember = s; + s->parent = this; + } + } } /* BUG: should check: - * o no virtual functions or non-static data members of classes + * o no virtual functions or non-static data members of classes */ } const char *TemplateDeclaration::kind() { return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; + ? onemember->kind() + : (char *)"template"; } /********************************** @@ -462,34 +521,34 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) #endif f = s->isTemplateDeclaration(); if (!f) - return FALSE; + return FALSE; TemplateDeclaration *pthis = this; for (pf = &pthis; *pf; pf = &(*pf)->overnext) { #if 0 - // Conflict if TemplateParameter's match - // Will get caught anyway later with TemplateInstance, but - // should check it now. - TemplateDeclaration *f2 = *pf; + // Conflict if TemplateParameter's match + // Will get caught anyway later with TemplateInstance, but + // should check it now. + TemplateDeclaration *f2 = *pf; - if (f->parameters->dim != f2->parameters->dim) - goto Lcontinue; + if (f->parameters->dim != f2->parameters->dim) + goto Lcontinue; - for (int i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; - TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; + for (int i = 0; i < f->parameters->dim; i++) + { TemplateParameter *p1 = (TemplateParameter *)f->parameters->data[i]; + TemplateParameter *p2 = (TemplateParameter *)f2->parameters->data[i]; - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } + if (!p1->overloadMatch(p2)) + goto Lcontinue; + } #if LOG - printf("\tfalse: conflict\n"); + printf("\tfalse: conflict\n"); #endif - return FALSE; + return FALSE; Lcontinue: - ; + ; #endif } @@ -501,20 +560,63 @@ int TemplateDeclaration::overloadInsert(Dsymbol *s) return TRUE; } +/**************************** + * Declare all the function parameters as variables + * and add them to the scope + */ +void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope) +{ + /* We do this ONLY if there is only one function in the template. + */ + FuncDeclaration *fd = onemember && onemember->toAlias() ? + onemember->toAlias()->isFuncDeclaration() : NULL; + if (fd) + { + paramscope->parent = fd; + int fvarargs; // function varargs + Parameters *fparameters = fd->getParameters(&fvarargs); + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (int i = 0; i < nfparams; i++) + { + Parameter *fparam = Parameter::getNth(fparameters, i)->syntaxCopy(); + if (!fparam->ident) + continue; // don't add it, if it has no name + Type *vtype = fparam->type->syntaxCopy(); + // isPure will segfault if called on a ctor, because fd->type is null. + if (fd->type && fd->isPure()) + vtype = vtype->addMod(MODconst); + VarDeclaration *v = new VarDeclaration(loc, vtype, fparam->ident, NULL); + v->storage_class |= STCparameter; + // Not sure if this condition is correct/necessary. + // It's from func.c + if (//fd->type && fd->type->ty == Tfunction && + fvarargs == 2 && i + 1 == nfparams) + v->storage_class |= STCvariadic; + + v->storage_class |= fparam->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); + v->semantic(paramscope); + if (!paramscope->insert(v)) + error("parameter %s.%s is already defined", toChars(), v->toChars()); + else + v->parent = this; + } + } +} + /*************************************** * Given that ti is an instance of this TemplateDeclaration, * deduce the types of the parameters to this, and store * those deduced types in dedtypes[]. * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() + * flag 1: don't do semantic() because of dummy types + * 2: don't change types in matchArg() * Output: - * dedtypes deduced arguments + * dedtypes deduced arguments * Return match level. */ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, int flag) + Objects *dedtypes, int flag) { MATCH m; int dedtypes_dim = dedtypes->dim; @@ -526,9 +628,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, #if 0 printf("dedtypes->dim = %d, parameters->dim = %d\n", dedtypes_dim, parameters->dim); if (ti->tiargs->dim) - printf("ti->tiargs->dim = %d, [0] = %p\n", - ti->tiargs->dim, - ti->tiargs->data[0]); + printf("ti->tiargs->dim = %d, [0] = %p\n", + ti->tiargs->dim, + ti->tiargs->data[0]); #endif dedtypes->zero(); @@ -539,9 +641,9 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, if (ti->tiargs->dim > parameters_dim && !variadic) { #if LOGM - printf(" no match: more arguments than parameters\n"); + printf(" no match: more arguments than parameters\n"); #endif - return MATCHnomatch; + return MATCHnomatch; } assert(dedtypes_dim == parameters_dim); @@ -557,65 +659,66 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, // Attempt type deduction m = MATCHexact; for (int i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Declaration *sparam; + { MATCH m2; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Declaration *sparam; - //printf("\targument [%d]\n", i); + //printf("\targument [%d]\n", i); #if LOGM - //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - if (ttp) - printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); + //printf("\targument [%d] is %s\n", i, oarg ? oarg->toChars() : "null"); + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + if (ttp) + printf("\tparameter[%d] is %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); #endif #if DMDV1 - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); + m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); #else - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); + m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam, (flag & 2) ? 1 : 0); #endif - //printf("\tm2 = %d\n", m2); + //printf("\tm2 = %d\n", m2); - if (m2 == MATCHnomatch) - { + if (m2 == MATCHnomatch) + { #if 0 - printf("\tmatchArg() for parameter %i failed\n", i); + printf("\tmatchArg() for parameter %i failed\n", i); #endif - goto Lnomatch; - } + goto Lnomatch; + } - if (m2 < m) - m = m2; + if (m2 < m) + m = m2; - if (!flag) - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; + if (!flag) + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; } if (!flag) { - /* Any parameter left without a type gets the type of - * its corresponding arg - */ - for (int i = 0; i < dedtypes_dim; i++) - { - if (!dedtypes->data[i]) - { assert(i < ti->tiargs->dim); - dedtypes->data[i] = ti->tiargs->data[i]; - } - } + /* Any parameter left without a type gets the type of + * its corresponding arg + */ + for (int i = 0; i < dedtypes_dim; i++) + { + if (!dedtypes->data[i]) + { assert(i < ti->tiargs->dim); + dedtypes->data[i] = ti->tiargs->data[i]; + } + } } #if DMDV2 if (m && constraint && !(flag & 1)) - { /* Check to see if constraint is satisfied. - */ - Expression *e = constraint->syntaxCopy(); - paramscope->flags |= SCOPEstaticif; - e = e->semantic(paramscope); - e = e->optimize(WANTvalue | WANTinterpret); + { /* Check to see if constraint is satisfied. + */ + makeParamNamesVisibleInConstraint(paramscope); + Expression *e = constraint->syntaxCopy(); + paramscope->flags |= SCOPEstaticif; + e = e->semantic(paramscope); + e = e->optimize(WANTvalue | WANTinterpret); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -634,22 +737,22 @@ MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, printf("instance %s\n", ti->toChars()); if (m) { - for (int i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Object *oarg; + for (int i = 0; i < dedtypes_dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Object *oarg; - printf(" [%d]", i); + printf(" [%d]", i); - if (i < ti->tiargs->dim) - oarg = (Object *)ti->tiargs->data[i]; - else - oarg = NULL; - tp->print(oarg, (Object *)dedtypes->data[i]); - } + if (i < ti->tiargs->dim) + oarg = (Object *)ti->tiargs->data[i]; + else + oarg = NULL; + tp->print(oarg, (Object *)dedtypes->data[i]); + } } else - goto Lnomatch; + goto Lnomatch; #endif #if LOGM @@ -674,8 +777,8 @@ Lret: /******************************************** * Determine partial specialization order of 'this' vs td2. * Returns: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this + * match this is at least as specialized as td2 + * 0 td2 is more specialized than this */ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) @@ -687,10 +790,10 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) * as td2. */ - TemplateInstance ti(0, ident); // create dummy template instance + TemplateInstance ti(0, ident); // create dummy template instance Objects dedtypes; -#define LOG_LEASTAS 0 +#define LOG_LEASTAS 0 #if LOG_LEASTAS printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); @@ -702,13 +805,13 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) ti.tiargs->setDim(parameters->dim); for (int i = 0; i < ti.tiargs->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - void *p = tp->dummyArg(); - if (p) - ti.tiargs->data[i] = p; - else - ti.tiargs->setDim(i); + void *p = tp->dummyArg(); + if (p) + ti.tiargs->data[i] = p; + else + ti.tiargs->setDim(i); } // Temporary Array to hold deduced types @@ -719,16 +822,16 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) MATCH m = td2->matchWithInstance(&ti, &dedtypes, 1); if (m) { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; + /* A non-variadic template is more specialized than a + * variadic one. + */ + if (isVariadic() && !td2->isVariadic()) + goto L1; #if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); + printf(" matches %d, so is least as specialized\n", m); #endif - return m; + return m; } L1: #if LOG_LEASTAS @@ -741,40 +844,42 @@ MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) /************************************************* * Match function arguments against a specific template function. * Input: - * loc instantiation location - * targsi Expression/Type initial list of template arguments - * ethis 'this' argument if !NULL - * fargs arguments to function + * loc instantiation location + * targsi Expression/Type initial list of template arguments + * ethis 'this' argument if !NULL + * fargs arguments to function * Output: - * dedargs Expression/Type deduced template arguments + * dedargs Expression/Type deduced template arguments * Returns: - * match level + * match level */ -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, - Expression *ethis, Expressions *fargs, - Objects *dedargs) +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, + Expression *ethis, Expressions *fargs, + Objects *dedargs) { size_t i; size_t nfparams; size_t nfargs; - size_t nargsi; // array size of targsi + size_t nargsi; // array size of targsi int fptupindex = -1; int tuple_dim = 0; MATCH match = MATCHexact; FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - Arguments *fparameters; // function parameter list - int fvarargs; // function varargs - Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T + Parameters *fparameters; // function parameter list + int fvarargs; // function varargs + Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T #if 0 printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); for (i = 0; i < fargs->dim; i++) - { Expression *e = (Expression *)fargs->data[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); + { Expression *e = (Expression *)fargs->data[i]; + printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); } printf("fd = %s\n", fd->toChars()); - printf("fd->type = %p\n", fd->type); + printf("fd->type = %s\n", fd->type->toChars()); + if (ethis) + printf("ethis->type = %s\n", ethis->type->toChars()); #endif assert((size_t)scope > 0x10000); @@ -791,95 +896,83 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Scope *paramscope = scope->push(paramsym); TemplateTupleParameter *tp = isVariadic(); + int tp_is_declared = 0; #if 0 for (i = 0; i < dedargs->dim; i++) { - printf("\tdedarg[%d] = ", i); - Object *oarg = (Object *)dedargs->data[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); + printf("\tdedarg[%d] = ", i); + Object *oarg = (Object *)dedargs->data[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); } #endif nargsi = 0; if (targsi) - { // Set initial template arguments - size_t n; + { // Set initial template arguments - nargsi = targsi->dim; - n = parameters->dim; - if (tp) - n--; - if (nargsi > n) - { if (!tp) - goto Lnomatch; + nargsi = targsi->dim; + size_t n = parameters->dim; + if (tp) + n--; + if (nargsi > n) + { if (!tp) + goto Lnomatch; - /* The extra initial template arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - assert(parameters->dim); - dedargs->data[parameters->dim - 1] = (void *)t; + /* The extra initial template arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + assert(parameters->dim); + dedargs->data[parameters->dim - 1] = (void *)t; - tuple_dim = nargsi - n; - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { - t->objects.data[i] = (void *)targsi->data[n + i]; - } - declareParameter(paramscope, tp, t); - } - else - n = nargsi; + tuple_dim = nargsi - n; + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { + t->objects.data[i] = (void *)targsi->data[n + i]; + } + declareParameter(paramscope, tp, t); + tp_is_declared = 1; + } + else + n = nargsi; - memcpy(dedargs->data, targsi->data, n * sizeof(*dedargs->data)); + memcpy(dedargs->data, targsi->data, n * sizeof(*dedargs->data)); - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - MATCH m; - Declaration *sparam = NULL; + for (size_t i = 0; i < n; i++) + { assert(i < parameters->dim); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + MATCH m; + Declaration *sparam = NULL; - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; + m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); + //printf("\tdeduceType m = %d\n", m); + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } + sparam->semantic(paramscope); + if (!paramscope->insert(sparam)) + goto Lnomatch; + } } #if 0 for (i = 0; i < dedargs->dim; i++) { - printf("\tdedarg[%d] = ", i); - Object *oarg = (Object *)dedargs->data[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); + printf("\tdedarg[%d] = ", i); + Object *oarg = (Object *)dedargs->data[i]; + if (oarg) printf("%s", oarg->toChars()); + printf("\n"); } #endif - if (fd->type) - { - assert(fd->type->ty == Tfunction); - TypeFunction *fdtype = (TypeFunction *)fd->type; - fparameters = fdtype->parameters; - fvarargs = fdtype->varargs; - } - else - { CtorDeclaration *fctor = fd->isCtorDeclaration(); - assert(fctor); - fparameters = fctor->arguments; - fvarargs = fctor->varargs; - } - - nfparams = Argument::dim(fparameters); // number of function parameters - nfargs = fargs ? fargs->dim : 0; // number of function arguments + fparameters = fd->getParameters(&fvarargs); + nfparams = Parameter::dim(fparameters); // number of function parameters + nfargs = fargs ? fargs->dim : 0; // number of function arguments /* Check for match of function arguments with variadic template * parameter, such as: @@ -887,281 +980,355 @@ MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Loc loc, Objects *targsi, * template Foo(T, A...) { void Foo(T t, A a); } * void main() { Foo(1,2,3); } */ - if (tp) // if variadic + if (tp) // if variadic { - if (nfparams == 0) // if no function parameters - { - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->data[parameters->dim - 1] = (void *)t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Argument *fparam = (Argument *)fparameters->data[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; + if (nfparams == 0 && nfargs != 0) // if no function parameters + { + if (tp_is_declared) + goto L2; + Tuple *t = new Tuple(); + //printf("t = %p\n", t); + dedargs->data[parameters->dim - 1] = (void *)t; + declareParameter(paramscope, tp, t); + goto L2; + } + else if (nfargs < nfparams - 1) + goto L1; + else + { + /* Figure out which of the function parameters matches + * the tuple template parameter. Do this by matching + * type identifiers. + * Set the index of this function parameter to fptupindex. + */ + for (fptupindex = 0; fptupindex < nfparams; fptupindex++) + { + Parameter *fparam = (Parameter *)fparameters->data[fptupindex]; + if (fparam->type->ty != Tident) + continue; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + continue; - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template + if (fvarargs) // variadic function doesn't + goto Lnomatch; // go with variadic template - /* The types of the function arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->data[parameters->dim - 1] = (void *)t; + if (tp_is_declared) + goto L2; - tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (i = 0; i < tuple_dim; i++) - { Expression *farg = (Expression *)fargs->data[fptupindex + i]; - t->objects.data[i] = (void *)farg->type; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } + /* The types of the function arguments + * now form the tuple argument. + */ + Tuple *t = new Tuple(); + dedargs->data[parameters->dim - 1] = (void *)t; + + tuple_dim = nfargs - (nfparams - 1); + t->objects.setDim(tuple_dim); + for (i = 0; i < tuple_dim; i++) + { Expression *farg = (Expression *)fargs->data[fptupindex + i]; + t->objects.data[i] = (void *)farg->type; + } + declareParameter(paramscope, tp, t); + goto L2; + } + fptupindex = -1; + } } L1: if (nfparams == nfargs) - ; + ; else if (nfargs > nfparams) { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion + if (fvarargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion } L2: #if DMDV2 - // Match 'ethis' to any TemplateThisParameter's if (ethis) { - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - { MATCH m; + // Match 'ethis' to any TemplateThisParameter's + for (size_t i = 0; i < parameters->dim; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateThisParameter *ttp = tp->isTemplateThisParameter(); + if (ttp) + { MATCH m; - Type *t = new TypeIdentifier(0, ttp->ident); - m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); - if (!m) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } + Type *t = new TypeIdentifier(0, ttp->ident); + m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); + if (!m) + goto Lnomatch; + if (m < match) + match = m; // pick worst match + } + } + + // Match attributes of ethis against attributes of fd + if (fd->type) + { + Type *tthis = ethis->type; + unsigned mod = fd->type->mod; + StorageClass stc = scope->stc; + if (stc & (STCshared | STCsynchronized)) + mod |= MODshared; + if (stc & STCimmutable) + mod |= MODimmutable; + if (stc & STCconst) + mod |= MODconst; + if (stc & STCwild) + mod |= MODwild; + // Fix mod + if (mod & MODimmutable) + mod = MODimmutable; + if (mod & MODconst) + mod &= ~STCwild; + if (tthis->mod != mod) + { + if (!MODimplicitConv(tthis->mod, mod)) + goto Lnomatch; + if (MATCHconst < match) + match = MATCHconst; + } + } } #endif // Loop through the function parameters - for (i = 0; i < nfparams; i++) + for (size_t parami = 0; parami < nfparams; parami++) { - /* Skip over function parameters which wound up - * as part of a template tuple parameter. - */ - if (i == fptupindex) - { if (fptupindex == nfparams - 1) - break; - i += tuple_dim - 1; - continue; - } + /* Skip over function parameters which wound up + * as part of a template tuple parameter. + */ + if (parami == fptupindex) + continue; + /* Set i = index into function arguments + * Function parameters correspond to function arguments as follows. + * Note that tuple_dim may be zero, and there may be default or + * variadic arguments at the end. + * arg [0..fptupindex] == param[0..fptupindex] + * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] + * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] + */ + i = parami; + if (fptupindex >= 0 && parami > fptupindex) + i += tuple_dim - 1; - Argument *fparam = Argument::getNth(fparameters, i); + Parameter *fparam = Parameter::getNth(fparameters, parami); - if (i >= nfargs) // if not enough arguments - { - if (fparam->defaultArg) - { /* Default arguments do not participate in template argument - * deduction. - */ - goto Lmatch; - } - } - else - { Expression *farg = (Expression *)fargs->data[i]; + if (i >= nfargs) // if not enough arguments + { + if (fparam->defaultArg) + { /* Default arguments do not participate in template argument + * deduction. + */ + goto Lmatch; + } + } + else + { Expression *farg = (Expression *)fargs->data[i]; #if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); + printf("\tfarg->type = %s\n", farg->type->toChars()); + printf("\tfparam->type = %s\n", fparam->type->toChars()); #endif - Type *argtype = farg->type; + Type *argtype = farg->type; #if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } + /* Allow string literals which are type [] to match with [dim] + */ + if (farg->op == TOKstring) + { StringExp *se = (StringExp *)farg; + if (!se->committed && argtype->ty == Tarray && + fparam->type->toBasetype()->ty == Tsarray) + { + argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); + argtype = argtype->semantic(se->loc, NULL); + argtype = argtype->invariantOf(); + } + } #endif - MATCH m; - m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes); - //printf("\tdeduceType m = %d\n", m); + MATCH m; + m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes); + //printf("\tdeduceType m = %d\n", m); - /* If no match, see if there's a conversion to a delegate - */ - if (!m && fparam->type->toBasetype()->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; + /* If no match, see if there's a conversion to a delegate + */ + if (!m && fparam->type->toBasetype()->ty == Tdelegate) + { + TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); + TypeFunction *tf = (TypeFunction *)td->next; - if (!tf->varargs && Argument::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } + if (!tf->varargs && Parameter::dim(tf->parameters) == 0) + { + m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); + if (!m && tf->next->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + //printf("\tm2 = %d\n", m); + } - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } + if (m) + { if (m < match) + match = m; // pick worst match + continue; + } + } - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; + /* The following code for variadic arguments closely + * matches TypeFunction::callMatch() + */ + if (!(fvarargs == 2 && i + 1 == nfparams)) + goto Lnomatch; - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = (Expression *)fargs->data[i]; - assert(arg); - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; + /* Check for match with function parameter T... + */ + Type *tb = fparam->type->toBasetype(); + switch (tb->ty) + { + // Perhaps we can do better with this, see TypeFunction::callMatch() + case Tsarray: + { TypeSArray *tsa = (TypeSArray *)tb; + dinteger_t sz = tsa->dim->toInteger(); + if (sz != nfargs - i) + goto Lnomatch; + } + case Tarray: + { TypeArray *ta = (TypeArray *)tb; + for (; i < nfargs; i++) + { + Expression *arg = (Expression *)fargs->data[i]; + assert(arg); + MATCH m; + /* If lazy array of delegates, + * convert arg(s) to delegate(s) + */ + Type *tret = fparam->isLazyArray(); + if (tret) + { + if (ta->next->equals(arg->type)) + { m = MATCHexact; + } + else + { + m = arg->implicitConvTo(tret); + if (m == MATCHnomatch) + { + if (tret->toBasetype()->ty == Tvoid) + m = MATCHconvert; + } + } + } + else + { + m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); + //m = arg->implicitConvTo(ta->next); + } + if (m == MATCHnomatch) + goto Lnomatch; + if (m < match) + match = m; + } + goto Lmatch; + } + case Tclass: + case Tident: + goto Lmatch; - default: - goto Lnomatch; - } + default: + goto Lnomatch; + } } Lmatch: - /* Fill in any missing arguments with their defaults. - */ for (i = nargsi; i < dedargs->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - //printf("tp[%d] = %s\n", i, tp->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = (Object *)dedargs->data[i]; - Object *oded = (Object *)dedtypes.data[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tp->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->data[i] = (void *)oded; - MATCH m2 = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0); - //printf("m2 = %d\n", m2); - if (!m2) - goto Lnomatch; - if (m2 < match) - match = m2; // pick worst match - if (dedtypes.data[i] != oded) - error("specialization not allowed for deduced parameter %s", tp->ident->toChars()); - } - } - else - { oded = tp->defaultArg(loc, paramscope); - if (!oded) - goto Lnomatch; - } - declareParameter(paramscope, tp, oded); - dedargs->data[i] = (void *)oded; - } + TemplateParameter *tparam = (TemplateParameter *)parameters->data[i]; + //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); + /* For T:T*, the dedargs is the T*, dedtypes is the T + * But for function templates, we really need them to match + */ + Object *oarg = (Object *)dedargs->data[i]; + Object *oded = (Object *)dedtypes.data[i]; + //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); + //if (oarg) printf("oarg: %s\n", oarg->toChars()); + //if (oded) printf("oded: %s\n", oded->toChars()); + if (!oarg) + { + if (oded) + { + if (tparam->specialization()) + { /* The specialization can work as long as afterwards + * the oded == oarg + */ + Declaration *sparam; + dedargs->data[i] = (void *)oded; + MATCH m2 = tparam->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam, 0); + //printf("m2 = %d\n", m2); + if (!m2) + goto Lnomatch; + if (m2 < match) + match = m2; // pick worst match + if (dedtypes.data[i] != oded) + error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); + } + } + else + { oded = tparam->defaultArg(loc, paramscope); + if (!oded) + { + if (tp && // if tuple parameter and + fptupindex < 0 && // tuple parameter was not in function parameter list and + nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) + { // make tuple argument an empty tuple + oded = (Object *)new Tuple(); + } + else + goto Lnomatch; + } + } + declareParameter(paramscope, tparam, oded); + dedargs->data[i] = (void *)oded; + } } #if DMDV2 if (constraint) - { /* Check to see if constraint is satisfied. - */ - Expression *e = constraint->syntaxCopy(); - paramscope->flags |= SCOPEstaticif; - e = e->semantic(paramscope); - e = e->optimize(WANTvalue | WANTinterpret); + { /* Check to see if constraint is satisfied. + */ + makeParamNamesVisibleInConstraint(paramscope); + Expression *e = constraint->syntaxCopy(); + paramscope->flags |= SCOPEstaticif; + + /* Detect recursive attempts to instantiate this template declaration, + * void foo(T)(T x) if (is(typeof(foo(x)))) { } + * static assert(!is(typeof(bug4072(7)))); + * Recursive attempts are regarded as a constraint failure. + */ + for (Previous *p = previous; p; p = p->prev) + { + if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) + goto Lnomatch; + /* BUG: should also check for ref param differences + */ + } + Previous pr; + pr.prev = previous; + pr.dedargs = dedargs; + previous = ≺ // add this to threaded list + + int nerrors = global.errors; + + e = e->semantic(paramscope); + + previous = pr.prev; // unlink from threaded list + + if (nerrors != global.errors) // if any errors from evaluating the constraint, no match + goto Lnomatch; + + e = e->optimize(WANTvalue | WANTinterpret); if (e->isBool(TRUE)) ; else if (e->isBool(FALSE)) @@ -1175,8 +1342,8 @@ Lmatch: #if 0 for (i = 0; i < dedargs->dim; i++) - { Type *t = (Type *)dedargs->data[i]; - printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); + { Type *t = (Type *)dedargs->data[i]; + printf("\tdedargs[%d] = %d, %s\n", i, t->dyncast(), t->toChars()); } #endif @@ -1210,53 +1377,53 @@ void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Obj s = sc->search(loc, tp->ident, &scopesym); if (s && scopesym == sc->scopesym) { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return; - } - } + TupleDeclaration *td = s->isTupleDeclaration(); + if (va && td) + { Tuple tup; + tup.objects = *td->objects; + if (match(va, &tup, this, sc)) + { + return; + } + } } if (targ) { - //printf("type %s\n", targ->toChars()); - s = new AliasDeclaration(0, tp->ident, targ); + //printf("type %s\n", targ->toChars()); + s = new AliasDeclaration(0, tp->ident, targ); } else if (sa) { - //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); - s = new AliasDeclaration(0, tp->ident, sa); + //printf("Alias %s %s;\n", sa->ident->toChars(), tp->ident->toChars()); + s = new AliasDeclaration(0, tp->ident, sa); } else if (ea) { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + // tdtypes.data[i] always matches ea here + Initializer *init = new ExpInitializer(loc, ea); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - Type *t = tvp ? tvp->valType : NULL; + Type *t = tvp ? tvp->valType : NULL; - VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); - v->storage_class = STCmanifest; - s = v; + VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); + v->storage_class = STCmanifest; + s = v; } else if (va) { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp->ident, &va->objects); } else { #ifdef DEBUG - o->print(); + o->print(); #endif - assert(0); + assert(0); } if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); + error("declaration %s is already defined", tp->ident->toChars()); s->semantic(sc); } @@ -1269,7 +1436,7 @@ TemplateTupleParameter *isVariadic(TemplateParameters *parameters) TemplateTupleParameter *tp = NULL; if (dim) - tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); + tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); return tp; } @@ -1292,16 +1459,16 @@ int TemplateDeclaration::isOverloadable() * to expand, and return that function. * If no match, give error message and return NULL. * Input: - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !NULL, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return NULL */ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expression *ethis, Expressions *fargs, int flags) + Objects *targsi, Expression *ethis, Expressions *fargs, int flags) { MATCH m_best = MATCHnomatch; TemplateDeclaration *td_ambig = NULL; @@ -1314,86 +1481,89 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); printf(" targsi:\n"); if (targsi) - { for (int i = 0; i < targsi->dim; i++) - { Object *arg = (Object *)targsi->data[i]; - printf("\t%s\n", arg->toChars()); - } + { for (int i = 0; i < targsi->dim; i++) + { Object *arg = (Object *)targsi->data[i]; + printf("\t%s\n", arg->toChars()); + } } printf(" fargs:\n"); for (int i = 0; i < fargs->dim; i++) - { Expression *arg = (Expression *)fargs->data[i]; - printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); - //printf("\tty = %d\n", arg->type->ty); + { Expression *arg = (Expression *)fargs->data[i]; + printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); + //printf("\tty = %d\n", arg->type->ty); } + printf("stc = %llx\n", scope->stc); #endif for (TemplateDeclaration *td = this; td; td = td->overnext) { - if (!td->semanticRun) - { - error("forward reference to template %s", td->toChars()); - goto Lerror; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - goto Lerror; - } + if (!td->semanticRun) + { + error("forward reference to template %s", td->toChars()); + goto Lerror; + } + if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) + { + error("is not a function template"); + goto Lerror; + } - MATCH m; - Objects dedargs; + MATCH m; + Objects dedargs; - m = td->deduceFunctionTemplateMatch(loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); - if (!m) // if no match - continue; + m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); + //printf("deduceFunctionTemplateMatch = %d\n", m); + if (!m) // if no match + continue; - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best); + MATCH c2 = td_best->leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; - Ltd: // td is the new best match - td_ambig = NULL; - assert((size_t)td->scope > 0x10000); - td_best = td; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); - continue; + Ltd: // td is the new best match + td_ambig = NULL; + assert((size_t)td->scope > 0x10000); + td_best = td; + m_best = m; + tdargs->setDim(dedargs.dim); + memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); + continue; } if (!td_best) { - if (!(flags & 1)) - error(loc, "does not match any function template declaration"); - goto Lerror; + if (!(flags & 1)) + error(loc, "does not match any function template declaration"); + goto Lerror; } if (td_ambig) { - error(loc, "matches more than one function template declaration:\n %s\nand:\n %s", - td_best->toChars(), td_ambig->toChars()); + error(loc, "%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); } /* The best match is td_best with arguments tdargs. @@ -1401,10 +1571,10 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, */ assert((size_t)td_best->scope > 0x10000); ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc); + ti->semantic(sc, fargs); fd = ti->toAlias()->isFuncDeclaration(); if (!fd) - goto Lerror; + goto Lerror; return fd; Lerror: @@ -1412,24 +1582,24 @@ FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, if (!(flags & 1)) #endif { - HdrGenState hgs; + HdrGenState hgs; - OutBuffer bufa; - Objects *args = targsi; - if (args) - { for (int i = 0; i < args->dim; i++) - { - if (i) - bufa.writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } + OutBuffer bufa; + Objects *args = targsi; + if (args) + { for (int i = 0; i < args->dim; i++) + { + if (i) + bufa.writeByte(','); + Object *oarg = (Object *)args->data[i]; + ObjectToCBuffer(&bufa, &hgs, oarg); + } + } - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - error(loc, "cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); + OutBuffer buf; + argExpTypesToCBuffer(&buf, fargs, &hgs); + error(loc, "cannot deduce template function from argument types !(%s)(%s)", + bufa.toChars(), buf.toChars()); } return NULL; } @@ -1438,7 +1608,7 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { #if 0 // Should handle template functions if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); + buf->writestring("foo "); #endif buf->writestring(kind()); buf->writeByte(' '); @@ -1446,36 +1616,36 @@ void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writeByte('('); for (int i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (hgs->ddoc) - tp = (TemplateParameter *)origParameters->data[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + if (hgs->ddoc) + tp = (TemplateParameter *)origParameters->data[i]; + if (i) + buf->writeByte(','); + tp->toCBuffer(buf, hgs); } buf->writeByte(')'); #if DMDV2 if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); + { buf->writestring(" if ("); + constraint->toCBuffer(buf, hgs); + buf->writeByte(')'); } #endif if (hgs->hdrgen) { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->toCBuffer(buf, hgs); - } - buf->writebyte('}'); - buf->writenl(); - hgs->tpltMember--; + hgs->tpltMember++; + buf->writenl(); + buf->writebyte('{'); + buf->writenl(); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->toCBuffer(buf, hgs); + } + buf->writebyte('}'); + buf->writenl(); + hgs->tpltMember--; } } @@ -1489,17 +1659,17 @@ char *TemplateDeclaration::toChars() buf.writeByte('('); for (int i = 0; i < parameters->dim; i++) { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + if (i) + buf.writeByte(','); + tp->toCBuffer(&buf, &hgs); } buf.writeByte(')'); #if DMDV2 if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); + { buf.writestring(" if ("); + constraint->toCBuffer(&buf, &hgs); + buf.writeByte(')'); } #endif buf.writeByte(0); @@ -1518,8 +1688,8 @@ int templateIdentifierLookup(Identifier *id, TemplateParameters *parameters) for (size_t i = 0; i < parameters->dim; i++) { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (tp->ident->equals(id)) - return i; + if (tp->ident->equals(id)) + return i; } return -1; } @@ -1531,7 +1701,7 @@ int templateParameterLookup(Type *tparam, TemplateParameters *parameters) //printf("\ttident = '%s'\n", tident->toChars()); if (tident->idents.dim == 0) { - return templateIdentifierLookup(tident->ident, parameters); + return templateIdentifierLookup(tident->ident, parameters); } return -1; } @@ -1541,18 +1711,18 @@ int templateParameterLookup(Type *tparam, TemplateParameters *parameters) * it is matched against the template declaration parameter specialization * 'tparam' to determine the type to be used for the parameter. * Example: - * template Foo(T:T*) // template declaration - * Foo!(int*) // template instantiation + * template Foo(T:T*) // template declaration + * Foo!(int*) // template instantiation * Input: - * this = int* - * tparam = T - * parameters = [ T:T* ] // Array of TemplateParameter's + * this = int* + * tparam = T + * parameters = [ T:T* ] // Array of TemplateParameter's * Output: - * dedtypes = [ int ] // Array of Expression/Type's + * dedtypes = [ int ] // Array of Expression/Type's */ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) + Objects *dedtypes) { #if 0 printf("Type::deduceType()\n"); @@ -1560,101 +1730,211 @@ MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, printf("\ttparam = %d, ", tparam->ty); tparam->print(); #endif if (!tparam) - goto Lnomatch; + goto Lnomatch; if (this == tparam) - goto Lexact; + goto Lexact; if (tparam->ty == Tident) { - // Determine which parameter tparam is - int i = templateParameterLookup(tparam, parameters); - if (i == -1) - { - if (!sc) - goto Lnomatch; + // Determine which parameter tparam is + int i = templateParameterLookup(tparam, parameters); + if (i == -1) + { + if (!sc) + goto Lnomatch; - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[0]; - loc = tp->loc; - } + /* Need a loc to go with the semantic routine. + */ + Loc loc; + if (parameters->dim) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[0]; + loc = tp->loc; + } - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = tparam->semantic(loc, sc); - assert(tparam->ty != Tident); - return deduceType(sc, tparam, parameters, dedtypes); - } + /* BUG: what if tparam is a template instance, that + * has as an argument another Tident? + */ + tparam = tparam->semantic(loc, sc); + assert(tparam->ty != Tident); + return deduceType(sc, tparam, parameters, dedtypes); + } - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *tt = this; - Type *at = (Type *)dedtypes->data[i]; + // Found the corresponding parameter tp + if (!tp->isTemplateTypeParameter()) + goto Lnomatch; + Type *tt = this; + Type *at = (Type *)dedtypes->data[i]; - // 3*3 == 9 cases - if (tparam->isMutable()) - { // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) invariant(T) => invariant(T) - if (!at) - { dedtypes->data[i] = (void *)this; - goto Lexact; - } - } - else if (mod == tparam->mod) - { // foo(U:const(U)) const(T) => T - // foo(U:invariant(U)) invariant(T) => T - tt = mutableOf(); - if (!at) - { dedtypes->data[i] = (void *)tt; - goto Lexact; - } - } - else if (tparam->isConst()) - { // foo(U:const(U)) T => T - // foo(U:const(U)) invariant(T) => T - tt = mutableOf(); - if (!at) - { dedtypes->data[i] = (void *)tt; - goto Lconst; - } - } - else - { // foo(U:invariant(U)) T => nomatch - // foo(U:invariant(U)) const(T) => nomatch - if (!at) - goto Lnomatch; - } + // 7*7 == 49 cases - if (tt->equals(at)) - goto Lexact; - else if (tt->ty == Tclass && at->ty == Tclass) - { - return tt->implicitConvTo(at); - } - else if (tt->ty == Tsarray && at->ty == Tarray && - tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) - { - goto Lexact; - } - else - goto Lnomatch; + #define X(U,T) ((U) << 4) | (T) + switch (X(tparam->mod, mod)) + { + case X(0, 0): + case X(0, MODconst): + case X(0, MODimmutable): + case X(0, MODshared): + case X(0, MODconst | MODshared): + case X(0, MODwild): + case X(0, MODwild | MODshared): + // foo(U:U) T => T + // foo(U:U) const(T) => const(T) + // foo(U:U) immutable(T) => immutable(T) + // foo(U:U) shared(T) => shared(T) + // foo(U:U) const(shared(T)) => const(shared(T)) + // foo(U:U) wild(T) => wild(T) + // foo(U:U) wild(shared(T)) => wild(shared(T)) + if (!at) + { dedtypes->data[i] = (void *)tt; + goto Lexact; + } + break; + + case X(MODconst, MODconst): + case X(MODimmutable, MODimmutable): + case X(MODshared, MODshared): + case X(MODconst | MODshared, MODconst | MODshared): + case X(MODwild, MODwild): + case X(MODwild | MODshared, MODwild | MODshared): + // foo(U:const(U)) const(T) => T + // foo(U:immutable(U)) immutable(T) => T + // foo(U:shared(U)) shared(T) => T + // foo(U:const(shared(U)) const(shared(T)) => T + // foo(U:wild(U)) wild(T) => T + // foo(U:wild(shared(U)) wild(shared(T)) => T + tt = mutableOf()->unSharedOf(); + if (!at) + { dedtypes->data[i] = (void *)tt; + goto Lexact; + } + break; + + case X(MODconst, 0): + case X(MODconst, MODimmutable): + case X(MODconst, MODconst | MODshared): + case X(MODconst | MODshared, MODimmutable): + case X(MODconst, MODwild): + case X(MODconst, MODwild | MODshared): + // foo(U:const(U)) T => T + // foo(U:const(U)) immutable(T) => T + // foo(U:const(U)) const(shared(T)) => shared(T) + // foo(U:const(shared(U)) immutable(T) => T + // foo(U:const(U)) wild(shared(T)) => shared(T) + tt = mutableOf(); + if (!at) + { dedtypes->data[i] = (void *)tt; + goto Lconst; + } + break; + + case X(MODshared, MODconst | MODshared): + case X(MODconst | MODshared, MODshared): + case X(MODshared, MODwild | MODshared): + // foo(U:shared(U)) const(shared(T)) => const(T) + // foo(U:const(shared(U)) shared(T) => T + // foo(U:shared(U)) wild(shared(T)) => wild(T) + tt = unSharedOf(); + if (!at) + { dedtypes->data[i] = (void *)tt; + goto Lconst; + } + break; + + case X(MODimmutable, 0): + case X(MODimmutable, MODconst): + case X(MODimmutable, MODshared): + case X(MODimmutable, MODconst | MODshared): + case X(MODconst, MODshared): + case X(MODshared, 0): + case X(MODshared, MODconst): + case X(MODshared, MODimmutable): + case X(MODconst | MODshared, 0): + case X(MODconst | MODshared, MODconst): + case X(MODimmutable, MODwild): + case X(MODshared, MODwild): + case X(MODconst | MODshared, MODwild): + case X(MODwild, 0): + case X(MODwild, MODconst): + case X(MODwild, MODimmutable): + case X(MODwild, MODshared): + case X(MODwild, MODconst | MODshared): + case X(MODwild | MODshared, 0): + case X(MODwild | MODshared, MODconst): + case X(MODwild | MODshared, MODimmutable): + case X(MODwild | MODshared, MODshared): + case X(MODwild | MODshared, MODconst | MODshared): + case X(MODwild | MODshared, MODwild): + case X(MODimmutable, MODwild | MODshared): + case X(MODconst | MODshared, MODwild | MODshared): + case X(MODwild, MODwild | MODshared): + + // foo(U:immutable(U)) T => nomatch + // foo(U:immutable(U)) const(T) => nomatch + // foo(U:immutable(U)) shared(T) => nomatch + // foo(U:immutable(U)) const(shared(T)) => nomatch + // foo(U:const(U)) shared(T) => nomatch + // foo(U:shared(U)) T => nomatch + // foo(U:shared(U)) const(T) => nomatch + // foo(U:shared(U)) immutable(T) => nomatch + // foo(U:const(shared(U)) T => nomatch + // foo(U:const(shared(U)) const(T) => nomatch + // foo(U:immutable(U)) wild(T) => nomatch + // foo(U:shared(U)) wild(T) => nomatch + // foo(U:const(shared(U)) wild(T) => nomatch + // foo(U:wild(U)) T => nomatch + // foo(U:wild(U)) const(T) => nomatch + // foo(U:wild(U)) immutable(T) => nomatch + // foo(U:wild(U)) shared(T) => nomatch + // foo(U:wild(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) T => nomatch + // foo(U:wild(shared(U)) const(T) => nomatch + // foo(U:wild(shared(U)) immutable(T) => nomatch + // foo(U:wild(shared(U)) shared(T) => nomatch + // foo(U:wild(shared(U)) const(shared(T)) => nomatch + // foo(U:wild(shared(U)) wild(T) => nomatch + // foo(U:immutable(U)) wild(shared(T)) => nomatch + // foo(U:const(shared(U))) wild(shared(T)) => nomatch + // foo(U:wild(U)) wild(shared(T)) => nomatch + //if (!at) + goto Lnomatch; + break; + + default: + assert(0); + } + #undef X + + if (tt->equals(at)) + goto Lexact; + else if (tt->ty == Tclass && at->ty == Tclass) + { + return tt->implicitConvTo(at); + } + else if (tt->ty == Tsarray && at->ty == Tarray && + tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) + { + goto Lexact; + } + else + goto Lnomatch; } if (ty != tparam->ty) - return implicitConvTo(tparam); -// goto Lnomatch; + { +#if DMDV2 + // Can't instantiate AssociativeArray!() without a scope + if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) + ((TypeAArray*)tparam)->sc = sc; +#endif + return implicitConvTo(tparam); + } if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); + return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); Lexact: return MATCHexact; @@ -1670,7 +1950,7 @@ Lconst: #if DMDV2 MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) + Objects *dedtypes) { #if 0 printf("TypeDArray::deduceType()\n"); @@ -1685,7 +1965,7 @@ MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame #endif MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) + Objects *dedtypes) { #if 0 printf("TypeSArray::deduceType()\n"); @@ -1696,78 +1976,78 @@ MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame // Extra check that array dimensions must match if (tparam) { - if (tparam->ty == Tsarray) - { - TypeSArray *tp = (TypeSArray *)tparam; + if (tparam->ty == Tsarray) + { + TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && - ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters); - // This code matches code in TypeInstance::deduceType() - if (i == -1) - goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->data[i]; - if (e) - { - if (!dim->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tvp->valType->semantic(0, sc); - MATCH m = (MATCH)dim->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->data[i] = dim; - } - } - else if (dim->toInteger() != tp->dim->toInteger()) - return MATCHnomatch; - } - else if (tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident) - { TypeIdentifier *tident = (TypeIdentifier *)tp->index; + if (tp->dim->op == TOKvar && + ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) + { int i = templateIdentifierLookup(((VarExp *)tp->dim)->var->ident, parameters); + // This code matches code in TypeInstance::deduceType() + if (i == -1) + goto Lnomatch; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + if (!tvp) + goto Lnomatch; + Expression *e = (Expression *)dedtypes->data[i]; + if (e) + { + if (!dim->equals(e)) + goto Lnomatch; + } + else + { Type *vt = tvp->valType->semantic(0, sc); + MATCH m = (MATCH)dim->implicitConvTo(vt); + if (!m) + goto Lnomatch; + dedtypes->data[i] = dim; + } + } + else if (dim->toInteger() != tp->dim->toInteger()) + return MATCHnomatch; + } + else if (tparam->ty == Taarray) + { + TypeAArray *tp = (TypeAArray *)tparam; + if (tp->index->ty == Tident) + { TypeIdentifier *tident = (TypeIdentifier *)tp->index; - if (tident->idents.dim == 0) - { Identifier *id = tident->ident; + if (tident->idents.dim == 0) + { Identifier *id = tident->ident; - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + for (size_t i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - if (tp->ident->equals(id)) - { // Found the corresponding template parameter - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (!tvp || !tvp->valType->isintegral()) - goto Lnomatch; + if (tp->ident->equals(id)) + { // Found the corresponding template parameter + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + if (!tvp || !tvp->valType->isintegral()) + goto Lnomatch; - if (dedtypes->data[i]) - { - if (!dim->equals((Object *)dedtypes->data[i])) - goto Lnomatch; - } - else - { dedtypes->data[i] = (void *)dim; - } - return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - } - } - } - } - } - else if (tparam->ty == Tarray) - { MATCH m; + if (dedtypes->data[i]) + { + if (!dim->equals((Object *)dedtypes->data[i])) + goto Lnomatch; + } + else + { dedtypes->data[i] = (void *)dim; + } + return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); + } + } + } + } + } + else if (tparam->ty == Tarray) + { MATCH m; - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } + m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes); + if (m == MATCHexact) + m = MATCHconvert; + return m; + } } return Type::deduceType(sc, tparam, parameters, dedtypes); @@ -1786,11 +2066,11 @@ MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame // Extra check that index type must match if (tparam && tparam->ty == Taarray) { - TypeAArray *tp = (TypeAArray *)tparam; - if (!index->deduceType(sc, tp->index, parameters, dedtypes)) - { - return MATCHnomatch; - } + TypeAArray *tp = (TypeAArray *)tparam; + if (!index->deduceType(sc, tp->index, parameters, dedtypes)) + { + return MATCHnomatch; + } } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -1804,87 +2084,87 @@ MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *para // Extra check that function characteristics must match if (tparam && tparam->ty == Tfunction) { - TypeFunction *tp = (TypeFunction *)tparam; - if (varargs != tp->varargs || - linkage != tp->linkage) - return MATCHnomatch; + TypeFunction *tp = (TypeFunction *)tparam; + if (varargs != tp->varargs || + linkage != tp->linkage) + return MATCHnomatch; - size_t nfargs = Argument::dim(this->parameters); - size_t nfparams = Argument::dim(tp->parameters); + size_t nfargs = Parameter::dim(this->parameters); + size_t nfparams = Parameter::dim(tp->parameters); - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Argument *fparam = Argument::getNth(tp->parameters, nfparams - 1); - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.dim) - goto L1; + /* See if tuple match + */ + if (nfparams > 0 && nfargs >= nfparams - 1) + { + /* See if 'A' of the template parameter matches 'A' + * of the type of the last function parameter. + */ + Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); + assert(fparam); + assert(fparam->type); + if (fparam->type->ty != Tident) + goto L1; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (tid->idents.dim) + goto L1; - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { if (tupi == parameters->dim) - goto L1; - TemplateParameter *t = (TemplateParameter *)parameters->data[tupi]; - TemplateTupleParameter *tup = t->isTemplateTupleParameter(); - if (tup && tup->ident->equals(tid->ident)) - break; - } + /* Look through parameters to find tuple matching tid->ident + */ + size_t tupi = 0; + for (; 1; tupi++) + { if (tupi == parameters->dim) + goto L1; + TemplateParameter *t = (TemplateParameter *)parameters->data[tupi]; + TemplateTupleParameter *tup = t->isTemplateTupleParameter(); + if (tup && tup->ident->equals(tid->ident)) + break; + } - /* The types of the function arguments [nfparams - 1 .. nfargs] - * now form the tuple argument. - */ - int tuple_dim = nfargs - (nfparams - 1); + /* The types of the function arguments [nfparams - 1 .. nfargs] + * now form the tuple argument. + */ + int tuple_dim = nfargs - (nfparams - 1); - /* See if existing tuple, and whether it matches or not - */ - Object *o = (Object *)dedtypes->data[tupi]; - if (o) - { // Existing deduced argument must be a tuple, and must match - Tuple *t = isTuple(o); - if (!t || t->objects.dim != tuple_dim) - return MATCHnomatch; - for (size_t i = 0; i < tuple_dim; i++) - { Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals((Object *)t->objects.data[i])) - return MATCHnomatch; - } - } - else - { // Create new tuple - Tuple *t = new Tuple(); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Argument *arg = Argument::getNth(this->parameters, nfparams - 1 + i); - t->objects.data[i] = (void *)arg->type; - } - dedtypes->data[tupi] = (void *)t; - } - nfparams--; // don't consider the last parameter for type deduction - goto L2; - } + /* See if existing tuple, and whether it matches or not + */ + Object *o = (Object *)dedtypes->data[tupi]; + if (o) + { // Existing deduced argument must be a tuple, and must match + Tuple *t = isTuple(o); + if (!t || t->objects.dim != tuple_dim) + return MATCHnomatch; + for (size_t i = 0; i < tuple_dim; i++) + { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); + if (!arg->type->equals((Object *)t->objects.data[i])) + return MATCHnomatch; + } + } + else + { // Create new tuple + Tuple *t = new Tuple(); + t->objects.setDim(tuple_dim); + for (size_t i = 0; i < tuple_dim; i++) + { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); + t->objects.data[i] = (void *)arg->type; + } + dedtypes->data[tupi] = (void *)t; + } + nfparams--; // don't consider the last parameter for type deduction + goto L2; + } L1: - if (nfargs != nfparams) - return MATCHnomatch; + if (nfargs != nfparams) + return MATCHnomatch; L2: - for (size_t i = 0; i < nfparams; i++) - { - Argument *a = Argument::getNth(this->parameters, i); - Argument *ap = Argument::getNth(tp->parameters, i); - if (a->storageClass != ap->storageClass || - !a->type->deduceType(sc, ap->type, parameters, dedtypes)) - return MATCHnomatch; - } + for (size_t i = 0; i < nfparams; i++) + { + Parameter *a = Parameter::getNth(this->parameters, i); + Parameter *ap = Parameter::getNth(tp->parameters, i); + if (a->storageClass != ap->storageClass || + !a->type->deduceType(sc, ap->type, parameters, dedtypes)) + return MATCHnomatch; + } } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -1894,23 +2174,23 @@ MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *pa // Extra check if (tparam && tparam->ty == Tident) { - TypeIdentifier *tp = (TypeIdentifier *)tparam; + TypeIdentifier *tp = (TypeIdentifier *)tparam; - for (int i = 0; i < idents.dim; i++) - { - Identifier *id1 = (Identifier *)idents.data[i]; - Identifier *id2 = (Identifier *)tp->idents.data[i]; + for (int i = 0; i < idents.dim; i++) + { + Identifier *id1 = (Identifier *)idents.data[i]; + Identifier *id2 = (Identifier *)tp->idents.data[i]; - if (!id1->equals(id2)) - return MATCHnomatch; - } + if (!id1->equals(id2)) + return MATCHnomatch; + } } return Type::deduceType(sc, tparam, parameters, dedtypes); } MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) + Type *tparam, TemplateParameters *parameters, + Objects *dedtypes) { #if 0 printf("TypeInstance::deduceType()\n"); @@ -1921,208 +2201,208 @@ MATCH TypeInstance::deduceType(Scope *sc, // Extra check if (tparam && tparam->ty == Tinstance) { - TypeInstance *tp = (TypeInstance *)tparam; + TypeInstance *tp = (TypeInstance *)tparam; - //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); - //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); - if (!tp->tempinst->tempdecl) - { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); - if (!tp->tempinst->name->equals(tempinst->name)) - { - /* Handle case of: - * template Foo(T : sa!(T), alias sa) - */ - int i = templateIdentifierLookup(tp->tempinst->name, parameters); - if (i == -1) - { /* Didn't find it as a parameter identifier. Try looking - * it up and seeing if is an alias. See Bugzilla 1454 - */ - Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); - if (s) - { - s = s->toAlias(); - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td && td == tempinst->tempdecl) - goto L2; - } - goto Lnomatch; - } - TemplateParameter *tpx = (TemplateParameter *)parameters->data[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if (dedtypes->data[i]) - { // Must match already deduced symbol - Object *s = (Object *)dedtypes->data[i]; + //printf("tempinst->tempdecl = %p\n", tempinst->tempdecl); + //printf("tp->tempinst->tempdecl = %p\n", tp->tempinst->tempdecl); + if (!tp->tempinst->tempdecl) + { //printf("tp->tempinst->name = '%s'\n", tp->tempinst->name->toChars()); + if (!tp->tempinst->name->equals(tempinst->name)) + { + /* Handle case of: + * template Foo(T : sa!(T), alias sa) + */ + int i = templateIdentifierLookup(tp->tempinst->name, parameters); + if (i == -1) + { /* Didn't find it as a parameter identifier. Try looking + * it up and seeing if is an alias. See Bugzilla 1454 + */ + Dsymbol *s = tempinst->tempdecl->scope->search(0, tp->tempinst->name, NULL); + if (s) + { + s = s->toAlias(); + TemplateDeclaration *td = s->isTemplateDeclaration(); + if (td && td == tempinst->tempdecl) + goto L2; + } + goto Lnomatch; + } + TemplateParameter *tpx = (TemplateParameter *)parameters->data[i]; + // This logic duplicates tpx->matchArg() + TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Object *sa = tempinst->tempdecl; + if (!sa) + goto Lnomatch; + if (ta->specAlias && sa != ta->specAlias) + goto Lnomatch; + if (dedtypes->data[i]) + { // Must match already deduced symbol + Object *s = (Object *)dedtypes->data[i]; - if (s != sa) - goto Lnomatch; - } - dedtypes->data[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; + if (s != sa) + goto Lnomatch; + } + dedtypes->data[i] = sa; + } + } + else if (tempinst->tempdecl != tp->tempinst->tempdecl) + goto Lnomatch; L2: - for (int i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; - if (i < tempinst->tiargs->dim) - o1 = (Object *)tempinst->tiargs->data[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = (Object *)tempinst->tdtypes.data[i]; - else - break; + for (int i = 0; 1; i++) + { + //printf("\ttest: tempinst->tiargs[%d]\n", i); + Object *o1; + if (i < tempinst->tiargs->dim) + o1 = (Object *)tempinst->tiargs->data[i]; + else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) + // Pick up default arg + o1 = (Object *)tempinst->tdtypes.data[i]; + else + break; - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; + if (i >= tp->tempinst->tiargs->dim) + goto Lnomatch; - Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; + Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; - Type *t1 = isType(o1); - Type *t2 = isType(o2); + Type *t1 = isType(o1); + Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); + Tuple *v1 = isTuple(o1); + Tuple *v2 = isTuple(o2); #if 0 - if (t1) printf("t1 = %s\n", t1->toChars()); - if (t2) printf("t2 = %s\n", t2->toChars()); - if (e1) printf("e1 = %s\n", e1->toChars()); - if (e2) printf("e2 = %s\n", e2->toChars()); - if (s1) printf("s1 = %s\n", s1->toChars()); - if (s2) printf("s2 = %s\n", s2->toChars()); - if (v1) printf("v1 = %s\n", v1->toChars()); - if (v2) printf("v2 = %s\n", v2->toChars()); + if (t1) printf("t1 = %s\n", t1->toChars()); + if (t2) printf("t2 = %s\n", t2->toChars()); + if (e1) printf("e1 = %s\n", e1->toChars()); + if (e2) printf("e2 = %s\n", e2->toChars()); + if (s1) printf("s1 = %s\n", s1->toChars()); + if (s2) printf("s2 = %s\n", s2->toChars()); + if (v1) printf("v1 = %s\n", v1->toChars()); + if (v2) printf("v2 = %s\n", v2->toChars()); #endif - TemplateTupleParameter *ttp; - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - i == tempinst->tempdecl->parameters->dim - 1 && - (ttp = tempinst->tempdecl->isVariadic()) != NULL) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (!is(X Y == A!(Z), Z)) - * deduce that Z is a tuple(int, float) - */ + TemplateTupleParameter *ttp; + int j; + if (t2 && + t2->ty == Tident && + i == tp->tempinst->tiargs->dim - 1 && + i == tempinst->tempdecl->parameters->dim - 1 && + (ttp = tempinst->tempdecl->isVariadic()) != NULL) + { + /* Given: + * struct A(B...) {} + * alias A!(int, float) X; + * static if (!is(X Y == A!(Z), Z)) + * deduce that Z is a tuple(int, float) + */ - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; + j = templateParameterLookup(t2, parameters); + if (j == -1) + goto Lnomatch; - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - int vtdim = tempinst->tiargs->dim - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - vt->objects.data[k] = (void *)tempinst->tiargs->data[i + k]; + /* Create tuple from remaining args + */ + Tuple *vt = new Tuple(); + int vtdim = tempinst->tiargs->dim - i; + vt->objects.setDim(vtdim); + for (size_t k = 0; k < vtdim; k++) + vt->objects.data[k] = (void *)tempinst->tiargs->data[i + k]; - Tuple *v = (Tuple *)dedtypes->data[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->data[j] = vt; - break; //return MATCHexact; - } + Tuple *v = (Tuple *)dedtypes->data[j]; + if (v) + { + if (!match(v, vt, tempinst->tempdecl, sc)) + goto Lnomatch; + } + else + dedtypes->data[j] = vt; + break; //return MATCHexact; + } - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes)) - goto Lnomatch; - } - else if (e1 && e2) - { - if (!e1->equals(e2)) - { if (e2->op == TOKvar) - { - /* - * (T:Number!(e2), int e2) - */ - j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); - goto L1; - } - goto Lnomatch; - } - } - else if (e1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - L1: - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->data[j]; - if (e) - { - if (!e1->equals(e)) - goto Lnomatch; - } - else - { Type *vt = tv->valType->semantic(0, sc); - MATCH m = (MATCH)e1->implicitConvTo(vt); - if (!m) - goto Lnomatch; - dedtypes->data[j] = e1; - } - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->data[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - dedtypes->data[j] = s1; - } - } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters - else - goto Lnomatch; - } + if (t1 && t2) + { + if (!t1->deduceType(sc, t2, parameters, dedtypes)) + goto Lnomatch; + } + else if (e1 && e2) + { + if (!e1->equals(e2)) + { if (e2->op == TOKvar) + { + /* + * (T:Number!(e2), int e2) + */ + j = templateIdentifierLookup(((VarExp *)e2)->var->ident, parameters); + goto L1; + } + goto Lnomatch; + } + } + else if (e1 && t2 && t2->ty == Tident) + { + j = templateParameterLookup(t2, parameters); + L1: + if (j == -1) + goto Lnomatch; + TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; + // BUG: use tp->matchArg() instead of the following + TemplateValueParameter *tv = tp->isTemplateValueParameter(); + if (!tv) + goto Lnomatch; + Expression *e = (Expression *)dedtypes->data[j]; + if (e) + { + if (!e1->equals(e)) + goto Lnomatch; + } + else + { Type *vt = tv->valType->semantic(0, sc); + MATCH m = (MATCH)e1->implicitConvTo(vt); + if (!m) + goto Lnomatch; + dedtypes->data[j] = e1; + } + } + else if (s1 && t2 && t2->ty == Tident) + { + j = templateParameterLookup(t2, parameters); + if (j == -1) + goto Lnomatch; + TemplateParameter *tp = (TemplateParameter *)parameters->data[j]; + // BUG: use tp->matchArg() instead of the following + TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); + if (!ta) + goto Lnomatch; + Dsymbol *s = (Dsymbol *)dedtypes->data[j]; + if (s) + { + if (!s1->equals(s)) + goto Lnomatch; + } + else + { + dedtypes->data[j] = s1; + } + } + else if (s1 && s2) + { + if (!s1->equals(s2)) + goto Lnomatch; + } + // BUG: Need to handle tuple parameters + else + goto Lnomatch; + } } return Type::deduceType(sc, tparam, parameters, dedtypes); @@ -2145,41 +2425,41 @@ MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parame if (tparam && tparam->ty == Tinstance) { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes); - } + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + return t->deduceType(sc, tparam, parameters, dedtypes); + } - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); + tpi->idents.dim++; + return m; + } + } + } } // Extra check if (tparam && tparam->ty == Tstruct) { - TypeStruct *tp = (TypeStruct *)tparam; + TypeStruct *tp = (TypeStruct *)tparam; - if (sym != tp->sym) - return MATCHnomatch; + if (sym != tp->sym) + return MATCHnomatch; } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -2189,10 +2469,10 @@ MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramete // Extra check if (tparam && tparam->ty == Tenum) { - TypeEnum *tp = (TypeEnum *)tparam; + TypeEnum *tp = (TypeEnum *)tparam; - if (sym != tp->sym) - return MATCHnomatch; + if (sym != tp->sym) + return MATCHnomatch; } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -2202,14 +2482,71 @@ MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *param // Extra check if (tparam && tparam->ty == Ttypedef) { - TypeTypedef *tp = (TypeTypedef *)tparam; + TypeTypedef *tp = (TypeTypedef *)tparam; - if (sym != tp->sym) - return MATCHnomatch; + if (sym != tp->sym) + return MATCHnomatch; } return Type::deduceType(sc, tparam, parameters, dedtypes); } +/* Helper for TypeClass::deduceType(). + * Classes can match with implicit conversion to a base class or interface. + * This is complicated, because there may be more than one base class which + * matches. In such cases, one or more parameters remain ambiguous. + * For example, + * + * interface I(X, Y) {} + * class C : I(uint, double), I(char, double) {} + * C x; + * foo(T, U)( I!(T, U) x) + * + * deduces that U is double, but T remains ambiguous (could be char or uint). + * + * Given a baseclass b, and initial deduced types 'dedtypes', this function + * tries to match tparam with b, and also tries all base interfaces of b. + * If a match occurs, numBaseClassMatches is incremented, and the new deduced + * types are ANDed with the current 'best' estimate for dedtypes. + */ +void deduceBaseClassParameters(BaseClass *b, + Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, + Objects *best, int &numBaseClassMatches) +{ + TemplateInstance *parti = b->base->parent->isTemplateInstance(); + if (parti) + { + // Make a temporary copy of dedtypes so we don't destroy it + Objects *tmpdedtypes = new Objects(); + tmpdedtypes->setDim(dedtypes->dim); + memcpy(tmpdedtypes->data, dedtypes->data, dedtypes->dim * sizeof(void *)); + + TypeInstance *t = new TypeInstance(0, parti); + MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); + if (m != MATCHnomatch) + { + // If this is the first ever match, it becomes our best estimate + if (numBaseClassMatches==0) + memcpy(best->data, tmpdedtypes->data, tmpdedtypes->dim * sizeof(void *)); + else for (size_t k = 0; k < tmpdedtypes->dim; ++k) + { + // If we've found more than one possible type for a parameter, + // mark it as unknown. + if (tmpdedtypes->data[k] != best->data[k]) + best->data[k] = dedtypes->data[k]; + } + ++numBaseClassMatches; + } + } + // Now recursively test the inherited interfaces + for (size_t j = 0; j < b->baseInterfaces_dim; ++j) + { + deduceBaseClassParameters( &(b->baseInterfaces)[j], + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + +} + MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) { //printf("TypeClass::deduceType(this = %s)\n", toChars()); @@ -2222,41 +2559,86 @@ MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *paramet if (tparam && tparam->ty == Tinstance) { - if (ti && ti->toAlias() == sym) - { - TypeInstance *t = new TypeInstance(0, ti); - return t->deduceType(sc, tparam, parameters, dedtypes); - } + if (ti && ti->toAlias() == sym) + { + TypeInstance *t = new TypeInstance(0, ti); + MATCH m = t->deduceType(sc, tparam, parameters, dedtypes); + // Even if the match fails, there is still a chance it could match + // a base class. + if (m != MATCHnomatch) + return m; + } - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; - if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) - { - Type *tparent = sym->parent->getType(); - if (tparent) - { - /* Slice off the .foo in S!(T).foo - */ - tpi->idents.dim--; - MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); - tpi->idents.dim++; - return m; - } - } - } + /* Match things like: + * S!(T).foo + */ + TypeInstance *tpi = (TypeInstance *)tparam; + if (tpi->idents.dim) + { Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim - 1]; + if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id)) + { + Type *tparent = sym->parent->getType(); + if (tparent) + { + /* Slice off the .foo in S!(T).foo + */ + tpi->idents.dim--; + MATCH m = tparent->deduceType(sc, tpi, parameters, dedtypes); + tpi->idents.dim++; + return m; + } + } + } + + // If it matches exactly or via implicit conversion, we're done + MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes); + if (m != MATCHnomatch) + return m; + + /* There is still a chance to match via implicit conversion to + * a base class or interface. Because there could be more than one such + * match, we need to check them all. + */ + + int numBaseClassMatches = 0; // Have we found an interface match? + + // Our best guess at dedtypes + Objects *best = new Objects(); + best->setDim(dedtypes->dim); + + ClassDeclaration *s = sym; + while(s && s->baseclasses->dim > 0) + { + // Test the base class + deduceBaseClassParameters((BaseClass *)(s->baseclasses->data[0]), + sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + + // Test the interfaces inherited by the base class + for (size_t i = 0; i < s->interfaces_dim; ++i) + { + BaseClass *b = s->interfaces[i]; + deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, + best, numBaseClassMatches); + } + s = ((BaseClass *)(s->baseclasses->data[0]))->base; + } + + if (numBaseClassMatches == 0) + return MATCHnomatch; + + // If we got at least one match, copy the known types into dedtypes + memcpy(dedtypes->data, best->data, best->dim * sizeof(void *)); + return MATCHconvert; } // Extra check if (tparam && tparam->ty == Tclass) { - TypeClass *tp = (TypeClass *)tparam; + TypeClass *tp = (TypeClass *)tparam; - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return implicitConvTo(tp); } return Type::deduceType(sc, tparam, parameters, dedtypes); } @@ -2302,7 +2684,7 @@ TemplateThisParameter *TemplateParameter::isTemplateThisParameter() // type-parameter TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) + Type *defaultType) : TemplateParameter(loc, ident) { this->ident = ident; @@ -2319,9 +2701,9 @@ TemplateParameter *TemplateTypeParameter::syntaxCopy() { TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); if (tp->specType) - tp->specType = specType->syntaxCopy(); + tp->specType = specType->syntaxCopy(); if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); + tp->defaultType = defaultType->syntaxCopy(); return tp; } @@ -2331,7 +2713,7 @@ void TemplateTypeParameter::declareParameter(Scope *sc) TypeIdentifier *ti = new TypeIdentifier(loc, ident); sparam = new AliasDeclaration(loc, ident, ti); if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); + error(loc, "parameter '%s' multiply defined", ident->toChars()); } void TemplateTypeParameter::semantic(Scope *sc) @@ -2339,12 +2721,12 @@ void TemplateTypeParameter::semantic(Scope *sc) //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); if (specType) { - specType = specType->semantic(loc, sc); + specType = specType->semantic(loc, sc); } #if 0 // Don't do semantic() until instantiation if (defaultType) { - defaultType = defaultType->semantic(loc, sc); + defaultType = defaultType->semantic(loc, sc); } #endif } @@ -2353,8 +2735,8 @@ void TemplateTypeParameter::semantic(Scope *sc) * Determine if two TemplateParameters are the same * as far as TemplateDeclaration overloading goes. * Returns: - * 1 match - * 0 no match + * 1 match + * 0 no match */ int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) @@ -2363,13 +2745,13 @@ int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) if (ttp) { - if (specType != ttp->specType) - goto Lnomatch; + if (specType != ttp->specType) + goto Lnomatch; - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; + if (specType && !specType->equals(ttp->specType)) + goto Lnomatch; - return 1; // match + return 1; // match } Lnomatch: @@ -2379,17 +2761,17 @@ Lnomatch: /******************************************* * Match to a particular TemplateParameter. * Input: - * i i'th argument - * tiargs[] actual arguments to template instance - * parameters[] template parameters - * dedtypes[] deduced arguments to template instance - * *psparam set to symbol declared and initialized to dedtypes[i] - * flags 1: don't do 'toHeadMutable()' + * i i'th argument + * tiargs[] actual arguments to template instance + * parameters[] template parameters + * dedtypes[] deduced arguments to template instance + * *psparam set to symbol declared and initialized to dedtypes[i] + * flags 1: don't do 'toHeadMutable()' */ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - int i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) + int i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam, int flags) { //printf("TemplateTypeParameter::matchArg()\n"); Type *t; @@ -2398,27 +2780,27 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, Type *ta; if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; + oarg = (Object *)tiargs->data[i]; else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - { - goto Lnomatch; - } - flags |= 1; // already deduced, so don't to toHeadMutable() - } + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = (Object *)dedtypes->data[i]; + if (!oarg) + { + goto Lnomatch; + } + flags |= 1; // already deduced, so don't to toHeadMutable() + } } ta = isType(oarg); if (!ta) { - //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); - goto Lnomatch; + //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); + goto Lnomatch; } //printf("ta is %s\n", ta->toChars()); @@ -2426,43 +2808,43 @@ MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, if (specType) { - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } + //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); + MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); + if (m2 == MATCHnomatch) + { //printf("\tfailed deduceType\n"); + goto Lnomatch; + } - if (m2 < m) - m = m2; - t = (Type *)dedtypes->data[i]; + if (m2 < m) + m = m2; + t = (Type *)dedtypes->data[i]; } else { - // So that matches with specializations are better - m = MATCHconvert; + // So that matches with specializations are better + m = MATCHconvert; - /* This is so that: - * template Foo(T), Foo!(const int), => ta == int - */ -// if (!(flags & 1)) -// ta = ta->toHeadMutable(); + /* This is so that: + * template Foo(T), Foo!(const int), => ta == int + */ +// if (!(flags & 1)) +// ta = ta->toHeadMutable(); - if (t) - { // Must match already deduced type + if (t) + { // Must match already deduced type - m = MATCHexact; - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } + m = MATCHexact; + if (!t->equals(ta)) + { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); + goto Lnomatch; + } + } } if (!t) { - dedtypes->data[i] = ta; - t = ta; + dedtypes->data[i] = ta; + t = ta; } *psparam = new AliasDeclaration(loc, ident, t); //printf("\tm = %d\n", m); @@ -2485,10 +2867,10 @@ void TemplateTypeParameter::print(Object *oarg, Object *oded) assert(ta); if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); + printf("\tSpecialization: %s\n", specType->toChars()); if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tArgument: %s\n", t ? t->toChars() : "NULL"); + printf("\tDefault: %s\n", defaultType->toChars()); + printf("\tParameter: %s\n", t ? t->toChars() : "NULL"); printf("\tDeduced Type: %s\n", ta->toChars()); } @@ -2498,13 +2880,13 @@ void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(ident->toChars()); if (specType) { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); + buf->writestring(" : "); + specType->toCBuffer(buf, NULL, hgs); } if (defaultType) { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); + buf->writestring(" = "); + defaultType->toCBuffer(buf, NULL, hgs); } } @@ -2513,10 +2895,10 @@ void *TemplateTypeParameter::dummyArg() { Type *t; if (specType) - t = specType; + t = specType; else { // Use this for alias-parameter's too (?) - t = new TypeIdentifier(loc, ident); + t = new TypeIdentifier(loc, ident); } return (void *)t; } @@ -2535,8 +2917,8 @@ Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) t = defaultType; if (t) { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); + t = t->syntaxCopy(); + t = t->semantic(loc, sc); } return t; } @@ -2547,8 +2929,8 @@ Object *TemplateTypeParameter::defaultArg(Loc loc, Scope *sc) // this-parameter TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, - Type *specType, - Type *defaultType) + Type *specType, + Type *defaultType) : TemplateTypeParameter(loc, ident, specType, defaultType) { } @@ -2562,9 +2944,9 @@ TemplateParameter *TemplateThisParameter::syntaxCopy() { TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); if (tp->specType) - tp->specType = specType->syntaxCopy(); + tp->specType = specType->syntaxCopy(); if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); + tp->defaultType = defaultType->syntaxCopy(); return tp; } @@ -2582,7 +2964,7 @@ void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) Dsymbol *TemplateAliasParameter::sdummy = NULL; TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, - Type *specType, Object *specAlias, Object *defaultAlias) + Type *specType, Object *specAlias, Object *defaultAlias) : TemplateParameter(loc, ident) { this->ident = ident; @@ -2600,7 +2982,7 @@ TemplateParameter *TemplateAliasParameter::syntaxCopy() { TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); if (tp->specType) - tp->specType = specType->syntaxCopy(); + tp->specType = specType->syntaxCopy(); tp->specAlias = objectSyntaxCopy(specAlias); tp->defaultAlias = objectSyntaxCopy(defaultAlias); return tp; @@ -2611,27 +2993,27 @@ void TemplateAliasParameter::declareParameter(Scope *sc) TypeIdentifier *ti = new TypeIdentifier(loc, ident); sparam = new AliasDeclaration(loc, ident, ti); if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); + error(loc, "parameter '%s' multiply defined", ident->toChars()); } Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) { if (o) { - Expression *ea = isExpression(o); - Type *ta = isType(o); - if (ta) - { Dsymbol *s = ta->toDsymbol(sc); - if (s) - o = s; - else - o = ta->semantic(loc, sc); - } - else if (ea) - { - ea = ea->semantic(sc); - o = ea->optimize(WANTvalue | WANTinterpret); - } + Expression *ea = isExpression(o); + Type *ta = isType(o); + if (ta) + { Dsymbol *s = ta->toDsymbol(sc); + if (s) + o = s; + else + o = ta->semantic(loc, sc); + } + else if (ea) + { + ea = ea->semantic(sc); + o = ea->optimize(WANTvalue | WANTinterpret); + } } return o; } @@ -2640,12 +3022,12 @@ void TemplateAliasParameter::semantic(Scope *sc) { if (specType) { - specType = specType->semantic(loc, sc); + specType = specType->semantic(loc, sc); } specAlias = aliasParameterSemantic(loc, sc, specAlias); #if 0 // Don't do semantic() until instantiation if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); + defaultAlias = defaultAlias->semantic(loc, sc); #endif } @@ -2655,10 +3037,10 @@ int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) if (tap) { - if (specAlias != tap->specAlias) - goto Lnomatch; + if (specAlias != tap->specAlias) + goto Lnomatch; - return 1; // match + return 1; // match } Lnomatch: @@ -2666,9 +3048,9 @@ Lnomatch: } MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) + Objects *tiargs, int i, TemplateParameters *parameters, + Objects *dedtypes, + Declaration **psparam, int flags) { Object *sa; Object *oarg; @@ -2678,77 +3060,77 @@ MATCH TemplateAliasParameter::matchArg(Scope *sc, //printf("TemplateAliasParameter::matchArg()\n"); if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; + oarg = (Object *)tiargs->data[i]; else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - goto Lnomatch; - } + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = (Object *)dedtypes->data[i]; + if (!oarg) + goto Lnomatch; + } } sa = getDsymbol(oarg); if (sa) { - /* specType means the alias must be a declaration with a type - * that matches specType. - */ - if (specType) - { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); - if (!d) - goto Lnomatch; - if (!d->type->equals(specType)) - goto Lnomatch; - } + /* specType means the alias must be a declaration with a type + * that matches specType. + */ + if (specType) + { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); + if (!d) + goto Lnomatch; + if (!d->type->equals(specType)) + goto Lnomatch; + } } else { - sa = oarg; - ea = isExpression(oarg); - if (ea) - { if (specType) - { - if (!ea->type->equals(specType)) - goto Lnomatch; - } - } - else - goto Lnomatch; + sa = oarg; + ea = isExpression(oarg); + if (ea) + { if (specType) + { + if (!ea->type->equals(specType)) + goto Lnomatch; + } + } + else + goto Lnomatch; } if (specAlias) { - if (sa == sdummy) - goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; + if (sa == sdummy) + goto Lnomatch; + if (sa != specAlias) + goto Lnomatch; } else if (dedtypes->data[i]) { // Must match already deduced symbol - Object *s = (Object *)dedtypes->data[i]; + Object *s = (Object *)dedtypes->data[i]; - if (!sa || s != sa) - goto Lnomatch; + if (!sa || s != sa) + goto Lnomatch; } dedtypes->data[i] = sa; s = isDsymbol(sa); if (s) - *psparam = new AliasDeclaration(loc, ident, s); + *psparam = new AliasDeclaration(loc, ident, s); else { - assert(ea); + assert(ea); // Declare manifest constant Initializer *init = new ExpInitializer(loc, ea); VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); v->storage_class = STCmanifest; v->semantic(sc); - *psparam = v; + *psparam = v; } return MATCHexact; @@ -2766,27 +3148,27 @@ void TemplateAliasParameter::print(Object *oarg, Object *oded) Dsymbol *sa = isDsymbol(oded); assert(sa); - printf("\tArgument alias: %s\n", sa->toChars()); + printf("\tParameter alias: %s\n", sa->toChars()); } void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("alias "); if (specType) - { HdrGenState hgs; - specType->toCBuffer(buf, ident, &hgs); + { HdrGenState hgs; + specType->toCBuffer(buf, ident, &hgs); } else - buf->writestring(ident->toChars()); + buf->writestring(ident->toChars()); if (specAlias) { - buf->writestring(" : "); - ObjectToCBuffer(buf, hgs, specAlias); + buf->writestring(" : "); + ObjectToCBuffer(buf, hgs, specAlias); } if (defaultAlias) { - buf->writestring(" = "); - ObjectToCBuffer(buf, hgs, defaultAlias); + buf->writestring(" = "); + ObjectToCBuffer(buf, hgs, defaultAlias); } } @@ -2797,9 +3179,9 @@ void *TemplateAliasParameter::dummyArg() s = specAlias; if (!s) { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; + if (!sdummy) + sdummy = new Dsymbol(); + s = sdummy; } return (void*)s; } @@ -2813,7 +3195,18 @@ Object *TemplateAliasParameter::specialization() Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) { - Object *o = aliasParameterSemantic(loc, sc, defaultAlias); + Object *da = defaultAlias; + Type *ta = isType(defaultAlias); + if (ta) + { + if (ta->ty == Tinstance) + { + // If the default arg is a template, instantiate for each type + da = ta->syntaxCopy(); + } + } + + Object *o = aliasParameterSemantic(loc, sc, da); return o; } @@ -2824,7 +3217,7 @@ Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) Expression *TemplateValueParameter::edummy = NULL; TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) + Expression *specValue, Expression *defaultValue) : TemplateParameter(loc, ident) { this->ident = ident; @@ -2841,12 +3234,12 @@ TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() TemplateParameter *TemplateValueParameter::syntaxCopy() { TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); + new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); tp->valType = valType->syntaxCopy(); if (specValue) - tp->specValue = specValue->syntaxCopy(); + tp->specValue = specValue->syntaxCopy(); if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); + tp->defaultValue = defaultValue->syntaxCopy(); return tp; } @@ -2855,7 +3248,7 @@ void TemplateValueParameter::declareParameter(Scope *sc) VarDeclaration *v = new VarDeclaration(loc, valType, ident, NULL); v->storage_class = STCtemplateparameter; if (!sc->insert(v)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); + error(loc, "parameter '%s' multiply defined", ident->toChars()); sparam = v; } @@ -2864,31 +3257,31 @@ void TemplateValueParameter::semantic(Scope *sc) sparam->semantic(sc); valType = valType->semantic(loc, sc); if (!(valType->isintegral() || valType->isfloating() || valType->isString()) && - valType->ty != Tident) - error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); + valType->ty != Tident) + error(loc, "arithmetic/string type expected for value-parameter, not %s", valType->toChars()); if (specValue) { Expression *e = specValue; - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64 || e->op == TOKfloat64 || - e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) - specValue = e; - //e->toInteger(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64 || e->op == TOKfloat64 || + e->op == TOKcomplex80 || e->op == TOKnull || e->op == TOKstring) + specValue = e; + //e->toInteger(); } -#if 0 // defer semantic analysis to arg match +#if 0 // defer semantic analysis to arg match if (defaultValue) { Expression *e = defaultValue; - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->op == TOKint64) - defaultValue = e; - //e->toInteger(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + if (e->op == TOKint64) + defaultValue = e; + //e->toInteger(); } #endif } @@ -2899,16 +3292,16 @@ int TemplateValueParameter::overloadMatch(TemplateParameter *tp) if (tvp) { - if (valType != tvp->valType) - goto Lnomatch; + if (valType != tvp->valType) + goto Lnomatch; - if (valType && !valType->equals(tvp->valType)) - goto Lnomatch; + if (valType && !valType->equals(tvp->valType)) + goto Lnomatch; - if (specValue != tvp->specValue) - goto Lnomatch; + if (specValue != tvp->specValue) + goto Lnomatch; - return 1; // match + return 1; // match } Lnomatch: @@ -2917,8 +3310,8 @@ Lnomatch: MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam, int flags) + Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam, int flags) { //printf("TemplateValueParameter::matchArg()\n"); @@ -2929,57 +3322,57 @@ MATCH TemplateValueParameter::matchArg(Scope *sc, Object *oarg; if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; + oarg = (Object *)tiargs->data[i]; else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - goto Lnomatch; - } + { // Get default argument instead + oarg = defaultArg(loc, sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = (Object *)dedtypes->data[i]; + if (!oarg) + goto Lnomatch; + } } ei = isExpression(oarg); Type *vt; if (!ei && oarg) - goto Lnomatch; + goto Lnomatch; if (ei && ei->op == TOKvar) - { // Resolve const variables that we had skipped earlier - ei = ei->optimize(WANTvalue | WANTinterpret); + { // Resolve const variables that we had skipped earlier + ei = ei->optimize(WANTvalue | WANTinterpret); } if (specValue) { - if (!ei || ei == edummy) - goto Lnomatch; + if (!ei || ei == edummy) + goto Lnomatch; - Expression *e = specValue; + Expression *e = specValue; - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - //e->type = e->type->toHeadMutable(); + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + //e->type = e->type->toHeadMutable(); - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->optimize(WANTvalue | WANTinterpret); - //ei->type = ei->type->toHeadMutable(); - //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; + ei = ei->syntaxCopy(); + ei = ei->semantic(sc); + ei = ei->optimize(WANTvalue | WANTinterpret); + //ei->type = ei->type->toHeadMutable(); + //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); + //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); + if (!ei->equals(e)) + goto Lnomatch; } else if (dedtypes->data[i]) { // Must match already deduced value - Expression *e = (Expression *)dedtypes->data[i]; + Expression *e = (Expression *)dedtypes->data[i]; - if (!ei || !ei->equals(e)) - goto Lnomatch; + if (!ei || !ei->equals(e)) + goto Lnomatch; } Lmatch: //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); @@ -2988,10 +3381,10 @@ Lmatch: //printf("vt = %s\n", vt->toChars()); if (ei->type) { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; + m = (MATCH)ei->implicitConvTo(vt); + //printf("m: %d\n", m); + if (!m) + goto Lnomatch; } dedtypes->data[i] = ei; @@ -3015,8 +3408,8 @@ void TemplateValueParameter::print(Object *oarg, Object *oded) Expression *ea = isExpression(oded); if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL"); + printf("\tSpecialization: %s\n", specValue->toChars()); + printf("\tParameter Value: %s\n", ea ? ea->toChars() : "NULL"); } @@ -3025,13 +3418,13 @@ void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) valType->toCBuffer(buf, ident, hgs); if (specValue) { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); + buf->writestring(" : "); + specValue->toCBuffer(buf, hgs); } if (defaultValue) { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); + buf->writestring(" = "); + defaultValue->toCBuffer(buf, hgs); } } @@ -3042,10 +3435,10 @@ void *TemplateValueParameter::dummyArg() e = specValue; if (!e) { - // Create a dummy value - if (!edummy) - edummy = valType->defaultInit(); - e = edummy; + // Create a dummy value + if (!edummy) + edummy = valType->defaultInit(); + e = edummy; } return (void *)e; } @@ -3062,13 +3455,10 @@ Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) Expression *e = defaultValue; if (e) { - e = e->syntaxCopy(); - e = e->semantic(sc); + e = e->syntaxCopy(); + e = e->semantic(sc); #if DMDV2 - if (e->op == TOKdefault) - { DefaultInitExp *de = (DefaultInitExp *)e; - e = de->resolve(loc, sc); - } + e = e->resolveLoc(loc, sc); #endif } return e; @@ -3100,7 +3490,7 @@ void TemplateTupleParameter::declareParameter(Scope *sc) TypeIdentifier *ti = new TypeIdentifier(loc, ident); sparam = new AliasDeclaration(loc, ident, ti); if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); + error(loc, "parameter '%s' multiply defined", ident->toChars()); } void TemplateTupleParameter::semantic(Scope *sc) @@ -3113,7 +3503,7 @@ int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) if (tvp) { - return 1; // match + return 1; // match } Lnomatch: @@ -3121,30 +3511,30 @@ Lnomatch: } MATCH TemplateTupleParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam, int flags) + Objects *tiargs, int i, TemplateParameters *parameters, + Objects *dedtypes, + Declaration **psparam, int flags) { //printf("TemplateTupleParameter::matchArg()\n"); /* The rest of the actual arguments (tiargs[]) form the match * for the variadic parameter. */ - assert(i + 1 == dedtypes->dim); // must be the last one + assert(i + 1 == dedtypes->dim); // must be the last one Tuple *ovar; if (i + 1 == tiargs->dim && isTuple((Object *)tiargs->data[i])) - ovar = isTuple((Object *)tiargs->data[i]); + ovar = isTuple((Object *)tiargs->data[i]); else { - ovar = new Tuple(); - //printf("ovar = %p\n", ovar); - if (i < tiargs->dim) - { - //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); - ovar->objects.setDim(tiargs->dim - i); - for (size_t j = 0; j < ovar->objects.dim; j++) - ovar->objects.data[j] = tiargs->data[i + j]; - } + ovar = new Tuple(); + //printf("ovar = %p\n", ovar); + if (i < tiargs->dim) + { + //printf("i = %d, tiargs->dim = %d\n", i, tiargs->dim); + ovar->objects.setDim(tiargs->dim - i); + for (size_t j = 0; j < ovar->objects.dim; j++) + ovar->objects.data[j] = tiargs->data[i + j]; + } } *psparam = new TupleDeclaration(loc, ident, &ovar->objects); dedtypes->data[i] = (void *)ovar; @@ -3161,24 +3551,24 @@ void TemplateTupleParameter::print(Object *oarg, Object *oded) //printf("|%d| ", v->objects.dim); for (int i = 0; i < v->objects.dim; i++) { - if (i) - printf(", "); + if (i) + printf(", "); - Object *o = (Object *)v->objects.data[i]; + Object *o = (Object *)v->objects.data[i]; - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); + Dsymbol *sa = isDsymbol(o); + if (sa) + printf("alias: %s", sa->toChars()); - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); + Type *ta = isType(o); + if (ta) + printf("type: %s", ta->toChars()); - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); + Expression *ea = isExpression(o); + if (ea) + printf("exp: %s", ea->toChars()); - assert(!isTuple(o)); // no nested Tuple arguments + assert(!isTuple(o)); // no nested Tuple arguments } printf("]\n"); @@ -3280,12 +3670,12 @@ Objects *TemplateInstance::arraySyntaxCopy(Objects *objs) { Objects *a = NULL; if (objs) - { a = new Objects(); - a->setDim(objs->dim); - for (size_t i = 0; i < objs->dim; i++) - { - a->data[i] = objectSyntaxCopy((Object *)objs->data[i]); - } + { a = new Objects(); + a->setDim(objs->dim); + for (size_t i = 0; i < objs->dim; i++) + { + a->data[i] = objectSyntaxCopy((Object *)objs->data[i]); + } } return a; } @@ -3295,9 +3685,9 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) TemplateInstance *ti; if (s) - ti = (TemplateInstance *)s; + ti = (TemplateInstance *)s; else - ti = new TemplateInstance(loc, name); + ti = new TemplateInstance(loc, name); ti->tiargs = arraySyntaxCopy(tiargs); @@ -3308,26 +3698,33 @@ Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) void TemplateInstance::semantic(Scope *sc) { - if (global.errors) + semantic(sc, NULL); +} + +void TemplateInstance::semantic(Scope *sc, Expressions *fargs) +{ + //printf("TemplateInstance::semantic('%s', this=%p, gag = %d)\n", toChars(), this, global.gag); + if (global.errors && name != Id::AssociativeArray) { - if (!global.gag) - { - /* Trying to soldier on rarely generates useful messages - * at this point. - */ - fatal(); - } - return; + //printf("not instantiating %s due to %d errors\n", toChars(), global.errors); + if (!global.gag) + { + /* Trying to soldier on rarely generates useful messages + * at this point. + */ + fatal(); + } +// return; } #if LOG printf("\n+TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); #endif - if (inst) // if semantic() was already run + if (inst) // if semantic() was already run { #if LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); + printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); #endif - return; + return; } // get the enclosing template instance from the scope tinst @@ -3335,9 +3732,12 @@ void TemplateInstance::semantic(Scope *sc) if (semanticRun != 0) { - error(loc, "recursive template expansion"); -// inst = this; - return; +#if LOG + printf("Recursive template expansion\n"); +#endif + error(loc, "recursive template expansion"); +// inst = this; + return; } semanticRun = 1; #if IN_LLVM @@ -3357,33 +3757,42 @@ void TemplateInstance::semantic(Scope *sc) #endif if (havetempdecl) { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, 2)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } + assert((size_t)tempdecl->scope > 0x10000); + // Deduce tdtypes + tdtypes.setDim(tempdecl->parameters->dim); + if (!tempdecl->matchWithInstance(this, &tdtypes, 2)) + { + error("incompatible arguments for template instantiation"); + inst = this; + return; + } } else { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); + /* Run semantic on each argument, place results in tiargs[] + * (if we havetempdecl, then tiargs is already evaluated) + */ + semanticTiargs(sc); + if (arrayObjectIsError(tiargs)) + { inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc); - if (!tempdecl || global.errors) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } + tempdecl = findTemplateDeclaration(sc); + if (tempdecl) + tempdecl = findBestMatch(sc); + if (!tempdecl || global.errors) + { inst = this; + //printf("error return %p, %d\n", tempdecl, global.errors); + return; // error recovery + } } + // If tempdecl is a mixin, disallow it + if (tempdecl->ismixin) + error("mixin templates are not regular templates"); + hasNestedArgs(tiargs); /* See if there is an existing TemplateInstantiation that already @@ -3392,41 +3801,63 @@ void TemplateInstance::semantic(Scope *sc) for (size_t i = 0; i < tempdecl->instances.dim; i++) { - TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; + TemplateInstance *ti = (TemplateInstance *)tempdecl->instances.data[i]; #if LOG - printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); + printf("\t%s: checking for match with instance %d (%p): '%s'\n", toChars(), i, ti, ti->toChars()); #endif - assert(tdtypes.dim == ti->tdtypes.dim); + assert(tdtypes.dim == ti->tdtypes.dim); - // Nesting must match - if (isnested != ti->isnested) - { - //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); - continue; - } + // Nesting must match + if (isnested != ti->isnested) + { + //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); + continue; + } #if 0 - if (isnested && sc->parent != ti->parent) - continue; + if (isnested && sc->parent != ti->parent) + continue; #endif - for (size_t j = 0; j < tdtypes.dim; j++) - { Object *o1 = (Object *)tdtypes.data[j]; - Object *o2 = (Object *)ti->tdtypes.data[j]; - if (!match(o1, o2, tempdecl, sc)) - { - goto L1; - } - } + if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) + goto L1; - // It's a match - inst = ti; - parent = ti->parent; + /* Template functions may have different instantiations based on + * "auto ref" parameters. + */ + if (fargs) + { + FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); + if (fd) + { + Parameters *fparameters = fd->getParameters(NULL); + size_t nfparams = Parameter::dim(fparameters); // Num function parameters + for (int i = 0; i < nfparams && i < fargs->dim; i++) + { Parameter *fparam = Parameter::getNth(fparameters, i); + Expression *farg = (Expression *)fargs->data[i]; + if (fparam->storageClass & STCauto) // if "auto ref" + { + if (farg->isLvalue()) + { if (!(fparam->storageClass & STCref)) + goto L1; // auto ref's don't match + } + else + { if (fparam->storageClass & STCref) + goto L1; // auto ref's don't match + } + } + } + } + } + + // It's a match + inst = ti; + parent = ti->parent; #if LOG - printf("\tit's a match with instance %p\n", inst); + printf("\tit's a match with instance %p\n", inst); #endif - return; + return; L1: - ; + ; } /* So, we need to implement 'this' instance. @@ -3441,11 +3872,11 @@ void TemplateInstance::semantic(Scope *sc) parent = tempdecl->parent; //printf("parent = '%s'\n", parent->kind()); - ident = genIdent(); // need an identifier for name mangling purposes. + ident = genIdent(); // need an identifier for name mangling purposes. #if 1 if (isnested) - parent = isnested; + parent = isnested; #endif //printf("parent = '%s'\n", parent->kind()); @@ -3453,49 +3884,49 @@ void TemplateInstance::semantic(Scope *sc) // will get called on the instance members #if 1 int dosemantic3 = 0; - { Array *a; + { Array *a; - Scope *scx = sc; + Scope *scx = sc; #if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; + for (scx = sc; scx; scx = scx->enclosing) + if (scx->scopesym) + break; #endif - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() + //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + if (scx && scx->scopesym && + scx->scopesym->members && !scx->scopesym->isTemplateMixin() #if 0 // removed because it bloated compile times - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - */ - && !scx->module->selfImports() + /* The problem is if A imports B, and B imports A, and both A + * and B instantiate the same template, does the compilation of A + * or the compilation of B do the actual instantiation? + * + * see bugzilla 2500. + */ + && !scx->module->selfImports() #endif - ) - { - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; - if (m->semanticRun >= 3) - dosemantic3 = 1; - } - for (int i = 0; 1; i++) - { - if (i == a->dim) - { - a->push(this); - break; - } - if (this == (Dsymbol *)a->data[i]) // if already in Array - break; - } + ) + { + //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); + a = scx->scopesym->members; + } + else + { Module *m = sc->module->importedFrom; + //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); + a = m->members; + if (m->semanticRun >= 3) + dosemantic3 = 1; + } + for (int i = 0; 1; i++) + { + if (i == a->dim) + { + a->push(this); + break; + } + if (this == (Dsymbol *)a->data[i]) // if already in Array + break; + } } #endif @@ -3506,8 +3937,8 @@ void TemplateInstance::semantic(Scope *sc) Scope *scope = tempdecl->scope; if (!tempdecl->semanticRun) { - error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); - return; + error("template instantiation %s forward references template declaration %s\n", toChars(), tempdecl->toChars()); + return; } #if LOG @@ -3530,11 +3961,11 @@ void TemplateInstance::semantic(Scope *sc) int memnum = 0; for (int i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; + Dsymbol *s = (Dsymbol *)members->data[i]; #if LOG - printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); + printf("\t[%d] adding member '%s' %p kind %s to '%s', memnum = %d\n", i, s->toChars(), s, s->kind(), this->toChars(), memnum); #endif - memnum |= s->addMember(scope, this, memnum); + memnum |= s->addMember(scope, this, memnum); } #if LOG printf("adding members done\n"); @@ -3547,16 +3978,16 @@ void TemplateInstance::semantic(Scope *sc) //printf("members->dim = %d\n", members->dim); if (members->dim) { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - if (s->ident && s->ident->equals(tempdecl->ident)) - { - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); + Dsymbol *s; + if (Dsymbol::oneMembers(members, &s) && s) + { + //printf("s->kind = '%s'\n", s->kind()); + //s->print(); + //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); + if (s->ident && s->ident->equals(tempdecl->ident)) + { + //printf("setting aliasdecl\n"); + aliasdecl = new AliasDeclaration(loc, s->ident, s); #if IN_LLVM // LDC propagate internal information @@ -3567,8 +3998,24 @@ void TemplateInstance::semantic(Scope *sc) } } #endif - } - } + } + } + } + + /* If function template declaration + */ + if (fargs && aliasdecl) + { + FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); + if (fd) + { + /* Transmit fargs to type so that TypeFunction::semantic() can + * resolve any "auto ref" storage classes. + */ + TypeFunction *tf = (TypeFunction *)fd->type; + if (tf && tf->ty == Tfunction) + tf->fargs = fargs; + } } // Do semantic() analysis on template instance members @@ -3589,28 +4036,28 @@ void TemplateInstance::semantic(Scope *sc) //printf("%d\n", nest); if (++nest > 500) { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); } for (int i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); + //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); +// if (isnested) +// s->parent = sc->parent; + //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + s->semantic(sc2); + //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); + sc2->module->runDeferredSemantic(); } --nest; #if WINDOWS_SEH } __except (__ehfilter(GetExceptionInformation())) { - global.gag = 0; // ensure error message gets printed + global.gag = 0; // ensure error message gets printed error("recursive expansion"); fatal(); } @@ -3621,10 +4068,10 @@ void TemplateInstance::semantic(Scope *sc) * or semantic3() yet. */ for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; + { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; - if (sd->parent == this) - goto Laftersemantic; + if (sd->parent == this) + goto Laftersemantic; } /* The problem is when to parse the initializer for a variable. @@ -3633,15 +4080,36 @@ void TemplateInstance::semantic(Scope *sc) */ // if (sc->parent->isFuncDeclaration()) - /* BUG 782: this has problems if the classes this depends on - * are forward referenced. Find a way to defer semantic() - * on this template. - */ - semantic2(sc2); + /* BUG 782: this has problems if the classes this depends on + * are forward referenced. Find a way to defer semantic() + * on this template. + */ + semantic2(sc2); if (sc->func || dosemantic3) { - semantic3(sc2); +#if WINDOWS_SEH + __try + { +#endif + static int nest; + if (++nest > 300) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } + semantic3(sc2); + --nest; +#if WINDOWS_SEH + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } +#endif } Laftersemantic: @@ -3652,14 +4120,20 @@ void TemplateInstance::semantic(Scope *sc) // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { - error("error instantiating"); - if (tinst && !global.gag) - { tinst->printInstantiationTrace(); - fatal(); - } - errors = 1; - if (global.gag) - tempdecl->instances.remove(tempdecl_instance_idx); + error("error instantiating"); + if (tinst) + { tinst->printInstantiationTrace(); + } + errors = 1; + if (global.gag) + { // Try to reset things so we can try again later to instantiate it + tempdecl->instances.remove(tempdecl_instance_idx); + if (!(sc->flags & SCOPEstaticif)) + { // Bugzilla 4302 for discussion + semanticRun = 0; + inst = NULL; + } + } } #if LOG @@ -3672,14 +4146,14 @@ void TemplateInstance::semanticTiargs(Scope *sc) { //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); if (semantictiargsdone) - return; + return; semantictiargsdone = 1; semanticTiargs(loc, sc, tiargs, 0); } /********************************** * Input: - * flags 1: replace const variables with their initializers + * flags 1: replace const variables with their initializers */ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) @@ -3687,120 +4161,120 @@ void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int f // Run semantic on each argument, place results in tiargs[] //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); if (!tiargs) - return; + return; for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (Object *)tiargs->data[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); + Object *o = (Object *)tiargs->data[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); - //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - /* This test is to skip substituting a const var with - * its initializer. The problem is the initializer won't - * match with an 'alias' parameter. Instead, do the - * const substitution in TemplateValueParameter::matchArg(). - */ - if (ea->op != TOKvar || flags & 1) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[j] = ea; - } - else if (sa) - { tiargs->data[j] = sa; - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - size_t dim = d->objects->dim; - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - } - } - else if (ta) - { - Ltype: - if (ta->ty == Ttuple) - { // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Argument *arg = (Argument *)tt->arguments->data[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - tiargs->data[j] = ta; - } - else - { - assert(global.errors); - tiargs->data[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new IntegerExp(0); - } - assert(ea); - ea = ea->semantic(sc); - if (ea->op != TOKvar || flags & 1) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[j] = ea; - if (ea->op == TOKtype) - { ta = ea->type; - goto Ltype; - } - if (ea->op == TOKtuple) - { // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->data[i]); - } - j--; - } - } - else if (sa) - { - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && !td->semanticRun && td->literal) - td->semantic(sc); - } - else - { - assert(0); - } - //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); + //printf("1: tiargs->data[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); + if (ta) + { + //printf("type %s\n", ta->toChars()); + // It might really be an Expression or an Alias + ta->resolve(loc, sc, &ea, &ta, &sa); + if (ea) + { + ea = ea->semantic(sc); + /* This test is to skip substituting a const var with + * its initializer. The problem is the initializer won't + * match with an 'alias' parameter. Instead, do the + * const substitution in TemplateValueParameter::matchArg(). + */ + if (ea->op != TOKvar || flags & 1) + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->data[j] = ea; + } + else if (sa) + { tiargs->data[j] = sa; + TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); + if (d) + { + size_t dim = d->objects->dim; + tiargs->remove(j); + tiargs->insert(j, d->objects); + j--; + } + } + else if (ta) + { + Ltype: + if (ta->ty == Ttuple) + { // Expand tuple + TypeTuple *tt = (TypeTuple *)ta; + size_t dim = tt->arguments->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + { Parameter *arg = (Parameter *)tt->arguments->data[i]; + tiargs->insert(j + i, arg->type); + } + } + j--; + } + else + tiargs->data[j] = ta; + } + else + { + assert(global.errors); + tiargs->data[j] = Type::terror; + } + } + else if (ea) + { + if (!ea) + { assert(global.errors); + ea = new ErrorExp(); + } + assert(ea); + ea = ea->semantic(sc); + if (ea->op != TOKvar || flags & 1) + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->data[j] = ea; + if (ea->op == TOKtype) + { ta = ea->type; + goto Ltype; + } + if (ea->op == TOKtuple) + { // Expand tuple + TupleExp *te = (TupleExp *)ea; + size_t dim = te->exps->dim; + tiargs->remove(j); + if (dim) + { tiargs->reserve(dim); + for (size_t i = 0; i < dim; i++) + tiargs->insert(j + i, te->exps->data[i]); + } + j--; + } + } + else if (sa) + { + TemplateDeclaration *td = sa->isTemplateDeclaration(); + if (td && !td->semanticRun && td->literal) + td->semantic(sc); + } + else + { + assert(0); + } + //printf("1: tiargs->data[%d] = %p\n", j, tiargs->data[j]); } #if 0 printf("-TemplateInstance::semanticTiargs('%s', this=%p)\n", toChars(), this); for (size_t j = 0; j < tiargs->dim; j++) { - Object *o = (Object *)tiargs->data[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); + Object *o = (Object *)tiargs->data[j]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); - printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); + printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); } #endif } @@ -3814,98 +4288,124 @@ TemplateDeclaration *TemplateInstance::findTemplateDeclaration(Scope *sc) //printf("TemplateInstance::findTemplateDeclaration() %s\n", toChars()); if (!tempdecl) { - /* Given: - * foo!( ... ) - * figure out which TemplateDeclaration foo refers to. - */ - Dsymbol *s; - Dsymbol *scopesym; - Identifier *id; - int i; + /* Given: + * foo!( ... ) + * figure out which TemplateDeclaration foo refers to. + */ + Dsymbol *s; + Dsymbol *scopesym; + Identifier *id; + int i; + + id = name; + s = sc->search(loc, id, &scopesym); + if (!s) + { + s = sc->search_correct(id); + if (s) + error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); + else + error("template '%s' is not defined", id->toChars()); + return NULL; + } + + /* If an OverloadSet, look for a unique member that is a template declaration + */ + OverloadSet *os = s->isOverloadSet(); + if (os) + { s = NULL; + for (int i = 0; i < os->a.dim; i++) + { Dsymbol *s2 = (Dsymbol *)os->a.data[i]; + if (s2->isTemplateDeclaration()) + { + if (s) + error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); + s = s2; + } + } + if (!s) + { error("template '%s' is not defined", id->toChars()); + return NULL; + } + } - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { error("identifier '%s' is not defined", id->toChars()); - return NULL; - } #if LOG - printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); - if (s->parent) - printf("s->parent = '%s'\n", s->parent->toChars()); + printf("It's an instance of '%s' kind '%s'\n", s->toChars(), s->kind()); + if (s->parent) + printf("s->parent = '%s'\n", s->parent->toChars()); #endif - withsym = scopesym->isWithScopeSymbol(); + withsym = scopesym->isWithScopeSymbol(); - /* We might have found an alias within a template when - * we really want the template. - */ - TemplateInstance *ti; - if (s->parent && - (ti = s->parent->isTemplateInstance()) != NULL) - { - if ( - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - s = tempdecl; - } - } + /* We might have found an alias within a template when + * we really want the template. + */ + TemplateInstance *ti; + if (s->parent && + (ti = s->parent->isTemplateInstance()) != NULL) + { + if ( + (ti->name == id || + ti->toAlias()->ident == id) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + s = tempdecl; + } + } - s = s->toAlias(); + s = s->toAlias(); - /* It should be a TemplateDeclaration, not some other symbol - */ - tempdecl = s->isTemplateDeclaration(); - if (!tempdecl) - { - if (!s->parent && global.errors) - return NULL; - if (!s->parent && s->getType()) - { Dsymbol *s2 = s->getType()->toDsymbol(sc); - if (!s2) - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - s = s2; - } + /* It should be a TemplateDeclaration, not some other symbol + */ + tempdecl = s->isTemplateDeclaration(); + if (!tempdecl) + { + if (!s->parent && global.errors) + return NULL; + if (!s->parent && s->getType()) + { Dsymbol *s2 = s->getType()->toDsymbol(sc); + if (!s2) + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + s = s2; + } #ifdef DEBUG - //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); + //if (!s->parent) printf("s = %s %s\n", s->kind(), s->toChars()); #endif - //assert(s->parent); - TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; - if (ti && - (ti->name == id || - ti->toAlias()->ident == id) - && - ti->tempdecl) - { - /* This is so that one can refer to the enclosing - * template, even if it has the same name as a member - * of the template, if it has a !(arguments) - */ - tempdecl = ti->tempdecl; - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - } - else - { - error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); - return NULL; - } - } + //assert(s->parent); + TemplateInstance *ti = s->parent ? s->parent->isTemplateInstance() : NULL; + if (ti && + (ti->name == id || + ti->toAlias()->ident == id) + && + ti->tempdecl) + { + /* This is so that one can refer to the enclosing + * template, even if it has the same name as a member + * of the template, if it has a !(arguments) + */ + tempdecl = ti->tempdecl; + if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's + tempdecl = tempdecl->overroot; // then get the start + } + else + { + error("%s is not a template declaration, it is a %s", id->toChars(), s->kind()); + return NULL; + } + } } else - assert(tempdecl->isTemplateDeclaration()); + assert(tempdecl->isTemplateDeclaration()); return tempdecl; } @@ -3925,91 +4425,93 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) // First look for forward references for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference - td->semantic(td->scope); - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s\n", toChars(), td->toChars()); - return NULL; - } - } + if (!td->semanticRun) + { + if (td->scope) + { // Try to fix forward reference + td->semantic(td->scope); + } + if (!td->semanticRun) + { + error("%s forward references template declaration %s\n", toChars(), td->toChars()); + return NULL; + } + } } for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) { - MATCH m; + MATCH m; //if (tiargs->dim) printf("2: tiargs->dim = %d, data[0] = %p\n", tiargs->dim, tiargs->data[0]); - // If more arguments than parameters, - // then this is no match. - if (td->parameters->dim < tiargs->dim) - { - if (!td->isVariadic()) - continue; - } + // If more arguments than parameters, + // then this is no match. + if (td->parameters->dim < tiargs->dim) + { + if (!td->isVariadic()) + continue; + } - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; + dedtypes.setDim(td->parameters->dim); + dedtypes.zero(); + assert(td->semanticRun); + m = td->matchWithInstance(this, &dedtypes, 0); + //printf("matchWithInstance = %d\n", m); + if (!m) // no match at all + continue; - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best); - MATCH c2 = td_best->leastAsSpecialized(td); - //printf("c1 = %d, c2 = %d\n", c1, c2); + { + // Disambiguate by picking the most specialized TemplateDeclaration + MATCH c1 = td->leastAsSpecialized(td_best); + MATCH c2 = td_best->leastAsSpecialized(td); + //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - else - goto Lambig; - } + if (c1 > c2) + goto Ltd; + else if (c1 < c2) + goto Ltd_best; + else + goto Lambig; + } - Lambig: // td_best and td are ambiguous - td_ambig = td; - continue; + Lambig: // td_best and td are ambiguous + td_ambig = td; + continue; - Ltd_best: // td_best is the best match so far - td_ambig = NULL; - continue; + Ltd_best: // td_best is the best match so far + td_ambig = NULL; + continue; - Ltd: // td is the new best match - td_ambig = NULL; - td_best = td; - m_best = m; - tdtypes.setDim(dedtypes.dim); - memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); - continue; + Ltd: // td is the new best match + td_ambig = NULL; + td_best = td; + m_best = m; + tdtypes.setDim(dedtypes.dim); + memcpy(tdtypes.data, dedtypes.data, tdtypes.dim * sizeof(void *)); + continue; } if (!td_best) { - if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); - else - error("%s does not match any template declaration", toChars()); - return NULL; + if (tempdecl && !tempdecl->overnext) + // Only one template, so we can give better error message + error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); + else + error("%s does not match any template declaration", toChars()); + return NULL; } if (td_ambig) { - error("%s matches more than one template declaration, %s and %s", - toChars(), td_best->toChars(), td_ambig->toChars()); + error("%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", + toChars(), + td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), + td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); } /* The best match is td_best @@ -4020,18 +4522,18 @@ TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) /* Cast any value arguments to be same type as value parameter */ for (size_t i = 0; i < tiargs->dim; i++) - { Object *o = (Object *)tiargs->data[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[i] = (Object *)ea; - } + { Object *o = (Object *)tiargs->data[i]; + Expression *ea = isExpression(o); // value argument + TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + if (tvp) + { + assert(ea); + ea = ea->castTo(tvp->valType); + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->data[i] = (Object *)ea; + } } #endif @@ -4056,77 +4558,73 @@ int TemplateInstance::hasNestedArgs(Objects *args) */ for (size_t i = 0; i < args->dim; i++) { Object *o = (Object *)args->data[i]; - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - if (ea) - { - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - goto Lsa; - } - } - else if (sa) - { - Lsa: - Declaration *d = NULL; - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && td->literal) - { - goto L2; - } - d = sa->isDeclaration(); - if (d && !d->isDataseg() && + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + if (ea) + { + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + goto Lsa; + } + if (ea->op == TOKfunction) + { + sa = ((FuncExp *)ea)->fd; + goto Lsa; + } + } + else if (sa) + { + Lsa: + TemplateDeclaration *td = sa->isTemplateDeclaration(); + Declaration *d = sa->isDeclaration(); + if ((td && td->literal) || + (d && !d->isDataseg() && #if DMDV2 - !(d->storage_class & STCmanifest) && + !(d->storage_class & STCmanifest) && #endif - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin()) - { - L2: - // if module level template - if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = sa->toParent(); - if (!isnested) - isnested = dparent; - else if (isnested != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = isnested; p; p = p->parent) - { - if (p == dparent) - goto L1; // isnested is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), isnested->toChars(), dparent->toChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as parameter to non-global template %s", d->toChars(), tempdecl->toChars()); - } - } - else if (va) - { - nested |= hasNestedArgs(&va->objects); - } + (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && + !isTemplateMixin() + )) + { + // if module level template + if (tempdecl->toParent()->isModule()) + { Dsymbol *dparent = sa->toParent(); + if (!isnested) + isnested = dparent; + else if (isnested != dparent) + { + /* Select the more deeply nested of the two. + * Error if one is not nested inside the other. + */ + for (Dsymbol *p = isnested; p; p = p->parent) + { + if (p == dparent) + goto L1; // isnested is most nested + } + for (Dsymbol *p = dparent; p; p = p->parent) + { + if (p == isnested) + { isnested = dparent; + goto L1; // dparent is most nested + } + } + error("%s is nested in both %s and %s", + toChars(), isnested->toChars(), dparent->toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested->toChars()); + nested |= 1; + } + else + error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); + } + } + else if (va) + { + nested |= hasNestedArgs(&va->objects); + } } return nested; } @@ -4139,102 +4637,100 @@ int TemplateInstance::hasNestedArgs(Objects *args) Identifier *TemplateInstance::genIdent() { OutBuffer buf; - char *id; - Objects *args; //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - id = tempdecl->ident->toChars(); + char *id = tempdecl->ident->toChars(); buf.printf("__T%zu%s", strlen(id), id); - args = tiargs; + Objects *args = tiargs; for (int i = 0; i < args->dim; i++) { Object *o = (Object *)args->data[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); + if (ta) + { + buf.writeByte('T'); + if (ta->deco) + buf.writestring(ta->deco); + else + { #ifdef DEBUG - printf("ta = %d, %s\n", ta->ty, ta->toChars()); + printf("ta = %d, %s\n", ta->ty, ta->toChars()); #endif - assert(global.errors); - } - } - else if (ea) - { - Lea: - sinteger_t v; - real_t r; + assert(global.errors); + } + } + else if (ea) + { + Lea: + sinteger_t v; + real_t r; - ea = ea->optimize(WANTvalue | WANTinterpret); - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKfunction) - { - sa = ((FuncExp *)ea)->fd; - ea = NULL; - goto Lsa; - } - buf.writeByte('V'); - if (ea->op == TOKtuple) - { ea->error("tuple is not a valid template value argument"); - continue; - } + ea = ea->optimize(WANTvalue | WANTinterpret); + if (ea->op == TOKvar) + { + sa = ((VarExp *)ea)->var; + ea = NULL; + goto Lsa; + } + if (ea->op == TOKfunction) + { + sa = ((FuncExp *)ea)->fd; + ea = NULL; + goto Lsa; + } + buf.writeByte('V'); + if (ea->op == TOKtuple) + { ea->error("tuple is not a valid template value argument"); + continue; + } #if 1 - /* Use deco that matches what it would be for a function parameter - */ - buf.writestring(ea->type->deco); + /* Use deco that matches what it would be for a function parameter + */ + buf.writestring(ea->type->deco); #else - // Use type of parameter, not type of argument - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); + // Use type of parameter, not type of argument + TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; + assert(tp); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + assert(tvp); + buf.writestring(tvp->valType->deco); #endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - { error("forward reference of %s", d->toChars()); - continue; - } + ea->toMangleBuffer(&buf); + } + else if (sa) + { + Lsa: + buf.writeByte('S'); + Declaration *d = sa->isDeclaration(); + if (d && (!d->type || !d->type->deco)) + { error("forward reference of %s", d->toChars()); + continue; + } #if 0 - VarDeclaration *v = sa->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - ea = ei->exp; - goto Lea; - } - } + VarDeclaration *v = sa->isVarDeclaration(); + if (v && v->storage_class & STCmanifest) + { ExpInitializer *ei = v->init->isExpInitializer(); + if (ei) + { + ea = ei->exp; + goto Lea; + } + } #endif - const char *p = sa->mangle(); - buf.printf("%zu%s", strlen(p), p); - } - else if (va) - { - assert(i + 1 == args->dim); // must be last one - args = &va->objects; - i = -1; - } - else - assert(0); + const char *p = sa->mangle(); + buf.printf("%zu%s", strlen(p), p); + } + else if (va) + { + assert(i + 1 == args->dim); // must be last one + args = &va->objects; + i = -1; + } + else + assert(0); } buf.writeByte('Z'); id = buf.toChars(); @@ -4254,42 +4750,88 @@ void TemplateInstance::declareParameters(Scope *sc) //printf("TemplateInstance::declareParameters()\n"); for (int i = 0; i < tdtypes.dim; i++) { - TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; - //Object *o = (Object *)tiargs->data[i]; - Object *o = (Object *)tdtypes.data[i]; // initializer for tp + TemplateParameter *tp = (TemplateParameter *)tempdecl->parameters->data[i]; + //Object *o = (Object *)tiargs->data[i]; + Object *o = (Object *)tdtypes.data[i]; // initializer for tp - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); + //printf("\ttdtypes[%d] = %p\n", i, o); + tempdecl->declareParameter(sc, tp, o); } } +/***************************************************** + * Determine if template instance is really a template function, + * and that template function needs to infer types from the function + * arguments. + */ + +int TemplateInstance::needsTypeInference(Scope *sc) +{ + //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); + if (!tempdecl) + tempdecl = findTemplateDeclaration(sc); + int multipleMatches = FALSE; + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + /* If any of the overloaded template declarations need inference, + * then return TRUE + */ + FuncDeclaration *fd; + if (!td->onemember || + (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || + fd->type->ty != Tfunction) + { + /* Not a template function, therefore type inference is not possible. + */ + //printf("false\n"); + return FALSE; + } + + /* Determine if the instance arguments, tiargs, are all that is necessary + * to instantiate the template. + */ + TemplateTupleParameter *tp = td->isVariadic(); + //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); + TypeFunction *fdtype = (TypeFunction *)fd->type; + if (Parameter::dim(fdtype->parameters) && + (tp || tiargs->dim < td->parameters->dim)) + return TRUE; + /* If there is more than one function template which matches, we may + * need type inference (see Bugzilla 4430) + */ + if (td != tempdecl) + multipleMatches = TRUE; + } + //printf("false\n"); + return multipleMatches; +} void TemplateInstance::semantic2(Scope *sc) { int i; if (semanticRun >= 2) - return; + return; semanticRun = 2; #if LOG printf("+TemplateInstance::semantic2('%s')\n", toChars()); #endif if (!errors && members) { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; + sc = tempdecl->scope; + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; #if LOG printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); #endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); } #if LOG printf("-TemplateInstance::semantic2('%s')\n", toChars()); @@ -4303,30 +4845,101 @@ void TemplateInstance::semantic3(Scope *sc) #endif //if (toChars()[0] == 'D') *(char*)0=0; if (semanticRun >= 3) - return; + return; semanticRun = 3; if (!errors && members) { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic3(sc); - } - sc = sc->pop(); - sc->pop(); + sc = tempdecl->scope; + sc = sc->push(argsym); + sc = sc->push(this); + sc->tinst = this; + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc = sc->pop(); + sc->pop(); } } #if IN_DMD +/************************************** + * Given an error instantiating the TemplateInstance, + * give the nested TemplateInstance instantiations that got + * us here. Those are a list threaded into the nested scopes. + */ void TemplateInstance::printInstantiationTrace() { if (global.gag) - return; + return; + + const int max_shown = 6; + const char format[] = "%s: instantiated from here: %s\n"; + + // determine instantiation depth and number of recursive instantiations + int n_instantiations = 1; + int n_totalrecursions = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + ++n_instantiations; + // If two instantiations use the same declaration, they are recursive. + // (this works even if they are instantiated from different places in the + // same template). + // In principle, we could also check for multiple-template recursion, but it's + // probably not worthwhile. + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + ++n_totalrecursions; + } + + // show full trace only if it's short or verbose is on + if (n_instantiations <= max_shown || global.params.verbose) + { + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + fprintf(stdmsg, format, cur->loc.toChars(), cur->toChars()); + } + } + else if (n_instantiations - n_totalrecursions <= max_shown) + { + // By collapsing recursive instantiations into a single line, + // we can stay under the limit. + int recursionDepth=0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl + && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) + { + ++recursionDepth; + } + else + { + if (recursionDepth) + fprintf(stdmsg, "%s: %d recursive instantiations from here: %s\n", cur->loc.toChars(), recursionDepth+2, cur->toChars()); + else + fprintf(stdmsg,format, cur->loc.toChars(), cur->toChars()); + recursionDepth = 0; + } + } + } + else + { + // Even after collapsing the recursions, the depth is too deep. + // Just display the first few and last few instantiations. + size_t i = 0; + for (TemplateInstance *cur = this; cur; cur = cur->tinst) + { + if (i == max_shown / 2) + fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); + + if (i < max_shown / 2 || + i >= n_instantiations - max_shown + max_shown / 2) + fprintf(stdmsg, format, cur->loc.toChars(), cur->toChars()); + ++i; + } + } } void TemplateInstance::toObjFile(int multiobj) @@ -4336,17 +4949,17 @@ void TemplateInstance::toObjFile(int multiobj) #endif if (!errors && members) { - if (multiobj) - // Append to list of object files to be written later - obj_append(this); - else - { - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->toObjFile(multiobj); - } - } + if (multiobj) + // Append to list of object files to be written later + obj_append(this); + else + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->toObjFile(multiobj); + } + } } } @@ -4359,11 +4972,11 @@ void TemplateInstance::inlineScan() #endif if (!errors && members) { - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->inlineScan(); - } + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->inlineScan(); + } } } @@ -4375,19 +4988,19 @@ void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) buf->writestring(id->toChars()); buf->writestring("!("); if (nest) - buf->writestring("..."); + buf->writestring("..."); else { - nest++; - Objects *args = tiargs; - for (i = 0; i < args->dim; i++) - { - if (i) - buf->writeByte(','); - Object *oarg = (Object *)args->data[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - nest--; + nest++; + Objects *args = tiargs; + for (i = 0; i < args->dim; i++) + { + if (i) + buf->writeByte(','); + Object *oarg = (Object *)args->data[i]; + ObjectToCBuffer(buf, hgs, oarg); + } + nest--; } buf->writeByte(')'); } @@ -4399,16 +5012,17 @@ Dsymbol *TemplateInstance::toAlias() printf("TemplateInstance::toAlias()\n"); #endif if (!inst) - { error("cannot resolve forward reference"); - return this; + { error("cannot resolve forward reference"); + errors = 1; + return this; } if (inst != this) - return inst->toAlias(); + return inst->toAlias(); if (aliasdecl) { - return aliasdecl->toAlias(); + return aliasdecl->toAlias(); } return inst; @@ -4486,8 +5100,8 @@ void TemplateInstance::printInstantiationTrace() /* ======================== TemplateMixin ================================ */ TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Array *idents, Objects *tiargs) - : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) + Array *idents, Objects *tiargs) + : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) { //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); this->ident = ident; @@ -4502,7 +5116,7 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) Array *ids = new Array(); ids->setDim(idents->dim); for (int i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() + { // Matches TypeQualified::syntaxCopyHelper() Identifier *id = (Identifier *)idents->data[i]; if (id->dyncast() == DYNCAST_DSYMBOL) { @@ -4515,8 +5129,8 @@ Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) } tm = new TemplateMixin(loc, ident, - (Type *)(tqual ? tqual->syntaxCopy() : NULL), - ids, tiargs); + (Type *)(tqual ? tqual->syntaxCopy() : NULL), + ids, tiargs); TemplateInstance::syntaxCopy(tm); return tm; } @@ -4527,18 +5141,22 @@ void TemplateMixin::semantic(Scope *sc) printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); fflush(stdout); #endif - if (semanticRun && - // This for when a class/struct contains mixin members, and - // is done over because of forward references - (!parent || !toParent()->isAggregateDeclaration())) + if (semanticRun) { + // This for when a class/struct contains mixin members, and + // is done over because of forward references + if (parent && toParent()->isAggregateDeclaration()) + semanticRun = 1; // do over + else + { #if LOG - printf("\tsemantic done\n"); + printf("\tsemantic done\n"); #endif - return; + return; + } } if (!semanticRun) - semanticRun = 1; + semanticRun = 1; #if LOG printf("\tdo semantic\n"); #endif @@ -4550,104 +5168,106 @@ void TemplateMixin::semantic(Scope *sc) Scope *scx = NULL; if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; + { sc = scope; + scx = scope; // save so we don't make redundant copies + scope = NULL; } // Follow qualifications to find the TemplateDeclaration if (!tempdecl) - { Dsymbol *s; - int i; - Identifier *id; + { Dsymbol *s; + int i; + Identifier *id; - if (tqual) - { s = tqual->toDsymbol(sc); - i = 0; - } - else - { - i = 1; - id = (Identifier *)idents->data[0]; - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - s = sc->search(loc, id, NULL); - break; + if (tqual) + { s = tqual->toDsymbol(sc); + i = 0; + } + else + { + i = 1; + id = (Identifier *)idents->data[0]; + switch (id->dyncast()) + { + case DYNCAST_IDENTIFIER: + s = sc->search(loc, id, NULL); + break; - case DYNCAST_DSYMBOL: - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->semantic(sc); - s = ti; - break; - } - default: - assert(0); - } - } + case DYNCAST_DSYMBOL: + { + TemplateInstance *ti = (TemplateInstance *)id; + ti->semantic(sc); + s = ti; + break; + } + default: + assert(0); + } + } - for (; i < idents->dim; i++) - { - if (!s) - break; - id = (Identifier *)idents->data[i]; - s = s->searchX(loc, sc, id); - } - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } + for (; i < idents->dim; i++) + { + if (!s) + break; + id = (Identifier *)idents->data[i]; + s = s->searchX(loc, sc, id); + } + if (!s) + { + error("is not defined"); + inst = this; + return; + } + tempdecl = s->toAlias()->isTemplateDeclaration(); + if (!tempdecl) + { + error("%s isn't a template", s->toChars()); + inst = this; + return; + } } // Look for forward reference assert(tempdecl); for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) { - if (!td->semanticRun) - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = 0; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = 2; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } + if (!td->semanticRun) + { + /* Cannot handle forward references if mixin is a struct member, + * because addField must happen during struct's semantic, not + * during the mixin semantic. + * runDeferred will re-run mixin's semantic outside of the struct's + * semantic. + */ + semanticRun = 0; + AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); + if (ad) + ad->sizeok = 2; + else + { + // Forward reference + //printf("forward reference - deferring\n"); + scope = scx ? scx : new Scope(*sc); + scope->setNoFree(); + scope->module->addDeferredSemantic(this); + } + return; + } } // Run semantic on each argument, place results in tiargs[] semanticTiargs(sc); + if (errors) + return; tempdecl = findBestMatch(sc); if (!tempdecl) - { inst = this; - return; // error recovery + { inst = this; + return; // error recovery } if (!ident) - ident = genIdent(); + ident = genIdent(); inst = this; parent = sc->parent; @@ -4656,66 +5276,66 @@ void TemplateMixin::semantic(Scope *sc) */ for (Dsymbol *s = parent; s; s = s->parent) { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - continue; + //printf("\ts = '%s'\n", s->toChars()); + TemplateMixin *tm = s->isTemplateMixin(); + if (!tm || tempdecl != tm->tempdecl) + continue; - /* Different argument list lengths happen with variadic args - */ - if (tiargs->dim != tm->tiargs->dim) - continue; + /* Different argument list lengths happen with variadic args + */ + if (tiargs->dim != tm->tiargs->dim) + continue; - for (int i = 0; i < tiargs->dim; i++) - { Object *o = (Object *)tiargs->data[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = (Object *)tm->tiargs->data[i]; - if (ta) - { - Type *tmta = isType(tmo); - if (!tmta) - goto Lcontinue; - if (!ta->equals(tmta)) - goto Lcontinue; - } - else if (ea) - { Expression *tme = isExpression(tmo); - if (!tme || !ea->equals(tme)) - goto Lcontinue; - } - else if (sa) - { - Dsymbol *tmsa = isDsymbol(tmo); - if (sa != tmsa) - goto Lcontinue; - } - else - assert(0); - } - error("recursive mixin instantiation"); - return; + for (int i = 0; i < tiargs->dim; i++) + { Object *o = (Object *)tiargs->data[i]; + Type *ta = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Object *tmo = (Object *)tm->tiargs->data[i]; + if (ta) + { + Type *tmta = isType(tmo); + if (!tmta) + goto Lcontinue; + if (!ta->equals(tmta)) + goto Lcontinue; + } + else if (ea) + { Expression *tme = isExpression(tmo); + if (!tme || !ea->equals(tme)) + goto Lcontinue; + } + else if (sa) + { + Dsymbol *tmsa = isDsymbol(tmo); + if (sa != tmsa) + goto Lcontinue; + } + else + assert(0); + } + error("recursive mixin instantiation"); + return; Lcontinue: - continue; + continue; } // Copy the syntax trees from the TemplateDeclaration members = Dsymbol::arraySyntaxCopy(tempdecl->members); if (!members) - return; + return; symtab = new DsymbolTable(); for (Scope *sce = sc; 1; sce = sce->enclosing) { - ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; - if (sds) - { - sds->importScope(this, PROTpublic); - break; - } + ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; + if (sds) + { + sds->importScope(this, PROTpublic); + break; + } } #if LOG @@ -4738,11 +5358,11 @@ void TemplateMixin::semantic(Scope *sc) for (unsigned i = 0; i < members->dim; i++) { Dsymbol *s; - s = (Dsymbol *)members->data[i]; - s->addMember(argscope, this, i); - //sc->insert(s); - //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); - //printf("s->parent = %s\n", s->parent->toChars()); + s = (Dsymbol *)members->data[i]; + s->addMember(argscope, this, i); + //sc->insert(s); + //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); + //printf("s->parent = %s\n", s->parent->toChars()); } // Do semantic() analysis on template instance members @@ -4757,15 +5377,15 @@ void TemplateMixin::semantic(Scope *sc) //printf("%d\n", nest); if (++nest > 500) { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); } for (int i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc2); + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc2); } nest--; @@ -4778,17 +5398,17 @@ void TemplateMixin::semantic(Scope *sc) */ // if (sc->parent->isFuncDeclaration()) - semantic2(sc2); + semantic2(sc2); if (sc->func) { - semantic3(sc2); + semantic3(sc2); } // Give additional context info if error occurred during instantiation if (global.errors != errorsave) { - error("error instantiating"); + error("error instantiating"); } sc2->pop(); @@ -4797,7 +5417,7 @@ void TemplateMixin::semantic(Scope *sc) // if (!isAnonymous()) { - scy->pop(); + scy->pop(); } #if LOG printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); @@ -4808,26 +5428,26 @@ void TemplateMixin::semantic2(Scope *sc) { int i; if (semanticRun >= 2) - return; + return; semanticRun = 2; #if LOG printf("+TemplateMixin::semantic2('%s')\n", toChars()); #endif if (members) { - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; + assert(sc); + sc = sc->push(argsym); + sc = sc->push(this); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; #if LOG - printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); + printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); #endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); } #if LOG printf("-TemplateMixin::semantic2('%s')\n", toChars()); @@ -4838,22 +5458,22 @@ void TemplateMixin::semantic3(Scope *sc) { int i; if (semanticRun >= 3) - return; + return; semanticRun = 3; #if LOG printf("TemplateMixin::semantic3('%s')\n", toChars()); #endif if (members) { - sc = sc->push(argsym); - sc = sc->push(this); - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic3(sc); - } - sc = sc->pop(); - sc->pop(); + sc = sc->push(argsym); + sc = sc->push(this); + for (i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc = sc->pop(); + sc->pop(); } } @@ -4877,12 +5497,12 @@ int TemplateMixin::hasPointers() //printf("TemplateMixin::hasPointers() %s\n", toChars()); for (size_t i = 0; i < members->dim; i++) { - Dsymbol *s = (Dsymbol *)members->data[i]; - //printf(" s = %s %s\n", s->kind(), s->toChars()); - if (s->hasPointers()) - { - return 1; - } + Dsymbol *s = (Dsymbol *)members->data[i]; + //printf(" s = %s %s\n", s->kind(), s->toChars()); + if (s->hasPointers()) + { + return 1; + } } return 0; } @@ -4906,9 +5526,9 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (int i = 0; i < idents->dim; i++) { Identifier *id = (Identifier *)idents->data[i]; - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); + if (i) + buf->writeByte('.'); + buf->writestring(id->toChars()); } buf->writestring("!("); if (tiargs) @@ -4916,34 +5536,34 @@ void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) for (int i = 0; i < tiargs->dim; i++) { if (i) buf->writebyte(','); - Object *oarg = (Object *)tiargs->data[i]; - Type *t = isType(oarg); - Expression *e = isExpression(oarg); - Dsymbol *s = isDsymbol(oarg); - if (t) - t->toCBuffer(buf, NULL, hgs); - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - char *p = s->ident ? s->ident->toChars() : s->toChars(); - buf->writestring(p); - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { - assert(0); - } + Object *oarg = (Object *)tiargs->data[i]; + Type *t = isType(oarg); + Expression *e = isExpression(oarg); + Dsymbol *s = isDsymbol(oarg); + if (t) + t->toCBuffer(buf, NULL, hgs); + else if (e) + e->toCBuffer(buf, hgs); + else if (s) + { + char *p = s->ident ? s->ident->toChars() : s->toChars(); + buf->writestring(p); + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { + assert(0); + } } } buf->writebyte(')'); if (ident) { - buf->writebyte(' '); - buf->writestring(ident->toChars()); + buf->writebyte(' '); + buf->writestring(ident->toChars()); } buf->writebyte(';'); buf->writenl(); diff --git a/dmd2/template.h b/dmd2/template.h index b1a4aa77..1178d69f 100644 --- a/dmd2/template.h +++ b/dmd2/template.h @@ -1,380 +1,394 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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. - -#ifndef DMD_TEMPLATE_H -#define DMD_TEMPLATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ -#if IN_LLVM -#include -#endif -#include "root.h" -#include "arraytypes.h" -#include "dsymbol.h" -#if IN_LLVM -#include "mtype.h" -#endif - -struct OutBuffer; -struct Identifier; -struct TemplateInstance; -struct TemplateParameter; -struct TemplateTypeParameter; -struct TemplateThisParameter; -struct TemplateValueParameter; -struct TemplateAliasParameter; -struct TemplateTupleParameter; -struct Type; -struct TypeTypeof; -struct Scope; -struct Expression; -struct AliasDeclaration; -struct FuncDeclaration; -struct HdrGenState; -enum MATCH; - -struct Tuple : Object -{ - Objects objects; - - int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() -}; - - -struct TemplateDeclaration : ScopeDsymbol -{ - TemplateParameters *parameters; // array of TemplateParameter's - - TemplateParameters *origParameters; // originals for Ddoc - Expression *constraint; - Array instances; // array of TemplateInstance's - - TemplateDeclaration *overnext; // next overloaded TemplateDeclaration - TemplateDeclaration *overroot; // first in overnext list - - int semanticRun; // 1 semantic() run - - Dsymbol *onemember; // if !=NULL then one member of this template - - int literal; // this template declaration is a literal - - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, - Expression *constraint, Array *decldefs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - - void emitComment(Scope *sc); -// void toDocBuffer(OutBuffer *buf); - - MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); - MATCH leastAsSpecialized(TemplateDeclaration *td2); - - MATCH deduceFunctionTemplateMatch(Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); - void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); - - TemplateDeclaration *isTemplateDeclaration() { return this; } - - TemplateTupleParameter *isVariadic(); - int isOverloadable(); - -#if IN_LLVM - // LDC - std::string intrinsicName; -#endif -}; - -struct TemplateParameter -{ - /* For type-parameter: - * template Foo(ident) // specType is set to NULL - * template Foo(ident : specType) - * For value-parameter: - * template Foo(valType ident) // specValue is set to NULL - * template Foo(valType ident : specValue) - * For alias-parameter: - * template Foo(alias ident) - * For this-parameter: - * template Foo(this ident) - */ - - Loc loc; - Identifier *ident; - - Declaration *sparam; - - TemplateParameter(Loc loc, Identifier *ident); - - virtual TemplateTypeParameter *isTemplateTypeParameter(); - virtual TemplateValueParameter *isTemplateValueParameter(); - virtual TemplateAliasParameter *isTemplateAliasParameter(); -#if DMDV2 - virtual TemplateThisParameter *isTemplateThisParameter(); -#endif - virtual TemplateTupleParameter *isTemplateTupleParameter(); - - virtual TemplateParameter *syntaxCopy() = 0; - virtual void declareParameter(Scope *sc) = 0; - virtual void semantic(Scope *) = 0; - virtual void print(Object *oarg, Object *oded) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual Object *specialization() = 0; - virtual Object *defaultArg(Loc loc, Scope *sc) = 0; - - /* If TemplateParameter's match as far as overloading goes. - */ - virtual int overloadMatch(TemplateParameter *) = 0; - - /* Match actual argument against parameter. - */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; - - /* Create dummy argument based on parameter. - */ - virtual void *dummyArg() = 0; -}; - -struct TemplateTypeParameter : TemplateParameter -{ - /* Syntax: - * ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateTypeParameter *isTemplateTypeParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -#if DMDV2 -struct TemplateThisParameter : TemplateTypeParameter -{ - /* Syntax: - * this ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateThisParameter *isTemplateThisParameter(); - TemplateParameter *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct TemplateValueParameter : TemplateParameter -{ - /* Syntax: - * valType ident : specValue = defaultValue - */ - - Type *valType; - Expression *specValue; - Expression *defaultValue; - - static Expression *edummy; - - TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); - - TemplateValueParameter *isTemplateValueParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateAliasParameter : TemplateParameter -{ - /* Syntax: - * specType ident : specAlias = defaultAlias - */ - - Type *specType; - Object *specAlias; - Object *defaultAlias; - - static Dsymbol *sdummy; - - TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, Object *specAlias, Object *defaultAlias); - - TemplateAliasParameter *isTemplateAliasParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateTupleParameter : TemplateParameter -{ - /* Syntax: - * ident ... - */ - - TemplateTupleParameter(Loc loc, Identifier *ident); - - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); - void *dummyArg(); -}; - -struct TemplateInstance : ScopeDsymbol -{ - /* Given: - * foo!(args) => - * name = foo - * tiargs = args - */ - Identifier *name; - //Array idents; - Objects *tiargs; // Array of Types/Expressions of template - // instance arguments [int*, char, 10*10] - - Objects tdtypes; // Array of Types/Expressions corresponding - // to TemplateDeclaration.parameters - // [int, char, 100] - - TemplateDeclaration *tempdecl; // referenced by foo.bar.abc - TemplateInstance *inst; // refer to existing instance - TemplateInstance *tinst; // enclosing template instance - ScopeDsymbol *argsym; // argument symbol table - AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its - // sole member - WithScopeSymbol *withsym; // if a member of a with statement - int semanticRun; // has semantic() been done? - int semantictiargsdone; // has semanticTiargs() been done? - int nest; // for recursion detection - int havetempdecl; // 1 if used second constructor - Dsymbol *isnested; // if referencing local symbols, this is the context - int errors; // 1 if compiled with errors -#ifdef IN_GCC - /* On some targets, it is necessary to know whether a symbol - will be emitted in the output or not before the symbol - is used. This can be different from getModule(). */ - Module * objFileModule; -#endif - - TemplateInstance(Loc loc, Identifier *temp_id); - TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); - static Objects *arraySyntaxCopy(Objects *objs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *toAlias(); // resolve real symbol - const char *kind(); - int oneMember(Dsymbol **ps); - char *toChars(); - char *mangle(); - void printInstantiationTrace(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - // Internal - static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); - void semanticTiargs(Scope *sc); - TemplateDeclaration *findTemplateDeclaration(Scope *sc); - TemplateDeclaration *findBestMatch(Scope *sc); - void declareParameters(Scope *sc); - int hasNestedArgs(Objects *tiargs); - Identifier *genIdent(); - - TemplateInstance *isTemplateInstance() { return this; } - AliasDeclaration *isAliasDeclaration(); - -#if IN_LLVM - // LDC - Module* tmodule; // module from outermost enclosing template instantiation - Module* emittedInModule; // which module this template instance has been emitted in - - void codegen(Ir*); -#endif -}; - -struct TemplateMixin : TemplateInstance -{ - Array *idents; - Type *tqual; - - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - const char *kind(); - int oneMember(Dsymbol **ps); - int hasPointers(); - char *toChars(); - char *mangle(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - TemplateMixin *isTemplateMixin() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -Expression *isExpression(Object *o); -Dsymbol *isDsymbol(Object *o); -Type *isType(Object *o); -Tuple *isTuple(Object *o); -Type *getType(Object *o); -Dsymbol *getDsymbol(Object *o); - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); - -#endif /* DMD_TEMPLATE_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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. + +#ifndef DMD_TEMPLATE_H +#define DMD_TEMPLATE_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ +#if IN_LLVM +#include +#endif +#include "root.h" +#include "arraytypes.h" +#include "dsymbol.h" +#if IN_LLVM +#include "mtype.h" +#endif + +struct OutBuffer; +struct Identifier; +struct TemplateInstance; +struct TemplateParameter; +struct TemplateTypeParameter; +struct TemplateThisParameter; +struct TemplateValueParameter; +struct TemplateAliasParameter; +struct TemplateTupleParameter; +struct Type; +struct TypeTypeof; +struct Scope; +struct Expression; +struct AliasDeclaration; +struct FuncDeclaration; +struct HdrGenState; +enum MATCH; + +struct Tuple : Object +{ + Objects objects; + + int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() +}; + + +struct TemplateDeclaration : ScopeDsymbol +{ + TemplateParameters *parameters; // array of TemplateParameter's + + TemplateParameters *origParameters; // originals for Ddoc + Expression *constraint; + Array instances; // array of TemplateInstance's + + TemplateDeclaration *overnext; // next overloaded TemplateDeclaration + TemplateDeclaration *overroot; // first in overnext list + + int semanticRun; // 1 semantic() run + + Dsymbol *onemember; // if !=NULL then one member of this template + + int literal; // this template declaration is a literal + int ismixin; // template declaration is only to be used as a mixin + + struct Previous + { Previous *prev; + Objects *dedargs; + }; + Previous *previous; // threaded list of previous instantiation attempts on stack + + TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, + Expression *constraint, Dsymbols *decldefs, int ismixin); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc); + int overloadInsert(Dsymbol *s); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); + char *toChars(); + + void emitComment(Scope *sc); + void toJsonBuffer(OutBuffer *buf); +// void toDocBuffer(OutBuffer *buf); + + MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, int flag); + MATCH leastAsSpecialized(TemplateDeclaration *td2); + + MATCH deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); + FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); + void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); + + TemplateDeclaration *isTemplateDeclaration() { return this; } + + TemplateTupleParameter *isVariadic(); + int isOverloadable(); + + void makeParamNamesVisibleInConstraint(Scope *paramscope); +#if IN_LLVM + // LDC + std::string intrinsicName; +#endif +}; + +struct TemplateParameter +{ + /* For type-parameter: + * template Foo(ident) // specType is set to NULL + * template Foo(ident : specType) + * For value-parameter: + * template Foo(valType ident) // specValue is set to NULL + * template Foo(valType ident : specValue) + * For alias-parameter: + * template Foo(alias ident) + * For this-parameter: + * template Foo(this ident) + */ + + Loc loc; + Identifier *ident; + + Declaration *sparam; + + TemplateParameter(Loc loc, Identifier *ident); + + virtual TemplateTypeParameter *isTemplateTypeParameter(); + virtual TemplateValueParameter *isTemplateValueParameter(); + virtual TemplateAliasParameter *isTemplateAliasParameter(); +#if DMDV2 + virtual TemplateThisParameter *isTemplateThisParameter(); +#endif + virtual TemplateTupleParameter *isTemplateTupleParameter(); + + virtual TemplateParameter *syntaxCopy() = 0; + virtual void declareParameter(Scope *sc) = 0; + virtual void semantic(Scope *) = 0; + virtual void print(Object *oarg, Object *oded) = 0; + virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; + virtual Object *specialization() = 0; + virtual Object *defaultArg(Loc loc, Scope *sc) = 0; + + /* If TemplateParameter's match as far as overloading goes. + */ + virtual int overloadMatch(TemplateParameter *) = 0; + + /* Match actual argument against parameter. + */ + virtual MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags = 0) = 0; + + /* Create dummy argument based on parameter. + */ + virtual void *dummyArg() = 0; +}; + +struct TemplateTypeParameter : TemplateParameter +{ + /* Syntax: + * ident : specType = defaultType + */ + Type *specType; // type parameter: if !=NULL, this is the type specialization + Type *defaultType; + + TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); + + TemplateTypeParameter *isTemplateTypeParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Loc loc, Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + void *dummyArg(); +}; + +#if DMDV2 +struct TemplateThisParameter : TemplateTypeParameter +{ + /* Syntax: + * this ident : specType = defaultType + */ + Type *specType; // type parameter: if !=NULL, this is the type specialization + Type *defaultType; + + TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); + + TemplateThisParameter *isTemplateThisParameter(); + TemplateParameter *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; +#endif + +struct TemplateValueParameter : TemplateParameter +{ + /* Syntax: + * valType ident : specValue = defaultValue + */ + + Type *valType; + Expression *specValue; + Expression *defaultValue; + + static Expression *edummy; + + TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); + + TemplateValueParameter *isTemplateValueParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Loc loc, Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + void *dummyArg(); +}; + +struct TemplateAliasParameter : TemplateParameter +{ + /* Syntax: + * specType ident : specAlias = defaultAlias + */ + + Type *specType; + Object *specAlias; + Object *defaultAlias; + + static Dsymbol *sdummy; + + TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, Object *specAlias, Object *defaultAlias); + + TemplateAliasParameter *isTemplateAliasParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Loc loc, Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + void *dummyArg(); +}; + +struct TemplateTupleParameter : TemplateParameter +{ + /* Syntax: + * ident ... + */ + + TemplateTupleParameter(Loc loc, Identifier *ident); + + TemplateTupleParameter *isTemplateTupleParameter(); + TemplateParameter *syntaxCopy(); + void declareParameter(Scope *sc); + void semantic(Scope *); + void print(Object *oarg, Object *oded); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Object *specialization(); + Object *defaultArg(Loc loc, Scope *sc); + int overloadMatch(TemplateParameter *); + MATCH matchArg(Scope *sc, Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam, int flags); + void *dummyArg(); +}; + +struct TemplateInstance : ScopeDsymbol +{ + /* Given: + * foo!(args) => + * name = foo + * tiargs = args + */ + Identifier *name; + //Array idents; + Objects *tiargs; // Array of Types/Expressions of template + // instance arguments [int*, char, 10*10] + + Objects tdtypes; // Array of Types/Expressions corresponding + // to TemplateDeclaration.parameters + // [int, char, 100] + + TemplateDeclaration *tempdecl; // referenced by foo.bar.abc + TemplateInstance *inst; // refer to existing instance + TemplateInstance *tinst; // enclosing template instance + ScopeDsymbol *argsym; // argument symbol table + AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its + // sole member + WithScopeSymbol *withsym; // if a member of a with statement + int semanticRun; // has semantic() been done? + int semantictiargsdone; // has semanticTiargs() been done? + int nest; // for recursion detection + int havetempdecl; // 1 if used second constructor + Dsymbol *isnested; // if referencing local symbols, this is the context + int errors; // 1 if compiled with errors +#ifdef IN_GCC + /* On some targets, it is necessary to know whether a symbol + will be emitted in the output or not before the symbol + is used. This can be different from getModule(). */ + Module * objFileModule; +#endif + + TemplateInstance(Loc loc, Identifier *temp_id); + TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); + static Objects *arraySyntaxCopy(Objects *objs); + Dsymbol *syntaxCopy(Dsymbol *); + void semantic(Scope *sc, Expressions *fargs); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Dsymbol *toAlias(); // resolve real symbol + const char *kind(); + int oneMember(Dsymbol **ps); + int needsTypeInference(Scope *sc); + char *toChars(); + char *mangle(); + void printInstantiationTrace(); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file +#endif + + // Internal + static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); + void semanticTiargs(Scope *sc); + TemplateDeclaration *findTemplateDeclaration(Scope *sc); + TemplateDeclaration *findBestMatch(Scope *sc); + void declareParameters(Scope *sc); + int hasNestedArgs(Objects *tiargs); + Identifier *genIdent(); + + TemplateInstance *isTemplateInstance() { return this; } + AliasDeclaration *isAliasDeclaration(); + +#if IN_LLVM + // LDC + Module* tmodule; // module from outermost enclosing template instantiation + Module* emittedInModule; // which module this template instance has been emitted in + + void codegen(Ir*); +#endif +}; + +struct TemplateMixin : TemplateInstance +{ + Array *idents; + Type *tqual; + + TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Array *idents, Objects *tiargs); + Dsymbol *syntaxCopy(Dsymbol *s); + void semantic(Scope *sc); + void semantic2(Scope *sc); + void semantic3(Scope *sc); + void inlineScan(); + const char *kind(); + int oneMember(Dsymbol **ps); + int hasPointers(); + char *toChars(); + char *mangle(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + +#if IN_DMD + void toObjFile(int multiobj); // compile to .obj file +#endif + + TemplateMixin *isTemplateMixin() { return this; } + +#if IN_LLVM + void codegen(Ir*); +#endif +}; + +Expression *isExpression(Object *o); +Dsymbol *isDsymbol(Object *o); +Type *isType(Object *o); +Tuple *isTuple(Object *o); +int arrayObjectIsError(Objects *args); +int isError(Object *o); +Type *getType(Object *o); +Dsymbol *getDsymbol(Object *o); + +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); +Object *objectSyntaxCopy(Object *o); + +#endif /* DMD_TEMPLATE_H */ diff --git a/dmd2/traits.c b/dmd2/traits.c index 7b27be18..f1777368 100644 --- a/dmd2/traits.c +++ b/dmd2/traits.c @@ -1,423 +1,479 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 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 -#include -#include -#include -#include - -#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" - -#define LOGSEMANTIC 0 - -#if DMDV2 - -/************************************************ - * 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 = 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 - */ - e = e->trySemantic(sc); - if (!e) - { if (global.gag) - global.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->getModule(), 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]; - Expression *e; - - unsigned errors = global.errors; - global.gag++; - - Type *t = isType(o); - if (t) - { Dsymbol *s; - 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", (int)dim); - goto Lfalse; - - -Lfalse: - return new IntegerExp(loc, 0, Type::tbool); - -Ltrue: - return new IntegerExp(loc, 1, Type::tbool); -} - - -#endif + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2010 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 +#include +#include +#include +#include + +#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" + +#define LOGSEMANTIC 0 + +#if DMDV2 + +/************************************************ + * Delegate to be passed to overloadApply() that looks + * for functions matching a trait. + */ + +struct Ptrait +{ + Expression *e1; + Expressions *exps; // collected results + Identifier *ident; // which trait we're looking for +}; + +static int fptraits(void *param, FuncDeclaration *f) +{ Ptrait *p = (Ptrait *)param; + + if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) + return 0; + + 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; + Declaration *d; + 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()) + } +#if DMDV2 + else if (ident == Id::isStaticFunction) + { + ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis()) + } + else if (ident == Id::isRef) + { + ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isRef()) + } + else if (ident == Id::isOut) + { + ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isOut()) + } + else if (ident == Id::isLazy) + { + ISDSYMBOL((d = s->isDeclaration()) != NULL && d->storage_class & STClazy) + } + else if (ident == Id::identifier) + { // Get identifier for symbol as a string literal + if (dim != 1) + goto Ldimerror; + Object *o = (Object *)args->data[0]; + Dsymbol *s = getDsymbol(o); + if (!s || !s->ident) + { + error("argument %s has no identifier", o->toChars()); + goto Lfalse; + } + StringExp *se = new StringExp(loc, s->ident->toChars()); + return se->semantic(sc); + } + +#endif + else if (ident == Id::hasMember || + ident == Id::getMember || + ident == Id::getOverloads || + 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 = 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 + */ + e = e->trySemantic(sc); + if (!e) + { if (global.gag) + global.errors++; + goto Lfalse; + } + else + goto Ltrue; + } + else if (ident == Id::getMember) + { + e = e->semantic(sc); + return e; + } + else if (ident == Id::getVirtualFunctions || + ident == Id::getOverloads) + { + 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 functions 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; + Ptrait p; + p.exps = exps; + p.e1 = e; + p.ident = ident; + overloadApply(f->getModule(), f, fptraits, &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; + } +#if DMDV1 + Expression *e = new ArrayLiteralExp(loc, exps); +#endif +#if DMDV2 + /* Making this a tuple is more flexible, as it can be statically unrolled. + * To make an array literal, enclose __traits in [ ]: + * [ __traits(allMembers, ...) ] + */ + Expression *e = new TupleExp(loc, exps); +#endif + 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]; + Expression *e; + + unsigned errors = global.errors; + global.gag++; + + Type *t = isType(o); + if (t) + { Dsymbol *s; + t->resolve(loc, sc, &e, &t, &s); + if (t) + t->semantic(loc, sc); + else if (e) + { e = e->semantic(sc); + e = e->optimize(WANTvalue); + } + } + else + { e = isExpression(o); + if (e) + { e = e->semantic(sc); + e = e->optimize(WANTvalue); + } + } + + global.gag--; + if (errors != global.errors) + { + 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); + + //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); +#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) + { + if (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", (int)dim); + goto Lfalse; + + +Lfalse: + return new IntegerExp(loc, 0, Type::tbool); + +Ltrue: + return new IntegerExp(loc, 1, Type::tbool); +} + + +#endif diff --git a/dmd2/unialpha.c b/dmd2/unialpha.c index 2f604f48..5c407180 100644 --- a/dmd2/unialpha.c +++ b/dmd2/unialpha.c @@ -1,323 +1,323 @@ - -// Copyright (c) 2003 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 - -/******************************* - * Return !=0 if unicode alpha. - * Use table from C99 Appendix D. - */ - -int isUniAlpha(unsigned u) -{ - static unsigned short table[][2] = - { - { 0x00AA, 0x00AA }, - { 0x00B5, 0x00B5 }, - { 0x00B7, 0x00B7 }, - { 0x00BA, 0x00BA }, - { 0x00C0, 0x00D6 }, - { 0x00D8, 0x00F6 }, - { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, - { 0x0250, 0x02A8 }, - { 0x02B0, 0x02B8 }, - { 0x02BB, 0x02BB }, - { 0x02BD, 0x02C1 }, - { 0x02D0, 0x02D1 }, - { 0x02E0, 0x02E4 }, - { 0x037A, 0x037A }, - { 0x0386, 0x0386 }, - { 0x0388, 0x038A }, - { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, - { 0x03A3, 0x03CE }, - { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, - { 0x03DC, 0x03DC }, - { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, - { 0x03E2, 0x03F3 }, - { 0x0401, 0x040C }, - { 0x040E, 0x044F }, - { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, - { 0x0490, 0x04C4 }, - { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, - { 0x04D0, 0x04EB }, - { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - { 0x0531, 0x0556 }, - { 0x0559, 0x0559 }, - { 0x0561, 0x0587 }, - { 0x05B0, 0x05B9 }, - { 0x05BB, 0x05BD }, - { 0x05BF, 0x05BF }, - { 0x05C1, 0x05C2 }, - { 0x05D0, 0x05EA }, - { 0x05F0, 0x05F2 }, - { 0x0621, 0x063A }, - { 0x0640, 0x0652 }, - { 0x0660, 0x0669 }, - { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, - { 0x06C0, 0x06CE }, - { 0x06D0, 0x06DC }, - { 0x06E5, 0x06E8 }, - { 0x06EA, 0x06ED }, - { 0x06F0, 0x06F9 }, - { 0x0901, 0x0903 }, - { 0x0905, 0x0939 }, - { 0x093D, 0x093D }, - { 0x093E, 0x094D }, - { 0x0950, 0x0952 }, - { 0x0958, 0x0963 }, - { 0x0966, 0x096F }, - { 0x0981, 0x0983 }, - { 0x0985, 0x098C }, - { 0x098F, 0x0990 }, - { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, - { 0x09B2, 0x09B2 }, - { 0x09B6, 0x09B9 }, - { 0x09BE, 0x09C4 }, - { 0x09C7, 0x09C8 }, - { 0x09CB, 0x09CD }, - { 0x09DC, 0x09DD }, - { 0x09DF, 0x09E3 }, - { 0x09E6, 0x09EF }, - { 0x09F0, 0x09F1 }, - { 0x0A02, 0x0A02 }, - { 0x0A05, 0x0A0A }, - { 0x0A0F, 0x0A10 }, - { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, - { 0x0A32, 0x0A33 }, - { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, - { 0x0A3E, 0x0A42 }, - { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, - { 0x0A59, 0x0A5C }, - { 0x0A5E, 0x0A5E }, - { 0x0A66, 0x0A6F }, - { 0x0A74, 0x0A74 }, - { 0x0A81, 0x0A83 }, - { 0x0A85, 0x0A8B }, - { 0x0A8D, 0x0A8D }, - { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, - { 0x0AAA, 0x0AB0 }, - { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, - { 0x0ABD, 0x0AC5 }, - { 0x0AC7, 0x0AC9 }, - { 0x0ACB, 0x0ACD }, - { 0x0AD0, 0x0AD0 }, - { 0x0AE0, 0x0AE0 }, - { 0x0AE6, 0x0AEF }, - { 0x0B01, 0x0B03 }, - { 0x0B05, 0x0B0C }, - { 0x0B0F, 0x0B10 }, - { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, - { 0x0B32, 0x0B33 }, - { 0x0B36, 0x0B39 }, - { 0x0B3D, 0x0B3D }, - { 0x0B3E, 0x0B43 }, - { 0x0B47, 0x0B48 }, - { 0x0B4B, 0x0B4D }, - { 0x0B5C, 0x0B5D }, - { 0x0B5F, 0x0B61 }, - { 0x0B66, 0x0B6F }, - { 0x0B82, 0x0B83 }, - { 0x0B85, 0x0B8A }, - { 0x0B8E, 0x0B90 }, - { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, - { 0x0B9C, 0x0B9C }, - { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, - { 0x0BA8, 0x0BAA }, - { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - { 0x0BBE, 0x0BC2 }, - { 0x0BC6, 0x0BC8 }, - { 0x0BCA, 0x0BCD }, - { 0x0BE7, 0x0BEF }, - { 0x0C01, 0x0C03 }, - { 0x0C05, 0x0C0C }, - { 0x0C0E, 0x0C10 }, - { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, - { 0x0C35, 0x0C39 }, - { 0x0C3E, 0x0C44 }, - { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, - { 0x0C60, 0x0C61 }, - { 0x0C66, 0x0C6F }, - { 0x0C82, 0x0C83 }, - { 0x0C85, 0x0C8C }, - { 0x0C8E, 0x0C90 }, - { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, - { 0x0CB5, 0x0CB9 }, - { 0x0CBE, 0x0CC4 }, - { 0x0CC6, 0x0CC8 }, - { 0x0CCA, 0x0CCD }, - { 0x0CDE, 0x0CDE }, - { 0x0CE0, 0x0CE1 }, - { 0x0CE6, 0x0CEF }, - { 0x0D02, 0x0D03 }, - { 0x0D05, 0x0D0C }, - { 0x0D0E, 0x0D10 }, - { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, - { 0x0D3E, 0x0D43 }, - { 0x0D46, 0x0D48 }, - { 0x0D4A, 0x0D4D }, - { 0x0D60, 0x0D61 }, - { 0x0D66, 0x0D6F }, - { 0x0E01, 0x0E3A }, - { 0x0E40, 0x0E5B }, -// { 0x0E50, 0x0E59 }, - { 0x0E81, 0x0E82 }, - { 0x0E84, 0x0E84 }, - { 0x0E87, 0x0E88 }, - { 0x0E8A, 0x0E8A }, - { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, - { 0x0E99, 0x0E9F }, - { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, - { 0x0EA7, 0x0EA7 }, - { 0x0EAA, 0x0EAB }, - { 0x0EAD, 0x0EAE }, - { 0x0EB0, 0x0EB9 }, - { 0x0EBB, 0x0EBD }, - { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - { 0x0EC8, 0x0ECD }, - { 0x0ED0, 0x0ED9 }, - { 0x0EDC, 0x0EDD }, - { 0x0F00, 0x0F00 }, - { 0x0F18, 0x0F19 }, - { 0x0F20, 0x0F33 }, - { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, - { 0x0F3E, 0x0F47 }, - { 0x0F49, 0x0F69 }, - { 0x0F71, 0x0F84 }, - { 0x0F86, 0x0F8B }, - { 0x0F90, 0x0F95 }, - { 0x0F97, 0x0F97 }, - { 0x0F99, 0x0FAD }, - { 0x0FB1, 0x0FB7 }, - { 0x0FB9, 0x0FB9 }, - { 0x10A0, 0x10C5 }, - { 0x10D0, 0x10F6 }, - { 0x1E00, 0x1E9B }, - { 0x1EA0, 0x1EF9 }, - { 0x1F00, 0x1F15 }, - { 0x1F18, 0x1F1D }, - { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, - { 0x1F50, 0x1F57 }, - { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, - { 0x1F5D, 0x1F5D }, - { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, - { 0x1FB6, 0x1FBC }, - { 0x1FBE, 0x1FBE }, - { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, - { 0x1FD0, 0x1FD3 }, - { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, - { 0x1FF2, 0x1FF4 }, - { 0x1FF6, 0x1FFC }, - { 0x203F, 0x2040 }, - { 0x207F, 0x207F }, - { 0x2102, 0x2102 }, - { 0x2107, 0x2107 }, - { 0x210A, 0x2113 }, - { 0x2115, 0x2115 }, - { 0x2118, 0x211D }, - { 0x2124, 0x2124 }, - { 0x2126, 0x2126 }, - { 0x2128, 0x2128 }, - { 0x212A, 0x2131 }, - { 0x2133, 0x2138 }, - { 0x2160, 0x2182 }, - { 0x3005, 0x3007 }, - { 0x3021, 0x3029 }, - { 0x3041, 0x3093 }, - { 0x309B, 0x309C }, - { 0x30A1, 0x30F6 }, - { 0x30FB, 0x30FC }, - { 0x3105, 0x312C }, - { 0x4E00, 0x9FA5 }, - { 0xAC00, 0xD7A3 }, - }; - -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - //printf("%x\n", table[i][0]); - assert(table[i][0] <= table[i][1]); - if (i < sizeof(table) / sizeof(table[0]) - 1) - assert(table[i][1] < table[i + 1][0]); - } -#endif - - if (u > 0xD7A3) - goto Lisnot; - - // Binary search - int mid; - int low; - int high; - - low = 0; - high = sizeof(table) / sizeof(table[0]) - 1; - while (low <= high) - { - mid = (low + high) >> 1; - if (u < table[mid][0]) - high = mid - 1; - else if (u > table[mid][1]) - low = mid + 1; - else - goto Lis; - } - -Lisnot: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - assert(u < table[i][0] || u > table[i][1]); - } -#endif - return 0; - -Lis: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (u >= table[i][0] && u <= table[i][1]) - return 1; - } - assert(0); // should have been in table -#endif - return 1; -} - + +// Copyright (c) 2003 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 + +/******************************* + * Return !=0 if unicode alpha. + * Use table from C99 Appendix D. + */ + +int isUniAlpha(unsigned u) +{ + static unsigned short table[][2] = + { + { 0x00AA, 0x00AA }, + { 0x00B5, 0x00B5 }, + { 0x00B7, 0x00B7 }, + { 0x00BA, 0x00BA }, + { 0x00C0, 0x00D6 }, + { 0x00D8, 0x00F6 }, + { 0x00F8, 0x01F5 }, + { 0x01FA, 0x0217 }, + { 0x0250, 0x02A8 }, + { 0x02B0, 0x02B8 }, + { 0x02BB, 0x02BB }, + { 0x02BD, 0x02C1 }, + { 0x02D0, 0x02D1 }, + { 0x02E0, 0x02E4 }, + { 0x037A, 0x037A }, + { 0x0386, 0x0386 }, + { 0x0388, 0x038A }, + { 0x038C, 0x038C }, + { 0x038E, 0x03A1 }, + { 0x03A3, 0x03CE }, + { 0x03D0, 0x03D6 }, + { 0x03DA, 0x03DA }, + { 0x03DC, 0x03DC }, + { 0x03DE, 0x03DE }, + { 0x03E0, 0x03E0 }, + { 0x03E2, 0x03F3 }, + { 0x0401, 0x040C }, + { 0x040E, 0x044F }, + { 0x0451, 0x045C }, + { 0x045E, 0x0481 }, + { 0x0490, 0x04C4 }, + { 0x04C7, 0x04C8 }, + { 0x04CB, 0x04CC }, + { 0x04D0, 0x04EB }, + { 0x04EE, 0x04F5 }, + { 0x04F8, 0x04F9 }, + { 0x0531, 0x0556 }, + { 0x0559, 0x0559 }, + { 0x0561, 0x0587 }, + { 0x05B0, 0x05B9 }, + { 0x05BB, 0x05BD }, + { 0x05BF, 0x05BF }, + { 0x05C1, 0x05C2 }, + { 0x05D0, 0x05EA }, + { 0x05F0, 0x05F2 }, + { 0x0621, 0x063A }, + { 0x0640, 0x0652 }, + { 0x0660, 0x0669 }, + { 0x0670, 0x06B7 }, + { 0x06BA, 0x06BE }, + { 0x06C0, 0x06CE }, + { 0x06D0, 0x06DC }, + { 0x06E5, 0x06E8 }, + { 0x06EA, 0x06ED }, + { 0x06F0, 0x06F9 }, + { 0x0901, 0x0903 }, + { 0x0905, 0x0939 }, + { 0x093D, 0x093D }, + { 0x093E, 0x094D }, + { 0x0950, 0x0952 }, + { 0x0958, 0x0963 }, + { 0x0966, 0x096F }, + { 0x0981, 0x0983 }, + { 0x0985, 0x098C }, + { 0x098F, 0x0990 }, + { 0x0993, 0x09A8 }, + { 0x09AA, 0x09B0 }, + { 0x09B2, 0x09B2 }, + { 0x09B6, 0x09B9 }, + { 0x09BE, 0x09C4 }, + { 0x09C7, 0x09C8 }, + { 0x09CB, 0x09CD }, + { 0x09DC, 0x09DD }, + { 0x09DF, 0x09E3 }, + { 0x09E6, 0x09EF }, + { 0x09F0, 0x09F1 }, + { 0x0A02, 0x0A02 }, + { 0x0A05, 0x0A0A }, + { 0x0A0F, 0x0A10 }, + { 0x0A13, 0x0A28 }, + { 0x0A2A, 0x0A30 }, + { 0x0A32, 0x0A33 }, + { 0x0A35, 0x0A36 }, + { 0x0A38, 0x0A39 }, + { 0x0A3E, 0x0A42 }, + { 0x0A47, 0x0A48 }, + { 0x0A4B, 0x0A4D }, + { 0x0A59, 0x0A5C }, + { 0x0A5E, 0x0A5E }, + { 0x0A66, 0x0A6F }, + { 0x0A74, 0x0A74 }, + { 0x0A81, 0x0A83 }, + { 0x0A85, 0x0A8B }, + { 0x0A8D, 0x0A8D }, + { 0x0A8F, 0x0A91 }, + { 0x0A93, 0x0AA8 }, + { 0x0AAA, 0x0AB0 }, + { 0x0AB2, 0x0AB3 }, + { 0x0AB5, 0x0AB9 }, + { 0x0ABD, 0x0AC5 }, + { 0x0AC7, 0x0AC9 }, + { 0x0ACB, 0x0ACD }, + { 0x0AD0, 0x0AD0 }, + { 0x0AE0, 0x0AE0 }, + { 0x0AE6, 0x0AEF }, + { 0x0B01, 0x0B03 }, + { 0x0B05, 0x0B0C }, + { 0x0B0F, 0x0B10 }, + { 0x0B13, 0x0B28 }, + { 0x0B2A, 0x0B30 }, + { 0x0B32, 0x0B33 }, + { 0x0B36, 0x0B39 }, + { 0x0B3D, 0x0B3D }, + { 0x0B3E, 0x0B43 }, + { 0x0B47, 0x0B48 }, + { 0x0B4B, 0x0B4D }, + { 0x0B5C, 0x0B5D }, + { 0x0B5F, 0x0B61 }, + { 0x0B66, 0x0B6F }, + { 0x0B82, 0x0B83 }, + { 0x0B85, 0x0B8A }, + { 0x0B8E, 0x0B90 }, + { 0x0B92, 0x0B95 }, + { 0x0B99, 0x0B9A }, + { 0x0B9C, 0x0B9C }, + { 0x0B9E, 0x0B9F }, + { 0x0BA3, 0x0BA4 }, + { 0x0BA8, 0x0BAA }, + { 0x0BAE, 0x0BB5 }, + { 0x0BB7, 0x0BB9 }, + { 0x0BBE, 0x0BC2 }, + { 0x0BC6, 0x0BC8 }, + { 0x0BCA, 0x0BCD }, + { 0x0BE7, 0x0BEF }, + { 0x0C01, 0x0C03 }, + { 0x0C05, 0x0C0C }, + { 0x0C0E, 0x0C10 }, + { 0x0C12, 0x0C28 }, + { 0x0C2A, 0x0C33 }, + { 0x0C35, 0x0C39 }, + { 0x0C3E, 0x0C44 }, + { 0x0C46, 0x0C48 }, + { 0x0C4A, 0x0C4D }, + { 0x0C60, 0x0C61 }, + { 0x0C66, 0x0C6F }, + { 0x0C82, 0x0C83 }, + { 0x0C85, 0x0C8C }, + { 0x0C8E, 0x0C90 }, + { 0x0C92, 0x0CA8 }, + { 0x0CAA, 0x0CB3 }, + { 0x0CB5, 0x0CB9 }, + { 0x0CBE, 0x0CC4 }, + { 0x0CC6, 0x0CC8 }, + { 0x0CCA, 0x0CCD }, + { 0x0CDE, 0x0CDE }, + { 0x0CE0, 0x0CE1 }, + { 0x0CE6, 0x0CEF }, + { 0x0D02, 0x0D03 }, + { 0x0D05, 0x0D0C }, + { 0x0D0E, 0x0D10 }, + { 0x0D12, 0x0D28 }, + { 0x0D2A, 0x0D39 }, + { 0x0D3E, 0x0D43 }, + { 0x0D46, 0x0D48 }, + { 0x0D4A, 0x0D4D }, + { 0x0D60, 0x0D61 }, + { 0x0D66, 0x0D6F }, + { 0x0E01, 0x0E3A }, + { 0x0E40, 0x0E5B }, +// { 0x0E50, 0x0E59 }, + { 0x0E81, 0x0E82 }, + { 0x0E84, 0x0E84 }, + { 0x0E87, 0x0E88 }, + { 0x0E8A, 0x0E8A }, + { 0x0E8D, 0x0E8D }, + { 0x0E94, 0x0E97 }, + { 0x0E99, 0x0E9F }, + { 0x0EA1, 0x0EA3 }, + { 0x0EA5, 0x0EA5 }, + { 0x0EA7, 0x0EA7 }, + { 0x0EAA, 0x0EAB }, + { 0x0EAD, 0x0EAE }, + { 0x0EB0, 0x0EB9 }, + { 0x0EBB, 0x0EBD }, + { 0x0EC0, 0x0EC4 }, + { 0x0EC6, 0x0EC6 }, + { 0x0EC8, 0x0ECD }, + { 0x0ED0, 0x0ED9 }, + { 0x0EDC, 0x0EDD }, + { 0x0F00, 0x0F00 }, + { 0x0F18, 0x0F19 }, + { 0x0F20, 0x0F33 }, + { 0x0F35, 0x0F35 }, + { 0x0F37, 0x0F37 }, + { 0x0F39, 0x0F39 }, + { 0x0F3E, 0x0F47 }, + { 0x0F49, 0x0F69 }, + { 0x0F71, 0x0F84 }, + { 0x0F86, 0x0F8B }, + { 0x0F90, 0x0F95 }, + { 0x0F97, 0x0F97 }, + { 0x0F99, 0x0FAD }, + { 0x0FB1, 0x0FB7 }, + { 0x0FB9, 0x0FB9 }, + { 0x10A0, 0x10C5 }, + { 0x10D0, 0x10F6 }, + { 0x1E00, 0x1E9B }, + { 0x1EA0, 0x1EF9 }, + { 0x1F00, 0x1F15 }, + { 0x1F18, 0x1F1D }, + { 0x1F20, 0x1F45 }, + { 0x1F48, 0x1F4D }, + { 0x1F50, 0x1F57 }, + { 0x1F59, 0x1F59 }, + { 0x1F5B, 0x1F5B }, + { 0x1F5D, 0x1F5D }, + { 0x1F5F, 0x1F7D }, + { 0x1F80, 0x1FB4 }, + { 0x1FB6, 0x1FBC }, + { 0x1FBE, 0x1FBE }, + { 0x1FC2, 0x1FC4 }, + { 0x1FC6, 0x1FCC }, + { 0x1FD0, 0x1FD3 }, + { 0x1FD6, 0x1FDB }, + { 0x1FE0, 0x1FEC }, + { 0x1FF2, 0x1FF4 }, + { 0x1FF6, 0x1FFC }, + { 0x203F, 0x2040 }, + { 0x207F, 0x207F }, + { 0x2102, 0x2102 }, + { 0x2107, 0x2107 }, + { 0x210A, 0x2113 }, + { 0x2115, 0x2115 }, + { 0x2118, 0x211D }, + { 0x2124, 0x2124 }, + { 0x2126, 0x2126 }, + { 0x2128, 0x2128 }, + { 0x212A, 0x2131 }, + { 0x2133, 0x2138 }, + { 0x2160, 0x2182 }, + { 0x3005, 0x3007 }, + { 0x3021, 0x3029 }, + { 0x3041, 0x3093 }, + { 0x309B, 0x309C }, + { 0x30A1, 0x30F6 }, + { 0x30FB, 0x30FC }, + { 0x3105, 0x312C }, + { 0x4E00, 0x9FA5 }, + { 0xAC00, 0xD7A3 }, + }; + +#ifdef DEBUG + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + //printf("%x\n", table[i][0]); + assert(table[i][0] <= table[i][1]); + if (i < sizeof(table) / sizeof(table[0]) - 1) + assert(table[i][1] < table[i + 1][0]); + } +#endif + + if (u > 0xD7A3) + goto Lisnot; + + // Binary search + int mid; + int low; + int high; + + low = 0; + high = sizeof(table) / sizeof(table[0]) - 1; + while (low <= high) + { + mid = (low + high) >> 1; + if (u < table[mid][0]) + high = mid - 1; + else if (u > table[mid][1]) + low = mid + 1; + else + goto Lis; + } + +Lisnot: +#ifdef DEBUG + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + assert(u < table[i][0] || u > table[i][1]); + } +#endif + return 0; + +Lis: +#ifdef DEBUG + for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) + { + if (u >= table[i][0] && u <= table[i][1]) + return 1; + } + assert(0); // should have been in table +#endif + return 1; +} + diff --git a/dmd2/unittests.c b/dmd2/unittests.c new file mode 100644 index 00000000..1b3c2770 --- /dev/null +++ b/dmd2/unittests.c @@ -0,0 +1,17 @@ + +#include + +#include "mars.h" + +void unittest_speller(); +void unittest_importHint(); +void unittest_aa(); + +void unittests() +{ +#if UNITTEST + unittest_speller(); + unittest_importHint(); + unittest_aa(); +#endif +} diff --git a/dmd2/utf.c b/dmd2/utf.c index ac517fef..53e234dc 100644 --- a/dmd2/utf.c +++ b/dmd2/utf.c @@ -1,5 +1,5 @@ // utf.c -// Copyright (c) 2003 by Digital Mars +// Copyright (c) 2003-2009 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -18,14 +18,48 @@ int utf_isValidDchar(dchar_t c) { return c < 0xD800 || - (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); + (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); +} + +static const unsigned char UTF8stride[256] = +{ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, +}; + +/** + * stride() returns the length of a UTF-8 sequence starting at index i + * in string s. + * Returns: + * The number of bytes in the UTF-8 sequence or + * 0xFF meaning s[i] is not the start of of UTF-8 sequence. + */ + +unsigned stride(unsigned char* s, size_t i) +{ + unsigned result = UTF8stride[s[i]]; + return result; } /******************************************** * Decode a single UTF-8 character sequence. * Returns: - * NULL success - * !=NULL error message string + * NULL success + * !=NULL error message string */ const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult) @@ -34,69 +68,71 @@ const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t * size_t i = *pidx; unsigned char u = s[i]; + //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); + assert(i >= 0 && i < len); if (u & 0x80) { unsigned n; - unsigned char u2; + unsigned char u2; - /* The following encodings are valid, except for the 5 and 6 byte - * combinations: - * 0xxxxxxx - * 110xxxxx 10xxxxxx - * 1110xxxx 10xxxxxx 10xxxxxx - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - for (n = 1; ; n++) - { - if (n > 4) - goto Lerr; // only do the first 4 of 6 encodings - if (((u << n) & 0x80) == 0) - { - if (n == 1) - goto Lerr; - break; - } - } + /* The following encodings are valid, except for the 5 and 6 byte + * combinations: + * 0xxxxxxx + * 110xxxxx 10xxxxxx + * 1110xxxx 10xxxxxx 10xxxxxx + * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx + */ + for (n = 1; ; n++) + { + if (n > 4) + goto Lerr; // only do the first 4 of 6 encodings + if (((u << n) & 0x80) == 0) + { + if (n == 1) + goto Lerr; + break; + } + } - // Pick off (7 - n) significant bits of B from first byte of octet - V = (dchar_t)(u & ((1 << (7 - n)) - 1)); + // Pick off (7 - n) significant bits of B from first byte of octet + V = (dchar_t)(u & ((1 << (7 - n)) - 1)); - if (i + (n - 1) >= len) - goto Lerr; // off end of string + if (i + (n - 1) >= len) + goto Lerr; // off end of string - /* The following combinations are overlong, and illegal: - * 1100000x (10xxxxxx) - * 11100000 100xxxxx (10xxxxxx) - * 11110000 1000xxxx (10xxxxxx 10xxxxxx) - * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) - * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) - */ - u2 = s[i + 1]; - if ((u & 0xFE) == 0xC0 || - (u == 0xE0 && (u2 & 0xE0) == 0x80) || - (u == 0xF0 && (u2 & 0xF0) == 0x80) || - (u == 0xF8 && (u2 & 0xF8) == 0x80) || - (u == 0xFC && (u2 & 0xFC) == 0x80)) - goto Lerr; // overlong combination + /* The following combinations are overlong, and illegal: + * 1100000x (10xxxxxx) + * 11100000 100xxxxx (10xxxxxx) + * 11110000 1000xxxx (10xxxxxx 10xxxxxx) + * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) + * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) + */ + u2 = s[i + 1]; + if ((u & 0xFE) == 0xC0 || + (u == 0xE0 && (u2 & 0xE0) == 0x80) || + (u == 0xF0 && (u2 & 0xF0) == 0x80) || + (u == 0xF8 && (u2 & 0xF8) == 0x80) || + (u == 0xFC && (u2 & 0xFC) == 0x80)) + goto Lerr; // overlong combination - for (unsigned j = 1; j != n; j++) - { - u = s[i + j]; - if ((u & 0xC0) != 0x80) - goto Lerr; // trailing bytes are 10xxxxxx - V = (V << 6) | (u & 0x3F); - } - if (!utf_isValidDchar(V)) - goto Lerr; - i += n; + for (unsigned j = 1; j != n; j++) + { + u = s[i + j]; + if ((u & 0xC0) != 0x80) + goto Lerr; // trailing bytes are 10xxxxxx + V = (V << 6) | (u & 0x3F); + } + if (!utf_isValidDchar(V)) + goto Lerr; + i += n; } else { - V = (dchar_t) u; - i++; + V = (dchar_t) u; + i++; } assert(utf_isValidDchar(V)); @@ -113,8 +149,8 @@ const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t * /*************************************************** * Validate a UTF-8 string. * Returns: - * NULL success - * !=NULL error message string + * NULL success + * !=NULL error message string */ const char *utf_validateString(unsigned char *s, size_t len) @@ -125,9 +161,9 @@ const char *utf_validateString(unsigned char *s, size_t len) for (idx = 0; idx < len; ) { - err = utf_decodeChar(s, len, &idx, &dc); - if (err) - break; + err = utf_decodeChar(s, len, &idx, &dc); + if (err) + break; } return err; } @@ -136,8 +172,8 @@ const char *utf_validateString(unsigned char *s, size_t len) /******************************************** * Decode a single UTF-16 character sequence. * Returns: - * NULL success - * !=NULL error message string + * NULL success + * !=NULL error message string */ @@ -150,34 +186,34 @@ const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t assert(i >= 0 && i < len); if (u & ~0x7F) { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; + { unsigned u2; - if (i + 1 == len) - { msg = "surrogate UTF-16 high value past end of string"; - goto Lerr; - } - u2 = s[i + 1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) - { msg = "surrogate UTF-16 low value out of range"; - goto Lerr; - } - u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); - i += 2; - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { msg = "unpaired surrogate UTF-16 value"; - goto Lerr; - } - else if (u == 0xFFFE || u == 0xFFFF) - { msg = "illegal UTF-16 value"; - goto Lerr; - } - else - i++; + if (i + 1 == len) + { msg = "surrogate UTF-16 high value past end of string"; + goto Lerr; + } + u2 = s[i + 1]; + if (u2 < 0xDC00 || u2 > 0xDFFF) + { msg = "surrogate UTF-16 low value out of range"; + goto Lerr; + } + u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); + i += 2; + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { msg = "unpaired surrogate UTF-16 value"; + goto Lerr; + } + else if (u == 0xFFFE || u == 0xFFFF) + { msg = "illegal UTF-16 value"; + goto Lerr; + } + else + i++; } else { - i++; + i++; } assert(utf_isValidDchar(u)); diff --git a/dmd2/version.c b/dmd2/version.c index c55c238b..c3a0e582 100644 --- a/dmd2/version.c +++ b/dmd2/version.c @@ -1,181 +1,181 @@ - -// Copyright (c) 1999-2005 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 -#include - -#include "root.h" - -#include "identifier.h" -#include "dsymbol.h" -#include "cond.h" -#include "version.h" -#include "module.h" - -/* ================================================== */ - -/* DebugSymbol's happen for statements like: - * debug = identifier; - * debug = integer; - */ - -DebugSymbol::DebugSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -DebugSymbol::DebugSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DebugSymbol *ds = new DebugSymbol(loc, ident); - ds->level = level; - return ds; -} - -int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("DebugSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->debugidsNot, ident)) - error("defined after use"); - if (!m->debugids) - m->debugids = new Array(); - m->debugids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->debuglevel = level; - } - return 0; -} - -void DebugSymbol::semantic(Scope *sc) -{ - //printf("DebugSymbol::semantic() %s\n", toChars()); -} - -void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("debug = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *DebugSymbol::kind() -{ - return "debug"; -} - -/* ================================================== */ - -/* VersionSymbol's happen for statements like: - * version = identifier; - * version = integer; - */ - -VersionSymbol::VersionSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -VersionSymbol::VersionSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - VersionSymbol *ds = new VersionSymbol(loc, ident); - ds->level = level; - return ds; -} - -int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - VersionCondition::checkPredefined(loc, ident->toChars()); - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->versionidsNot, ident)) - error("defined after use"); - if (!m->versionids) - m->versionids = new Array(); - m->versionids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->versionlevel = level; - } - return 0; -} - -void VersionSymbol::semantic(Scope *sc) -{ -} - -void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("version = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *VersionSymbol::kind() -{ - return "version"; -} - - + +// Copyright (c) 1999-2005 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 +#include + +#include "root.h" + +#include "identifier.h" +#include "dsymbol.h" +#include "cond.h" +#include "version.h" +#include "module.h" + +/* ================================================== */ + +/* DebugSymbol's happen for statements like: + * debug = identifier; + * debug = integer; + */ + +DebugSymbol::DebugSymbol(Loc loc, Identifier *ident) + : Dsymbol(ident) +{ + this->loc = loc; +} + +DebugSymbol::DebugSymbol(Loc loc, unsigned level) + : Dsymbol() +{ + this->level = level; + this->loc = loc; +} + +Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s) +{ + assert(!s); + DebugSymbol *ds = new DebugSymbol(loc, ident); + ds->level = level; + return ds; +} + +int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("DebugSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); + Module *m; + + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + m = sd->isModule(); + if (ident) + { + if (!m) + error("declaration must be at module level"); + else + { + if (findCondition(m->debugidsNot, ident)) + error("defined after use"); + if (!m->debugids) + m->debugids = new Array(); + m->debugids->push(ident->toChars()); + } + } + else + { + if (!m) + error("level declaration must be at module level"); + else + m->debuglevel = level; + } + return 0; +} + +void DebugSymbol::semantic(Scope *sc) +{ + //printf("DebugSymbol::semantic() %s\n", toChars()); +} + +void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("debug = "); + if (ident) + buf->writestring(ident->toChars()); + else + buf->printf("%u", level); + buf->writestring(";"); + buf->writenl(); +} + +const char *DebugSymbol::kind() +{ + return "debug"; +} + +/* ================================================== */ + +/* VersionSymbol's happen for statements like: + * version = identifier; + * version = integer; + */ + +VersionSymbol::VersionSymbol(Loc loc, Identifier *ident) + : Dsymbol(ident) +{ + this->loc = loc; +} + +VersionSymbol::VersionSymbol(Loc loc, unsigned level) + : Dsymbol() +{ + this->level = level; + this->loc = loc; +} + +Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s) +{ + assert(!s); + VersionSymbol *ds = new VersionSymbol(loc, ident); + ds->level = level; + return ds; +} + +int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) +{ + //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); + Module *m; + + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + m = sd->isModule(); + if (ident) + { + VersionCondition::checkPredefined(loc, ident->toChars()); + if (!m) + error("declaration must be at module level"); + else + { + if (findCondition(m->versionidsNot, ident)) + error("defined after use"); + if (!m->versionids) + m->versionids = new Array(); + m->versionids->push(ident->toChars()); + } + } + else + { + if (!m) + error("level declaration must be at module level"); + else + m->versionlevel = level; + } + return 0; +} + +void VersionSymbol::semantic(Scope *sc) +{ +} + +void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("version = "); + if (ident) + buf->writestring(ident->toChars()); + else + buf->printf("%u", level); + buf->writestring(";"); + buf->writenl(); +} + +const char *VersionSymbol::kind() +{ + return "version"; +} + + diff --git a/dmd2/version.h b/dmd2/version.h index 286accff..b5ae51d2 100644 --- a/dmd2/version.h +++ b/dmd2/version.h @@ -1,51 +1,51 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 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. - -#ifndef DMD_VERSION_H -#define DMD_VERSION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct OutBuffer; -struct HdrGenState; - -struct DebugSymbol : Dsymbol -{ - unsigned level; - - DebugSymbol(Loc loc, Identifier *ident); - DebugSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct VersionSymbol : Dsymbol -{ - unsigned level; - - VersionSymbol(Loc loc, Identifier *ident); - VersionSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -#endif /* DMD_VERSION_H */ + +// Compiler implementation of the D programming language +// Copyright (c) 1999-2006 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. + +#ifndef DMD_VERSION_H +#define DMD_VERSION_H + +#ifdef __DMC__ +#pragma once +#endif /* __DMC__ */ + +#include "dsymbol.h" + +struct OutBuffer; +struct HdrGenState; + +struct DebugSymbol : Dsymbol +{ + unsigned level; + + DebugSymbol(Loc loc, Identifier *ident); + DebugSymbol(Loc loc, unsigned level); + Dsymbol *syntaxCopy(Dsymbol *); + + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); +}; + +struct VersionSymbol : Dsymbol +{ + unsigned level; + + VersionSymbol(Loc loc, Identifier *ident); + VersionSymbol(Loc loc, unsigned level); + Dsymbol *syntaxCopy(Dsymbol *); + + int addMember(Scope *sc, ScopeDsymbol *s, int memnum); + void semantic(Scope *sc); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + const char *kind(); +}; + +#endif /* DMD_VERSION_H */ diff --git a/gen/functions.h b/gen/functions.h index e6785d56..bc569e9f 100644 --- a/gen/functions.h +++ b/gen/functions.h @@ -13,12 +13,6 @@ namespace llvm class Value; } -// TODO: hack for old d2 frontends -#if DMDV2 -typedef Argument Parameter; -typedef Arguments Parameters; -#endif - const llvm::FunctionType* DtoFunctionType(Type* t, Type* thistype, Type* nesttype, bool ismain = false); const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl); diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 94942d84..48bb2058 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -1520,7 +1520,7 @@ Type * stripModifiers( Type * type ) case MODshared: t = type->sto; break; - case MODinvariant: + case MODimmutable: t = type->ito; break; case MODshared | MODconst: @@ -1554,7 +1554,7 @@ Type * stripModifiers( Type * type ) t->cto = type; break; - case MODinvariant: + case MODimmutable: t->ito = type; break; diff --git a/gen/main.cpp b/gen/main.cpp index 9d9c3a5a..e40b2533 100644 --- a/gen/main.cpp +++ b/gen/main.cpp @@ -825,8 +825,6 @@ LDC_TARGETS fatal(); #endif -// TODO: hack for old d2 frontends -#if DMDV1 // load all unconditional imports for better symbol resolving for (int i = 0; i < modules.dim; i++) { @@ -837,7 +835,6 @@ LDC_TARGETS } if (global.errors) fatal(); -#endif // Do semantic analysis for (int i = 0; i < modules.dim; i++) diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 132a0d33..b3ebf638 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -13,12 +13,6 @@ #include "gen/logger.h" -// TODO: hack for old d2 frontends -#if DMDV2 -typedef Argument Parameter; -typedef Arguments Parameters; -#endif - ////////////////////////////////////////////////////////////////////////////////////////// TypeFunction* DtoTypeFunction(DValue* fnval) diff --git a/gen/typinf.cpp b/gen/typinf.cpp index ee39caf5..30847c6d 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -46,12 +46,6 @@ #include "ir/irvar.h" #include "ir/irtype.h" -// TODO: hack for old d2 frontends -#if DMDV2 -typedef Argument Parameter; -typedef Arguments Parameters; -#endif - /******************************************* * Get a canonicalized form of the TypeInfo for use with the internal * runtime library routines. Canonicalized in that static arrays are @@ -128,7 +122,7 @@ Expression *Type::getTypeInfo(Scope *sc) #if DMDV2 if (t->isConst()) t->vtinfo = new TypeInfoConstDeclaration(t); - else if (t->isInvariant()) + else if (t->isImmutable()) t->vtinfo = new TypeInfoInvariantDeclaration(t); else #endif diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index 656fa670..fcf88221 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -58,9 +58,9 @@ elseif(D_VERSION EQUAL 2) set(RUNTIME_DC druntime-rt-ldc) set(RUNTIME_AIO druntime-ldc) set(RUNTIME_DC_DIR ${RUNTIME_DIR}/src/compiler/ldc) - set(RUNTIME_GC_DIR ${RUNTIME_DIR}/src/gc/basic) - file(GLOB CORE_D ${RUNTIME_DIR}/src/common/core/*.d) - file(GLOB CORE_C ${RUNTIME_DIR}/src/common/core/stdc/*.c) + set(RUNTIME_GC_DIR ${RUNTIME_DIR}/src/gc) + file(GLOB CORE_D ${RUNTIME_DIR}/src/core/*.d ) + file(GLOB CORE_C ${RUNTIME_DIR}/src/core/stdc/*.c) endif(D_VERSION EQUAL 1) # should only be necessary if run independently from ldc cmake project