Mercurial > projects > ldc
changeset 336:aaade6ded589 trunk
[svn r357] Merged DMD 1.033
author | lindquist |
---|---|
date | Sat, 12 Jul 2008 19:38:31 +0200 |
parents | 17b844102023 |
children | d03d748a9b5f |
files | dmd/access.c dmd/aggregate.h dmd/attrib.c dmd/attrib.h dmd/cast.c dmd/class.c dmd/clone.c dmd/constfold.c dmd/declaration.c dmd/declaration.h dmd/doc.c dmd/dsymbol.c dmd/dsymbol.h dmd/enum.c dmd/enum.h dmd/expression.c dmd/expression.h dmd/func.c dmd/id.c dmd/id.h dmd/idgen.c dmd/import.c dmd/import.h dmd/init.c dmd/inline.c dmd/interpret.c dmd/lexer.c dmd/lexer.h dmd/mars.c dmd/mars.h dmd/module.c dmd/module.h dmd/mtype.c dmd/mtype.h dmd/optimize.c dmd/parse.c dmd/parse.h dmd/root.c dmd/root.h dmd/statement.c dmd/statement.h dmd/staticassert.c dmd/staticassert.h dmd/stringtable.c dmd/stringtable.h dmd/struct.c dmd/template.c dmd/template.h dmd/version.c dmd/version.h gen/asmstmt.cpp gen/classes.cpp gen/dvalue.cpp gen/functions.cpp gen/structs.cpp gen/toir.cpp gen/toobj.cpp gen/typinf.cpp premake.lua |
diffstat | 59 files changed, 18358 insertions(+), 16984 deletions(-) [+] |
line wrap: on
line diff
--- a/dmd/access.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/access.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,423 +1,424 @@ - -// 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 <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#include "root.h" -#include "mem.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()); - } -} - -/**************************************** - * 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->prot() == PROTprivate && d->getModule() != sc->module || - 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 <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "root.h" +#include "mem.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->prot() == PROTprivate && d->getModule() != sc->module || + 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); + } +}
--- a/dmd/aggregate.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/aggregate.h Sat Jul 12 19:38:31 2008 +0200 @@ -64,14 +64,15 @@ // 2: cannot determine size; fwd referenced int isdeprecated; // !=0 if deprecated Scope *scope; // !=NULL means context to use - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor // Special member functions InvariantDeclaration *inv; // invariant NewDeclaration *aggNew; // allocator DeleteDeclaration *aggDelete; // deallocator + FuncDeclarations dtors; // Array of destructors + FuncDeclaration *dtor; // aggregate destructor + #ifdef IN_GCC Array methods; // flat list of all methods for debug information #endif @@ -119,19 +120,26 @@ 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(); - char *kind(); + const char *kind(); Expression *cloneMembers(); void toDocBuffer(OutBuffer *buf); PROT getAccess(Dsymbol *smember); // determine access to smember - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file void toDt(dt_t **pdt); void toDebug(); // to symbolic debug info @@ -142,7 +150,7 @@ { UnionDeclaration(Loc loc, Identifier *id); Dsymbol *syntaxCopy(Dsymbol *s); - char *kind(); + const char *kind(); UnionDeclaration *isUnionDeclaration() { return this; } }; @@ -168,7 +176,7 @@ void copyBaseInterfaces(BaseClasses *); }; -#if V2 +#if DMDV2 #define CLASSINFO_SIZE (0x3C+16) // value of ClassInfo.size #else #define CLASSINFO_SIZE (0x3C+12) // value of ClassInfo.size @@ -218,7 +226,7 @@ virtual int isBaseOf(ClassDeclaration *cd, int *poffset); Dsymbol *search(Loc, Identifier *ident, int flags); -#if V2 +#if DMDV2 int isFuncHidden(FuncDeclaration *fd); #endif FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); @@ -226,12 +234,12 @@ int isNested(); int isCOMclass(); virtual int isCOMinterface(); -#if V2 +#if DMDV2 virtual int isCPPinterface(); #endif int isAbstract(); virtual int vtblOffset(); - char *kind(); + const char *kind(); char *mangle(); void toDocBuffer(OutBuffer *buf); @@ -240,7 +248,7 @@ void addLocalClass(ClassDeclarations *); // Back end - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file void toDebug(); unsigned baseVtblOffset(BaseClass *bc); Symbol *toSymbol(); @@ -258,7 +266,7 @@ struct InterfaceDeclaration : ClassDeclaration { -#if V2 +#if DMDV2 int cpp; // !=0 if this is a C++ interface #endif InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); @@ -266,14 +274,14 @@ void semantic(Scope *sc); int isBaseOf(ClassDeclaration *cd, int *poffset); int isBaseOf(BaseClass *bc, int *poffset); - char *kind(); + const char *kind(); int vtblOffset(); -#if V2 +#if DMDV2 int isCPPinterface(); #endif virtual int isCOMinterface(); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file Symbol *toSymbol(); InterfaceDeclaration *isInterfaceDeclaration() { return this; }
--- a/dmd/attrib.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/attrib.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -35,6 +35,7 @@ #include "../gen/logger.h" extern void obj_includelib(char *name); +void obj_startaddress(Symbol *s); /********************************* AttribDeclaration ****************************/ @@ -52,16 +53,13 @@ int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { - unsigned i; int m = 0; Array *d = include(sc, sd); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; m |= s->addMember(sc, sd, m | memnum); } } @@ -72,7 +70,7 @@ { Array *d = include(sc, NULL); - //printf("\tAttribDeclaration::semantic '%s'\n",toChars()); + //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) { for (unsigned i = 0; i < d->dim; i++) @@ -86,15 +84,12 @@ void AttribDeclaration::semantic2(Scope *sc) { - unsigned i; Array *d = include(sc, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; s->semantic2(sc); } } @@ -102,15 +97,12 @@ void AttribDeclaration::semantic3(Scope *sc) { - unsigned i; Array *d = include(sc, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; s->semantic3(sc); } } @@ -118,15 +110,12 @@ void AttribDeclaration::inlineScan() { - unsigned i; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); s->inlineScan(); } @@ -137,15 +126,12 @@ { if (comment) { - unsigned i; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; //printf("AttribDeclaration::addComment %s\n", s->toChars()); s->addComment(comment); } @@ -163,50 +149,41 @@ // if (sc->docbuf) // return; - unsigned i; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; //printf("AttribDeclaration::emitComment %s\n", s->toChars()); s->emitComment(sc); } } } -void AttribDeclaration::toObjFile() +void AttribDeclaration::toObjFile(int multiobj) { - unsigned i; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; - s->toObjFile(); + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; + s->toObjFile(multiobj); } } } int AttribDeclaration::cvMember(unsigned char *p) { - unsigned i; int nwritten = 0; int n; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; n = s->cvMember(p); if (p) p += n; @@ -232,7 +209,7 @@ return 0; } -char *AttribDeclaration::kind() +const char *AttribDeclaration::kind() { return "attribute"; } @@ -246,15 +223,12 @@ void AttribDeclaration::checkCtorConstInit() { - unsigned i; Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; s->checkCtorConstInit(); } } @@ -264,15 +238,13 @@ */ void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ unsigned i; +{ Array *d = include(NULL, NULL); if (d) { - for (i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)d->data[i]; + for (unsigned i = 0; i < d->dim; i++) + { Dsymbol *s = (Dsymbol *)d->data[i]; s->addLocalClass(aclasses); } } @@ -723,7 +695,7 @@ buf->writestring("}\n"); } -char *AnonDeclaration::kind() +const char *AnonDeclaration::kind() { return (char *)(isunion ? "anonymous union" : "anonymous struct"); } @@ -1023,12 +995,12 @@ return TRUE; } -char *PragmaDeclaration::kind() +const char *PragmaDeclaration::kind() { return "pragma"; } -void PragmaDeclaration::toObjFile() +void PragmaDeclaration::toObjFile(int multiobj) { if (ident == Id::lib) { @@ -1044,7 +1016,7 @@ name[se->len] = 0; obj_includelib(name); } - AttribDeclaration::toObjFile(); + AttribDeclaration::toObjFile(multiobj); } void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -1214,6 +1186,7 @@ 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: @@ -1240,7 +1213,7 @@ { Array *d = include(sc, sd); - //printf("\tStaticIfDeclaration::semantic '%s'\n",toChars()); + //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); if (d) { if (!addisdone) @@ -1257,7 +1230,7 @@ } } -char *StaticIfDeclaration::kind() +const char *StaticIfDeclaration::kind() { return "static if"; } @@ -1268,8 +1241,10 @@ CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) : AttribDeclaration(NULL) { + this->loc = loc; this->exp = exp; this->sd = NULL; + this->compiled = 0; } Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) @@ -1281,32 +1256,50 @@ int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) { + //printf("CompileDeclaration::addMember(sc = %p)\n", sc); 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()\n"); + 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"); - 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; + + if (!compiled) + { + compileIt(sc); + AttribDeclaration::addMember(sc, sd, 0); + compiled = 1; } - 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) - { - error("incomplete mixin declaration (%s)", se->toChars()); - } - - AttribDeclaration::addMember(sc, sd, 0); AttribDeclaration::semantic(sc); }
--- a/dmd/attrib.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/attrib.h Sat Jul 12 19:38:31 2008 +0200 @@ -42,7 +42,7 @@ void inlineScan(); void addComment(unsigned char *comment); void emitComment(Scope *sc); - char *kind(); + const char *kind(); int oneMember(Dsymbol **ps); int hasPointers(); void checkCtorConstInit(); @@ -50,7 +50,7 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); AttribDeclaration *isAttribDeclaration() { return this; } - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); }; @@ -106,7 +106,7 @@ Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); }; struct PragmaDeclaration : AttribDeclaration @@ -118,8 +118,8 @@ void semantic(Scope *sc); int oneMember(Dsymbol **ps); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); - void toObjFile(); // compile to .obj file + const char *kind(); + void toObjFile(int multiobj); // compile to .obj file }; struct ConditionalDeclaration : AttribDeclaration @@ -145,7 +145,7 @@ Dsymbol *syntaxCopy(Dsymbol *s); int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); - char *kind(); + const char *kind(); }; // Mixin declarations @@ -155,10 +155,12 @@ 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); };
--- a/dmd/cast.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/cast.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -1345,31 +1345,52 @@ goto Lt1; } else if (t1->ty == Tclass || t2->ty == Tclass) - { int i1; - int i2; - - i1 = e2->implicitConvTo(t1); - i2 = e1->implicitConvTo(t2); - - if (i1 && i2) + { + while (1) { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } + 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; + 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 = tc1->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 (i1) - { - goto Lt1; - } - else - goto Lincompatible; } else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) {
--- a/dmd/class.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/class.c Sat Jul 12 19:38:31 2008 +0200 @@ -147,7 +147,7 @@ Type::typeinfotypelist = this; } -#if V2 +#if DMDV2 if (id == Id::TypeInfo_Const) { if (Type::typeinfoconst) Type::typeinfoconst->error("%s", msg); @@ -261,7 +261,7 @@ #endif if (sc->stc & STCdeprecated) - { //printf("test1: %s is deprecated\n", toChars()); + { isdeprecated = 1; } @@ -302,6 +302,7 @@ else { tc = (TypeClass *)(tb); + if (tc->sym->isDeprecated()) { if (!isDeprecated()) @@ -565,7 +566,7 @@ scope->setNoFree(); scope->module->addDeferredSemantic(this); - //printf("\tsemantic('%s') failed\n", toChars()); + //printf("\tsemantic('%s') failed due to forward references\n", toChars()); return; } @@ -599,7 +600,7 @@ if (!ctor && baseClass && baseClass->ctor) { //printf("Creating default this(){} for class %s\n", toChars()); - ctor = new CtorDeclaration(0, 0, NULL, 0); + ctor = new CtorDeclaration(loc, 0, NULL, 0); ctor->fbody = new CompoundStatement(0, new Statements()); members->push(ctor); ctor->addMember(sc, this, 1); @@ -796,7 +797,7 @@ * Return 1 if function is hidden (not findable through search). */ -#if V2 +#if DMDV2 int isf(void *param, FuncDeclaration *fd) { //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); @@ -857,12 +858,11 @@ } void ClassDeclaration::interfaceSemantic(Scope *sc) -{ int i; - +{ vtblInterfaces = new BaseClasses(); vtblInterfaces->reserve(interfaces_dim); - for (i = 0; i < interfaces_dim; i++) + for (size_t i = 0; i < interfaces_dim; i++) { BaseClass *b = interfaces[i]; @@ -911,6 +911,7 @@ return FALSE; } + /**************************************** * Returns !=0 if there's an extra member which is the 'this' * pointer to the enclosing context (enclosing class or function) @@ -936,7 +937,7 @@ /**************************************** */ -char *ClassDeclaration::kind() +const char *ClassDeclaration::kind() { return "class"; } @@ -1234,7 +1235,7 @@ /******************************************* */ -char *InterfaceDeclaration::kind() +const char *InterfaceDeclaration::kind() { return "interface"; }
--- a/dmd/clone.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/clone.c Sat Jul 12 19:38:31 2008 +0200 @@ -28,7 +28,7 @@ * (can be NULL for members that don't need one) */ -#if V2 +#if DMDV2 Expression *StructDeclaration::cloneMembers() { Expression *e = NULL; @@ -89,7 +89,7 @@ //printf("StructDeclaration::buildDtor() %s\n", toChars()); Expression *e = NULL; -#if V2 +#if DMDV2 for (size_t i = 0; i < fields.dim; i++) { Dsymbol *s = (Dsymbol *)fields.data[i];
--- a/dmd/constfold.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/constfold.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,1506 +1,1512 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> -#include <math.h> - -#if __DMC__ -#include <complex.h> -#endif - -#include "mem.h" -#include "root.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.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 - -#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 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(0, 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); -#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); -#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(0, 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; - integer_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; - integer_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; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(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; - - assert(es1->sz == es2->sz); - 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 (isnan(r1) || 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 && e2->op == TOKnull) - { - cmp = 1; - } - 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; - integer_t n; - real_t r1; - real_t r2; - - 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 IN_GCC - if (real_isnan(&r1) || real_isnan(&r2)) // if unordered -#else - if (isnan(r1) || isnan(r2)) // if unordered -#endif - { - 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("e1->type = %s\n", e1->type->toChars()); - if (type->equals(e1->type) && to->equals(type)) - return e1; - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - Type *tb = to->toBasetype(); - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { integer_t result; - real_t r = e1->toReal(); - - switch (type->toBasetype()->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); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", 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 %llu is out of bounds %s[0 .. %llu]", 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 %llu 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 [%llu .. %llu] is out of bounds", ilwr, iupr); - else - { integer_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 [%llu .. %llu] 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; - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->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(); - integer_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; - - assert(sz == es2->sz); - 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; - integer_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; - integer_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 && - e1->type->equals(e2->type)) - { - // 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(e1->type->toBasetype()->next, new IntegerExp(0, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(0, 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(0, 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-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <math.h> + +#if __DMC__ +#include <complex.h> +#endif + +#include "mem.h" +#include "root.h" + +#include "mtype.h" +#include "expression.h" +#include "aggregate.h" +#include "declaration.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 + +#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 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(0, 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); +#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); +#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(0, 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; + integer_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; + integer_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; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() & e2->toInteger(), type); + return e; +} + +Expression *Or(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(loc, e1->toInteger() | e2->toInteger(), type); + return e; +} + +Expression *Xor(Type *type, Expression *e1, Expression *e2) +{ Expression *e; + Loc loc = e1->loc; + + e = new IntegerExp(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; + + assert(es1->sz == es2->sz); + 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 (isnan(r1) || 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 && e2->op == TOKnull) + { + cmp = 1; + } + 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; + integer_t n; + real_t r1; + real_t r2; + + 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 IN_GCC + if (real_isnan(&r1) || real_isnan(&r2)) // if unordered +#else + if (isnan(r1) || isnan(r2)) // if unordered +#endif + { + 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("e1->type = %s\n", e1->type->toChars()); + if (type->equals(e1->type) && to->equals(type)) + return e1; + + if (e1->isConst() != 1) + return EXP_CANT_INTERPRET; + + Type *tb = to->toBasetype(); + if (tb->ty == Tbool) + e = new IntegerExp(loc, e1->toInteger() != 0, type); + else if (type->isintegral()) + { + if (e1->type->isfloating()) + { integer_t result; + real_t r = e1->toReal(); + + switch (type->toBasetype()->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); + } + return e; +} + + +Expression *ArrayLength(Type *type, Expression *e1) +{ Expression *e; + Loc loc = e1->loc; + + if (e1->op == TOKstring) + { StringExp *es1 = (StringExp *)e1; + + e = new IntegerExp(loc, es1->len, type); + } + else if (e1->op == TOKarrayliteral) + { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; + size_t dim; + + dim = ale->elements ? ale->elements->dim : 0; + e = new IntegerExp(loc, dim, type); + } + else if (e1->op == TOKassocarrayliteral) + { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; + size_t dim = ale->keys->dim; + + e = new IntegerExp(loc, dim, type); + } + else + e = EXP_CANT_INTERPRET; + return e; +} + +/* Also return EXP_CANT_INTERPRET if this fails + */ +Expression *Index(Type *type, Expression *e1, Expression *e2) +{ Expression *e = EXP_CANT_INTERPRET; + Loc loc = e1->loc; + + //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); + assert(e1->type); + if (e1->op == TOKstring && e2->op == TOKint64) + { StringExp *es1 = (StringExp *)e1; + uinteger_t i = e2->toInteger(); + + if (i >= es1->len) + e1->error("string index %llu is out of bounds [0 .. %"PRIuSIZE"]", 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 %llu is out of bounds %s[0 .. %llu]", 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 %llu 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 [%llu .. %llu] is out of bounds", ilwr, iupr); + else + { integer_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 [%llu .. %llu] 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; + + //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->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(); + integer_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; + + assert(sz == es2->sz); + 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; + integer_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; + integer_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 && + e1->type->equals(e2->type)) + { + // 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(e1->type->toBasetype()->next, new IntegerExp(0, es1->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(0, 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(0, 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; +} +
--- a/dmd/declaration.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/declaration.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -39,7 +39,7 @@ { } -char *Declaration::kind() +const char *Declaration::kind() { return "declaration"; } @@ -80,6 +80,76 @@ 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) + { + char *p = NULL; + if (isConst()) + p = "const"; + else if (isInvariant()) + p = "invariant"; + else if (storage_class & STCmanifest) + p = "manifest constant"; + else if (!t->isAssignable()) + p = "struct with immutable members"; + if (p) + { error(loc, "cannot modify %s", p); + halt(); + } + } + } +} +#endif + + /********************************* TupleDeclaration ****************************/ TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) @@ -97,7 +167,7 @@ return NULL; } -char *TupleDeclaration::kind() +const char *TupleDeclaration::kind() { return "tuple"; } @@ -231,6 +301,7 @@ type = type->semantic(loc, sc); if (sc->parent->isFuncDeclaration() && init) semantic2(sc); + storage_class |= sc->stc & STCdeprecated; } else if (sem == 1) { @@ -257,7 +328,7 @@ } } -char *TypedefDeclaration::kind() +const char *TypedefDeclaration::kind() { return "typedef"; } @@ -318,6 +389,7 @@ Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) { + //printf("AliasDeclaration::syntaxCopy()\n"); assert(!s); AliasDeclaration *sa; if (type) @@ -466,7 +538,7 @@ } } -char *AliasDeclaration::kind() +const char *AliasDeclaration::kind() { return "alias"; } @@ -601,7 +673,9 @@ void VarDeclaration::semantic(Scope *sc) { //printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - //printf("type = %s\n", type->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(); @@ -629,6 +703,7 @@ originalType = type; type = type->semantic(loc, sc); } + //printf(" semantic type = %s\n", type ? type->toChars() : "null"); type->checkDeprecated(loc, sc); linkage = sc->linkage; @@ -636,7 +711,7 @@ //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\n", storage_class); + //printf("storage_class = x%x\n", storage_class); Dsymbol *parent = toParent(); FuncDeclaration *fd = parent->isFuncDeclaration(); @@ -749,6 +824,8 @@ error("field not allowed in interface"); } + /* Templates cannot add fields to aggregates + */ TemplateInstance *ti = parent->isTemplateInstance(); if (ti) { @@ -853,10 +930,6 @@ // possibilities. if (fd && !isStatic() && !isConst() && !init->isVoidInitializer()) { - Expression *e1; - Type *t; - int dim; - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); if (!ei) { @@ -874,15 +947,15 @@ init = ei; } - e1 = new VarExp(loc, this); + Expression *e1 = new VarExp(loc, this); - t = type->toBasetype(); + Type *t = type->toBasetype(); if (t->ty == Tsarray) { ei->exp = ei->exp->semantic(sc); if (!ei->exp->implicitConvTo(type)) { - dim = ((TypeSArray *)t)->dim->toInteger(); + int dim = ((TypeSArray *)t)->dim->toInteger(); // If multidimensional static array, treat as one large array while (1) { @@ -974,7 +1047,7 @@ ei = init->isExpInitializer(); else { - Expression *e = type->defaultInit(); + Expression *e = type->defaultInit(loc); if (e) ei = new ExpInitializer(loc, e); else @@ -1001,7 +1074,7 @@ } } -char *VarDeclaration::kind() +const char *VarDeclaration::kind() { return "variable"; } @@ -1020,6 +1093,17 @@ buf->writestring("const "); if (storage_class & STCstatic) buf->writestring("static "); + if (storage_class & STCauto) + buf->writestring("auto "); +#if DMDV2 + if (storage_class & STCmanifest) + buf->writestring("manifest "); + if (storage_class & STCinvariant) + buf->writestring("invariant "); + if (storage_class & STCtls) + buf->writestring("__thread "); +#endif + if (type) type->toCBuffer(buf, ident, hgs); else @@ -1052,15 +1136,18 @@ } /************************************ - * Check to see if variable is a reference to an enclosing function - * or not. + * 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) { + // The function that this variable is in FuncDeclaration *fdv = toParent()->isFuncDeclaration(); + // The current function FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); if (fdv && fdthis) @@ -1077,6 +1164,7 @@ /******************************* * Does symbol go into data segment? + * Includes extern variables. */ int VarDeclaration::isDataseg() @@ -1201,7 +1289,7 @@ /***************************** TypeInfoConstDeclaration **********************/ -#if V2 +#if DMDV2 TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) { @@ -1210,7 +1298,7 @@ /***************************** TypeInfoInvariantDeclaration **********************/ -#if V2 +#if DMDV2 TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) : TypeInfoDeclaration(tinfo, 0) {
--- a/dmd/declaration.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/declaration.h Sat Jul 12 19:38:31 2008 +0200 @@ -73,6 +73,7 @@ STCnothrow = 0x2000000, // never throws exceptions STCpure = 0x4000000, // pure function STCtls = 0x8000000, // thread local + STCalias = 0x10000000, // alias parameter }; struct Match @@ -101,7 +102,7 @@ Declaration(Identifier *id); void semantic(Scope *sc); - char *kind(); + const char *kind(); unsigned size(Loc loc); void checkModify(Loc loc, Scope *sc, Type *t); @@ -150,7 +151,7 @@ TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); Dsymbol *syntaxCopy(Dsymbol *); - char *kind(); + const char *kind(); Type *getType(); int needThis(); @@ -174,7 +175,7 @@ void semantic(Scope *sc); void semantic2(Scope *sc); char *mangle(); - char *kind(); + const char *kind(); Type *getType(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #ifdef _DH @@ -184,7 +185,7 @@ void toDocBuffer(OutBuffer *buf); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file void toDebug(); int cvMember(unsigned char *p); @@ -207,7 +208,7 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); int overloadInsert(Dsymbol *s); - char *kind(); + const char *kind(); Type *getType(); Dsymbol *toAlias(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); @@ -242,7 +243,7 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void semantic2(Scope *sc); - char *kind(); + const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); #ifdef _DH Type *htype; @@ -259,7 +260,7 @@ Dsymbol *toAlias(); Symbol *toSymbol(); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); // Eliminate need for dynamic_cast @@ -325,7 +326,7 @@ void emitComment(Scope *sc); Symbol *toSymbol(); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file virtual void toDt(dt_t **pdt); virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } @@ -467,6 +468,32 @@ void llvmDefine(); }; +#if DMDV2 +struct TypeInfoConstDeclaration : TypeInfoDeclaration +{ + TypeInfoConstDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; + +struct TypeInfoInvariantDeclaration : TypeInfoDeclaration +{ + TypeInfoInvariantDeclaration(Type *tinfo); + + void toDt(dt_t **pdt); + + // LLVMDC + void llvmDeclare(); + void llvmDefine(); +}; +#endif + +/**************************************************************/ + struct ThisDeclaration : VarDeclaration { ThisDeclaration(Type *t); @@ -481,8 +508,7 @@ }; /**************************************************************/ - -#if V2 +#if DMDV2 enum BUILTIN { @@ -548,7 +574,7 @@ VarDeclaration *nrvo_var; // variable to replace with shidden Symbol *shidden; // hidden pointer passed to function -#if V2 +#if DMDV2 enum BUILTIN builtin; // set if this is a known, builtin // function we can evaluate at compile // time @@ -597,7 +623,7 @@ void inlineScan(); int canInline(int hasthis, int hdrscan = 0); Expression *doInline(InlineScanState *iss, Expression *ethis, Array *arguments); - char *kind(); + const char *kind(); void toDocBuffer(OutBuffer *buf); static FuncDeclaration *genCfunc(Type *treturn, char *name); @@ -605,7 +631,7 @@ Symbol *toSymbol(); Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file int cvMember(unsigned char *p); FuncDeclaration *isFuncDeclaration() { return this; } @@ -627,7 +653,7 @@ FuncAliasDeclaration(FuncDeclaration *funcalias); FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - char *kind(); + const char *kind(); Symbol *toSymbol(); }; @@ -640,9 +666,10 @@ void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Dsymbol *syntaxCopy(Dsymbol *); int isNested(); + int isVirtual(); FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - char *kind(); + const char *kind(); }; struct CtorDeclaration : FuncDeclaration @@ -653,7 +680,7 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); char *toChars(); int isVirtual(); int addPreInvariant(); @@ -663,6 +690,24 @@ 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); @@ -696,7 +741,8 @@ }; struct StaticDtorDeclaration : FuncDeclaration -{ +{ VarDeclaration *vgate; // 'gate' variable + StaticDtorDeclaration(Loc loc, Loc endloc); Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); @@ -748,7 +794,7 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); int isVirtual(); int addPreInvariant(); int addPostInvariant(); @@ -764,7 +810,7 @@ Dsymbol *syntaxCopy(Dsymbol *); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); int isDelete(); int isVirtual(); int addPreInvariant();
--- a/dmd/doc.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/doc.c Sat Jul 12 19:38:31 2008 +0200 @@ -400,7 +400,7 @@ void ScopeDsymbol::emitMemberComments(Scope *sc) { - //printf("ScopeDsymbol::emitMemberComments()\n"); + //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); OutBuffer *buf = sc->docbuf; if (members) @@ -417,8 +417,9 @@ else if (isTemplateDeclaration()) m = "$(DDOC_TEMPLATE_MEMBERS \n"; - // BUG: if no members are actually printed, we should not emit DDOC_MEMBERS + 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++) { @@ -427,7 +428,14 @@ s->emitComment(sc); } sc->pop(); - buf->writestring(")\n"); + if (buf->offset == offset2) + { + /* Didn't write out any members, so back out last write + */ + buf->offset = offset1; + } + else + buf->writestring(")\n"); } } @@ -448,7 +456,9 @@ void Dsymbol::emitComment(Scope *sc) { } void InvariantDeclaration::emitComment(Scope *sc) { } -//void PostBlitDeclaration::emitComment(Scope *sc) { } +#if DMDV2 +void PostBlitDeclaration::emitComment(Scope *sc) { } +#endif void DtorDeclaration::emitComment(Scope *sc) { } void StaticCtorDeclaration::emitComment(Scope *sc) { } void StaticDtorDeclaration::emitComment(Scope *sc) { } @@ -525,12 +535,8 @@ //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); if (prot() == PROTprivate) return; - if (!comment) - return; - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; + unsigned char *com = comment; int hasmembers = 1; Dsymbol *ss = this; @@ -542,12 +548,22 @@ { ss = onemember->isFuncDeclaration(); if (ss) - hasmembers = 0; + { hasmembers = 0; + if (com != ss->comment) + com = Lexer::combineComments(com, ss->comment); + } else ss = this; } } + if (!com) + return; + + OutBuffer *buf = sc->docbuf; + DocComment *dc = DocComment::parse(sc, this, com); + unsigned o; + if (!dc) { ss->emitDitto(sc); @@ -667,7 +683,7 @@ buf->writestring("static "); if (d->isConst()) buf->writestring("const "); -#if V2 +#if DMDV2 if (d->isInvariant()) buf->writestring("invariant "); #endif @@ -743,7 +759,9 @@ if (parent && (td = parent->isTemplateDeclaration()) != NULL && td->onemember == this) - { HdrGenState hgs; + { /* It's a function template + */ + HdrGenState hgs; unsigned o = buf->offset; TypeFunction *tf = (TypeFunction *)type; @@ -1581,7 +1599,13 @@ */ if (f && f->type) { - TypeFunction *tf = (TypeFunction *)f->type; + TypeFunction *tf; + if (f->originalType) + { + tf = (TypeFunction *)f->originalType; + } + else + tf = (TypeFunction *)f->type; if (tf->parameters) {
--- a/dmd/dsymbol.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/dsymbol.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -201,7 +201,7 @@ return loc.toChars(); } -char *Dsymbol::kind() +const char *Dsymbol::kind() { return "symbol"; } @@ -244,6 +244,16 @@ return s; } +TemplateInstance *Dsymbol::inTemplateInstance() +{ + for (Dsymbol *parent = this->parent; parent; parent = parent->parent) + { + TemplateInstance *ti = parent->isTemplateInstance(); + if (ti) + return ti; + } + return NULL; +} int Dsymbol::isAnonymous() { @@ -270,6 +280,16 @@ // Most Dsymbols have no further semantic analysis needed } +/********************************************* + * 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 + * Returns: + * NULL if not found + */ + Dsymbol *Dsymbol::search(Loc loc, Identifier *ident, int flags) { //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); @@ -389,7 +409,9 @@ AggregateDeclaration *Dsymbol::isMember() // is this a member of an AggregateDeclaration? { + //printf("Dsymbol::isMember() %s\n", toChars()); Dsymbol *parent = toParent(); + //printf("parent is %s %s\n", parent->kind(), parent->toChars()); return parent ? parent->isAggregateDeclaration() : NULL; } @@ -502,6 +524,10 @@ { if (sc->scopesym && sc->scopesym->isDeprecated()) return; + + // If inside a StorageClassDeclaration that is deprecated + if (sc->stc & STCdeprecated) + return; } error(loc, "is deprecated"); @@ -617,12 +643,11 @@ } Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ Dsymbol *s; - int i; +{ + //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); // Look in symbols declared in this module - s = symtab ? symtab->lookup(ident) : NULL; + Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; if (s) { //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); @@ -630,7 +655,7 @@ else if (imports) { // Look in imported modules - for (i = 0; i < imports->dim; i++) + for (int i = 0; i < imports->dim; i++) { ScopeDsymbol *ss = (ScopeDsymbol *)imports->data[i]; Dsymbol *s2; @@ -639,6 +664,8 @@ 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; @@ -646,6 +673,10 @@ { 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; } @@ -768,7 +799,7 @@ return sprev; } -char *ScopeDsymbol::kind() +const char *ScopeDsymbol::kind() { return "ScopeDsymbol"; } @@ -780,7 +811,7 @@ * Returns NULL if not found */ -#if V2 +#if DMDV2 FuncDeclaration *ScopeDsymbol::findGetMembers() { Dsymbol *s = search_function(this, Id::getmembers);
--- a/dmd/dsymbol.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/dsymbol.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -123,12 +123,13 @@ Dsymbol *pastMixin(); Dsymbol *toParent(); Dsymbol *toParent2(); + TemplateInstance *inTemplateInstance(); int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() static Array *arraySyntaxCopy(Array *a); - virtual char *kind(); + virtual const char *kind(); virtual Dsymbol *toAlias(); // resolve real symbol virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); virtual void semantic(Scope *sc); @@ -150,7 +151,7 @@ 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 isImportedSymbol(); // is Dsymbol imported? virtual int isDeprecated(); // is Dsymbol deprecated? virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? @@ -172,7 +173,7 @@ // Backend virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(); // compile to .obj file + 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 @@ -247,7 +248,7 @@ void defineRef(Dsymbol *s); static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); Dsymbol *nameCollision(Dsymbol *s); - char *kind(); + const char *kind(); void emitMemberComments(Scope *sc);
--- a/dmd/enum.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/enum.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,5 +1,5 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -14,6 +14,7 @@ #include "enum.h" #include "mtype.h" #include "scope.h" +#include "declaration.h" /********************************* EnumDeclaration ****************************/ @@ -27,6 +28,7 @@ minval = 0; defaultval = 0; sinit = NULL; + isdeprecated = 0; } Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) @@ -57,6 +59,9 @@ return; if (!memtype) memtype = Type::tint32; + if (sc->stc & STCdeprecated) + isdeprecated = 1; + parent = sc->scopesym; memtype = memtype->semantic(loc, sc); @@ -265,11 +270,16 @@ return type; } -char *EnumDeclaration::kind() +const char *EnumDeclaration::kind() { return "enum"; } +int EnumDeclaration::isDeprecated() +{ + return isdeprecated; +} + /********************************* EnumMember ****************************/ EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value) @@ -306,7 +316,7 @@ } } -char *EnumMember::kind() +const char *EnumMember::kind() { return "enum member"; }
--- a/dmd/enum.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/enum.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -30,9 +30,19 @@ { Type *type; // the TypeEnum Type *memtype; // type of the members + +#if DMDV1 integer_t maxval; integer_t minval; integer_t defaultval; // default initializer +#else + Expression *maxval; + Expression *minval; + Expression *defaultval; // default initializer + + Scope *scope; // !=NULL means context to use +#endif + int isdeprecated; EnumDeclaration(Loc loc, Identifier *id, Type *memtype); Dsymbol *syntaxCopy(Dsymbol *s); @@ -40,14 +50,18 @@ int oneMember(Dsymbol **ps); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Type *getType(); - char *kind(); + 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; } - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file void toDebug(); int cvMember(unsigned char *p); @@ -63,7 +77,7 @@ EnumMember(Loc loc, Identifier *id, Expression *value); Dsymbol *syntaxCopy(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); void emitComment(Scope *sc); void toDocBuffer(OutBuffer *buf);
--- a/dmd/expression.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/expression.c Sat Jul 12 19:38:31 2008 +0200 @@ -111,6 +111,9 @@ precedence[TOKassert] = PREC_primary; precedence[TOKfunction] = PREC_primary; precedence[TOKvar] = PREC_primary; +#if DMDV2 + precedence[TOKdefault] = PREC_primary; +#endif // post precedence[TOKdotti] = PREC_primary; @@ -195,6 +198,89 @@ 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++; + 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. @@ -383,6 +469,32 @@ } } +/********************************************* + * 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, @@ -432,7 +544,15 @@ error(loc, "expected %"PRIuSIZE" arguments, not %"PRIuSIZE, nparams, nargs); break; } - arg = p->defaultArg->copy(); + 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++; } @@ -572,7 +692,7 @@ tb = arg->type->toBasetype(); if (tb->ty == Tsarray) { TypeSArray *ts = (TypeSArray *)tb; - Type *ta = tb->next->arrayOf(); + Type *ta = ts->next->arrayOf(); if (ts->size(arg->loc) == 0) { arg = new NullExp(arg->loc); arg->type = ta; @@ -580,7 +700,19 @@ 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); @@ -609,6 +741,7 @@ void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) { + //if (precedence[e->op] == 0) e->dump(0); if (precedence[e->op] < pr) { buf->writeByte('('); @@ -706,7 +839,7 @@ Expression *Expression::semantic(Scope *sc) { #if LOGSEMANTIC - printf("Expression::semantic()\n"); + printf("Expression::semantic() %s\n", toChars()); #endif if (type) type = type->semantic(loc, sc); @@ -747,6 +880,7 @@ dump(0); halt(); #endif + type = Type::tint32; } } @@ -939,7 +1073,7 @@ e = new NullExp(loc); else e = new AddrExp(loc, this); - e->type = tb->next->pointerTo(); + e->type = ts->next->pointerTo(); } return e; } @@ -970,7 +1104,7 @@ { Expression *e; e = new PtrExp(loc, this); - e->type = type->next; + e->type = ((TypeReference *)type)->next; return e; } return this; @@ -994,6 +1128,18 @@ return FALSE; } +/******************************** + * Can this expression throw an exception? + * Valid only after semantic() pass. + */ + +int Expression::canThrow() +{ + return TRUE; +} + + + Expressions *Expression::arraySyntaxCopy(Expressions *exps) { Expressions *a = NULL; @@ -1019,6 +1165,7 @@ //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; } @@ -1093,9 +1240,13 @@ } default: - print(); - type->print(); - assert(0); + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { type->print(); + assert(0); + } break; } break; @@ -1246,10 +1397,17 @@ goto L3; default: + /* This can happen if errors, such as + * the type is painted on like in fromConstInitializer(). + */ + if (!global.errors) + { #ifdef DEBUG - t->print(); + t->print(); #endif - assert(0); + assert(0); + } + break; } } else if (v & 0x8000000000000000LL) @@ -1993,7 +2151,8 @@ fd->nestedFrameRef = 1; } #endif - sc->callSuper |= CSXthis; + if (!sc->intypeof) + sc->callSuper |= CSXthis; return this; Lerr: @@ -2102,7 +2261,8 @@ } #endif - sc->callSuper |= CSXsuper; + if (!sc->intypeof) + sc->callSuper |= CSXsuper; return this; @@ -3396,6 +3556,7 @@ { #if LOGSEMANTIC printf("NewAnonClassExp::semantic() %s\n", toChars()); + //printf("thisexp = %p\n", thisexp); //printf("type: %s\n", type->toChars()); #endif @@ -3982,6 +4143,8 @@ #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; } @@ -4258,7 +4421,7 @@ buf->writestring(" == "); tspec->toCBuffer(buf, NULL, hgs); } -#if V2 +#if DMDV2 if (parameters) { // First parameter is already output, so start with second for (int i = 1; i < parameters->dim; i++) @@ -4830,6 +4993,16 @@ 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) { @@ -4973,55 +5146,19 @@ if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution { AggregateDeclaration *ad = var->toParent()->isAggregateDeclaration(); - L1: - Type *t = e1->type->toBasetype(); - - if (ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1 = e1->semantic(sc); - - // Skip over nested functions, and get the enclosing - // class type. - Dsymbol *s = tcd->toParent(); - while (s && s->isFuncDeclaration()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - e1 = new VarExp(loc, f->vthis); - } - s = s->toParent(); - } - if (s && s->isClassDeclaration()) - e1->type = s->isClassDeclaration()->type; - - e1 = e1->semantic(sc); - goto L1; - } -#ifdef DEBUG - printf("2: "); -#endif - error("this for %s needs to be type %s not type %s", - var->toChars(), ad->toChars(), t->toChars()); + e1 = getRightThis(loc, sc, ad, e1, var); + if (!sc->noaccesscheck) + accessCheck(loc, sc, e1, var); + + VarDeclaration *v = var->isVarDeclaration(); + if (v && v->isConst()) + { ExpInitializer *ei = v->getExpInitializer(); + if (ei) + { Expression *e = ei->exp->copy(); + e = e->semantic(sc); + return e; } } - accessCheck(loc, sc, e1, var); } } //printf("-DotVarExp::semantic('%s')\n", toChars()); @@ -5211,7 +5348,7 @@ return e; Lerr: - return new IntegerExp(0); + return new IntegerExp(loc, 0, Type::tint32); } void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) @@ -5239,44 +5376,9 @@ e1 = e1->semantic(sc); type = new TypeDelegate(func->type); type = type->semantic(loc, sc); -//----------------- - /* For func, we need to get the - * right 'this' pointer if func is in an outer class, but our - * existing 'this' pointer is in an inner class. - * This code is analogous to that used for variables - * in DotVarExp::semantic(). - */ AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - L10: - Type *t = e1->type; - if (func->needThis() && ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) && - !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1 = e1->semantic(sc); - goto L10; - } -#ifdef DEBUG - printf("3: "); -#endif - error("this for %s needs to be type %s not type %s", - func->toChars(), ad->toChars(), t->toChars()); - } - } -//----------------- + if (func->needThis()) + e1 = getRightThis(loc, sc, ad, e1, func); } return this; } @@ -5535,7 +5637,7 @@ DotTemplateExp *dte; AggregateDeclaration *ad; UnaExp *ue = (UnaExp *)(e1); - + if (e1->op == TOKdotvar) { // Do overload resolution dve = (DotVarExp *)(e1); @@ -5560,40 +5662,20 @@ } ad = td->toParent()->isAggregateDeclaration(); } - /* Now that we have the right function f, we need to get the - * right 'this' pointer if f is in an outer class, but our - * existing 'this' pointer is in an inner class. - * This code is analogous to that used for variables - * in DotVarExp::semantic(). + 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) */ - L10: - Type *t = ue->e1->type->toBasetype(); - if (f->needThis() && ad && - !(t->ty == Tpointer && t->next->ty == Tstruct && - ((TypeStruct *)t->next)->sym == ad) && - !(t->ty == Tstruct && ((TypeStruct *)t)->sym == ad) + if (sc->func && sc->func->isInvariantDeclaration() && + ue->e1->op == TOKthis && + f->addPostInvariant() ) { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - if (tcd && tcd->isNested()) - { // Try again with outer scope - - ue->e1 = new DotVarExp(loc, ue->e1, tcd->vthis); - ue->e1 = ue->e1->semantic(sc); - goto L10; - } -#ifdef DEBUG - printf("1: "); -#endif - error("this for %s needs to be type %s not type %s", - f->toChars(), ad->toChars(), t->toChars()); - } + error("cannot call public/export function %s from invariant", f->toChars()); } checkDeprecated(sc, f); @@ -5647,15 +5729,18 @@ } else { + if (!sc->intypeof) + { #if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); + 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; + 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 = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); @@ -5680,15 +5765,18 @@ } else { + if (!sc->intypeof) + { #if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); + 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; + 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 = cd->ctor; f = f->overloadResolve(loc, arguments);
--- a/dmd/expression.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/expression.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -140,6 +140,7 @@ 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);
--- a/dmd/func.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/func.c Sat Jul 12 19:38:31 2008 +0200 @@ -103,6 +103,7 @@ 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); @@ -208,6 +209,18 @@ 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; @@ -306,7 +319,7 @@ if (fdv->isFinal()) error("cannot override final function %s", fdv->toPrettyChars()); -#if V2 +#if DMDV2 if (!isOverride() && global.params.warnings) warning("%s: overrides base class function %s, but is not marked with 'override'", locToChars() fdv->toPrettyChars()); #endif @@ -322,7 +335,7 @@ #if !BREAKABI && !isDtorDeclaration() #endif -#if V2 +#if DMDV2 && !isPostBlitDeclaration() #endif ) @@ -978,7 +991,8 @@ f = (TypeFunction *)type; } - int offend = fbody ? fbody->fallOffEnd() : TRUE; + int offend = fbody ? fbody->blockExit() & BEfallthru : TRUE; + //int offend = fbody ? fbody->fallOffEnd() : TRUE; if (isStaticCtorDeclaration()) { /* It's a static constructor. Ensure that all @@ -1471,7 +1485,7 @@ return 1; } -#if V2 +#if DMDV2 /* Allow covariant matches, if it's just a const conversion * of the return type */ @@ -1777,6 +1791,7 @@ } return (LabelDsymbol *)s; } + /**************************************** * If non-static member function that has a 'this' pointer, * return the aggregate it is a member of. @@ -2031,17 +2046,18 @@ return fd; } -char *FuncDeclaration::kind() +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 V2 +#if DMDV2 int FuncDeclaration::needsClosure() { /* Need a closure for all the closureVars[] if any of the @@ -2051,7 +2067,11 @@ * 1) is a virtual function * 2) has its address taken * 3) has a parent that escapes - * 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()); @@ -2065,14 +2085,14 @@ assert(f != this); //printf("\t\tf = %s, %d, %d\n", f->toChars(), f->isVirtual(), f->tookAddressOf); - if (f->isVirtual() || 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 != this; s = s->parent) { f = s->isFuncDeclaration(); - if (f && (f->isVirtual() || f->tookAddressOf)) + if (f && (f->isThis() || f->tookAddressOf)) goto Lyes; } } @@ -2097,7 +2117,7 @@ this->funcalias = funcalias; } -char *FuncAliasDeclaration::kind() +const char *FuncAliasDeclaration::kind() { return "function alias"; } @@ -2142,7 +2162,12 @@ return (tok == TOKdelegate); } -char *FuncLiteralDeclaration::kind() +int FuncLiteralDeclaration::isVirtual() +{ + return FALSE; +} + +const char *FuncLiteralDeclaration::kind() { // GCC requires the (char*) casts return (tok == TOKdelegate) ? (char*)"delegate" : (char*)"function"; @@ -2214,6 +2239,8 @@ else tret = cd->type; //->referenceTo(); type = new TypeFunction(arguments, tret, varargs, LINKd); + if (!originalType) + originalType = type; sc->flags |= SCOPEctor; type = type->semantic(loc, sc); @@ -2240,7 +2267,7 @@ cd->defaultCtor = this; } -char *CtorDeclaration::kind() +const char *CtorDeclaration::kind() { return "constructor"; } @@ -2377,6 +2404,34 @@ 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 @@ -2432,6 +2487,7 @@ : FuncDeclaration(loc, endloc, Identifier::generateId("_staticDtor"), STCstatic, NULL) { + vgate = NULL; } Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) @@ -2455,6 +2511,36 @@ } 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(-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); + vgate = v; + } + FuncDeclaration::semantic(sc); // We're going to need ModuleInfo @@ -2583,12 +2669,7 @@ static Identifier *unitTestId() { - static int n; - char buffer[10 + sizeof(n)*3 + 1]; - - sprintf(buffer,"__unittest%d", n); - n++; - return Lexer::idPool(buffer); + return Lexer::uniqueId("__unittest"); } UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) @@ -2713,7 +2794,7 @@ FuncDeclaration::semantic(sc); } -char *NewDeclaration::kind() +const char *NewDeclaration::kind() { return "allocator"; } @@ -2797,7 +2878,7 @@ FuncDeclaration::semantic(sc); } -char *DeleteDeclaration::kind() +const char *DeleteDeclaration::kind() { return "deallocator"; }
--- a/dmd/id.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/id.c Sat Jul 12 19:38:31 2008 +0200 @@ -40,6 +40,8 @@ Identifier *Id::empty; Identifier *Id::p; Identifier *Id::coverage; +Identifier *Id::__vptr; +Identifier *Id::__monitor; Identifier *Id::TypeInfo; Identifier *Id::TypeInfo_Class; Identifier *Id::TypeInfo_Interface; @@ -213,6 +215,8 @@ empty = Lexer::idPool(""); p = Lexer::idPool("p"); coverage = Lexer::idPool("__coverage"); + __vptr = Lexer::idPool("__vptr"); + __monitor = Lexer::idPool("__monitor"); TypeInfo = Lexer::idPool("TypeInfo"); TypeInfo_Class = Lexer::idPool("TypeInfo_Class"); TypeInfo_Interface = Lexer::idPool("TypeInfo_Interface");
--- a/dmd/id.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/id.h Sat Jul 12 19:38:31 2008 +0200 @@ -42,6 +42,8 @@ static Identifier *empty; static Identifier *p; static Identifier *coverage; + static Identifier *__vptr; + static Identifier *__monitor; static Identifier *TypeInfo; static Identifier *TypeInfo_Class; static Identifier *TypeInfo_Interface;
--- a/dmd/idgen.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/idgen.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,302 +1,304 @@ - -// 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. - -// Program to generate string files in d data structures. -// Saves much tedious typing, and eliminates typo problems. -// Generates: -// id.h -// id.c - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <assert.h> - -struct Msgtable -{ - char *ident; // name to use in DMD source - char *name; // name in D executable -}; - -Msgtable msgtable[] = -{ - { "IUnknown" }, - { "Object" }, - { "object" }, - { "max" }, - { "min" }, - { "This", "this" }, - { "ctor", "_ctor" }, - { "dtor", "_dtor" }, - { "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" }, - { "withSym", "__withSym" }, - { "result", "__result" }, - { "returnLabel", "__returnLabel" }, - { "delegate" }, - { "line" }, - { "empty", "" }, - { "p" }, - { "coverage", "__coverage" }, - - { "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" }, - { "elements" }, - { "_arguments_typeinfo" }, - { "_arguments" }, - { "_argptr" }, - { "_match" }, - - { "LINE", "__LINE__" }, - { "FILE", "__FILE__" }, - { "DATE", "__DATE__" }, - { "TIME", "__TIME__" }, - { "TIMESTAMP", "__TIMESTAMP__" }, - { "VENDOR", "__VENDOR__" }, - { "VERSIONX", "__VERSION__" }, - - { "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" }, - - // 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" }, - - { "classNew", "new" }, - { "classDelete", "delete" }, - - // For foreach - { "apply", "opApply" }, - { "applyReverse", "opApplyReverse" }, - - { "adDup", "_adDupT" }, - { "adReverse", "_adReverse" }, - - // For internal functions - { "aaLen", "_aaLen" }, - { "aaKeys", "_aaKeys" }, - { "aaValues", "_aaValues" }, - { "aaRehash", "_aaRehash" }, - - // For pragma's - { "lib" }, - { "msg" }, - { "GNU_asm" }, - { "LLVM_intrinsic" }, - { "LLVM_internal" }, - - // For toHash/toString - { "tohash", "toHash" }, - { "tostring", "toString" }, - - // Special functions - { "alloca" }, - { "main" }, - { "WinMain" }, - { "DllMain" }, -}; - - -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++) - { 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++) - { char *id = msgtable[i].ident; - 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++) - { char *id = msgtable[i].ident; - 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-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. + +// Program to generate string files in d data structures. +// Saves much tedious typing, and eliminates typo problems. +// Generates: +// id.h +// id.c + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> +#include <assert.h> + +struct Msgtable +{ + char *ident; // name to use in DMD source + char *name; // name in D executable +}; + +Msgtable msgtable[] = +{ + { "IUnknown" }, + { "Object" }, + { "object" }, + { "max" }, + { "min" }, + { "This", "this" }, + { "ctor", "_ctor" }, + { "dtor", "_dtor" }, + { "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" }, + { "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" }, + { "elements" }, + { "_arguments_typeinfo" }, + { "_arguments" }, + { "_argptr" }, + { "_match" }, + + { "LINE", "__LINE__" }, + { "FILE", "__FILE__" }, + { "DATE", "__DATE__" }, + { "TIME", "__TIME__" }, + { "TIMESTAMP", "__TIMESTAMP__" }, + { "VENDOR", "__VENDOR__" }, + { "VERSIONX", "__VERSION__" }, + + { "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" }, + + // 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" }, + + { "classNew", "new" }, + { "classDelete", "delete" }, + + // For foreach + { "apply", "opApply" }, + { "applyReverse", "opApplyReverse" }, + + { "adDup", "_adDupT" }, + { "adReverse", "_adReverse" }, + + // For internal functions + { "aaLen", "_aaLen" }, + { "aaKeys", "_aaKeys" }, + { "aaValues", "_aaValues" }, + { "aaRehash", "_aaRehash" }, + + // For pragma's + { "lib" }, + { "msg" }, + { "GNU_asm" }, + { "LLVM_intrinsic" }, + { "LLVM_internal" }, + + // For toHash/toString + { "tohash", "toHash" }, + { "tostring", "toString" }, + + // Special functions + { "alloca" }, + { "main" }, + { "WinMain" }, + { "DllMain" }, +}; + + +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++) + { 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++) + { char *id = msgtable[i].ident; + 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++) + { char *id = msgtable[i].ident; + 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; +}
--- a/dmd/import.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/import.c Sat Jul 12 19:38:31 2008 +0200 @@ -55,7 +55,7 @@ aliases.push(alias); } -char *Import::kind() +const char *Import::kind() { return isstatic ? (char *)"static import" : (char *)"import"; }
--- a/dmd/import.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/import.h Sat Jul 12 19:38:31 2008 +0200 @@ -48,7 +48,7 @@ int isstatic); void addAlias(Identifier *name, Identifier *alias); - char *kind(); + const char *kind(); Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees void load(Scope *sc); void semantic(Scope *sc);
--- a/dmd/init.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/init.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,584 +1,586 @@ - -// 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 <stdio.h> -#include <assert.h> - -#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()); - 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->next); - value.data[i] = (void *)val; - length++; - if (length == 0) - error("array dimension overflow"); - if (length > dim) - dim = length; - } - unsigned long amax = 0x80000000; - if ((unsigned long) dim * t->next->size() >= amax) - error(loc, "array dimension %u exceeds max of %llu", dim, amax / t->next->size()); - return this; -} - -/******************************** - * If possible, convert array initializer to array literal. - */ - -Expression *ArrayInitializer::toExpression() -{ Expressions *elements; - Expression *e; - - //printf("ArrayInitializer::toExpression()\n"); - //static int i; if (++i == 2) halt(); - elements = new Expressions(); - for (size_t i = 0; i < value.dim; i++) - { - if (index.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 ArrayLiteralExp(loc, elements); - e->type = type; - return e; - -Lno: - delete elements; - error(loc, "array initializers as expressions are not allowed"); - return NULL; -} - - -/******************************** - * 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) -{ - for (size_t i = 0; i < value.dim; i++) - { - if (index.data[i]) - goto Lno; - } - if (value.dim) - { - Initializer *iz = (Initializer *)value.data[0]; - if (iz) - { Type *t = iz->inferType(sc); - t = new TypeSArray(t, new IntegerExp(value.dim)); - t = t->semantic(loc, sc); - return t; - } - } - -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); - 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->next->equals(exp->type->toBasetype()->next) && - exp->implicitConvTo(tb->next) - ) - { - t = tb->next; - } - - 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); - return exp->type; -} - -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-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 <stdio.h> +#include <assert.h> + +#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->next); + 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->next->size() >= amax) + error(loc, "array dimension %u exceeds max of %llu", dim, amax / t->next->size()); + return this; +} + +/******************************** + * If possible, convert array initializer to array literal. + */ + +Expression *ArrayInitializer::toExpression() +{ Expressions *elements; + Expression *e; + + //printf("ArrayInitializer::toExpression()\n"); + //static int i; if (++i == 2) halt(); + elements = new Expressions(); + for (size_t i = 0; i < value.dim; i++) + { + if (index.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 ArrayLiteralExp(loc, elements); + e->type = type; + return e; + +Lno: + delete elements; + error(loc, "array initializers as expressions are not allowed"); + return NULL; +} + + +/******************************** + * 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) +{ + for (size_t i = 0; i < value.dim; i++) + { + if (index.data[i]) + goto Lno; + } + if (value.dim) + { + Initializer *iz = (Initializer *)value.data[0]; + if (iz) + { Type *t = iz->inferType(sc); + t = new TypeSArray(t, new IntegerExp(value.dim)); + t = t->semantic(loc, sc); + return t; + } + } + +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); + 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->next->equals(exp->type->toBasetype()->next) && + exp->implicitConvTo(tb->next) + ) + { + t = tb->next; + } + + 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); + return exp->type; +} + +Expression *ExpInitializer::toExpression() +{ + return exp; +} + + +void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + exp->toCBuffer(buf, hgs); +} + + +
--- a/dmd/inline.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/inline.c Sat Jul 12 19:38:31 2008 +0200 @@ -860,7 +860,7 @@ } -#if V2 +#if DMDV2 Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) { lwr = lwr->inlineScan(iss); @@ -1290,7 +1290,7 @@ #endif isSynchronized() || isImportedSymbol() || -#if V2 +#if DMDV2 closureVars.dim || // no nested references to this frame #else nestedFrameRef || // no nested references to this frame
--- a/dmd/interpret.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/interpret.c Sat Jul 12 19:38:31 2008 +0200 @@ -729,7 +729,7 @@ return e; } -#if V2 +#if DMDV2 Expression *ForeachRangeStatement::interpret(InterState *istate) { #if LOG @@ -989,7 +989,7 @@ SymbolDeclaration *s = d->isSymbolDeclaration(); if (v) { -#if V2 +#if DMDV2 if ((v->isConst() || v->isInvariant()) && v->init && !v->value) #else if (v->isConst() && v->init) @@ -1045,7 +1045,7 @@ else if (v->init->isVoidInitializer()) e = NULL; } -#if V2 +#if DMDV2 else if (s == v && (v->isConst() || v->isInvariant()) && v->init) #else else if (s == v && v->isConst() && v->init) @@ -1855,7 +1855,7 @@ FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); if (fd) { -#if V2 +#if DMDV2 enum BUILTIN b = fd->isBuiltin(); if (b) { Expressions args;
--- a/dmd/lexer.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/lexer.c Sat Jul 12 19:38:31 2008 +0200 @@ -568,7 +568,7 @@ t->value = hexStringConstant(t); return; -#if V2 +#if DMDV2 case 'q': if (p[1] == '"') { @@ -627,7 +627,7 @@ 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 V2 +#if DMDV2 case 'p': /*case 'q': case 'r':*/ case 's': case 't': #else case 'p': case 'q': /*case 'r':*/ case 's': case 't': @@ -677,6 +677,7 @@ sprintf(timestamp, "%.24s", p); } +#if DMDV1 if (mod && id == Id::FILE) { t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); @@ -687,7 +688,9 @@ t->value = TOKint64v; t->uns64value = loc.linnum; } - else if (id == Id::DATE) + else +#endif + if (id == Id::DATE) { t->ustring = (unsigned char *)date; goto Lstring; @@ -730,7 +733,7 @@ t->value = TOKint64v; t->uns64value = major * 1000 + minor; } -#if V2 +#if DMDV2 else if (id == Id::EOFX) { t->value = TOKeof; @@ -1476,7 +1479,7 @@ } -#if V2 +#if DMDV2 /************************************** * Lex delimited strings: * q"(foo(xxx))" // "foo(xxx)" @@ -2917,11 +2920,14 @@ // Added after 1.0 { "ref", TOKref }, { "macro", TOKmacro }, -#if V2 +#if DMDV2 { "pure", TOKpure }, { "nothrow", TOKnothrow }, + { "__thread", TOKtls }, { "__traits", TOKtraits }, { "__overloadset", TOKoverloadset }, + { "__FILE__", TOKfile }, + { "__LINE__", TOKline }, #endif }; @@ -2974,7 +2980,7 @@ Token::tochars[TOKxorass] = "^="; Token::tochars[TOKassign] = "="; Token::tochars[TOKconstruct] = "="; -#if V2 +#if DMDV2 Token::tochars[TOKblit] = "="; #endif Token::tochars[TOKlt] = "<";
--- a/dmd/lexer.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/lexer.h Sat Jul 12 19:38:31 2008 +0200 @@ -150,10 +150,14 @@ // Added after 1.0 TOKref, TOKmacro, -#if V2 +#if DMDV2 TOKtraits, TOKoverloadset, TOKpure, + TOKnothrow, + TOKtls, + TOKline, + TOKfile, #endif TOKMAX @@ -273,7 +277,7 @@ unsigned escapeSequence(); TOK wysiwygStringConstant(Token *t, int tc); TOK hexStringConstant(Token *t); -#if V2 +#if DMDV2 TOK delimitedStringConstant(Token *t); TOK tokenStringConstant(Token *t); #endif
--- a/dmd/mars.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/mars.c Sat Jul 12 19:38:31 2008 +0200 @@ -1043,7 +1043,7 @@ if (global.params.verbose) printf("code %s\n", m->toChars()); if (global.params.obj) - m->genobjfile(); + m->genobjfile(0); if (global.errors) m->deleteObjFile(); else
--- a/dmd/mars.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/mars.h Sat Jul 12 19:38:31 2008 +0200 @@ -32,7 +32,7 @@ /* Changes for the GDC compiler by David Friedman */ #endif -#define V2 0 // Version 2.0 features +#define DMDV2 0 // Version 2.0 features #define BREAKABI 1 // 0 if not ready to break the ABI just yet struct Array; @@ -300,7 +300,7 @@ { MATCHnomatch, // no match MATCHconvert, // match with conversions -#if V2 +#if DMDV2 MATCHconst, // match with conversion to const #endif MATCHexact // exact match
--- a/dmd/module.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/module.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,983 +1,982 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <stdlib.h> -#include <assert.h> - -#if _MSC_VER || __MINGW32__ -#include <malloc.h> -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#include "mem.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 - -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; - FileName *cfilename; - FileName *hfilename; - FileName *objfilename; - FileName *llfilename; - FileName *bcfilename; - FileName *symfilename; - -// 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 - insearch = 0; - searchCacheIdent = NULL; - searchCacheSymbol = NULL; - searchCacheFlags = 0; - semanticstarted = 0; - semanticdone = 0; - decldefs = NULL; - vmoduleinfo = NULL; - massert = NULL; - marray = NULL; - sictor = NULL; - sctor = NULL; - sdtor = NULL; - stest = NULL; - sfilename = NULL; - root = 0; - importedFrom = NULL; - srcfile = NULL; - docfile = NULL; - - debuglevel = 0; - debugids = NULL; - debugidsNot = NULL; - versionlevel = 0; - versionids = NULL; - versionidsNot = NULL; - - macrotable = NULL; - escapetable = NULL; - cov = NULL; - covb = NULL; - - srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext)) - { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - isHtml = 1; - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } - } - - 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); - - llfilename = FileName::forceExt(argobj, global.ll_ext); - bcfilename = FileName::forceExt(argobj, global.bc_ext); - - symfilename = FileName::forceExt(filename, global.sym_ext); - - srcfile = new File(srcfilename); - - if (doDocComment) - { - setDocfile(); - } - - if (doHdrGen) - { - setHdrfile(); - } - - objfile = new File(objfilename); - bcfile = new File(bcfilename); - llfile = new File(llfilename); - symfile = new File(symfilename); -} - -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); -} - -void Module::deleteObjFile() -{ - if (global.params.obj) - objfile->remove(); - //if (global.params.llvmBC) - bcfile->remove(); - if (docfile) - docfile->remove(); -} - -Module::~Module() -{ -} - -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 (!docfile) - setDocfile(); - 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; - 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() -{ 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; - - s = (Dsymbol *)members->data[i]; - s->addMember(NULL, sc->scopesym, 1); - } - - // Pass 1 semantic routines: do public side of the definition - for (i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; - //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); - s->semantic(sc); - runDeferredSemantic(); - } - - sc = sc->pop(); - sc->pop(); - semanticdone = semanticstarted; - //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); -} - -void Module::semantic2() -{ 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(); - semanticdone = semanticstarted; - //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); -} - -void Module::semantic3() -{ 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(); - semanticdone = 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(); - } - semanticdone = semanticstarted; -} - -/**************************************************** - */ - -void Module::gensymfile() -{ - OutBuffer buf; - HdrGenState hgs; - int i; - - //printf("Module::gensymfile()\n"); - - buf.printf("// Sym file generated from '%s'", srcfile->toChars()); - buf.writenl(); - - for (i = 0; i < members->dim; i++) - { - Dsymbol *s; - - 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 || global.params.cov; -} - -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); -} - -/* =========================== ModuleDeclaration ===================== */ - -ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id) -{ - this->packages = packages; - this->id = id; -} - -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) -{ -} - - -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 (p->isModule()) - { p->error("module and package have the same name"); - fatal(); - break; - } - } - 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-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#if _MSC_VER || __MINGW32__ +#include <malloc.h> +#endif + +#if IN_GCC +#include "gdc_alloca.h" +#endif + +#include "mem.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 + +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; + FileName *cfilename; + FileName *hfilename; + FileName *objfilename; + FileName *llfilename; + FileName *bcfilename; + FileName *symfilename; + +// 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 + insearch = 0; + searchCacheIdent = NULL; + searchCacheSymbol = NULL; + searchCacheFlags = 0; + semanticstarted = 0; + semanticdone = 0; + decldefs = NULL; + vmoduleinfo = NULL; + massert = NULL; + marray = NULL; + sictor = NULL; + sctor = NULL; + sdtor = NULL; + stest = NULL; + sfilename = NULL; + root = 0; + importedFrom = NULL; + srcfile = NULL; + docfile = NULL; + + debuglevel = 0; + debugids = NULL; + debugidsNot = NULL; + versionlevel = 0; + versionids = NULL; + versionidsNot = NULL; + + macrotable = NULL; + escapetable = NULL; + doppelganger = 0; + cov = NULL; + covb = NULL; + + srcfilename = FileName::defaultExt(filename, global.mars_ext); + if (!srcfilename->equalsExt(global.mars_ext) && + !srcfilename->equalsExt("dd")) + { + if (srcfilename->equalsExt("html") || + srcfilename->equalsExt("htm") || + srcfilename->equalsExt("xhtml")) + isHtml = 1; + else + { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); + fatal(); + } + } + + 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); + + llfilename = FileName::forceExt(argobj, global.ll_ext); + bcfilename = FileName::forceExt(argobj, global.bc_ext); + + symfilename = FileName::forceExt(filename, global.sym_ext); + + srcfile = new File(srcfilename); + + if (doDocComment) + { + setDocfile(); + } + + if (doHdrGen) + { + setHdrfile(); + } + + objfile = new File(objfilename); + bcfile = new File(bcfilename); + llfile = new File(llfilename); + symfile = new File(symfilename); +} + +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); +} + +void Module::deleteObjFile() +{ + if (global.params.obj) + objfile->remove(); + //if (global.params.llvmBC) + bcfile->remove(); + if (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 (!docfile) + setDocfile(); + 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; + 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() +{ 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; + + s = (Dsymbol *)members->data[i]; + s->addMember(NULL, sc->scopesym, 1); + } + + // Pass 1 semantic routines: do public side of the definition + for (i = 0; i < members->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); + s->semantic(sc); + runDeferredSemantic(); + } + + sc = sc->pop(); + sc->pop(); + semanticdone = semanticstarted; + //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); +} + +void Module::semantic2() +{ 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(); + semanticdone = semanticstarted; + //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); +} + +void Module::semantic3() +{ 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(); + semanticdone = 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(); + } + semanticdone = semanticstarted; +} + +/**************************************************** + */ + +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 || global.params.cov; +} + +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); +} + +/* =========================== ModuleDeclaration ===================== */ + +ModuleDeclaration::ModuleDeclaration(Array *packages, Identifier *id) +{ + this->packages = packages; + this->id = id; +} + +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 (p->isModule()) + { p->error("module and package have the same name"); + fatal(); + break; + } + } + parent = p; + dst = ((Package *)p)->symtab; + if (ppkg && !*ppkg) + *ppkg = (Package *)p; + } + if (pparent) + { + *pparent = parent; + } + } + return dst; +}
--- a/dmd/module.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/module.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,185 +1,187 @@ - -// Compiler implementation of the D programming language -// 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. - -#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; - -// Back end -#if IN_LLVM -struct DValue; -typedef DValue elem; -#else -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#else -struct elem; -#endif -#endif - -struct Package : ScopeDsymbol -{ - Package(Identifier *ident); - 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 *bcfile; // output .bc file - File *llfile; // output .ll 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 insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - - int semanticstarted; // has semantic() been started? - int semanticdone; // 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 - - 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); - char *kind(); - void setDocfile(); // set docfile member - 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(); // semantic analysis - void semantic2(); // pass 2 semantic analysis - void semantic3(); // pass 3 semantic analysis - void inlineScan(); // scan for functions to inline - void setHdrfile(); // set hdrfile member -#ifdef _DH - void genhdrfile(); // generate D import file -#endif - void genobjfile(); - void gensymfile(); - void gendocfile(); - int needModuleInfo(); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void deleteObjFile(); - void addDeferredSemantic(Dsymbol *s); - void runDeferredSemantic(); - - // Back end - - 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(); - void genmoduleinfo(); - - // LLVMDC - Module *isModule() { return this; } -}; - - -struct ModuleDeclaration -{ - Identifier *id; - Array *packages; // array of Identifier's representing packages - - ModuleDeclaration(Array *packages, Identifier *id); - - 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 +struct DValue; +typedef DValue elem; +#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 *bcfile; // output .bc file + File *llfile; // output .ll 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 insearch; + Identifier *searchCacheIdent; + Dsymbol *searchCacheSymbol; // cached value of search + int searchCacheFlags; // cached flags + + int semanticstarted; // has semantic() been started? + int semanticdone; // 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 + + 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(); + void setDocfile(); // set docfile member + 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(); // semantic analysis + void semantic2(); // pass 2 semantic analysis + void semantic3(); // pass 3 semantic analysis + void inlineScan(); // scan for functions to inline + void setHdrfile(); // set hdrfile member +#ifdef _DH + void genhdrfile(); // generate D import file +#endif + void genobjfile(int multiobj); + void gensymfile(); + void gendocfile(); + int needModuleInfo(); + Dsymbol *search(Loc loc, Identifier *ident, int flags); + void deleteObjFile(); + void addDeferredSemantic(Dsymbol *s); + void runDeferredSemantic(); + + // Back end + + 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(); + void genmoduleinfo(); + + // LLVMDC + Module *isModule() { return this; } +}; + + +struct ModuleDeclaration +{ + Identifier *id; + Array *packages; // array of Identifier's representing packages + + ModuleDeclaration(Array *packages, Identifier *id); + + char *toChars(); +}; + +#endif /* DMD_MODULE_H */
--- a/dmd/mtype.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/mtype.c Sat Jul 12 19:38:31 2008 +0200 @@ -115,7 +115,7 @@ this->mod = 0; this->next = next; this->deco = NULL; -#if V2 +#if DMDV2 this->cto = NULL; this->ito = NULL; #endif @@ -2226,6 +2226,35 @@ return merge(); } +void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) +{ + //printf("TypeAArray::resolve() %s\n", toChars()); + + // 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; + + 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"); + } + Type::resolve(loc, sc, pe, pt, ps); +} + + Expression *TypeAArray::dotExp(Scope *sc, Expression *e, Identifier *ident) { #if LOGDOTEXP @@ -3151,6 +3180,7 @@ 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 (i = 0; i < idents.dim; i++) @@ -3548,7 +3578,7 @@ { Type *t; - t = semantic(0, sc); + t = semantic(loc, sc); if (t == this) return NULL; return t->toDsymbol(sc); @@ -3624,6 +3654,10 @@ 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) { @@ -4174,6 +4208,7 @@ { /* 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++) @@ -4182,7 +4217,10 @@ exps->push(fe); } e = new TupleExp(e->loc, exps); + sc = sc->push(); + sc->noaccesscheck = 1; e = e->semantic(sc); + sc->pop(); return e; } @@ -4206,6 +4244,8 @@ //return getProperty(e->loc, ident); return Type::dotExp(sc, e, ident); } + if (!s->isFuncDeclaration()) // because of overloading + s->checkDeprecated(e->loc, sc); s = s->toAlias(); v = s->isVarDeclaration(); @@ -4459,6 +4499,7 @@ { /* 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++) @@ -4467,7 +4508,10 @@ exps->push(fe); } e = new TupleExp(e->loc, exps); + sc = sc->push(); + sc->noaccesscheck = 1; e = e->semantic(sc); + sc->pop(); return e; } @@ -4541,6 +4585,7 @@ e = new PtrExp(e->loc, e); e->type = ct->next->next->next; } + } #else @@ -4565,9 +4610,31 @@ e->type = t->pointerTo(); } e = new PtrExp(e->loc, e, t); - -#endif - } + } + +#endif // !LLVMDC + + return e; + } + + if (ident == Id::__vptr) + { /* The pointer to the vtbl[] + * *cast(void***)e + */ + e = e->castTo(sc, tvoidptr->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; } @@ -4587,6 +4654,8 @@ return Type::dotExp(sc, e, ident); } } + if (!s->isFuncDeclaration()) // because of overloading + s->checkDeprecated(e->loc, sc); s = s->toAlias(); v = s->isVarDeclaration(); if (v && v->isConst())
--- a/dmd/mtype.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/mtype.h Sat Jul 12 19:38:31 2008 +0200 @@ -355,6 +355,7 @@ 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); void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); Expression *dotExp(Scope *sc, Expression *e, Identifier *ident);
--- a/dmd/optimize.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/optimize.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,752 +1,752 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <ctype.h> -#include <assert.h> -#include <math.h> - -#if __DMC__ -#include <complex.h> -#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 expression is a variable with a const initializer, - * return that initializer. - */ - -Expression *fromConstInitializer(Expression *e1) -{ - //printf("fromConstInitializer(%s)\n", e1->toChars()); - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->isConst() && v->init) - { Expression *ei = v->init->toExpression(); - if (ei && ei->type) - e1 = ei; - } - } - return e1; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - if (result & WANTinterpret) - { - return fromConstInitializer(this); - } - return 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()); - 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()) - { - e = new SymOffExp(loc, ve->var, 0); - e->type = type; - return e; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - integer_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - integer_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %lld is out of bounds [0..%lld]", index, dim); - e = new SymOffExp(loc, ve->var, index * ts->next->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; - } - - return this; -} - -Expression *CallExp::optimize(int result) -{ Expression *e = this; - - e1 = e1->optimize(result); - if (e1->op == TOKvar && result & WANTinterpret) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { - Expression *eresult = fd->interpret(NULL, arguments); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else if (result & WANTinterpret) - 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("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; - - e1 = e1->optimize(result); - if (result & WANTinterpret) - e1 = fromConstInitializer(e1); - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - type->next->equals(e1->type->next) - ) - { - e1->type = type; - 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)) - { - e1->type = type; - 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; - 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; - return e; -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - integer_t i2 = e2->toInteger(); - d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { - error("shift assign by %lld is outside the range 0..%"PRIuSIZE, 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) - { - integer_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 > sz) - { - error("shift by %lld is outside the range 0..%"PRIuSIZE, 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(this->e1); - Expression *e2 = fromConstInitializer(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()) - { - 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)); - if (result & WANTinterpret) - e1 = fromConstInitializer(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->next) - e = e1->castTo(NULL, t->next->arrayOf()); - } - return e; - } - if (result & WANTinterpret) - e1 = fromConstInitializer(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; - 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(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Cmp(op, type, this->e1, this->e2); - } - else - 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-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +#include <stdio.h> +#include <ctype.h> +#include <assert.h> +#include <math.h> + +#if __DMC__ +#include <complex.h> +#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 expression is a variable with a const initializer, + * return that initializer. + */ + +Expression *fromConstInitializer(Expression *e1) +{ + //printf("fromConstInitializer(%s)\n", e1->toChars()); + if (e1->op == TOKvar) + { VarExp *ve = (VarExp *)e1; + VarDeclaration *v = ve->var->isVarDeclaration(); + if (v && v->isConst() && v->init) + { Expression *ei = v->init->toExpression(); + if (ei && ei->type) + e1 = ei; + } + } + return e1; +} + + +Expression *Expression::optimize(int result) +{ + //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); + return this; +} + +Expression *VarExp::optimize(int result) +{ + if (result & WANTinterpret) + { + return fromConstInitializer(this); + } + return 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()); + 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()) + { + e = new SymOffExp(loc, ve->var, 0); + e->type = type; + return e; + } + } + if (e1->op == TOKindex) + { // Convert &array[n] to &array+n + IndexExp *ae = (IndexExp *)e1; + + if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) + { + integer_t index = ae->e2->toInteger(); + VarExp *ve = (VarExp *)ae->e1; + if (ve->type->ty == Tsarray && ve->type->next->ty != Tbit + && !ve->var->isImportedSymbol()) + { + TypeSArray *ts = (TypeSArray *)ve->type; + integer_t dim = ts->dim->toInteger(); + if (index < 0 || index >= dim) + error("array index %lld is out of bounds [0..%lld]", index, dim); + e = new SymOffExp(loc, ve->var, index * ts->next->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; + } + + return this; +} + +Expression *CallExp::optimize(int result) +{ Expression *e = this; + + e1 = e1->optimize(result); + if (e1->op == TOKvar && result & WANTinterpret) + { + FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); + if (fd) + { + Expression *eresult = fd->interpret(NULL, arguments); + if (eresult && eresult != EXP_VOID_INTERPRET) + e = eresult; + else if (result & WANTinterpret) + 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("type = %p\n", type); + assert(type); + enum TOK op1 = e1->op; + + e1 = e1->optimize(result); + if (result & WANTinterpret) + e1 = fromConstInitializer(e1); + + if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && + (type->ty == Tpointer || type->ty == Tarray) && + type->next->equals(e1->type->next) + ) + { + e1->type = type; + 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)) + { + e1->type = type; + 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; + 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; + return e; +} + +Expression *BinExp::optimize(int result) +{ + //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); + e1 = e1->optimize(result); + e2 = e2->optimize(result); + if (op == TOKshlass || op == TOKshrass || op == TOKushrass) + { + if (e2->isConst() == 1) + { + integer_t i2 = e2->toInteger(); + d_uns64 sz = e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { + error("shift assign by %lld is outside the range 0..%"PRIuSIZE, 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) + { + integer_t i2 = e->e2->toInteger(); + d_uns64 sz = e->e1->type->size() * 8; + if (i2 < 0 || i2 > sz) + { + error("shift by %lld is outside the range 0..%"PRIuSIZE, 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(this->e1); + Expression *e2 = fromConstInitializer(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()) + { + 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)); + if (result & WANTinterpret) + e1 = fromConstInitializer(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->next) + e = e1->castTo(NULL, t->next->arrayOf()); + } + return e; + } + if (result & WANTinterpret) + e1 = fromConstInitializer(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; + 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(result); + e2 = e2->optimize(result); + if (e1->isConst() == 1 && e2->isConst() == 1) + { + e = Cmp(op, type, this->e1, this->e2); + } + else + 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; +} + +
--- a/dmd/parse.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/parse.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,4919 +1,5156 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include <stdio.h> -#include <assert.h> - -#include "mem.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" - -// 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 C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -// Support left-to-right array declarations -#define LTORARRAYDECL 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; - - nextToken(); - 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); - - 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; - unsigned stc; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Array(); - do - { - comment = token.blockComment; - switch (token.value) - { - case TOKenum: - s = parseEnum(); - 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(); - decldefs->append(a); - continue; - - case TOKthis: - s = parseCtor(); - break; - - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: -#if 1 - s = parseInvariant(); -#else - if (peek(&token)->value == TOKlcurly) - s = parseInvariant(); - else - { - stc = STCinvariant; - goto Lstc; - } -#endif - 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: stc = STCconst; 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; - - Lstc: - nextToken(); - Lstc2: - switch (token.value) - { - case TOKconst: stc |= STCconst; 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 TOKinvariant: stc |= STCinvariant; goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - while (1) - { - Identifier *ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = stc; - s = v; - if (token.value == TOKsemicolon) - { - nextToken(); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - decldefs->push(s); - addComment(s, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - } - else - { a = parseBlock(); - s = new StorageClassDeclaration(stc, 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(); - a = parseBlock(); - s = new ProtDeclaration(prot, a); - break; - - case TOKalign: - { unsigned n; - - 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(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) - 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; -} - - -/******************************************** - * 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 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 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) - { -#if _WIN32 - link = LINKwindows; -#else - link = LINKc; -#endif - } - 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 V2 - /* 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(arguments) { body } - * Current token is 'this'. - */ - -CtorDeclaration *Parser::parseCtor() -{ - CtorDeclaration *f; - Arguments *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new CtorDeclaration(loc, 0, arguments, varargs); - 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; - Type *at; - Argument *a; - unsigned storageClass; - Expression *ae; - - ai = NULL; - storageClass = STCin; // parameter is "in" by default - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKin: - storageClass = STCin; - nextToken(); - goto L1; - - case TOKout: - storageClass = STCout; - nextToken(); - goto L1; - - case TOKinout: - case TOKref: - storageClass = STCref; - nextToken(); - goto L1; - - case TOKlazy: - storageClass = STClazy; - nextToken(); - goto L1; - - default: - L1: - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseAssignExp(); - 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; - } - a = new Argument(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - break; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *t; - 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(); - t = parseBasicType(); - } - else - t = NULL; - - e = new EnumDeclaration(loc, id, t); - 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) - { - if (token.value == TOKidentifier) - { EnumMember *em; - Expression *value; - Identifier *ident; - - loc = this->loc; - ident = token.ident; - value = NULL; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - em = new EnumMember(loc, ident, value); - e->members->push(em); - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma); - } - addComment(em, comment); - comment = token.blockComment; - } - else - { error("enum member expected"); - nextToken(); - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - return e; -} - -Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; - int anon = 0; - enum TOK tok; - Identifier *id; - TemplateParameters *tpl = 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(); - } - } - - 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) - { Array *decldefs; - TemplateDeclaration *tempdecl; - - // Wrap a template around the aggregate declaration - decldefs = new Array(); - decldefs->push(a); - tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - enum PROT protection = PROTpublic; - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - switch (token.value) - { - case TOKidentifier: - break; - case TOKprivate: - protection = PROTprivate; - continue; - case TOKpackage: - protection = PROTpackage; - continue; - case TOKprotected: - protection = PROTprotected; - continue; - case TOKpublic: - protection = PROTpublic; - continue; - default: - error("base classes expected instead of %s", token.toChars()); - return NULL; - } - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - protection = PROTpublic; - } - return baseclasses; -} - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration() -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Array *decldefs; - 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; - - 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, decldefs); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - */ - -TemplateParameters *Parser::parseTemplateParameterList() -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (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(); - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("Identifier expected for template parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseBasicType(); - tp_spectype = parseDeclarator(tp_spectype, NULL); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseBasicType(); - tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); - } - 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); - } - else - { // ValueParameter - tp_valtype = parseBasicType(); - tp_valtype = parseDeclarator(tp_valtype, &tp_ident); - if (!tp_ident) - { - error("no identifier 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 = parseCondExp(); - } - 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) - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tqual = new TypeTypeof(loc, exp); - check(TOKdot); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - goto Lerr; - } - id = token.ident; - nextToken(); - } - - idents = new Array(); - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - nextToken(); - tiargs = parseTemplateArgumentList(); - } - - 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; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - Objects *tiargs = new Objects(); - if (token.value != TOKlparen) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return tiargs; - } - nextToken(); - - // Get TemplateArgumentList - if (token.value != TOKrparen) - { - while (1) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Type - Type *ta; - - // Get TemplateArgument - ta = parseBasicType(); - ta = parseDeclarator(ta, NULL); - tiargs->push(ta); - } - else - { // Expression - Expression *ea; - - ea = parseAssignExp(); - tiargs->push(ea); - } - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen, "template argument list"); - 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, token.ident, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { Identifier *name; - Identifier *alias; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following :"); - break; - } - 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; -} - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - TemplateInstance *tempinst; - - //printf("parseBasicType()\n"); - switch (token.value) - { - CASE_BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - nextToken(); - tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - 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) - { - nextToken(); - tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = parseTemplateArgumentList(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - id = Id::empty; - goto Lident; - - case TOKtypeof: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - tid = new TypeTypeof(loc, exp); - goto Lident2; - } - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -Type *Parser::parseBasicType2(Type *t) -{ - Type *ts; - Type *ta; - - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: -#if LTORARRAYDECL - // 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 - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's [expression]\n"); - inBrackets++; - Expression *e = parseExpression(); // [ expression ] - if (token.value == TOKslice) - { Expression *e2; - - nextToken(); - e2 = parseExpression(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; -#else - // Handle []. Make sure things like - // int[3][1] a; - // is (array[3] of array[1] of int) - ts = t; - while (token.value == TOKlbracket) - { - nextToken(); - if (token.value == TOKrbracket) - { - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t,e); - check(TOKrbracket); - } - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - } - t = ts; - continue; -#endif - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) - // t function(parameter list) - Arguments *arguments; - int varargs; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - t = new TypeFunction(arguments, t, varargs, linkage); - if (save == TOKdelegate) - t = new TypeDelegate(t); - else - t = new TypePointer(t); // pointer to function - continue; - } - - default: - ts = t; - break; - } - break; - } - return ts; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) -{ Type *ts; - Type *ta; - - //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: - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - - default: - ts = t; - break; - } - - while (1) - { - switch (token.value) - { -#if CARRAYDECL - case TOKlbracket: - { // This is the old C-style post [] syntax. - nextToken(); - if (token.value == TOKrbracket) - { - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - Type *index; - - //printf("it's an associative array\n"); - index = parseBasicType(); - index = parseDeclarator(index, NULL); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("it's [expression]\n"); - Expression *e = parseExpression(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { Arguments *arguments; - int varargs; - - if (tpl) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - if (peekPastParen(&token)->value == TOKlparen) - { // It's a function template declaration - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - } - - arguments = parseParameters(&varargs); - Type *ta = new TypeFunction(arguments, t, varargs, linkage); - Type **pt; - for (pt = &ts; *pt != t; pt = &(*pt)->next) - ; - *pt = ta; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Return array of Declaration *'s. - */ - -Array *Parser::parseDeclarations() -{ - enum STC storage_class; - enum STC stc; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Array *a; - enum TOK tok; - unsigned char *comment = token.blockComment; - enum LINK link = linkage; - - //printf("parseDeclarations()\n"); - switch (token.value) - { - case TOKtypedef: - case TOKalias: - tok = token.value; - nextToken(); - break; - - default: - tok = TOKreserved; - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: stc = STCconst; 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; - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = (STC) (storage_class | stc); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - a = new Array(); - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - while (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - ident = token.ident; - nextToken(); - nextToken(); - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storage_class; - 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)) - { - error("Identifier expected following comma"); - } - else - continue; - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - return a; - } - - if (token.value == TOKclass) - { AggregateDeclaration *s; - - s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - a->push(s); - addComment(s, comment); - return a; - } - - ts = parseBasicType(); - ts = parseBasicType2(ts); - tfirst = NULL; - - 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; - - 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) - { FuncDeclaration *f; - Dsymbol *s; - - f = new FuncDeclaration(loc, 0, ident, storage_class, t); - addComment(f, comment); - parseContracts(f); - addComment(f, NULL); - if (link == linkage) - { - s = f; - } - else - { - Array *ax = new Array(); - ax->push(f); - s = new LinkDeclaration(link, ax); - } - if (tpl) // it's a function template - { Array *decldefs; - TemplateDeclaration *tempdecl; - - // Wrap a template around the aggregate declaration - decldefs = new Array(); - decldefs->push(s); - tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { VarDeclaration *v; - Initializer *init; - - init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - 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 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; -} - -/***************************************** - */ - -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; - - 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: - 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; - } -} - - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - 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: - // Need to look ahead to see if it is a declaration, label, or expression - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - Identifier *ident; - - 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: - 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_BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKfinal: - case TOKinvariant: -// case TOKtypeof: - Ldeclaration: - { Array *a; - - a = parseDeclarations(); - 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 CompoundStatement(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: - { Dsymbol *d; - - d = parseEnum(); - 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 = STCin; - 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; - } - } - tb = parseBasicType(); - at = parseDeclarator(tb, &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(); - 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(STCin, 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 *tb; - Type *at; - Identifier *ai; - - tb = parseBasicType(); - at = parseDeclarator(tb, &ai); - check(TOKassign); - arg = new Argument(STCin, 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(STCin, 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) - 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: - { Expression *condition; - Statement *body; - - nextToken(); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Array cases; // array of Expression's - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - 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); - - // 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); - t = parseBasicType(); - id = NULL; - t = parseDeclarator(t, &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); - 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, 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 - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - int haveId = 0; - - if (!isBasicType(&t)) - return FALSE; - if (!isDeclarator(&t, &haveId, endtok)) - return FALSE; - if ( needId == 1 || - (needId == 0 && !haveId) || - (needId == 2 && haveId)) - { if (pt) - *pt = t; - return TRUE; - } - else - return FALSE; -} - -int Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - Token *t2; - int parens; - - switch (t->value) - { - CASE_BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - 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: - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - 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; - - default: - goto Lfalse; - } - *pt = t; - return TRUE; - -Lfalse: - 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; - 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; - int tmp; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - while (1) - { - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - - case TOKin: - case TOKout: - case TOKinout: - case TOKref: - case TOKlazy: - t = peek(t); - default: - if (!isBasicType(&t)) - return FALSE; - 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; - } - if (t->value == TOKcomma) - { t = peek(t); - 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; - - 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 TOKslice: - if (brnest) - continue; - break; - - 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; - - switch (token.value) - { - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - 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, token.int32value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, token.uns32value, 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; - - 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, token.uns32value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, token.uns32value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, token.uns32value, 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 = new TypeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { Expression *exp; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - t = new TypeTypeof(loc, exp); - if (token.value == TOKdot) - goto L1; - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { Type *t; - - nextToken(); - check(TOKlparen, "typeid"); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( type ) - check(TOKrparen); - e = new TypeidExp(loc, t); - break; - } - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseBasicType(); - targ = parseDeclarator(targ, &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 || - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseBasicType(); - tspec = parseDeclarator(tspec, NULL); - } - } - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2); - 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 (1) - { - 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 } - * delegate type(parameters) { body } - */ - Arguments *arguments; - int varargs; - FuncLiteralDeclaration *fd; - Type *t; - - 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); - } - t = new TypeFunction(arguments, t, varargs, linkage); - fd = new FuncLiteralDeclaration(loc, 0, t, 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 parsePostExp(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 && peek(&token)->value == TOKlparen) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - tempinst->tiargs = parseTemplateArgumentList(); - 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 - { Type *t; - - nextToken(); - check(TOKlparen); - t = parseBasicType(); - t = parseDeclarator(t,NULL); // ( 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 TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKnot: - 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: - CASE_BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseBasicType(); - t = parseDeclarator(t,NULL); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = new 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(); - break; - } - default: - e = parsePrimaryExp(); - 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()\n"); - 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; - } - -#if LTORARRAYDECL - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { - Type *index = ((TypeAArray *)t)->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(t->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(t->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } -#else - t = parseBasicType(); - while (token.value == TOKmul) - { t = new TypePointer(t); - nextToken(); - } - if (token.value == TOKlbracket) - { - Expression *e; - - nextToken(); - e = parseAssignExp(); - arguments = new Array(); - arguments->push(e); - check(TOKrbracket); - t = parseDeclarator(t, NULL); - t = new TypeDArray(t); - } - else if (token.value == TOKlparen) - arguments = parseArguments(); -#endif - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); -} - - -/********************************* ***************************/ - + +// 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. + +// This is the D parser + +#include <stdio.h> +#include <assert.h> + +#include "mem.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" + +// 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 left-to-right array declarations +#define LTORARRAYDECL 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; + + nextToken(); + 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); + + 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; + unsigned stc; + Condition *condition; + unsigned char *comment; + + //printf("Parser::parseDeclDefs()\n"); + decldefs = new Array(); + do + { + comment = token.blockComment; + switch (token.value) + { + case TOKenum: + s = parseEnum(); + 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(); + decldefs->append(a); + continue; + + case TOKthis: + s = parseCtor(); + break; + + case TOKtilde: + s = parseDtor(); + break; + + case TOKinvariant: +#if 1 + s = parseInvariant(); +#else + if (peek(&token)->value == TOKlcurly) + s = parseInvariant(); + else + { + stc = STCinvariant; + goto Lstc; + } +#endif + 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: stc = STCconst; 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; + + Lstc: + nextToken(); + Lstc2: + switch (token.value) + { + case TOKconst: stc |= STCconst; 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 TOKinvariant: stc |= STCinvariant; goto Lstc; + default: + break; + } + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + while (1) + { + Identifier *ident = token.ident; + nextToken(); + nextToken(); + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = stc; + s = v; + if (token.value == TOKsemicolon) + { + nextToken(); + } + else if (token.value == TOKcomma) + { + nextToken(); + if (token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + decldefs->push(s); + addComment(s, comment); + continue; + } + else + error("Identifier expected following comma"); + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + break; + } + } + else + { a = parseBlock(); + s = new StorageClassDeclaration(stc, 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(); + a = parseBlock(); + s = new ProtDeclaration(prot, a); + break; + + case TOKalign: + { unsigned n; + + 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(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) + 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; +} + + +/******************************************** + * 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 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) + { +#if _WIN32 + link = LINKwindows; +#else + link = LINKc; +#endif + } + 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(arguments) { body } + * Current token is 'this'. + */ + +CtorDeclaration *Parser::parseCtor() +{ + CtorDeclaration *f; + Arguments *arguments; + int varargs; + Loc loc = this->loc; + + nextToken(); + arguments = parseParameters(&varargs); + f = new CtorDeclaration(loc, 0, arguments, varargs); + 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; + Expression *ae; + + storageClass = STCin; // parameter is "in" by default + switch (token.value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + varargs = 1; + nextToken(); + break; + + case TOKin: + storageClass = STCin; + nextToken(); + goto L1; + + case TOKout: + storageClass = STCout; + nextToken(); + goto L1; + + case TOKinout: + case TOKref: + storageClass = STCref; + nextToken(); + goto L1; + + case TOKlazy: + storageClass = STClazy; + nextToken(); + goto L1; + + default: + L1: + tb = parseBasicType(); + at = parseDeclarator(tb, &ai); + ae = NULL; + if (token.value == TOKassign) // = defaultArg + { nextToken(); + ae = parseAssignExp(); + 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; + } + a = new Argument(storageClass, at, ai, ae); + arguments->push(a); + if (token.value == TOKcomma) + { nextToken(); + continue; + } + break; + } + break; + } + check(TOKrparen); + *pvarargs = varargs; + return arguments; +} + + +/************************************* + */ + +EnumDeclaration *Parser::parseEnum() +{ EnumDeclaration *e; + Identifier *id; + Type *t; + 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(); + t = parseBasicType(); + } + else + t = NULL; + + e = new EnumDeclaration(loc, id, t); + 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) + { + if (token.value == TOKidentifier) + { EnumMember *em; + Expression *value; + Identifier *ident; + + loc = this->loc; + ident = token.ident; + value = NULL; + nextToken(); + if (token.value == TOKassign) + { + nextToken(); + value = parseAssignExp(); + } + em = new EnumMember(loc, ident, value); + e->members->push(em); + if (token.value == TOKrcurly) + ; + else + { addComment(em, comment); + comment = NULL; + check(TOKcomma); + } + addComment(em, comment); + comment = token.blockComment; + } + else + { error("enum member expected"); + nextToken(); + } + } + nextToken(); + } + else + error("enum declaration is invalid"); + + //printf("-parseEnum() %s\n", e->toChars()); + return e; +} + +Dsymbol *Parser::parseAggregate() +{ AggregateDeclaration *a = NULL; + int anon = 0; + enum TOK tok; + Identifier *id; + TemplateParameters *tpl = 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(); + } + } + + 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) + { Array *decldefs; + TemplateDeclaration *tempdecl; + + // Wrap a template around the aggregate declaration + decldefs = new Array(); + decldefs->push(a); + tempdecl = new TemplateDeclaration(loc, id, tpl, decldefs); + return tempdecl; + } + + return a; +} + +/******************************************* + */ + +BaseClasses *Parser::parseBaseClasses() +{ + enum PROT protection = PROTpublic; + BaseClasses *baseclasses = new BaseClasses(); + + for (; 1; nextToken()) + { + switch (token.value) + { + case TOKidentifier: + break; + case TOKprivate: + protection = PROTprivate; + continue; + case TOKpackage: + protection = PROTpackage; + continue; + case TOKprotected: + protection = PROTprotected; + continue; + case TOKpublic: + protection = PROTpublic; + continue; + default: + error("base classes expected instead of %s", token.toChars()); + return NULL; + } + BaseClass *b = new BaseClass(parseBasicType(), protection); + baseclasses->push(b); + if (token.value != TOKcomma) + break; + protection = PROTpublic; + } + 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; + 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; + + 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, decldefs); + return tempdecl; + +Lerr: + return NULL; +} + +/****************************************** + * Parse template parameter list. + */ + +TemplateParameters *Parser::parseTemplateParameterList() +{ + TemplateParameters *tpl = new TemplateParameters(); + + if (token.value != TOKlparen) + { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); + goto Lerr; + } + nextToken(); + + // Get array of TemplateParameters + if (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(); + if (token.value != TOKidentifier) + { error("Identifier expected for template parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseBasicType(); + tp_spectype = parseDeclarator(tp_spectype, NULL); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseBasicType(); + tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); + } + tp = new TemplateAliasParameter(loc, tp_ident, tp_spectype, tp_defaulttype); + } + else if (t->value == TOKcolon || t->value == TOKassign || + t->value == TOKcomma || t->value == TOKrparen) + { // TypeParameter + if (token.value != TOKidentifier) + { error("Identifier expected for template parameter"); + goto Lerr; + } + tp_ident = token.ident; + nextToken(); + if (token.value == TOKcolon) // : Type + { + nextToken(); + tp_spectype = parseBasicType(); + tp_spectype = parseDeclarator(tp_spectype, NULL); + } + if (token.value == TOKassign) // = Type + { + nextToken(); + tp_defaulttype = parseBasicType(); + tp_defaulttype = parseDeclarator(tp_defaulttype, NULL); + } + 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 = parseBasicType(); + tp_valtype = parseDeclarator(tp_valtype, &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 = parseCondExp(); + } + 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) + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + tqual = new TypeTypeof(loc, exp); + 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(); + tiargs = parseTemplateArgumentList(); + } + + 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"); + Objects *tiargs = new Objects(); + if (token.value != TOKlparen) + { error("!(TemplateArgumentList) expected following TemplateIdentifier"); + return tiargs; + } + nextToken(); + + // Get TemplateArgumentList + if (token.value != TOKrparen) + { + while (1) + { + // See if it is an Expression or a Type + if (isDeclaration(&token, 0, TOKreserved, NULL)) + { // Type + Type *ta; + + // Get TemplateArgument + ta = parseBasicType(); + ta = parseDeclarator(ta, NULL); + tiargs->push(ta); + } + else + { // Expression + Expression *ea; + + ea = parseAssignExp(); + tiargs->push(ea); + } + if (token.value != TOKcomma) + break; + nextToken(); + } + } + check(TOKrparen, "template argument list"); + 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, token.ident, aliasid, isstatic); + decldefs->push(s); + + /* Look for + * : alias=name, alias=name; + * syntax. + */ + if (token.value == TOKcolon) + { + do + { Identifier *name; + Identifier *alias; + + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following :"); + break; + } + 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; +} + +Type *Parser::parseBasicType() +{ Type *t; + Identifier *id; + TypeQualified *tid; + TemplateInstance *tempinst; + + //printf("parseBasicType()\n"); + switch (token.value) + { + CASE_BASIC_TYPES_X(t): + nextToken(); + break; + + case TOKidentifier: + id = token.ident; + nextToken(); + if (token.value == TOKnot) + { + nextToken(); + tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = parseTemplateArgumentList(); + 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) + { + nextToken(); + tempinst = new TemplateInstance(loc, id); + tempinst->tiargs = parseTemplateArgumentList(); + tid->addIdent((Identifier *)tempinst); + } + else + tid->addIdent(id); + } + t = tid; + break; + + case TOKdot: + // Leading . as in .foo + id = Id::empty; + goto Lident; + + case TOKtypeof: + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + tid = new TypeTypeof(loc, exp); + goto Lident2; + } + + 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) +{ + Type *ts; + Type *ta; + + //printf("parseBasicType2()\n"); + while (1) + { + switch (token.value) + { + case TOKmul: + t = new TypePointer(t); + nextToken(); + continue; + + case TOKlbracket: +#if LTORARRAYDECL + // 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 + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + t = new TypeAArray(t, index); + check(TOKrbracket); + } + else + { + //printf("it's [expression]\n"); + inBrackets++; + Expression *e = parseExpression(); // [ expression ] + if (token.value == TOKslice) + { Expression *e2; + + nextToken(); + e2 = parseExpression(); // [ exp .. exp ] + t = new TypeSlice(t, e, e2); + } + else + t = new TypeSArray(t,e); + inBrackets--; + check(TOKrbracket); + } + continue; +#else + // Handle []. Make sure things like + // int[3][1] a; + // is (array[3] of array[1] of int) + ts = t; + while (token.value == TOKlbracket) + { + nextToken(); + if (token.value == TOKrbracket) + { + ta = new TypeDArray(t); // [] + nextToken(); + } + else if (isDeclaration(&token, 0, TOKrbracket, NULL)) + { // It's an associative array declaration + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + check(TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("it's [expression]\n"); + Expression *e = parseExpression(); // [ expression ] + ta = new TypeSArray(t,e); + check(TOKrbracket); + } + Type **pt; + for (pt = &ts; *pt != t; pt = &(*pt)->next) + ; + *pt = ta; + } + t = ts; + continue; +#endif + + case TOKdelegate: + case TOKfunction: + { // Handle delegate declaration: + // t delegate(parameter list) + // t function(parameter list) + Arguments *arguments; + int varargs; + enum TOK save = token.value; + + nextToken(); + arguments = parseParameters(&varargs); + t = new TypeFunction(arguments, t, varargs, linkage); + if (save == TOKdelegate) + t = new TypeDelegate(t); + else + t = new TypePointer(t); // pointer to function + continue; + } + + default: + ts = t; + break; + } + break; + } + return ts; +} + +Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl) +{ Type *ts; + Type *ta; + + //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; + } + + 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. + 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 declaration + Type *index; + + //printf("it's an associative array\n"); + index = parseBasicType(); + index = parseDeclarator(index, NULL); // [ type ] + check(TOKrbracket); + ta = new TypeAArray(t, index); + } + else + { + //printf("it's [expression]\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 = &(*pt)->next) + ; + *pt = ta; + continue; + } +#endif + case TOKlparen: + { Arguments *arguments; + int varargs; + + if (tpl) + { + /* Look ahead to see if this is (...)(...), + * i.e. a function template declaration + */ + if (peekPastParen(&token)->value == TOKlparen) + { // It's a function template declaration + //printf("function template declaration\n"); + + // Gather template parameter list + *tpl = parseTemplateParameterList(); + } + } + + arguments = parseParameters(&varargs); + Type *ta = new TypeFunction(arguments, t, varargs, linkage); + Type **pt; + for (pt = &ts; *pt != t; pt = &(*pt)->next) + ; + *pt = ta; + 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() +{ + enum STC storage_class; + enum STC stc; + Type *ts; + Type *t; + Type *tfirst; + Identifier *ident; + Array *a; + enum TOK tok; + unsigned char *comment = token.blockComment; + enum LINK link = linkage; + + //printf("parseDeclarations()\n"); + switch (token.value) + { + case TOKtypedef: + case TOKalias: + tok = token.value; + nextToken(); + break; + + default: + tok = TOKreserved; + break; + } + + storage_class = STCundefined; + while (1) + { + switch (token.value) + { + case TOKconst: stc = STCconst; 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; + L1: + if (storage_class & stc) + error("redundant storage class '%s'", token.toChars()); + storage_class = (STC) (storage_class | stc); + nextToken(); + continue; + + case TOKextern: + if (peek(&token)->value != TOKlparen) + { stc = STCextern; + goto L1; + } + + link = parseLinkage(); + continue; + + default: + break; + } + break; + } + + a = new Array(); + + /* Look for auto initializers: + * storage_class identifier = initializer; + */ + while (storage_class && + token.value == TOKidentifier && + peek(&token)->value == TOKassign) + { + ident = token.ident; + nextToken(); + nextToken(); + Initializer *init = parseInitializer(); + VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); + v->storage_class = storage_class; + 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)) + { + error("Identifier expected following comma"); + } + else + continue; + } + else + error("semicolon expected following auto declaration, not '%s'", token.toChars()); + return a; + } + + if (token.value == TOKclass) + { AggregateDeclaration *s; + + s = (AggregateDeclaration *)parseAggregate(); + s->storage_class |= storage_class; + a->push(s); + addComment(s, comment); + return a; + } + + ts = parseBasicType(); + ts = parseBasicType2(ts); + tfirst = NULL; + + 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; + + 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) + { FuncDeclaration *f; + Dsymbol *s; + + f = new FuncDeclaration(loc, 0, ident, storage_class, t); + addComment(f, comment); + parseContracts(f); + addComment(f, NULL); + if (link == linkage) + { + s = f; + } + else + { + Array *ax = new Array(); + ax->push(f); + s = new LinkDeclaration(link, ax); + } + if (tpl) // it's a function template + { Array *decldefs; + TemplateDeclaration *tempdecl; + + // Wrap a template around the aggregate declaration + decldefs = new Array(); + decldefs->push(s); + tempdecl = new TemplateDeclaration(loc, s->ident, tpl, decldefs); + s = tempdecl; + } + addComment(s, comment); + a->push(s); + } + else + { VarDeclaration *v; + Initializer *init; + + init = NULL; + if (token.value == TOKassign) + { + nextToken(); + init = parseInitializer(); + } + 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; +} + +/***************************************** + */ + +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; + + 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: + 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; + 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: + // Need to look ahead to see if it is a declaration, label, or expression + t = peek(&token); + if (t->value == TOKcolon) + { // It's a label + Identifier *ident; + + 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_BASIC_TYPES: + case TOKtypedef: + case TOKalias: + case TOKconst: + case TOKauto: + case TOKextern: + case TOKfinal: + case TOKinvariant: +// case TOKtypeof: + Ldeclaration: + { Array *a; + + a = parseDeclarations(); + 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 CompoundStatement(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: + { Dsymbol *d; + + d = parseEnum(); + 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 = STCin; + 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; + } + } + tb = parseBasicType(); + at = parseDeclarator(tb, &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(); + 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(STCin, 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 *tb; + Type *at; + Identifier *ai; + + tb = parseBasicType(); + at = parseDeclarator(tb, &ai); + check(TOKassign); + arg = new Argument(STCin, 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(STCin, 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) + 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: + { Expression *condition; + Statement *body; + + nextToken(); + check(TOKlparen); + condition = parseExpression(); + check(TOKrparen); + body = parseStatement(PSscope); + s = new SwitchStatement(loc, condition, body); + break; + } + + case TOKcase: + { Expression *exp; + Statements *statements; + Array cases; // array of Expression's + + while (1) + { + nextToken(); + exp = parseAssignExp(); + cases.push(exp); + if (token.value != TOKcomma) + break; + } + 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); + + // 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); + t = parseBasicType(); + id = NULL; + t = parseDeclarator(t, &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, 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 + */ + +int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) +{ + int haveId = 0; + +#if DMDV2 + if ((t->value == TOKconst || t->value == TOKinvariant) && + peek(t)->value != TOKlparen) + { /* const type + * invariant type + */ + t = peek(t); + } +#endif + + if (!isBasicType(&t)) + return FALSE; + if (!isDeclarator(&t, &haveId, endtok)) + return FALSE; + if ( needId == 1 || + (needId == 0 && !haveId) || + (needId == 2 && haveId)) + { if (pt) + *pt = t; + return TRUE; + } + else + return FALSE; +} + +int Parser::isBasicType(Token **pt) +{ + // This code parallels parseBasicType() + Token *t = *pt; + Token *t2; + int parens; + + switch (t->value) + { + CASE_BASIC_TYPES: + t = peek(t); + break; + + case TOKidentifier: + 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: + t = peek(t); + if (t->value != TOKlparen) + goto Lfalse; + if (!skipParens(t, &t)) + 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; + + default: + goto Lfalse; + } + *pt = t; + return TRUE; + +Lfalse: + 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; + 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; + int tmp; + + //printf("isParameters()\n"); + if (t->value != TOKlparen) + return FALSE; + + t = peek(t); + while (1) + { + switch (t->value) + { + case TOKrparen: + break; + + case TOKdotdotdot: + t = peek(t); + break; + + case TOKin: + case TOKout: + case TOKinout: + case TOKref: + case TOKlazy: + t = peek(t); + default: + if (!isBasicType(&t)) + return FALSE; + 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; + } + if (t->value == TOKcomma) + { t = peek(t); + 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; + + 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 TOKslice: + if (brnest) + continue; + break; + + 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 && peek(&token)->value == TOKlparen) + { // identifier!(template-argument-list) + TemplateInstance *tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + tempinst->tiargs = parseTemplateArgumentList(); + 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, token.int32value, Type::tint32); + nextToken(); + break; + + case TOKuns32v: + e = new IntegerExp(loc, token.uns32value, 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: + { char *s = loc.filename ? loc.filename : mod->ident->toChars(); + e = new StringExp(loc, 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, token.uns32value, Type::tchar); + nextToken(); + break; + + case TOKwcharv: + e = new IntegerExp(loc, token.uns32value, Type::twchar); + nextToken(); + break; + + case TOKdcharv: + e = new IntegerExp(loc, token.uns32value, 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 = new TypeDotIdExp(loc, t, token.ident); + nextToken(); + break; + + case TOKtypeof: + { Expression *exp; + + nextToken(); + check(TOKlparen); + exp = parseExpression(); + check(TOKrparen); + t = new TypeTypeof(loc, exp); + e = new TypeExp(loc, t); + break; + } + + case TOKtypeid: + { Type *t; + + nextToken(); + check(TOKlparen, "typeid"); + t = parseBasicType(); + t = parseDeclarator(t,NULL); // ( 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; + Loc loc = this->loc; + + nextToken(); + if (token.value == TOKlparen) + { + nextToken(); + targ = parseBasicType(); + targ = parseDeclarator(targ, &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 || + token.value == TOKfunction || + token.value == TOKdelegate || + token.value == TOKreturn)) + { + tok2 = token.value; + nextToken(); + } + else + { + tspec = parseBasicType(); + tspec = parseDeclarator(tspec, NULL); + } + } + check(TOKrparen); + } + else + { error("(type identifier : specialization) expected following is"); + goto Lerr; + } + e = new IsExp(loc, targ, ident, tok, tspec, tok2); + 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 (1) + { + 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 } + * delegate type(parameters) { body } + */ + Arguments *arguments; + int varargs; + FuncLiteralDeclaration *fd; + Type *t; + + 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); + } + t = new TypeFunction(arguments, t, varargs, linkage); + fd = new FuncLiteralDeclaration(loc, 0, t, 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 parsePostExp(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 && peek(&token)->value == TOKlparen) + { // identifier!(template-argument-list) + TemplateInstance *tempinst; + + tempinst = new TemplateInstance(loc, id); + nextToken(); + tempinst->tiargs = parseTemplateArgumentList(); + 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 + { Type *t; + + nextToken(); + check(TOKlparen); + t = parseBasicType(); + t = parseDeclarator(t,NULL); // ( 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 TOKdot: + case TOKplusplus: + case TOKminusminus: + case TOKnot: + 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 = parseBasicType(); + t = parseDeclarator(t,NULL); + check(TOKrparen); + + // if .identifier + if (token.value == TOKdot) + { + nextToken(); + if (token.value != TOKidentifier) + { error("Identifier expected following (type)."); + return NULL; + } + e = new 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(); + break; + } + default: + e = parsePrimaryExp(); + 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; + } + +#if LTORARRAYDECL + t = parseBasicType(); + t = parseBasicType2(t); + if (t->ty == Taarray) + { + Type *index = ((TypeAArray *)t)->index; + + Expression *e = index->toExpression(); + if (e) + { arguments = new Expressions(); + arguments->push(e); + t = new TypeDArray(t->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(t->next); + } + else if (token.value == TOKlparen) + { + arguments = parseArguments(); + } +#else + t = parseBasicType(); + while (token.value == TOKmul) + { t = new TypePointer(t); + nextToken(); + } + if (token.value == TOKlbracket) + { + Expression *e; + + nextToken(); + e = parseAssignExp(); + arguments = new Array(); + arguments->push(e); + check(TOKrbracket); + t = parseDeclarator(t, NULL); + t = new TypeDArray(t); + } + else if (token.value == TOKlparen) + arguments = parseArguments(); +#endif + e = new NewExp(loc, thisexp, newargs, t, arguments); + return e; +} + +/********************************************** + */ + +void Parser::addComment(Dsymbol *s, unsigned char *blockComment) +{ + s->addComment(combineComments(blockComment, token.lineComment)); +} + + +/********************************* ***************************/ +
--- a/dmd/parse.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/parse.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -20,6 +20,7 @@ #include "enum.h" struct Type; +struct TypeQualified; struct Expression; struct Declaration; struct Statement; @@ -27,6 +28,7 @@ struct Initializer; struct FuncDeclaration; struct CtorDeclaration; +struct PostBlitDeclaration; struct DtorDeclaration; struct StaticCtorDeclaration; struct StaticDtorDeclaration;
--- a/dmd/root.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/root.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,1836 +1,1855 @@ - -// 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 <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <string.h> -#include <stdint.h> -#include <assert.h> - -#if _MSC_VER ||__MINGW32__ -#include <malloc.h> -#endif - -#if _WIN32 -#include <windows.h> -#include <direct.h> -#endif - -#if linux -#include <sys/types.h> -#include <sys/stat.h> -#include <fcntl.h> -#include <errno.h> -#include <unistd.h> -#include <utime.h> -#endif - -#include "port.h" -#include "root.h" -#include "dchar.h" -#include "mem.h" -#include "mars.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 "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(char *path, char *name) -{ char *f; - size_t pathlen; - size_t namelen; - - if (!path || !*path) - return name; - pathlen = strlen(path); - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if linux - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#endif -#if _WIN32 - if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#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 linux - 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 linux - case '~': - buf.writestring(getenv("HOME")); - continue; -#endif - - case ' ': - case '\t': // tabs in filenames? - if (!instring) // if not in string - break; // treat as end of path - 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) -{ -#if _WIN32 - return stricmp(str,((FileName *)obj)->str); -#else - return String::compare(obj); -#endif -} - -int FileName::equals(Object *obj) -{ -#if _WIN32 - return stricmp(str,((FileName *)obj)->str) == 0; -#else - return String::equals(obj); -#endif -} - -/************************************ - * Return !=0 if absolute path name. - */ - -int FileName::absolute(const char *name) -{ -#if _WIN32 - return (*name == '\\') || - (*name == '/') || - (*name && name[1] == ':'); -#endif -#if linux - return (*name == '/'); -#endif -} - -/******************************** - * Return filename extension (read-only). - * 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 linux - case '/': - break; -#endif -#if _WIN32 - case '\\': - case ':': - break; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return NULL; - } -} - -char *FileName::ext() -{ - return ext(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 linux - case '/': - return e + 1; -#endif -#if _WIN32 - case '\\': - case ':': - 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 linux - if (n[-1] == '/') - n--; -#endif -#if _WIN32 - if (n[-1] == '\\') - n--; -#endif - } - pathlen = n - str; - path = (char *)mem.malloc(pathlen + 1); - memcpy(path, str, pathlen); - path[pathlen] = 0; - return path; -} - -/************************************** - * Replace filename portion of path. - */ - -char *FileName::replaceName(char *path, 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 linux - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#endif -#if _WIN32 - if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#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 linux - return strcmp(e,ext) == 0; -#endif -#if _WIN32 - return stricmp(e,ext) == 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 -#endif -#if linux - file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time -#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, char *name, int cwd) -{ - if (absolute(name)) - { - return exists(name) ? name : NULL; - } - if (cwd) - { - if (exists(name)) - return 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 linux - struct stat st; - - if (stat(name, &st) < 0) - return 0; - if (S_ISDIR(st.st_mode)) - return 2; - return 1; -#endif -#if _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; -#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(p); - if (len > 2 && p[-1] == ':') - { mem.free(p); - return; - } -#endif - ensurePathExists(p); - mem.free(p); - } -#if _WIN32 - if (path[strlen(path) - 1] != '\\') -#endif -#if linux - if (path[strlen(path) - 1] != '\\') -#endif - { - //printf("mkdir(%s)\n", path); -#if _WIN32 - if (mkdir(path)) -#endif -#if linux - 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 linux - 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; -#endif -#if _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; -#endif -} - -/***************************** - * Read a file with memory mapped file I/O. - */ - -int File::mmread() -{ -#if linux - return read(); -#endif -#if _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 -#endif -} - -/********************************************* - * Write a file. - * Returns: - * 0 success - */ - -int File::write() -{ -#if linux - int fd; - ssize_t numwritten; - char *name; - - name = this->name->toChars(); - fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0660); - 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; -#endif -#if _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; -#endif -} - -/********************************************* - * Append to a file. - * Returns: - * 0 success - */ - -int File::append() -{ -#if linux - return 1; -#endif -#if _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; -#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 linux - return 0; -#endif -#if _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; -#endif -} - -void File::remove() -{ -#if linux - ::remove(this->name->toChars()); -#endif -#if _WIN32 - DeleteFileA(this->name->toChars()); -#endif -} - -Array *File::match(char *n) -{ - return match(new FileName(n, 0)); -} - -Array *File::match(FileName *n) -{ -#if linux - return NULL; -#endif -#if _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; -#endif -} - -int File::compareTime(File *f) -{ -#if linux - return 0; -#endif -#if _WIN32 - if (!touchtime) - stat(); - if (!f->touchtime) - f->stat(); - return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); -#endif -} - -void File::stat() -{ -#if linux - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(struct stat)); - } -#endif -#if _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); - } -#endif -} - -void File::checkoffset(size_t offset, size_t nbytes) -{ - if (offset > len || offset + nbytes > len) - error("Corrupt file '%s': offset x%"PRIxSIZE" 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(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(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); -} - -void OutBuffer::vprintf(const char *format, va_list args) -{ - char buffer[128]; - char *p; - unsigned psize; - int count; - - p = buffer; - psize = sizeof(buffer); - for (;;) - { -#if _WIN32 - count = _vsnprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#endif -#if linux - count = vsnprintf(p,psize,format,args); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#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; - - p = buffer; - psize = sizeof(buffer) / sizeof(buffer[0]); - for (;;) - { -#if _WIN32 - count = _vsnwprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#endif -#if linux - count = vsnwprintf(p,psize,format,args); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#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, char *left, unsigned j, 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-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 <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <stdint.h> +#include <assert.h> + +#if _MSC_VER ||__MINGW32__ +#include <malloc.h> +#endif + +#if _WIN32 +#include <windows.h> +#include <direct.h> +#endif + +#if linux +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <utime.h> +#endif + +#include "port.h" +#include "root.h" +#include "dchar.h" +#include "mem.h" +#include "mars.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 "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(char *path, char *name) +{ char *f; + size_t pathlen; + size_t namelen; + + if (!path || !*path) + return name; + pathlen = strlen(path); + namelen = strlen(name); + f = (char *)mem.malloc(pathlen + 1 + namelen + 1); + memcpy(f, path, pathlen); +#if linux + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#endif +#if _WIN32 + if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#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 linux + 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 linux + case '~': + buf.writestring(getenv("HOME")); + continue; +#endif + + case ' ': + case '\t': // tabs in filenames? + if (!instring) // if not in string + break; // treat as end of path + 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) +{ +#if _WIN32 + return stricmp(str,((FileName *)obj)->str); +#else + return String::compare(obj); +#endif +} + +int FileName::equals(Object *obj) +{ +#if _WIN32 + return stricmp(str,((FileName *)obj)->str) == 0; +#else + return String::equals(obj); +#endif +} + +/************************************ + * Return !=0 if absolute path name. + */ + +int FileName::absolute(const char *name) +{ +#if _WIN32 + return (*name == '\\') || + (*name == '/') || + (*name && name[1] == ':'); +#endif +#if linux + return (*name == '/'); +#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 linux + 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 linux + case '/': + return e + 1; +#endif +#if _WIN32 + case '\\': + case ':': + 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 linux + if (n[-1] == '/') + n--; +#endif +#if _WIN32 + if (n[-1] == '\\') + n--; +#endif + } + pathlen = n - str; + path = (char *)mem.malloc(pathlen + 1); + memcpy(path, str, pathlen); + path[pathlen] = 0; + return path; +} + +/************************************** + * Replace filename portion of path. + */ + +char *FileName::replaceName(char *path, 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 linux + if (path[pathlen - 1] != '/') + { f[pathlen] = '/'; + pathlen++; + } +#endif +#if _WIN32 + if (path[pathlen - 1] != '\\' && path[pathlen - 1] != ':') + { f[pathlen] = '\\'; + pathlen++; + } +#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 linux + return strcmp(e,ext) == 0; +#endif +#if _WIN32 + return stricmp(e,ext) == 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 +#endif +#if linux + file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time +#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, char *name, int cwd) +{ + if (absolute(name)) + { + return exists(name) ? name : NULL; + } + if (cwd) + { + if (exists(name)) + return 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 linux + struct stat st; + + if (stat(name, &st) < 0) + return 0; + if (S_ISDIR(st.st_mode)) + return 2; + return 1; +#endif +#if _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; +#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(p); + if (len > 2 && p[-1] == ':') + { mem.free(p); + return; + } +#endif + ensurePathExists(p); + mem.free(p); + } +#if _WIN32 + if (path[strlen(path) - 1] != '\\') +#endif +#if linux + if (path[strlen(path) - 1] != '\\') +#endif + { + //printf("mkdir(%s)\n", path); +#if _WIN32 + if (mkdir(path)) +#endif +#if linux + 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 linux + 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; +#endif +#if _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; +#endif +} + +/***************************** + * Read a file with memory mapped file I/O. + */ + +int File::mmread() +{ +#if linux + return read(); +#endif +#if _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 +#endif +} + +/********************************************* + * Write a file. + * Returns: + * 0 success + */ + +int File::write() +{ +#if linux + 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; +#endif +#if _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; +#endif +} + +/********************************************* + * Append to a file. + * Returns: + * 0 success + */ + +int File::append() +{ +#if linux + return 1; +#endif +#if _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; +#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 linux + return 0; +#endif +#if _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; +#endif +} + +void File::remove() +{ +#if linux + ::remove(this->name->toChars()); +#endif +#if _WIN32 + DeleteFileA(this->name->toChars()); +#endif +} + +Array *File::match(char *n) +{ + return match(new FileName(n, 0)); +} + +Array *File::match(FileName *n) +{ +#if linux + return NULL; +#endif +#if _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; +#endif +} + +int File::compareTime(File *f) +{ +#if linux + return 0; +#endif +#if _WIN32 + if (!touchtime) + stat(); + if (!f->touchtime) + f->stat(); + return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); +#endif +} + +void File::stat() +{ +#if linux + if (!touchtime) + { + touchtime = mem.calloc(1, sizeof(struct stat)); + } +#endif +#if _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); + } +#endif +} + +void File::checkoffset(size_t offset, size_t nbytes) +{ + if (offset > len || offset + nbytes > len) + error("Corrupt file '%s': offset x%"PRIxSIZE" 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(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); +} + +void OutBuffer::vprintf(const char *format, va_list args) +{ + char buffer[128]; + char *p; + unsigned psize; + int count; + + p = buffer; + psize = sizeof(buffer); + for (;;) + { +#if _WIN32 + count = _vsnprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#endif +#if linux + count = vsnprintf(p,psize,format,args); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#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; + + p = buffer; + psize = sizeof(buffer) / sizeof(buffer[0]); + for (;;) + { +#if _WIN32 + count = _vsnwprintf(p,psize,format,args); + if (count != -1) + break; + psize *= 2; +#endif +#if linux + count = vsnwprintf(p,psize,format,args); + if (count == -1) + psize *= 2; + else if (count >= psize) + psize = count + 1; + else + break; +#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, char *left, unsigned j, 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]; +} + + + + + + + + + + + + + + +
--- a/dmd/root.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/root.h Sat Jul 12 19:38:31 2008 +0200 @@ -125,6 +125,7 @@ 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 *); @@ -263,7 +264,7 @@ void reset(); void write(const void *data, unsigned nbytes); void writebstring(unsigned char *string); - void writestring(char *string); + void writestring(const char *string); void writedstring(const char *string); void writedstring(const wchar_t *string); void prependstring(char *string);
--- a/dmd/statement.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/statement.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,6 +1,6 @@ // Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com @@ -113,6 +113,16 @@ 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 may fall off the end without a throw or return int Statement::fallOffEnd() @@ -197,6 +207,25 @@ 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::fallOffEnd() { if (exp) @@ -237,15 +266,15 @@ buf->writenl(); } -Statement *CompileStatement::semantic(Scope *sc) +Statements *CompileStatement::flatten(Scope *sc) { - //printf("CompileStatement::semantic() %s\n", exp->toChars()); + //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 this; + return NULL; } StringExp *se = (StringExp *)exp; se = se->toUTF8(sc); @@ -253,14 +282,22 @@ p.loc = loc; p.nextToken(); - Statements *statements = new Statements(); + Statements *a = new Statements(); while (p.token.value != TOKeof) { Statement *s = p.parseStatement(PSsemi | PScurlyscope); - statements->push(s); + a->push(s); } - - Statement *s = new CompoundStatement(loc, statements); + 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); } @@ -468,7 +505,9 @@ i++; } if (statements->dim == 1 && !isAsmBlockStatement()) - return s; + { + return (Statement *)statements->data[0]; + } return this; } @@ -478,13 +517,11 @@ } ReturnStatement *CompoundStatement::isReturnStatement() -{ int i; +{ ReturnStatement *rs = NULL; - for (i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; if (s) { rs = s->isReturnStatement(); @@ -496,12 +533,9 @@ } void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ int i; - - for (i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[i]; +{ + for (int i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; if (s) s->toCBuffer(buf, hgs); } @@ -510,15 +544,38 @@ int CompoundStatement::usesEH() { for (int i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[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 (global.params.warnings) + { fprintf(stdmsg, "warning - "); + s->error("statement is not reachable"); + } + } + + result &= ~BEfallthru; + result |= s->blockExit(); + } + } + return result; +} + int CompoundStatement::fallOffEnd() { int falloff = TRUE; @@ -634,15 +691,27 @@ int UnrolledLoopStatement::usesEH() { for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (Statement *) statements->data[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::fallOffEnd() { //printf("UnrolledLoopStatement::fallOffEnd()\n"); @@ -655,7 +724,6 @@ return TRUE; } - int UnrolledLoopStatement::comeFrom() { int comefrom = FALSE; @@ -743,6 +811,12 @@ return statement ? statement->usesEH() : FALSE; } +int ScopeStatement::blockExit() +{ + //printf("ScopeStatement::blockExit(%p)\n", statement); + return statement ? statement->blockExit() : BEfallthru; +} + int ScopeStatement::fallOffEnd() { return statement ? statement->fallOffEnd() : TRUE; @@ -844,6 +918,35 @@ return body ? body->usesEH() : 0; } +int WhileStatement::blockExit() +{ + //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::fallOffEnd() { if (body) @@ -917,6 +1020,28 @@ 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::fallOffEnd() { if (body) @@ -1024,6 +1149,31 @@ 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; + } + else + result &= ~BEfallthru; // the body must do the exiting + if (body) + { int r = body->blockExit(); + if (r & BEbreak) + result |= BEfallthru; + result |= r & ~(BEbreak | BEcontinue); + } + if (increment && increment->canThrow()) + result |= BEthrow; + return result; +} + int ForStatement::fallOffEnd() { if (body) @@ -1216,10 +1366,6 @@ VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); if (e->isConst()) v->storage_class |= STCconst; -#if V2 - else - v->storage_class |= STCfinal; -#endif var = v; } } @@ -1589,6 +1735,19 @@ 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::fallOffEnd() { if (body) @@ -1607,7 +1766,6 @@ { buf->writestring(Token::toChars(op)); buf->writestring(" ("); - int i; for (int i = 0; i < arguments->dim; i++) { Argument *a = (Argument *)arguments->data[i]; @@ -1718,6 +1876,42 @@ 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; +} + int IfStatement::fallOffEnd() { if (!ifbody || ifbody->fallOffEnd() || @@ -1812,13 +2006,21 @@ { 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(); } @@ -1908,6 +2110,18 @@ 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; +} + int PragmaStatement::fallOffEnd() { if (body) @@ -2097,6 +2311,24 @@ 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; +} + int SwitchStatement::fallOffEnd() { if (body) @@ -2204,6 +2436,11 @@ return statement->usesEH(); } +int CaseStatement::blockExit() +{ + return statement->blockExit(); +} + int CaseStatement::fallOffEnd() { return statement->fallOffEnd(); @@ -2243,6 +2480,7 @@ Statement *DefaultStatement::semantic(Scope *sc) { + //printf("DefaultStatement::semantic()\n"); if (sc->sw) { if (sc->sw->sdefault) @@ -2262,6 +2500,11 @@ return statement->usesEH(); } +int DefaultStatement::blockExit() +{ + return statement->blockExit(); +} + int DefaultStatement::fallOffEnd() { return statement->fallOffEnd(); @@ -2302,6 +2545,11 @@ return this; } +int GotoDefaultStatement::blockExit() +{ + return BEgoto; +} + int GotoDefaultStatement::fallOffEnd() { return FALSE; @@ -2351,6 +2599,11 @@ return this; } +int GotoCaseStatement::blockExit() +{ + return BEgoto; +} + int GotoCaseStatement::fallOffEnd() { return FALSE; @@ -2374,6 +2627,11 @@ { } +int SwitchErrorStatement::blockExit() +{ + return BEthrow; +} + int SwitchErrorStatement::fallOffEnd() { return FALSE; @@ -2427,6 +2685,8 @@ 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; @@ -2636,9 +2896,13 @@ } if (exp && tbret->ty == Tvoid && !fd->isMain()) - { Statement *s; - - s = new ExpStatement(loc, exp); + { + /* Replace: + * return exp; + * with: + * exp; return; + */ + Statement *s = new ExpStatement(loc, exp); loc = 0; exp = NULL; return new CompoundStatement(loc, s, this); @@ -2647,6 +2911,14 @@ return this; } +int ReturnStatement::blockExit() +{ int result = BEreturn; + + if (exp && exp->canThrow()) + result |= BEthrow; + return result; +} + int ReturnStatement::fallOffEnd() { return FALSE; @@ -2678,6 +2950,7 @@ Statement *BreakStatement::semantic(Scope *sc) { + //printf("BreakStatement::semantic()\n"); enclosinghandler = sc->tfOfTry; // If: // break Identifier; @@ -2739,6 +3012,12 @@ return this; } +int BreakStatement::blockExit() +{ + //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); + return ident ? BEgoto : BEbreak; +} + int BreakStatement::fallOffEnd() { return FALSE; @@ -2842,6 +3121,11 @@ return this; } +int ContinueStatement::blockExit() +{ + return ident ? BEgoto : BEcontinue; +} + int ContinueStatement::fallOffEnd() { return FALSE; @@ -2932,6 +3216,11 @@ return TRUE; } +int SynchronizedStatement::blockExit() +{ + return body ? body->blockExit() : BEfallthru; +} + int SynchronizedStatement::fallOffEnd() { return body ? body->fallOffEnd() : TRUE; @@ -3042,6 +3331,18 @@ 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; +} + int WithStatement::fallOffEnd() { return body ? body->fallOffEnd() : TRUE; @@ -3075,14 +3376,14 @@ { body = body->semanticScope(sc, NULL /*this*/, NULL); - for (int i = 0; i < catches->dim; i++) - { Catch *c; - - c = (Catch *)catches->data[i]; + /* 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 (int j = 0; j < i; j++) + for (size_t j = 0; j < i; j++) { Catch *cj = (Catch *)catches->data[j]; char *si = c->loc.toChars(); char *sj = cj->loc.toChars(); @@ -3104,6 +3405,20 @@ return TRUE; } +int TryCatchStatement::blockExit() +{ int result; + + assert(body); + result = body->blockExit(); + + for (size_t i = 0; i < catches->dim; i++) + { + Catch *c = (Catch *)catches->data[i]; + result |= c->blockExit(); + } + return result; +} + int TryCatchStatement::fallOffEnd() { int result = FALSE; @@ -3126,8 +3441,7 @@ buf->writenl(); if (body) body->toCBuffer(buf, hgs); - int i; - for (i = 0; i < catches->dim; i++) + for (size_t i = 0; i < catches->dim; i++) { Catch *c = (Catch *)catches->data[i]; c->toCBuffer(buf, hgs); @@ -3193,6 +3507,11 @@ sc->pop(); } +int Catch::blockExit() +{ + return handler ? handler->blockExit() : BEfallthru; +} + void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("catch"); @@ -3204,7 +3523,8 @@ buf->writenl(); buf->writebyte('{'); buf->writenl(); - handler->toCBuffer(buf, hgs); + if (handler) + handler->toCBuffer(buf, hgs); buf->writebyte('}'); buf->writenl(); } @@ -3269,6 +3589,12 @@ return TRUE; } +int TryFinallyStatement::blockExit() +{ + int result = body->blockExit(); + return result; +} + int TryFinallyStatement::fallOffEnd() { int result; @@ -3300,6 +3626,11 @@ 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)); @@ -3391,6 +3722,11 @@ return this; } +int ThrowStatement::blockExit() +{ + return BEthrow; // obviously +} + int ThrowStatement::fallOffEnd() { return FALSE; @@ -3449,6 +3785,11 @@ return a; } +int VolatileStatement::blockExit() +{ + return statement ? statement->blockExit() : BEfallthru; +} + int VolatileStatement::fallOffEnd() { return statement ? statement->fallOffEnd() : TRUE; @@ -3512,6 +3853,12 @@ return this; } +int GotoStatement::blockExit() +{ + //printf("GotoStatement::blockExit(%p)\n", this); + return BEgoto; +} + int GotoStatement::fallOffEnd() { return FALSE; @@ -3601,6 +3948,12 @@ return statement ? statement->usesEH() : FALSE; } +int LabelStatement::blockExit() +{ + //printf("LabelStatement::blockExit(%p)\n", this); + return statement ? statement->blockExit() : BEfallthru; +} + int LabelStatement::fallOffEnd() { return statement ? statement->fallOffEnd() : TRUE;
--- a/dmd/statement.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/statement.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,848 +1,926 @@ - -// 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_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; -struct AsmBlockStatement; -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct HdrGenState; -struct InterState; -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; - -enum TOK; - -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} - -// 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; - -// LLVMDC this is used for tracking try-finally, synchronized and volatile scopes -// definitions in gen/llvmhelpers.cpp -struct EnclosingHandler : Object -{ - virtual void emitCode(IRState* p) = 0; - virtual EnclosingHandler* getEnclosing() = 0; -}; -struct EnclosingTryFinally : EnclosingHandler -{ - TryFinallyStatement* tf; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {} -}; -struct EnclosingVolatile : EnclosingHandler -{ - VolatileStatement* v; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {} -}; -struct EnclosingSynchro : EnclosingHandler -{ - SynchronizedStatement* s; - void emitCode(IRState* p); - EnclosingHandler* getEnclosing(); - EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {} -}; - -struct Statement : Object -{ - Loc loc; - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...); - 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; } -#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 fallOffEnd(); - virtual int comeFrom(); - virtual void scopeCode(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; } -}; - -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 fallOffEnd(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct CompileStatement : Statement -{ - Expression *exp; - - CompileStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - 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(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); - Statement *semantic(Scope *sc); - int usesEH(); - int fallOffEnd(); - int comeFrom(); - 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); - - virtual CompoundStatement *isCompoundStatement() { return this; } -}; - -/* 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; - EnclosingHandler* enclosinghandler; - - UnrolledLoopStatement(Loc loc, Statements *statements); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - 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 fallOffEnd(); - int comeFrom(); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct WhileStatement : Statement -{ - Expression *condition; - Statement *body; - EnclosingHandler* enclosinghandler; - - WhileStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - 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; - EnclosingHandler* enclosinghandler; - - DoStatement(Loc loc, Statement *b, Expression *c); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - 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; - EnclosingHandler* enclosinghandler; - - ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - 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; - EnclosingHandler* enclosinghandler; - - 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); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -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 fallOffEnd(); - 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(); - - 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 fallOffEnd(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -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; - DefaultStatement *sdefault; - EnclosingHandler* enclosinghandler; - - Array gotoCases; // array of unresolved GotoCaseStatement's - Array *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - - SwitchStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int fallOffEnd(); - 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 - - CaseStatement(Loc loc, Expression *exp, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int compare(Object *obj); - int usesEH(); - int fallOffEnd(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - CaseStatement* isCaseStatement() { return this; } - - // LLVMDC - llvm::BasicBlock* bodyBB; - llvm::ConstantInt* llvmIdx; -}; - -struct DefaultStatement : Statement -{ - Statement *statement; -#if IN_GCC - block *cblock; // back end: label for the block -#endif - - DefaultStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int fallOffEnd(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LLVMDC - llvm::BasicBlock* bodyBB; -}; - -struct GotoDefaultStatement : Statement -{ - SwitchStatement *sw; - EnclosingHandler* enclosinghandler; - - GotoDefaultStatement(Loc loc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int fallOffEnd(); - 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 - EnclosingHandler* enclosinghandler; - SwitchStatement *sw; - - GotoCaseStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int fallOffEnd(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct SwitchErrorStatement : Statement -{ - SwitchErrorStatement(Loc loc); - int fallOffEnd(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct ReturnStatement : Statement -{ - Expression *exp; - EnclosingHandler* enclosinghandler; - - ReturnStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int fallOffEnd(); - 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; - EnclosingHandler* enclosinghandler; - - BreakStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int fallOffEnd(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LLVMDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct ContinueStatement : Statement -{ - Identifier *ident; - EnclosingHandler* enclosinghandler; - - ContinueStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int fallOffEnd(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - - // LLVMDC: only set if ident is set: label statement to jump to - LabelStatement *target; -}; - -struct SynchronizedStatement : Statement -{ - Expression *exp; - Statement *body; - EnclosingHandler* enclosinghandler; - - SynchronizedStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int fallOffEnd(); - 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); - llvm::Value* llsync; -}; - -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 fallOffEnd(); - - 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 fallOffEnd(); - - 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); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TryFinallyStatement : Statement -{ - Statement *body; - Statement *finalbody; - EnclosingHandler* enclosinghandler; - - 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 fallOffEnd(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct OnScopeStatement : Statement -{ - TOK tok; - Statement *statement; - - OnScopeStatement(Loc loc, TOK tok, Statement *statement); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int usesEH(); - void scopeCode(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 fallOffEnd(); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct VolatileStatement : Statement -{ - Statement *statement; - EnclosingHandler* enclosinghandler; - - VolatileStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int fallOffEnd(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct GotoStatement : Statement -{ - Identifier *ident; - LabelDsymbol *label; - TryFinallyStatement *tf; - EnclosingHandler* enclosinghandler; - - GotoStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int fallOffEnd(); - 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 *tf; - EnclosingHandler* enclosinghandler; - 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 fallOffEnd(); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - // LLVMDC - llvm::BasicBlock* llvmBB; - bool asmLabel; // for labels inside inline assembler -}; - -struct LabelDsymbol : Dsymbol -{ - LabelStatement *statement; - - 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 comeFrom(); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmStatement *isAsmStatement() { return this; } - - void toIR(IRState *irs); - - // LLVMDC - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; -}; - -struct AsmBlockStatement : CompoundStatement -{ - EnclosingHandler* enclosinghandler; - - 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); -}; - -#endif /* DMD_STATEMENT_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_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; +struct AsmBlockStatement; +struct GotoStatement; +struct ScopeStatement; +struct TryCatchStatement; +struct TryFinallyStatement; +struct HdrGenState; +struct InterState; +struct CaseStatement; +struct LabelStatement; +struct VolatileStatement; +struct SynchronizedStatement; + +enum TOK; + +namespace llvm +{ + class Value; + class BasicBlock; + class ConstantInt; +} + +// 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 + */ +enum BE +{ + BEnone = 0, + BEfallthru = 1, + BEthrow = 2, + BEreturn = 4, + BEgoto = 8, + BEhalt = 0x10, + BEbreak = 0x20, + BEcontinue = 0x40, + BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), +}; + +// LLVMDC this is used for tracking try-finally, synchronized and volatile scopes +// definitions in gen/llvmhelpers.cpp +struct EnclosingHandler : Object +{ + virtual void emitCode(IRState* p) = 0; + virtual EnclosingHandler* getEnclosing() = 0; +}; +struct EnclosingTryFinally : EnclosingHandler +{ + TryFinallyStatement* tf; + void emitCode(IRState* p); + EnclosingHandler* getEnclosing(); + EnclosingTryFinally(TryFinallyStatement* _tf) : tf(_tf) {} +}; +struct EnclosingVolatile : EnclosingHandler +{ + VolatileStatement* v; + void emitCode(IRState* p); + EnclosingHandler* getEnclosing(); + EnclosingVolatile(VolatileStatement* _tf) : v(_tf) {} +}; +struct EnclosingSynchro : EnclosingHandler +{ + SynchronizedStatement* s; + void emitCode(IRState* p); + EnclosingHandler* getEnclosing(); + EnclosingSynchro(SynchronizedStatement* _tf) : s(_tf) {} +}; + +struct Statement : Object +{ + Loc loc; + + Statement(Loc loc); + virtual Statement *syntaxCopy(); + + void print(); + char *toChars(); + + void error(const char *format, ...); + 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; } +#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 fallOffEnd(); + virtual int blockExit(); + virtual int comeFrom(); + virtual void scopeCode(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; } +}; + +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 fallOffEnd(); + int blockExit(); + + int inlineCost(InlineCostState *ics); + Expression *doInline(InlineDoState *ids); + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +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(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 fallOffEnd(); + int comeFrom(); + 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); + + virtual CompoundStatement *isCompoundStatement() { return this; } +}; + +/* 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; + EnclosingHandler* enclosinghandler; + + UnrolledLoopStatement(Loc loc, Statements *statements); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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 fallOffEnd(); + int comeFrom(); + Expression *interpret(InterState *istate); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct WhileStatement : Statement +{ + Expression *condition; + Statement *body; + EnclosingHandler* enclosinghandler; + + WhileStatement(Loc loc, Expression *c, Statement *b); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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; + EnclosingHandler* enclosinghandler; + + DoStatement(Loc loc, Statement *b, Expression *c); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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; + EnclosingHandler* enclosinghandler; + + ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + void scopeCode(Statement **sentry, Statement **sexit, Statement **sfinally); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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; + EnclosingHandler* enclosinghandler; + + 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); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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 fallOffEnd(); + 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(); + int fallOffEnd(); + 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(); + + 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(); + int fallOffEnd(); + + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); +}; + +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; + + DefaultStatement *sdefault; + EnclosingHandler* enclosinghandler; + + Array gotoCases; // array of unresolved GotoCaseStatement's + Array *cases; // array of CaseStatement's + int hasNoDefault; // !=0 if no default statement + + SwitchStatement(Loc loc, Expression *c, Statement *b); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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 + + CaseStatement(Loc loc, Expression *exp, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int compare(Object *obj); + int usesEH(); + int blockExit(); + int fallOffEnd(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + CaseStatement* isCaseStatement() { return this; } + + // LLVMDC + llvm::BasicBlock* bodyBB; + llvm::ConstantInt* llvmIdx; +}; + +struct DefaultStatement : Statement +{ + Statement *statement; +#if IN_GCC + block *cblock; // back end: label for the block +#endif + + DefaultStatement(Loc loc, Statement *s); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int usesEH(); + int blockExit(); + int fallOffEnd(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + // LLVMDC + llvm::BasicBlock* bodyBB; +}; + +struct GotoDefaultStatement : Statement +{ + SwitchStatement *sw; + EnclosingHandler* enclosinghandler; + + GotoDefaultStatement(Loc loc); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int fallOffEnd(); + 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 + EnclosingHandler* enclosinghandler; + SwitchStatement *sw; + + GotoCaseStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int fallOffEnd(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct SwitchErrorStatement : Statement +{ + SwitchErrorStatement(Loc loc); + int blockExit(); + int fallOffEnd(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); +}; + +struct ReturnStatement : Statement +{ + Expression *exp; + EnclosingHandler* enclosinghandler; + + ReturnStatement(Loc loc, Expression *exp); + Statement *syntaxCopy(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + Statement *semantic(Scope *sc); + int blockExit(); + int fallOffEnd(); + 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; + EnclosingHandler* enclosinghandler; + + BreakStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int fallOffEnd(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + + // LLVMDC: only set if ident is set: label statement to jump to + LabelStatement *target; +}; + +struct ContinueStatement : Statement +{ + Identifier *ident; + EnclosingHandler* enclosinghandler; + + ContinueStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Expression *interpret(InterState *istate); + int blockExit(); + int fallOffEnd(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + void toIR(IRState *irs); + + // LLVMDC: only set if ident is set: label statement to jump to + LabelStatement *target; +}; + +struct SynchronizedStatement : Statement +{ + Expression *exp; + Statement *body; + EnclosingHandler* enclosinghandler; + + SynchronizedStatement(Loc loc, Expression *exp, Statement *body); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int hasBreak(); + int hasContinue(); + int usesEH(); + int blockExit(); + int fallOffEnd(); + 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); + llvm::Value* llsync; +}; + +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(); + int fallOffEnd(); + + 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(); + int fallOffEnd(); + + 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; + EnclosingHandler* enclosinghandler; + + 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(); + int fallOffEnd(); + + 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(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(); + int fallOffEnd(); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct VolatileStatement : Statement +{ + Statement *statement; + EnclosingHandler* enclosinghandler; + + VolatileStatement(Loc loc, Statement *statement); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + Statements *flatten(Scope *sc); + int blockExit(); + int fallOffEnd(); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); +}; + +struct GotoStatement : Statement +{ + Identifier *ident; + LabelDsymbol *label; + TryFinallyStatement *tf; + EnclosingHandler* enclosinghandler; + + GotoStatement(Loc loc, Identifier *ident); + Statement *syntaxCopy(); + Statement *semantic(Scope *sc); + int blockExit(); + int fallOffEnd(); + 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 *tf; + EnclosingHandler* enclosinghandler; + 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 fallOffEnd(); + int comeFrom(); + Expression *interpret(InterState *istate); + void toCBuffer(OutBuffer *buf, HdrGenState *hgs); + + Statement *inlineScan(InlineScanState *iss); + + void toIR(IRState *irs); + + // LLVMDC + llvm::BasicBlock* llvmBB; + bool asmLabel; // for labels inside inline assembler +}; + +struct LabelDsymbol : Dsymbol +{ + LabelStatement *statement; + + 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); + + // LLVMDC + // non-zero if this is a branch, contains the target labels identifier + Identifier* isBranchToLabel; +}; + +struct AsmBlockStatement : CompoundStatement +{ + EnclosingHandler* enclosinghandler; + + 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); +}; + +#endif /* DMD_STATEMENT_H */
--- a/dmd/staticassert.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/staticassert.c Sat Jul 12 19:38:31 2008 +0200 @@ -86,11 +86,11 @@ { } -void StaticAssert::toObjFile() +void StaticAssert::toObjFile(int multiobj) { } -char *StaticAssert::kind() +const char *StaticAssert::kind() { return "static assert"; }
--- a/dmd/staticassert.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/staticassert.h Sat Jul 12 19:38:31 2008 +0200 @@ -35,8 +35,8 @@ void semantic2(Scope *sc); void inlineScan(); int oneMember(Dsymbol **ps); - void toObjFile(); - char *kind(); + void toObjFile(int multiobj); + const char *kind(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); };
--- a/dmd/stringtable.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/stringtable.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,8 +1,8 @@ -// Copyright (c) 1999-2006 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright -// www.digitalmars.com +// 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.
--- a/dmd/stringtable.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/stringtable.h Sat Jul 12 19:38:31 2008 +0200 @@ -1,7 +1,7 @@ -// Copyright (c) 1999-2002 by Digital Mars +// Copyright (c) 1999-2008 by Digital Mars // All Rights Reserved // written by Walter Bright -// www.digitalmars.com +// 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.
--- a/dmd/struct.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/struct.c Sat Jul 12 19:38:31 2008 +0200 @@ -254,6 +254,8 @@ handle = type->pointerTo(); structalign = sc->structalign; protection = sc->protection; + if (sc->stc & STCdeprecated) + isdeprecated = 1; assert(!isAnonymous()); if (sc->stc & STCabstract) error("structs, unions cannot be abstract"); @@ -450,7 +452,7 @@ } -char *StructDeclaration::kind() +const char *StructDeclaration::kind() { return "struct"; } @@ -475,7 +477,7 @@ } -char *UnionDeclaration::kind() +const char *UnionDeclaration::kind() { return "union"; }
--- a/dmd/template.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/template.c Sat Jul 12 19:38:31 2008 +0200 @@ -1,4159 +1,4296 @@ - -// 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. - -// Handle template implementation - -#include <stdio.h> -#include <assert.h> - -#if !IN_LLVM -#if _WIN32 -#include <windows.h> -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif -#endif - -#include "root.h" -#include "mem.h" -#include "stringtable.h" -#include "mars.h" -#include "identifier.h" -#include "mtype.h" -#include "template.h" -#include "init.h" -#include "expression.h" -#include "scope.h" -#include "module.h" -#include "aggregate.h" -#include "declaration.h" -#include "dsymbol.h" -#include "hdrgen.h" - -#define LOG 0 - -/******************************************** - * These functions substitute for dynamic_cast. dynamic_cast does not work - * on earlier versions of gcc. - */ - -Expression *isExpression(Object *o) -{ - //return dynamic_cast<Expression *>(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(Object *o) -{ - //return dynamic_cast<Dsymbol *>(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(Object *o) -{ - //return dynamic_cast<Type *>(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(Object *o) -{ - //return dynamic_cast<Tuple *>(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - - -/*********************** - * Try to get arg as a type. - */ - -Type *getType(Object *o) -{ - Type *t = isType(o); - if (!t) - { Expression *e = isExpression(o); - if (e) - t = e->type; - } - return t; -} - -Dsymbol *getDsymbol(Object *oarg) -{ - Dsymbol *sa; - 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; - } - 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 - } - return sa; -} - -/****************************** - * If o1 matches o2, return 1. - * Else, return 0. - */ - -int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) -{ - Type *t1 = isType(o1); - Type *t2 = isType(o2); - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(o2); - Dsymbol *s1 = isDsymbol(o1); - Dsymbol *s2 = isDsymbol(o2); - Tuple *v1 = isTuple(o1); - Tuple *v2 = isTuple(o2); - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); - - /* A proper implementation of the various equals() overrides - * should make it possible to just do o1->equals(o2), but - * we'll do that another day. - */ - - 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 (!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(); - } -#endif - 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; - } - } - 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; - } - } - return 1; // match -Lnomatch: - return 0; // nomatch; -} - -/**************************************** - */ - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) -{ - //printf("ObjectToCBuffer()\n"); - Type *t = isType(oarg); - Expression *e = isExpression(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); - } - else if (e) - e->toCBuffer(buf, hgs); - else if (s) - { - 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); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs) - : ScopeDsymbol(id) -{ -#if LOG - printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); -#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(); - - if (ttp) - { - printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); - } - } -#endif - this->loc = loc; - this->parameters = parameters; - this->origParameters = parameters; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->scope = NULL; - this->onemember = NULL; -} - -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(); - } - } - d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, d); - return td; -} - -void TemplateDeclaration::semantic(Scope *sc) -{ -#if LOG - printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); -#endif - if (scope) - return; // semantic() already run - - if (sc->func) - { - error("cannot declare template at function scope %s", sc->func->toChars()); - } - - if (/*global.params.useArrayBounds &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - sc->module->toModuleArray(); - } - - if (/*global.params.useAssert &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - sc->module->toModuleAssert(); - } - - /* Remember Scope for later instantiations, but make - * a copy since attributes can change. - */ - this->scope = new Scope(*sc); - this->scope->setNoFree(); - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = sc->parent; - Scope *paramscope = sc->push(paramsym); - paramscope->parameterSpecialization = 1; - - 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(); - } - } - - for (int i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - tp->declareParameter(paramscope); - } - - for (int i = 0; i < parameters->dim; 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"); - } - - paramscope->pop(); - - if (members) - { - 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 - */ -} - -char *TemplateDeclaration::kind() -{ - return (onemember && onemember->isAggregateDeclaration()) - ? onemember->kind() - : (char *)"template"; -} - -/********************************** - * Overload existing TemplateDeclaration 'this' with the new one 's'. - * Return !=0 if successful; i.e. no conflict. - */ - -int TemplateDeclaration::overloadInsert(Dsymbol *s) -{ - TemplateDeclaration **pf; - TemplateDeclaration *f; - -#if LOG - printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); -#endif - f = s->isTemplateDeclaration(); - if (!f) - 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; - - 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]; - - if (!p1->overloadMatch(p2)) - goto Lcontinue; - } - -#if LOG - printf("\tfalse: conflict\n"); -#endif - return FALSE; - - Lcontinue: - ; -#endif - } - - f->overroot = this; - *pf = f; -#if LOG - printf("\ttrue: no conflict\n"); -#endif - return TRUE; -} - -/*************************************** - * 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() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, int flag) -{ MATCH m; - int dedtypes_dim = dedtypes->dim; - -#define LOGM 0 -#if LOGM - printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); -#endif - -#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]); -#endif - dedtypes->zero(); - - int parameters_dim = parameters->dim; - int variadic = isVariadic() != NULL; - - // If more arguments than parameters, no match - if (ti->tiargs->dim > parameters_dim && !variadic) - { -#if LOGM - printf(" no match: more arguments than parameters\n"); -#endif - return MATCHnomatch; - } - - assert(dedtypes_dim == parameters_dim); - assert(dedtypes_dim >= ti->tiargs->dim || variadic); - - // Set up scope for parameters - assert((size_t)scope > 0x10000); - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - - // Attempt type deduction - m = MATCHexact; - for (int i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Declaration *sparam; - - //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() : ""); -#endif - - m2 = tp->matchArg(paramscope, ti->tiargs, i, parameters, dedtypes, &sparam); - //printf("\tm2 = %d\n", m2); - - if (m2 == MATCHnomatch) - { -#if 0 - printf("\tmatchArg() for parameter %i failed\n", i); -#endif - goto Lnomatch; - } - - if (m2 < m) - m = m2; - - 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]; - } - } - } - -#if LOGM - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti->toChars()); - if (m) - { - for (int i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - Object *oarg; - - printf(" [%d]", 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; -#endif - -#if LOGM - printf(" match = %d\n", m); -#endif - goto Lret; - -Lnomatch: -#if LOGM - printf(" no match\n"); -#endif - m = MATCHnomatch; - -Lret: - paramscope->pop(); -#if LOGM - printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); -#endif - return m; -} - -/******************************************** - * Determine partial specialization order of 'this' vs td2. - * Returns: - * 1 this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) -{ - /* This works by taking the template parameters to this template - * declaration and feeding them to td2 as if it were a template - * instance. - * If it works, then this template is at least as specialized - * as td2. - */ - - TemplateInstance ti(0, ident); // create dummy template instance - Objects dedtypes; - -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); -#endif - - // Set type arguments to dummy template instance to be types - // generated from the parameters to this template declaration - ti.tiargs = new Objects(); - ti.tiargs->setDim(parameters->dim); - for (int i = 0; i < ti.tiargs->dim; i++) - { - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - void *p = tp->dummyArg(); - if (p) - ti.tiargs->data[i] = p; - else - ti.tiargs->setDim(i); - } - - // Temporary Array to hold deduced types - //dedtypes.setDim(parameters->dim); - dedtypes.setDim(td2->parameters->dim); - - // Attempt a type deduction - if (td2->matchWithInstance(&ti, &dedtypes, 1)) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#if LOG_LEASTAS - printf(" matches, so is least as specialized\n"); -#endif - return 1; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return 0; -} - - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * targsi Expression/Type initial list of template arguments - * fargs arguments to function - * Output: - * dedargs Expression/Type deduced template arguments - * Returns: - * match level - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, - Objects *dedargs) -{ - size_t i; - size_t nfparams; - size_t nfargs; - size_t nargsi; // array size of targsi - int fptupindex = -1; - int tuple_dim = 0; - MATCH match = MATCHexact; - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - TypeFunction *fdtype; // type of fd - TemplateTupleParameter *tp; - 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()); - } -#endif - - assert((size_t)scope > 0x10000); - - dedargs->setDim(parameters->dim); - dedargs->zero(); - - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - // Set up scope for parameters - ScopeDsymbol *paramsym = new ScopeDsymbol(); - paramsym->parent = scope->parent; - Scope *paramscope = scope->push(paramsym); - - tp = isVariadic(); - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - if (nargsi > parameters->dim) - { if (!tp) - goto Lnomatch; - dedargs->setDim(nargsi); - dedargs->zero(); - } - - memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); - - for (i = 0; i < nargsi; i++) - { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - MATCH m; - Declaration *sparam; - - 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; - } - } - - assert(fd->type->ty == Tfunction); - fdtype = (TypeFunction *)fd->type; - - nfparams = Argument::dim(fdtype->parameters); // number of function parameters - nfargs = fargs->dim; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * template Foo(T, A...) { void Foo(T t, A a); } - * void main() { Foo(1,2,3); } - */ - tp = isVariadic(); - 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; - 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 *)fdtype->parameters->data[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fdtype->varargs) // 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; - - 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; - } - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fdtype->varargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -L2: - // Loop through the function parameters - for (i = 0; i < nfparams; i++) - { - /* 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; - } - - Argument *fparam = Argument::getNth(fdtype->parameters, 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()); -#endif - - MATCH m; - m = farg->type->deduceType(scope, 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 (!tf->varargs && Argument::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(scope, 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 (!(fdtype->varargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *t = fparam->type; - switch (t->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - case Tarray: - case Tclass: - case Tident: - goto Lmatch; - - 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) - { - 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); - //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(paramscope); - if (!oded) - goto Lnomatch; - } - declareParameter(paramscope, tp, oded); - dedargs->data[i] = (void *)oded; - } - } - -#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()); - } -#endif - - paramscope->pop(); - //printf("\tmatch %d\n", match); - return match; - -Lnomatch: - paramscope->pop(); - //printf("\tnomatch\n"); - return MATCHnomatch; -} - -/************************************************** - * Declare template parameter tp with value o. - */ - -void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) -{ - //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); - - Type *targ = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - - Dsymbol *s; - - if (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); - } - else if (ea) - { - // tdtypes.data[i] always matches ea here - Initializer *init = new ExpInitializer(loc, ea); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - - VarDeclaration *v = new VarDeclaration(0, tvp->valType, tp->ident, init); - v->storage_class = STCconst; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - else - { -#ifdef DEBUG - o->print(); -#endif - assert(0); - } - if (!sc->insert(s)) - error("declaration %s is already defined", tp->ident->toChars()); - s->semantic(sc); -} - -/************************************** - * Determine if TemplateDeclaration is variadic. - */ - -TemplateTupleParameter *isVariadic(TemplateParameters *parameters) -{ size_t dim = parameters->dim; - TemplateTupleParameter *tp = NULL; - - if (dim) - tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); - return tp; -} - -TemplateTupleParameter *TemplateDeclaration::isVariadic() -{ - return ::isVariadic(parameters); -} - -/*********************************** - * We can overload templates. - */ - -int TemplateDeclaration::isOverloadable() -{ - return 1; -} - -/************************************************* - * Given function arguments, figure out which template function - * to expand, and return that function. - * If no match, give error message and return NULL. - * Input: - * targsi initial list of template arguments - * fargs arguments to function - */ - -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expressions *fargs) -{ - MATCH m_best = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd; - -#if 0 - 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()); - } - } - 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); - } -#endif - - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - if (!td->scope) - { - 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; - - m = td->deduceFunctionTemplateMatch(targsi, 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; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - int c1 = td->leastAsSpecialized(td_best); - int 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; - } - - 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: // 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) - { - error(loc, "does not match any template declaration"); - goto Lerror; - } - if (td_ambig) - { - error(loc, "%s matches more than one function template declaration, %s and %s", - toChars(), td_best->toChars(), td_ambig->toChars()); - } - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert((size_t)td_best->scope > 0x10000); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc); - fd = ti->toAlias()->isFuncDeclaration(); - if (!fd) - goto Lerror; - return fd; - - Lerror: - { - OutBuffer buf; - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, fargs, &hgs); - error(loc, "cannot deduce template function from argument types (%s)", - buf.toChars()); - return NULL; - } -} - -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - buf->writestring(kind()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - 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); - } - buf->writeByte(')'); - - 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--; - } -} - - -char *TemplateDeclaration::toChars() -{ OutBuffer buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf.writestring(ident->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); - } - buf.writeByte(')'); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ======================== Type ============================================ */ - -/**** - * Given an identifier, figure out which TemplateParameter it is. - * Return -1 if not found. - */ - -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; - } - return -1; -} - -int templateParameterLookup(Type *tparam, TemplateParameters *parameters) -{ - assert(tparam->ty == Tident); - TypeIdentifier *tident = (TypeIdentifier *)tparam; - //printf("\ttident = '%s'\n", tident->toChars()); - if (tident->idents.dim == 0) - { - return templateIdentifierLookup(tident->ident, parameters); - } - return -1; -} - -/* These form the heart of template argument deduction. - * Given 'this' being the type argument to the template instance, - * 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 - * Input: - * this = int* - * tparam = T - * parameters = [ T:T* ] // Array of TemplateParameter's - * Output: - * dedtypes = [ int ] // Array of Expression/Type's - */ - -MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ - //printf("Type::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - if (!tparam) - goto Lnomatch; - - if (this == tparam) - goto Lexact; - - if (tparam->ty == Tident) - { - // Determine which parameter tparam is - int i = templateParameterLookup(tparam, parameters); - if (i == -1) - { - if (!sc) - goto Lnomatch; - /* BUG: what if tparam is a template instance, that - * has as an argument another Tident? - */ - tparam = tparam->semantic(0, sc); - assert(tparam->ty != Tident); - return deduceType(sc, tparam, parameters, dedtypes); - } - - TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *at = (Type *)dedtypes->data[i]; - if (!at) - { - dedtypes->data[i] = (void *)this; - goto Lexact; - } - if (equals(at)) - goto Lexact; - else if (ty == Tclass && at->ty == Tclass) - { - return (MATCH) implicitConvTo(at); - } - else if (ty == Tsarray && at->ty == Tarray && - nextOf()->equals(at->nextOf())) - { - goto Lexact; - } - else - goto Lnomatch; - } - - if (ty != tparam->ty) - goto Lnomatch; - - if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); - -Lexact: - return MATCHexact; - -Lnomatch: - return MATCHnomatch; -} - -MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ -#if 0 - printf("TypeSArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // Extra check that array dimensions must match - if (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 (tident->idents.dim == 0) - { Identifier *id = tident->ident; - - 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 (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; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ -#if 0 - printf("TypeAArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // 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; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeFunction::deduceType()\n"); - //printf("\tthis = %d, ", ty); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // 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; - - size_t nfargs = Argument::dim(this->parameters); - size_t nfparams = Argument::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 *)tp->parameters->data[nfparams - 1]; - 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; - } - - /* 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; - } - - L1: - 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; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - 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]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes) -{ - //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars()); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - // Extra check - if (tparam && tparam->ty == Tinstance) - { - 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; - Dsymbol *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if (dedtypes->data[i]) - { // Must match already deduced symbol - Dsymbol *s = (Dsymbol *)dedtypes->data[i]; - - if (s != sa) - goto Lnomatch; - } - dedtypes->data[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim) - goto Lnomatch; - - for (int i = 0; i < tempinst->tiargs->dim; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - int j; - Object *o1 = (Object *)tempinst->tiargs->data[i]; - Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; - - Type *t1 = isType(o1); - Type *t2 = isType(o2); - - Expression *e1 = isExpression(o1); - Expression *e2 = isExpression(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()); -#endif - - 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; - } - } - // BUG: Need to handle alias and tuple parameters - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes); - -Lnomatch: - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeStruct::deduceType()\n"); - //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); - //printf("\ttparam = %d, ", tparam->ty); tparam->print(); - - /* If this struct is a template struct, and we're matching - * it against a template instance, convert the struct type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - 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; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) -{ - //printf("TypeClass::deduceType(this = %s)\n", toChars()); - - /* If this class is a template class, and we're matching - * it against a template instance, convert the class type - * to a template instance, too, and try again. - */ - TemplateInstance *ti = sym->parent->isTemplateInstance(); - - if (tparam && tparam->ty == Tinstance) - { - 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; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return (MATCH) implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes); -} - -/* ======================== TemplateParameter =============================== */ - -TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) -{ - this->loc = loc; - this->ident = ident; - this->sparam = NULL; -} - -TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() -{ - return NULL; -} - -TemplateValueParameter *TemplateParameter::isTemplateValueParameter() -{ - return NULL; -} - -TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() -{ - return NULL; -} - -TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() -{ - return NULL; -} - -/* ======================== TemplateTypeParameter =========================== */ - -// type-parameter - -TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, - Type *defaultType) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->defaultType = defaultType; -} - -TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() -{ - return this; -} - -TemplateParameter *TemplateTypeParameter::syntaxCopy() -{ - TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - if (defaultType) - tp->defaultType = defaultType->syntaxCopy(); - return tp; -} - -void TemplateTypeParameter::declareParameter(Scope *sc) -{ - //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); - TypeIdentifier *ti = new TypeIdentifier(loc, ident); - sparam = new AliasDeclaration(loc, ident, ti); - if (!sc->insert(sparam)) - error(loc, "parameter '%s' multiply defined", ident->toChars()); -} - -void TemplateTypeParameter::semantic(Scope *sc) -{ - //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); - if (specType) - { - specType = specType->semantic(loc, sc); - } -#if 0 // Don't do semantic() until instantiation - if (defaultType) - { - defaultType = defaultType->semantic(loc, sc); - } -#endif -} - -/**************************************** - * Determine if two TemplateParameters are the same - * as far as TemplateDeclaration overloading goes. - * Returns: - * 1 match - * 0 no match - */ - -int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); - - if (ttp) - { - if (specType != ttp->specType) - goto Lnomatch; - - if (specType && !specType->equals(ttp->specType)) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -/******************************************* - * 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] - */ - -MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, - int i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Type *t; - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; - else - { // Get default argument instead - oarg = defaultArg(sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = (Object *)dedtypes->data[i]; - if (!oarg) - goto Lnomatch; - } - } - - ta = isType(oarg); - if (!ta) - goto Lnomatch; - //printf("ta is %s\n", ta->toChars()); - - t = (Type *)dedtypes->data[i]; - - if (specType) - { - //printf("\tcalling deduceType(), specType is %s\n", 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]; - } - else - { - m = MATCHconvert; - if (t) - { // Must match already deduced type - - m = MATCHexact; - if (!t->equals(ta)) - goto Lnomatch; - } - } - - if (!t) - { - dedtypes->data[i] = ta; - t = ta; - } - *psparam = new AliasDeclaration(loc, ident, t); - //printf("\tm = %d\n", m); - return m; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateTypeParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Type *t = isType(oarg); - Type *ta = isType(oded); - - assert(ta); - - if (specType) - printf("\tSpecialization: %s\n", specType->toChars()); - if (defaultType) - printf("\tDefault: %s\n", defaultType->toChars()); - printf("\tArgument: %s\n", t ? t->toChars() : "NULL"); - printf("\tDeduced Type: %s\n", ta->toChars()); -} - - -void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - if (specType) - { - buf->writestring(" : "); - specType->toCBuffer(buf, NULL, hgs); - } - if (defaultType) - { - buf->writestring(" = "); - defaultType->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateTypeParameter::dummyArg() -{ Type *t; - - if (specType) - t = specType; - else - { // Use this for alias-parameter's too (?) - t = new TypeIdentifier(loc, ident); - } - return (void *)t; -} - - -Object *TemplateTypeParameter::specialization() -{ - return specType; -} - - -Object *TemplateTypeParameter::defaultArg(Scope *sc) -{ - Type *t; - - t = defaultType; - if (t) - { - t = t->syntaxCopy(); - t = t->semantic(loc, sc); - } - return t; -} - -/* ======================== TemplateAliasParameter ========================== */ - -// alias-parameter - -Dsymbol *TemplateAliasParameter::sdummy = NULL; - -TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specAliasT = specAliasT; - this->defaultAlias = defaultAlias; - - this->specAlias = NULL; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); - if (tp->specAliasT) - tp->specAliasT = specAliasT->syntaxCopy(); - if (defaultAlias) - tp->defaultAlias = defaultAlias->syntaxCopy(); - return tp; -} - -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()); -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specAliasT) - { - specAlias = specAliasT->toDsymbol(sc); - if (!specAlias) - error("%s is not a symbol", specAliasT->toChars()); - } -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#endif -} - -int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - - if (tap) - { - if (specAlias != tap->specAlias) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateAliasParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - Dsymbol *sa; - Object *oarg; - Expression *ea; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; - else - { // Get default argument instead - oarg = defaultArg(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) - goto Lnomatch; - - if (specAlias) - { - if (!sa || sa == sdummy) - goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; - } - else if (dedtypes->data[i]) - { // Must match already deduced symbol - Dsymbol *s = (Dsymbol *)dedtypes->data[i]; - - if (!sa || s != sa) - goto Lnomatch; - } - dedtypes->data[i] = sa; - - *psparam = new AliasDeclaration(loc, ident, sa); - return MATCHexact; - -Lnomatch: - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tArgument alias: %s\n", sa->toChars()); -} - -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - buf->writestring(ident->toChars()); - if (specAliasT) - { - buf->writestring(" : "); - specAliasT->toCBuffer(buf, NULL, hgs); - } - if (defaultAlias) - { - buf->writestring(" = "); - defaultAlias->toCBuffer(buf, NULL, hgs); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Dsymbol *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAliasT; -} - - -Object *TemplateAliasParameter::defaultArg(Scope *sc) -{ - Dsymbol *s = NULL; - - if (defaultAlias) - { - s = defaultAlias->toDsymbol(sc); - if (!s) - error("%s is not a symbol", defaultAlias->toChars()); - } - return s; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -Expression *TemplateValueParameter::edummy = NULL; - -TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, - Expression *specValue, Expression *defaultValue) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->valType = valType; - this->specValue = specValue; - this->defaultValue = defaultValue; -} - -TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() -{ - return this; -} - -TemplateParameter *TemplateValueParameter::syntaxCopy() -{ - TemplateValueParameter *tp = - new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); - tp->valType = valType->syntaxCopy(); - if (specValue) - tp->specValue = specValue->syntaxCopy(); - if (defaultValue) - tp->defaultValue = defaultValue->syntaxCopy(); - return tp; -} - -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()); - sparam = v; -} - -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()); - - 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(); - } - -#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(); - } -#endif -} - -int TemplateValueParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - - if (tvp) - { - if (valType != tvp->valType) - goto Lnomatch; - - if (valType && !valType->equals(tvp->valType)) - goto Lnomatch; - - if (specValue != tvp->specValue) - goto Lnomatch; - - return 1; // match - } - -Lnomatch: - return 0; -} - - -MATCH TemplateValueParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateValueParameter::matchArg()\n"); - - Initializer *init; - Declaration *sparam; - MATCH m = MATCHexact; - Expression *ei; - Object *oarg; - - if (i < tiargs->dim) - oarg = (Object *)tiargs->data[i]; - else - { // Get default argument instead - oarg = defaultArg(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; - - if (specValue) - { - if (!ei || ei == edummy) - goto Lnomatch; - - Expression *e = specValue; - - e = e->semantic(sc); - e = e->implicitCastTo(sc, valType); - e = e->optimize(WANTvalue | WANTinterpret); - - ei = ei->syntaxCopy(); - ei = ei->semantic(sc); - ei = ei->optimize(WANTvalue | WANTinterpret); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("e : %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]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } -Lmatch: - //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - dedtypes->data[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCconst; - *psparam = sparam; - return m; - -Lnomatch: - //printf("\tno match\n"); - *psparam = NULL; - return MATCHnomatch; -} - - -void TemplateValueParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Expression *ea = isExpression(oded); - - if (specValue) - printf("\tSpecialization: %s\n", specValue->toChars()); - printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL"); -} - - -void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - valType->toCBuffer(buf, ident, hgs); - if (specValue) - { - buf->writestring(" : "); - specValue->toCBuffer(buf, hgs); - } - if (defaultValue) - { - buf->writestring(" = "); - defaultValue->toCBuffer(buf, hgs); - } -} - - -void *TemplateValueParameter::dummyArg() -{ Expression *e; - - e = specValue; - if (!e) - { - // Create a dummy value - if (!edummy) - edummy = valType->defaultInit(); - e = edummy; - } - return (void *)e; -} - - -Object *TemplateValueParameter::specialization() -{ - return specValue; -} - - -Object *TemplateValueParameter::defaultArg(Scope *sc) -{ - Expression *e; - - e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - e = e->semantic(sc); - } - return e; -} - -/* ======================== TemplateTupleParameter ========================== */ - -// variadic-parameter - -TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) - : TemplateParameter(loc, ident) -{ - this->ident = ident; -} - -TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() -{ - return this; -} - -TemplateParameter *TemplateTupleParameter::syntaxCopy() -{ - TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); - return tp; -} - -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()); -} - -void TemplateTupleParameter::semantic(Scope *sc) -{ -} - -int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) -{ - TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); - - if (tvp) - { - return 1; // match - } - -Lnomatch: - return 0; -} - -MATCH TemplateTupleParameter::matchArg(Scope *sc, - Objects *tiargs, int i, TemplateParameters *parameters, - Objects *dedtypes, - Declaration **psparam) -{ - //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 - Tuple *ovar; - if (i + 1 == tiargs->dim && 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]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->data[i] = (void *)ovar; - return MATCHexact; -} - - -void TemplateTupleParameter::print(Object *oarg, Object *oded) -{ - printf(" %s... [", ident->toChars()); - Tuple *v = isTuple(oded); - assert(v); - - //printf("|%d| ", v->objects.dim); - for (int i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = (Object *)v->objects.data[i]; - - Dsymbol *sa = isDsymbol(o); - if (sa) - printf("alias: %s", sa->toChars()); - - Type *ta = isType(o); - if (ta) - printf("type: %s", ta->toChars()); - - Expression *ea = isExpression(o); - if (ea) - printf("exp: %s", ea->toChars()); - - assert(!isTuple(o)); // no nested Tuple arguments - } - - printf("]\n"); -} - -void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writestring("..."); -} - - -void *TemplateTupleParameter::dummyArg() -{ - return NULL; -} - - -Object *TemplateTupleParameter::specialization() -{ - return NULL; -} - - -Object *TemplateTupleParameter::defaultArg(Scope *sc) -{ - return NULL; -} - -/* ======================== TemplateInstance ================================ */ - -TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); -#endif - this->loc = loc; - this->name = ident; - this->tiargs = NULL; - this->tempdecl = NULL; - this->inst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->errors = 0; -} - - -TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) - : ScopeDsymbol(NULL) -{ -#if LOG - printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); -#endif - this->loc = loc; - this->name = td->ident; - this->tiargs = tiargs; - this->tempdecl = td; - this->inst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->errors = 0; - - assert((size_t)tempdecl->scope > 0x10000); -} - - -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++) - { - Type *ta = isType((Object *)objs->data[i]); - if (ta) - a->data[i] = ta->syntaxCopy(); - else - { - Expression *ea = isExpression((Object *)objs->data[i]); - assert(ea); - a->data[i] = ea->syntaxCopy(); - } - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - int i; - - if (s) - ti = (TemplateInstance *)s; - else - ti = new TemplateInstance(loc, name); - - ti->tiargs = arraySyntaxCopy(tiargs); - - ScopeDsymbol::syntaxCopy(ti); - return ti; -} - - -void TemplateInstance::semantic(Scope *sc) -{ - if (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 LOG - printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); -#endif - return; - } - - if (semanticdone != 0) - { - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticdone = 1; - -#if LOG - printf("\tdo semantic\n"); -#endif - if (havetempdecl) - { - assert((size_t)tempdecl->scope > 0x10000); - // Deduce tdtypes - tdtypes.setDim(tempdecl->parameters->dim); - if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - // Run semantic on each argument, place results in tiargs[] - semanticTiargs(sc); - - 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 - } - } - - isNested(tiargs); - - /* See if there is an existing TemplateInstantiation that already - * implements the typeargs. If so, just refer to that one instead. - */ - - for (size_t i = 0; i < tempdecl->instances.dim; 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()); -#endif - assert(tdtypes.dim == ti->tdtypes.dim); - - // Nesting must match - if (isnested != ti->isnested) - continue; -#if 0 - 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; - } - - // It's a match - inst = ti; - parent = ti->parent; -#if LOG - printf("\tit's a match with instance %p\n", inst); -#endif - return; - - L1: - ; - } - - /* So, we need to implement 'this' instance. - */ -#if LOG - printf("\timplement template instance '%s'\n", toChars()); -#endif - unsigned errorsave = global.errors; - inst = this; - int tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; - //printf("parent = '%s'\n", parent->kind()); - - ident = genIdent(); // need an identifier for name mangling purposes. - -#if 1 - if (isnested) - parent = isnested; -#endif - //printf("parent = '%s'\n", parent->kind()); - - // Add 'this' to the enclosing scope's members[] so the semantic routines - // will get called on the instance members -#if 1 - int dosemantic3 = 0; - { Array *a; - int i; - - if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin()) - { - //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); - a = sc->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s\n", m->toChars()); - a = m->members; - if (m->semanticdone >= 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 - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - - // Create our own scope for the template parameters - Scope *scope = tempdecl->scope; - if (!scope) - { - error("forward reference to template declaration %s\n", tempdecl->toChars()); - return; - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - argsym = new ScopeDsymbol(); - argsym->parent = scope->parent; - scope = scope->push(argsym); - - // Declare each template parameter as an alias for the argument type - declareParameters(scope); - - // Add members of template instance to template instance symbol table -// parent = scope->scopesym; - symtab = new DsymbolTable(); - int memnum = 0; - for (int i = 0; i < members->dim; 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); -#endif - memnum |= s->addMember(scope, this, memnum); - } -#if LOG - printf("adding members done\n"); -#endif - - /* See if there is only one member of template instance, and that - * member has the same name as the template instance. - * If so, this template instance becomes an alias for that member. - */ - //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); - } - } - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = scope->push(this); - //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); - sc2->parent = /*isnested ? sc->parent :*/ this; - -#if !IN_LLVM -#if _WIN32 - __try - { -#endif -#endif - 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(); - } -#if !IN_LLVM -#if _WIN32 - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif -#endif - - /* If any of the instantiation members didn't get semantic() run - * on them due to forward references, we cannot run semantic2() - * or semantic3() yet. - */ - for (size_t i = 0; i < Module::deferred.dim; i++) - { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; - - if (sd->parent == this) - goto Laftersemantic; - } - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// 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); - - if (sc->func || dosemantic3) - { - semantic3(sc2); - } - - Laftersemantic: - sc2->pop(); - - scope->pop(); - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error("error instantiating"); - errors = 1; - if (global.gag) - tempdecl->instances.remove(tempdecl_instance_idx); - } - -#if LOG - printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - - -void TemplateInstance::semanticTiargs(Scope *sc) -{ - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - semanticTiargs(loc, sc, tiargs); -} - -void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); - if (!tiargs) - 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); - - //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); - 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) - { - 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); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->data[j] = ea; - if (ea->op == TOKtype) - tiargs->data[j] = ea->type; - } - else if (sa) - { - } - 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); - - printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); - } -#endif -} - -/********************************************** - * Find template declaration corresponding to template instance. - */ - -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; - - 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()); -#endif - 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; - } - } - - 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; - } -#ifdef DEBUG - //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; - } - } - } - else - assert(tempdecl->isTemplateDeclaration()); - return tempdecl; -} - -TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) -{ - /* Since there can be multiple TemplateDeclaration's with the same - * name, look for the best match. - */ - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - MATCH m_best = MATCHnomatch; - Objects dedtypes; - -#if LOG - printf("TemplateInstance::findBestMatch()\n"); -#endif - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - 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; - } - - dedtypes.setDim(td->parameters->dim); - dedtypes.zero(); - if (!td->scope) - { - error("forward reference to template declaration %s", td->toChars()); - return NULL; - } - m = td->matchWithInstance(this, &dedtypes, 0); - //printf("m = %d\n", m); - if (!m) // no match at all - continue; - -#if 1 - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; -#else - if (!m_best) - goto Ltd; -#endif - { - // Disambiguate by picking the most specialized TemplateDeclaration - int c1 = td->leastAsSpecialized(td_best); - int 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; - } - - 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: // 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) - { - 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()); - } - - /* The best match is td_best - */ - tempdecl = td_best; - -#if 0 - /* 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; - } - } -#endif - -#if LOG - printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); -#endif - return tempdecl; -} - - -/***************************************** - * Determines if a TemplateInstance will need a nested - * generation of the TemplateDeclaration. - */ - -int TemplateInstance::isNested(Objects *args) -{ int nested = 0; - //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars()); - - /* A nested instance happens when an argument references a local - * symbol that is on the stack. - */ - 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 = sa->isDeclaration(); - if (d && !d->isDataseg() && -#if V2 - !(d->storage_class & STCmanifest) && -#endif - (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && - !isTemplateMixin()) - { - // if module level template - if (tempdecl->toParent()->isModule()) - { Dsymbol *dparent = d->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; 1; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("is nested in both %s and %s", isnested->toChars(), dparent->toChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as template parameter", d->toChars()); - } - } - else if (va) - { - nested |= isNested(&va->objects); - } - } - return nested; -} - -/**************************************** - * This instance needs an identifier for name mangling purposes. - * Create one by taking the template declaration name and adding - * the type signature for it. - */ - -Identifier *TemplateInstance::genIdent() -{ OutBuffer buf; - char *id; - Objects *args; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - id = tempdecl->ident->toChars(); - buf.printf("__T%"PRIuSIZE"%s", strlen(id), id); - 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 %p ta %p ea %p sa %p va %p\n", 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()); -#endif - assert(global.errors); - } - } - else if (ea) - { sinteger_t v; - real_t r; - - 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); -#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); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && !d->type->deco) - error("forward reference of %s", d->toChars()); - else - { - char *p = sa->mangle(); - buf.printf("%"PRIuSIZE"%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(); - buf.data = NULL; - return new Identifier(id, TOKidentifier); -} - - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *scope) -{ - //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]; - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(scope, tp, o); - } -} - - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticdone >= 2) - return; - semanticdone = 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); - 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(); - } -#if LOG - printf("-TemplateInstance::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateInstance::semantic3(Scope *sc) -{ int i; - -#if LOG - printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone); -#endif -//if (toChars()[0] == 'D') *(char*)0=0; - if (semanticdone >= 3) - return; - semanticdone = 3; - if (!errors && members) - { - sc = tempdecl->scope; - 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(); - } -} - -void TemplateInstance::toObjFile() -{ int i; - -#if LOG - printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); -#endif - if (!errors && members) - { - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->toObjFile(); - } - } -} - -void TemplateInstance::inlineScan() -{ int i; - -#if LOG - printf("TemplateInstance::inlineScan('%s')\n", toChars()); -#endif - if (!errors && members) - { - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->inlineScan(); - } - } -} - -void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int i; - - Identifier *id = name; - buf->writestring(id->toChars()); - buf->writestring("!("); - if (nest) - 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--; - } - buf->writeByte(')'); -} - - -Dsymbol *TemplateInstance::toAlias() -{ -#if LOG - printf("TemplateInstance::toAlias()\n"); -#endif - if (!inst) - { error("cannot resolve forward reference"); - return this; - } - - if (inst != this) - return inst->toAlias(); - - if (aliasdecl) - return aliasdecl->toAlias(); - - return inst; -} - -AliasDeclaration *TemplateInstance::isAliasDeclaration() -{ - return aliasdecl; -} - -char *TemplateInstance::kind() -{ - return "template instance"; -} - -int TemplateInstance::oneMember(Dsymbol **ps) -{ - *ps = NULL; - return TRUE; -} - -char *TemplateInstance::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Array *idents, Objects *tiargs) - : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) -{ - //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); - this->ident = ident; - this->tqual = tqual; - this->idents = idents; - this->tiargs = tiargs ? tiargs : new Objects(); - this->scope = NULL; -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) -{ TemplateMixin *tm; - - Array *ids = new Array(); - ids->setDim(idents->dim); - for (int i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = (Identifier *)idents->data[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - ids->data[i] = id; - } - - tm = new TemplateMixin(loc, ident, - (Type *)(tqual ? tqual->syntaxCopy() : NULL), - ids, tiargs); - TemplateInstance::syntaxCopy(tm); - return tm; -} - -void TemplateMixin::semantic(Scope *sc) -{ -#if LOG - printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); - fflush(stdout); -#endif - if (semanticdone && - // This for when a class/struct contains mixin members, and - // is done over because of forward references - (!parent || !toParent()->isAggregateDeclaration())) - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - if (!semanticdone) - semanticdone = 1; -#if LOG - printf("\tdo semantic\n"); -#endif - - Scope *scx = NULL; - if (scope) - { 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; - - 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); - } - } - - 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->scope) - { - /* 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. - */ - semanticdone = 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); - - tempdecl = findBestMatch(sc); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(); - - inst = this; - parent = sc->parent; - - /* Detect recursive mixin instantiations. - */ - for (Dsymbol *s = parent; s; s = s->parent) - { - //printf("\ts = '%s'\n", s->toChars()); - TemplateMixin *tm = s->isTemplateMixin(); - if (!tm || tempdecl != tm->tempdecl) - 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; - - Lcontinue: - continue; - } - - // Copy the syntax trees from the TemplateDeclaration - members = Dsymbol::arraySyntaxCopy(tempdecl->members); - if (!members) - return; - - symtab = new DsymbolTable(); - - for (Scope *sce = sc; 1; sce = sce->enclosing) - { - ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; - if (sds) - { - sds->importScope(this, PROTpublic); - break; - } - } - -#if LOG - printf("\tcreate scope for template parameters '%s'\n", toChars()); -#endif - Scope *scy = sc; - scy = sc->push(this); - scy->parent = this; - - argsym = new ScopeDsymbol(); - argsym->parent = scy->parent; - Scope *scope = scy->push(argsym); - - unsigned errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - declareParameters(scope); - - // Add members to enclosing scope, as well as this scope - for (unsigned i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = (Dsymbol *)members->data[i]; - s->addMember(scope, 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 -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = scope->push(this); - sc2->offset = sc->offset; - for (int i = 0; i < members->dim; i++) - { - Dsymbol *s = (Dsymbol *)members->data[i]; - s->semantic(sc2); - } - sc->offset = sc2->offset; - - /* The problem is when to parse the initializer for a variable. - * Perhaps VarDeclaration::semantic() should do it like it does - * for initializers inside a function. - */ -// if (sc->parent->isFuncDeclaration()) - - semantic2(sc2); - - if (sc->func) - { - semantic3(sc2); - } - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error("error instantiating"); - } - - sc2->pop(); - - scope->pop(); - -// if (!isAnonymous()) - { - scy->pop(); - } -#if LOG - printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - -void TemplateMixin::semantic2(Scope *sc) -{ int i; - - if (semanticdone >= 2) - return; - semanticdone = 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]; -#if LOG - printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - s->semantic2(sc); - } - sc = sc->pop(); - sc->pop(); - } -#if LOG - printf("-TemplateMixin::semantic2('%s')\n", toChars()); -#endif -} - -void TemplateMixin::semantic3(Scope *sc) -{ int i; - - if (semanticdone >= 3) - return; - semanticdone = 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(); - } -} - -void TemplateMixin::inlineScan() -{ - TemplateInstance::inlineScan(); -} - -char *TemplateMixin::kind() -{ - return "mixin"; -} - -int TemplateMixin::oneMember(Dsymbol **ps) -{ - return Dsymbol::oneMember(ps); -} - -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; - } - } - return 0; -} - -char *TemplateMixin::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - TemplateInstance::toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin "); - int i; - for (i = 0; i < idents->dim; i++) - { Identifier *id = (Identifier *)idents->data[i]; - - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); - } - buf->writestring("!("); - if (tiargs) - { - for (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); - } - } - } - buf->writebyte(')'); - buf->writebyte(';'); - buf->writenl(); -} - - -void TemplateMixin::toObjFile() -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(); -} - + +// 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. + +// Handle template implementation + +#include <stdio.h> +#include <assert.h> + +#if !IN_LLVM +#if _WIN32 +#include <windows.h> +long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); +#endif +#endif + +#include "root.h" +#include "mem.h" +#include "stringtable.h" +#include "mars.h" +#include "identifier.h" +#include "mtype.h" +#include "template.h" +#include "init.h" +#include "expression.h" +#include "scope.h" +#include "module.h" +#include "aggregate.h" +#include "declaration.h" +#include "dsymbol.h" +#include "hdrgen.h" + +#define LOG 0 + +/******************************************** + * These functions substitute for dynamic_cast. dynamic_cast does not work + * on earlier versions of gcc. + */ + +Expression *isExpression(Object *o) +{ + //return dynamic_cast<Expression *>(o); + if (!o || o->dyncast() != DYNCAST_EXPRESSION) + return NULL; + return (Expression *)o; +} + +Dsymbol *isDsymbol(Object *o) +{ + //return dynamic_cast<Dsymbol *>(o); + if (!o || o->dyncast() != DYNCAST_DSYMBOL) + return NULL; + return (Dsymbol *)o; +} + +Type *isType(Object *o) +{ + //return dynamic_cast<Type *>(o); + if (!o || o->dyncast() != DYNCAST_TYPE) + return NULL; + return (Type *)o; +} + +Tuple *isTuple(Object *o) +{ + //return dynamic_cast<Tuple *>(o); + if (!o || o->dyncast() != DYNCAST_TUPLE) + return NULL; + return (Tuple *)o; +} + + +/*********************** + * Try to get arg as a type. + */ + +Type *getType(Object *o) +{ + Type *t = isType(o); + if (!t) + { Expression *e = isExpression(o); + if (e) + t = e->type; + } + return t; +} + +Dsymbol *getDsymbol(Object *oarg) +{ + Dsymbol *sa; + 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; + } + 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 + } + return sa; +} + +/****************************** + * If o1 matches o2, return 1. + * Else, return 0. + */ + +int match(Object *o1, Object *o2, TemplateDeclaration *tempdecl, Scope *sc) +{ + Type *t1 = isType(o1); + Type *t2 = isType(o2); + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(o2); + Dsymbol *s1 = isDsymbol(o1); + Dsymbol *s2 = isDsymbol(o2); + Tuple *v1 = isTuple(o1); + Tuple *v2 = isTuple(o2); + + //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, v1 %p v2 %p\n", t1,t2,e1,e2,s1,s2,v1,v2); + + /* A proper implementation of the various equals() overrides + * should make it possible to just do o1->equals(o2), but + * we'll do that another day. + */ + + 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 (!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(); + } +#endif + 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; + } + } + 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; + } + } + return 1; // match +Lnomatch: + return 0; // nomatch; +} + +/**************************************** + */ + +void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg) +{ + //printf("ObjectToCBuffer()\n"); + Type *t = isType(oarg); + Expression *e = isExpression(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); + } + else if (e) + e->toCBuffer(buf, hgs); + else if (s) + { + 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); + } + } + else if (!oarg) + { + buf->writestring("NULL"); + } + else + { +#ifdef DEBUG + printf("bad Object = %p\n", oarg); +#endif + assert(0); + } +} + + + +/* ======================== TemplateDeclaration ============================= */ + +TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, Array *decldefs) + : ScopeDsymbol(id) +{ +#if LOG + printf("TemplateDeclaration(this = %p, id = '%s')\n", this, id->toChars()); +#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(); + + if (ttp) + { + printf("\tparameter[%d] = %s : %s\n", i, tp->ident->toChars(), ttp->specType ? ttp->specType->toChars() : ""); + } + } +#endif + this->loc = loc; + this->parameters = parameters; + this->origParameters = parameters; + this->members = decldefs; + this->overnext = NULL; + this->overroot = NULL; + this->scope = NULL; + this->onemember = NULL; +} + +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(); + } + } + d = Dsymbol::arraySyntaxCopy(members); + td = new TemplateDeclaration(loc, ident, p, d); + return td; +} + +void TemplateDeclaration::semantic(Scope *sc) +{ +#if LOG + printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); +#endif + if (scope) + return; // semantic() already run + + if (sc->func) + { + error("cannot declare template at function scope %s", sc->func->toChars()); + } + + if (/*global.params.useArrayBounds &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc->module->toModuleArray(); + } + + if (/*global.params.useAssert &&*/ sc->module) + { + // Generate this function as it may be used + // when template is instantiated in other modules + sc->module->toModuleAssert(); + } + + /* Remember Scope for later instantiations, but make + * a copy since attributes can change. + */ + this->scope = new Scope(*sc); + this->scope->setNoFree(); + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = sc->parent; + Scope *paramscope = sc->push(paramsym); + paramscope->parameterSpecialization = 1; + + 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(); + } + } + + for (int i = 0; i < parameters->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + + tp->declareParameter(paramscope); + } + + for (int i = 0; i < parameters->dim; 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"); + } + + paramscope->pop(); + + if (members) + { + 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 + */ +} + +const char *TemplateDeclaration::kind() +{ + return (onemember && onemember->isAggregateDeclaration()) + ? onemember->kind() + : (char *)"template"; +} + +/********************************** + * Overload existing TemplateDeclaration 'this' with the new one 's'. + * Return !=0 if successful; i.e. no conflict. + */ + +int TemplateDeclaration::overloadInsert(Dsymbol *s) +{ + TemplateDeclaration **pf; + TemplateDeclaration *f; + +#if LOG + printf("TemplateDeclaration::overloadInsert('%s')\n", s->toChars()); +#endif + f = s->isTemplateDeclaration(); + if (!f) + 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; + + 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]; + + if (!p1->overloadMatch(p2)) + goto Lcontinue; + } + +#if LOG + printf("\tfalse: conflict\n"); +#endif + return FALSE; + + Lcontinue: + ; +#endif + } + + f->overroot = this; + *pf = f; +#if LOG + printf("\ttrue: no conflict\n"); +#endif + return TRUE; +} + +/*************************************** + * 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() + * Output: + * dedtypes deduced arguments + * Return match level. + */ + +MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, + Objects *dedtypes, int flag) +{ MATCH m; + int dedtypes_dim = dedtypes->dim; + +#define LOGM 0 +#if LOGM + printf("\n+TemplateDeclaration::matchWithInstance(this = %s, ti = %s, flag = %d)\n", toChars(), ti->toChars(), flag); +#endif + +#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]); +#endif + dedtypes->zero(); + + int parameters_dim = parameters->dim; + int variadic = isVariadic() != NULL; + + // If more arguments than parameters, no match + if (ti->tiargs->dim > parameters_dim && !variadic) + { +#if LOGM + printf(" no match: more arguments than parameters\n"); +#endif + return MATCHnomatch; + } + + assert(dedtypes_dim == parameters_dim); + assert(dedtypes_dim >= ti->tiargs->dim || variadic); + + // Set up scope for parameters + assert((size_t)scope > 0x10000); + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + + // Attempt type deduction + m = MATCHexact; + for (int i = 0; i < dedtypes_dim; i++) + { MATCH m2; + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Declaration *sparam; + + //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() : ""); +#endif + +#if DMDV1 + 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); + +#endif + //printf("\tm2 = %d\n", m2); + + if (m2 == MATCHnomatch) + { +#if 0 + printf("\tmatchArg() for parameter %i failed\n", i); +#endif + goto Lnomatch; + } + + if (m2 < m) + m = m2; + + 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]; + } + } + } + +#if LOGM + // Print out the results + printf("--------------------------\n"); + printf("template %s\n", toChars()); + printf("instance %s\n", ti->toChars()); + if (m) + { + for (int i = 0; i < dedtypes_dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + Object *oarg; + + printf(" [%d]", 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; +#endif + +#if LOGM + printf(" match = %d\n", m); +#endif + goto Lret; + +Lnomatch: +#if LOGM + printf(" no match\n"); +#endif + m = MATCHnomatch; + +Lret: + paramscope->pop(); +#if LOGM + printf("-TemplateDeclaration::matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); +#endif + return m; +} + +/******************************************** + * Determine partial specialization order of 'this' vs td2. + * Returns: + * 1 this is at least as specialized as td2 + * 0 td2 is more specialized than this + */ + +int TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2) +{ + /* This works by taking the template parameters to this template + * declaration and feeding them to td2 as if it were a template + * instance. + * If it works, then this template is at least as specialized + * as td2. + */ + + TemplateInstance ti(0, ident); // create dummy template instance + Objects dedtypes; + +#define LOG_LEASTAS 0 + +#if LOG_LEASTAS + printf("%s.leastAsSpecialized(%s)\n", toChars(), td2->toChars()); +#endif + + // Set type arguments to dummy template instance to be types + // generated from the parameters to this template declaration + ti.tiargs = new Objects(); + ti.tiargs->setDim(parameters->dim); + for (int i = 0; i < ti.tiargs->dim; i++) + { + TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + + void *p = tp->dummyArg(); + if (p) + ti.tiargs->data[i] = p; + else + ti.tiargs->setDim(i); + } + + // Temporary Array to hold deduced types + //dedtypes.setDim(parameters->dim); + dedtypes.setDim(td2->parameters->dim); + + // Attempt a type deduction + if (td2->matchWithInstance(&ti, &dedtypes, 1)) + { + /* A non-variadic template is more specialized than a + * variadic one. + */ + if (isVariadic() && !td2->isVariadic()) + goto L1; + +#if LOG_LEASTAS + printf(" matches, so is least as specialized\n"); +#endif + return 1; + } + L1: +#if LOG_LEASTAS + printf(" doesn't match, so is not as specialized\n"); +#endif + return 0; +} + + +/************************************************* + * Match function arguments against a specific template function. + * Input: + * targsi Expression/Type initial list of template arguments + * fargs arguments to function + * Output: + * dedargs Expression/Type deduced template arguments + * Returns: + * match level + */ + +MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Objects *targsi, Expressions *fargs, + Objects *dedargs) +{ + size_t i; + size_t nfparams; + size_t nfargs; + size_t nargsi; // array size of targsi + int fptupindex = -1; + int tuple_dim = 0; + MATCH match = MATCHexact; + FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); + TypeFunction *fdtype; // type of fd + TemplateTupleParameter *tp; + 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()); + } +#endif + + assert((size_t)scope > 0x10000); + + dedargs->setDim(parameters->dim); + dedargs->zero(); + + dedtypes.setDim(parameters->dim); + dedtypes.zero(); + + // Set up scope for parameters + ScopeDsymbol *paramsym = new ScopeDsymbol(); + paramsym->parent = scope->parent; + Scope *paramscope = scope->push(paramsym); + + tp = isVariadic(); + + nargsi = 0; + if (targsi) + { // Set initial template arguments + + nargsi = targsi->dim; + if (nargsi > parameters->dim) + { if (!tp) + goto Lnomatch; + dedargs->setDim(nargsi); + dedargs->zero(); + } + + memcpy(dedargs->data, targsi->data, nargsi * sizeof(*dedargs->data)); + + for (i = 0; i < nargsi; i++) + { TemplateParameter *tp = (TemplateParameter *)parameters->data[i]; + MATCH m; + Declaration *sparam; + + 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; + } + } + + assert(fd->type->ty == Tfunction); + fdtype = (TypeFunction *)fd->type; + + nfparams = Argument::dim(fdtype->parameters); // number of function parameters + nfargs = fargs->dim; // number of function arguments + + /* Check for match of function arguments with variadic template + * parameter, such as: + * + * template Foo(T, A...) { void Foo(T t, A a); } + * void main() { Foo(1,2,3); } + */ + tp = isVariadic(); + 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; + 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 *)fdtype->parameters->data[fptupindex]; + if (fparam->type->ty != Tident) + continue; + TypeIdentifier *tid = (TypeIdentifier *)fparam->type; + if (!tp->ident->equals(tid->ident) || tid->idents.dim) + continue; + + if (fdtype->varargs) // 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; + + 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; + } + goto L2; + } + fptupindex = -1; + } + } + +L1: + if (nfparams == nfargs) + ; + else if (nfargs > nfparams) + { + if (fdtype->varargs == 0) + goto Lnomatch; // too many args, no match + match = MATCHconvert; // match ... with a conversion + } + +L2: + // Loop through the function parameters + for (i = 0; i < nfparams; i++) + { + /* 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; + } + + Argument *fparam = Argument::getNth(fdtype->parameters, 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()); +#endif + + MATCH m; + m = farg->type->deduceType(scope, 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 (!tf->varargs && Argument::dim(tf->parameters) == 0) + { + m = farg->type->deduceType(scope, 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; + } + } + + /* The following code for variadic arguments closely + * matches TypeFunction::callMatch() + */ + if (!(fdtype->varargs == 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; + integer_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(scope, 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; + } + } + +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) + { + 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); + //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(paramscope); + if (!oded) + goto Lnomatch; + } + declareParameter(paramscope, tp, oded); + dedargs->data[i] = (void *)oded; + } + } + +#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()); + } +#endif + + paramscope->pop(); + //printf("\tmatch %d\n", match); + return match; + +Lnomatch: + paramscope->pop(); + //printf("\tnomatch\n"); + return MATCHnomatch; +} + +/************************************************** + * Declare template parameter tp with value o. + */ + +void TemplateDeclaration::declareParameter(Scope *sc, TemplateParameter *tp, Object *o) +{ + //printf("TemplateDeclaration::declareParameter('%s', o = %p)\n", tp->ident->toChars(), o); + + Type *targ = isType(o); + Expression *ea = isExpression(o); + Dsymbol *sa = isDsymbol(o); + Tuple *va = isTuple(o); + + Dsymbol *s; + + if (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); + } + else if (ea) + { + // tdtypes.data[i] always matches ea here + Initializer *init = new ExpInitializer(loc, ea); + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + assert(tvp); + + VarDeclaration *v = new VarDeclaration(loc, tvp->valType, tp->ident, init); + v->storage_class = STCconst; + s = v; + } + else if (va) + { + //printf("\ttuple\n"); + s = new TupleDeclaration(loc, tp->ident, &va->objects); + } + else + { +#ifdef DEBUG + o->print(); +#endif + assert(0); + } + if (!sc->insert(s)) + error("declaration %s is already defined", tp->ident->toChars()); + s->semantic(sc); +} + +/************************************** + * Determine if TemplateDeclaration is variadic. + */ + +TemplateTupleParameter *isVariadic(TemplateParameters *parameters) +{ size_t dim = parameters->dim; + TemplateTupleParameter *tp = NULL; + + if (dim) + tp = ((TemplateParameter *)parameters->data[dim - 1])->isTemplateTupleParameter(); + return tp; +} + +TemplateTupleParameter *TemplateDeclaration::isVariadic() +{ + return ::isVariadic(parameters); +} + +/*********************************** + * We can overload templates. + */ + +int TemplateDeclaration::isOverloadable() +{ + return 1; +} + +/************************************************* + * Given function arguments, figure out which template function + * 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 + * fargs arguments to function + */ + +FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, + Objects *targsi, Expressions *fargs) +{ + MATCH m_best = MATCHnomatch; + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + Objects *tdargs = new Objects(); + TemplateInstance *ti; + FuncDeclaration *fd; + +#if 0 + 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()); + } + } + 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); + } +#endif + + for (TemplateDeclaration *td = this; td; td = td->overnext) + { + if (!td->scope) + { + 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; + + m = td->deduceFunctionTemplateMatch(targsi, 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; + + { + // Disambiguate by picking the most specialized TemplateDeclaration + int c1 = td->leastAsSpecialized(td_best); + int 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; + } + + 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: // 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) + { + error(loc, "does not match any template declaration"); + goto Lerror; + } + if (td_ambig) + { + error(loc, "%s matches more than one function template declaration, %s and %s", + toChars(), td_best->toChars(), td_ambig->toChars()); + } + + /* The best match is td_best with arguments tdargs. + * Now instantiate the template. + */ + assert((size_t)td_best->scope > 0x10000); + ti = new TemplateInstance(loc, td_best, tdargs); + ti->semantic(sc); + fd = ti->toAlias()->isFuncDeclaration(); + if (!fd) + goto Lerror; + return fd; + + Lerror: + { + OutBuffer buf; + HdrGenState hgs; + + argExpTypesToCBuffer(&buf, fargs, &hgs); + error(loc, "cannot deduce template function from argument types (%s)", + buf.toChars()); + return NULL; + } +} + +void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ +#if 0 // Should handle template functions + if (onemember && onemember->isFuncDeclaration()) + buf->writestring("foo "); +#endif + buf->writestring(kind()); + buf->writeByte(' '); + buf->writestring(ident->toChars()); + 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); + } + buf->writeByte(')'); + + 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--; + } +} + + +char *TemplateDeclaration::toChars() +{ OutBuffer buf; + HdrGenState hgs; + + memset(&hgs, 0, sizeof(hgs)); + buf.writestring(ident->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); + } + buf.writeByte(')'); + buf.writeByte(0); + return (char *)buf.extractData(); +} + +/* ======================== Type ============================================ */ + +/**** + * Given an identifier, figure out which TemplateParameter it is. + * Return -1 if not found. + */ + +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; + } + return -1; +} + +int templateParameterLookup(Type *tparam, TemplateParameters *parameters) +{ + assert(tparam->ty == Tident); + TypeIdentifier *tident = (TypeIdentifier *)tparam; + //printf("\ttident = '%s'\n", tident->toChars()); + if (tident->idents.dim == 0) + { + return templateIdentifierLookup(tident->ident, parameters); + } + return -1; +} + +/* These form the heart of template argument deduction. + * Given 'this' being the type argument to the template instance, + * 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 + * Input: + * this = int* + * tparam = T + * parameters = [ T:T* ] // Array of TemplateParameter's + * Output: + * dedtypes = [ int ] // Array of Expression/Type's + */ + +MATCH Type::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes) +{ + //printf("Type::deduceType()\n"); + //printf("\tthis = %d, ", ty); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + if (!tparam) + goto Lnomatch; + + if (this == tparam) + goto Lexact; + + if (tparam->ty == Tident) + { + // 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; + } + + /* 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]; + + // Found the corresponding parameter tp + if (!tp->isTemplateTypeParameter()) + goto Lnomatch; + Type *at = (Type *)dedtypes->data[i]; + if (!at) + { + dedtypes->data[i] = (void *)this; + goto Lexact; + } + if (equals(at)) + goto Lexact; + else if (ty == Tclass && at->ty == Tclass) + { + return (MATCH) implicitConvTo(at); + } + else if (ty == Tsarray && at->ty == Tarray && + nextOf()->equals(at->nextOf())) + { + goto Lexact; + } + else + goto Lnomatch; + } + + if (ty != tparam->ty) + return implicitConvTo(tparam); +// goto Lnomatch; + + if (nextOf()) + return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes); + +Lexact: + return MATCHexact; + +Lnomatch: + return MATCHnomatch; +} + +MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, + Objects *dedtypes) +{ +#if 0 + printf("TypeSArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // Extra check that array dimensions must match + if (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 (tident->idents.dim == 0) + { Identifier *id = tident->ident; + + 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 (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; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes); + + Lnomatch: + return MATCHnomatch; +} + +MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ +#if 0 + printf("TypeAArray::deduceType()\n"); + printf("\tthis = %d, ", ty); print(); + printf("\ttparam = %d, ", tparam->ty); tparam->print(); +#endif + + // 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; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + //printf("TypeFunction::deduceType()\n"); + //printf("\tthis = %d, ", ty); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + // 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; + + size_t nfargs = Argument::dim(this->parameters); + size_t nfparams = Argument::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 *)tp->parameters->data[nfparams - 1]; + 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; + } + + /* 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; + } + + L1: + 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; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + // Extra check + if (tparam && tparam->ty == Tident) + { + 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]; + + if (!id1->equals(id2)) + return MATCHnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeInstance::deduceType(Scope *sc, + Type *tparam, TemplateParameters *parameters, + Objects *dedtypes) +{ + //printf("TypeInstance::deduceType(tparam = %s) %s\n", tparam->toChars(), toChars()); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + // Extra check + if (tparam && tparam->ty == Tinstance) + { + 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; + Dsymbol *sa = tempinst->tempdecl; + if (!sa) + goto Lnomatch; + if (ta->specAlias && sa != ta->specAlias) + goto Lnomatch; + if (dedtypes->data[i]) + { // Must match already deduced symbol + Dsymbol *s = (Dsymbol *)dedtypes->data[i]; + + if (s != sa) + goto Lnomatch; + } + dedtypes->data[i] = sa; + } + } + else if (tempinst->tempdecl != tp->tempinst->tempdecl) + goto Lnomatch; + + L2: + if (tempinst->tiargs->dim != tp->tempinst->tiargs->dim) + goto Lnomatch; + + for (int i = 0; i < tempinst->tiargs->dim; i++) + { + //printf("\ttest: tempinst->tiargs[%d]\n", i); + int j; + Object *o1 = (Object *)tempinst->tiargs->data[i]; + Object *o2 = (Object *)tp->tempinst->tiargs->data[i]; + + Type *t1 = isType(o1); + Type *t2 = isType(o2); + + Expression *e1 = isExpression(o1); + Expression *e2 = isExpression(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()); +#endif + + 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; + } + } + // BUG: Need to handle alias and tuple parameters + else + goto Lnomatch; + } + } + return Type::deduceType(sc, tparam, parameters, dedtypes); + +Lnomatch: + return MATCHnomatch; +} + +MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + //printf("TypeStruct::deduceType()\n"); + //printf("\tthis->parent = %s, ", sym->parent->toChars()); print(); + //printf("\ttparam = %d, ", tparam->ty); tparam->print(); + + /* If this struct is a template struct, and we're matching + * it against a template instance, convert the struct type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + 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; + } + } + } + } + + // Extra check + if (tparam && tparam->ty == Tstruct) + { + TypeStruct *tp = (TypeStruct *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + // Extra check + if (tparam && tparam->ty == Tenum) + { + TypeEnum *tp = (TypeEnum *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + // Extra check + if (tparam && tparam->ty == Ttypedef) + { + TypeTypedef *tp = (TypeTypedef *)tparam; + + if (sym != tp->sym) + return MATCHnomatch; + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes) +{ + //printf("TypeClass::deduceType(this = %s)\n", toChars()); + + /* If this class is a template class, and we're matching + * it against a template instance, convert the class type + * to a template instance, too, and try again. + */ + TemplateInstance *ti = sym->parent->isTemplateInstance(); + + if (tparam && tparam->ty == Tinstance) + { + 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; + } + } + } + } + + // Extra check + if (tparam && tparam->ty == Tclass) + { + TypeClass *tp = (TypeClass *)tparam; + + //printf("\t%d\n", (MATCH) implicitConvTo(tp)); + return (MATCH) implicitConvTo(tp); + } + return Type::deduceType(sc, tparam, parameters, dedtypes); +} + +/* ======================== TemplateParameter =============================== */ + +TemplateParameter::TemplateParameter(Loc loc, Identifier *ident) +{ + this->loc = loc; + this->ident = ident; + this->sparam = NULL; +} + +TemplateTypeParameter *TemplateParameter::isTemplateTypeParameter() +{ + return NULL; +} + +TemplateValueParameter *TemplateParameter::isTemplateValueParameter() +{ + return NULL; +} + +TemplateAliasParameter *TemplateParameter::isTemplateAliasParameter() +{ + return NULL; +} + +TemplateTupleParameter *TemplateParameter::isTemplateTupleParameter() +{ + return NULL; +} + +#if DMDV2 +TemplateThisParameter *TemplateParameter::isTemplateThisParameter() +{ + return NULL; +} +#endif + +/* ======================== TemplateTypeParameter =========================== */ + +// type-parameter + +TemplateTypeParameter::TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, + Type *defaultType) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specType = specType; + this->defaultType = defaultType; +} + +TemplateTypeParameter *TemplateTypeParameter::isTemplateTypeParameter() +{ + return this; +} + +TemplateParameter *TemplateTypeParameter::syntaxCopy() +{ + TemplateTypeParameter *tp = new TemplateTypeParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateTypeParameter::declareParameter(Scope *sc) +{ + //printf("TemplateTypeParameter::declareParameter('%s')\n", ident->toChars()); + TypeIdentifier *ti = new TypeIdentifier(loc, ident); + sparam = new AliasDeclaration(loc, ident, ti); + if (!sc->insert(sparam)) + error(loc, "parameter '%s' multiply defined", ident->toChars()); +} + +void TemplateTypeParameter::semantic(Scope *sc) +{ + //printf("TemplateTypeParameter::semantic('%s')\n", ident->toChars()); + if (specType) + { + specType = specType->semantic(loc, sc); + } +#if 0 // Don't do semantic() until instantiation + if (defaultType) + { + defaultType = defaultType->semantic(loc, sc); + } +#endif +} + +/**************************************** + * Determine if two TemplateParameters are the same + * as far as TemplateDeclaration overloading goes. + * Returns: + * 1 match + * 0 no match + */ + +int TemplateTypeParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTypeParameter *ttp = tp->isTemplateTypeParameter(); + + if (ttp) + { + if (specType != ttp->specType) + goto Lnomatch; + + if (specType && !specType->equals(ttp->specType)) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +/******************************************* + * 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] + */ + +MATCH TemplateTypeParameter::matchArg(Scope *sc, Objects *tiargs, + int i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateTypeParameter::matchArg()\n"); + Type *t; + Object *oarg; + MATCH m = MATCHexact; + Type *ta; + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(sc); + if (!oarg) + { assert(i < dedtypes->dim); + // It might have already been deduced + oarg = (Object *)dedtypes->data[i]; + if (!oarg) + goto Lnomatch; + } + } + + ta = isType(oarg); + if (!ta) + goto Lnomatch; + //printf("ta is %s\n", ta->toChars()); + + t = (Type *)dedtypes->data[i]; + + 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; + } + + if (m2 < m) + m = m2; + t = (Type *)dedtypes->data[i]; + } + else + { + // So that matches with specializations are better + m = MATCHconvert; + 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; + } + } + } + + if (!t) + { + dedtypes->data[i] = ta; + t = ta; + } + *psparam = new AliasDeclaration(loc, ident, t); + //printf("\tm = %d\n", m); + return m; + +Lnomatch: + *psparam = NULL; + //printf("\tm = %d\n", MATCHnomatch); + return MATCHnomatch; +} + + +void TemplateTypeParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Type *t = isType(oarg); + Type *ta = isType(oded); + + assert(ta); + + if (specType) + printf("\tSpecialization: %s\n", specType->toChars()); + if (defaultType) + printf("\tDefault: %s\n", defaultType->toChars()); + printf("\tArgument: %s\n", t ? t->toChars() : "NULL"); + printf("\tDeduced Type: %s\n", ta->toChars()); +} + + +void TemplateTypeParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + if (specType) + { + buf->writestring(" : "); + specType->toCBuffer(buf, NULL, hgs); + } + if (defaultType) + { + buf->writestring(" = "); + defaultType->toCBuffer(buf, NULL, hgs); + } +} + + +void *TemplateTypeParameter::dummyArg() +{ Type *t; + + if (specType) + t = specType; + else + { // Use this for alias-parameter's too (?) + t = new TypeIdentifier(loc, ident); + } + return (void *)t; +} + + +Object *TemplateTypeParameter::specialization() +{ + return specType; +} + + +Object *TemplateTypeParameter::defaultArg(Scope *sc) +{ + Type *t; + + t = defaultType; + if (t) + { + t = t->syntaxCopy(); + t = t->semantic(loc, sc); + } + return t; +} + +/* ======================== TemplateThisParameter =========================== */ + +#if DMDV2 +// this-parameter + +TemplateThisParameter::TemplateThisParameter(Loc loc, Identifier *ident, + Type *specType, + Type *defaultType) + : TemplateTypeParameter(loc, ident, specType, defaultType) +{ +} + +TemplateThisParameter *TemplateThisParameter::isTemplateThisParameter() +{ + return this; +} + +TemplateParameter *TemplateThisParameter::syntaxCopy() +{ + TemplateThisParameter *tp = new TemplateThisParameter(loc, ident, specType, defaultType); + if (tp->specType) + tp->specType = specType->syntaxCopy(); + if (defaultType) + tp->defaultType = defaultType->syntaxCopy(); + return tp; +} + +void TemplateThisParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("this "); + TemplateTypeParameter::toCBuffer(buf, hgs); +} +#endif + +/* ======================== TemplateAliasParameter ========================== */ + +// alias-parameter + +Dsymbol *TemplateAliasParameter::sdummy = NULL; + +TemplateAliasParameter::TemplateAliasParameter(Loc loc, Identifier *ident, Type *specAliasT, Type *defaultAlias) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->specAliasT = specAliasT; + this->defaultAlias = defaultAlias; + + this->specAlias = NULL; +} + +TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() +{ + return this; +} + +TemplateParameter *TemplateAliasParameter::syntaxCopy() +{ + TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specAliasT, defaultAlias); + if (tp->specAliasT) + tp->specAliasT = specAliasT->syntaxCopy(); + if (defaultAlias) + tp->defaultAlias = defaultAlias->syntaxCopy(); + return tp; +} + +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()); +} + +void TemplateAliasParameter::semantic(Scope *sc) +{ + if (specAliasT) + { + specAlias = specAliasT->toDsymbol(sc); + if (!specAlias) + error(loc, "%s is not a symbol", specAliasT->toChars()); + } +#if 0 // Don't do semantic() until instantiation + if (defaultAlias) + defaultAlias = defaultAlias->semantic(loc, sc); +#endif +} + +int TemplateAliasParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); + + if (tap) + { + if (specAlias != tap->specAlias) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + +MATCH TemplateAliasParameter::matchArg(Scope *sc, + Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + Dsymbol *sa; + Object *oarg; + Expression *ea; + + //printf("TemplateAliasParameter::matchArg()\n"); + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(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) + goto Lnomatch; + + if (specAlias) + { + if (!sa || sa == sdummy) + goto Lnomatch; + if (sa != specAlias) + goto Lnomatch; + } + else if (dedtypes->data[i]) + { // Must match already deduced symbol + Dsymbol *s = (Dsymbol *)dedtypes->data[i]; + + if (!sa || s != sa) + goto Lnomatch; + } + dedtypes->data[i] = sa; + + *psparam = new AliasDeclaration(loc, ident, sa); + return MATCHexact; + +Lnomatch: + *psparam = NULL; + return MATCHnomatch; +} + + +void TemplateAliasParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Dsymbol *sa = isDsymbol(oded); + assert(sa); + + printf("\tArgument alias: %s\n", sa->toChars()); +} + +void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("alias "); + buf->writestring(ident->toChars()); + if (specAliasT) + { + buf->writestring(" : "); + specAliasT->toCBuffer(buf, NULL, hgs); + } + if (defaultAlias) + { + buf->writestring(" = "); + defaultAlias->toCBuffer(buf, NULL, hgs); + } +} + + +void *TemplateAliasParameter::dummyArg() +{ Dsymbol *s; + + s = specAlias; + if (!s) + { + if (!sdummy) + sdummy = new Dsymbol(); + s = sdummy; + } + return (void*)s; +} + + +Object *TemplateAliasParameter::specialization() +{ + return specAliasT; +} + + +Object *TemplateAliasParameter::defaultArg(Scope *sc) +{ + Dsymbol *s = NULL; + + if (defaultAlias) + { + s = defaultAlias->toDsymbol(sc); + if (!s) + error("%s is not a symbol", defaultAlias->toChars()); + } + return s; +} + +/* ======================== TemplateValueParameter ========================== */ + +// value-parameter + +Expression *TemplateValueParameter::edummy = NULL; + +TemplateValueParameter::TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, + Expression *specValue, Expression *defaultValue) + : TemplateParameter(loc, ident) +{ + this->ident = ident; + this->valType = valType; + this->specValue = specValue; + this->defaultValue = defaultValue; +} + +TemplateValueParameter *TemplateValueParameter::isTemplateValueParameter() +{ + return this; +} + +TemplateParameter *TemplateValueParameter::syntaxCopy() +{ + TemplateValueParameter *tp = + new TemplateValueParameter(loc, ident, valType, specValue, defaultValue); + tp->valType = valType->syntaxCopy(); + if (specValue) + tp->specValue = specValue->syntaxCopy(); + if (defaultValue) + tp->defaultValue = defaultValue->syntaxCopy(); + return tp; +} + +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()); + sparam = v; +} + +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()); + + 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(); + } + +#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(); + } +#endif +} + +int TemplateValueParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateValueParameter *tvp = tp->isTemplateValueParameter(); + + if (tvp) + { + if (valType != tvp->valType) + goto Lnomatch; + + if (valType && !valType->equals(tvp->valType)) + goto Lnomatch; + + if (specValue != tvp->specValue) + goto Lnomatch; + + return 1; // match + } + +Lnomatch: + return 0; +} + + +MATCH TemplateValueParameter::matchArg(Scope *sc, + Objects *tiargs, int i, TemplateParameters *parameters, Objects *dedtypes, + Declaration **psparam) +{ + //printf("TemplateValueParameter::matchArg()\n"); + + Initializer *init; + Declaration *sparam; + MATCH m = MATCHexact; + Expression *ei; + Object *oarg; + + if (i < tiargs->dim) + oarg = (Object *)tiargs->data[i]; + else + { // Get default argument instead + oarg = defaultArg(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; + + if (specValue) + { + if (!ei || ei == edummy) + goto Lnomatch; + + Expression *e = specValue; + + e = e->semantic(sc); + e = e->implicitCastTo(sc, valType); + e = e->optimize(WANTvalue | WANTinterpret); + + ei = ei->syntaxCopy(); + ei = ei->semantic(sc); + ei = ei->optimize(WANTvalue | WANTinterpret); + //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); + //printf("e : %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]; + + if (!ei || !ei->equals(e)) + goto Lnomatch; + } +Lmatch: + //printf("valType: %s, ty = %d\n", valType->toChars(), valType->ty); + vt = valType->semantic(0, sc); + //printf("ei: %s, %s\n", ei->toChars(), ei->type->toChars()); + if (ei->type) + { + m = (MATCH)ei->implicitConvTo(vt); + //printf("m: %d\n", m); + if (!m) + goto Lnomatch; + } + dedtypes->data[i] = ei; + + init = new ExpInitializer(loc, ei); + sparam = new VarDeclaration(loc, vt, ident, init); + sparam->storage_class = STCconst; + *psparam = sparam; + return m; + +Lnomatch: + //printf("\tno match\n"); + *psparam = NULL; + return MATCHnomatch; +} + + +void TemplateValueParameter::print(Object *oarg, Object *oded) +{ + printf(" %s\n", ident->toChars()); + + Expression *ea = isExpression(oded); + + if (specValue) + printf("\tSpecialization: %s\n", specValue->toChars()); + printf("\tArgument Value: %s\n", ea ? ea->toChars() : "NULL"); +} + + +void TemplateValueParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + valType->toCBuffer(buf, ident, hgs); + if (specValue) + { + buf->writestring(" : "); + specValue->toCBuffer(buf, hgs); + } + if (defaultValue) + { + buf->writestring(" = "); + defaultValue->toCBuffer(buf, hgs); + } +} + + +void *TemplateValueParameter::dummyArg() +{ Expression *e; + + e = specValue; + if (!e) + { + // Create a dummy value + if (!edummy) + edummy = valType->defaultInit(); + e = edummy; + } + return (void *)e; +} + + +Object *TemplateValueParameter::specialization() +{ + return specValue; +} + + +Object *TemplateValueParameter::defaultArg(Scope *sc) +{ + Expression *e = defaultValue; + if (e) + { + e = e->syntaxCopy(); + e = e->semantic(sc); +#if DMDV2 + if (e->op == TOKdefault) + { DefaultInitExp *de = (DefaultInitExp *)e; + e = de->resolve(loc, sc); + } +#endif + } + return e; +} + +/* ======================== TemplateTupleParameter ========================== */ + +// variadic-parameter + +TemplateTupleParameter::TemplateTupleParameter(Loc loc, Identifier *ident) + : TemplateParameter(loc, ident) +{ + this->ident = ident; +} + +TemplateTupleParameter *TemplateTupleParameter::isTemplateTupleParameter() +{ + return this; +} + +TemplateParameter *TemplateTupleParameter::syntaxCopy() +{ + TemplateTupleParameter *tp = new TemplateTupleParameter(loc, ident); + return tp; +} + +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()); +} + +void TemplateTupleParameter::semantic(Scope *sc) +{ +} + +int TemplateTupleParameter::overloadMatch(TemplateParameter *tp) +{ + TemplateTupleParameter *tvp = tp->isTemplateTupleParameter(); + + if (tvp) + { + return 1; // match + } + +Lnomatch: + return 0; +} + +MATCH TemplateTupleParameter::matchArg(Scope *sc, + Objects *tiargs, int i, TemplateParameters *parameters, + Objects *dedtypes, + Declaration **psparam) +{ + //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 + Tuple *ovar; + if (i + 1 == tiargs->dim && 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]; + } + } + *psparam = new TupleDeclaration(loc, ident, &ovar->objects); + dedtypes->data[i] = (void *)ovar; + return MATCHexact; +} + + +void TemplateTupleParameter::print(Object *oarg, Object *oded) +{ + printf(" %s... [", ident->toChars()); + Tuple *v = isTuple(oded); + assert(v); + + //printf("|%d| ", v->objects.dim); + for (int i = 0; i < v->objects.dim; i++) + { + if (i) + printf(", "); + + Object *o = (Object *)v->objects.data[i]; + + Dsymbol *sa = isDsymbol(o); + if (sa) + printf("alias: %s", sa->toChars()); + + Type *ta = isType(o); + if (ta) + printf("type: %s", ta->toChars()); + + Expression *ea = isExpression(o); + if (ea) + printf("exp: %s", ea->toChars()); + + assert(!isTuple(o)); // no nested Tuple arguments + } + + printf("]\n"); +} + +void TemplateTupleParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring(ident->toChars()); + buf->writestring("..."); +} + + +void *TemplateTupleParameter::dummyArg() +{ + return NULL; +} + + +Object *TemplateTupleParameter::specialization() +{ + return NULL; +} + + +Object *TemplateTupleParameter::defaultArg(Scope *sc) +{ + return NULL; +} + +/* ======================== TemplateInstance ================================ */ + +TemplateInstance::TemplateInstance(Loc loc, Identifier *ident) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, ident = '%s')\n", this, ident ? ident->toChars() : "null"); +#endif + this->loc = loc; + this->name = ident; + this->tiargs = NULL; + this->tempdecl = NULL; + this->inst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticdone = 0; + this->semantictiargsdone = 0; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 0; + this->isnested = NULL; + this->errors = 0; +} + + +TemplateInstance::TemplateInstance(Loc loc, TemplateDeclaration *td, Objects *tiargs) + : ScopeDsymbol(NULL) +{ +#if LOG + printf("TemplateInstance(this = %p, tempdecl = '%s')\n", this, td->toChars()); +#endif + this->loc = loc; + this->name = td->ident; + this->tiargs = tiargs; + this->tempdecl = td; + this->inst = NULL; + this->argsym = NULL; + this->aliasdecl = NULL; + this->semanticdone = 0; + this->semantictiargsdone = 1; + this->withsym = NULL; + this->nest = 0; + this->havetempdecl = 1; + this->isnested = NULL; + this->errors = 0; + + assert((size_t)tempdecl->scope > 0x10000); +} + + +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++) + { + Type *ta = isType((Object *)objs->data[i]); + if (ta) + a->data[i] = ta->syntaxCopy(); + else + { + Expression *ea = isExpression((Object *)objs->data[i]); + assert(ea); + a->data[i] = ea->syntaxCopy(); + } + } + } + return a; +} + +Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) +{ + TemplateInstance *ti; + int i; + + if (s) + ti = (TemplateInstance *)s; + else + ti = new TemplateInstance(loc, name); + + ti->tiargs = arraySyntaxCopy(tiargs); + + ScopeDsymbol::syntaxCopy(ti); + return ti; +} + + +void TemplateInstance::semantic(Scope *sc) +{ + if (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 LOG + printf("-TemplateInstance::semantic('%s', this=%p) already run\n", inst->toChars(), inst); +#endif + return; + } + + if (semanticdone != 0) + { + error(loc, "recursive template expansion"); +// inst = this; + return; + } + semanticdone = 1; + +#if LOG + printf("\tdo semantic\n"); +#endif + if (havetempdecl) + { + assert((size_t)tempdecl->scope > 0x10000); + // Deduce tdtypes + tdtypes.setDim(tempdecl->parameters->dim); + if (!tempdecl->matchWithInstance(this, &tdtypes, 0)) + { + error("incompatible arguments for template instantiation"); + inst = this; + return; + } + } + else + { + // Run semantic on each argument, place results in tiargs[] + semanticTiargs(sc); + + 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 + } + } + + isNested(tiargs); + + /* See if there is an existing TemplateInstantiation that already + * implements the typeargs. If so, just refer to that one instead. + */ + + for (size_t i = 0; i < tempdecl->instances.dim; 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()); +#endif + assert(tdtypes.dim == ti->tdtypes.dim); + + // Nesting must match + if (isnested != ti->isnested) + continue; +#if 0 + 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; + } + + // It's a match + inst = ti; + parent = ti->parent; +#if LOG + printf("\tit's a match with instance %p\n", inst); +#endif + return; + + L1: + ; + } + + /* So, we need to implement 'this' instance. + */ +#if LOG + printf("\timplement template instance '%s'\n", toChars()); +#endif + unsigned errorsave = global.errors; + inst = this; + int tempdecl_instance_idx = tempdecl->instances.dim; + tempdecl->instances.push(this); + parent = tempdecl->parent; + //printf("parent = '%s'\n", parent->kind()); + + ident = genIdent(); // need an identifier for name mangling purposes. + +#if 1 + if (isnested) + parent = isnested; +#endif + //printf("parent = '%s'\n", parent->kind()); + + // Add 'this' to the enclosing scope's members[] so the semantic routines + // will get called on the instance members +#if 1 + int dosemantic3 = 0; + { Array *a; + int i; + + if (sc->scopesym && sc->scopesym->members && !sc->scopesym->isTemplateMixin()) + { + //printf("\t1: adding to %s %s\n", sc->scopesym->kind(), sc->scopesym->toChars()); + a = sc->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->semanticdone >= 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 + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + + // Create our own scope for the template parameters + Scope *scope = tempdecl->scope; + if (!scope) + { + error("forward reference to template declaration %s\n", tempdecl->toChars()); + return; + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + argsym = new ScopeDsymbol(); + argsym->parent = scope->parent; + scope = scope->push(argsym); + + // Declare each template parameter as an alias for the argument type + declareParameters(scope); + + // Add members of template instance to template instance symbol table +// parent = scope->scopesym; + symtab = new DsymbolTable(); + int memnum = 0; + for (int i = 0; i < members->dim; 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); +#endif + memnum |= s->addMember(scope, this, memnum); + } +#if LOG + printf("adding members done\n"); +#endif + + /* See if there is only one member of template instance, and that + * member has the same name as the template instance. + * If so, this template instance becomes an alias for that member. + */ + //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); + } + } + } + + // Do semantic() analysis on template instance members +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = scope->push(this); + //printf("isnested = %d, sc->parent = %s\n", isnested, sc->parent->toChars()); + sc2->parent = /*isnested ? sc->parent :*/ this; + +#if !IN_LLVM +#if _WIN32 + __try + { +#endif +#endif + 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(); + } +#if !IN_LLVM +#if _WIN32 + } + __except (__ehfilter(GetExceptionInformation())) + { + global.gag = 0; // ensure error message gets printed + error("recursive expansion"); + fatal(); + } +#endif +#endif + + /* If any of the instantiation members didn't get semantic() run + * on them due to forward references, we cannot run semantic2() + * or semantic3() yet. + */ + for (size_t i = 0; i < Module::deferred.dim; i++) + { Dsymbol *sd = (Dsymbol *)Module::deferred.data[i]; + + if (sd->parent == this) + goto Laftersemantic; + } + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// 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); + + if (sc->func || dosemantic3) + { + semantic3(sc2); + } + + Laftersemantic: + sc2->pop(); + + scope->pop(); + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error("error instantiating"); + errors = 1; + if (global.gag) + tempdecl->instances.remove(tempdecl_instance_idx); + } + +#if LOG + printf("-TemplateInstance::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + + +void TemplateInstance::semanticTiargs(Scope *sc) +{ + //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); + if (semantictiargsdone) + return; + semantictiargsdone = 1; + semanticTiargs(loc, sc, tiargs); +} + +void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs) +{ + // Run semantic on each argument, place results in tiargs[] + //printf("+TemplateInstance::semanticTiargs() %s\n", toChars()); + if (!tiargs) + 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); + + //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); + 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) + { + 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); + ea = ea->optimize(WANTvalue | WANTinterpret); + tiargs->data[j] = ea; + if (ea->op == TOKtype) + tiargs->data[j] = ea->type; + } + else if (sa) + { + } + 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); + + printf("\ttiargs[%d] = ta %p, ea %p, sa %p, va %p\n", j, ta, ea, sa, va); + } +#endif +} + +/********************************************** + * Find template declaration corresponding to template instance. + */ + +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; + + 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()); +#endif + 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; + } + } + + 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; + } +#ifdef DEBUG + //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; + } + } + } + else + assert(tempdecl->isTemplateDeclaration()); + return tempdecl; +} + +TemplateDeclaration *TemplateInstance::findBestMatch(Scope *sc) +{ + /* Since there can be multiple TemplateDeclaration's with the same + * name, look for the best match. + */ + TemplateDeclaration *td_ambig = NULL; + TemplateDeclaration *td_best = NULL; + MATCH m_best = MATCHnomatch; + Objects dedtypes; + +#if LOG + printf("TemplateInstance::findBestMatch()\n"); +#endif + for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) + { + 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; + } + + dedtypes.setDim(td->parameters->dim); + dedtypes.zero(); + if (!td->scope) + { + error("forward reference to template declaration %s", td->toChars()); + return NULL; + } + m = td->matchWithInstance(this, &dedtypes, 0); + //printf("m = %d\n", m); + if (!m) // no match at all + continue; + +#if 1 + if (m < m_best) + goto Ltd_best; + if (m > m_best) + goto Ltd; +#else + if (!m_best) + goto Ltd; +#endif + { + // Disambiguate by picking the most specialized TemplateDeclaration + int c1 = td->leastAsSpecialized(td_best); + int 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; + } + + 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: // 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) + { + 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()); + } + + /* The best match is td_best + */ + tempdecl = td_best; + +#if 0 + /* 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; + } + } +#endif + +#if LOG + printf("\tIt's a match with template declaration '%s'\n", tempdecl->toChars()); +#endif + return tempdecl; +} + + +/***************************************** + * Determines if a TemplateInstance will need a nested + * generation of the TemplateDeclaration. + */ + +int TemplateInstance::isNested(Objects *args) +{ int nested = 0; + //printf("TemplateInstance::isNested('%s')\n", tempdecl->ident->toChars()); + + /* A nested instance happens when an argument references a local + * symbol that is on the stack. + */ + 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 = sa->isDeclaration(); + if (d && !d->isDataseg() && +#if DMDV2 + !(d->storage_class & STCmanifest) && +#endif + (!d->isFuncDeclaration() || d->isFuncDeclaration()->isNested()) && + !isTemplateMixin()) + { + // if module level template + if (tempdecl->toParent()->isModule()) + { Dsymbol *dparent = d->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; 1; p = p->parent) + { + if (p == isnested) + { isnested = dparent; + goto L1; // dparent is most nested + } + } + error("is nested in both %s and %s", isnested->toChars(), dparent->toChars()); + } + L1: + //printf("\tnested inside %s\n", isnested->toChars()); + nested |= 1; + } + else + error("cannot use local '%s' as template parameter", d->toChars()); + } + } + else if (va) + { + nested |= isNested(&va->objects); + } + } + return nested; +} + +/**************************************** + * This instance needs an identifier for name mangling purposes. + * Create one by taking the template declaration name and adding + * the type signature for it. + */ + +Identifier *TemplateInstance::genIdent() +{ OutBuffer buf; + char *id; + Objects *args; + + //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); + id = tempdecl->ident->toChars(); + buf.printf("__T%"PRIuSIZE"%s", strlen(id), id); + 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 %p ta %p ea %p sa %p va %p\n", 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()); +#endif + assert(global.errors); + } + } + else if (ea) + { sinteger_t v; + real_t r; + + 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); +#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); +#endif + ea->toMangleBuffer(&buf); + } + else if (sa) + { + Lsa: + buf.writeByte('S'); + Declaration *d = sa->isDeclaration(); + if (d && !d->type->deco) + error("forward reference of %s", d->toChars()); + else + { + char *p = sa->mangle(); + buf.printf("%"PRIuSIZE"%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(); + buf.data = NULL; + return new Identifier(id, TOKidentifier); +} + + +/**************************************************** + * Declare parameters of template instance, initialize them with the + * template instance arguments. + */ + +void TemplateInstance::declareParameters(Scope *scope) +{ + //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]; + + //printf("\ttdtypes[%d] = %p\n", i, o); + tempdecl->declareParameter(scope, tp, o); + } +} + + +void TemplateInstance::semantic2(Scope *sc) +{ int i; + + if (semanticdone >= 2) + return; + semanticdone = 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); + 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(); + } +#if LOG + printf("-TemplateInstance::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateInstance::semantic3(Scope *sc) +{ +#if LOG + printf("TemplateInstance::semantic3('%s'), semanticdone = %d\n", toChars(), semanticdone); +#endif +//if (toChars()[0] == 'D') *(char*)0=0; + if (semanticdone >= 3) + return; + semanticdone = 3; + if (!errors && members) + { + sc = tempdecl->scope; + sc = sc->push(argsym); + sc = sc->push(this); + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic3(sc); + } + sc = sc->pop(); + sc->pop(); + } +} + +void TemplateInstance::toObjFile(int multiobj) +{ +#if LOG + printf("TemplateInstance::toObjFile('%s', this = %p)\n", toChars(), this); +#endif + if (!errors && members) + { + if (multiobj) + // Append to list of object files to be written later + //obj_append(this); + assert(0 && "multiobj"); + else + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->toObjFile(multiobj); + } + } + } +} + +void TemplateInstance::inlineScan() +{ +#if LOG + printf("TemplateInstance::inlineScan('%s')\n", toChars()); +#endif + if (!errors && members) + { + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->inlineScan(); + } + } +} + +void TemplateInstance::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + int i; + + Identifier *id = name; + buf->writestring(id->toChars()); + buf->writestring("!("); + if (nest) + 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--; + } + buf->writeByte(')'); +} + + +Dsymbol *TemplateInstance::toAlias() +{ +#if LOG + printf("TemplateInstance::toAlias()\n"); +#endif + if (!inst) + { error("cannot resolve forward reference"); + return this; + } + + if (inst != this) + return inst->toAlias(); + + if (aliasdecl) + return aliasdecl->toAlias(); + + return inst; +} + +AliasDeclaration *TemplateInstance::isAliasDeclaration() +{ + return aliasdecl; +} + +const char *TemplateInstance::kind() +{ + return "template instance"; +} + +int TemplateInstance::oneMember(Dsymbol **ps) +{ + *ps = NULL; + return TRUE; +} + +char *TemplateInstance::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +/* ======================== TemplateMixin ================================ */ + +TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, + Array *idents, Objects *tiargs) + : TemplateInstance(loc, (Identifier *)idents->data[idents->dim - 1]) +{ + //printf("TemplateMixin(ident = '%s')\n", ident ? ident->toChars() : ""); + this->ident = ident; + this->tqual = tqual; + this->idents = idents; + this->tiargs = tiargs ? tiargs : new Objects(); + this->scope = NULL; +} + +Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) +{ TemplateMixin *tm; + + Array *ids = new Array(); + ids->setDim(idents->dim); + for (int i = 0; i < idents->dim; i++) + { // Matches TypeQualified::syntaxCopyHelper() + Identifier *id = (Identifier *)idents->data[i]; + if (id->dyncast() == DYNCAST_DSYMBOL) + { + TemplateInstance *ti = (TemplateInstance *)id; + + ti = (TemplateInstance *)ti->syntaxCopy(NULL); + id = (Identifier *)ti; + } + ids->data[i] = id; + } + + tm = new TemplateMixin(loc, ident, + (Type *)(tqual ? tqual->syntaxCopy() : NULL), + ids, tiargs); + TemplateInstance::syntaxCopy(tm); + return tm; +} + +void TemplateMixin::semantic(Scope *sc) +{ +#if LOG + printf("+TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); + fflush(stdout); +#endif + if (semanticdone && + // This for when a class/struct contains mixin members, and + // is done over because of forward references + (!parent || !toParent()->isAggregateDeclaration())) + { +#if LOG + printf("\tsemantic done\n"); +#endif + return; + } + if (!semanticdone) + semanticdone = 1; +#if LOG + printf("\tdo semantic\n"); +#endif + +#if !IN_LLVM + // dont know what this is + util_progress(); +#endif + + Scope *scx = NULL; + if (scope) + { 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; + + 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); + } + } + + 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->scope) + { + /* 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. + */ + semanticdone = 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); + + tempdecl = findBestMatch(sc); + if (!tempdecl) + { inst = this; + return; // error recovery + } + + if (!ident) + ident = genIdent(); + + inst = this; + parent = sc->parent; + + /* Detect recursive mixin instantiations. + */ + for (Dsymbol *s = parent; s; s = s->parent) + { + //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; + + 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; + } + + // Copy the syntax trees from the TemplateDeclaration + members = Dsymbol::arraySyntaxCopy(tempdecl->members); + if (!members) + return; + + symtab = new DsymbolTable(); + + for (Scope *sce = sc; 1; sce = sce->enclosing) + { + ScopeDsymbol *sds = (ScopeDsymbol *)sce->scopesym; + if (sds) + { + sds->importScope(this, PROTpublic); + break; + } + } + +#if LOG + printf("\tcreate scope for template parameters '%s'\n", toChars()); +#endif + Scope *scy = sc; + scy = sc->push(this); + scy->parent = this; + + argsym = new ScopeDsymbol(); + argsym->parent = scy->parent; + Scope *scope = scy->push(argsym); + + unsigned errorsave = global.errors; + + // Declare each template parameter as an alias for the argument type + declareParameters(scope); + + // Add members to enclosing scope, as well as this scope + for (unsigned i = 0; i < members->dim; i++) + { Dsymbol *s; + + s = (Dsymbol *)members->data[i]; + s->addMember(scope, 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 +#if LOG + printf("\tdo semantic() on template instance members '%s'\n", toChars()); +#endif + Scope *sc2; + sc2 = scope->push(this); + sc2->offset = sc->offset; + for (int i = 0; i < members->dim; i++) + { + Dsymbol *s = (Dsymbol *)members->data[i]; + s->semantic(sc2); + } + sc->offset = sc2->offset; + + /* The problem is when to parse the initializer for a variable. + * Perhaps VarDeclaration::semantic() should do it like it does + * for initializers inside a function. + */ +// if (sc->parent->isFuncDeclaration()) + + semantic2(sc2); + + if (sc->func) + { + semantic3(sc2); + } + + // Give additional context info if error occurred during instantiation + if (global.errors != errorsave) + { + error("error instantiating"); + } + + sc2->pop(); + + scope->pop(); + +// if (!isAnonymous()) + { + scy->pop(); + } +#if LOG + printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); +#endif +} + +void TemplateMixin::semantic2(Scope *sc) +{ int i; + + if (semanticdone >= 2) + return; + semanticdone = 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]; +#if LOG + printf("\tmember '%s', kind = '%s'\n", s->toChars(), s->kind()); +#endif + s->semantic2(sc); + } + sc = sc->pop(); + sc->pop(); + } +#if LOG + printf("-TemplateMixin::semantic2('%s')\n", toChars()); +#endif +} + +void TemplateMixin::semantic3(Scope *sc) +{ int i; + + if (semanticdone >= 3) + return; + semanticdone = 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(); + } +} + +void TemplateMixin::inlineScan() +{ + TemplateInstance::inlineScan(); +} + +const char *TemplateMixin::kind() +{ + return "mixin"; +} + +int TemplateMixin::oneMember(Dsymbol **ps) +{ + return Dsymbol::oneMember(ps); +} + +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; + } + } + return 0; +} + +char *TemplateMixin::toChars() +{ + OutBuffer buf; + HdrGenState hgs; + char *s; + + TemplateInstance::toCBuffer(&buf, &hgs); + s = buf.toChars(); + buf.data = NULL; + return s; +} + +void TemplateMixin::toCBuffer(OutBuffer *buf, HdrGenState *hgs) +{ + buf->writestring("mixin "); + + for (int i = 0; i < idents->dim; i++) + { Identifier *id = (Identifier *)idents->data[i]; + + if (i) + buf->writeByte('.'); + buf->writestring(id->toChars()); + } + buf->writestring("!("); + if (tiargs) + { + 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); + } + } + } + buf->writebyte(')'); + if (ident) + { + buf->writebyte(' '); + buf->writestring(ident->toChars()); + } + buf->writebyte(';'); + buf->writenl(); +} + + +void TemplateMixin::toObjFile(int multiobj) +{ + //printf("TemplateMixin::toObjFile('%s')\n", toChars()); + TemplateInstance::toObjFile(multiobj); +} +
--- a/dmd/template.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/template.h Sat Jul 12 19:38:31 2008 +0200 @@ -26,6 +26,7 @@ struct TemplateInstance; struct TemplateParameter; struct TemplateTypeParameter; +struct TemplateThisParameter; struct TemplateValueParameter; struct TemplateAliasParameter; struct TemplateTupleParameter; @@ -52,7 +53,7 @@ TemplateParameters *origParameters; // originals for Ddoc - Array instances; // array of TemplateInstance's + Array instances; // array of TemplateInstance's TemplateDeclaration *overnext; // next overloaded TemplateDeclaration TemplateDeclaration *overroot; // first in overnext list @@ -65,7 +66,7 @@ void semantic(Scope *sc); int overloadInsert(Dsymbol *s); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); char *toChars(); void emitComment(Scope *sc); @@ -152,6 +153,23 @@ 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: @@ -251,6 +269,7 @@ // sole member WithScopeSymbol *withsym; // if a member of a with statement int semanticdone; // 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 @@ -272,12 +291,12 @@ void inlineScan(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); Dsymbol *toAlias(); // resolve real symbol - char *kind(); + const char *kind(); int oneMember(Dsymbol **ps); char *toChars(); char *mangle(); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file // Internal static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs); @@ -305,14 +324,14 @@ void semantic2(Scope *sc); void semantic3(Scope *sc); void inlineScan(); - char *kind(); + const char *kind(); int oneMember(Dsymbol **ps); int hasPointers(); char *toChars(); char *mangle(); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toObjFile(); // compile to .obj file + void toObjFile(int multiobj); // compile to .obj file TemplateMixin *isTemplateMixin() { return this; } };
--- a/dmd/version.c Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/version.c Sat Jul 12 19:38:31 2008 +0200 @@ -93,7 +93,7 @@ buf->writenl(); } -char *DebugSymbol::kind() +const char *DebugSymbol::kind() { return "debug"; } @@ -173,7 +173,7 @@ buf->writenl(); } -char *VersionSymbol::kind() +const char *VersionSymbol::kind() { return "version"; }
--- a/dmd/version.h Sat Jul 12 17:04:36 2008 +0200 +++ b/dmd/version.h Sat Jul 12 19:38:31 2008 +0200 @@ -31,7 +31,7 @@ int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); }; struct VersionSymbol : Dsymbol @@ -45,7 +45,7 @@ int addMember(Scope *sc, ScopeDsymbol *s, int memnum); void semantic(Scope *sc); void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *kind(); + const char *kind(); }; #endif /* DMD_VERSION_H */
--- a/gen/asmstmt.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/asmstmt.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -165,6 +165,12 @@ return this; } +int AsmStatement::blockExit() +{ + //printf("AsmStatement::blockExit(%p)\n", this); + return BEfallthru | BEreturn | BEgoto | BEhalt; +} + void AsmStatement::toIR(IRState * irs) {
--- a/gen/classes.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/classes.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -80,7 +80,7 @@ for (int k=0; k < arr->dim; k++) { VarDeclaration* v = (VarDeclaration*)(arr->data[k]); - v->toObjFile(); + v->toObjFile(0); // TODO: multiobj } } } @@ -147,7 +147,7 @@ if(cd->members) { for (int k=0; k < cd->members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(cd->members->data[k]); - dsym->toObjFile(); + dsym->toObjFile(0); // TODO: multiobj } }
--- a/gen/dvalue.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/dvalue.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -1,12 +1,12 @@ #include "gen/llvm.h" -#include "declaration.h" - #include "gen/tollvm.h" #include "gen/irstate.h" #include "gen/logger.h" #include "gen/dvalue.h" +#include "declaration.h" + ///////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/functions.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/functions.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -86,7 +86,7 @@ if (typesafeVararg) { ClassDeclaration* ti = Type::typeinfo; - ti->toObjFile(); + ti->toObjFile(0); // TODO: multiobj DtoForceConstInitDsymbol(ti); assert(ti->ir.irStruct->constInit); std::vector<const LLType*> types;
--- a/gen/structs.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/structs.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -131,7 +131,7 @@ Array* arr = &sd->fields; for (int k=0; k < arr->dim; k++) { VarDeclaration* v = (VarDeclaration*)arr->data[k]; - v->toObjFile(); + v->toObjFile(0); // TODO: multiobj } bool thisModule = false; @@ -144,11 +144,11 @@ Dsymbol* s = (Dsymbol*)arr->data[k]; if (FuncDeclaration* fd = s->isFuncDeclaration()) { if (thisModule || (fd->prot() != PROTprivate)) { - fd->toObjFile(); + fd->toObjFile(0); // TODO: multiobj } } else if (s->isAttribDeclaration()) { - s->toObjFile(); + s->toObjFile(0); // TODO: multiobj } else { Logger::println("Ignoring dsymbol '%s' in this->members of kind '%s'", s->toPrettyChars(), s->kind());
--- a/gen/toir.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/toir.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -52,7 +52,7 @@ // static if (vd->isDataseg()) { - vd->toObjFile(); // TODO + vd->toObjFile(0); // TODO: multiobj } else { @@ -245,7 +245,7 @@ else { // take care of forward references of global variables if (vd->isDataseg() || (vd->storage_class & STCextern)) { - vd->toObjFile(); + vd->toObjFile(0); // TODO: multiobj DtoConstInitGlobal(vd); } if (!vd->ir.getIrValue() || DtoType(vd->type)->isAbstract()) {
--- a/gen/toobj.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/toobj.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -53,7 +53,7 @@ ////////////////////////////////////////////////////////////////////////////////////////// -void Module::genobjfile() +void Module::genobjfile(int multiobj) { Logger::cout() << "Generating module: " << (md ? md->toChars() : toChars()) << '\n'; LOG_SCOPE; @@ -120,7 +120,7 @@ for (int k=0; k < members->dim; k++) { Dsymbol* dsym = (Dsymbol*)(members->data[k]); assert(dsym); - dsym->toObjFile(); + dsym->toObjFile(multiobj); } // main driver loop @@ -550,7 +550,7 @@ /* ================================================================== */ -void Dsymbol::toObjFile() +void Dsymbol::toObjFile(int multiobj) { Logger::println("Ignoring Dsymbol::toObjFile for %s", toChars()); } @@ -564,7 +564,7 @@ /* ================================================================== */ -void InterfaceDeclaration::toObjFile() +void InterfaceDeclaration::toObjFile(int multiobj) { //Logger::println("Ignoring InterfaceDeclaration::toObjFile for %s", toChars()); gIR->resolveList.push_back(this); @@ -572,14 +572,14 @@ /* ================================================================== */ -void StructDeclaration::toObjFile() +void StructDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); } /* ================================================================== */ -void ClassDeclaration::toObjFile() +void ClassDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); } @@ -596,7 +596,7 @@ /* ================================================================== */ -void VarDeclaration::toObjFile() +void VarDeclaration::toObjFile(int multiobj) { Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars()); LOG_SCOPE; @@ -604,7 +604,7 @@ if (aliassym) { Logger::println("alias sym"); - toAlias()->toObjFile(); + toAlias()->toObjFile(multiobj); return; } @@ -669,7 +669,7 @@ /* ================================================================== */ -void TypedefDeclaration::toObjFile() +void TypedefDeclaration::toObjFile(int multiobj) { static int tdi = 0; Logger::print("TypedefDeclaration::toObjFile(%d): %s\n", tdi++, toChars()); @@ -681,14 +681,14 @@ /* ================================================================== */ -void EnumDeclaration::toObjFile() +void EnumDeclaration::toObjFile(int multiobj) { Logger::println("Ignoring EnumDeclaration::toObjFile for %s", toChars()); } /* ================================================================== */ -void FuncDeclaration::toObjFile() +void FuncDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); }
--- a/gen/typinf.cpp Sat Jul 12 17:04:36 2008 +0200 +++ b/gen/typinf.cpp Sat Jul 12 19:38:31 2008 +0200 @@ -123,7 +123,7 @@ } else // if in obj generation pass { - t->vtinfo->toObjFile(); + t->vtinfo->toObjFile(0); // TODO: multiobj } } } @@ -244,7 +244,7 @@ // MAGIC PLACE ////////////////////////////////////////////////////////////////////////////// -void TypeInfoDeclaration::toObjFile() +void TypeInfoDeclaration::toObjFile(int multiobj) { gIR->resolveList.push_back(this); }
--- a/premake.lua Sat Jul 12 17:04:36 2008 +0200 +++ b/premake.lua Sat Jul 12 19:38:31 2008 +0200 @@ -18,6 +18,9 @@ end end +-- D version - don't change these !!! +DMDV1 = "1" + -- idgen package = newpackage() package.name = "idgen" @@ -26,6 +29,7 @@ package.files = { "dmd/idgen.c" } package.buildoptions = { "-x c++" } package.postbuildcommands = { "./idgen", "mv -f id.c id.h dmd" } +package.defines = { "DMDV1="..DMDV1 } -- impcnvgen package = newpackage() @@ -35,6 +39,14 @@ package.files = { "dmd/impcnvgen.c" } package.buildoptions = { "-x c++" } package.postbuildcommands = { "./impcnvgen", "mv -f impcnvtab.c dmd" } +package.defines = { "DMDV1="..DMDV1 } + +--md5 +package = newpackage() +package.name = "md5" +package.kind = "lib" +package.language = "c" +package.files = { "dmd/md5.c" } -- llvmdc package = newpackage() @@ -43,7 +55,7 @@ package.kind = "exe" package.language = "c++" package.files = { matchfiles("dmd/*.c"), matchfiles("gen/*.cpp"), matchfiles("ir/*.cpp") } -package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c" } +package.excludes = { "dmd/idgen.c", "dmd/impcnvgen.c", "dmd/md5.c" } package.buildoptions = { "-x c++", "`llvm-config --cxxflags`" } package.linkoptions = { -- long but it's faster than just 'all' @@ -55,6 +67,7 @@ "_DH", "OPAQUE_VTBLS="..OPAQUE_VTBLS, "USE_BOEHM_GC="..USE_BOEHM_GC, + "DMDV1="..DMDV1, } package.config.Release.defines = { "LLVMD_NO_LOGGER" } package.config.Debug.buildoptions = { "-g -O0" }