diff --git a/dmd2/access.c b/dmd2/access.c deleted file mode 100644 index b8b677c6..00000000 --- a/dmd2/access.c +++ /dev/null @@ -1,412 +0,0 @@ - -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "aggregate.h" -#include "init.h" -#include "attrib.h" -#include "scope.h" -#include "id.h" -#include "mtype.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "module.h" - -#define LOG 0 - -/* Code to do access checks - */ - -int hasPackageAccess(Scope *sc, Dsymbol *s); - -/**************************************** - * Return PROT access for Dsymbol smember in this declaration. - */ - -enum PROT AggregateDeclaration::getAccess(Dsymbol *smember) -{ - return PROTpublic; -} - -enum PROT StructDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+StructDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - return access_ret; -} - -enum PROT ClassDeclaration::getAccess(Dsymbol *smember) -{ - enum PROT access_ret = PROTnone; - -#if LOG - printf("+ClassDeclaration::getAccess(this = '%s', smember = '%s')\n", - toChars(), smember->toChars()); -#endif - if (smember->toParent() == this) - { - access_ret = smember->prot(); - } - else - { - if (smember->isDeclaration()->isStatic()) - { - access_ret = smember->prot(); - } - - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = (*baseclasses)[i]; - - enum PROT access = b->base->getAccess(smember); - switch (access) - { - case PROTnone: - break; - - case PROTprivate: - access_ret = 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 (size_t i = 0; i < cdthis->baseclasses->dim; i++) - { BaseClass *b = (*cdthis->baseclasses)[i]; - enum PROT 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 (size_t i = 0; i < cdthis->baseclasses->dim; i++) - { BaseClass *b = (*cdthis->baseclasses)[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 access2 = smember->prot(); - - result = access2 >= PROTpublic || - hasPrivateAccess(f) || - isFriendOf(cdscope) || - (access2 == 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 && getAccessModule() == cd->getAccessModule()) - { -#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 && getAccessModule() == smember->getAccessModule()) - { -#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->toPrettyChars()); - } -#endif - if (!e) - { - if (d->prot() == PROTprivate && d->getAccessModule() != sc->module || - d->prot() == PROTpackage && !hasPackageAccess(sc, d)) - { - error(loc, "%s %s is not accessible from module %s", - d->kind(), d->toPrettyChars(), sc->module->toChars()); - } - } - else if (e->type->ty == Tclass) - { // Do access check - ClassDeclaration *cd = (ClassDeclaration *)(((TypeClass *)e->type)->sym); - if (e->op == TOKsuper) - { - ClassDeclaration *cd2 = sc->func->toParent()->isClassDeclaration(); - if (cd2) - cd = cd2; - } - cd->accessCheck(loc, sc, d); - } - else if (e->type->ty == Tstruct) - { // Do access check - StructDeclaration *cd = (StructDeclaration *)(((TypeStruct *)e->type)->sym); - cd->accessCheck(loc, sc, d); - } -} diff --git a/dmd2/aggregate.h b/dmd2/aggregate.h deleted file mode 100644 index 1d534d28..00000000 --- a/dmd2/aggregate.h +++ /dev/null @@ -1,363 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_AGGREGATE_H -#define DMD_AGGREGATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#include "dsymbol.h" - -#if IN_LLVM -#include -#include -#include -#endif - -struct Identifier; -struct Type; -struct TypeFunction; -struct Expression; -struct FuncDeclaration; -struct CtorDeclaration; -struct DtorDeclaration; -struct InvariantDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct InterfaceDeclaration; -struct TypeInfoClassDeclaration; -struct VarDeclaration; -struct dt_t; - -#if IN_LLVM -struct ClassInfoDeclaration; -namespace llvm -{ - class Type; - class Value; - class Constant; - class ConstantStruct; - class GlobalVariable; -} -#endif - -struct AggregateDeclaration : ScopeDsymbol -{ - Type *type; - StorageClass storage_class; - enum PROT protection; - Type *handle; // 'this' type - unsigned structsize; // size of struct - unsigned alignsize; // size of struct for alignment purposes - unsigned structalign; // struct member alignment in effect - int hasUnions; // set if aggregate has overlapping fields - VarDeclarations fields; // VarDeclaration fields - unsigned sizeok; // set when structsize contains valid data - // 0: no size - // 1: size is correct - // 2: cannot determine size; fwd referenced - Dsymbol *deferred; // any deferred semantic2() or semantic3() symbol - bool isdeprecated; // !=0 if deprecated - -#if DMDV2 - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this aggregate is nested -#endif - // Special member functions - InvariantDeclaration *inv; // invariant - NewDeclaration *aggNew; // allocator - DeleteDeclaration *aggDelete; // deallocator - -#if DMDV2 - //CtorDeclaration *ctor; - Dsymbol *ctor; // CtorDeclaration or TemplateDeclaration - CtorDeclaration *defaultCtor; // default constructor - Dsymbol *aliasthis; // forward unresolved lookups to aliasthis - bool noDefaultCtor; // no default construction -#endif - - FuncDeclarations dtors; // Array of destructors - FuncDeclaration *dtor; // aggregate destructor - -#ifdef IN_GCC - Array methods; // flat list of all methods for debug information -#endif - - AggregateDeclaration(Loc loc, Identifier *id); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - unsigned size(Loc loc); - static void alignmember(unsigned salign, unsigned size, unsigned *poffset); - Type *getType(); - void addField(Scope *sc, VarDeclaration *v); - int firstFieldInUnion(int indx); // first field in union that includes indx - int numFieldsInUnion(int firstIndex); // #fields in union starting at index - int isDeprecated(); // is aggregate deprecated? - FuncDeclaration *buildDtor(Scope *sc); - int isNested(); - int isExport(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - // For access checking - virtual PROT getAccess(Dsymbol *smember); // determine access to smember - int isFriendOf(AggregateDeclaration *cd); - int hasPrivateAccess(Dsymbol *smember); // does smember have private access to members of this class? - void accessCheck(Loc loc, Scope *sc, Dsymbol *smember); - - enum PROT prot(); - -#if IN_DMD - // Back end - Symbol *stag; // tag symbol for debug data - Symbol *sinit; - Symbol *toInitializer(); -#endif - - AggregateDeclaration *isAggregateDeclaration() { return this; } - -#if IN_LLVM - // Aggregates that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; -#endif -}; - -struct AnonymousAggregateDeclaration : AggregateDeclaration -{ - AnonymousAggregateDeclaration() - : AggregateDeclaration(0, NULL) - { - } - - AnonymousAggregateDeclaration *isAnonymousAggregateDeclaration() { return this; } -}; - -struct StructDeclaration : AggregateDeclaration -{ - int zeroInit; // !=0 if initialize with 0 fill -#if DMDV2 - int hasIdentityAssign; // !=0 if has identity opAssign - int hasIdentityEquals; // !=0 if has identity opEquals - FuncDeclaration *cpctor; // generated copy-constructor, if any - FuncDeclarations postblits; // Array of postblit functions - FuncDeclaration *postblit; // aggregate postblit - - FuncDeclaration *xeq; // TypeInfo_Struct.xopEquals - static FuncDeclaration *xerreq; // object.xopEquals -#endif - - StructDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - Dsymbol *search(Loc, Identifier *ident, int flags); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *mangle(); - const char *kind(); - void finalizeSize(); -#if DMDV1 - Expression *cloneMembers(); -#endif -#if DMDV2 - int needOpAssign(); - int needOpEquals(); - FuncDeclaration *buildOpAssign(Scope *sc); - FuncDeclaration *buildOpEquals(Scope *sc); - FuncDeclaration *buildPostBlit(Scope *sc); - FuncDeclaration *buildCpCtor(Scope *sc); - - FuncDeclaration *buildXopEquals(Scope *sc); -#endif - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDt(dt_t **pdt); - void toDebug(); // to symbolic debug info -#endif - - StructDeclaration *isStructDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct UnionDeclaration : StructDeclaration -{ - UnionDeclaration(Loc loc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - const char *kind(); - - UnionDeclaration *isUnionDeclaration() { return this; } -}; - -// warning: two classes with the same base class share the same -// BaseClass instance. -struct BaseClass -{ - Type *type; // (before semantic processing) - enum PROT protection; // protection for the base interface - - ClassDeclaration *base; - int offset; // 'this' pointer offset - FuncDeclarations vtbl; // for interfaces: Array of FuncDeclaration's - // making up the vtbl[] - - size_t baseInterfaces_dim; - BaseClass *baseInterfaces; // if BaseClass is an interface, these - // are a copy of the InterfaceDeclaration::interfaces - - BaseClass(); - BaseClass(Type *type, enum PROT protection); - - int fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance); - void copyBaseInterfaces(BaseClasses *); -}; - -#if DMDV2 -#define CLASSINFO_SIZE_64 0x98 // value of ClassInfo.size -#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size -#else -#define CLASSINFO_SIZE (0x3C+12+4) // value of ClassInfo.size -#endif - -struct ClassDeclaration : AggregateDeclaration -{ - static ClassDeclaration *object; - static ClassDeclaration *classinfo; - static ClassDeclaration *throwable; - static ClassDeclaration *exception; - static ClassDeclaration *errorException; - - ClassDeclaration *baseClass; // NULL only if this is Object -#if DMDV1 - CtorDeclaration *ctor; - CtorDeclaration *defaultCtor; // default constructor -#endif - FuncDeclaration *staticCtor; - FuncDeclaration *staticDtor; - Dsymbols vtbl; // Array of FuncDeclaration's making up the vtbl[] - Dsymbols vtblFinal; // More FuncDeclaration's that aren't in vtbl[] - - BaseClasses *baseclasses; // Array of BaseClass's; first is super, - // rest are Interface's - - size_t interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class - // (does not include baseClass) - - BaseClasses *vtblInterfaces; // array of base interfaces that have - // their own vtbl[] - TypeInfoClassDeclaration *vclassinfo; // the ClassInfo object for this ClassDeclaration - int com; // !=0 if this is a COM class (meaning - // it derives from IUnknown) - int isscope; // !=0 if this is an auto class - int isabstract; // !=0 if abstract class -#if DMDV1 - int isnested; // !=0 if is nested - VarDeclaration *vthis; // 'this' parameter if this class is nested -#endif - int inuse; // to prevent recursive attempts - - ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isBaseOf2(ClassDeclaration *cd); - - #define OFFSET_RUNTIME 0x76543210 - virtual int isBaseOf(ClassDeclaration *cd, int *poffset); - - virtual int isBaseInfoComplete(); - Dsymbol *search(Loc, Identifier *ident, int flags); - Dsymbol *searchBase(Loc, Identifier *ident); -#if DMDV2 - int isFuncHidden(FuncDeclaration *fd); -#endif - FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); - void interfaceSemantic(Scope *sc); -#if DMDV1 - int isNested(); -#endif - int isCOMclass(); - virtual int isCOMinterface(); -#if DMDV2 - virtual int isCPPinterface(); -#endif - int isAbstract(); - virtual int vtblOffset(); - const char *kind(); - char *mangle(); - void toDocBuffer(OutBuffer *buf); - - PROT getAccess(Dsymbol *smember); // determine access to smember - - void addLocalClass(ClassDeclarations *); - -#if IN_DMD - // Back end - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - unsigned baseVtblOffset(BaseClass *bc); - Symbol *toSymbol(); - Symbol *toVtblSymbol(); - void toDt(dt_t **pdt); - void toDt2(dt_t **pdt, ClassDeclaration *cd); - - Symbol *vtblsym; -#endif - - ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; } - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct InterfaceDeclaration : ClassDeclaration -{ -#if DMDV2 - int cpp; // !=0 if this is a C++ interface -#endif - InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - int isBaseOf(ClassDeclaration *cd, int *poffset); - int isBaseOf(BaseClass *bc, int *poffset); - const char *kind(); - int isBaseInfoComplete(); - int vtblOffset(); -#if DMDV2 - int isCPPinterface(); -#endif - virtual int isCOMinterface(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); -#endif - - InterfaceDeclaration *isInterfaceDeclaration() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -#endif /* DMD_AGGREGATE_H */ diff --git a/dmd2/aliasthis.c b/dmd2/aliasthis.c deleted file mode 100644 index f8a74b48..00000000 --- a/dmd2/aliasthis.c +++ /dev/null @@ -1,79 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2009-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "identifier.h" -#include "aliasthis.h" -#include "scope.h" -#include "aggregate.h" -#include "dsymbol.h" - -#if DMDV2 - - -AliasThis::AliasThis(Loc loc, Identifier *ident) - : Dsymbol(NULL) // it's anonymous (no identifier) -{ - this->loc = loc; - this->ident = ident; -} - -Dsymbol *AliasThis::syntaxCopy(Dsymbol *s) -{ - assert(!s); - /* Since there is no semantic information stored here, - * we don't need to copy it. - */ - return this; -} - -void AliasThis::semantic(Scope *sc) -{ - Dsymbol *parent = sc->parent; - if (parent) - parent = parent->pastMixin(); - AggregateDeclaration *ad = NULL; - if (parent) - ad = parent->isAggregateDeclaration(); - if (ad) - { - assert(ad->members); - Dsymbol *s = ad->search(loc, ident, 0); - if (!s) - { s = sc->search(loc, ident, 0); - if (s) - ::error(loc, "%s is not a member of %s", s->toChars(), ad->toChars()); - else - ::error(loc, "undefined identifier %s", ident->toChars()); - } - else if (ad->aliasthis && s != ad->aliasthis) - error("there can be only one alias this"); - ad->aliasthis = s; - } - else - error("alias this can only appear in struct or class declaration, not %s", parent ? parent->toChars() : "nowhere"); -} - -const char *AliasThis::kind() -{ - return "alias this"; -} - -void AliasThis::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - buf->writestring(ident->toChars()); - buf->writestring(" this;\n"); -} - -#endif diff --git a/dmd2/aliasthis.h b/dmd2/aliasthis.h deleted file mode 100644 index c804cdb5..00000000 --- a/dmd2/aliasthis.h +++ /dev/null @@ -1,41 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2009-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ALIASTHIS_H -#define DMD_ALIASTHIS_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "mars.h" -#include "dsymbol.h" - -/**************************************************************/ - -#if DMDV2 - -struct AliasThis : Dsymbol -{ - // alias Identifier this; - Identifier *ident; - - AliasThis(Loc loc, Identifier *ident); - - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - AliasThis *isAliasThis() { return this; } -}; - -#endif - -#endif diff --git a/dmd2/apply.c b/dmd2/apply.c deleted file mode 100644 index f5a5ede8..00000000 --- a/dmd2/apply.c +++ /dev/null @@ -1,165 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "expression.h" - - -/************************************** - * An Expression tree walker that will visit each Expression e in the tree, - * in depth-first evaluation order, and call fp(e,param) on it. - * fp() signals whether the walking continues with its return value: - * Returns: - * 0 continue - * 1 done - * It's a bit slower than using virtual functions, but more encapsulated and less brittle. - * Creating an iterator for this would be much more complex. - */ - -typedef int (*fp_t)(Expression *, void *); - -int Expression::apply(fp_t fp, void *param) -{ - return (*fp)(this, param); -} - -/****************************** - * Perform apply() on an array of Expressions. - */ - -int arrayExpressionApply(Expressions *a, fp_t fp, void *param) -{ - //printf("arrayExpressionApply(%p)\n", a); - if (a) - { - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (*a)[i]; - - if (e) - { - if (e->apply(fp, param)) - return 1; - } - } - } - return 0; -} - -int NewExp::apply(int (*fp)(Expression *, void *), void *param) -{ - //printf("NewExp::apply(): %s\n", toChars()); - - return ((thisexp ? thisexp->apply(fp, param) : 0) || - arrayExpressionApply(newargs, fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param)); -} - -int NewAnonClassExp::apply(int (*fp)(Expression *, void *), void *param) -{ - //printf("NewAnonClassExp::apply(): %s\n", toChars()); - - return ((thisexp ? thisexp->apply(fp, param) : 0) || - arrayExpressionApply(newargs, fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param)); -} - -int UnaExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - (*fp)(this, param); -} - -int BinExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - e2->apply(fp, param) || - (*fp)(this, param); -} - -int AssertExp::apply(fp_t fp, void *param) -{ - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - (msg ? msg->apply(fp, param) : 0) || - (*fp)(this, param); -} - - -int CallExp::apply(fp_t fp, void *param) -{ - //printf("CallExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param); -} - - -int ArrayExp::apply(fp_t fp, void *param) -{ - //printf("ArrayExp::apply(fp_t fp, void *param): %s\n", toChars()); - return e1->apply(fp, param) || - arrayExpressionApply(arguments, fp, param) || - (*fp)(this, param); -} - - -int SliceExp::apply(fp_t fp, void *param) -{ - return e1->apply(fp, param) || - (lwr ? lwr->apply(fp, param) : 0) || - (upr ? upr->apply(fp, param) : 0) || - (*fp)(this, param); -} - - -int ArrayLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(elements, fp, param) || - (*fp)(this, param); -} - - -int AssocArrayLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(keys, fp, param) || - arrayExpressionApply(values, fp, param) || - (*fp)(this, param); -} - - -int StructLiteralExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(elements, fp, param) || - (*fp)(this, param); -} - - -int TupleExp::apply(fp_t fp, void *param) -{ - return arrayExpressionApply(exps, fp, param) || - (*fp)(this, param); -} - - -int CondExp::apply(fp_t fp, void *param) -{ - return econd->apply(fp, param) || - e1->apply(fp, param) || - e2->apply(fp, param) || - (*fp)(this, param); -} - - - diff --git a/dmd2/argtypes.c b/dmd2/argtypes.c deleted file mode 100644 index 3f1d3620..00000000 --- a/dmd2/argtypes.c +++ /dev/null @@ -1,193 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2010-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/argtypes.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" -#include "hdrgen.h" - -/**************************************************** - * This breaks a type down into 'simpler' types that can be passed to a function - * in registers, and returned in registers. - * It's highly platform dependent. - * Returning a tuple of zero length means the type cannot be passed/returned in registers. - */ - - -TypeTuple *Type::toArgTypes() -{ - return NULL; // not valid for a parameter -} - - -TypeTuple *TypeBasic::toArgTypes() -{ Type *t1 = NULL; - Type *t2 = NULL; - switch (ty) - { - case Tvoid: - return NULL; - - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tint32: - case Tuns32: - case Tfloat32: - case Tint64: - case Tuns64: - case Tfloat64: - case Tfloat80: - t1 = this; - break; - - case Timaginary32: - t1 = Type::tfloat32; - break; - - case Timaginary64: - t1 = Type::tfloat64; - break; - - case Timaginary80: - t1 = Type::tfloat80; - break; - - case Tcomplex32: - if (global.params.is64bit) - t1 = Type::tfloat64; // weird, eh? - else - { - t1 = Type::tfloat64; - t2 = Type::tfloat64; - } - break; - - case Tcomplex64: - t1 = Type::tfloat64; - t2 = Type::tfloat64; - break; - - case Tcomplex80: - t1 = Type::tfloat80; - t2 = Type::tfloat80; - break; - - case Tascii: - t1 = Type::tuns8; - break; - - case Twchar: - t1 = Type::tuns16; - break; - - case Tdchar: - t1 = Type::tuns32; - break; - - default: assert(0); - } - - TypeTuple *t; - if (t1) - { - if (t2) - t = new TypeTuple(t1, t2); - else - t = new TypeTuple(t1); - } - else - t = new TypeTuple(); - return t; -} - -TypeTuple *TypeVector::toArgTypes() -{ - return new TypeTuple(Type::tfloat64); -} - -TypeTuple *TypeSArray::toArgTypes() -{ -#if DMDV2 - return new TypeTuple(); // pass on the stack for efficiency -#else - return new TypeTuple(Type::tvoidptr); -#endif -} - -TypeTuple *TypeDArray::toArgTypes() -{ - return new TypeTuple(); // pass on the stack for efficiency -} - -TypeTuple *TypeAArray::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - -TypeTuple *TypePointer::toArgTypes() -{ - return new TypeTuple(this); -} - -TypeTuple *TypeDelegate::toArgTypes() -{ - return new TypeTuple(); // pass on the stack for efficiency -} - -TypeTuple *TypeStruct::toArgTypes() -{ - d_uns64 sz = size(0); - assert(sz < 0xFFFFFFFF); - switch ((unsigned)sz) - { - case 1: - return new TypeTuple(Type::tint8); - case 2: - return new TypeTuple(Type::tint16); - case 4: - return new TypeTuple(Type::tint32); - case 8: - return new TypeTuple(Type::tint64); - } - return new TypeTuple(); // pass on the stack -} - -TypeTuple *TypeEnum::toArgTypes() -{ - return toBasetype()->toArgTypes(); -} - -TypeTuple *TypeTypedef::toArgTypes() -{ - return sym->basetype->toArgTypes(); -} - -TypeTuple *TypeClass::toArgTypes() -{ - return new TypeTuple(Type::tvoidptr); -} - diff --git a/dmd2/arrayop.c b/dmd2/arrayop.c deleted file mode 100644 index ed685c18..00000000 --- a/dmd2/arrayop.c +++ /dev/null @@ -1,682 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "aav.h" - -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "declaration.h" -#include "scope.h" -#include "id.h" -#include "module.h" -#include "init.h" - -#if IN_DMD -extern int binary(const char *p , const char **tab, int high); - -/************************************** - * Hash table of array op functions already generated or known about. - */ - -AA *arrayfuncs; -#else -int binary(const char *p , const char **tab, int high) -{ - int i = 0, j = high, k, l; - do - { - k = (i + j) / 2; - l = strcmp(p, tab[k]); - if (!l) - return k; - else if (l < 0) - j = k; - else - i = k + 1; - } - while (i != j); - return -1; -} -#endif - -/********************************************** - * Check that there are no uses of arrays without []. - */ -bool isArrayOpValid(Expression *e) -{ - if (e->op == TOKslice) - return true; - Type *tb = e->type->toBasetype(); - - if ( (tb->ty == Tarray) || (tb->ty == Tsarray) ) - { - switch (e->op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: -#if DMDV2 - case TOKpow: - case TOKpowass: -#endif - return isArrayOpValid(((BinExp *)e)->e1) && isArrayOpValid(((BinExp *)e)->e2); - - case TOKcall: - return false; // TODO: Decide if [] is required after arrayop calls. - - case TOKneg: - case TOKtilde: - return isArrayOpValid(((UnaExp *)e)->e1); - - default: - return false; - } - } - return true; -} - -/*********************************** - * Construct the array operation expression. - */ - -Expression *BinExp::arrayOp(Scope *sc) -{ - - Type *tb = type->toBasetype(); - assert(tb->ty == Tarray || tb->ty == Tsarray); - if (tb->nextOf()->toBasetype()->ty == Tvoid) - { - error("Cannot perform array operations on void[] arrays"); - return new ErrorExp(); - } - - if (!isArrayOpValid(e2)) - { - e2->error("invalid array operation %s (did you forget a [] ?)", toChars()); - return new ErrorExp(); - } - - Expressions *arguments = new Expressions(); - - /* The expression to generate an array operation for is mangled - * into a name to use as the array operation function name. - * Mangle in the operands and operators in RPN order, and type. - */ - OutBuffer buf; - buf.writestring("_array"); - buildArrayIdent(&buf, arguments); - buf.writeByte('_'); - - /* Append deco of array element type - */ -#if DMDV2 - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->mutableOf()->deco); -#else - buf.writestring(type->toBasetype()->nextOf()->toBasetype()->deco); -#endif - - size_t namelen = buf.offset; - buf.writeByte(0); - char *name = buf.toChars(); - Identifier *ident = Lexer::idPool(name); - - /* Look up name in hash table - */ -#if IN_LLVM - FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&sc->module->arrayfuncs, ident); -#else - FuncDeclaration **pfd = (FuncDeclaration **)_aaGet(&arrayfuncs, ident); -#endif - FuncDeclaration *fd = (FuncDeclaration *)*pfd; - if (!fd) - { - /* Some of the array op functions are written as library functions, - * presumably to optimize them with special CPU vector instructions. - * List those library functions here, in alpha order. - */ - static const char *libArrayopFuncs[] = - { - "_arrayExpSliceAddass_a", - "_arrayExpSliceAddass_d", // T[]+=T - "_arrayExpSliceAddass_f", // T[]+=T - "_arrayExpSliceAddass_g", - "_arrayExpSliceAddass_h", - "_arrayExpSliceAddass_i", - "_arrayExpSliceAddass_k", - "_arrayExpSliceAddass_s", - "_arrayExpSliceAddass_t", - "_arrayExpSliceAddass_u", - "_arrayExpSliceAddass_w", - - "_arrayExpSliceDivass_d", // T[]/=T - "_arrayExpSliceDivass_f", // T[]/=T - - "_arrayExpSliceMinSliceAssign_a", - "_arrayExpSliceMinSliceAssign_d", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_f", // T[]=T-T[] - "_arrayExpSliceMinSliceAssign_g", - "_arrayExpSliceMinSliceAssign_h", - "_arrayExpSliceMinSliceAssign_i", - "_arrayExpSliceMinSliceAssign_k", - "_arrayExpSliceMinSliceAssign_s", - "_arrayExpSliceMinSliceAssign_t", - "_arrayExpSliceMinSliceAssign_u", - "_arrayExpSliceMinSliceAssign_w", - - "_arrayExpSliceMinass_a", - "_arrayExpSliceMinass_d", // T[]-=T - "_arrayExpSliceMinass_f", // T[]-=T - "_arrayExpSliceMinass_g", - "_arrayExpSliceMinass_h", - "_arrayExpSliceMinass_i", - "_arrayExpSliceMinass_k", - "_arrayExpSliceMinass_s", - "_arrayExpSliceMinass_t", - "_arrayExpSliceMinass_u", - "_arrayExpSliceMinass_w", - - "_arrayExpSliceMulass_d", // T[]*=T - "_arrayExpSliceMulass_f", // T[]*=T - "_arrayExpSliceMulass_i", - "_arrayExpSliceMulass_k", - "_arrayExpSliceMulass_s", - "_arrayExpSliceMulass_t", - "_arrayExpSliceMulass_u", - "_arrayExpSliceMulass_w", - - "_arraySliceExpAddSliceAssign_a", - "_arraySliceExpAddSliceAssign_d", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_f", // T[]=T[]+T - "_arraySliceExpAddSliceAssign_g", - "_arraySliceExpAddSliceAssign_h", - "_arraySliceExpAddSliceAssign_i", - "_arraySliceExpAddSliceAssign_k", - "_arraySliceExpAddSliceAssign_s", - "_arraySliceExpAddSliceAssign_t", - "_arraySliceExpAddSliceAssign_u", - "_arraySliceExpAddSliceAssign_w", - - "_arraySliceExpDivSliceAssign_d", // T[]=T[]/T - "_arraySliceExpDivSliceAssign_f", // T[]=T[]/T - - "_arraySliceExpMinSliceAssign_a", - "_arraySliceExpMinSliceAssign_d", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_f", // T[]=T[]-T - "_arraySliceExpMinSliceAssign_g", - "_arraySliceExpMinSliceAssign_h", - "_arraySliceExpMinSliceAssign_i", - "_arraySliceExpMinSliceAssign_k", - "_arraySliceExpMinSliceAssign_s", - "_arraySliceExpMinSliceAssign_t", - "_arraySliceExpMinSliceAssign_u", - "_arraySliceExpMinSliceAssign_w", - - "_arraySliceExpMulSliceAddass_d", // T[] += T[]*T - "_arraySliceExpMulSliceAddass_f", - "_arraySliceExpMulSliceAddass_r", - - "_arraySliceExpMulSliceAssign_d", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_f", // T[]=T[]*T - "_arraySliceExpMulSliceAssign_i", - "_arraySliceExpMulSliceAssign_k", - "_arraySliceExpMulSliceAssign_s", - "_arraySliceExpMulSliceAssign_t", - "_arraySliceExpMulSliceAssign_u", - "_arraySliceExpMulSliceAssign_w", - - "_arraySliceExpMulSliceMinass_d", // T[] -= T[]*T - "_arraySliceExpMulSliceMinass_f", - "_arraySliceExpMulSliceMinass_r", - - "_arraySliceSliceAddSliceAssign_a", - "_arraySliceSliceAddSliceAssign_d", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_f", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_g", - "_arraySliceSliceAddSliceAssign_h", - "_arraySliceSliceAddSliceAssign_i", - "_arraySliceSliceAddSliceAssign_k", - "_arraySliceSliceAddSliceAssign_r", // T[]=T[]+T[] - "_arraySliceSliceAddSliceAssign_s", - "_arraySliceSliceAddSliceAssign_t", - "_arraySliceSliceAddSliceAssign_u", - "_arraySliceSliceAddSliceAssign_w", - - "_arraySliceSliceAddass_a", - "_arraySliceSliceAddass_d", // T[]+=T[] - "_arraySliceSliceAddass_f", // T[]+=T[] - "_arraySliceSliceAddass_g", - "_arraySliceSliceAddass_h", - "_arraySliceSliceAddass_i", - "_arraySliceSliceAddass_k", - "_arraySliceSliceAddass_s", - "_arraySliceSliceAddass_t", - "_arraySliceSliceAddass_u", - "_arraySliceSliceAddass_w", - - "_arraySliceSliceMinSliceAssign_a", - "_arraySliceSliceMinSliceAssign_d", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_f", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_g", - "_arraySliceSliceMinSliceAssign_h", - "_arraySliceSliceMinSliceAssign_i", - "_arraySliceSliceMinSliceAssign_k", - "_arraySliceSliceMinSliceAssign_r", // T[]=T[]-T[] - "_arraySliceSliceMinSliceAssign_s", - "_arraySliceSliceMinSliceAssign_t", - "_arraySliceSliceMinSliceAssign_u", - "_arraySliceSliceMinSliceAssign_w", - - "_arraySliceSliceMinass_a", - "_arraySliceSliceMinass_d", // T[]-=T[] - "_arraySliceSliceMinass_f", // T[]-=T[] - "_arraySliceSliceMinass_g", - "_arraySliceSliceMinass_h", - "_arraySliceSliceMinass_i", - "_arraySliceSliceMinass_k", - "_arraySliceSliceMinass_s", - "_arraySliceSliceMinass_t", - "_arraySliceSliceMinass_u", - "_arraySliceSliceMinass_w", - - "_arraySliceSliceMulSliceAssign_d", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_f", // T[]=T[]*T[] - "_arraySliceSliceMulSliceAssign_i", - "_arraySliceSliceMulSliceAssign_k", - "_arraySliceSliceMulSliceAssign_s", - "_arraySliceSliceMulSliceAssign_t", - "_arraySliceSliceMulSliceAssign_u", - "_arraySliceSliceMulSliceAssign_w", - - "_arraySliceSliceMulass_d", // T[]*=T[] - "_arraySliceSliceMulass_f", // T[]*=T[] - "_arraySliceSliceMulass_i", - "_arraySliceSliceMulass_k", - "_arraySliceSliceMulass_s", - "_arraySliceSliceMulass_t", - "_arraySliceSliceMulass_u", - "_arraySliceSliceMulass_w", - }; - - int i = binary(name, libArrayopFuncs, sizeof(libArrayopFuncs) / sizeof(char *)); - if (i == -1) - { -#ifdef DEBUG // Make sure our array is alphabetized - for (i = 0; i < sizeof(libArrayopFuncs) / sizeof(char *); i++) - { - if (strcmp(name, libArrayopFuncs[i]) == 0) - assert(0); - } -#endif - /* Not in library, so generate it. - * Construct the function body: - * foreach (i; 0 .. p.length) for (size_t i = 0; i < p.length; i++) - * loopbody; - * return p; - */ - - Parameters *fparams = new Parameters(); - Expression *loopbody = buildArrayLoop(fparams); - Parameter *p = (*fparams)[0 /*fparams->dim - 1*/]; -#if DMDV1 - // for (size_t i = 0; i < p.length; i++) - Initializer *init = new ExpInitializer(0, new IntegerExp(0, 0, Type::tsize_t)); - Dsymbol *d = new VarDeclaration(0, Type::tsize_t, Id::p, init); - Statement *s1 = new ForStatement(0, - new DeclarationStatement(0, d), - new CmpExp(TOKlt, 0, new IdentifierExp(0, Id::p), new ArrayLengthExp(0, new IdentifierExp(0, p->ident))), - new PostExp(TOKplusplus, 0, new IdentifierExp(0, Id::p)), - new ExpStatement(0, loopbody)); -#else - // foreach (i; 0 .. p.length) - Statement *s1 = new ForeachRangeStatement(0, TOKforeach, - new Parameter(0, NULL, Id::p, NULL), - new IntegerExp(0, 0, Type::tint32), - new ArrayLengthExp(0, new IdentifierExp(0, p->ident)), - new ExpStatement(0, loopbody)); -#endif - Statement *s2 = new ReturnStatement(0, new IdentifierExp(0, p->ident)); - //printf("s2: %s\n", s2->toChars()); - Statement *fbody = new CompoundStatement(0, s1, s2); - - /* Construct the function - */ - TypeFunction *ftype = new TypeFunction(fparams, type, 0, LINKc); - //printf("ftype: %s\n", ftype->toChars()); - fd = new FuncDeclaration(loc, 0, ident, STCundefined, ftype); - fd->fbody = fbody; - fd->protection = PROTpublic; - fd->linkage = LINKd; - fd->isArrayOp = 1; - - sc->module->importedFrom->members->push(fd); - - sc = sc->push(); - sc->parent = sc->module->importedFrom; - sc->stc = 0; - sc->linkage = LINKc; - fd->semantic(sc); - fd->semantic2(sc); - fd->semantic3(sc); - sc->pop(); - } -#if IN_LLVM - else - { /* In library, refer to it. - */ - Parameters *fparams = new Parameters(); - buildArrayLoop(fparams); - fd = FuncDeclaration::genCfunc(fparams, type, ident); - fd->isArrayOp = 2; - } -#else - else - { /* In library, refer to it. - */ - fd = FuncDeclaration::genCfunc(type, ident); - } -#endif - *pfd = fd; // cache symbol in hash table - } - - /* Call the function fd(arguments) - */ - Expression *ec = new VarExp(0, fd); - Expression *e = new CallExp(loc, ec, arguments); - e->type = type; - return e; -} - -/****************************************** - * Construct the identifier for the array operation function, - * and build the argument list to pass to it. - */ - -void Expression::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Exp"); - arguments->shift(this); -} - -void CastExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - e1->buildArrayIdent(buf, arguments); - } - else - Expression::buildArrayIdent(buf, arguments); -} - -void SliceExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - buf->writestring("Slice"); - arguments->shift(this); -} - -void AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - /* Evaluate assign expressions right to left - */ - e2->buildArrayIdent(buf, arguments); - e1->buildArrayIdent(buf, arguments); - buf->writestring("Assign"); -} - -#define X(Str) \ -void Str##AssignExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - e2->buildArrayIdent(buf, arguments); \ - e1->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ - buf->writestring("ass"); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -void NegExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Neg"); -} - -void ComExp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) -{ - e1->buildArrayIdent(buf, arguments); - buf->writestring("Com"); -} - -#define X(Str) \ -void Str##Exp::buildArrayIdent(OutBuffer *buf, Expressions *arguments) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - e1->buildArrayIdent(buf, arguments); \ - e2->buildArrayIdent(buf, arguments); \ - buf->writestring(#Str); \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -/****************************************** - * Construct the inner loop for the array operation function, - * and build the parameter list. - */ - -Expression *Expression::buildArrayLoop(Parameters *fparams) -{ - Identifier *id = Identifier::generateId("c", fparams->dim); - Parameter *param = new Parameter(0, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - return e; -} - -Expression *CastExp::buildArrayLoop(Parameters *fparams) -{ - Type *tb = type->toBasetype(); - if (tb->ty == Tarray || tb->ty == Tsarray) - { - return e1->buildArrayLoop(fparams); - } - else - return Expression::buildArrayLoop(fparams); -} - -Expression *SliceExp::buildArrayLoop(Parameters *fparams) -{ - Identifier *id = Identifier::generateId("p", fparams->dim); - Parameter *param = new Parameter(STCconst, type, id, NULL); - fparams->shift(param); - Expression *e = new IdentifierExp(0, id); - Expressions *arguments = new Expressions(); - Expression *index = new IdentifierExp(0, Id::p); - arguments->push(index); - e = new ArrayExp(0, e, arguments); - return e; -} - -Expression *AssignExp::buildArrayLoop(Parameters *fparams) -{ - /* Evaluate assign expressions right to left - */ - Expression *ex2 = e2->buildArrayLoop(fparams); -#if DMDV2 - /* Need the cast because: - * b = c + p[i]; - * where b is a byte fails because (c + p[i]) is an int - * which cannot be implicitly cast to byte. - */ - ex2 = new CastExp(0, ex2, e1->type->nextOf()); -#endif - Expression *ex1 = e1->buildArrayLoop(fparams); - Parameter *param = (*fparams)[0]; - param->storageClass = 0; - Expression *e = new AssignExp(0, ex1, ex2); - return e; -} - -#define X(Str) \ -Expression *Str##AssignExp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions right to left \ - */ \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Parameter *param = (*fparams)[0]; \ - param->storageClass = 0; \ - Expression *e = new Str##AssignExp(loc, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - -Expression *NegExp::buildArrayLoop(Parameters *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new NegExp(0, ex1); - return e; -} - -Expression *ComExp::buildArrayLoop(Parameters *fparams) -{ - Expression *ex1 = e1->buildArrayLoop(fparams); - Expression *e = new ComExp(0, ex1); - return e; -} - -#define X(Str) \ -Expression *Str##Exp::buildArrayLoop(Parameters *fparams) \ -{ \ - /* Evaluate assign expressions left to right \ - */ \ - Expression *ex1 = e1->buildArrayLoop(fparams); \ - Expression *ex2 = e2->buildArrayLoop(fparams); \ - Expression *e = new Str##Exp(0, ex1, ex2); \ - return e; \ -} - -X(Add) -X(Min) -X(Mul) -X(Div) -X(Mod) -X(Xor) -X(And) -X(Or) -#if DMDV2 -X(Pow) -#endif - -#undef X - - -/*********************************************** - * Test if operand is a valid array op operand. - */ - -int Expression::isArrayOperand() -{ - //printf("Expression::isArrayOperand() %s\n", toChars()); - if (op == TOKslice) - return 1; - if (type->toBasetype()->ty == Tarray) - { - switch (op) - { - case TOKadd: - case TOKmin: - case TOKmul: - case TOKdiv: - case TOKmod: - case TOKxor: - case TOKand: - case TOKor: - case TOKassign: - case TOKaddass: - case TOKminass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKxorass: - case TOKandass: - case TOKorass: -#if DMDV2 - case TOKpow: - case TOKpowass: -#endif - case TOKneg: - case TOKtilde: - return 1; - - default: - break; - } - } - return 0; -} diff --git a/dmd2/arraytypes.h b/dmd2/arraytypes.h deleted file mode 100644 index be854a62..00000000 --- a/dmd2/arraytypes.h +++ /dev/null @@ -1,77 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2006-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ARRAYTYPES_H -#define DMD_ARRAYTYPES_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - - -#include "root.h" - -typedef ArrayBase TemplateParameters; - -typedef ArrayBase Expressions; - -typedef ArrayBase Statements; - -typedef ArrayBase BaseClasses; - -typedef ArrayBase ClassDeclarations; - -typedef ArrayBase Dsymbols; - -typedef ArrayBase Objects; - -typedef ArrayBase FuncDeclarations; - -typedef ArrayBase Parameters; - -typedef ArrayBase Identifiers; - -typedef ArrayBase Initializers; - -typedef ArrayBase VarDeclarations; - -typedef ArrayBase Types; - -typedef ArrayBase ScopeDsymbols; - -typedef ArrayBase Catches; - -typedef ArrayBase StaticDtorDeclarations; - -typedef ArrayBase SharedStaticDtorDeclarations; - -typedef ArrayBase AliasDeclarations; - -typedef ArrayBase Modules; - -typedef ArrayBase Files; - -typedef ArrayBase CaseStatements; - -typedef ArrayBase CompoundStatements; - -typedef ArrayBase GotoCaseStatements; - -typedef ArrayBase TemplateInstances; - -//typedef ArrayBase Strings; - -typedef ArrayBase Voids; - -typedef ArrayBase Blocks; - -typedef ArrayBase Symbols; - -#endif diff --git a/dmd2/artistic.txt b/dmd2/artistic.txt deleted file mode 100644 index cd17757e..00000000 --- a/dmd2/artistic.txt +++ /dev/null @@ -1,117 +0,0 @@ - - - - - The "Artistic License" - - Preamble - -The intent of this document is to state the conditions under which a -Package may be copied, such that the Copyright Holder maintains some -semblance of artistic control over the development of the package, -while giving the users of the package the right to use and distribute -the Package in a more-or-less customary fashion, plus the right to make -reasonable modifications. - -Definitions: - - "Package" refers to the collection of files distributed by the - Copyright Holder, and derivatives of that collection of files - created through textual modification. - - "Standard Version" refers to such a Package if it has not been - modified, or has been modified in accordance with the wishes - of the Copyright Holder as specified below. - - "Copyright Holder" is whoever is named in the copyright or - copyrights for the package. - - "You" is you, if you're thinking about copying or distributing - this Package. - - "Reasonable copying fee" is whatever you can justify on the - basis of media cost, duplication charges, time of people involved, - and so on. (You will not be required to justify it to the - Copyright Holder, but only to the computing community at large - as a market that must bear the fee.) - - "Freely Available" means that no fee is charged for the item - itself, though there may be fees involved in handling the item. - It also means that recipients of the item may redistribute it - under the same conditions they received it. - -1. You may make and give away verbatim copies of the source form of the -Standard Version of this Package without restriction, provided that you -duplicate all of the original copyright notices and associated disclaimers. - -2. You may apply bug fixes, portability fixes and other modifications -derived from the Public Domain or from the Copyright Holder. A Package -modified in such a way shall still be considered the Standard Version. - -3. You may otherwise modify your copy of this Package in any way, provided -that you insert a prominent notice in each changed file stating how and -when you changed that file, and provided that you do at least ONE of the -following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or - an equivalent medium, or placing the modifications on a major archive - site such as uunet.uu.net, or by allowing the Copyright Holder to include - your modifications in the Standard Version of the Package. - - b) use the modified Package only within your corporation or organization. - - c) rename any non-standard executables so the names do not conflict - with standard executables, which must also be provided, and provide - a separate manual page for each non-standard executable that clearly - documents how it differs from the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -4. You may distribute the programs of this Package in object code or -executable form, provided that you do at least ONE of the following: - - a) distribute a Standard Version of the executables and library files, - together with instructions (in the manual page or equivalent) on where - to get the Standard Version. - - b) accompany the distribution with the machine-readable source of - the Package with your modifications. - - c) give non-standard executables non-standard names, and clearly - document the differences in manual pages (or equivalent), together - with instructions on where to get the Standard Version. - - d) make other distribution arrangements with the Copyright Holder. - -5. You may charge a reasonable copying fee for any distribution of this -Package. You may charge any fee you choose for support of this -Package. You may not charge a fee for this Package itself. However, -you may distribute this Package in aggregate with other (possibly -commercial) programs as part of a larger (possibly commercial) software -distribution provided that you do not advertise this Package as a -product of your own. You may embed this Package's interpreter within -an executable of yours (by linking); this shall be construed as a mere -form of aggregation, provided that the complete Standard Version of the -interpreter is so embedded. - -6. The source code and object code supplied as input to or produced as -output from the programs of this Package do not automatically fall -under the copyright of this Package, but belong to whoever generated -them, and may be sold commercially, and may be aggregated with this -Package. - -7. Aggregation of this Package with a commercial distribution is always -permitted provided that the use of this Package is embedded; that is, -when no overt attempt is made to make this Package's interfaces visible -to the end user of the commercial distribution. Such use shall not be -construed as a distribution of this Package. - -8. The name of the Copyright Holder may not be used to endorse or promote -products derived from this software without specific prior written permission. - -9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. - - The End diff --git a/dmd2/attrib.c b/dmd2/attrib.c deleted file mode 100644 index 5d55cd20..00000000 --- a/dmd2/attrib.c +++ /dev/null @@ -1,1565 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "cond.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "module.h" -#include "parse.h" -#include "template.h" -#if TARGET_NET - #include "frontend.net/pragma.h" -#endif -#if IN_LLVM -#include "../gen/pragma.h" -#endif - - -extern void obj_includelib(const char *name); - -#if IN_DMD -void obj_startaddress(Symbol *s); -#endif - - -/********************************* AttribDeclaration ****************************/ - -AttribDeclaration::AttribDeclaration(Dsymbols *decl) - : Dsymbol() -{ - this->decl = decl; -} - -Dsymbols *AttribDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - return decl; -} - -int AttribDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int m = 0; - Dsymbols *d = include(sc, sd); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("\taddMember %s to %s\n", s->toChars(), sd->toChars()); - m |= s->addMember(sc, sd, m | memnum); - } - } - return m; -} - -void AttribDeclaration::setScopeNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = decl->tdata()[i]; - - s->setScope(newsc); // yes, the only difference from semanticNewSc() - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semanticNewSc(Scope *sc, - StorageClass stc, enum LINK linkage, enum PROT protection, int explicitProtection, - unsigned structalign) -{ - if (decl) - { - Scope *newsc = sc; - if (stc != sc->stc || - linkage != sc->linkage || - protection != sc->protection || - explicitProtection != sc->explicitProtection || - structalign != sc->structalign) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->stc = stc; - newsc->linkage = linkage; - newsc->protection = protection; - newsc->explicitProtection = explicitProtection; - newsc->structalign = structalign; - } - for (unsigned i = 0; i < decl->dim; i++) - { Dsymbol *s = decl->tdata()[i]; - - s->semantic(newsc); - } - if (newsc != sc) - { - sc->offset = newsc->offset; - newsc->pop(); - } - } -} - -void AttribDeclaration::semantic(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tAttribDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = d->tdata()[i]; - - s->semantic(sc); - } - } -} - -void AttribDeclaration::semantic2(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->semantic2(sc); - } - } -} - -void AttribDeclaration::semantic3(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->semantic3(sc); - } - } -} - -void AttribDeclaration::inlineScan() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("AttribDeclaration::inlineScan %s\n", s->toChars()); - s->inlineScan(); - } - } -} - -void AttribDeclaration::addComment(unsigned char *comment) -{ - //printf("AttribDeclaration::addComment %s\n", comment); - if (comment) - { - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("AttribDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - } -} - -void AttribDeclaration::emitComment(Scope *sc) -{ - //printf("AttribDeclaration::emitComment(sc = %p)\n", sc); - - /* A general problem with this, illustrated by BUGZILLA 2516, - * is that attributes are not transmitted through to the underlying - * member declarations for template bodies, because semantic analysis - * is not done for template declaration bodies - * (only template instantiations). - * Hence, Ddoc omits attributes from template members. - */ - - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("AttribDeclaration::emitComment %s\n", s->toChars()); - s->emitComment(sc); - } - } -} - -#if IN_DMD - -void AttribDeclaration::toObjFile(int multiobj) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->toObjFile(multiobj); - } - } -} - -int AttribDeclaration::cvMember(unsigned char *p) -{ - int nwritten = 0; - int n; - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - n = s->cvMember(p); - if (p) - p += n; - nwritten += n; - } - } - return nwritten; -} -#endif - -int AttribDeclaration::hasPointers() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = d->tdata()[i]; - if (s->hasPointers()) - return 1; - } - } - return 0; -} - -bool AttribDeclaration::hasStaticCtorOrDtor() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (size_t i = 0; i < d->dim; i++) - { - Dsymbol *s = (*d)[i]; - if (s->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -const char *AttribDeclaration::kind() -{ - return "attribute"; -} - -int AttribDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - Dsymbols *d = include(NULL, NULL); - - return Dsymbol::oneMembers(d, ps, ident); -} - -void AttribDeclaration::checkCtorConstInit() -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->checkCtorConstInit(); - } - } -} - -/**************************************** - */ - -void AttribDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - Dsymbols *d = include(NULL, NULL); - - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->addLocalClass(aclasses); - } - } -} - - -void AttribDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (decl) - { - if (decl->dim == 0) - buf->writestring("{}"); - else if (decl->dim == 1) - (decl->tdata()[0])->toCBuffer(buf, hgs); - else - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(';'); - buf->writenl(); -} - -/************************* StorageClassDeclaration ****************************/ - -StorageClassDeclaration::StorageClassDeclaration(StorageClass stc, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->stc = stc; -} - -Dsymbol *StorageClassDeclaration::syntaxCopy(Dsymbol *s) -{ - StorageClassDeclaration *scd; - - assert(!s); - scd = new StorageClassDeclaration(stc, Dsymbol::arraySyntaxCopy(decl)); - return scd; -} - -int StorageClassDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - - int t = Dsymbol::oneMembers(decl, ps, ident); - if (t && *ps) - { - /* This is to deal with the following case: - * struct Tick { - * template to(T) { const T to() { ... } } - * } - * For eponymous function templates, the 'const' needs to get attached to 'to' - * before the semantic analysis of 'to', so that template overloading based on the - * 'this' pointer can be successful. - */ - - FuncDeclaration *fd = (*ps)->isFuncDeclaration(); - if (fd) - { - /* Use storage_class2 instead of storage_class otherwise when we do .di generation - * we'll wind up with 'const const' rather than 'const'. - */ - /* Don't think we need to worry about mutually exclusive storage classes here - */ - fd->storage_class2 |= stc; - } - } - return t; -} - -void StorageClassDeclaration::setScope(Scope *sc) -{ - if (decl) - { - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - - setScopeNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::semantic(Scope *sc) -{ - if (decl) - { - StorageClass scstc = sc->stc; - - /* These sets of storage classes are mutually exclusive, - * so choose the innermost or most recent one. - */ - if (stc & (STCauto | STCscope | STCstatic | STCextern | STCmanifest)) - scstc &= ~(STCauto | STCscope | STCstatic | STCextern | STCmanifest); - if (stc & (STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared)) - scstc &= ~(STCauto | STCscope | STCstatic | STCtls | STCmanifest | STCgshared); - if (stc & (STCconst | STCimmutable | STCmanifest)) - scstc &= ~(STCconst | STCimmutable | STCmanifest); - if (stc & (STCgshared | STCshared | STCtls)) - scstc &= ~(STCgshared | STCshared | STCtls); - if (stc & (STCsafe | STCtrusted | STCsystem)) - scstc &= ~(STCsafe | STCtrusted | STCsystem); - scstc |= stc; - - semanticNewSc(sc, scstc, sc->linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void StorageClassDeclaration::stcToCBuffer(OutBuffer *buf, StorageClass stc) -{ - struct SCstring - { - StorageClass stc; - enum TOK tok; - Identifier *id; - }; - - static SCstring table[] = - { - { STCauto, TOKauto }, - { STCscope, TOKscope }, - { STCstatic, TOKstatic }, - { STCextern, TOKextern }, - { STCconst, TOKconst }, - { STCfinal, TOKfinal }, - { STCabstract, TOKabstract }, - { STCsynchronized, TOKsynchronized }, - { STCdeprecated, TOKdeprecated }, - { STCoverride, TOKoverride }, - { STClazy, TOKlazy }, - { STCalias, TOKalias }, - { STCout, TOKout }, - { STCin, TOKin }, -#if DMDV2 - { STCmanifest, TOKenum }, - { STCimmutable, TOKimmutable }, - { STCshared, TOKshared }, - { STCnothrow, TOKnothrow }, - { STCpure, TOKpure }, - { STCref, TOKref }, - { STCtls, TOKtls }, - { STCgshared, TOKgshared }, - { STCproperty, TOKat, Id::property }, - { STCsafe, TOKat, Id::safe }, - { STCtrusted, TOKat, Id::trusted }, - { STCsystem, TOKat, Id::system }, - { STCdisable, TOKat, Id::disable }, -#endif - }; - - for (int i = 0; i < sizeof(table)/sizeof(table[0]); i++) - { - if (stc & table[i].stc) - { - enum TOK tok = table[i].tok; -#if DMDV2 - if (tok == TOKat) - { - buf->writeByte('@'); - buf->writestring(table[i].id->toChars()); - } - else -#endif - buf->writestring(Token::toChars(tok)); - buf->writeByte(' '); - } - } -} - -void StorageClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - stcToCBuffer(buf, stc); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* LinkDeclaration ****************************/ - -LinkDeclaration::LinkDeclaration(enum LINK p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - //printf("LinkDeclaration(linkage = %d, decl = %p)\n", p, decl); - linkage = p; -} - -Dsymbol *LinkDeclaration::syntaxCopy(Dsymbol *s) -{ - LinkDeclaration *ld; - - assert(!s); - ld = new LinkDeclaration(linkage, Dsymbol::arraySyntaxCopy(decl)); - return ld; -} - -void LinkDeclaration::setScope(Scope *sc) -{ - //printf("LinkDeclaration::setScope(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - setScopeNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic(Scope *sc) -{ - //printf("LinkDeclaration::semantic(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { - semanticNewSc(sc, sc->stc, linkage, sc->protection, sc->explicitProtection, sc->structalign); - } -} - -void LinkDeclaration::semantic3(Scope *sc) -{ - //printf("LinkDeclaration::semantic3(linkage = %d, decl = %p)\n", linkage, decl); - if (decl) - { enum LINK linkage_save = sc->linkage; - - sc->linkage = linkage; - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - s->semantic3(sc); - } - sc->linkage = linkage_save; - } - else - { - sc->linkage = linkage; - } -} - -void LinkDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ const char *p; - - switch (linkage) - { - case LINKd: p = "D"; break; - case LINKc: p = "C"; break; - case LINKcpp: p = "C++"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - -#if IN_LLVM - case LINKintrinsic: p = "Intrinsic"; break; -#endif - default: - assert(0); - break; - } - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - AttribDeclaration::toCBuffer(buf, hgs); -} - -char *LinkDeclaration::toChars() -{ - return (char *)"extern ()"; -} - -/********************************* ProtDeclaration ****************************/ - -ProtDeclaration::ProtDeclaration(enum PROT p, Dsymbols *decl) - : AttribDeclaration(decl) -{ - protection = p; - //printf("decl = %p\n", decl); -} - -Dsymbol *ProtDeclaration::syntaxCopy(Dsymbol *s) -{ - ProtDeclaration *pd; - - assert(!s); - pd = new ProtDeclaration(protection, Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void ProtDeclaration::setScope(Scope *sc) -{ - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::importAll(Scope *sc) -{ - Scope *newsc = sc; - if (sc->protection != protection || - sc->explicitProtection != 1) - { - // create new one for changes - newsc = new Scope(*sc); - newsc->flags &= ~SCOPEfree; - newsc->protection = protection; - newsc->explicitProtection = 1; - } - - for (size_t i = 0; i < decl->dim; i++) - { - Dsymbol *s = (*decl)[i]; - s->importAll(newsc); - } - - if (newsc != sc) - newsc->pop(); -} - -void ProtDeclaration::semantic(Scope *sc) -{ - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, protection, 1, sc->structalign); - } -} - -void ProtDeclaration::protectionToCBuffer(OutBuffer *buf, enum PROT protection) -{ - const char *p; - - switch (protection) - { - case PROTprivate: p = "private"; break; - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTpublic: p = "public"; break; - case PROTexport: p = "export"; break; - default: - assert(0); - break; - } - buf->writestring(p); - buf->writeByte(' '); -} - -void ProtDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - protectionToCBuffer(buf, protection); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AlignDeclaration ****************************/ - -AlignDeclaration::AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - salign = sa; -} - -Dsymbol *AlignDeclaration::syntaxCopy(Dsymbol *s) -{ - AlignDeclaration *ad; - - assert(!s); - ad = new AlignDeclaration(loc, salign, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AlignDeclaration::setScope(Scope *sc) -{ - //printf("\tAlignDeclaration::setScope '%s'\n",toChars()); - if (decl) - { - setScopeNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } -} - -void AlignDeclaration::semantic(Scope *sc) -{ - //printf("\tAlignDeclaration::semantic '%s'\n",toChars()); - if (decl) - { - semanticNewSc(sc, sc->stc, sc->linkage, sc->protection, sc->explicitProtection, salign); - } - else - assert(0 && "what kind of align use triggers this?"); -} - - -void AlignDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("align (%d)", salign); - AttribDeclaration::toCBuffer(buf, hgs); -} - -/********************************* AnonDeclaration ****************************/ - -AnonDeclaration::AnonDeclaration(Loc loc, int isunion, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->isunion = isunion; - this->sem = 0; -} - -Dsymbol *AnonDeclaration::syntaxCopy(Dsymbol *s) -{ - AnonDeclaration *ad; - - assert(!s); - ad = new AnonDeclaration(loc, isunion, Dsymbol::arraySyntaxCopy(decl)); - return ad; -} - -void AnonDeclaration::semantic(Scope *sc) -{ - //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this); - - if (sem == 1) - { //printf("already completed\n"); - scope = NULL; - return; // semantic() already completed - } - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - - assert(sc->parent); - - Dsymbol *parent = sc->parent->pastMixin(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - - if (!ad || (!ad->isStructDeclaration() && !ad->isClassDeclaration())) - { - error("can only be a part of an aggregate"); - return; - } - - if (decl) - { - AnonymousAggregateDeclaration aad; - int adisunion; - - if (sc->anonAgg) - { ad = sc->anonAgg; - adisunion = sc->inunion; - } - else - adisunion = ad->isUnionDeclaration() != NULL; - -// printf("\tsc->anonAgg = %p\n", sc->anonAgg); -// printf("\tad = %p\n", ad); -// printf("\taad = %p\n", &aad); - - sc = sc->push(); - sc->anonAgg = &aad; - sc->stc &= ~(STCauto | STCscope | STCstatic | STCtls | STCgshared); - sc->inunion = isunion; - sc->offset = 0; - sc->flags = 0; - aad.structalign = sc->structalign; - aad.parent = ad; - - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - s->semantic(sc); - if (isunion) - sc->offset = 0; - if (aad.sizeok == 2) - { - break; - } - } - sc = sc->pop(); - - // If failed due to forward references, unwind and try again later - if (aad.sizeok == 2) - { - ad->sizeok = 2; - //printf("\tsetting ad->sizeok %p to 2\n", ad); - if (!sc->anonAgg) - { - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - Module::dprogress = dprogress_save; - //printf("\tforward reference %p\n", this); - return; - } - if (sem == 0) - { Module::dprogress++; - sem = 1; - //printf("\tcompleted %p\n", this); - } - else - ;//printf("\talready completed %p\n", this); - - // 0 sized structs are set to 1 byte - if (aad.structsize == 0) - { - aad.structsize = 1; - aad.alignsize = 1; - } - - // Align size of anonymous aggregate -//printf("aad.structalign = %d, aad.alignsize = %d, sc->offset = %d\n", aad.structalign, aad.alignsize, sc->offset); - ad->alignmember(aad.structalign, aad.alignsize, &sc->offset); - //ad->structsize = sc->offset; -//printf("sc->offset = %d\n", sc->offset); - - // Add members of aad to ad - //printf("\tadding members of aad to '%s'\n", ad->toChars()); - for (unsigned i = 0; i < aad.fields.dim; i++) - { - VarDeclaration *v = aad.fields.tdata()[i]; - - v->offset += sc->offset; - ad->fields.push(v); - } - - // Add size of aad to ad - if (adisunion) - { - if (aad.structsize > ad->structsize) - ad->structsize = aad.structsize; - sc->offset = 0; - } - else - { - ad->structsize = sc->offset + aad.structsize; - sc->offset = ad->structsize; - } - - if (ad->alignsize < aad.alignsize) - ad->alignsize = aad.alignsize; - } -} - - -void AnonDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf(isunion ? "union" : "struct"); - buf->writestring("\n{\n"); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - //buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writestring("}\n"); -} - -const char *AnonDeclaration::kind() -{ - return (isunion ? "anonymous union" : "anonymous struct"); -} - -/********************************* PragmaDeclaration ****************************/ - -PragmaDeclaration::PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl) - : AttribDeclaration(decl) -{ - this->loc = loc; - this->ident = ident; - this->args = args; -} - -Dsymbol *PragmaDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("PragmaDeclaration::syntaxCopy(%s)\n", toChars()); - PragmaDeclaration *pd; - - assert(!s); - pd = new PragmaDeclaration(loc, ident, - Expression::arraySyntaxCopy(args), Dsymbol::arraySyntaxCopy(decl)); - return pd; -} - -void PragmaDeclaration::setScope(Scope *sc) -{ -#if TARGET_NET - if (ident == Lexer::idPool("assembly")) - { - if (!args || args->dim != 1) - { - error("pragma has invalid number of arguments"); - } - else - { - Expression *e = args->tdata()[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->tdata()[0] = e; - StringExp* se = e->toString(); - if (!se) - { - error("string expected, not '%s'", e->toChars()); - } - PragmaScope* pragma = new PragmaScope(this, sc->parent, se); - - assert(sc); - pragma->setScope(sc); - - //add to module members - assert(sc->module); - assert(sc->module->members); - sc->module->members->push(pragma); - } - } -#endif // TARGET_NET -} - -void PragmaDeclaration::semantic(Scope *sc) -{ // Should be merged with PragmaStatement - -#if IN_LLVM - Pragma llvm_internal = LLVMnone; - std::string arg1str; -#endif - - //printf("\tPragmaDeclaration::semantic '%s'\n",toChars()); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = args->tdata()[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - StringExp *se = e->toString(); - if (se) - { - fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); - } - else - fprintf(stdmsg, "%s", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - goto Lnodecl; - } - else if (ident == Id::lib) - { - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = args->tdata()[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->tdata()[0] = e; - if (e->op == TOKerror) - goto Lnodecl; - StringExp *se = e->toString(); - if (!se) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } - goto Lnodecl; - } -#if IN_GCC - else if (ident == Id::GNU_asm) - { - if (! args || args->dim != 2) - error("identifier and string expected for asm name"); - else - { - Expression *e; - Declaration *d = NULL; - StringExp *s = NULL; - - e = args->tdata()[0]; - e = e->semantic(sc); - if (e->op == TOKvar) - { - d = ((VarExp *)e)->var; - if (! d->isFuncDeclaration() && ! d->isVarDeclaration()) - d = NULL; - } - if (!d) - error("first argument of GNU_asm must be a function or variable declaration"); - - e = args->tdata()[1]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - e = e->toString(); - if (e && ((StringExp *)e)->sz == 1) - s = ((StringExp *)e); - else - error("second argument of GNU_asm must be a char string"); - - if (d && s) - d->c_ident = Lexer::idPool((char*) s->string); - } - goto Lnodecl; - } -#endif -#if DMDV2 - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = args->tdata()[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - args->tdata()[0] = e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - } - goto Lnodecl; - } -#endif -#if TARGET_NET - else if (ident == Lexer::idPool("assembly")) - { - } -#endif // TARGET_NET -#if IN_LLVM - else if ((llvm_internal = DtoGetPragma(sc, this, arg1str)) != LLVMnone) - { - // nothing to do anymore - } -#endif - else if (global.params.ignoreUnsupportedPragmas) - { - if (global.params.verbose) - { - /* Print unrecognized pragmas - */ - printf("pragma %s", ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = args->tdata()[i]; - // ignore errors in ignored pragmas. - global.gag++; - unsigned errors_save = global.errors; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - if (i == 0) - printf(" ("); - else - printf(","); - printf("%s", e->toChars()); - - // restore error state. - global.gag--; - global.errors = errors_save; - } - if (args->dim) - printf(")"); - } - printf("\n"); - } - } - else - error("unrecognized pragma(%s)", ident->toChars()); - -Ldecl: - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - s->semantic(sc); - -#if IN_LLVM - DtoCheckPragma(this, s, llvm_internal, arg1str); -#endif - } - } - return; - -Lnodecl: - if (decl) - { - error("pragma is missing closing ';'"); - goto Ldecl; // do them anyway, to avoid segfaults. - } -} - -int PragmaDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - *ps = NULL; - return TRUE; -} - -const char *PragmaDeclaration::kind() -{ - return "pragma"; -} - -#if IN_DMD -void PragmaDeclaration::toObjFile(int multiobj) -{ - if (ident == Id::lib) - { - assert(args && args->dim == 1); - - Expression *e = args->tdata()[0]; - - assert(e->op == TOKstring); - - StringExp *se = (StringExp *)e; - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; -#if OMFOBJ - /* The OMF format allows library names to be inserted - * into the object file. The linker will then automatically - * search that library, too. - */ - obj_includelib(name); -#elif ELFOBJ || MACHOBJ - /* The format does not allow embedded library names, - * so instead append the library name to the list to be passed - * to the linker. - */ - global.params.libfiles->push(name); -#else - error("pragma lib not supported"); -#endif - } -#if DMDV2 - else if (ident == Id::startaddress) - { - assert(args && args->dim == 1); - Expression *e = args->tdata()[0]; - Dsymbol *sa = getDsymbol(e); - FuncDeclaration *f = sa->isFuncDeclaration(); - assert(f); - Symbol *s = f->toSymbol(); - obj_startaddress(s); - } -#endif - AttribDeclaration::toObjFile(multiobj); -} -#endif - -void PragmaDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("pragma (%s", ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - AttribDeclaration::toCBuffer(buf, hgs); -} - - -/********************************* ConditionalDeclaration ****************************/ - -ConditionalDeclaration::ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl) - : AttribDeclaration(decl) -{ - //printf("ConditionalDeclaration::ConditionalDeclaration()\n"); - this->condition = condition; - this->elsedecl = elsedecl; -} - -Dsymbol *ConditionalDeclaration::syntaxCopy(Dsymbol *s) -{ - ConditionalDeclaration *dd; - - assert(!s); - dd = new ConditionalDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int ConditionalDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("ConditionalDeclaration::oneMember(), inc = %d\n", condition->inc); - if (condition->inc) - { - Dsymbols *d = condition->include(NULL, NULL) ? decl : elsedecl; - return Dsymbol::oneMembers(d, ps, ident); - } - *ps = NULL; - return TRUE; -} - -void ConditionalDeclaration::emitComment(Scope *sc) -{ - //printf("ConditionalDeclaration::emitComment(sc = %p)\n", sc); - if (condition->inc) - { - AttribDeclaration::emitComment(sc); - } - else if (sc->docbuf) - { - /* If generating doc comment, be careful because if we're inside - * a template, then include(NULL, NULL) will fail. - */ - Dsymbols *d = decl ? decl : elsedecl; - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - s->emitComment(sc); - } - } -} - -// Decide if 'then' or 'else' code should be included - -Dsymbols *ConditionalDeclaration::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("ConditionalDeclaration::include()\n"); - assert(condition); - return condition->include(sc, sd) ? decl : elsedecl; -} - -void ConditionalDeclaration::setScope(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tConditionalDeclaration::setScope '%s', d = %p\n",toChars(), d); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = d->tdata()[i]; - - s->setScope(sc); - } - } -} - -void ConditionalDeclaration::importAll(Scope *sc) -{ - Dsymbols *d = include(sc, NULL); - - //printf("\tConditionalDeclaration::importAll '%s', d = %p\n",toChars(), d); - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = d->tdata()[i]; - - s->importAll(sc); - } - } -} - -void ConditionalDeclaration::addComment(unsigned char *comment) -{ - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - - if (comment) - { - Dsymbols *d = decl; - - for (int j = 0; j < 2; j++) - { - if (d) - { - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s; - - s = d->tdata()[i]; - //printf("ConditionalDeclaration::addComment %s\n", s->toChars()); - s->addComment(comment); - } - } - d = elsedecl; - } - } -} - -void ConditionalDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - if (decl || elsedecl) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (decl) - { - for (unsigned i = 0; i < decl->dim; i++) - { - Dsymbol *s = decl->tdata()[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - } - buf->writeByte('}'); - if (elsedecl) - { - buf->writenl(); - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (unsigned i = 0; i < elsedecl->dim; i++) - { - Dsymbol *s = elsedecl->tdata()[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - } - } - else - buf->writeByte(':'); - buf->writenl(); -} - -/***************************** StaticIfDeclaration ****************************/ - -StaticIfDeclaration::StaticIfDeclaration(Condition *condition, - Dsymbols *decl, Dsymbols *elsedecl) - : ConditionalDeclaration(condition, decl, elsedecl) -{ - //printf("StaticIfDeclaration::StaticIfDeclaration()\n"); - sd = NULL; - addisdone = 0; -} - - -Dsymbol *StaticIfDeclaration::syntaxCopy(Dsymbol *s) -{ - StaticIfDeclaration *dd; - - assert(!s); - dd = new StaticIfDeclaration(condition->syntaxCopy(), - Dsymbol::arraySyntaxCopy(decl), - Dsymbol::arraySyntaxCopy(elsedecl)); - return dd; -} - - -int StaticIfDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("StaticIfDeclaration::addMember() '%s'\n",toChars()); - /* This is deferred until semantic(), so that - * expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this->sd = sd; - int m = 0; - - if (memnum == 0) - { m = AttribDeclaration::addMember(sc, sd, memnum); - addisdone = 1; - } - return m; -} - - -void StaticIfDeclaration::importAll(Scope *sc) -{ - // do not evaluate condition before semantic pass -} - -void StaticIfDeclaration::setScope(Scope *sc) -{ - // do not evaluate condition before semantic pass -} - -void StaticIfDeclaration::semantic(Scope *sc) -{ - Dsymbols *d = include(sc, sd); - - //printf("\tStaticIfDeclaration::semantic '%s', d = %p\n",toChars(), d); - if (d) - { - if (!addisdone) - { AttribDeclaration::addMember(sc, sd, 1); - addisdone = 1; - } - - for (unsigned i = 0; i < d->dim; i++) - { - Dsymbol *s = d->tdata()[i]; - - s->semantic(sc); - } - } -} - -const char *StaticIfDeclaration::kind() -{ - return "static if"; -} - - -/***************************** CompileDeclaration *****************************/ - -CompileDeclaration::CompileDeclaration(Loc loc, Expression *exp) - : AttribDeclaration(NULL) -{ - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); - this->loc = loc; - this->exp = exp; - this->sd = NULL; - this->compiled = 0; -} - -Dsymbol *CompileDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - CompileDeclaration *sc = new CompileDeclaration(loc, exp->syntaxCopy()); - return sc; -} - -int CompileDeclaration::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("CompileDeclaration::addMember(sc = %p, sd = %p, memnum = %d)\n", sc, sd, memnum); - this->sd = sd; - if (memnum == 0) - { /* No members yet, so parse the mixin now - */ - compileIt(sc); - memnum |= AttribDeclaration::addMember(sc, sd, memnum); - compiled = 1; - } - return memnum; -} - -void CompileDeclaration::compileIt(Scope *sc) -{ - //printf("CompileDeclaration::compileIt(loc = %d) %s\n", loc.linnum, exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - StringExp *se = exp->toString(); - if (!se) - { exp->error("argument to mixin must be a string, not (%s)", exp->toChars()); - } - else - { - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - decl = p.parseDeclDefs(0); - if (p.token.value != TOKeof) - exp->error("incomplete mixin declaration (%s)", se->toChars()); - } -} - -void CompileDeclaration::semantic(Scope *sc) -{ - //printf("CompileDeclaration::semantic()\n"); - - if (!compiled) - { - compileIt(sc); - AttribDeclaration::addMember(sc, sd, 0); - compiled = 1; - } - AttribDeclaration::semantic(sc); -} - -void CompileDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd2/attrib.h b/dmd2/attrib.h deleted file mode 100644 index 388cd55d..00000000 --- a/dmd2/attrib.h +++ /dev/null @@ -1,202 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ATTRIB_H -#define DMD_ATTRIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -struct Initializer; -struct Module; -struct Condition; -struct HdrGenState; - -/**************************************************************/ - -struct AttribDeclaration : Dsymbol -{ - Dsymbols *decl; // array of Dsymbol's - - AttribDeclaration(Dsymbols *decl); - virtual Dsymbols *include(Scope *sc, ScopeDsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void setScopeNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); - void semanticNewSc(Scope *sc, - StorageClass newstc, enum LINK linkage, enum PROT protection, int explictProtection, - unsigned structalign); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void addComment(unsigned char *comment); - void emitComment(Scope *sc); - const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); - int hasPointers(); - bool hasStaticCtorOrDtor(); - void checkCtorConstInit(); - void addLocalClass(ClassDeclarations *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - AttribDeclaration *isAttribDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); -#endif - -#if IN_LLVM - virtual void codegen(Ir*); -#endif -}; - -struct StorageClassDeclaration: AttribDeclaration -{ - StorageClass stc; - - StorageClassDeclaration(StorageClass stc, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void stcToCBuffer(OutBuffer *buf, StorageClass stc); -}; - -struct LinkDeclaration : AttribDeclaration -{ - enum LINK linkage; - - LinkDeclaration(enum LINK p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void semantic3(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - char *toChars(); -}; - -struct ProtDeclaration : AttribDeclaration -{ - enum PROT protection; - - ProtDeclaration(enum PROT p, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void importAll(Scope *sc); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - static void protectionToCBuffer(OutBuffer *buf, enum PROT protection); -}; - -struct AlignDeclaration : AttribDeclaration -{ - unsigned salign; - - AlignDeclaration(Loc loc, unsigned sa, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void setScope(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AnonDeclaration : AttribDeclaration -{ - int isunion; - int sem; // 1 if successful semantic() - - AnonDeclaration(Loc loc, int isunion, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct PragmaDeclaration : AttribDeclaration -{ - Expressions *args; // array of Expression's - - PragmaDeclaration(Loc loc, Identifier *ident, Expressions *args, Dsymbols *decl); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void setScope(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -struct ConditionalDeclaration : AttribDeclaration -{ - Condition *condition; - Dsymbols *elsedecl; // array of Dsymbol's for else block - - ConditionalDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int oneMember(Dsymbol **ps, Identifier *ident); - void emitComment(Scope *sc); - Dsymbols *include(Scope *sc, ScopeDsymbol *s); - void addComment(unsigned char *comment); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - void importAll(Scope *sc); - void setScope(Scope *sc); -}; - -struct StaticIfDeclaration : ConditionalDeclaration -{ - ScopeDsymbol *sd; - int addisdone; - - StaticIfDeclaration(Condition *condition, Dsymbols *decl, Dsymbols *elsedecl); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void importAll(Scope *sc); - void setScope(Scope *sc); - const char *kind(); -}; - -// Mixin declarations - -struct CompileDeclaration : AttribDeclaration -{ - Expression *exp; - - ScopeDsymbol *sd; - int compiled; - - CompileDeclaration(Loc loc, Expression *exp); - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void compileIt(Scope *sc); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif /* DMD_ATTRIB_H */ diff --git a/dmd2/builtin.c b/dmd2/builtin.c deleted file mode 100644 index 4cfee71f..00000000 --- a/dmd2/builtin.c +++ /dev/null @@ -1,234 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#if __FreeBSD__ -extern "C" -{ - long double sinl(long double); - long double cosl(long double); - long double tanl(long double); - long double sqrtl(long double); -} -#endif - -#include "mars.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if DMDV2 - -/********************************** - * Determine if function is a builtin one that we can - * evaluate at compile time. - */ -enum BUILTIN FuncDeclaration::isBuiltin() -{ - static const char FeZe [] = "FNaNbNfeZe"; // @safe pure nothrow real function(real) - static const char FeZe2[] = "FNaNbNeeZe"; // @trusted pure nothrow real function(real) - static const char FuintZint[] = "FNaNbkZi"; // pure nothrow int function(uint) - static const char FuintZuint[] = "FNaNbkZk"; // pure nothrow uint function(uint) - static const char FulongZulong[] = "FNaNbkZk"; // pure nothrow int function(ulong) - static const char FulongZint[] = "FNaNbmZi"; // pure nothrow int function(uint) - static const char FrealrealZreal [] = "FNaNbNfeeZe"; // @safe pure nothrow real function(real, real) - static const char FrealZlong [] = "FNaNbNfeZl"; // @safe pure nothrow long function(real) - - //printf("FuncDeclaration::isBuiltin() %s, %d\n", toChars(), builtin); - if (builtin == BUILTINunknown) - { - builtin = BUILTINnot; - if (parent && parent->isModule()) - { - // If it's in the std.math package - if (parent->ident == Id::math && - parent->parent && (parent->parent->ident == Id::std || parent->parent->ident == Id::core) && - !parent->parent->parent) - { - //printf("deco = %s\n", type->deco); - if (strcmp(type->deco, FeZe) == 0 || strcmp(type->deco, FeZe2) == 0) - { - if (ident == Id::sin) - builtin = BUILTINsin; - else if (ident == Id::cos) - builtin = BUILTINcos; - else if (ident == Id::tan) - builtin = BUILTINtan; - else if (ident == Id::_sqrt) - builtin = BUILTINsqrt; - else if (ident == Id::fabs) - builtin = BUILTINfabs; - else if (ident == Id::expm1) - builtin = BUILTINexpm1; - else if (ident == Id::exp2) - builtin = BUILTINexp2; - //printf("builtin = %d\n", builtin); - } - // if float or double versions - else if (strcmp(type->deco, "FNaNbNfdZd") == 0 || - strcmp(type->deco, "FNaNbNffZf") == 0) - { - if (ident == Id::_sqrt) - builtin = BUILTINsqrt; - } - else if (strcmp(type->deco, FrealrealZreal) == 0) - { - if (ident == Id::atan2) - builtin = BUILTINatan2; - else if (ident == Id::yl2x) - builtin = BUILTINyl2x; - else if (ident == Id::yl2xp1) - builtin = BUILTINyl2xp1; - } - else if (strcmp(type->deco, FrealZlong) == 0 && ident == Id::rndtol) - builtin = BUILTINrndtol; - } - if (parent->ident == Id::bitop && - parent->parent && parent->parent->ident == Id::core && - !parent->parent->parent) - { - //printf("deco = %s\n", type->deco); - if (strcmp(type->deco, FuintZint) == 0 || strcmp(type->deco, FulongZint) == 0) - { - if (ident == Id::bsf) - builtin = BUILTINbsf; - else if (ident == Id::bsr) - builtin = BUILTINbsr; - } - else if (strcmp(type->deco, FuintZuint) == 0) - { - if (ident == Id::bswap) - builtin = BUILTINbswap; - } - } - } - } - return builtin; -} - -int eval_bsf(uinteger_t n) -{ - n = (n ^ (n - 1)) >> 1; // convert trailing 0s to 1, and zero rest - int k = 0; - while( n ) - { ++k; - n >>=1; - } - return k; -} - -int eval_bsr(uinteger_t n) -{ int k= 0; - while(n>>=1) - { - ++k; - } - return k; -} - -uinteger_t eval_bswap(Expression *arg0) -{ uinteger_t n = arg0->toInteger(); - #define BYTEMASK 0x00FF00FF00FF00FFLL - #define SHORTMASK 0x0000FFFF0000FFFFLL - #define INTMASK 0x0000FFFF0000FFFFLL - // swap adjacent ubytes - n = ((n >> 8 ) & BYTEMASK) | ((n & BYTEMASK) << 8 ); - // swap adjacent ushorts - n = ((n >> 16) & SHORTMASK) | ((n & SHORTMASK) << 16); - TY ty = arg0->type->toBasetype()->ty; - // If 64 bits, we need to swap high and low uints - if (ty == Tint64 || ty == Tuns64) - n = ((n >> 32) & INTMASK) | ((n & INTMASK) << 32); - return n; -} - -/************************************** - * Evaluate builtin function. - * Return result; NULL if cannot evaluate it. - */ - -Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments) -{ - assert(arguments && arguments->dim); - Expression *arg0 = arguments->tdata()[0]; - Expression *e = NULL; - switch (builtin) - { - case BUILTINsin: - if (arg0->op == TOKfloat64) - e = new RealExp(0, sinl(arg0->toReal()), arg0->type); - break; - - case BUILTINcos: - if (arg0->op == TOKfloat64) - e = new RealExp(0, cosl(arg0->toReal()), arg0->type); - break; - - case BUILTINtan: - if (arg0->op == TOKfloat64) - e = new RealExp(0, tanl(arg0->toReal()), arg0->type); - break; - - case BUILTINsqrt: - if (arg0->op == TOKfloat64) - e = new RealExp(0, sqrtl(arg0->toReal()), arg0->type); - break; - - case BUILTINfabs: - if (arg0->op == TOKfloat64) - e = new RealExp(0, fabsl(arg0->toReal()), arg0->type); - break; - // These math intrinsics are not yet implemented - case BUILTINatan2: - break; - case BUILTINrndtol: - break; - case BUILTINexpm1: - break; - case BUILTINexp2: - break; - case BUILTINyl2x: - break; - case BUILTINyl2xp1: - break; - case BUILTINbsf: - if (arg0->op == TOKint64) - { if (arg0->toInteger()==0) - error(loc, "bsf(0) is undefined"); - else - e = new IntegerExp(loc, eval_bsf(arg0->toInteger()), Type::tint32); - } - break; - case BUILTINbsr: - if (arg0->op == TOKint64) - { if (arg0->toInteger()==0) - error(loc, "bsr(0) is undefined"); - else - e = new IntegerExp(loc, eval_bsr(arg0->toInteger()), Type::tint32); - } - break; - case BUILTINbswap: - if (arg0->op == TOKint64) - e = new IntegerExp(loc, eval_bswap(arg0), arg0->type); - break; - } - return e; -} - -#endif diff --git a/dmd2/canthrow.c b/dmd2/canthrow.c deleted file mode 100644 index 885b241a..00000000 --- a/dmd2/canthrow.c +++ /dev/null @@ -1,189 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "attrib.h" - -int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow); -int lambdaCanThrow(Expression *e, void *param); - -/******************************************** - * Convert from expression to delegate that returns the expression, - * i.e. convert: - * expr - * to: - * t delegate() { return expr; } - */ - -struct CanThrow -{ - bool can; - bool mustnot; -}; - -int Expression::canThrow(bool mustNotThrow) -{ - CanThrow ct; - ct.can = FALSE; - ct.mustnot = mustNotThrow; - apply(&lambdaCanThrow, &ct); - return ct.can; -} - -int lambdaCanThrow(Expression *e, void *param) -{ - CanThrow *pct = (CanThrow *)param; - switch (e->op) - { - case TOKdeclaration: - { DeclarationExp *de = (DeclarationExp *)e; - pct->can = Dsymbol_canThrow(de->declaration, pct->mustnot); - break; - } - - case TOKcall: - { CallExp *ce = (CallExp *)e; - - if (global.errors && !ce->e1->type) - break; // error recovery - - /* If calling a function or delegate that is typed as nothrow, - * then this expression cannot throw. - * Note that pure functions can throw. - */ - Type *t = ce->e1->type->toBasetype(); - if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) - ; - else if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - ; - else - { - if (pct->mustnot) - e->error("%s is not nothrow", ce->e1->toChars()); - pct->can = TRUE; - } - break; - } - - case TOKnew: - { NewExp *ne = (NewExp *)e; - if (ne->member) - { - // See if constructor call can throw - Type *t = ne->member->type->toBasetype(); - if (t->ty == Tfunction && !((TypeFunction *)t)->isnothrow) - { - if (pct->mustnot) - e->error("constructor %s is not nothrow", ne->member->toChars()); - pct->can = TRUE; - } - } - // regard storage allocation failures as not recoverable - break; - } - - case TOKnewanonclass: - assert(0); // should have been lowered by semantic() - break; - - default: - break; - } - return pct->can; // stop walking if we determine this expression can throw -} - -/************************************** - * Does symbol, when initialized, throw? - * Mirrors logic in Dsymbol_toElem(). - */ - -int Dsymbol_canThrow(Dsymbol *s, bool mustNotThrow) -{ - AttribDeclaration *ad; - VarDeclaration *vd; - TemplateMixin *tm; - TupleDeclaration *td; - - //printf("Dsymbol_toElem() %s\n", s->toChars()); - ad = s->isAttribDeclaration(); - if (ad) - { - Dsymbols *decl = ad->include(NULL, NULL); - if (decl && decl->dim) - { - for (size_t i = 0; i < decl->dim; i++) - { - s = decl->tdata()[i]; - if (Dsymbol_canThrow(s, mustNotThrow)) - return 1; - } - } - } - else if ((vd = s->isVarDeclaration()) != NULL) - { - s = s->toAlias(); - if (s != vd) - return Dsymbol_canThrow(s, mustNotThrow); - if (vd->storage_class & STCmanifest) - ; - else if (vd->isStatic() || vd->storage_class & (STCextern | STCtls | STCgshared)) - ; - else - { - if (vd->init) - { ExpInitializer *ie = vd->init->isExpInitializer(); - if (ie && ie->exp->canThrow(mustNotThrow)) - return 1; - } - if (vd->edtor && !vd->noscope) - return vd->edtor->canThrow(mustNotThrow); - } - } - else if ((tm = s->isTemplateMixin()) != NULL) - { - //printf("%s\n", tm->toChars()); - if (tm->members) - { - for (size_t i = 0; i < tm->members->dim; i++) - { - Dsymbol *sm = tm->members->tdata()[i]; - if (Dsymbol_canThrow(sm, mustNotThrow)) - return 1; - } - } - } - else if ((td = s->isTupleDeclaration()) != NULL) - { - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = td->objects->tdata()[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *eo = (Expression *)o; - if (eo->op == TOKdsymbol) - { DsymbolExp *se = (DsymbolExp *)eo; - if (Dsymbol_canThrow(se->s, mustNotThrow)) - return 1; - } - } - } - } - return 0; -} diff --git a/dmd2/cast.c b/dmd2/cast.c deleted file mode 100644 index bab1d50d..00000000 --- a/dmd2/cast.c +++ /dev/null @@ -1,2641 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "rmem.h" - -#include "expression.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" - -//#define DUMP .dump(__PRETTY_FUNCTION__, this) -#define DUMP - -/* ==================== implicitCast ====================== */ - -/************************************** - * Do an implicit cast. - * Issue error if it can't be done. - */ - -Expression *Expression::implicitCastTo(Scope *sc, Type *t) -{ - //printf("Expression::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - - MATCH match = implicitConvTo(t); - if (match) - { TY tyfrom = type->toBasetype()->ty; - TY tyto = t->toBasetype()->ty; -#if DMDV1 - if (global.params.warnings && - Type::impcnvWarn[tyfrom][tyto] && - op != TOKint64) - { - Expression *e = optimize(WANTflags | WANTvalue); - - if (e->op == TOKint64) - return e->implicitCastTo(sc, t); - if (tyfrom == Tint32 && - (op == TOKadd || op == TOKmin || - op == TOKand || op == TOKor || op == TOKxor) - ) - { - /* This is really only a semi-kludge fix, - * we really should look at the operands of op - * and see if they are narrower types. - * For example, b=b|b and b=b|7 and s=b+b should be allowed, - * but b=b|i should be an error. - */ - ; - } - else - { - warning("implicit conversion of expression (%s) of type %s to %s can cause loss of data", - toChars(), type->toChars(), t->toChars()); - } - } -#endif -#if DMDV2 - if (match == MATCHconst && t == type->constOf()) - { - Expression *e = copy(); - e->type = t; - return e; - } -#endif - return castTo(sc, t); - } - - Expression *e = optimize(WANTflags | WANTvalue); - if (e != this) - return e->implicitCastTo(sc, t); - -#if 0 -printf("ty = %d\n", type->ty); -print(); -type->print(); -printf("to:\n"); -t->print(); -printf("%p %p type: %s to: %s\n", type->deco, t->deco, type->deco, t->deco); -//printf("%p %p %p\n", type->nextOf()->arrayOf(), type, t); -fflush(stdout); -#endif - if (t->ty != Terror && type->ty != Terror) - { - if (!t->deco) - { /* Can happen with: - * enum E { One } - * class A - * { static void fork(EDG dg) { dg(E.One); } - * alias void delegate(E) EDG; - * } - * Should eventually make it work. - */ - error("forward reference to type %s", t->toChars()); - } - else if (t->reliesOnTident()) - error("forward reference to type %s", t->reliesOnTident()->toChars()); - - error("cannot implicitly convert expression (%s) of type %s to %s", - toChars(), type->toChars(), t->toChars()); - } - return new ErrorExp(); -} - -Expression *StringExp::implicitCastTo(Scope *sc, Type *t) -{ - //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", toChars(), type->toChars(), t->toChars()); - unsigned char committed = this->committed; - Expression *e = Expression::implicitCastTo(sc, t); - if (e->op == TOKstring) - { - // Retain polysemous nature if it started out that way - ((StringExp *)e)->committed = committed; - } - return e; -} - -Expression *ErrorExp::implicitCastTo(Scope *sc, Type *t) -{ - return this; -} - -/******************************************* - * Return !=0 if we can implicitly convert this to type t. - * Don't do the actual cast. - */ - -MATCH Expression::implicitConvTo(Type *t) -{ -#if 0 - printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - //static int nest; if (++nest == 10) halt(); - if (t == Type::terror) - return MATCHnomatch; - if (!type) - { error("%s is not an expression", toChars()); - type = Type::terror; - } - Expression *e = optimize(WANTvalue | WANTflags); - if (e->type == t) - return MATCHexact; - if (e != this) - { //printf("\toptimized to %s of type %s\n", e->toChars(), e->type->toChars()); - return e->implicitConvTo(t); - } - MATCH match = type->implicitConvTo(t); - if (match != MATCHnomatch) - return match; - - /* See if we can do integral narrowing conversions - */ - if (type->isintegral() && t->isintegral() && - type->isTypeBasic() && t->isTypeBasic()) - { IntRange src = this->getIntRange() DUMP; - IntRange targetUnsigned = IntRange::fromType(t, /*isUnsigned*/true) DUMP; - IntRange targetSigned = IntRange::fromType(t, /*isUnsigned*/false) DUMP; - if (targetUnsigned.contains(src) || targetSigned.contains(src)) - return MATCHconvert; - } - -#if 0 - Type *tb = t->toBasetype(); - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - match = type->implicitConvTo(tf->nextOf()); - if (match) - return match; - if (tf->nextOf()->toBasetype()->ty == Tvoid) - return MATCHconvert; - } - } -#endif - return MATCHnomatch; -} - - -MATCH IntegerExp::implicitConvTo(Type *t) -{ -#if 0 - printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = type->implicitConvTo(t); - if (m >= MATCHconst) - return m; - - TY ty = type->toBasetype()->ty; - TY toty = t->toBasetype()->ty; - - if (m == MATCHnomatch && t->ty == Tenum) - goto Lno; - - if (t->ty == Tvector) - { TypeVector *tv = (TypeVector *)t; - TypeBasic *tb = tv->elementType(); - toty = tb->ty; - } - - switch (ty) - { - case Tbool: - value &= 1; - ty = Tint32; - break; - - case Tint8: - value = (signed char)value; - ty = Tint32; - break; - - case Tchar: - case Tuns8: - value &= 0xFF; - ty = Tint32; - break; - - case Tint16: - value = (short)value; - ty = Tint32; - break; - - case Tuns16: - case Twchar: - value &= 0xFFFF; - ty = Tint32; - break; - - case Tint32: - value = (int)value; - break; - - case Tuns32: - case Tdchar: - value &= 0xFFFFFFFF; - ty = Tuns32; - break; - - default: - break; - } - - // Only allow conversion if no change in value - switch (toty) - { - case Tbool: - if ((value & 1) != value) - goto Lno; - goto Lyes; - - case Tint8: - if ((signed char)value != value) - goto Lno; - goto Lyes; - - case Tchar: - case Tuns8: - //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value); - if ((unsigned char)value != value) - goto Lno; - goto Lyes; - - case Tint16: - if ((short)value != value) - goto Lno; - goto Lyes; - - case Tuns16: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tint32: - if (ty == Tuns32) - { - } - else if ((int)value != value) - goto Lno; - goto Lyes; - - case Tuns32: - if (ty == Tint32) - { - } - else if ((unsigned)value != value) - goto Lno; - goto Lyes; - - case Tdchar: - if (value > 0x10FFFFUL) - goto Lno; - goto Lyes; - - case Twchar: - if ((unsigned short)value != value) - goto Lno; - goto Lyes; - - case Tfloat32: - { - volatile float f; - if (type->isunsigned()) - { - f = (float)value; - if (f != value) - goto Lno; - } - else - { - f = (float)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat64: - { - volatile double f; - if (type->isunsigned()) - { - f = (double)value; - if (f != value) - goto Lno; - } - else - { - f = (double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tfloat80: - { - volatile long double f; - if (type->isunsigned()) - { - f = (long double)value; - if (f != value) - goto Lno; - } - else - { - f = (long double)(long long)value; - if (f != (long long)value) - goto Lno; - } - goto Lyes; - } - - case Tpointer: -//printf("type = %s\n", type->toBasetype()->toChars()); -//printf("t = %s\n", t->toBasetype()->toChars()); - if (ty == Tpointer && - type->toBasetype()->nextOf()->ty == t->toBasetype()->nextOf()->ty) - { /* Allow things like: - * const char* P = cast(char *)3; - * char* q = P; - */ - goto Lyes; - } - break; - } - return Expression::implicitConvTo(t); - -Lyes: - //printf("MATCHconvert\n"); - return MATCHconvert; - -Lno: - //printf("MATCHnomatch\n"); - return MATCHnomatch; -} - -MATCH NullExp::implicitConvTo(Type *t) -{ -#if 0 - printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s, committed = %d)\n", - toChars(), type->toChars(), t->toChars(), committed); -#endif - if (this->type->equals(t)) - return MATCHexact; - - /* Allow implicit conversions from immutable to mutable|const, - * and mutable to immutable. It works because, after all, a null - * doesn't actually point to anything. - */ - if (t->invariantOf()->equals(type->invariantOf())) - return MATCHconst; - - return Expression::implicitConvTo(t); -} - -#if DMDV2 -MATCH StructLiteralExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH m = Expression::implicitConvTo(t); - if (m != MATCHnomatch) - return m; - if (type->ty == t->ty && type->ty == Tstruct && - ((TypeStruct *)type)->sym == ((TypeStruct *)t)->sym) - { - m = MATCHconst; - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - Type *te = e->type; - te = te->castMod(t->mod); - MATCH m2 = e->implicitConvTo(te); - //printf("\t%s => %s, match = %d\n", e->toChars(), te->toChars(), m2); - if (m2 < m) - m = m2; - } - } - return m; -} -#endif - -MATCH StringExp::implicitConvTo(Type *t) -{ -#if 0 - printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", - toChars(), committed, type->toChars(), t->toChars()); -#endif - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - return MATCHnomatch; - } - if (type->ty == Tsarray || type->ty == Tarray || type->ty == Tpointer) - { - TY tyn = type->nextOf()->ty; - if (tyn == Tchar || tyn == Twchar || tyn == Tdchar) - { Type *tn; - MATCH m; - - switch (t->ty) - { - case Tsarray: - if (type->ty == Tsarray) - { - if (((TypeSArray *)type)->dim->toInteger() != - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - TY tynto = t->nextOf()->ty; - if (tynto == tyn) - return MATCHexact; - if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) - return MATCHexact; - } - else if (type->ty == Tarray) - { - if (length() > - ((TypeSArray *)t)->dim->toInteger()) - return MATCHnomatch; - TY tynto = t->nextOf()->ty; - if (tynto == tyn) - return MATCHexact; - if (!committed && (tynto == Tchar || tynto == Twchar || tynto == Tdchar)) - return MATCHexact; - } - case Tarray: - case Tpointer: - tn = t->nextOf(); - m = MATCHexact; - if (type->nextOf()->mod != tn->mod) - { if (!tn->isConst()) - return MATCHnomatch; - m = MATCHconst; - } - switch (tn->ty) - { - case Tchar: - case Twchar: - case Tdchar: - if (!committed) - return m; - break; - } - break; - } - } - } - return Expression::implicitConvTo(t); -#if 0 - m = (MATCH)type->implicitConvTo(t); - if (m) - { - return m; - } - - return MATCHnomatch; -#endif -} - -MATCH ArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - -#if 0 - printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - result = MATCHnomatch; - } - - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = (*elements)[i]; - MATCH m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - - if (!result) - result = type->implicitConvTo(t); - - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH AssocArrayLiteralExp::implicitConvTo(Type *t) -{ MATCH result = MATCHexact; - - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray) - { - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; - MATCH m = (MATCH)e->implicitConvTo(((TypeAArray *)tb)->index); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - e = values->tdata()[i]; - m = (MATCH)e->implicitConvTo(tb->nextOf()); - if (m < result) - result = m; // remember worst match - if (result == MATCHnomatch) - break; // no need to check for worse - } - return result; - } - else - return Expression::implicitConvTo(t); -} - -MATCH CallExp::implicitConvTo(Type *t) -{ -#if 0 - printf("CalLExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - - MATCH m = Expression::implicitConvTo(t); - if (m) - return m; - - /* Allow the result of strongly pure functions to - * convert to immutable - */ - if (f && f->isPure() == PUREstrong && !f->type->hasWild()) - return type->invariantOf()->implicitConvTo(t); - - return MATCHnomatch; -} - -MATCH AddrExp::implicitConvTo(Type *t) -{ -#if 0 - printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (size_t i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = eo->vars->a[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf(), m)) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - result = MATCHexact; - } - } - } - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - t->ty == Tpointer && t->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { -#if !IN_LLVM - /* I don't think this can ever happen - - * it should have been - * converted to a SymOffExp. - */ - assert(0); -#endif - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f && f->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH SymOffExp::implicitConvTo(Type *t) -{ -#if 0 - printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - //printf("\tresult = %d\n", result); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - t = t->toBasetype(); - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { f = f->overloadExactMatch(t->nextOf(), m); - if (f) - { if ((t->ty == Tdelegate && (f->needThis() || f->isNested())) || - (t->ty == Tpointer && !(f->needThis() || f->isNested()))) - { - result = MATCHexact; - } - } - } - } - } - //printf("\tresult = %d\n", result); - return result; -} - -MATCH DelegateExp::implicitConvTo(Type *t) -{ -#if 0 - printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == MATCHnomatch) - { - // Look for pointers to functions where the functions are overloaded. - - t = t->toBasetype(); - if (type->ty == Tdelegate && - t->ty == Tdelegate) - { - if (func && func->overloadExactMatch(t->nextOf(), m)) - result = MATCHexact; - } - } - return result; -} - -MATCH FuncExp::implicitConvTo(Type *t) -{ - //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", type, type ? type->toChars() : NULL, t->toChars()); - if (type && type != Type::tvoid && tok == TOKreserved && type->ty == Tpointer - && (t->ty == Tpointer || t->ty == Tdelegate)) - { // Allow implicit function to delegate conversion - if (type->nextOf()->covariant(t->nextOf()) == 1) - return t->ty == Tpointer ? MATCHconst : MATCHconvert; - } - return Expression::implicitConvTo(t); -} - -MATCH OrExp::implicitConvTo(Type *t) -{ - MATCH result = Expression::implicitConvTo(t); - - if (result == MATCHnomatch) - { - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } - return result; -} - -MATCH XorExp::implicitConvTo(Type *t) -{ - MATCH result = Expression::implicitConvTo(t); - - if (result == MATCHnomatch) - { - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - - // Pick the worst match - result = (m1 < m2) ? m1 : m2; - } - return result; -} - -MATCH CondExp::implicitConvTo(Type *t) -{ - MATCH m1 = e1->implicitConvTo(t); - MATCH m2 = e2->implicitConvTo(t); - //printf("CondExp: m1 %d m2 %d\n", m1, m2); - - // Pick the worst match - return (m1 < m2) ? m1 : m2; -} - -MATCH CommaExp::implicitConvTo(Type *t) -{ - return e2->implicitConvTo(t); -} - -MATCH CastExp::implicitConvTo(Type *t) -{ -#if 0 - printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - MATCH result; - - result = type->implicitConvTo(t); - - if (result == MATCHnomatch) - { - if (t->isintegral() && - e1->type->isintegral() && - e1->implicitConvTo(t) != MATCHnomatch) - result = MATCHconvert; - else - result = Expression::implicitConvTo(t); - } - return result; -} - -/* ==================== castTo ====================== */ - -/************************************** - * Do an explicit cast. - */ - -Expression *Expression::castTo(Scope *sc, Type *t) -{ - //printf("Expression::castTo(this=%s, t=%s)\n", toChars(), t->toChars()); -#if 0 - printf("Expression::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { -#if !IN_LLVM - // Do (type *) cast of (type [dim]) - if (tb->ty == Tpointer && - typeb->ty == Tsarray - ) - { - //printf("Converting [dim] to *\n"); - - if (typeb->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, e); - } - else -#endif -#if 0 - if (tb->ty == Tdelegate && type->ty != Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - return toDelegate(sc, tf->nextOf()); - } - else -#endif - { - if (typeb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)typeb; - if (!(tb->ty == Tstruct && ts->sym == ((TypeStruct *)tb)->sym) && - ts->sym->aliasthis) - { /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); - Expression *e2 = new CastExp(loc, e1, tb); - e2 = e2->semantic(sc); - return e2; - } - } - else if (typeb->ty == Tclass) - { TypeClass *ts = (TypeClass *)typeb; - if (ts->sym->aliasthis) - { - if (tb->ty == Tclass) - { - ClassDeclaration *cdfrom = typeb->isClassHandle(); - ClassDeclaration *cdto = tb->isClassHandle(); - int offset; - if (cdto->isBaseOf(cdfrom, &offset)) - goto L1; - } - /* Forward the cast to our alias this member, rewrite to: - * cast(to)e1.aliasthis - */ - Expression *e1 = new DotIdExp(loc, this, ts->sym->aliasthis->ident); - Expression *e2 = new CastExp(loc, e1, tb); - e2 = e2->semantic(sc); - return e2; - } - L1: ; - } - else if (tb->ty == Tvector && typeb->ty != Tvector) - { - e = new VectorExp(loc, e, tb); - e = e->semantic(sc); - return e; - } - e = new CastExp(loc, e, tb); - } - } - else - { - e = e->copy(); // because of COW for assignment to e->type - } - assert(e != this); - e->type = t; - //printf("Returning: %s\n", e->toChars()); - return e; -} - - -Expression *ErrorExp::castTo(Scope *sc, Type *t) -{ - return this; -} - - -Expression *RealExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if ((type->isreal() && t->isreal()) || - (type->isimaginary() && t->isimaginary()) - ) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *ComplexExp::castTo(Scope *sc, Type *t) -{ Expression *e = this; - if (type != t) - { - if (type->iscomplex() && t->iscomplex()) - { e = copy(); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - - -Expression *NullExp::castTo(Scope *sc, Type *t) -{ - //printf("NullExp::castTo(t = %p)\n", t); - if (type == t) - { - committed = 1; - return this; - } - - NullExp *e = (NullExp *)copy(); - e->committed = 1; - Type *tb = t->toBasetype(); -#if 0 - e->type = type->toBasetype(); - if (tb != e->type) - { - // NULL implicitly converts to any pointer type or dynamic array - if (e->type->ty == Tpointer && e->type->nextOf()->ty == Tvoid && - (tb->ty == Tpointer || tb->ty == Tarray || tb->ty == Taarray || - tb->ty == Tdelegate)) - { - if (tb->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)tb; - TypeFunction *tf = (TypeFunction *)td->nextOf(); - - if (!tf->varargs && - !(tf->arguments && tf->arguments->dim) - ) - { - return Expression::castTo(sc, t); - } - } - } - else - { - //return e->Expression::castTo(sc, t); - } - } -#else - if (tb->ty == Tvoid) - { - e->type = type->toBasetype(); - return e->Expression::castTo(sc, t); - } -#endif - e->type = t; - return e; -} - -Expression *StringExp::castTo(Scope *sc, Type *t) -{ - /* This follows copy-on-write; any changes to 'this' - * will result in a copy. - * The this->string member is considered immutable. - */ - int copied = 0; - - //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t->toChars(), toChars(), committed); - - if (!committed && t->ty == Tpointer && t->nextOf()->ty == Tvoid) - { - error("cannot convert string literal to void*"); - return new ErrorExp(); - } - - StringExp *se = this; - if (!committed) - { se = (StringExp *)copy(); - se->committed = 1; - copied = 1; - } - - if (type == t) - { - return se; - } - - Type *tb = t->toBasetype(); - //printf("\ttype = %s\n", type->toChars()); - if (tb->ty == Tdelegate && type->toBasetype()->ty != Tdelegate) - return Expression::castTo(sc, t); - - Type *typeb = type->toBasetype(); - if (typeb == tb) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->type = t; - return se; - } - - if (committed && tb->ty == Tsarray && typeb->ty == Tarray) - { - se = (StringExp *)copy(); - d_uns64 szx = tb->nextOf()->size(); - assert(szx <= 255); - se->sz = (unsigned char)szx; - se->len = (len * sz) / se->sz; - se->committed = 1; - se->type = t; - return se; - } - - if (tb->ty != Tsarray && tb->ty != Tarray && tb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - if (typeb->ty != Tsarray && typeb->ty != Tarray && typeb->ty != Tpointer) - { if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - goto Lcast; - } - - if (typeb->nextOf()->size() == tb->nextOf()->size()) - { - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - if (tb->ty == Tsarray) - goto L2; // handle possible change in static array dimension - se->type = t; - return se; - } - - if (committed) - goto Lcast; - -#define X(tf,tt) ((tf) * 256 + (tt)) - { - OutBuffer buffer; - size_t newlen = 0; - int tfty = typeb->nextOf()->toBasetype()->ty; - int ttty = tb->nextOf()->toBasetype()->ty; - switch (X(tfty, ttty)) - { - case X(Tchar, Tchar): - case X(Twchar,Twchar): - case X(Tdchar,Tdchar): - break; - - case X(Tchar, Twchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF16(c); - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - case X(Tchar, Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeChar((unsigned char *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Twchar,Tchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - else - buffer.writeUTF8(c); - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Twchar,Tdchar): - for (size_t u = 0; u < len;) - { unsigned c; - const char *p = utf_decodeWchar((unsigned short *)se->string, len, &u, &c); - if (p) - error("%s", p); - buffer.write4(c); - newlen++; - } - buffer.write4(0); - goto L1; - - case X(Tdchar,Tchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF8(c); - newlen++; - } - newlen = buffer.offset; - buffer.writeUTF8(0); - goto L1; - - case X(Tdchar,Twchar): - for (size_t u = 0; u < len; u++) - { - unsigned c = ((unsigned *)se->string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - buffer.writeUTF16(c); - newlen++; - } - newlen = buffer.offset / 2; - buffer.writeUTF16(0); - goto L1; - - L1: - if (!copied) - { se = (StringExp *)copy(); - copied = 1; - } - se->string = buffer.extractData(); - se->len = newlen; - - { - d_uns64 szx = tb->nextOf()->size(); - assert(szx <= 255); - se->sz = (unsigned char)szx; - } - break; - - default: - assert(typeb->nextOf()->size() != tb->nextOf()->size()); - goto Lcast; - } - } -#undef X -L2: - assert(copied); - - // See if need to truncate or extend the literal - if (tb->ty == Tsarray) - { - dinteger_t dim2 = ((TypeSArray *)tb)->dim->toInteger(); - - //printf("dim from = %d, to = %d\n", (int)se->len, (int)dim2); - - // Changing dimensions - if (dim2 != se->len) - { - // Copy when changing the string literal - unsigned newsz = se->sz; - void *s; - int d; - - d = (dim2 < se->len) ? dim2 : se->len; - s = (unsigned char *)mem.malloc((dim2 + 1) * newsz); - memcpy(s, se->string, d * newsz); - // Extend with 0, add terminating 0 - memset((char *)s + d * newsz, 0, (dim2 + 1 - d) * newsz); - se->string = s; - se->len = dim2; - } - } - se->type = t; - return se; - -Lcast: - Expression *e = new CastExp(loc, se, t); - e->type = t; // so semantic() won't be run on e - return e; -} - -Expression *AddrExp::castTo(Scope *sc, Type *t) -{ - Type *tb; - -#if 0 - printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - Expression *e = this; - - tb = t->toBasetype(); - type = type->toBasetype(); - if (tb != type) - { - // Look for pointers to functions where the functions are overloaded. - - if (e1->op == TOKoverloadset && - (t->ty == Tpointer || t->ty == Tdelegate) && t->nextOf()->ty == Tfunction) - { OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - for (size_t i = 0; i < eo->vars->a.dim; i++) - { Dsymbol *s = eo->vars->a[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - assert(f2); - if (f2->overloadExactMatch(t->nextOf(), m)) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } -#if IN_LLVM - if (f) - { - f = f->overloadExactMatch(tb->nextOf(), m); - if (f) - { - if (tb->ty == Tdelegate) - { - if (f->needThis() && hasThis(sc)) - { - e = new DelegateExp(loc, new ThisExp(loc), f); - e = e->semantic(sc); - } - else if (f->isNested()) - { - e = new DelegateExp(loc, new IntegerExp(0), f); - e = e->semantic(sc); - } - else if (f->needThis()) - { error("no 'this' to create delegate for %s", f->toChars()); - return new ErrorExp(); - } - else - { error("cannot cast from function pointer to delegate"); - return new ErrorExp(); - } - } - else - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } -#if DMDV2 - f->tookAddressOf++; -#endif - return e; - } - } -#else - if (f) - { f->tookAddressOf++; - SymOffExp *se = new SymOffExp(loc, f, 0, 0); - se->semantic(sc); - // Let SymOffExp::castTo() do the heavy lifting - return se->castTo(sc, t); - } -#endif - } - - if (type->ty == Tpointer && type->nextOf()->ty == Tfunction && - tb->ty == Tpointer && tb->nextOf()->ty == Tfunction && - e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { -#if !IN_LLVM - assert(0); // should be SymOffExp instead -#endif - f = f->overloadExactMatch(tb->nextOf(), m); - if (f) - { - e = new VarExp(loc, f); - e->type = f->type; - e = new AddrExp(loc, e); - e->type = t; - return e; - } - } - } - - e = Expression::castTo(sc, t); - } -#if IN_LLVM - else if (e1->op == TOKvar) - { - VarExp *ve = (VarExp*)e1->copy(); - ve->hasOverloads = 0; - e1 = ve; - } -#endif - e->type = t; - return e; -} - - -Expression *TupleExp::castTo(Scope *sc, Type *t) -{ TupleExp *e = (TupleExp *)copy(); - e->exps = (Expressions *)exps->copy(); - for (size_t i = 0; i < e->exps->dim; i++) - { Expression *ex = e->exps->tdata()[i]; - ex = ex->castTo(sc, t); - e->exps->tdata()[i] = ex; - } - return e; -} - - -Expression *ArrayLiteralExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t) - return this; - ArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if ((tb->ty == Tarray || tb->ty == Tsarray) && - (typeb->ty == Tarray || typeb->ty == Tsarray) && - // Not trying to convert non-void[] to void[] - !(tb->nextOf()->toBasetype()->ty == Tvoid && typeb->nextOf()->toBasetype()->ty != Tvoid)) - { - if (tb->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)tb; - if (elements->dim != tsa->dim->toInteger()) - goto L1; - } - - e = (ArrayLiteralExp *)copy(); - e->elements = (Expressions *)elements->copy(); - for (size_t i = 0; i < elements->dim; i++) - { Expression *ex = (*elements)[i]; - ex = ex->castTo(sc, tb->nextOf()); - (*e->elements)[i] = ex; - } - e->type = t; - return e; - } - if (tb->ty == Tpointer && typeb->ty == Tsarray) - { - Type *tp = typeb->nextOf()->pointerTo(); - if (!tp->equals(e->type)) - { e = (ArrayLiteralExp *)copy(); - e->type = tp; - } - } -L1: - return e->Expression::castTo(sc, t); -} - -Expression *AssocArrayLiteralExp::castTo(Scope *sc, Type *t) -{ - if (type == t) - return this; - AssocArrayLiteralExp *e = this; - Type *typeb = type->toBasetype(); - Type *tb = t->toBasetype(); - if (tb->ty == Taarray && typeb->ty == Taarray && - tb->nextOf()->toBasetype()->ty != Tvoid) - { - e = (AssocArrayLiteralExp *)copy(); - e->keys = (Expressions *)keys->copy(); - e->values = (Expressions *)values->copy(); - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ex = values->tdata()[i]; - ex = ex->castTo(sc, tb->nextOf()); - e->values->tdata()[i] = ex; - - ex = keys->tdata()[i]; - ex = ex->castTo(sc, ((TypeAArray *)tb)->index); - e->keys->tdata()[i] = ex; - } - e->type = t; - return e; - } - return e->Expression::castTo(sc, t); -} - -Expression *SymOffExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - if (type == t && hasOverloads == 0) - return this; - Expression *e; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for pointers to functions where the functions are overloaded. - FuncDeclaration *f; - - if (hasOverloads && - typeb->ty == Tpointer && typeb->nextOf()->ty == Tfunction && - (tb->ty == Tpointer || tb->ty == Tdelegate) && tb->nextOf()->ty == Tfunction) - { - f = var->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(tb->nextOf(), m); - if (f) - { - if (tb->ty == Tdelegate) - { - if (f->needThis() && hasThis(sc)) - { - e = new DelegateExp(loc, new ThisExp(loc), f); - e = e->semantic(sc); - } - else if (f->isNested()) - { - e = new DelegateExp(loc, new IntegerExp(0), f); - e = e->semantic(sc); - } - else if (f->needThis()) - { error("no 'this' to create delegate for %s", f->toChars()); - return new ErrorExp(); - } - else - { error("cannot cast from function pointer to delegate"); - return new ErrorExp(); - } - } - else - { - e = new SymOffExp(loc, f, 0); - e->type = t; - } -#if DMDV2 - f->tookAddressOf++; -#endif - return e; - } - } - } - e = Expression::castTo(sc, t); - } - else - { e = copy(); - e->type = t; - ((SymOffExp *)e)->hasOverloads = 0; - } - return e; -} - -Expression *DelegateExp::castTo(Scope *sc, Type *t) -{ -#if 0 - printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", - toChars(), type->toChars(), t->toChars()); -#endif - static char msg[] = "cannot form delegate due to covariant return type"; - - Expression *e = this; - Type *tb = t->toBasetype(); - Type *typeb = type->toBasetype(); - if (tb != typeb) - { - // Look for delegates to functions where the functions are overloaded. - FuncDeclaration *f; - - if (typeb->ty == Tdelegate && - tb->ty == Tdelegate) - { - if (func) - { - f = func->overloadExactMatch(tb->nextOf(), m); - if (f) - { int offset; - if (f->tintro && f->tintro->nextOf()->isBaseOf(f->type->nextOf(), &offset) && offset) - error("%s", msg); - f->tookAddressOf++; - e = new DelegateExp(loc, e1, f); - e->type = t; - return e; - } - if (func->tintro) - error("%s", msg); - } - } - e = Expression::castTo(sc, t); - } - else - { int offset; - - func->tookAddressOf++; - if (func->tintro && func->tintro->nextOf()->isBaseOf(func->type->nextOf(), &offset) && offset) - error("%s", msg); - e = copy(); - e->type = t; - } - return e; -} - -Expression *FuncExp::castTo(Scope *sc, Type *t) -{ - //printf("FuncExp::castTo type = %s, t = %s\n", type->toChars(), t->toChars()); - if (tok == TOKreserved) - { assert(type && type != Type::tvoid); - if (type->ty == Tpointer && t->ty == Tdelegate) - { - Expression *e = copy(); - e->type = new TypeDelegate(fd->type); - e->type = e->type->semantic(loc, sc); - return e; - } - } - return Expression::castTo(sc, t); -} - -Expression *CondExp::castTo(Scope *sc, Type *t) -{ - Expression *e = this; - - if (type != t) - { - if (1 || e1->op == TOKstring || e2->op == TOKstring) - { e = new CondExp(loc, econd, e1->castTo(sc, t), e2->castTo(sc, t)); - e->type = t; - } - else - e = Expression::castTo(sc, t); - } - return e; -} - -Expression *CommaExp::castTo(Scope *sc, Type *t) -{ - Expression *e2c = e2->castTo(sc, t); - Expression *e; - - if (e2c != e2) - { - e = new CommaExp(loc, e1, e2c); - e->type = e2c->type; - } - else - { e = this; - e->type = e2->type; - } - return e; -} - -/* ==================== ====================== */ - -/**************************************** - * Scale addition/subtraction to/from pointer. - */ - -Expression *BinExp::scaleFactor(Scope *sc) -{ - if (sc->func && !sc->intypeof) - { - if (sc->func->setUnsafe()) - { - error("pointer arithmetic not allowed in @safe functions"); - return new ErrorExp(); - } - } - - d_uns64 stride; - Type *t1b = e1->type->toBasetype(); - Type *t2b = e2->type->toBasetype(); - - if (t1b->ty == Tpointer && t2b->isintegral()) - { // Need to adjust operator by the stride - // Replace (ptr + int) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - - stride = t1b->nextOf()->size(loc); - if (!t->equals(t2b)) - e2 = e2->castTo(sc, t); -// LDC: llvm uses typesafe pointer arithmetic -#if !IN_LLVM - e2 = new MulExp(loc, e2, new IntegerExp(0, stride, t)); -#endif - e2->type = t; - type = e1->type; - } - else if (t2b->ty == Tpointer && t1b->isintegral()) - { // Need to adjust operator by the stride - // Replace (int + ptr) with (ptr + (int * stride)) - Type *t = Type::tptrdiff_t; - Expression *e; - - stride = t2b->nextOf()->size(loc); - if (!t->equals(t1b)) - e = e1->castTo(sc, t); - else - e = e1; -#if !IN_LLVM - e = new MulExp(loc, e, new IntegerExp(0, stride, t)); -#endif - e->type = t; - type = e2->type; - e1 = e2; - e2 = e; - } - return this; -} - -/************************************** - * Return true if e is an empty array literal with dimensionality - * equal to or less than type of other array. - * [], [[]], [[[]]], etc. - * I.e., make sure that [1,2] is compatible with [], - * [[1,2]] is compatible with [[]], etc. - */ -bool isVoidArrayLiteral(Expression *e, Type *other) -{ - while (e->op == TOKarrayliteral && e->type->ty == Tarray - && (((ArrayLiteralExp *)e)->elements->dim == 1)) - { - e = ((ArrayLiteralExp *)e)->elements->tdata()[0]; - if (other->ty == Tsarray || other->ty == Tarray) - other = other->nextOf(); - else - return false; - } - if (other->ty != Tsarray && other->ty != Tarray) - return false; - Type *t = e->type; - return (e->op == TOKarrayliteral && t->ty == Tarray && - t->nextOf()->ty == Tvoid && - ((ArrayLiteralExp *)e)->elements->dim == 0); -} - - -/************************************** - * Combine types. - * Output: - * *pt merged type, if *pt is not NULL - * *pe1 rewritten e1 - * *pe2 rewritten e2 - * Returns: - * !=0 success - * 0 failed - */ - -int typeMerge(Scope *sc, Expression *e, Type **pt, Expression **pe1, Expression **pe2) -{ - //printf("typeMerge() %s op %s\n", (*pe1)->toChars(), (*pe2)->toChars()); - //e->dump(0); - - Expression *e1 = *pe1; - Expression *e2 = *pe2; - - if (e->op != TOKquestion || - e1->type->toBasetype()->ty != e2->type->toBasetype()->ty) - { - e1 = e1->integralPromotions(sc); - e2 = e2->integralPromotions(sc); - } - - Type *t1 = e1->type; - Type *t2 = e2->type; - assert(t1); - Type *t = t1; - - //if (t1) printf("\tt1 = %s\n", t1->toChars()); - //if (t2) printf("\tt2 = %s\n", t2->toChars()); -#ifdef DEBUG - if (!t2) printf("\te2 = '%s'\n", e2->toChars()); -#endif - assert(t2); - - Type *t1b = t1->toBasetype(); - Type *t2b = t2->toBasetype(); - - TY ty = (TY)Type::impcnvResult[t1b->ty][t2b->ty]; - if (ty != Terror) - { - TY ty1 = (TY)Type::impcnvType1[t1b->ty][t2b->ty]; - TY ty2 = (TY)Type::impcnvType2[t1b->ty][t2b->ty]; - - if (t1b->ty == ty1) // if no promotions - { - if (t1 == t2) - { - t = t1; - goto Lret; - } - - if (t1b == t2b) - { - t = t1b; - goto Lret; - } - } - - t = Type::basic[ty]; - - t1 = Type::basic[ty1]; - t2 = Type::basic[ty2]; - e1 = e1->castTo(sc, t1); - e2 = e2->castTo(sc, t2); - //printf("after typeCombine():\n"); - //dump(0); - //printf("ty = %d, ty1 = %d, ty2 = %d\n", ty, ty1, ty2); - goto Lret; - } - - t1 = t1b; - t2 = t2b; - -Lagain: - if (t1 == t2) - { - } - else if ((t1->ty == Tpointer && t2->ty == Tpointer) || - (t1->ty == Tdelegate && t2->ty == Tdelegate)) - { - // Bring pointers to compatible type - Type *t1n = t1->nextOf(); - Type *t2n = t2->nextOf(); - - if (t1n == t2n) - ; -#if IN_LLVM - else if (t1n->equals(t2n)) - ; -#endif - else if (t1n->ty == Tvoid) // pointers to void are always compatible - t = t2; - else if (t2n->ty == Tvoid) - ; - else if (t1->implicitConvTo(t2)) - { - goto Lt2; - } - else if (t2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1n->ty == Tfunction && t2n->ty == Tfunction) - { - TypeFunction *tf1 = (TypeFunction *)t1n; - TypeFunction *tf2 = (TypeFunction *)t2n; - TypeFunction *d = (TypeFunction *)tf1->syntaxCopy(); - - if (tf1->purity != tf2->purity) - d->purity = PUREimpure; - assert(d->purity != PUREfwdref); - - d->isnothrow = (tf1->isnothrow && tf2->isnothrow); - - if (tf1->trust == tf2->trust) - d->trust = tf1->trust; - else if (tf1->trust <= TRUSTsystem || tf2->trust <= TRUSTsystem) - d->trust = TRUSTsystem; - else - d->trust = TRUSTtrusted; - - Type *tx = NULL; - if (t1->ty == Tdelegate) - { - tx = new TypeDelegate(d); - tx = tx->merge(); - } - else - tx = d->pointerTo(); - - if (t1->implicitConvTo(tx) && t2->implicitConvTo(tx)) - { - t = tx; - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - goto Lret; - } - goto Lincompatible; - } - else if (t1n->mod != t2n->mod) - { - if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared()) - goto Lincompatible; - unsigned char mod = MODmerge(t1n->mod, t2n->mod); - t1 = t1n->castMod(mod)->pointerTo(); - t2 = t2n->castMod(mod)->pointerTo(); - t = t1; - goto Lagain; - } - else if (t1n->ty == Tclass && t2n->ty == Tclass) - { ClassDeclaration *cd1 = t1n->isClassHandle(); - ClassDeclaration *cd2 = t2n->isClassHandle(); - int offset; - - if (cd1->isBaseOf(cd2, &offset)) - { - if (offset) - e2 = e2->castTo(sc, t); - } - else if (cd2->isBaseOf(cd1, &offset)) - { - t = t2; - if (offset) - e1 = e1->castTo(sc, t); - } - else - goto Lincompatible; - } - else - { - t1 = t1n->constOf()->pointerTo(); - t2 = t2n->constOf()->pointerTo(); - if (t1->implicitConvTo(t2)) - { - goto Lt2; - } - else if (t2->implicitConvTo(t1)) - { - goto Lt1; - } - goto Lincompatible; - } - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && - (e2->op == TOKnull && t2->ty == Tpointer && t2->nextOf()->ty == Tvoid || - // if e2 is void[] - e2->op == TOKarrayliteral && t2->ty == Tsarray && t2->nextOf()->ty == Tvoid && ((TypeSArray *)t2)->dim->toInteger() == 0 || - isVoidArrayLiteral(e2, t1)) - ) - { /* (T[n] op void*) => T[] - * (T[] op void*) => T[] - * (T[n] op void[0]) => T[] - * (T[] op void[0]) => T[] - * (T[n] op void[]) => T[] - * (T[] op void[]) => T[] - */ - goto Lx1; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && - (e1->op == TOKnull && t1->ty == Tpointer && t1->nextOf()->ty == Tvoid || - e1->op == TOKarrayliteral && t1->ty == Tsarray && t1->nextOf()->ty == Tvoid && ((TypeSArray *)t1)->dim->toInteger() == 0 || - isVoidArrayLiteral(e1, t2)) - ) - { /* (void* op T[n]) => T[] - * (void* op T[]) => T[] - * (void[0] op T[n]) => T[] - * (void[0] op T[]) => T[] - * (void[] op T[n]) => T[] - * (void[] op T[]) => T[] - */ - goto Lx2; - } - else if ((t1->ty == Tsarray || t1->ty == Tarray) && t1->implicitConvTo(t2)) - { - if (t1->ty == Tsarray && e2->op == TOKarrayliteral) - goto Lt1; - goto Lt2; - } - else if ((t2->ty == Tsarray || t2->ty == Tarray) && t2->implicitConvTo(t1)) - { - if (t2->ty == Tsarray && e1->op == TOKarrayliteral) - goto Lt2; - goto Lt1; - } - /* If one is mutable and the other invariant, then retry - * with both of them as const - */ - else if ((t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Tpointer) && - (t2->ty == Tsarray || t2->ty == Tarray || t2->ty == Tpointer) && - t1->nextOf()->mod != t2->nextOf()->mod - ) - { - Type *t1n = t1->nextOf(); - Type *t2n = t2->nextOf(); - unsigned char mod; - if (e1->op == TOKnull && e2->op != TOKnull) - mod = t2n->mod; - else if (e1->op != TOKnull && e2->op == TOKnull) - mod = t1n->mod; - else if (!t1n->isImmutable() && !t2n->isImmutable() && t1n->isShared() != t2n->isShared()) - goto Lincompatible; - else - mod = MODmerge(t1n->mod, t2n->mod); - - if (t1->ty == Tpointer) - t1 = t1n->castMod(mod)->pointerTo(); - else - t1 = t1n->castMod(mod)->arrayOf(); - - if (t2->ty == Tpointer) - t2 = t2n->castMod(mod)->pointerTo(); - else - t2 = t2n->castMod(mod)->arrayOf(); - t = t1; - goto Lagain; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { - if (t1->mod != t2->mod) - { - unsigned char mod; - if (e1->op == TOKnull && e2->op != TOKnull) - mod = t2->mod; - else if (e1->op != TOKnull && e2->op == TOKnull) - mod = t1->mod; - else if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) - goto Lincompatible; - else - mod = MODmerge(t1->mod, t2->mod); - t1 = t1->castMod(mod); - t2 = t2->castMod(mod); - t = t1; - goto Lagain; - } - goto Lcc; - } - else if (t1->ty == Tclass || t2->ty == Tclass) - { -Lcc: - while (1) - { - int i1 = e2->implicitConvTo(t1); - int i2 = e1->implicitConvTo(t2); - - if (i1 && i2) - { - // We have the case of class vs. void*, so pick class - if (t1->ty == Tpointer) - i1 = 0; - else if (t2->ty == Tpointer) - i2 = 0; - } - - if (i2) - { - goto Lt2; - } - else if (i1) - { - goto Lt1; - } - else if (t1->ty == Tclass && t2->ty == Tclass) - { TypeClass *tc1 = (TypeClass *)t1; - TypeClass *tc2 = (TypeClass *)t2; - - /* Pick 'tightest' type - */ - ClassDeclaration *cd1 = tc1->sym->baseClass; - ClassDeclaration *cd2 = tc2->sym->baseClass; - - if (cd1 && cd2) - { t1 = cd1->type; - t2 = cd2->type; - } - else if (cd1) - t1 = cd1->type; - else if (cd2) - t2 = cd2->type; - else - goto Lincompatible; - } - else if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) - { - e1 = new DotIdExp(e1->loc, e1, ((TypeStruct *)t1)->sym->aliasthis->ident); - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - t1 = e1->type; - continue; - } - else if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) - { - e2 = new DotIdExp(e2->loc, e2, ((TypeStruct *)t2)->sym->aliasthis->ident); - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - t2 = e2->type; - continue; - } - else - goto Lincompatible; - } - } - else if (t1->ty == Tstruct && t2->ty == Tstruct) - { - if (t1->mod != t2->mod) - { - if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) - goto Lincompatible; - unsigned char mod = MODmerge(t1->mod, t2->mod); - t1 = t1->castMod(mod); - t2 = t2->castMod(mod); - t = t1; - goto Lagain; - } - - TypeStruct *ts1 = (TypeStruct *)t1; - TypeStruct *ts2 = (TypeStruct *)t2; - if (ts1->sym != ts2->sym) - { - if (!ts1->sym->aliasthis && !ts2->sym->aliasthis) - goto Lincompatible; - - int i1 = 0; - int i2 = 0; - - Expression *e1b = NULL; - Expression *e2b = NULL; - if (ts2->sym->aliasthis) - { - e2b = new DotIdExp(e2->loc, e2, ts2->sym->aliasthis->ident); - e2b = e2b->semantic(sc); - e2b = resolveProperties(sc, e2b); - i1 = e2b->implicitConvTo(t1); - } - if (ts1->sym->aliasthis) - { - e1b = new DotIdExp(e1->loc, e1, ts1->sym->aliasthis->ident); - e1b = e1b->semantic(sc); - e1b = resolveProperties(sc, e1b); - i2 = e1b->implicitConvTo(t2); - } - if (i1 && i2) - goto Lincompatible; - - if (i1) - goto Lt1; - else if (i2) - goto Lt2; - - if (e1b) - { e1 = e1b; - t1 = e1b->type->toBasetype(); - } - if (e2b) - { e2 = e2b; - t2 = e2b->type->toBasetype(); - } - t = t1; - goto Lagain; - } - } - else if (t1->ty == Tstruct || t2->ty == Tstruct) - { - if (t1->ty == Tstruct && ((TypeStruct *)t1)->sym->aliasthis) - { - e1 = new DotIdExp(e1->loc, e1, ((TypeStruct *)t1)->sym->aliasthis->ident); - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - t1 = e1->type; - t = t1; - goto Lagain; - } - if (t2->ty == Tstruct && ((TypeStruct *)t2)->sym->aliasthis) - { - e2 = new DotIdExp(e2->loc, e2, ((TypeStruct *)t2)->sym->aliasthis->ident); - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - t2 = e2->type; - t = t2; - goto Lagain; - } - goto Lincompatible; - } - else if ((e1->op == TOKstring || e1->op == TOKnull) && e1->implicitConvTo(t2)) - { - goto Lt2; - } - else if ((e2->op == TOKstring || e2->op == TOKnull) && e2->implicitConvTo(t1)) - { - goto Lt1; - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e2->implicitConvTo(t1->nextOf()->arrayOf())) - { - Lx1: - t = t1->nextOf()->arrayOf(); // T[] - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tsarray && t2->ty == Tsarray && - e1->implicitConvTo(t2->nextOf()->arrayOf())) - { - Lx2: - t = t2->nextOf()->arrayOf(); - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - } - else if (t1->ty == Tvector && t2->ty != Tvector && - e2->implicitConvTo(t1)) - { - e2 = e2->castTo(sc, t1); - t2 = t1; - goto Lagain; - } - else if (t2->ty == Tvector && t1->ty != Tvector && - e1->implicitConvTo(t2)) - { - e1 = e1->castTo(sc, t2); - t1 = t2; - goto Lagain; - } - else if (t1->isintegral() && t2->isintegral()) - { - assert(t1->ty == t2->ty); - if (!t1->isImmutable() && !t2->isImmutable() && t1->isShared() != t2->isShared()) - goto Lincompatible; - unsigned char mod = MODmerge(t1->mod, t2->mod); - - t1 = t1->castMod(mod); - t2 = t2->castMod(mod); - t = t1; - e1 = e1->castTo(sc, t); - e2 = e2->castTo(sc, t); - goto Lagain; - } - else if (e1->isArrayOperand() && t1->ty == Tarray && - e2->implicitConvTo(t1->nextOf())) - { // T[] op T - e2 = e2->castTo(sc, t1->nextOf()); - t = t1->nextOf()->arrayOf(); - } - else if (e2->isArrayOperand() && t2->ty == Tarray && - e1->implicitConvTo(t2->nextOf())) - { // T op T[] - e1 = e1->castTo(sc, t2->nextOf()); - t = t2->nextOf()->arrayOf(); - - //printf("test %s\n", e->toChars()); - e1 = e1->optimize(WANTvalue); - if (e && e->isCommutative() && e1->isConst()) - { /* Swap operands to minimize number of functions generated - */ - //printf("swap %s\n", e->toChars()); - Expression *tmp = e1; - e1 = e2; - e2 = tmp; - } - } - else - { - Lincompatible: - return 0; - } -Lret: - if (!*pt) - *pt = t; - *pe1 = e1; - *pe2 = e2; -#if 0 - printf("-typeMerge() %s op %s\n", e1->toChars(), e2->toChars()); - if (e1->type) printf("\tt1 = %s\n", e1->type->toChars()); - if (e2->type) printf("\tt2 = %s\n", e2->type->toChars()); - printf("\ttype = %s\n", t->toChars()); -#endif - //dump(0); - return 1; - - -Lt1: - e2 = e2->castTo(sc, t1); - t = t1; - goto Lret; - -Lt2: - e1 = e1->castTo(sc, t2); - t = t2; - goto Lret; -} - -/************************************ - * Bring leaves to common type. - */ - -Expression *BinExp::typeCombine(Scope *sc) -{ - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - if (op == TOKmin || op == TOKadd) - { - // struct+struct, and class+class are errors - if (t1->ty == Tstruct && t2->ty == Tstruct) - goto Lerror; - else if (t1->ty == Tclass && t2->ty == Tclass) - goto Lerror; - } - - if (!typeMerge(sc, this, &type, &e1, &e2)) - goto Lerror; - return this; - -Lerror: - incompatibleTypes(); - type = Type::terror; - e1 = new ErrorExp(); - e2 = new ErrorExp(); - return new ErrorExp(); -} - -/*********************************** - * Do integral promotions (convertchk). - * Don't convert to - */ - -Expression *Expression::integralPromotions(Scope *sc) -{ - Expression *e = this; - - //printf("integralPromotions %s %s\n", e->toChars(), e->type->toChars()); - switch (type->toBasetype()->ty) - { - case Tvoid: - error("void has no value"); - return new ErrorExp(); - - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: - case Tbool: - case Tchar: - case Twchar: - e = e->castTo(sc, Type::tint32); - break; - - case Tdchar: - e = e->castTo(sc, Type::tuns32); - break; - } - return e; -} - -/*********************************** - * See if both types are arrays that can be compared - * for equality. Return !=0 if so. - * If they are arrays, but incompatible, issue error. - * This is to enable comparing things like an immutable - * array with a mutable one. - */ - -int arrayTypeCompatible(Loc loc, Type *t1, Type *t2) -{ - t1 = t1->toBasetype(); - t2 = t2->toBasetype(); - - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - { - error(loc, "array equality comparison type mismatch, %s vs %s", t1->toChars(), t2->toChars()); - } - return 1; - } - return 0; -} - -/*********************************** - * See if both types are arrays that can be compared - * for equality without any casting. Return !=0 if so. - * This is to enable comparing things like an immutable - * array with a mutable one. - */ -int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2) -{ - t1 = t1->toBasetype(); - t2 = t2->toBasetype(); - - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - t2->ty == t1->ty) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) >= MATCHconst || - t2->nextOf()->implicitConvTo(t1->nextOf()) >= MATCHconst) - return 1; - } - return 0; -} - - -/******************************************************************/ - -/* Determine the integral ranges of an expression. - * This is used to determine if implicit narrowing conversions will - * be allowed. - */ - -uinteger_t getMask(uinteger_t v) -{ - // Ref: http://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2 - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - v |= v >> 32; - return v /* | 0xff*/; -} -IntRange Expression::getIntRange() -{ - return IntRange::fromType(type) DUMP; -} - -IntRange IntegerExp::getIntRange() -{ - return IntRange(value).cast(type) DUMP; -} - -IntRange CastExp::getIntRange() -{ - return e1->getIntRange().cast(type) DUMP; -} - -IntRange AddExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - return IntRange(ir1.imin + ir2.imin, ir1.imax + ir2.imax).cast(type) DUMP; -} - -IntRange MinExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - return IntRange(ir1.imin - ir2.imax, ir1.imax - ir2.imin).cast(type) DUMP; -} - -IntRange DivExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - // Should we ignore the possibility of div-by-0??? - if (ir2.containsZero()) - return Expression::getIntRange() DUMP; - - // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)] - SignExtendedNumber bdy[4] = { - ir1.imin / ir2.imin, - ir1.imin / ir2.imax, - ir1.imax / ir2.imin, - ir1.imax / ir2.imax - }; - return IntRange::fromNumbers4(bdy).cast(type) DUMP; -} - -IntRange MulExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - // [a,b] * [c,d] = [min (ac, ad, bc, bd), max (ac, ad, bc, bd)] - SignExtendedNumber bdy[4] = { - ir1.imin * ir2.imin, - ir1.imin * ir2.imax, - ir1.imax * ir2.imin, - ir1.imax * ir2.imax - }; - return IntRange::fromNumbers4(bdy).cast(type) DUMP; -} - -IntRange ModExp::getIntRange() -{ - IntRange irNum = e1->getIntRange(); - IntRange irDen = e2->getIntRange().absNeg(); - - /* - due to the rules of D (C)'s % operator, we need to consider the cases - separately in different range of signs. - - case 1. [500, 1700] % [7, 23] (numerator is always positive) - = [0, 22] - case 2. [-500, 1700] % [7, 23] (numerator can be negative) - = [-22, 22] - case 3. [-1700, -500] % [7, 23] (numerator is always negative) - = [-22, 0] - - the number 22 is the maximum absolute value in the denomator's range. We - don't care about divide by zero. - */ - - // Modding on 0 is invalid anyway. - if (!irDen.imin.negative) - return Expression::getIntRange() DUMP; - - ++ irDen.imin; - irDen.imax = -irDen.imin; - - if (!irNum.imin.negative) - irNum.imin.value = 0; - else if (irNum.imin < irDen.imin) - irNum.imin = irDen.imin; - - if (irNum.imax.negative) - { - irNum.imax.negative = false; - irNum.imax.value = 0; - } - else if (irNum.imax > irDen.imax) - irNum.imax = irDen.imax; - - return irNum.cast(type) DUMP; -} - -// The algorithms for &, |, ^ are not yet the best! Sometimes they will produce -// not the tightest bound. See -// https://github.com/D-Programming-Language/dmd/pull/116 -// for detail. -static IntRange unsignedBitwiseAnd(const IntRange& a, const IntRange& b) -{ - // the DiffMasks stores the mask of bits which are variable in the range. - uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value); - uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value); - // Since '&' computes the digitwise-minimum, the we could set all varying - // digits to 0 to get a lower bound, and set all varying digits to 1 to get - // an upper bound. - IntRange result; - result.imin.value = (a.imin.value & ~aDiffMask) & (b.imin.value & ~bDiffMask); - result.imax.value = (a.imax.value | aDiffMask) & (b.imax.value | bDiffMask); - // Sometimes the upper bound is overestimated. The upper bound will never - // exceed the input. - if (result.imax.value > a.imax.value) - result.imax.value = a.imax.value; - if (result.imax.value > b.imax.value) - result.imax.value = b.imax.value; - result.imin.negative = result.imax.negative = a.imin.negative && b.imin.negative; - return result; -} -static IntRange unsignedBitwiseOr(const IntRange& a, const IntRange& b) -{ - // the DiffMasks stores the mask of bits which are variable in the range. - uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value); - uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value); - // The imax algorithm by Adam D. Ruppe. - // http://www.digitalmars.com/pnews/read.php?server=news.digitalmars.com&group=digitalmars.D&artnum=108796 - IntRange result; - result.imin.value = (a.imin.value & ~aDiffMask) | (b.imin.value & ~bDiffMask); - result.imax.value = a.imax.value | b.imax.value | getMask(a.imax.value & b.imax.value); - // Sometimes the lower bound is underestimated. The lower bound will never - // less than the input. - if (result.imin.value < a.imin.value) - result.imin.value = a.imin.value; - if (result.imin.value < b.imin.value) - result.imin.value = b.imin.value; - result.imin.negative = result.imax.negative = a.imin.negative || b.imin.negative; - return result; -} -static IntRange unsignedBitwiseXor(const IntRange& a, const IntRange& b) -{ - // the DiffMasks stores the mask of bits which are variable in the range. - uinteger_t aDiffMask = getMask(a.imin.value ^ a.imax.value); - uinteger_t bDiffMask = getMask(b.imin.value ^ b.imax.value); - IntRange result; - result.imin.value = (a.imin.value ^ b.imin.value) & ~(aDiffMask | bDiffMask); - result.imax.value = (a.imax.value ^ b.imax.value) | (aDiffMask | bDiffMask); - result.imin.negative = result.imax.negative = a.imin.negative != b.imin.negative; - return result; -} - - -IntRange AndExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - IntRange ir1neg, ir1pos, ir2neg, ir2pos; - bool has1neg, has1pos, has2neg, has2pos; - - ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos); - ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos); - - IntRange result; - bool hasResult = false; - if (has1pos && has2pos) - result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2pos), /*ref*/hasResult); - if (has1pos && has2neg) - result.unionOrAssign(unsignedBitwiseAnd(ir1pos, ir2neg), /*ref*/hasResult); - if (has1neg && has2pos) - result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2pos), /*ref*/hasResult); - if (has1neg && has2neg) - result.unionOrAssign(unsignedBitwiseAnd(ir1neg, ir2neg), /*ref*/hasResult); - assert(hasResult); - return result.cast(type) DUMP; -} - -IntRange OrExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - IntRange ir1neg, ir1pos, ir2neg, ir2pos; - bool has1neg, has1pos, has2neg, has2pos; - - ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos); - ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos); - - IntRange result; - bool hasResult = false; - if (has1pos && has2pos) - result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2pos), /*ref*/hasResult); - if (has1pos && has2neg) - result.unionOrAssign(unsignedBitwiseOr(ir1pos, ir2neg), /*ref*/hasResult); - if (has1neg && has2pos) - result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2pos), /*ref*/hasResult); - if (has1neg && has2neg) - result.unionOrAssign(unsignedBitwiseOr(ir1neg, ir2neg), /*ref*/hasResult); - - assert(hasResult); - return result.cast(type) DUMP; -} - -IntRange XorExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - IntRange ir1neg, ir1pos, ir2neg, ir2pos; - bool has1neg, has1pos, has2neg, has2pos; - - ir1.splitBySign(ir1neg, has1neg, ir1pos, has1pos); - ir2.splitBySign(ir2neg, has2neg, ir2pos, has2pos); - - IntRange result; - bool hasResult = false; - if (has1pos && has2pos) - result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2pos), /*ref*/hasResult); - if (has1pos && has2neg) - result.unionOrAssign(unsignedBitwiseXor(ir1pos, ir2neg), /*ref*/hasResult); - if (has1neg && has2pos) - result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2pos), /*ref*/hasResult); - if (has1neg && has2neg) - result.unionOrAssign(unsignedBitwiseXor(ir1neg, ir2neg), /*ref*/hasResult); - - assert(hasResult); - return result.cast(type) DUMP; -} - -IntRange ShlExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - if (ir2.imin.negative) - ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); - - SignExtendedNumber lower = ir1.imin << (ir1.imin.negative ? ir2.imax : ir2.imin); - SignExtendedNumber upper = ir1.imax << (ir1.imax.negative ? ir2.imin : ir2.imax); - - return IntRange(lower, upper).cast(type) DUMP; -} - -IntRange ShrExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange(); - IntRange ir2 = e2->getIntRange(); - - if (ir2.imin.negative) - ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); - - SignExtendedNumber lower = ir1.imin >> (ir1.imin.negative ? ir2.imin : ir2.imax); - SignExtendedNumber upper = ir1.imax >> (ir1.imax.negative ? ir2.imax : ir2.imin); - - return IntRange(lower, upper).cast(type) DUMP; -} - -IntRange UshrExp::getIntRange() -{ - IntRange ir1 = e1->getIntRange().castUnsigned(e1->type); - IntRange ir2 = e2->getIntRange(); - - if (ir2.imin.negative) - ir2 = IntRange(SignExtendedNumber(0), SignExtendedNumber(64)); - - return IntRange(ir1.imin >> ir2.imax, ir1.imax >> ir2.imin).cast(type) DUMP; - -} - -IntRange CommaExp::getIntRange() -{ - return e2->getIntRange() DUMP; -} - -IntRange ComExp::getIntRange() -{ - IntRange ir = e1->getIntRange(); - return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), - SignExtendedNumber(~ir.imin.value, !ir.imin.negative)).cast(type) DUMP; -} - -IntRange NegExp::getIntRange() -{ - IntRange ir = e1->getIntRange(); - return IntRange(-ir.imax, -ir.imin).cast(type) DUMP; -} - diff --git a/dmd2/class.c b/dmd2/class.c deleted file mode 100644 index 238f89f8..00000000 --- a/dmd2/class.c +++ /dev/null @@ -1,1656 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "root.h" -#include "rmem.h" - -#include "enum.h" -#include "init.h" -#include "attrib.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "mtype.h" -#include "scope.h" -#include "module.h" -#include "expression.h" -#include "statement.h" - -/********************************* ClassDeclaration ****************************/ - -ClassDeclaration *ClassDeclaration::classinfo; -ClassDeclaration *ClassDeclaration::object; -ClassDeclaration *ClassDeclaration::throwable; -ClassDeclaration *ClassDeclaration::exception; -ClassDeclaration *ClassDeclaration::errorException; - -ClassDeclaration::ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : AggregateDeclaration(loc, id) -{ - static char msg[] = "only object.d can define this reserved class name"; - - if (baseclasses) - // Actually, this is a transfer - this->baseclasses = baseclasses; - else - this->baseclasses = new BaseClasses(); - baseClass = NULL; - - interfaces_dim = 0; - interfaces = NULL; - - vtblInterfaces = NULL; - - //printf("ClassDeclaration(%s), dim = %d\n", id->toChars(), this->baseclasses->dim); - - // For forward references - type = new TypeClass(this); - handle = type; - - staticCtor = NULL; - staticDtor = NULL; - -#if IN_DMD - vtblsym = NULL; -#endif - vclassinfo = NULL; - - if (id) - { // Look for special class names - - if (id == Id::__sizeof || id == Id::__xalignof || id == Id::mangleof) - error("illegal class name"); - - // BUG: What if this is the wrong TypeInfo, i.e. it is nested? - if (id->toChars()[0] == 'T') - { - if (id == Id::TypeInfo) - { if (Type::typeinfo) - Type::typeinfo->error("%s", msg); - Type::typeinfo = this; - } - - if (id == Id::TypeInfo_Class) - { if (Type::typeinfoclass) - Type::typeinfoclass->error("%s", msg); - Type::typeinfoclass = this; - } - - if (id == Id::TypeInfo_Interface) - { if (Type::typeinfointerface) - Type::typeinfointerface->error("%s", msg); - Type::typeinfointerface = this; - } - - if (id == Id::TypeInfo_Struct) - { if (Type::typeinfostruct) - Type::typeinfostruct->error("%s", msg); - Type::typeinfostruct = this; - } - - if (id == Id::TypeInfo_Typedef) - { if (Type::typeinfotypedef) - Type::typeinfotypedef->error("%s", msg); - Type::typeinfotypedef = this; - } - - if (id == Id::TypeInfo_Pointer) - { if (Type::typeinfopointer) - Type::typeinfopointer->error("%s", msg); - Type::typeinfopointer = this; - } - - if (id == Id::TypeInfo_Array) - { if (Type::typeinfoarray) - Type::typeinfoarray->error("%s", msg); - Type::typeinfoarray = this; - } - - if (id == Id::TypeInfo_StaticArray) - { //if (Type::typeinfostaticarray) - //Type::typeinfostaticarray->error("%s", msg); - Type::typeinfostaticarray = this; - } - - if (id == Id::TypeInfo_AssociativeArray) - { if (Type::typeinfoassociativearray) - Type::typeinfoassociativearray->error("%s", msg); - Type::typeinfoassociativearray = this; - } - - if (id == Id::TypeInfo_Enum) - { if (Type::typeinfoenum) - Type::typeinfoenum->error("%s", msg); - Type::typeinfoenum = this; - } - - if (id == Id::TypeInfo_Function) - { if (Type::typeinfofunction) - Type::typeinfofunction->error("%s", msg); - Type::typeinfofunction = this; - } - - if (id == Id::TypeInfo_Delegate) - { if (Type::typeinfodelegate) - Type::typeinfodelegate->error("%s", msg); - Type::typeinfodelegate = this; - } - - if (id == Id::TypeInfo_Tuple) - { if (Type::typeinfotypelist) - Type::typeinfotypelist->error("%s", msg); - Type::typeinfotypelist = this; - } - -#if DMDV2 - if (id == Id::TypeInfo_Const) - { if (Type::typeinfoconst) - Type::typeinfoconst->error("%s", msg); - Type::typeinfoconst = this; - } - - if (id == Id::TypeInfo_Invariant) - { if (Type::typeinfoinvariant) - Type::typeinfoinvariant->error("%s", msg); - Type::typeinfoinvariant = this; - } - - if (id == Id::TypeInfo_Shared) - { if (Type::typeinfoshared) - Type::typeinfoshared->error("%s", msg); - Type::typeinfoshared = this; - } - - if (id == Id::TypeInfo_Wild) - { if (Type::typeinfowild) - Type::typeinfowild->error("%s", msg); - Type::typeinfowild = this; - } -#endif - } - - if (id == Id::Object) - { if (object) - object->error("%s", msg); - object = this; - } - - if (id == Id::Throwable) - { if (throwable) - throwable->error("%s", msg); - throwable = this; - } - - if (id == Id::Exception) - { if (exception) - exception->error("%s", msg); - exception = this; - } - - if (id == Id::Error) - { if (errorException) - errorException->error("%s", msg); - errorException = this; - } - - //if (id == Id::ClassInfo) - if (id == Id::TypeInfo_Class) - { if (classinfo) - classinfo->error("%s", msg); - classinfo = this; - } - -#if !MODULEINFO_IS_STRUCT - if (id == Id::ModuleInfo) - { if (Module::moduleinfo) - Module::moduleinfo->error("%s", msg); - Module::moduleinfo = this; - } -#endif - } - - com = 0; - isscope = 0; - isabstract = 0; - inuse = 0; -} - -Dsymbol *ClassDeclaration::syntaxCopy(Dsymbol *s) -{ - ClassDeclaration *cd; - - //printf("ClassDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - cd = (ClassDeclaration *)s; - else - cd = new ClassDeclaration(loc, ident, NULL); - - cd->storage_class |= storage_class; - - cd->baseclasses->setDim(this->baseclasses->dim); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { - BaseClass *b = this->baseclasses->tdata()[i]; - BaseClass *b2 = new BaseClass(b->type->syntaxCopy(), b->protection); - cd->baseclasses->tdata()[i] = b2; - } - - ScopeDsymbol::syntaxCopy(cd); - return cd; -} - -void ClassDeclaration::semantic(Scope *sc) -{ - //printf("ClassDeclaration::semantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - //printf("\tparent = %p, '%s'\n", sc->parent, sc->parent ? sc->parent->toChars() : ""); - //printf("sc->stc = %x\n", sc->stc); - - //{ static int n; if (++n == 20) *(char*)0=0; } - - if (!ident) // if anonymous class - { const char *id = "__anonclass"; - - ident = Identifier::generateId(id); - } - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tclass '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) - { if (sizeok == 1 || !scope) - { //printf("\tsemantic for '%s' is already completed\n", toChars()); - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - unsigned dprogress_save = Module::dprogress; -#ifdef IN_GCC - methods.setDim(0); -#endif - - int errors = global.gaggedErrors; - - if (sc->stc & STCdeprecated) - { - isdeprecated = true; - } - - if (sc->linkage == LINKcpp) - error("cannot create C++ classes"); - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = baseclasses->tdata()[i]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses->remove(i); - size_t dim = Parameter::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *arg = Parameter::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses->insert(i + j, b); - } - } - else - i++; - } - - // See if there's a base class as first in baseclasses[] - if (baseclasses->dim) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = baseclasses->tdata()[0]; - //b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty != Tclass) - { error("base type must be class or interface, not %s", b->type->toChars()); - baseclasses->remove(0); - } - else - { - tc = (TypeClass *)(tb); - - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = true; - - tc->checkDeprecated(loc, sc); - } - } - - if (tc->sym->isInterfaceDeclaration()) - ; - else - { - for (ClassDeclaration *cdb = tc->sym; cdb; cdb = cdb->baseClass) - { - if (cdb == this) - { - error("circular inheritance"); - baseclasses->remove(0); - goto L7; - } - } - if (!tc->sym->symtab || tc->sym->sizeok == 0) - { // Try to resolve forward reference - if (/*sc->mustsemantic &&*/ tc->sym->scope) - tc->sym->semantic(NULL); - } - if (!tc->sym->symtab || tc->sym->scope || tc->sym->sizeok == 0) - { - //printf("%s: forward reference of base class %s\n", toChars(), tc->sym->toChars()); - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base class, try again later - //printf("\ttry later, forward reference of base class %s\n", tc->sym->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - else - { baseClass = tc->sym; - b->base = baseClass; - } - L7: ; - } - } - } - - // Treat the remaining entries in baseclasses as interfaces - // Check for errors, handle forward references - for (size_t i = (baseClass ? 1 : 0); i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = baseclasses->tdata()[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses->remove(i); - continue; - } - else - { - if (tc->sym->isDeprecated()) - { - if (!isDeprecated()) - { - // Deriving from deprecated class makes this one deprecated too - isdeprecated = true; - - tc->checkDeprecated(loc, sc); - } - } - - // Check for duplicate interfaces - for (size_t j = (baseClass ? 1 : 0); j < i; j++) - { - BaseClass *b2 = baseclasses->tdata()[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - if (!tc->sym->symtab) - { // Try to resolve forward reference - if (/*sc->mustsemantic &&*/ tc->sym->scope) - tc->sym->semantic(NULL); - } - - b->base = tc->sym; - if (!b->base->symtab || b->base->scope) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", baseClass->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - if (tc->sym->scope) - tc->sym->scope->module->addDeferredSemantic(tc->sym); - scope->module->addDeferredSemantic(this); - return; - } - } - i++; - } - - - // If no base class, and this is not an Object, use Object as base class - if (!baseClass && ident != Id::Object) - { - // BUG: what if Object is redefined in an inner scope? - Type *tbase = new TypeIdentifier(0, Id::Object); - BaseClass *b; - TypeClass *tc; - Type *bt; - - if (!object) - { - error("missing or corrupt object.d"); - fatal(); - } - bt = tbase->semantic(loc, sc)->toBasetype(); - b = new BaseClass(bt, PROTpublic); - baseclasses->shift(b); - assert(b->type->ty == Tclass); - tc = (TypeClass *)(b->type); - baseClass = tc->sym; - assert(!baseClass->isInterfaceDeclaration()); - b->base = baseClass; - } - - interfaces_dim = baseclasses->dim; - interfaces = baseclasses->tdata(); - - - if (baseClass) - { - if (baseClass->storage_class & STCfinal) - error("cannot inherit from final class %s", baseClass->toChars()); - - interfaces_dim--; - interfaces++; - - // Copy vtbl[] from base class - vtbl.setDim(baseClass->vtbl.dim); - memcpy(vtbl.tdata(), baseClass->vtbl.tdata(), sizeof(void *) * vtbl.dim); - - // Inherit properties from base class - com = baseClass->isCOMclass(); - isscope = baseClass->isscope; - vthis = baseClass->vthis; - storage_class |= baseClass->storage_class & STC_TYPECTOR; - } - else - { - // No base class, so this is the root of the class hierarchy - vtbl.setDim(0); - vtbl.push(this); // leave room for classinfo as first member - } - - protection = sc->protection; - storage_class |= sc->stc; - - if (sizeok == 0) - { - interfaceSemantic(sc); - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->addMember(sc, this, 1); - } - - /* If this is a nested class, add the hidden 'this' - * member which is a pointer to the enclosing scope. - */ - if (vthis) // if inheriting from nested class - { // Use the base class's 'this' member - isnested = 1; - if (storage_class & STCstatic) - error("static class cannot inherit from nested class %s", baseClass->toChars()); - if (toParent2() != baseClass->toParent2()) - { - if (toParent2()) - { - error("is nested within %s, but super class %s is nested within %s", - toParent2()->toChars(), - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - else - { - error("is not nested, but super class %s is nested within %s", - baseClass->toChars(), - baseClass->toParent2()->toChars()); - } - isnested = 0; - } - } - else if (!(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - AggregateDeclaration *ad = s->isClassDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - - if (ad || fd) - { isnested = 1; - Type *t; - if (ad) - t = ad->handle; - else if (fd) - { AggregateDeclaration *ad2 = fd->isMember2(); - if (ad2) - t = ad2->handle; - else - { - t = Type::tvoidptr; - } - } - else - assert(0); - if (t->ty == Tstruct) // ref to struct - t = Type::tvoidptr; - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - members->push(vthis); - } - } - } - } - - if (storage_class & STCauto) - error("storage class 'auto' is invalid when declaring a class, did you mean to use 'scope'?"); - if (storage_class & STCscope) - isscope = 1; - if (storage_class & STCabstract) - isabstract = 1; - - if (storage_class & STCimmutable) - type = type->addMod(MODimmutable); - if (storage_class & STCconst) - type = type->addMod(MODconst); - if (storage_class & STCshared) - type = type->addMod(MODshared); - - sc = sc->push(this); - //sc->stc &= ~(STCfinal | STCauto | STCscope | STCstatic | STCabstract | STCdeprecated | STC_TYPECTOR | STCtls | STCgshared); - //sc->stc |= storage_class & STC_TYPECTOR; - sc->stc &= STCsafe | STCtrusted | STCsystem; - sc->parent = this; - sc->inunion = 0; - - if (isCOMclass()) - { -#if _WIN32 - sc->linkage = LINKwindows; -#else - /* This enables us to use COM objects under Linux and - * work with things like XPCOM - */ - sc->linkage = LINKc; -#endif - } - sc->protection = PROTpublic; - sc->explicitProtection = 0; - sc->structalign = 8; - structalign = sc->structalign; - if (baseClass) - { sc->offset = baseClass->structsize; - alignsize = baseClass->alignsize; -// if (isnested) -// sc->offset += PTRSIZE; // room for uplevel context pointer - } - else - { sc->offset = PTRSIZE * 2; // allow room for __vptr and __monitor - alignsize = PTRSIZE; - } - structsize = sc->offset; - Scope scsave = *sc; - size_t members_dim = members->dim; - sizeok = 0; - - /* Set scope so if there are forward references, we still might be able to - * resolve individual members like enums. - */ - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = members->tdata()[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) - { - //printf("setScope %s %s\n", s->kind(), s->toChars()); - s->setScope(sc); - } - } - - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = members->tdata()[i]; - s->semantic(sc); - } - - if (global.gag && global.gaggedErrors != errors) - { // The type is no good, yet the error messages were gagged. - type = Type::terror; - } - - if (sizeok == 2) // failed due to forward references - { // semantic() failed due to forward references - // Unwind what we did, and defer it for later - - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - sc = sc->pop(); - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - Module::dprogress = dprogress_save; - - //printf("\tsemantic('%s') failed due to forward references\n", toChars()); - return; - } - - //printf("\tsemantic('%s') successful\n", toChars()); - - structsize = sc->offset; - //members->print(); - - /* Look for special member functions. - * They must be in this class, not in a base class. - */ - ctor = (CtorDeclaration *)search(0, Id::ctor, 0); - if (ctor && (ctor->toParent() != this || !ctor->isCtorDeclaration())) - ctor = NULL; - -// dtor = (DtorDeclaration *)search(Id::dtor, 0); -// if (dtor && dtor->toParent() != this) -// dtor = NULL; - -// inv = (InvariantDeclaration *)search(Id::classInvariant, 0); -// if (inv && inv->toParent() != this) -// inv = NULL; - - // Can be in base class - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - // If this class has no constructor, but base class does, create - // a constructor: - // this() { } - if (!ctor && baseClass && baseClass->ctor) - { - //printf("Creating default this(){} for class %s\n", toChars()); - Type *tf = new TypeFunction(NULL, NULL, 0, LINKd, 0); - CtorDeclaration *ctor = new CtorDeclaration(loc, 0, 0, tf); - ctor->fbody = new CompoundStatement(0, new Statements()); - members->push(ctor); - ctor->addMember(sc, this, 1); - *sc = scsave; // why? What about sc->nofree? - sc->offset = structsize; - ctor->semantic(sc); - this->ctor = ctor; - defaultCtor = ctor; - } - -#if 0 - if (baseClass) - { if (!aggDelete) - aggDelete = baseClass->aggDelete; - if (!aggNew) - aggNew = baseClass->aggNew; - } -#endif - - // Allocate instance of each new interface - for (size_t i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = vtblInterfaces->tdata()[i]; - unsigned thissize = PTRSIZE; - - alignmember(structalign, thissize, &sc->offset); - assert(b->offset == 0); - b->offset = sc->offset; - - // Take care of single inheritance offsets - while (b->baseInterfaces_dim) - { - b = &b->baseInterfaces[0]; - b->offset = sc->offset; - } - - sc->offset += thissize; - if (alignsize < thissize) - alignsize = thissize; - } - structsize = sc->offset; -#if IN_LLVM - if (global.params.is64bit) - structsize = (structsize + structalign - 1) & ~(structalign - 1); -#endif - sizeok = 1; - Module::dprogress++; - - dtor = buildDtor(sc); - - sc->pop(); - -#if 0 // Do not call until toObjfile() because of forward references - // Fill in base class vtbl[]s - for (i = 0; i < vtblInterfaces->dim; i++) - { - BaseClass *b = vtblInterfaces->tdata()[i]; - - //b->fillVtbl(this, &b->vtbl, 1); - } -#endif - //printf("-ClassDeclaration::semantic(%s), type = %p\n", toChars(), type); - - if (deferred && !global.gag) - { - deferred->semantic2(sc); - deferred->semantic3(sc); - } -} - -void ClassDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!isAnonymous()) - { - buf->printf("%s ", kind()); - buf->writestring(toChars()); - if (baseclasses->dim) - buf->writestring(" : "); - } - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = baseclasses->tdata()[i]; - - if (i) - buf->writeByte(','); - //buf->writestring(b->base->ident->toChars()); - b->type->toCBuffer(buf, NULL, hgs); - } - if (members) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writestring("}"); - } - else - buf->writeByte(';'); - buf->writenl(); -} - -#if 0 -void ClassDeclaration::defineRef(Dsymbol *s) -{ - ClassDeclaration *cd; - - AggregateDeclaration::defineRef(s); - cd = s->isClassDeclaration(); - baseType = cd->baseType; - cd->baseType = NULL; -} -#endif - -/********************************************* - * Determine if 'this' is a base class of cd. - * This is used to detect circular inheritance only. - */ - -int ClassDeclaration::isBaseOf2(ClassDeclaration *cd) -{ - if (!cd) - return 0; - //printf("ClassDeclaration::isBaseOf2(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; - - if (b->base == this || isBaseOf2(b->base)) - return 1; - } - return 0; -} - -/******************************************* - * Determine if 'this' is a base class of cd. - */ - -int ClassDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - //printf("ClassDeclaration::isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd->toChars()); - if (poffset) - *poffset = 0; - while (cd) - { - /* cd->baseClass might not be set if cd is forward referenced. - */ - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) - { - cd->semantic(NULL); - if (!cd->baseClass) - cd->error("base class is forward referenced by %s", toChars()); - } - - if (this == cd->baseClass) - return 1; - - cd = cd->baseClass; - } - return 0; -} - -/********************************************* - * Determine if 'this' has complete base class information. - * This is used to detect forward references in covariant overloads. - */ - -int ClassDeclaration::isBaseInfoComplete() -{ - if (!baseClass) - return ident == Id::Object; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; - if (!b->base || !b->base->isBaseInfoComplete()) - return 0; - } - return 1; -} - -Dsymbol *ClassDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - Dsymbol *s; - //printf("%s.ClassDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope && !symtab) - { Scope *sc = scope; - sc->mustsemantic++; - semantic(sc); - sc->mustsemantic--; - } - - if (!members || !symtab) - { - error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - s = ScopeDsymbol::search(loc, ident, flags); - if (!s) - { - // Search bases classes in depth-first, left to right order - - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = baseclasses->tdata()[i]; - - if (b->base) - { - if (!b->base->symtab) - error("base %s is forward referenced", b->base->ident->toChars()); - else - { - s = b->base->search(loc, ident, flags); - if (s == this) // happens if s is nested in this and derives from this - s = NULL; - else if (s) - break; - } - } - } - } - return s; -} - -Dsymbol *ClassDeclaration::searchBase(Loc loc, Identifier *ident) -{ - // Search bases classes in depth-first, left to right order - - for (size_t i = 0; i < baseclasses->dim; i++) - { - BaseClass *b = (*baseclasses)[i]; - Dsymbol *cdb = b->type->isClassHandle(); - if (cdb->ident->equals(ident)) - return cdb; - cdb = ((ClassDeclaration *)cdb)->searchBase(loc, ident); - if (cdb) - return cdb; - } - return NULL; -} - -/********************************************************** - * fd is in the vtbl[] for this class. - * Return 1 if function is hidden (not findable through search). - */ - -#if DMDV2 -int isf(void *param, FuncDeclaration *fd) -{ - //printf("param = %p, fd = %p %s\n", param, fd, fd->toChars()); - return param == fd; -} - -int ClassDeclaration::isFuncHidden(FuncDeclaration *fd) -{ - //printf("ClassDeclaration::isFuncHidden(class = %s, fd = %s)\n", toChars(), fd->toChars()); - Dsymbol *s = search(0, fd->ident, 4|2); - if (!s) - { //printf("not found\n"); - /* Because, due to a hack, if there are multiple definitions - * of fd->ident, NULL is returned. - */ - return 0; - } - s = s->toAlias(); - OverloadSet *os = s->isOverloadSet(); - if (os) - { - for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; - FuncDeclaration *f2 = s2->isFuncDeclaration(); - if (f2 && overloadApply(f2, &isf, fd)) - return 0; - } - return 1; - } - else - { - FuncDeclaration *fdstart = s->isFuncDeclaration(); - //printf("%s fdstart = %p\n", s->kind(), fdstart); - if (overloadApply(fdstart, &isf, fd)) - return 0; - - return !fd->parent->isTemplateMixin(); - } -} -#endif - -/**************** - * Find virtual function matching identifier and type. - * Used to build virtual function tables for interface implementations. - */ - -FuncDeclaration *ClassDeclaration::findFunc(Identifier *ident, TypeFunction *tf) -{ - //printf("ClassDeclaration::findFunc(%s, %s) %s\n", ident->toChars(), tf->toChars(), toChars()); - FuncDeclaration *fdmatch = NULL; - FuncDeclaration *fdambig = NULL; - - ClassDeclaration *cd = this; - Dsymbols *vtbl = &cd->vtbl; - while (1) - { - for (size_t i = 0; i < vtbl->dim; i++) - { - FuncDeclaration *fd = vtbl->tdata()[i]->isFuncDeclaration(); - if (!fd) - continue; // the first entry might be a ClassInfo - - //printf("\t[%d] = %s\n", i, fd->toChars()); - if (ident == fd->ident && - fd->type->covariant(tf) == 1) - { //printf("fd->parent->isClassDeclaration() = %p", fd->parent->isClassDeclaration()); - if (!fdmatch) - goto Lfd; - - { - // Function type matcing: exact > covariant - int m1 = tf->equals(fd ->type) ? MATCHexact : MATCHnomatch; - int m2 = tf->equals(fdmatch->type) ? MATCHexact : MATCHnomatch; - if (m1 > m2) - goto Lfd; - else if (m1 < m2) - goto Lfdmatch; - } - - { - // The way of definition: non-mixin > mixin - int m1 = fd ->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; - int m2 = fdmatch->parent->isClassDeclaration() ? MATCHexact : MATCHnomatch; - if (m1 > m2) - goto Lfd; - else if (m1 < m2) - goto Lfdmatch; - } - - Lambig: - fdambig = fd; - //printf("Lambig fdambig = %s %s [%s]\n", fdambig->toChars(), fdambig->type->toChars(), fdambig->loc.toChars()); - continue; - - Lfd: - fdmatch = fd, fdambig = NULL; - //printf("Lfd fdmatch = %s %s [%s]\n", fdmatch->toChars(), fdmatch->type->toChars(), fdmatch->loc.toChars()); - continue; - - Lfdmatch: - continue; - } - //else printf("\t\t%d\n", fd->type->covariant(tf)); - } - if (!cd) - break; - vtbl = &cd->vtblFinal; - cd = cd->baseClass; - } - - if (fdambig) - error("ambiguous virtual function %s", fdambig->toChars()); - return fdmatch; -} - -void ClassDeclaration::interfaceSemantic(Scope *sc) -{ - InterfaceDeclaration *id = isInterfaceDeclaration(); - - vtblInterfaces = new BaseClasses(); - vtblInterfaces->reserve(interfaces_dim); - - for (size_t i = 0; i < interfaces_dim; i++) - { - BaseClass *b = interfaces[i]; - - // If this is an interface, and it derives from a COM interface, - // then this is a COM interface too. - if (b->base->isCOMinterface()) - com = 1; - - if (b->base->isCPPinterface() && id) - id->cpp = 1; - - vtblInterfaces->push(b); - b->copyBaseInterfaces(vtblInterfaces); - } -} - -/**************************************** - */ - -int ClassDeclaration::isCOMclass() -{ - return com; -} - -int ClassDeclaration::isCOMinterface() -{ - return 0; -} - -#if DMDV2 -int ClassDeclaration::isCPPinterface() -{ - return 0; -} -#endif - - -/**************************************** - */ - -int ClassDeclaration::isAbstract() -{ - if (isabstract) - return TRUE; - for (size_t i = 1; i < vtbl.dim; i++) - { - FuncDeclaration *fd = vtbl.tdata()[i]->isFuncDeclaration(); - - //printf("\tvtbl[%d] = %p\n", i, fd); - if (!fd || fd->isAbstract()) - { - isabstract |= 1; - return TRUE; - } - } - return FALSE; -} - - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the classinfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int ClassDeclaration::vtblOffset() -{ - return 1; -} - -/**************************************** - */ - -const char *ClassDeclaration::kind() -{ - return "class"; -} - -/**************************************** - */ - -void ClassDeclaration::addLocalClass(ClassDeclarations *aclasses) -{ - aclasses->push(this); -} - -/********************************* InterfaceDeclaration ****************************/ - -InterfaceDeclaration::InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses) - : ClassDeclaration(loc, id, baseclasses) -{ - com = 0; - cpp = 0; - if (id == Id::IUnknown) // IUnknown is the root of all COM interfaces - { com = 1; - cpp = 1; // IUnknown is also a C++ interface - } -} - -Dsymbol *InterfaceDeclaration::syntaxCopy(Dsymbol *s) -{ - InterfaceDeclaration *id; - - if (s) - id = (InterfaceDeclaration *)s; - else - id = new InterfaceDeclaration(loc, ident, NULL); - - ClassDeclaration::syntaxCopy(id); - return id; -} - -void InterfaceDeclaration::semantic(Scope *sc) -{ - //printf("InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); - if (inuse) - return; - - if (!sc) - sc = scope; - if (!parent && sc->parent && !sc->parent->isModule()) - parent = sc->parent; - - type = type->semantic(loc, sc); - handle = type; - - if (!members) // if forward reference - { //printf("\tinterface '%s' is forward referenced\n", toChars()); - return; - } - if (symtab) // if already done - { if (!scope) - return; - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - int errors = global.gaggedErrors; - - if (sc->stc & STCdeprecated) - { - isdeprecated = true; - } - - // Expand any tuples in baseclasses[] - for (size_t i = 0; i < baseclasses->dim; ) - { BaseClass *b = baseclasses->tdata()[0]; - b->type = b->type->semantic(loc, sc); - Type *tb = b->type->toBasetype(); - - if (tb->ty == Ttuple) - { TypeTuple *tup = (TypeTuple *)tb; - enum PROT protection = b->protection; - baseclasses->remove(i); - size_t dim = Parameter::dim(tup->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *arg = Parameter::getNth(tup->arguments, j); - b = new BaseClass(arg->type, protection); - baseclasses->insert(i + j, b); - } - } - else - i++; - } - - if (!baseclasses->dim && sc->linkage == LINKcpp) - cpp = 1; - - // Check for errors, handle forward references - for (size_t i = 0; i < baseclasses->dim; ) - { TypeClass *tc; - BaseClass *b; - Type *tb; - - b = baseclasses->tdata()[i]; - b->type = b->type->semantic(loc, sc); - tb = b->type->toBasetype(); - if (tb->ty == Tclass) - tc = (TypeClass *)tb; - else - tc = NULL; - if (!tc || !tc->sym->isInterfaceDeclaration()) - { - error("base type must be interface, not %s", b->type->toChars()); - baseclasses->remove(i); - continue; - } - else - { - // Check for duplicate interfaces - for (size_t j = 0; j < i; j++) - { - BaseClass *b2 = baseclasses->tdata()[j]; - if (b2->base == tc->sym) - error("inherits from duplicate interface %s", b2->base->toChars()); - } - - b->base = tc->sym; - if (b->base == this || isBaseOf2(b->base)) - { - error("circular inheritance of interface"); - baseclasses->remove(i); - continue; - } - if (!b->base->symtab) - { // Try to resolve forward reference - if (sc->mustsemantic && b->base->scope) - b->base->semantic(NULL); - } - if (!b->base->symtab || b->base->scope || b->base->inuse) - { - //error("forward reference of base class %s", baseClass->toChars()); - // Forward reference of base, try again later - //printf("\ttry later, forward reference of base %s\n", b->base->toChars()); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - return; - } - } -#if 0 - // Inherit const/invariant from base class - storage_class |= b->base->storage_class & STC_TYPECTOR; -#endif - i++; - } - - interfaces_dim = baseclasses->dim; - interfaces = baseclasses->tdata(); - - interfaceSemantic(sc); - - if (vtblOffset()) - vtbl.push(this); // leave room at vtbl[0] for classinfo - - // Cat together the vtbl[]'s from base interfaces - for (size_t i = 0; i < interfaces_dim; i++) - { BaseClass *b = interfaces[i]; - - // Skip if b has already appeared - for (int k = 0; k < i; k++) - { - if (b == interfaces[k]) - goto Lcontinue; - } - - // Copy vtbl[] from base class - if (b->base->vtblOffset()) - { int d = b->base->vtbl.dim; - if (d > 1) - { - vtbl.reserve(d - 1); - for (int j = 1; j < d; j++) - vtbl.push(b->base->vtbl.tdata()[j]); - } - } - else - { - vtbl.append(&b->base->vtbl); - } - - Lcontinue: - ; - } - - protection = sc->protection; - storage_class |= sc->stc & STC_TYPECTOR; - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->addMember(sc, this, 1); - } - - sc = sc->push(this); - sc->stc &= STCsafe | STCtrusted | STCsystem; - sc->parent = this; - if (isCOMinterface()) - sc->linkage = LINKwindows; - else if (isCPPinterface()) - sc->linkage = LINKcpp; - sc->structalign = 8; - sc->protection = PROTpublic; - sc->explicitProtection = 0; - structalign = sc->structalign; - sc->offset = PTRSIZE * 2; - inuse++; - - /* Set scope so if there are forward references, we still might be able to - * resolve individual members like enums. - */ - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) - { - //printf("setScope %s %s\n", s->kind(), s->toChars()); - s->setScope(sc); - } - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic(sc); - } - - if (global.gag && global.gaggedErrors != errors) - { // The type is no good, yet the error messages were gagged. - type = Type::terror; - } - - inuse--; - //members->print(); - sc->pop(); - //printf("-InterfaceDeclaration::semantic(%s), type = %p\n", toChars(), type); -} - - -/******************************************* - * Determine if 'this' is a base class of cd. - * (Actually, if it is an interface supported by cd) - * Output: - * *poffset offset to start of class - * OFFSET_RUNTIME must determine offset at runtime - * Returns: - * 0 not a base - * 1 is a base - */ - -int InterfaceDeclaration::isBaseOf(ClassDeclaration *cd, int *poffset) -{ - unsigned j; - - //printf("%s.InterfaceDeclaration::isBaseOf(cd = '%s')\n", toChars(), cd->toChars()); - assert(!baseClass); - for (j = 0; j < cd->interfaces_dim; j++) - { - BaseClass *b = cd->interfaces[j]; - - //printf("\tbase %s\n", b->base->toChars()); - if (this == b->base) - { - //printf("\tfound at offset %d\n", b->offset); - if (poffset) - { *poffset = b->offset; - if (j && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && cd->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - - if (cd->baseClass && isBaseOf(cd->baseClass, poffset)) - return 1; - - if (poffset) - *poffset = 0; - return 0; -} - - -int InterfaceDeclaration::isBaseOf(BaseClass *bc, int *poffset) -{ - //printf("%s.InterfaceDeclaration::isBaseOf(bc = '%s')\n", toChars(), bc->base->toChars()); - for (unsigned j = 0; j < bc->baseInterfaces_dim; j++) - { - BaseClass *b = &bc->baseInterfaces[j]; - - if (this == b->base) - { - if (poffset) - { *poffset = b->offset; - if (j && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - } - return 1; - } - if (isBaseOf(b, poffset)) - { if (j && poffset && bc->base->isInterfaceDeclaration()) - *poffset = OFFSET_RUNTIME; - return 1; - } - } - if (poffset) - *poffset = 0; - return 0; -} - -/********************************************* - * Determine if 'this' has clomplete base class information. - * This is used to detect forward references in covariant overloads. - */ - -int InterfaceDeclaration::isBaseInfoComplete() -{ - assert(!baseClass); - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *b = baseclasses->tdata()[i]; - if (!b->base || !b->base->isBaseInfoComplete ()) - return 0; - } - return 1; -} - -/**************************************** - * Determine if slot 0 of the vtbl[] is reserved for something else. - * For class objects, yes, this is where the ClassInfo ptr goes. - * For COM interfaces, no. - * For non-COM interfaces, yes, this is where the Interface ptr goes. - */ - -int InterfaceDeclaration::vtblOffset() -{ - if (isCOMinterface() || isCPPinterface()) - return 0; - return 1; -} - -int InterfaceDeclaration::isCOMinterface() -{ - return com; -} - -#if DMDV2 -int InterfaceDeclaration::isCPPinterface() -{ - return cpp; -} -#endif - -/******************************************* - */ - -const char *InterfaceDeclaration::kind() -{ - return "interface"; -} - - -/******************************** BaseClass *****************************/ - -BaseClass::BaseClass() -{ - memset(this, 0, sizeof(BaseClass)); -} - -BaseClass::BaseClass(Type *type, enum PROT protection) -{ - //printf("BaseClass(this = %p, '%s')\n", this, type->toChars()); - this->type = type; - this->protection = protection; - base = NULL; - offset = 0; - - baseInterfaces_dim = 0; - baseInterfaces = NULL; -} - -/**************************************** - * Fill in vtbl[] for base class based on member functions of class cd. - * Input: - * vtbl if !=NULL, fill it in - * newinstance !=0 means all entries must be filled in by members - * of cd, not members of any base classes of cd. - * Returns: - * !=0 if any entries were filled in by members of cd (not exclusively - * by base classes) - */ - -int BaseClass::fillVtbl(ClassDeclaration *cd, FuncDeclarations *vtbl, int newinstance) -{ - ClassDeclaration *id = base; - int result = 0; - - //printf("BaseClass::fillVtbl(this='%s', cd='%s')\n", base->toChars(), cd->toChars()); - if (vtbl) - vtbl->setDim(base->vtbl.dim); - - // first entry is ClassInfo reference - for (size_t j = base->vtblOffset(); j < base->vtbl.dim; j++) - { - FuncDeclaration *ifd = base->vtbl.tdata()[j]->isFuncDeclaration(); - FuncDeclaration *fd; - TypeFunction *tf; - - //printf(" vtbl[%d] is '%s'\n", j, ifd ? ifd->toChars() : "null"); - - assert(ifd); - // Find corresponding function in this class - tf = (ifd->type->ty == Tfunction) ? (TypeFunction *)(ifd->type) : NULL; - fd = cd->findFunc(ifd->ident, tf); - if (fd && !fd->isAbstract()) - { - //printf(" found\n"); - // Check that calling conventions match - if (fd->linkage != ifd->linkage) - fd->error("linkage doesn't match interface function"); - - // Check that it is current - if (newinstance && - fd->toParent() != cd && - ifd->toParent() == base) - cd->error("interface function %s.%s is not implemented", - id->toChars(), ifd->ident->toChars()); - - if (fd->toParent() == cd) - result = 1; - } - else - { - //printf(" not found\n"); - // BUG: should mark this class as abstract? - if (!cd->isAbstract()) - cd->error("interface function %s.%s isn't implemented", - id->toChars(), ifd->ident->toChars()); - fd = NULL; - } - if (vtbl) - vtbl->tdata()[j] = fd; - } - - return result; -} - -void BaseClass::copyBaseInterfaces(BaseClasses *vtblInterfaces) -{ - //printf("+copyBaseInterfaces(), %s\n", base->toChars()); -// if (baseInterfaces_dim) -// return; - - baseInterfaces_dim = base->interfaces_dim; - baseInterfaces = (BaseClass *)mem.calloc(baseInterfaces_dim, sizeof(BaseClass)); - - //printf("%s.copyBaseInterfaces()\n", base->toChars()); - for (int i = 0; i < baseInterfaces_dim; i++) - { - BaseClass *b = &baseInterfaces[i]; - BaseClass *b2 = base->interfaces[i]; - - assert(b2->vtbl.dim == 0); // should not be filled yet - memcpy(b, b2, sizeof(BaseClass)); - - if (i) // single inheritance is i==0 - vtblInterfaces->push(b); // only need for M.I. - b->copyBaseInterfaces(vtblInterfaces); - } - //printf("-copyBaseInterfaces\n"); -} diff --git a/dmd2/clone.c b/dmd2/clone.c deleted file mode 100644 index 2664f864..00000000 --- a/dmd2/clone.c +++ /dev/null @@ -1,694 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "statement.h" -#include "init.h" -#include "template.h" - - -/******************************************* - * We need an opAssign for the struct if - * it has a destructor or a postblit. - * We need to generate one if a user-specified one does not exist. - */ - -int StructDeclaration::needOpAssign() -{ -#define X 0 - if (X) printf("StructDeclaration::needOpAssign() %s\n", toChars()); - if (hasIdentityAssign) - goto Ldontneed; - - if (dtor || postblit) - goto Lneed; - - /* If any of the fields need an opAssign, then we - * need it too. - */ - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->needOpAssign()) - goto Lneed; - } - } -Ldontneed: - if (X) printf("\tdontneed\n"); - return 0; - -Lneed: - if (X) printf("\tneed\n"); - return 1; -#undef X -} - -/****************************************** - * Build opAssign for struct. - * S* opAssign(S s) { ... } - * - * Note that s will be constructed onto the stack, probably copy-constructed. - * Then, the body is: - * S tmp = *this; // bit copy - * *this = s; // bit copy - * tmp.dtor(); - * Instead of running the destructor on s, run it on tmp instead. - */ - -FuncDeclaration *StructDeclaration::buildOpAssign(Scope *sc) -{ - if (!needOpAssign()) - return NULL; - - //printf("StructDeclaration::buildOpAssign() %s\n", toChars()); - - FuncDeclaration *fop = NULL; - - Parameters *fparams = new Parameters; - fparams->push(new Parameter(STCnodtor, type, Id::p, NULL)); - Type *ftype = new TypeFunction(fparams, handle, FALSE, LINKd); -#if STRUCTTHISREF - ((TypeFunction *)ftype)->isref = 1; -#endif - - fop = new FuncDeclaration(loc, 0, Id::assign, STCundefined, ftype); - - Expression *e = NULL; - if (postblit) - { /* Swap: - * tmp = *this; *this = s; tmp.dtor(); - */ - //printf("\tswap copy\n"); - Identifier *idtmp = Lexer::uniqueId("__tmp"); - VarDeclaration *tmp; - AssignExp *ec = NULL; - if (dtor) - { - tmp = new VarDeclaration(0, type, idtmp, new VoidInitializer(0)); - tmp->noscope = 1; - tmp->storage_class |= STCctfe; - e = new DeclarationExp(0, tmp); - ec = new AssignExp(0, - new VarExp(0, tmp), -#if STRUCTTHISREF - new ThisExp(0) -#else - new PtrExp(0, new ThisExp(0)) -#endif - ); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - ec = new AssignExp(0, -#if STRUCTTHISREF - new ThisExp(0), -#else - new PtrExp(0, new ThisExp(0)), -#endif - new IdentifierExp(0, Id::p)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - if (dtor) - { - /* Instead of running the destructor on s, run it - * on tmp. This avoids needing to copy tmp back in to s. - */ - Expression *ec2 = new DotVarExp(0, new VarExp(0, tmp), dtor, 0); - ec2 = new CallExp(0, ec2); - e = Expression::combine(e, ec2); - } - } - else - { /* Do memberwise copy - */ - //printf("\tmemberwise copy\n"); - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - // this.v = s.v; - AssignExp *ec = new AssignExp(0, - new DotVarExp(0, new ThisExp(0), v, 0), - new DotVarExp(0, new IdentifierExp(0, Id::p), v, 0)); - ec->op = TOKblit; - e = Expression::combine(e, ec); - } - } - Statement *s1 = new ExpStatement(0, e); - - /* Add: - * return this; - */ - e = new ThisExp(0); - Statement *s2 = new ReturnStatement(0, e); - - fop->fbody = new CompoundStatement(0, s1, s2); - - members->push(fop); - fop->addMember(sc, this, 1); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fop->semantic(sc); - - sc->pop(); - - //printf("-StructDeclaration::buildOpAssign() %s\n", toChars()); - - return fop; -} - -/******************************************* - * We need an opEquals for the struct if - * any fields has an opEquals. - * Generate one if a user-specified one does not exist. - */ - -int StructDeclaration::needOpEquals() -{ -#define X 0 - if (X) printf("StructDeclaration::needOpEquals() %s\n", toChars()); - - if (hasIdentityEquals) - goto Lneed; - - /* If any of the fields has an opEquals, then we - * need it too. - */ - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->needOpEquals()) - goto Lneed; - } - } - if (X) printf("\tdontneed\n"); - return 0; - -Lneed: - if (X) printf("\tneed\n"); - return 1; -#undef X -} - -/****************************************** - * Build opEquals for struct. - * const bool opEquals(const S s) { ... } - */ - -FuncDeclaration *StructDeclaration::buildOpEquals(Scope *sc) -{ - Dsymbol *eq = search_function(this, Id::eq); - if (eq) - { - for (size_t i = 0; i <= 1; i++) - { - Expression *e = - i == 0 ? new NullExp(loc, type->constOf()) // dummy rvalue - : type->constOf()->defaultInit(); // dummy lvalue - Expressions *arguments = new Expressions(); - arguments->push(e); - - // check identity opEquals exists - FuncDeclaration *fd = eq->isFuncDeclaration(); - if (fd) - { fd = fd->overloadResolve(loc, e, arguments, 1); - if (fd && !(fd->storage_class & STCdisable)) - return fd; - } - - TemplateDeclaration *td = eq->isTemplateDeclaration(); - if (td) - { fd = td->deduceFunctionTemplate(sc, loc, NULL, e, arguments, 1); - if (fd && !(fd->storage_class & STCdisable)) - return fd; - } - } - return NULL; - } - - if (!needOpEquals()) - return NULL; - - //printf("StructDeclaration::buildOpEquals() %s\n", toChars()); - - Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCin, type, Id::p, NULL)); - TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); - tf->mod = MODconst; - tf = (TypeFunction *)tf->semantic(loc, sc); - - FuncDeclaration *fop = new FuncDeclaration(loc, 0, Id::eq, STCundefined, tf); - - Expression *e = NULL; - /* Do memberwise compare - */ - //printf("\tmemberwise compare\n"); - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - assert(0); // what should we do with this? - // this.v == s.v; - EqualExp *ec = new EqualExp(TOKequal, loc, - new DotVarExp(loc, new ThisExp(loc), v, 0), - new DotVarExp(loc, new IdentifierExp(loc, Id::p), v, 0)); - if (e) - e = new AndAndExp(loc, e, ec); - else - e = ec; - } - if (!e) - e = new IntegerExp(loc, 1, Type::tbool); - fop->fbody = new ReturnStatement(loc, e); - - members->push(fop); - fop->addMember(sc, this, 1); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fop->semantic(sc); - - sc->pop(); - - //printf("-StructDeclaration::buildOpEquals() %s\n", toChars()); - - return fop; -} - -/****************************************** - * Build __xopEquals for TypeInfo_Struct - * bool __xopEquals(in void* p, in void* q) { ... } - */ - -FuncDeclaration *StructDeclaration::buildXopEquals(Scope *sc) -{ - if (!search_function(this, Id::eq)) - return NULL; - - /* static bool__xopEquals(in void* p, in void* q) { - * return ( *cast(const S*)(p) ).opEquals( *cast(const S*)(q) ); - * } - */ - - Parameters *parameters = new Parameters; - parameters->push(new Parameter(STCin, Type::tvoidptr, Id::p, NULL)); - parameters->push(new Parameter(STCin, Type::tvoidptr, Id::q, NULL)); - TypeFunction *tf = new TypeFunction(parameters, Type::tbool, 0, LINKd); - tf = (TypeFunction *)tf->semantic(loc, sc); - - Identifier *id = Lexer::idPool("__xopEquals"); - FuncDeclaration *fop = new FuncDeclaration(loc, 0, id, STCstatic, tf); - - Expression *e = new CallExp(0, - new DotIdExp(0, - new PtrExp(0, new CastExp(0, - new IdentifierExp(0, Id::p), type->pointerTo()->constOf())), - Id::eq), - new PtrExp(0, new CastExp(0, - new IdentifierExp(0, Id::q), type->pointerTo()->constOf()))); - - fop->fbody = new ReturnStatement(loc, e); - - size_t index = members->dim; - members->push(fop); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - unsigned errors = global.startGagging(); - fop->semantic(sc); - if (errors == global.gaggedErrors) - { fop->semantic2(sc); - if (errors == global.gaggedErrors) - { fop->semantic3(sc); - if (errors == global.gaggedErrors) - fop->addMember(sc, this, 1); - } - } - if (global.endGagging(errors)) // if errors happened - { - members->remove(index); - - if (!xerreq) - { - Expression *e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::object); - e = new DotIdExp(loc, e, Lexer::idPool("_xopEquals")); - e = e->semantic(sc); - Dsymbol *s = getDsymbol(e); - FuncDeclaration *fd = s->isFuncDeclaration(); - - xerreq = fd; - } - fop = xerreq; - } - - sc->pop(); - - return fop; -} - - -/******************************************* - * Build copy constructor for struct. - * Copy constructors are compiler generated only, and are only - * callable from the compiler. They are not user accessible. - * A copy constructor is: - * void cpctpr(ref const S s) const - * { - * (*cast(S*)&this) = *cast(S*)s; - * (*cast(S*)&this).postBlit(); - * } - * This is done so: - * - postBlit() never sees uninitialized data - * - memcpy can be much more efficient than memberwise copy - * - no fields are overlooked - */ - -FuncDeclaration *StructDeclaration::buildCpCtor(Scope *sc) -{ - //printf("StructDeclaration::buildCpCtor() %s\n", toChars()); - FuncDeclaration *fcp = NULL; - - /* Copy constructor is only necessary if there is a postblit function, - * otherwise the code generator will just do a bit copy. - */ - if (postblit) - { - //printf("generating cpctor\n"); - - StorageClass stc = postblit->storage_class & - (STCdisable | STCsafe | STCtrusted | STCsystem | STCpure | STCnothrow); - if (stc & (STCsafe | STCtrusted)) - stc = stc & ~STCsafe | STCtrusted; - - Parameters *fparams = new Parameters; - fparams->push(new Parameter(STCref, type->constOf(), Id::p, NULL)); - Type *ftype = new TypeFunction(fparams, Type::tvoid, FALSE, LINKd, stc); - ftype->mod = MODconst; - - fcp = new FuncDeclaration(loc, 0, Id::cpctor, stc, ftype); - - if (!(fcp->storage_class & STCdisable)) - { - // Build *this = p; - Expression *e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif - AssignExp *ea = new AssignExp(0, - new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())), - new PtrExp(0, new CastExp(0, new AddrExp(0, new IdentifierExp(0, Id::p)), type->mutableOf()->pointerTo())) - ); - ea->op = TOKblit; - Statement *s = new ExpStatement(0, ea); - - // Build postBlit(); - e = new ThisExp(0); -#if !STRUCTTHISREF - e = new PtrExp(0, e); -#endif - e = new PtrExp(0, new CastExp(0, new AddrExp(0, e), type->mutableOf()->pointerTo())); - e = new DotVarExp(0, e, postblit, 0); - e = new CallExp(0, e); - - s = new CompoundStatement(0, s, new ExpStatement(0, e)); - fcp->fbody = s; - } - else - fcp->fbody = new ExpStatement(0, (Expression *)NULL); - - members->push(fcp); - - sc = sc->push(); - sc->stc = 0; - sc->linkage = LINKd; - - fcp->semantic(sc); - - sc->pop(); - } - - return fcp; -} - -/***************************************** - * Create inclusive postblit for struct by aggregating - * all the postblits in postblits[] with the postblits for - * all the members. - * Note the close similarity with AggregateDeclaration::buildDtor(), - * and the ordering changes (runs forward instead of backwards). - */ - -#if DMDV2 -FuncDeclaration *StructDeclaration::buildPostBlit(Scope *sc) -{ - //printf("StructDeclaration::buildPostBlit() %s\n", toChars()); - Expression *e = NULL; - StorageClass stc = 0; - - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->postblit) - { - stc |= sd->postblit->storage_class & STCdisable; - - if (stc & STCdisable) - { - e = NULL; - break; - } - - // this.v - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 0) - { // this.v.postblit() - ex = new DotVarExp(0, ex, sd->postblit, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.postblit(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::postblit); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(e, ex); // combine in forward order - } - } - } - - /* Build our own "postblit" which executes e - */ - if (e || (stc & STCdisable)) - { //printf("Building __fieldPostBlit()\n"); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__fieldPostBlit")); - dd->storage_class |= stc; - dd->fbody = new ExpStatement(0, e); - postblits.shift(dd); - members->push(dd); - dd->semantic(sc); - } - - switch (postblits.dim) - { - case 0: - return NULL; - - case 1: - return postblits.tdata()[0]; - - default: - e = NULL; - for (size_t i = 0; i < postblits.dim; i++) - { FuncDeclaration *fd = postblits.tdata()[i]; - stc |= fd->storage_class & STCdisable; - if (stc & STCdisable) - { - e = NULL; - break; - } - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(e, ex); - } - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, 0, Lexer::idPool("__aggrPostBlit")); - dd->storage_class |= stc; - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - -#endif - -/***************************************** - * Create inclusive destructor for struct/class by aggregating - * all the destructors in dtors[] with the destructors for - * all the members. - * Note the close similarity with StructDeclaration::buildPostBlit(), - * and the ordering changes (runs backward instead of forwards). - */ - -FuncDeclaration *AggregateDeclaration::buildDtor(Scope *sc) -{ - //printf("AggregateDeclaration::buildDtor() %s\n", toChars()); - Expression *e = NULL; - -#if DMDV2 - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - if (v->storage_class & STCref) - continue; - Type *tv = v->type->toBasetype(); - dinteger_t dim = (tv->ty == Tsarray ? 1 : 0); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - dim *= ((TypeSArray *)tv)->dim->toInteger(); - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { Expression *ex; - - // this.v - ex = new ThisExp(0); - ex = new DotVarExp(0, ex, v, 0); - - if (dim == 0) - { // this.v.dtor() - ex = new DotVarExp(0, ex, sd->dtor, 0); - ex = new CallExp(0, ex); - } - else - { - // Typeinfo.destroy(cast(void*)&this.v); - Expression *ea = new AddrExp(0, ex); - ea = new CastExp(0, ea, Type::tvoid->pointerTo()); - - Expression *et = v->type->getTypeInfo(sc); - et = new DotIdExp(0, et, Id::destroy); - - ex = new CallExp(0, et, ea); - } - e = Expression::combine(ex, e); // combine in reverse order - } - } - } - - /* Build our own "destructor" which executes e - */ - if (e) - { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__fieldDtor")); - dd->fbody = new ExpStatement(0, e); - dtors.shift(dd); - members->push(dd); - dd->semantic(sc); - } -#endif - - switch (dtors.dim) - { - case 0: - return NULL; - - case 1: - return dtors.tdata()[0]; - - default: - e = NULL; - for (size_t i = 0; i < dtors.dim; i++) - { FuncDeclaration *fd = dtors.tdata()[i]; - Expression *ex = new ThisExp(0); - ex = new DotVarExp(0, ex, fd, 0); - ex = new CallExp(0, ex); - e = Expression::combine(ex, e); - } - DtorDeclaration *dd = new DtorDeclaration(loc, 0, Lexer::idPool("__aggrDtor")); - dd->fbody = new ExpStatement(0, e); - members->push(dd); - dd->semantic(sc); - return dd; - } -} - - diff --git a/dmd2/complex_t.h b/dmd2/complex_t.h deleted file mode 100644 index a1b4f4ed..00000000 --- a/dmd2/complex_t.h +++ /dev/null @@ -1,74 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright and Burton Radons -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_COMPLEX_T_H -#define DMD_COMPLEX_T_H - -/* Roll our own complex type for compilers that don't support complex - */ - -struct complex_t -{ - long double re; - long double im; - - complex_t() { this->re = 0; this->im = 0; } - complex_t(long double re) { this->re = re; this->im = 0; } - complex_t(long double re, long double im) { this->re = re; this->im = im; } - - complex_t operator + (complex_t y) { complex_t r; r.re = re + y.re; r.im = im + y.im; return r; } - complex_t operator - (complex_t y) { complex_t r; r.re = re - y.re; r.im = im - y.im; return r; } - complex_t operator - () { complex_t r; r.re = -re; r.im = -im; return r; } - complex_t operator * (complex_t y) { return complex_t(re * y.re - im * y.im, im * y.re + re * y.im); } - - complex_t operator / (complex_t y) - { - long double abs_y_re = y.re < 0 ? -y.re : y.re; - long double abs_y_im = y.im < 0 ? -y.im : y.im; - long double r, den; - - if (abs_y_re < abs_y_im) - { - r = y.re / y.im; - den = y.im + r * y.re; - return complex_t((re * r + im) / den, - (im * r - re) / den); - } - else - { - r = y.im / y.re; - den = y.re + r * y.im; - return complex_t((re + r * im) / den, - (im - r * re) / den); - } - } - - operator bool () { return re || im; } - - int operator == (complex_t y) { return re == y.re && im == y.im; } - int operator != (complex_t y) { return re != y.re || im != y.im; } -}; - -inline complex_t operator * (long double x, complex_t y) { return complex_t(x) * y; } -inline complex_t operator * (complex_t x, long double y) { return x * complex_t(y); } -inline complex_t operator / (complex_t x, long double y) { return x / complex_t(y); } - - -inline long double creall(complex_t x) -{ - return x.re; -} - -inline long double cimagl(complex_t x) -{ - return x.im; -} - -#endif diff --git a/dmd2/cond.c b/dmd2/cond.c deleted file mode 100644 index a37f2738..00000000 --- a/dmd2/cond.c +++ /dev/null @@ -1,405 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "identifier.h" -#include "expression.h" -#include "cond.h" -#include "module.h" -#include "template.h" -#include "lexer.h" -#include "mtype.h" -#include "scope.h" - -int findCondition(Strings *ids, Identifier *ident) -{ - if (ids) - { - for (size_t i = 0; i < ids->dim; i++) - { - const char *id = ids->tdata()[i]; - - if (strcmp(id, ident->toChars()) == 0) - return TRUE; - } - } - - return FALSE; -} - -/* ============================================================ */ - -Condition::Condition(Loc loc) -{ - this->loc = loc; - inc = 0; -} - -/* ============================================================ */ - -DVCondition::DVCondition(Module *mod, unsigned level, Identifier *ident) - : Condition(0) -{ - this->mod = mod; - this->level = level; - this->ident = ident; -} - -Condition *DVCondition::syntaxCopy() -{ - return this; // don't need to copy -} - -/* ============================================================ */ - -void DebugCondition::setGlobalLevel(unsigned level) -{ - global.params.debuglevel = level; -} - -void DebugCondition::addGlobalIdent(const char *ident) -{ - if (!global.params.debugids) - global.params.debugids = new Strings(); - global.params.debugids->push((char *)ident); -} - - -DebugCondition::DebugCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int DebugCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->debugids, ident)) - inc = 1; - else if (findCondition(global.params.debugids, ident)) - inc = 1; - else - { if (!mod->debugidsNot) - mod->debugidsNot = new Strings(); - mod->debugidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.debuglevel || level <= mod->debuglevel) - inc = 1; - } - return (inc == 1); -} - -void DebugCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("debug (%s)", ident->toChars()); - else - buf->printf("debug (%u)", level); -} - -/* ============================================================ */ - -void VersionCondition::setGlobalLevel(unsigned level) -{ - global.params.versionlevel = level; -} - -void VersionCondition::checkPredefined(Loc loc, const char *ident) -{ - static const char* reserved[] = - { - "DigitalMars", "X86", "X86_64", - "Windows", "Win32", "Win64", - "linux", -#if DMDV2 - /* Although Posix is predefined by D1, disallowing its - * redefinition breaks makefiles and older builds. - */ - "Posix", - "D_NET", -#endif - "OSX", "FreeBSD", - "OpenBSD", - "Solaris", - "LittleEndian", "BigEndian", - "all", - "none", - -#if IN_LLVM - "LLVM", "LDC", "LLVM64", - "PPC", "PPC64", - "darwin","solaris","freebsd" -#endif - }; - - for (unsigned i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) - { - if (strcmp(ident, reserved[i]) == 0) - goto Lerror; - } - - if (ident[0] == 'D' && ident[1] == '_') - goto Lerror; - - return; - - Lerror: - error(loc, "version identifier '%s' is reserved and cannot be set", ident); -} - -void VersionCondition::addGlobalIdent(const char *ident) -{ - checkPredefined(0, ident); - addPredefinedGlobalIdent(ident); -} - -void VersionCondition::addPredefinedGlobalIdent(const char *ident) -{ - if (!global.params.versionids) - global.params.versionids = new Strings(); - global.params.versionids->push((char *)ident); -} - - -VersionCondition::VersionCondition(Module *mod, unsigned level, Identifier *ident) - : DVCondition(mod, level, ident) -{ -} - -int VersionCondition::include(Scope *sc, ScopeDsymbol *s) -{ - //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel); - //if (ident) printf("\tident = '%s'\n", ident->toChars()); - if (inc == 0) - { - inc = 2; - if (ident) - { - if (findCondition(mod->versionids, ident)) - inc = 1; - else if (findCondition(global.params.versionids, ident)) - inc = 1; - else - { - if (!mod->versionidsNot) - mod->versionidsNot = new Strings(); - mod->versionidsNot->push(ident->toChars()); - } - } - else if (level <= global.params.versionlevel || level <= mod->versionlevel) - inc = 1; - } - return (inc == 1); -} - -void VersionCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (ident) - buf->printf("version (%s)", ident->toChars()); - else - buf->printf("version (%u)", level); -} - - -/**************************** StaticIfCondition *******************************/ - -StaticIfCondition::StaticIfCondition(Loc loc, Expression *exp) - : Condition(loc) -{ - this->exp = exp; -} - -Condition *StaticIfCondition::syntaxCopy() -{ - return new StaticIfCondition(loc, exp->syntaxCopy()); -} - -int StaticIfCondition::include(Scope *sc, ScopeDsymbol *s) -{ -#if 0 - printf("StaticIfCondition::include(sc = %p, s = %p)\n", sc, s); - if (s) - { - printf("\ts = '%s', kind = %s\n", s->toChars(), s->kind()); - } -#endif - if (inc == 0) - { - if (!sc) - { - error(loc, "static if conditional cannot be at global scope"); - inc = 2; - return 0; - } - - sc = sc->push(sc->scopesym); - sc->sd = s; // s gets any addMember() - sc->flags |= SCOPEstaticif; - Expression *e = exp->semantic(sc); - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - inc = 1; - else if (e->isBool(FALSE)) - inc = 2; - else - { - e->error("expression %s is not constant or does not evaluate to a bool", e->toChars()); - inc = 2; - } - } - return (inc == 1); -} - -void StaticIfCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("static if("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); -} - - -/**************************** IftypeCondition *******************************/ - -IftypeCondition::IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec) - : Condition(loc) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; -} - -Condition *IftypeCondition::syntaxCopy() -{ - return new IftypeCondition(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL); -} - -int IftypeCondition::include(Scope *sc, ScopeDsymbol *sd) -{ - //printf("IftypeCondition::include()\n"); - if (inc == 0) - { - if (!sc) - { - error(loc, "iftype conditional cannot be at global scope"); - inc = 2; - return 0; - } - Type *t = targ->trySemantic(loc, sc); - if (t) - targ = t; - else - inc = 2; // condition is false - - if (!t) - { - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - MATCH m; - TemplateTypeParameter tp(loc, id, NULL, NULL); - - TemplateParameters parameters; - parameters.setDim(1); - parameters.tdata()[0] = &tp; - - Objects dedtypes; - dedtypes.setDim(1); - - m = targ->deduceType(sc, tspec, ¶meters, &dedtypes); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - inc = 2; - else - { - inc = 1; - Type *tded = (Type *)dedtypes.tdata()[0]; - if (!tded) - tded = targ; - Dsymbol *s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - Dsymbol *s = new AliasDeclaration(loc, id, targ); - s->semantic(sc); - sc->insert(s); - if (sd) - s->addMember(sc, sd, 1); - inc = 1; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s\n", targ->toChars()); - //printf("tspec = %s\n", tspec->toChars()); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - inc = 1; - else - inc = 2; - } - else /* == */ - { if (targ->equals(tspec)) - inc = 1; - else - inc = 2; - } - } - else - inc = 1; - //printf("inc = %d\n", inc); - } - return (inc == 1); -} - -void IftypeCondition::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("iftype("); - targ->toCBuffer(buf, id, hgs); - if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } - buf->writeByte(')'); -} - - diff --git a/dmd2/cond.h b/dmd2/cond.h deleted file mode 100644 index 789503a4..00000000 --- a/dmd2/cond.h +++ /dev/null @@ -1,105 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 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_DEBCOND_H -#define DMD_DEBCOND_H - -struct Expression; -struct Identifier; -struct OutBuffer; -struct Module; -struct Scope; -struct ScopeDsymbol; -struct DebugCondition; -#include "lexer.h" // dmdhg -enum TOK; -struct HdrGenState; - -int findCondition(Strings *ids, Identifier *ident); - -struct Condition -{ - Loc loc; - int inc; // 0: not computed yet - // 1: include - // 2: do not include - - Condition(Loc loc); - - virtual Condition *syntaxCopy() = 0; - virtual int include(Scope *sc, ScopeDsymbol *s) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual DebugCondition *isDebugCondition() { return NULL; } -}; - -struct DVCondition : Condition -{ - unsigned level; - Identifier *ident; - Module *mod; - - DVCondition(Module *mod, unsigned level, Identifier *ident); - - Condition *syntaxCopy(); -}; - -struct DebugCondition : DVCondition -{ - static void setGlobalLevel(unsigned level); - static void addGlobalIdent(const char *ident); - static void addPredefinedGlobalIdent(const char *ident); - - DebugCondition(Module *mod, unsigned level, Identifier *ident); - - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - DebugCondition *isDebugCondition() { return this; } -}; - -struct VersionCondition : DVCondition -{ - static void setGlobalLevel(unsigned level); - static void checkPredefined(Loc loc, const char *ident); - static void addGlobalIdent(const char *ident); - static void addPredefinedGlobalIdent(const char *ident); - - VersionCondition(Module *mod, unsigned level, Identifier *ident); - - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct StaticIfCondition : Condition -{ - Expression *exp; - - StaticIfCondition(Loc loc, Expression *exp); - Condition *syntaxCopy(); - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct IftypeCondition : Condition -{ - /* iftype (targ id tok tspec) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - - IftypeCondition(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec); - Condition *syntaxCopy(); - int include(Scope *sc, ScopeDsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - - -#endif diff --git a/dmd2/constfold.c b/dmd2/constfold.c deleted file mode 100644 index 38d00efd..00000000 --- a/dmd2/constfold.c +++ /dev/null @@ -1,1876 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "rmem.h" -#include "root.h" -#include "port.h" - -#include "mtype.h" -#include "expression.h" -#include "aggregate.h" -#include "declaration.h" -#include "utf.h" - -#define LOG 0 - -int RealEquals(real_t x1, real_t x2); - -Expression *expType(Type *type, Expression *e) -{ - if (type != e->type) - { - e = e->copy(); - e->type = type; - } - return e; -} - -/* ================================== isConst() ============================== */ - -int Expression::isConst() -{ - //printf("Expression::isConst(): %s\n", toChars()); - return 0; -} - -int IntegerExp::isConst() -{ - return 1; -} - -int RealExp::isConst() -{ - return 1; -} - -int ComplexExp::isConst() -{ - return 1; -} - -int NullExp::isConst() -{ - return 0; -} - -int SymOffExp::isConst() -{ - return 2; -} - -/* =============================== constFold() ============================== */ - -/* The constFold() functions were redundant with the optimize() ones, - * and so have been folded in with them. - */ - -/* ========================================================================== */ - -Expression *Neg(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->type->isreal()) - { - e = new RealExp(loc, -e1->toReal(), type); - } - else if (e1->type->isimaginary()) - { - e = new RealExp(loc, -e1->toImaginary(), type); - } - else if (e1->type->iscomplex()) - { - e = new ComplexExp(loc, -e1->toComplex(), type); - } - else - e = new IntegerExp(loc, -e1->toInteger(), type); - return e; -} - -Expression *Com(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, ~e1->toInteger(), type); - return e; -} - -Expression *Not(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(0), type); - return e; -} - -Expression *Bool(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->isBool(1), type); - return e; -} - -Expression *Add(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - -#if LOG - printf("Add(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); -#endif - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() + e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() + e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 + r2); break; - case 0+1: v = r1 + i2 * I; break; - case 0+2: v = r1 + c2; break; - case 3+0: v = i1 * I + r2; break; - case 3+1: v = (complex_t) ((i1 + i2) * I); break; - case 3+2: v = i1 * I + c2; break; - case 6+0: v = c1 + r2; break; - case 6+1: v = c1 + i2 * I; break; - case 6+2: v = c1 + c2; break; -#else - case 0+0: v = complex_t(r1 + r2, 0); break; - case 0+1: v = complex_t(r1, i2); break; - case 0+2: v = complex_t(r1 + creall(c2), cimagl(c2)); break; - case 3+0: v = complex_t(r2, i1); break; - case 3+1: v = complex_t(0, i1 + i2); break; - case 3+2: v = complex_t(creall(c2), i1 + cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) + r2, cimagl(c2)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) + i2); break; - case 6+2: v = c1 + c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset + e2->toInteger()); - e->type = type; - } - else if (e2->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e2; - e = new SymOffExp(loc, soe->var, soe->offset + e1->toInteger()); - e->type = type; - } - else - e = new IntegerExp(loc, e1->toInteger() + e2->toInteger(), type); - return e; -} - - -Expression *Min(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isreal()) - { - e = new RealExp(loc, e1->toReal() - e2->toReal(), type); - } - else if (type->isimaginary()) - { - e = new RealExp(loc, e1->toImaginary() - e2->toImaginary(), type); - } - else if (type->iscomplex()) - { - // This rigamarole is necessary so that -0.0 doesn't get - // converted to +0.0 by doing an extraneous add with +0.0 - complex_t c1; - real_t r1; - real_t i1; - - complex_t c2; - real_t r2; - real_t i2; - - complex_t v; - int x; - - if (e1->type->isreal()) - { r1 = e1->toReal(); - x = 0; - } - else if (e1->type->isimaginary()) - { i1 = e1->toImaginary(); - x = 3; - } - else - { c1 = e1->toComplex(); - x = 6; - } - - if (e2->type->isreal()) - { r2 = e2->toReal(); - } - else if (e2->type->isimaginary()) - { i2 = e2->toImaginary(); - x += 1; - } - else - { c2 = e2->toComplex(); - x += 2; - } - - switch (x) - { -#if __DMC__ - case 0+0: v = (complex_t) (r1 - r2); break; - case 0+1: v = r1 - i2 * I; break; - case 0+2: v = r1 - c2; break; - case 3+0: v = i1 * I - r2; break; - case 3+1: v = (complex_t) ((i1 - i2) * I); break; - case 3+2: v = i1 * I - c2; break; - case 6+0: v = c1 - r2; break; - case 6+1: v = c1 - i2 * I; break; - case 6+2: v = c1 - c2; break; -#else - case 0+0: v = complex_t(r1 - r2, 0); break; - case 0+1: v = complex_t(r1, -i2); break; - case 0+2: v = complex_t(r1 - creall(c2), -cimagl(c2)); break; - case 3+0: v = complex_t(-r2, i1); break; - case 3+1: v = complex_t(0, i1 - i2); break; - case 3+2: v = complex_t(-creall(c2), i1 - cimagl(c2)); break; - case 6+0: v = complex_t(creall(c1) - r2, cimagl(c1)); break; - case 6+1: v = complex_t(creall(c1), cimagl(c1) - i2); break; - case 6+2: v = c1 - c2; break; -#endif - default: assert(0); - } - e = new ComplexExp(loc, v, type); - } - else if (e1->op == TOKsymoff) - { - SymOffExp *soe = (SymOffExp *)e1; - e = new SymOffExp(loc, soe->var, soe->offset - e2->toInteger()); - e->type = type; - } - else - { - e = new IntegerExp(loc, e1->toInteger() - e2->toInteger(), type); - } - return e; -} - -Expression *Mul(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - if (e1->type->isreal()) - { -#if __DMC__ - c = e1->toReal() * e2->toComplex(); -#else - r = e1->toReal(); - c = e2->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e1->type->isimaginary()) - { -#if __DMC__ - c = e1->toImaginary() * I * e2->toComplex(); -#else - r = e1->toImaginary(); - c = e2->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else if (e2->type->isreal()) - { -#if __DMC__ - c = e2->toReal() * e1->toComplex(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(r * creall(c), r * cimagl(c)); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - c = e1->toComplex() * e2->toImaginary() * I; -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(-r * cimagl(c), r * creall(c)); -#endif - } - else - c = e1->toComplex() * e2->toComplex(); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { - e = new IntegerExp(loc, e1->toInteger() * e2->toInteger(), type); - } - return e; -} - -Expression *Div(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { complex_t c; -#ifdef IN_GCC - real_t r; -#else - d_float80 r; -#endif - - //e1->type->print(); - //e2->type->print(); - if (e2->type->isreal()) - { - if (e1->type->isreal()) - { - e = new RealExp(loc, e1->toReal() / e2->toReal(), type); - return e; - } -#if __DMC__ - //r = e2->toReal(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lg\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / e2->toReal(); -#else - r = e2->toReal(); - c = e1->toComplex(); - c = complex_t(creall(c) / r, cimagl(c) / r); -#endif - } - else if (e2->type->isimaginary()) - { -#if __DMC__ - //r = e2->toImaginary(); - //c = e1->toComplex(); - //printf("(%Lg + %Lgi) / %Lgi\n", creall(c), cimagl(c), r); - - c = e1->toComplex() / (e2->toImaginary() * I); -#else - r = e2->toImaginary(); - c = e1->toComplex(); - c = complex_t(cimagl(c) / r, -creall(c) / r); -#endif - } - else - { - c = e1->toComplex() / e2->toComplex(); - } - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) / ((d_uns64) n2); - else - n = n1 / n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Mod(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - if (type->isfloating()) - { - complex_t c; - - if (e2->type->isreal()) - { real_t r2 = e2->toReal(); - -#ifdef __DMC__ - c = Port::fmodl(e1->toReal(), r2) + Port::fmodl(e1->toImaginary(), r2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % r2, e1->toImaginary() % r2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), r2), fmod(e1->toImaginary(), r2)); -#else - c = complex_t(Port::fmodl(e1->toReal(), r2), Port::fmodl(e1->toImaginary(), r2)); -#endif - } - else if (e2->type->isimaginary()) - { real_t i2 = e2->toImaginary(); - -#ifdef __DMC__ - c = Port::fmodl(e1->toReal(), i2) + Port::fmodl(e1->toImaginary(), i2) * I; -#elif defined(IN_GCC) - c = complex_t(e1->toReal() % i2, e1->toImaginary() % i2); -#elif (defined(__FreeBSD__) && __FreeBSD_version < 800000) || defined(__arm__) || defined(__thumb__) - // freebsd is kinda messed up. the STABLE branch doesn't support C99's fmodl !?! - // arm also doesn't like fmodl - c = complex_t(fmod(e1->toReal(), i2), fmod(e1->toImaginary(), i2)); -#else - c = complex_t(Port::fmodl(e1->toReal(), i2), Port::fmodl(e1->toImaginary(), i2)); -#endif - } - else - assert(0); - - if (type->isreal()) - e = new RealExp(loc, creall(c), type); - else if (type->isimaginary()) - e = new RealExp(loc, cimagl(c), type); - else if (type->iscomplex()) - e = new ComplexExp(loc, c, type); - else - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - sinteger_t n; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (n2 == 0) - { e2->error("divide by 0"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - if (n2 == -1 && !type->isunsigned()) - { // Check for int.min % -1 - if (n1 == 0xFFFFFFFF80000000ULL && type->toBasetype()->ty != Tint64) - { - e2->error("integer overflow: int.min % -1"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - else if (n1 == 0x8000000000000000LL) // long.min % -1 - { - e2->error("integer overflow: long.min % -1"); - e2 = new IntegerExp(loc, 1, e2->type); - n2 = 1; - } - } - if (e1->type->isunsigned() || e2->type->isunsigned()) - n = ((d_uns64) n1) % ((d_uns64) n2); - else - n = n1 % n2; - e = new IntegerExp(loc, n, type); - } - return e; -} - -Expression *Pow(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - // Handle integer power operations. - if (e2->type->isintegral()) - { - Expression * r; - Expression * v; - dinteger_t n = e2->toInteger(); - bool neg; - - if (!e2->type->isunsigned() && (sinteger_t)n < 0) - { - if (e1->type->isintegral()) - return EXP_CANT_INTERPRET; - - // Don't worry about overflow, from now on n is unsigned. - neg = true; - n = -n; - } - else - neg = false; - - if (e1->type->isfloating()) - { - r = new RealExp(loc, e1->toReal(), e1->type); - v = new RealExp(loc, 1.0, e1->type); - } - else - { - r = new RealExp(loc, e1->toReal(), Type::tfloat64); - v = new RealExp(loc, 1.0, Type::tfloat64); - } - - while (n != 0) - { - if (n & 1) - v = Mul(v->type, v, r); - n >>= 1; - r = Mul(r->type, r, r); - } - - if (neg) - v = Div(v->type, new RealExp(loc, 1.0, v->type), v); - - if (type->isintegral()) - e = new IntegerExp(loc, v->toInteger(), type); - else - e = new RealExp(loc, v->toReal(), type); - } - else if (e2->type->isfloating()) - { - // x ^^ y for x < 0 and y not an integer is not defined - if (e1->toReal() < 0.0) - { - e = new RealExp(loc, Port::nan, type); - } - else if (e2->toReal() == 0.5) - { - // Special case: call sqrt directly. - Expressions args; - args.setDim(1); - args.tdata()[0] = e1; - e = eval_builtin(loc, BUILTINsqrt, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - else - e = EXP_CANT_INTERPRET; - } - else - e = EXP_CANT_INTERPRET; - - return e; -} - -Expression *Shl(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - - e = new IntegerExp(loc, e1->toInteger() << e2->toInteger(), type); - return e; -} - -Expression *Shr(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - - dinteger_t value = e1->toInteger(); - dinteger_t dcount = e2->toInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - value = (d_int8)(value) >> count; - break; - - case Tuns8: - case Tchar: - value = (d_uns8)(value) >> count; - break; - - case Tint16: - value = (d_int16)(value) >> count; - break; - - case Tuns16: - case Twchar: - value = (d_uns16)(value) >> count; - break; - - case Tint32: - value = (d_int32)(value) >> count; - break; - - case Tuns32: - case Tdchar: - value = (d_uns32)(value) >> count; - break; - - case Tint64: - value = (d_int64)(value) >> count; - break; - - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - case Terror: - return e1; - - default: - assert(0); - } - Expression *e = new IntegerExp(loc, value, type); - return e; -} - -Expression *Ushr(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - - dinteger_t value = e1->toInteger(); - dinteger_t dcount = e2->toInteger(); - assert(dcount <= 0xFFFFFFFF); - unsigned count = (unsigned)dcount; - switch (e1->type->toBasetype()->ty) - { - case Tint8: - case Tuns8: - case Tchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFF) >> count; - break; - - case Tint16: - case Tuns16: - case Twchar: - // Possible only with >>>=. >>> always gets promoted to int. - value = (value & 0xFFFF) >> count; - break; - - case Tint32: - case Tuns32: - case Tdchar: - value = (value & 0xFFFFFFFF) >> count; - break; - - case Tint64: - case Tuns64: - value = (d_uns64)(value) >> count; - break; - - case Terror: - return e1; - - default: - assert(0); - } - Expression *e = new IntegerExp(loc, value, type); - return e; -} - -Expression *And(Type *type, Expression *e1, Expression *e2) -{ - Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() & e2->toInteger(), type); - return e; -} - -Expression *Or(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() | e2->toInteger(), type); - return e; -} - -Expression *Xor(Type *type, Expression *e1, Expression *e2) -{ Expression *e; - e = new IntegerExp(e1->loc, e1->toInteger() ^ e2->toInteger(), type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - */ -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - int cmp; - real_t r1; - real_t r2; - - //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - assert(op == TOKequal || op == TOKnotequal); - - if (e1->op == TOKnull) - { - if (e2->op == TOKnull) - cmp = 1; - else if (e2->op == TOKstring) - { StringExp *es2 = (StringExp *)e2; - cmp = (0 == es2->len); - } - else if (e2->op == TOKarrayliteral) - { ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - cmp = !es2->elements || (0 == es2->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e2->op == TOKnull) - { - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - cmp = (0 == es1->len); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - cmp = !es1->elements || (0 == es1->elements->dim); - } - else - return EXP_CANT_INTERPRET; - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - - if (es1->sz != es2->sz) - { - assert(global.errors); - return EXP_CANT_INTERPRET; - } - if (es1->len == es2->len && - memcmp(es1->string, es2->string, es1->sz * es1->len) == 0) - cmp = 1; - else - cmp = 0; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - if ((!es1->elements || !es1->elements->dim) && - (!es2->elements || !es2->elements->dim)) - cmp = 1; // both arrays are empty - else if (!es1->elements || !es2->elements) - cmp = 0; - else if (es1->elements->dim != es2->elements->dim) - cmp = 0; - else - { - for (size_t i = 0; i < es1->elements->dim; i++) - { Expression *ee1 = (*es1->elements)[i]; - Expression *ee2 = (*es2->elements)[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 *etmp = e1; - e1 = e2; - e2 = etmp; - 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 - { - cmp = 1; // if dim1 winds up being 0 - for (size_t i = 0; i < dim1; i++) - { - uinteger_t c = es1->charAt(i); - Expression *ee2 = (*es2->elements)[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 = (*es1->elements)[i]; - Expression *ee2 = (*es2->elements)[i]; - - if (ee1 == ee2) - continue; - if (!ee1 || !ee2) - { cmp = 0; - break; - } - Expression *v = Equal(TOKequal, Type::tint32, ee1, ee2); - if (v == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - cmp = v->toInteger(); - if (cmp == 0) - break; - } - } - } -#if 0 // Should handle this - else if (e1->op == TOKarrayliteral && e2->op == TOKstring) - { - } -#endif - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - cmp = (r1 == r2); -#else - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - cmp = 0; - } - else - { - cmp = (r1 == r2); - } -#endif - } - else if (e1->type->iscomplex()) - { - cmp = e1->toComplex() == e2->toComplex(); - } - else if (e1->type->isintegral() || e1->type->toBasetype()->ty == Tpointer) - { - cmp = (e1->toInteger() == e2->toInteger()); - } - else - return EXP_CANT_INTERPRET; - if (op == TOKnotequal) - cmp ^= 1; - e = new IntegerExp(loc, cmp, type); - return e; -} - -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - int cmp; - - if (e1->op == TOKnull) - { - cmp = (e2->op == TOKnull); - } - else if (e2->op == TOKnull) - { - cmp = 0; - } - else if (e1->op == TOKsymoff && e2->op == TOKsymoff) - { - SymOffExp *es1 = (SymOffExp *)e1; - SymOffExp *es2 = (SymOffExp *)e2; - - cmp = (es1->var == es2->var && es1->offset == es2->offset); - } - else - { - if (e1->type->isreal()) - { - cmp = RealEquals(e1->toReal(), e2->toReal()); - } - else if (e1->type->isimaginary()) - { - cmp = RealEquals(e1->toImaginary(), e2->toImaginary()); - } - else if (e1->type->iscomplex()) - { - complex_t v1 = e1->toComplex(); - complex_t v2 = e2->toComplex(); - cmp = RealEquals(creall(v1), creall(v2)) && - RealEquals(cimagl(v1), cimagl(v1)); - } - else - return Equal((op == TOKidentity) ? TOKequal : TOKnotequal, - type, e1, e2); - } - if (op == TOKnotidentity) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - - -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ Expression *e; - Loc loc = e1->loc; - dinteger_t n; - real_t r1; - real_t r2; - - //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - - if (e1->op == TOKstring && e2->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - size_t sz = es1->sz; - assert(sz == es2->sz); - - size_t len = es1->len; - if (es2->len < len) - len = es2->len; - - int cmp = memcmp(es1->string, es2->string, sz * len); - if (cmp == 0) - cmp = es1->len - es2->len; - - switch (op) - { - case TOKlt: n = cmp < 0; break; - case TOKle: n = cmp <= 0; break; - case TOKgt: n = cmp > 0; break; - case TOKge: n = cmp >= 0; break; - - case TOKleg: n = 1; break; - case TOKlg: n = cmp != 0; break; - case TOKunord: n = 0; break; - case TOKue: n = cmp == 0; break; - case TOKug: n = cmp > 0; break; - case TOKuge: n = cmp >= 0; break; - case TOKul: n = cmp < 0; break; - case TOKule: n = cmp <= 0; break; - - default: - assert(0); - } - } - else if (e1->isConst() != 1 || e2->isConst() != 1) - return EXP_CANT_INTERPRET; - else if (e1->type->isreal()) - { - r1 = e1->toReal(); - r2 = e2->toReal(); - goto L1; - } - else if (e1->type->isimaginary()) - { - r1 = e1->toImaginary(); - r2 = e2->toImaginary(); - L1: -#if __DMC__ - // DMC is the only compiler I know of that handles NAN arguments - // correctly in comparisons. - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = r1 <>= r2; break; - case TOKlg: n = r1 <> r2; break; - case TOKunord: n = r1 !<>= r2; break; - case TOKue: n = r1 !<> r2; break; - case TOKug: n = r1 !<= r2; break; - case TOKuge: n = r1 !< r2; break; - case TOKul: n = r1 !>= r2; break; - case TOKule: n = r1 !> r2; break; - - default: - assert(0); - } -#else - // Don't rely on compiler, handle NAN arguments separately - if (Port::isNan(r1) || Port::isNan(r2)) // if unordered - { - switch (op) - { - case TOKlt: n = 0; break; - case TOKle: n = 0; break; - case TOKgt: n = 0; break; - case TOKge: n = 0; break; - - case TOKleg: n = 0; break; - case TOKlg: n = 0; break; - case TOKunord: n = 1; break; - case TOKue: n = 1; break; - case TOKug: n = 1; break; - case TOKuge: n = 1; break; - case TOKul: n = 1; break; - case TOKule: n = 1; break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = r1 < r2; break; - case TOKle: n = r1 <= r2; break; - case TOKgt: n = r1 > r2; break; - case TOKge: n = r1 >= r2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = r1 != r2; break; - case TOKunord: n = 0; break; - case TOKue: n = r1 == r2; break; - case TOKug: n = r1 > r2; break; - case TOKuge: n = r1 >= r2; break; - case TOKul: n = r1 < r2; break; - case TOKule: n = r1 <= r2; break; - - default: - assert(0); - } - } -#endif - } - else if (e1->type->iscomplex()) - { - assert(0); - } - else - { sinteger_t n1; - sinteger_t n2; - - n1 = e1->toInteger(); - n2 = e2->toInteger(); - if (e1->type->isunsigned() || e2->type->isunsigned()) - { - switch (op) - { - case TOKlt: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKle: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - case TOKgt: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - - case TOKleg: n = 1; break; - case TOKlg: n = ((d_uns64) n1) != ((d_uns64) n2); break; - case TOKunord: n = 0; break; - case TOKue: n = ((d_uns64) n1) == ((d_uns64) n2); break; - case TOKug: n = ((d_uns64) n1) > ((d_uns64) n2); break; - case TOKuge: n = ((d_uns64) n1) >= ((d_uns64) n2); break; - case TOKul: n = ((d_uns64) n1) < ((d_uns64) n2); break; - case TOKule: n = ((d_uns64) n1) <= ((d_uns64) n2); break; - - default: - assert(0); - } - } - else - { - switch (op) - { - case TOKlt: n = n1 < n2; break; - case TOKle: n = n1 <= n2; break; - case TOKgt: n = n1 > n2; break; - case TOKge: n = n1 >= n2; break; - - case TOKleg: n = 1; break; - case TOKlg: n = n1 != n2; break; - case TOKunord: n = 0; break; - case TOKue: n = n1 == n2; break; - case TOKug: n = n1 > n2; break; - case TOKuge: n = n1 >= n2; break; - case TOKul: n = n1 < n2; break; - case TOKule: n = n1 <= n2; break; - - default: - assert(0); - } - } - } - e = new IntegerExp(loc, n, type); - return e; -} - -/* Also returns EXP_CANT_INTERPRET if cannot be computed. - * to: type to cast to - * type: type to paint the result - */ - -Expression *Cast(Type *type, Type *to, Expression *e1) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars()); - //printf("\te1->type = %s\n", e1->type->toChars()); - if (e1->type->equals(type) && type->equals(to)) - return e1; - if (e1->type->implicitConvTo(to) >= MATCHconst || - to->implicitConvTo(e1->type) >= MATCHconst) - return expType(to, e1); - - // Allow covariant converions of delegates - // (Perhaps implicit conversion from pure to impure should be a MATCHconst, - // then we wouldn't need this extra check.) - if (e1->type->toBasetype()->ty == Tdelegate && - e1->type->implicitConvTo(to) == MATCHconvert) - return expType(to, e1); - - Type *tb = to->toBasetype(); - Type *typeb = type->toBasetype(); - - /* Allow casting from one string type to another - */ - if (e1->op == TOKstring) - { - if (tb->ty == Tarray && typeb->ty == Tarray && - tb->nextOf()->size() == typeb->nextOf()->size()) - { - return expType(to, e1); - } - } - - if (e1->op == TOKarrayliteral && typeb == tb) - return e1; - - if (e1->isConst() != 1) - return EXP_CANT_INTERPRET; - - if (tb->ty == Tbool) - e = new IntegerExp(loc, e1->toInteger() != 0, type); - else if (type->isintegral()) - { - if (e1->type->isfloating()) - { dinteger_t result; - real_t r = e1->toReal(); - - switch (typeb->ty) - { - case Tint8: result = (d_int8)r; break; - case Tchar: - case Tuns8: result = (d_uns8)r; break; - case Tint16: result = (d_int16)r; break; - case Twchar: - case Tuns16: result = (d_uns16)r; break; - case Tint32: result = (d_int32)r; break; - case Tdchar: - case Tuns32: result = (d_uns32)r; break; - case Tint64: result = (d_int64)r; break; - case Tuns64: result = (d_uns64)r; break; - default: - assert(0); - } - - e = new IntegerExp(loc, result, type); - } - else if (type->isunsigned()) - e = new IntegerExp(loc, e1->toUInteger(), type); - else - e = new IntegerExp(loc, e1->toInteger(), type); - } - else if (tb->isreal()) - { real_t value = e1->toReal(); - - e = new RealExp(loc, value, type); - } - else if (tb->isimaginary()) - { real_t value = e1->toImaginary(); - - e = new RealExp(loc, value, type); - } - else if (tb->iscomplex()) - { complex_t value = e1->toComplex(); - - e = new ComplexExp(loc, value, type); - } - else if (tb->isscalar()) - e = new IntegerExp(loc, e1->toInteger(), type); - else if (tb->ty == Tvoid) - e = EXP_CANT_INTERPRET; - else if (tb->ty == Tstruct && e1->op == TOKint64) - { // Struct = 0; - StructDeclaration *sd = tb->toDsymbol(NULL)->isStructDeclaration(); - assert(sd); - Expressions *elements = new Expressions; - for (size_t i = 0; i < sd->fields.dim; i++) - { Dsymbol *s = sd->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - Expression *exp = new IntegerExp(0); - exp = Cast(v->type, v->type, exp); - if (exp == EXP_CANT_INTERPRET) - return exp; - elements->push(exp); - } - e = new StructLiteralExp(loc, sd, elements); - e->type = type; - } - else - { - if (type != Type::terror) - error(loc, "cannot cast %s to %s", e1->type->toChars(), type->toChars()); - e = new ErrorExp(); - } - return e; -} - - -Expression *ArrayLength(Type *type, Expression *e1) -{ Expression *e; - Loc loc = e1->loc; - - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - - e = new IntegerExp(loc, es1->len, type); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - size_t dim; - - dim = ale->elements ? ale->elements->dim : 0; - e = new IntegerExp(loc, dim, type); - } - else if (e1->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e1; - size_t dim = ale->keys->dim; - - e = new IntegerExp(loc, dim, type); - } - else - e = EXP_CANT_INTERPRET; - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Index(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - - //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - assert(e1->type); - if (e1->op == TOKstring && e2->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t i = e2->toInteger(); - - if (i >= es1->len) - { - e1->error("string index %ju is out of bounds [0 .. %zu]", i, es1->len); - e = new ErrorExp(); - } - else - { - e = new IntegerExp(loc, es1->charAt(i), 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) - { - e1->error("array index %ju is out of bounds %s[0 .. %ju]", i, e1->toChars(), length); - e = new ErrorExp(); - } - else if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - e = ale->elements->tdata()[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - } - } - else if (e1->type->toBasetype()->ty == Tarray && e2->op == TOKint64) - { - uinteger_t i = e2->toInteger(); - - if (e1->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (i >= ale->elements->dim) - { - e1->error("array index %ju is out of bounds %s[0 .. %u]", i, e1->toChars(), ale->elements->dim); - e = new ErrorExp(); - } - else - { e = ale->elements->tdata()[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - } - } - } - else if (e1->op == TOKassocarrayliteral) - { - 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 = ae->keys->tdata()[i]; - Expression *ex = Equal(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - return ex; - if (ex->isBool(TRUE)) - { e = ae->values->tdata()[i]; - e->type = type; - if (e->hasSideEffect()) - e = EXP_CANT_INTERPRET; - break; - } - } - } - return e; -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - -#if LOG - printf("Slice()\n"); - if (lwr) - { printf("\te1 = %s\n", e1->toChars()); - printf("\tlwr = %s\n", lwr->toChars()); - printf("\tupr = %s\n", upr->toChars()); - } -#endif - if (e1->op == TOKstring && lwr->op == TOKint64 && upr->op == TOKint64) - { StringExp *es1 = (StringExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->len || ilwr > iupr) - { - e1->error("string slice [%ju .. %ju] is out of bounds", ilwr, iupr); - e = new ErrorExp(); - } - else - { - 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->hasSideEffect()) - { ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - uinteger_t ilwr = lwr->toInteger(); - uinteger_t iupr = upr->toInteger(); - - if (iupr > es1->elements->dim || ilwr > iupr) - { - e1->error("array slice [%ju .. %ju] is out of bounds", ilwr, iupr); - e = new ErrorExp(); - } - else - { - Expressions *elements = new Expressions(); - elements->setDim(iupr - ilwr); - memcpy(elements->tdata(), - es1->elements->tdata() + ilwr, - (iupr - ilwr) * sizeof(es1->elements->tdata()[0])); - e = new ArrayLiteralExp(e1->loc, elements); - e->type = type; - } - } - return e; -} - -/* Set a slice of char array literal 'existingAE' from a string 'newval'. - * existingAE[firstIndex..firstIndex+newval.length] = newval. - */ -void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex) -{ - size_t newlen = newval->len; - size_t sz = newval->sz; - unsigned char *s = (unsigned char *)newval->string; - Type *elemType = existingAE->type->nextOf(); - for (size_t j = 0; j < newlen; j++) - { - dinteger_t val; - switch (sz) - { - case 1: val = s[j]; break; - case 2: val = ((unsigned short *)s)[j]; break; - case 4: val = ((unsigned *)s)[j]; break; - default: - assert(0); - break; - } - existingAE->elements->tdata()[j+firstIndex] - = new IntegerExp(newval->loc, val, elemType); - } -} - -/* Set a slice of string 'existingSE' from a char array literal 'newae'. - * existingSE[firstIndex..firstIndex+newae.length] = newae. - */ -void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < newae->elements->dim; j++) - { - unsigned value = (unsigned)(newae->elements->tdata()[j]->toInteger()); - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } -} - -/* Set a slice of string 'existingSE' from a string 'newstr'. - * existingSE[firstIndex..firstIndex+newstr.length] = newstr. - */ -void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex) -{ - unsigned char *s = (unsigned char *)existingSE->string; - size_t sz = existingSE->sz; - assert(sz == newstr->sz); - memcpy(s + firstIndex * sz, newstr->string, sz * newstr->len); -} - -/* Also return EXP_CANT_INTERPRET if this fails - */ -Expression *Cat(Type *type, Expression *e1, Expression *e2) -{ Expression *e = EXP_CANT_INTERPRET; - Loc loc = e1->loc; - Type *t; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - - //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars()); - //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars()); - - if (e1->op == TOKnull && (e2->op == TOKint64 || e2->op == TOKstructliteral)) - { e = e2; - t = t1; - goto L2; - } - else if ((e1->op == TOKint64 || e1->op == TOKstructliteral) && e2->op == TOKnull) - { e = e1; - t = t2; - L2: - Type *tn = e->type->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { - // Create a StringExp - void *s; - StringExp *es; - if (t->nextOf()) - t = t->nextOf()->toBasetype(); - int sz = t->size(); - - dinteger_t v = e->toInteger(); - - size_t len = (t->ty == tn->ty) ? 1 : utf_codeLength(sz, v); - s = mem.malloc((len + 1) * sz); - if (t->ty == tn->ty) - memcpy((unsigned char *)s, &v, sz); - else - utf_encode(sz, s, v); - - // 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 == TOKnull && e2->op == TOKnull) - { - if (type == e1->type) - { - // Handle null ~= null - if (t1->ty == Tarray && t2 == t1->nextOf()) - { - e = new ArrayLiteralExp(e1->loc, e2); - e->type = type; - return e; - } - else - return e1; - } - if (type == e2->type) - return e2; - return new NullExp(e1->loc, type); - } - else if (e1->op == TOKstring && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - size_t len = es1->len + es2->len; - int sz = es1->sz; - - if (sz != es2->sz) - { - /* Can happen with: - * auto s = "foo"d ~ "bar"c; - */ - assert(global.errors); - return e; - } - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - memcpy((unsigned char *)s + es1->len * sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed | es2->committed; - es->type = type; - e = es; - } - else if (e2->op == TOKstring && e1->op == TOKarrayliteral && - t1->nextOf()->isintegral()) - { - // [chars] ~ string --> [chars] - StringExp *es = (StringExp *)e2; - ArrayLiteralExp *ea = (ArrayLiteralExp *)e1; - size_t len = es->len + ea->elements->dim; - Expressions * elems = new Expressions; - elems->setDim(len); - for (size_t i= 0; i < ea->elements->dim; ++i) - { - elems->tdata()[i] = ea->elements->tdata()[i]; - } - ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); - dest->type = type; - sliceAssignArrayLiteralFromString(dest, es, ea->elements->dim); - return dest; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral && - t2->nextOf()->isintegral()) - { - // string ~ [chars] --> [chars] - StringExp *es = (StringExp *)e1; - ArrayLiteralExp *ea = (ArrayLiteralExp *)e2; - size_t len = es->len + ea->elements->dim; - Expressions * elems = new Expressions; - elems->setDim(len); - for (size_t i= 0; i < ea->elements->dim; ++i) - { - elems->tdata()[es->len + i] = ea->elements->tdata()[i]; - } - ArrayLiteralExp *dest = new ArrayLiteralExp(e1->loc, elems); - dest->type = type; - sliceAssignArrayLiteralFromString(dest, es, 0); - return dest; - } - else if (e1->op == TOKstring && e2->op == TOKint64) - { - // string ~ char --> string - void *s; - StringExp *es1 = (StringExp *)e1; - StringExp *es; - int sz = es1->sz; - dinteger_t v = e2->toInteger(); - - // Is it a concatentation of homogenous types? - // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) - bool homoConcat = (sz == t2->size()); - size_t len = es1->len; - len += homoConcat ? 1 : utf_codeLength(sz, v); - - s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - if (homoConcat) - memcpy((unsigned char *)s + (sz * es1->len), &v, sz); - else - utf_encode(sz, (unsigned char *)s + (sz * es1->len), v); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es1->committed; - es->type = type; - e = es; - } - else if (e1->op == TOKint64 && e2->op == TOKstring) - { - // Concatenate the strings - void *s; - StringExp *es2 = (StringExp *)e2; - StringExp *es; - size_t len = 1 + es2->len; - int sz = es2->sz; - dinteger_t v = e1->toInteger(); - - s = mem.malloc((len + 1) * sz); - memcpy((unsigned char *)s, &v, sz); - memcpy((unsigned char *)s + sz, es2->string, es2->len * sz); - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = es2->committed; - es->type = type; - e = es; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - // Concatenate the arrays - ArrayLiteralExp *es1 = (ArrayLiteralExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->insert(es1->elements->dim, es2->elements); - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKarrayliteral && e2->op == TOKnull && - t1->nextOf()->equals(t2->nextOf())) - { - e = e1; - goto L3; - } - else if (e1->op == TOKnull && e2->op == TOKarrayliteral && - t1->nextOf()->equals(t2->nextOf())) - { - e = e2; - L3: - // Concatenate the array with null - ArrayLiteralExp *es = (ArrayLiteralExp *)e; - - es = new ArrayLiteralExp(es->loc, (Expressions *)es->elements->copy()); - e = es; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(t1->nextOf(), new IntegerExp(loc, es->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if ((e1->op == TOKarrayliteral || e1->op == TOKnull) && - e1->type->toBasetype()->nextOf()->equals(e2->type)) - { - ArrayLiteralExp *es1; - if (e1->op == TOKarrayliteral) - { es1 = (ArrayLiteralExp *)e1; - es1 = new ArrayLiteralExp(es1->loc, (Expressions *)es1->elements->copy()); - es1->elements->push(e2); - } - else - { - es1 = new ArrayLiteralExp(e1->loc, e2); - } - e = es1; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e2->type, new IntegerExp(loc, es1->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e2->op == TOKarrayliteral && - e2->type->toBasetype()->nextOf()->equals(e1->type)) - { - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - - es2 = new ArrayLiteralExp(es2->loc, (Expressions *)es2->elements->copy()); - es2->elements->shift(e1); - e = es2; - - if (type->toBasetype()->ty == Tsarray) - { - e->type = new TypeSArray(e1->type, new IntegerExp(loc, es2->elements->dim, Type::tindex)); - e->type = e->type->semantic(loc, NULL); - } - else - e->type = type; - } - else if (e1->op == TOKnull && e2->op == TOKstring) - { - t = e1->type; - e = e2; - goto L1; - } - else if (e1->op == TOKstring && e2->op == TOKnull) - { e = e1; - t = e2->type; - L1: - Type *tb = t->toBasetype(); - if (tb->ty == Tarray && tb->nextOf()->equals(e->type)) - { Expressions *expressions = new Expressions(); - expressions->push(e); - e = new ArrayLiteralExp(loc, expressions); - e->type = t; - } - if (!e->type->equals(type)) - { StringExp *se = (StringExp *)e->copy(); - e = se->castTo(NULL, type); - } - } - return e; -} - -Expression *Ptr(Type *type, Expression *e1) -{ - //printf("Ptr(e1 = %s)\n", e1->toChars()); - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - if (ade->e1->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ade->e1; - unsigned offset = ae->e2->toInteger(); - Expression *e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - } - return EXP_CANT_INTERPRET; -} - diff --git a/dmd2/cppmangle.c b/dmd2/cppmangle.c deleted file mode 100644 index 630567ef..00000000 --- a/dmd2/cppmangle.c +++ /dev/null @@ -1,454 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" - -#if CPP_MANGLE - -/* Do mangling for C++ linkage. - * Follows Itanium C++ ABI 1.86 - * No attempt is made to support mangling of templates, operator - * overloading, or special functions. - * - * So why don't we use the C++ ABI for D name mangling? - * Because D supports a lot of things (like modules) that the C++ - * ABI has no concept of. These affect every D mangled name, - * so nothing would be compatible anyway. - */ - -struct CppMangleState -{ - static Voids components; - - int substitute(OutBuffer *buf, void *p); - int exist(void *p); - void store(void *p); -}; - -Voids CppMangleState::components; - - -void writeBase36(OutBuffer *buf, unsigned i) -{ - if (i >= 36) - { - writeBase36(buf, i / 36); - i %= 36; - } - if (i < 10) - buf->writeByte(i + '0'); - else if (i < 36) - buf->writeByte(i - 10 + 'A'); - else - assert(0); -} - -int CppMangleState::substitute(OutBuffer *buf, void *p) -{ - for (size_t i = 0; i < components.dim; i++) - { - if (p == components.tdata()[i]) - { - /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... - */ - buf->writeByte('S'); - if (i) - writeBase36(buf, i - 1); - buf->writeByte('_'); - return 1; - } - } - components.push(p); - return 0; -} - -int CppMangleState::exist(void *p) -{ - for (size_t i = 0; i < components.dim; i++) - { - if (p == components.tdata()[i]) - { - return 1; - } - } - return 0; -} - -void CppMangleState::store(void *p) -{ - components.push(p); -} - -void source_name(OutBuffer *buf, Dsymbol *s) -{ - char *name = s->ident->toChars(); - buf->printf("%d%s", strlen(name), name); -} - -void prefix_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) -{ - if (!cms->substitute(buf, s)) - { - Dsymbol *p = s->toParent(); - if (p && !p->isModule()) - { - prefix_name(buf, cms, p); - } - source_name(buf, s); - } -} - -void cpp_mangle_name(OutBuffer *buf, CppMangleState *cms, Dsymbol *s) -{ - Dsymbol *p = s->toParent(); - if (p && !p->isModule()) - { - buf->writeByte('N'); - - FuncDeclaration *fd = s->isFuncDeclaration(); - if (!fd) - { - s->error("C++ static variables not supported"); - } - else - if (fd->isConst()) - buf->writeByte('K'); - - prefix_name(buf, cms, p); - source_name(buf, s); - - buf->writeByte('E'); - } - else - source_name(buf, s); -} - - -char *cpp_mangle(Dsymbol *s) -{ - /* - * ::= _Z - * ::= - * ::= - * ::= - */ - - CppMangleState cms; - memset(&cms, 0, sizeof(cms)); - cms.components.setDim(0); - - OutBuffer buf; -#if MACHOBJ - buf.writestring("__Z"); -#else - buf.writestring("_Z"); -#endif - - cpp_mangle_name(&buf, &cms, s); - - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { // add - TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - Parameter::argsCppMangle(&buf, &cms, tf->parameters, tf->varargs); - } - buf.writeByte(0); - return (char *)buf.extractData(); -} - -/* ============= Type Encodings ============================================= */ - -void Type::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - /* Make this the 'vendor extended type' when there is no - * C++ analog. - * u - */ - if (!cms->substitute(buf, this)) - { assert(deco); - buf->printf("u%d%s", strlen(deco), deco); - } -} - -void TypeBasic::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ char c; - char p = 0; - - /* ABI spec says: - * v void - * w wchar_t - * b bool - * c char - * a signed char - * h unsigned char - * s short - * t unsigned short - * i int - * j unsigned int - * l long - * m unsigned long - * x long long, __int64 - * y unsigned long long, __int64 - * n __int128 - * o unsigned __int128 - * f float - * d double - * e long double, __float80 - * g __float128 - * z ellipsis - * u # vendor extended type - */ - - switch (ty) - { - case Tvoid: c = 'v'; break; - case Tint8: c = 'a'; break; - case Tuns8: c = 'h'; break; - case Tint16: c = 's'; break; - case Tuns16: c = 't'; break; - case Tint32: c = 'i'; break; - case Tuns32: c = 'j'; break; - case Tfloat32: c = 'f'; break; - case Tint64: c = 'x'; break; - case Tuns64: c = 'y'; break; - case Tfloat64: c = 'd'; break; - case Tfloat80: c = 'e'; break; - case Tbool: c = 'b'; break; - case Tchar: c = 'c'; break; - case Twchar: c = 't'; break; - case Tdchar: c = 'w'; break; - - case Timaginary32: p = 'G'; c = 'f'; break; - case Timaginary64: p = 'G'; c = 'd'; break; - case Timaginary80: p = 'G'; c = 'e'; break; - case Tcomplex32: p = 'C'; c = 'f'; break; - case Tcomplex64: p = 'C'; c = 'd'; break; - case Tcomplex80: p = 'C'; c = 'e'; break; - - default: assert(0); - } - if (p || isConst()) - { - if (cms->substitute(buf, this)) - return; - } - - if (isConst()) - buf->writeByte('K'); - - if (p) - buf->writeByte(p); - - buf->writeByte(c); -} - - -void TypeVector::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->writestring("U8__vector"); - basetype->toCppMangle(buf, cms); - } -} - -void TypeSArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->printf("A%ju_", dim ? dim->toInteger() : 0); - next->toCppMangle(buf, cms); - } -} - -void TypeDArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeAArray::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypePointer::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->exist(this)) - { buf->writeByte('P'); - next->toCppMangle(buf, cms); - cms->store(this); - } - else - cms->substitute(buf, this); -} - - -void TypeReference::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->exist(this)) - { buf->writeByte('R'); - next->toCppMangle(buf, cms); - cms->store(this); - } - else - cms->substitute(buf, this); -} - - -void TypeFunction::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ /* - * ::= F [Y] E - * ::= + - * # types are possible return type, then parameter types - */ - - /* ABI says: - "The type of a non-static member function is considered to be different, - for the purposes of substitution, from the type of a namespace-scope or - static member function whose type appears similar. The types of two - non-static member functions are considered to be different, for the - purposes of substitution, if the functions are members of different - classes. In other words, for the purposes of substitution, the class of - which the function is a member is considered part of the type of - function." - - BUG: Right now, types of functions are never merged, so our simplistic - component matcher always finds them to be different. - We should use Type::equals on these, and use different - TypeFunctions for non-static member functions, and non-static - member functions of different classes. - */ - if (!cms->substitute(buf, this)) - { - buf->writeByte('F'); - if (linkage == LINKc) - buf->writeByte('Y'); - next->toCppMangle(buf, cms); - Parameter::argsCppMangle(buf, cms, parameters, varargs); - buf->writeByte('E'); - } -} - - -void TypeDelegate::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeStruct::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->exist(this)) - { - if (isConst()) - buf->writeByte('K'); - - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); - - if (isConst()) - cms->store(this); - } - else - cms->substitute(buf, this); -} - - -void TypeEnum::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->exist(this)) - { - if (isConst()) - buf->writeByte('K'); - - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); - - if (isConst()) - cms->store(this); - } - else - cms->substitute(buf, this); -} - - -void TypeTypedef::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - Type::toCppMangle(buf, cms); -} - - -void TypeClass::toCppMangle(OutBuffer *buf, CppMangleState *cms) -{ - if (!cms->substitute(buf, this)) - { buf->writeByte('P'); - if (!cms->substitute(buf, sym)) - cpp_mangle_name(buf, cms, sym); - } -} - - - -void Parameter::argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs) -{ int n = 0; - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; - Type *t = arg->type; - if (arg->storageClass & (STCout | STCref)) - t = t->referenceTo(); - else if (arg->storageClass & STClazy) - { // Mangle as delegate - Type *td = new TypeFunction(NULL, t, 0, LINKd); - td = new TypeDelegate(td); - t = t->merge(); - } - if (t->ty == Tsarray) - { // Mangle static arrays as pointers - t = t->pointerTo(); - } - - /* If it is a basic, enum or struct type, - * then don't mark it const - */ - if ((t->ty == Tenum || t->ty == Tstruct || t->isTypeBasic()) && t->isConst()) - t->mutableOf()->toCppMangle(buf, cms); - else - t->toCppMangle(buf, cms); - - n++; - } - } - if (varargs) - buf->writestring("z"); - else if (!n) - buf->writeByte('v'); // encode ( ) arguments -} - - -#endif - diff --git a/dmd2/declaration.c b/dmd2/declaration.c deleted file mode 100644 index 6f7c3558..00000000 --- a/dmd2/declaration.c +++ /dev/null @@ -1,2327 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "mtype.h" -#include "template.h" -#include "scope.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "expression.h" -#include "statement.h" -#include "hdrgen.h" - -/********************************* Declaration ****************************/ - -Declaration::Declaration(Identifier *id) - : Dsymbol(id) -{ - type = NULL; - originalType = NULL; - storage_class = STCundefined; - protection = PROTundefined; - linkage = LINKdefault; - inuse = 0; - sem = SemanticStart; -} - -void Declaration::semantic(Scope *sc) -{ -} - -const char *Declaration::kind() -{ - return "declaration"; -} - -unsigned Declaration::size(Loc loc) -{ - assert(type); - return type->size(); -} - -int Declaration::isDelete() -{ - return FALSE; -} - -int Declaration::isDataseg() -{ - return FALSE; -} - -int Declaration::isThreadlocal() -{ - return FALSE; -} - -int Declaration::isCodeseg() -{ - return FALSE; -} - -enum PROT Declaration::prot() -{ - return protection; -} - -/************************************* - * Check to see if declaration can be modified in this context (sc). - * Issue error if not. - */ - -#if DMDV2 - -void Declaration::checkModify(Loc loc, Scope *sc, Type *t) -{ - if (sc->incontract && isParameter()) - error(loc, "cannot modify parameter '%s' in contract", toChars()); - - if (sc->incontract && isResult()) - error(loc, "cannot modify result '%s' in contract", toChars()); - - if (isCtorinit() && !t->isMutable() || - (storage_class & STCnodefaultctor)) - { // It's only modifiable if inside the right constructor - modifyFieldVar(loc, sc, isVarDeclaration(), NULL); - } - else - { - VarDeclaration *v = isVarDeclaration(); - if (v && v->canassign == 0) - { - const char *p = NULL; - if (isConst()) - p = "const"; - else if (isImmutable()) - p = "immutable"; - else if (isWild()) - p = "inout"; - else if (storage_class & STCmanifest) - p = "enum"; - else if (!t->isAssignable()) - p = "struct with immutable members"; - if (p) - { error(loc, "cannot modify %s", p); - } - } - } -} -#endif - - -/********************************* TupleDeclaration ****************************/ - -TupleDeclaration::TupleDeclaration(Loc loc, Identifier *id, Objects *objects) - : Declaration(id) -{ - this->loc = loc; - this->type = NULL; - this->objects = objects; - this->isexp = 0; - this->tupletype = NULL; -} - -Dsymbol *TupleDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); - return NULL; -} - -const char *TupleDeclaration::kind() -{ - return "tuple"; -} - -Type *TupleDeclaration::getType() -{ - /* If this tuple represents a type, return that type - */ - - //printf("TupleDeclaration::getType() %s\n", toChars()); - if (isexp) - return NULL; - if (!tupletype) - { - /* It's only a type tuple if all the Object's are types - */ - for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; - - if (o->dyncast() != DYNCAST_TYPE) - { - //printf("\tnot[%d], %p, %d\n", i, o, o->dyncast()); - return NULL; - } - } - - /* We know it's a type tuple, so build the TypeTuple - */ - Types *types = (Types *)objects; - Parameters *args = new Parameters(); - args->setDim(objects->dim); - OutBuffer buf; - int hasdeco = 1; - for (size_t i = 0; i < types->dim; i++) - { Type *t = types->tdata()[i]; - - //printf("type = %s\n", t->toChars()); -#if 0 - buf.printf("_%s_%d", ident->toChars(), i); - char *name = (char *)buf.extractData(); - Identifier *id = new Identifier(name, TOKidentifier); - Parameter *arg = new Parameter(STCin, t, id, NULL); -#else - Parameter *arg = new Parameter(0, t, NULL, NULL); -#endif - args->tdata()[i] = arg; - if (!t->deco) - hasdeco = 0; - } - - tupletype = new TypeTuple(args); - if (hasdeco) - return tupletype->semantic(0, NULL); - } - - return tupletype; -} - -int TupleDeclaration::needThis() -{ - //printf("TupleDeclaration::needThis(%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = objects->tdata()[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - if (d && d->needThis()) - { - return 1; - } - } - } - } - return 0; -} - -#if IN_LLVM - -void TupleDeclaration::semantic3(Scope *sc) -{ - //printf("TupleDeclaration::semantic3((%s)\n", toChars()); - for (size_t i = 0; i < objects->dim; i++) - { Object *o = (Object *)objects->data[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - { DsymbolExp *ve = (DsymbolExp *)e; - Declaration *d = ve->s->isDeclaration(); - d->semantic3(sc); - } - } - } -} - -#endif - -/********************************* TypedefDeclaration ****************************/ - -TypedefDeclaration::TypedefDeclaration(Loc loc, Identifier *id, Type *basetype, Initializer *init) - : Declaration(id) -{ - this->type = new TypeTypedef(this); - this->basetype = basetype->toBasetype(); - this->init = init; - this->htype = NULL; - this->hbasetype = NULL; - this->loc = loc; -#if IN_DMD - this->sinit = NULL; -#endif -} - -Dsymbol *TypedefDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *basetype = this->basetype->syntaxCopy(); - - Initializer *init = NULL; - if (this->init) - init = this->init->syntaxCopy(); - - assert(!s); - TypedefDeclaration *st; - st = new TypedefDeclaration(loc, ident, basetype, init); - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - st->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - st->htype = htype->syntaxCopy(); - if (!hbasetype) - { if (basetype) - { hbasetype = basetype->syntaxCopy(); - st->hbasetype = basetype->syntaxCopy(); - } - } - else - st->hbasetype = hbasetype->syntaxCopy(); - - return st; -} - -void TypedefDeclaration::semantic(Scope *sc) -{ - //printf("TypedefDeclaration::semantic(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticStart) - { sem = SemanticIn; - parent = sc->parent; - int errors = global.errors; - Type *savedbasetype = basetype; - basetype = basetype->semantic(loc, sc); - if (errors != global.errors) - { - basetype = savedbasetype; - sem = SemanticStart; - return; - } - sem = SemanticDone; -#if DMDV2 - type = type->addStorageClass(storage_class); -#endif - Type *savedtype = type; - type = type->semantic(loc, sc); - if (sc->parent->isFuncDeclaration() && init) - semantic2(sc); - if (errors != global.errors) - { - basetype = savedbasetype; - type = savedtype; - sem = SemanticStart; - return; - } - storage_class |= sc->stc & STCdeprecated; - } - else if (sem == SemanticIn) - { - error("circular definition"); - } -} - -void TypedefDeclaration::semantic2(Scope *sc) -{ - //printf("TypedefDeclaration::semantic2(%s) sem = %d\n", toChars(), sem); - if (sem == SemanticDone) - { sem = Semantic2Done; - if (init) - { - Initializer *savedinit = init; - int errors = global.errors; - init = init->semantic(sc, basetype, WANTinterpret); - if (errors != global.errors) - { - init = savedinit; - return; - } - - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - { - if (ie->exp->type == basetype) - ie->exp->type = type; - } - } - } -} - -const char *TypedefDeclaration::kind() -{ - return "typedef"; -} - -Type *TypedefDeclaration::getType() -{ - return type; -} - -void TypedefDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typedef "); - basetype->toCBuffer(buf, ident, hgs); - if (init) - { - buf->writestring(" = "); - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* AliasDeclaration ****************************/ - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Type *type) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("type = '%s'\n", type->toChars()); - this->loc = loc; - this->type = type; - this->aliassym = NULL; - this->htype = NULL; - this->haliassym = NULL; - this->overnext = NULL; - this->inSemantic = 0; - this->importprot = PROTundefined; - assert(type); -} - -AliasDeclaration::AliasDeclaration(Loc loc, Identifier *id, Dsymbol *s) - : Declaration(id) -{ - //printf("AliasDeclaration(id = '%s', s = %p)\n", id->toChars(), s); - assert(s != this); - this->loc = loc; - this->type = NULL; - this->aliassym = s; - this->htype = NULL; - this->haliassym = NULL; - this->overnext = NULL; - this->inSemantic = 0; - assert(s); -} - -Dsymbol *AliasDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("AliasDeclaration::syntaxCopy()\n"); - assert(!s); - AliasDeclaration *sa; - if (type) - sa = new AliasDeclaration(loc, ident, type->syntaxCopy()); - else - sa = new AliasDeclaration(loc, ident, aliassym->syntaxCopy(NULL)); - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sa->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sa->htype = htype->syntaxCopy(); - if (!haliassym) - { if (aliassym) - { haliassym = aliassym->syntaxCopy(s); - sa->haliassym = aliassym->syntaxCopy(s); - } - } - else - sa->haliassym = haliassym->syntaxCopy(s); - - return sa; -} - -void AliasDeclaration::semantic(Scope *sc) -{ - //printf("AliasDeclaration::semantic() %s\n", toChars()); - if (aliassym) - { - if (aliassym->isTemplateInstance()) - aliassym->semantic(sc); - return; - } - this->inSemantic = 1; - -#if DMDV1 // don't really know why this is here - if (storage_class & STCconst) - error("cannot be const"); -#endif - - storage_class |= sc->stc & STCdeprecated; - protection = sc->protection; - - // Given: - // alias foo.bar.abc def; - // it is not knowable from the syntax whether this is an alias - // for a type or an alias for a symbol. It is up to the semantic() - // pass to distinguish. - // If it is a type, then type is set and getType() will return that - // type. If it is a symbol, then aliassym is set and type is NULL - - // toAlias() will return aliasssym. - - int errors = global.errors; - Type *savedtype = type; - - Dsymbol *s; - Type *t; - Expression *e; - - /* This section is needed because resolve() will: - * const x = 3; - * alias x y; - * try to alias y to 3. - */ - s = type->toDsymbol(sc); - if (s -#if DMDV2 - && ((s->getType() && type->equals(s->getType())) || s->isEnumMember()) -#endif - ) - goto L2; // it's a symbolic alias - -#if DMDV2 - type = type->addStorageClass(storage_class); - if (storage_class & (STCref | STCnothrow | STCpure | STCdisable)) - { // For 'ref' to be attached to function types, and picked - // up by Type::resolve(), it has to go into sc. - sc = sc->push(); - sc->stc |= storage_class & (STCref | STCnothrow | STCpure | STCshared | STCdisable); - type->resolve(loc, sc, &e, &t, &s); - sc = sc->pop(); - } - else -#endif - type->resolve(loc, sc, &e, &t, &s); - if (s) - { - goto L2; - } - else if (e) - { - // Try to convert Expression to Dsymbol - s = getDsymbol(e); - if (s) - goto L2; - - error("cannot alias an expression %s", e->toChars()); - t = e->type; - } - else if (t) - { - type = t->semantic(loc, sc); - //printf("\talias resolved to type %s\n", type->toChars()); - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - this->inSemantic = 0; - - if (errors != global.errors) - type = savedtype; - return; - - L2: - //printf("alias is a symbol %s %s\n", s->kind(), s->toChars()); - type = NULL; - VarDeclaration *v = s->isVarDeclaration(); - if (0 && v && v->linkage == LINKdefault) - { - error("forward reference of %s", v->toChars()); - s = NULL; - } - else - { - Dsymbol *savedovernext = overnext; - FuncDeclaration *f = s->toAlias()->isFuncDeclaration(); - if (f) - { - if (overnext) - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); -#if IN_LLVM - fa->importprot = importprot; -#endif - if (!fa->overloadInsert(overnext)) - ScopeDsymbol::multiplyDefined(0, f, overnext); - overnext = NULL; - s = fa; - s->parent = sc->parent; - } - } - if (overnext) - ScopeDsymbol::multiplyDefined(0, this, overnext); - if (s == this) - { - assert(global.errors); - s = NULL; - } - if (errors != global.errors) - { - type = savedtype; - overnext = savedovernext; - aliassym = NULL; - inSemantic = 0; - return; - } - } - //printf("setting aliassym %s to %s %s\n", toChars(), s->kind(), s->toChars()); - aliassym = s; - this->inSemantic = 0; -} - -int AliasDeclaration::overloadInsert(Dsymbol *s) -{ - /* Don't know yet what the aliased symbol is, so assume it can - * be overloaded and check later for correctness. - */ - - //printf("AliasDeclaration::overloadInsert('%s')\n", s->toChars()); - if (aliassym) // see test/test56.d - { - Dsymbol *a = aliassym->toAlias(); - FuncDeclaration *f = a->isFuncDeclaration(); - if (f) // BUG: what if it's a template? - { - FuncAliasDeclaration *fa = new FuncAliasDeclaration(f); - aliassym = fa; - return fa->overloadInsert(s); - } - } - - if (overnext == NULL) - { - if (s == this) - { - return TRUE; - } - overnext = s; - return TRUE; - } - else - { - return overnext->overloadInsert(s); - } -} - -const char *AliasDeclaration::kind() -{ - return "alias"; -} - -Type *AliasDeclaration::getType() -{ - return type; -} - -Dsymbol *AliasDeclaration::toAlias() -{ - //printf("AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s')\n", toChars(), this, aliassym, aliassym ? aliassym->kind() : ""); - assert(this != aliassym); - //static int count; if (++count == 10) *(char*)0=0; - if (inSemantic) - { error("recursive alias declaration"); - aliassym = new AliasDeclaration(loc, ident, Type::terror); - type = Type::terror; - } - else if (!aliassym && scope) - semantic(scope); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void AliasDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); -#if 0 - if (hgs->hdrgen) - { - if (haliassym) - { - buf->writestring(haliassym->toChars()); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - htype->toCBuffer(buf, ident, hgs); - } - else -#endif - { - if (aliassym) - { -#if !IN_LLVM - aliassym->toCBuffer(buf, hgs); -#else - buf->writestring(aliassym->toChars()); -#endif - buf->writeByte(' '); - buf->writestring(ident->toChars()); - } - else - type->toCBuffer(buf, ident, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -/********************************* VarDeclaration ****************************/ - -VarDeclaration::VarDeclaration(Loc loc, Type *type, Identifier *id, Initializer *init) - : Declaration(id) -{ - //printf("VarDeclaration('%s')\n", id->toChars()); -#ifdef DEBUG - if (!type && !init) - { printf("VarDeclaration('%s')\n", id->toChars()); - //*(char*)0=0; - } -#endif - assert(type || init); - this->type = type; - this->init = init; - this->htype = NULL; - this->hinit = NULL; - this->loc = loc; - offset = 0; - noscope = 0; -#if DMDV2 - isargptr = FALSE; -#endif -#if DMDV1 - nestedref = 0; -#endif - ctorinit = 0; - aliassym = NULL; - onstack = 0; - canassign = 0; - ctfeAdrOnStack = (size_t)(-1); -#if DMDV2 - rundtor = NULL; - edtor = NULL; -#endif -#if IN_LLVM - aggrIndex = 0; - - nakedUse = false; - - availableExternally = true; // assume this unless proven otherwise -#endif -} - -Dsymbol *VarDeclaration::syntaxCopy(Dsymbol *s) -{ - //printf("VarDeclaration::syntaxCopy(%s)\n", toChars()); - - VarDeclaration *sv; - if (s) - { sv = (VarDeclaration *)s; - } - else - { - Initializer *init = NULL; - if (this->init) - { init = this->init->syntaxCopy(); - //init->isExpInitializer()->exp->print(); - //init->isExpInitializer()->exp->dump(0); - } - - sv = new VarDeclaration(loc, type ? type->syntaxCopy() : NULL, ident, init); - sv->storage_class = storage_class; - } - - // Syntax copy for header file - if (!htype) // Don't overwrite original - { if (type) // Make copy for both old and new instances - { htype = type->syntaxCopy(); - sv->htype = type->syntaxCopy(); - } - } - else // Make copy of original for new instance - sv->htype = htype->syntaxCopy(); - if (!hinit) - { if (init) - { hinit = init->syntaxCopy(); - sv->hinit = init->syntaxCopy(); - } - } - else - sv->hinit = hinit->syntaxCopy(); - - return sv; -} - -void VarDeclaration::semantic(Scope *sc) -{ -#if 0 - printf("VarDeclaration::semantic('%s', parent = '%s')\n", toChars(), sc->parent->toChars()); - printf(" type = %s\n", type ? type->toChars() : "null"); - printf(" stc = x%x\n", sc->stc); - printf(" storage_class = x%llx\n", storage_class); - printf("linkage = %d\n", sc->linkage); - //if (strcmp(toChars(), "mul") == 0) halt(); -#endif - -// if (sem > SemanticStart) -// return; -// sem = SemanticIn; - - if (scope) - { sc = scope; - scope = NULL; - } - - /* Pick up storage classes from context, but skip synchronized - */ - storage_class |= (sc->stc & ~STCsynchronized); - if (storage_class & STCextern && init) - error("extern symbols cannot have initializers"); - - AggregateDeclaration *ad = isThis(); - if (ad) - storage_class |= ad->storage_class & STC_TYPECTOR; - - /* If auto type inference, do the inference - */ - int inferred = 0; - if (!type) - { inuse++; - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai) - { Expression *e; - if (ai->isAssociativeArray()) - e = ai->toAssocArrayLiteral(); - else - e = init->toExpression(); - if (!e) - { - error("cannot infer type from initializer"); - e = new ErrorExp(); - } - init = new ExpInitializer(e->loc, e); - type = init->inferType(sc); - if (type->ty == Tsarray) - type = type->nextOf()->arrayOf(); - } - else - type = init->inferType(sc); - -//printf("test2: %s, %s, %s\n", toChars(), type->toChars(), type->deco); -// type = type->semantic(loc, sc); - - inuse--; - inferred = 1; - - if (init->isArrayInitializer() && type->toBasetype()->ty == Tsarray) - { // Prefer array literals to give a T[] type rather than a T[dim] - type = type->toBasetype()->nextOf()->arrayOf(); - } - - /* This is a kludge to support the existing syntax for RAII - * declarations. - */ - storage_class &= ~STCauto; - originalType = type; - } - else - { if (!originalType) - originalType = type; - type = type->semantic(loc, sc); - } - //printf(" semantic type = %s\n", type ? type->toChars() : "null"); - - type->checkDeprecated(loc, sc); - linkage = sc->linkage; - this->parent = sc->parent; - //printf("this = %p, parent = %p, '%s'\n", this, parent, parent->toChars()); - protection = sc->protection; - //printf("sc->stc = %x\n", sc->stc); - //printf("storage_class = x%x\n", storage_class); - -#if DMDV2 - // Safety checks - if (sc->func && !sc->intypeof) - { - if (storage_class & STCgshared) - { - if (sc->func->setUnsafe()) - error("__gshared not allowed in safe functions; use shared"); - } - if (init && init->isVoidInitializer() && type->hasPointers()) - { - if (sc->func->setUnsafe()) - error("void initializers for pointers not allowed in safe functions"); - } - if (type->hasPointers() && type->toDsymbol(sc)) - { - Dsymbol *s = type->toDsymbol(sc); - if (s) - { - AggregateDeclaration *ad2 = s->isAggregateDeclaration(); - if (ad2 && ad2->hasUnions) - { - if (sc->func->setUnsafe()) - error("unions containing pointers are not allowed in @safe functions"); - } - } - } - } -#endif - - Dsymbol *parent = toParent(); - FuncDeclaration *fd = parent->isFuncDeclaration(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tvoid && !(storage_class & STClazy)) - { error("voids have no value"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tfunction) - { error("cannot be declared to be a function"); - type = Type::terror; - tb = type; - } - if (tb->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tb; - - if (!ts->sym->members) - { - error("no definition of struct %s", ts->toChars()); - } - } - if ((storage_class & STCauto) && !inferred) - error("storage class 'auto' has no effect if type is not inferred, did you mean 'scope'?"); - - if (tb->ty == Ttuple) - { /* Instead, declare variables for each of the tuple elements - * and add those. - */ - TypeTuple *tt = (TypeTuple *)tb; - size_t nelems = Parameter::dim(tt->arguments); - Objects *exps = new Objects(); - exps->setDim(nelems); - Expression *ie = init ? init->toExpression() : NULL; - if (ie) ie = ie->semantic(sc); - - if (nelems > 0 && ie) - { - Expressions *iexps = new Expressions(); - iexps->push(ie); - - Expressions *exps = new Expressions(); - - for (size_t pos = 0; pos < iexps->dim; pos++) - { - Lexpand1: - Expression *e = iexps->tdata()[pos]; - Parameter *arg = Parameter::getNth(tt->arguments, pos); - arg->type = arg->type->semantic(loc, sc); - //printf("[%d] iexps->dim = %d, ", pos, iexps->dim); - //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars()); - //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); - - if (e != ie) - { - if (iexps->dim > nelems) - goto Lnomatch; - if (e->type->implicitConvTo(arg->type)) - continue; - } - - if (e->op == TOKtuple) - { - TupleExp *te = (TupleExp *)e; - if (iexps->dim - 1 + te->exps->dim > nelems) - goto Lnomatch; - - iexps->remove(pos); - iexps->insert(pos, te->exps); - goto Lexpand1; - } - else if (isAliasThisTuple(e)) - { - Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e->loc, e); - VarDeclaration *v = new VarDeclaration(loc, NULL, id, ei); - v->storage_class = STCctfe | STCref | STCforeach; - VarExp *ve = new VarExp(loc, v); - ve->type = e->type; - - exps->setDim(1); - (*exps)[0] = ve; - expandAliasThisTuples(exps, 0); - - for (size_t u = 0; u < exps->dim ; u++) - { - Lexpand2: - Expression *ee = (*exps)[u]; - Parameter *arg = Parameter::getNth(tt->arguments, pos + u); - arg->type = arg->type->semantic(loc, sc); - //printf("[%d+%d] exps->dim = %d, ", pos, u, exps->dim); - //printf("ee = (%s %s, %s), ", Token::tochars[ee->op], ee->toChars(), ee->type->toChars()); - //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); - - size_t iexps_dim = iexps->dim - 1 + exps->dim; - if (iexps_dim > nelems) - goto Lnomatch; - if (ee->type->implicitConvTo(arg->type)) - continue; - - if (expandAliasThisTuples(exps, u) != -1) - goto Lexpand2; - } - - if ((*exps)[0] != ve) - { - Expression *e0 = (*exps)[0]; - (*exps)[0] = new CommaExp(loc, new DeclarationExp(loc, v), e0); - (*exps)[0]->type = e0->type; - - iexps->remove(pos); - iexps->insert(pos, exps); - goto Lexpand1; - } - } - } - if (iexps->dim < nelems) - goto Lnomatch; - - ie = new TupleExp(init->loc, iexps); - } -Lnomatch: - - if (ie && ie->op == TOKtuple) - { size_t tedim = ((TupleExp *)ie)->exps->dim; - if (tedim != nelems) - { ::error(loc, "tuple of %d elements cannot be assigned to tuple of %d elements", (int)tedim, (int)nelems); - for (size_t u = tedim; u < nelems; u++) // fill dummy expression - ((TupleExp *)ie)->exps->push(new ErrorExp()); - } - } - - for (size_t i = 0; i < nelems; i++) - { Parameter *arg = Parameter::getNth(tt->arguments, i); - - OutBuffer buf; - buf.printf("_%s_field_%zu", ident->toChars(), i); - buf.writeByte(0); - const char *name = (const char *)buf.extractData(); - Identifier *id = Lexer::idPool(name); - - Expression *einit = ie; - if (ie && ie->op == TOKtuple) - { einit = ((TupleExp *)ie)->exps->tdata()[i]; - } - Initializer *ti = init; - if (einit) - { ti = new ExpInitializer(einit->loc, einit); - } - - VarDeclaration *v = new VarDeclaration(loc, arg->type, id, ti); - if (arg->storageClass & STCparameter) - v->storage_class |= arg->storageClass; - //printf("declaring field %s of type %s\n", v->toChars(), v->type->toChars()); - v->semantic(sc); - -#if !IN_LLVM -// removed for LDC since TupleDeclaration::toObj already creates the fields; -// adding them to the scope again leads to duplicates - if (sc->scopesym) - { //printf("adding %s to %s\n", v->toChars(), sc->scopesym->toChars()); - if (sc->scopesym->members) - sc->scopesym->members->push(v); - } -#endif - Expression *e = new DsymbolExp(loc, v); - exps->tdata()[i] = e; - } - TupleDeclaration *v2 = new TupleDeclaration(loc, ident, exps); - v2->isexp = 1; - aliassym = v2; - return; - } - - /* Storage class can modify the type - */ - type = type->addStorageClass(storage_class); - - /* Adjust storage class to reflect type - */ - if (type->isConst()) - { storage_class |= STCconst; - if (type->isShared()) - storage_class |= STCshared; - } - else if (type->isImmutable()) - storage_class |= STCimmutable; - else if (type->isShared()) - storage_class |= STCshared; - else if (type->isWild()) - storage_class |= STCwild; - - if (isSynchronized()) - { - error("variable %s cannot be synchronized", toChars()); - } - else if (isOverride()) - { - error("override cannot be applied to variable"); - } - else if (isAbstract()) - { - error("abstract cannot be applied to variable"); - } - else if (storage_class & STCfinal) - { - error("final cannot be applied to variable"); - } - - if (storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | STCtls | STCgshared | STCctfe)) - { - } - else - { - AggregateDeclaration *aad = sc->anonAgg; - if (!aad) - aad = parent->isAggregateDeclaration(); - if (aad) - { -#if DMDV2 - assert(!(storage_class & (STCextern | STCstatic | STCtls | STCgshared))); - - if (storage_class & (STCconst | STCimmutable) && init) - { - if (!tb->isTypeBasic()) - storage_class |= STCstatic; - } - else - { - aad->addField(sc, this); - if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->noDefaultCtor || - tb->ty == Tclass && ((TypeClass *)tb)->sym->noDefaultCtor) - aad->noDefaultCtor = TRUE; - } -#else - aad->addField(sc, this); -#endif - } - - InterfaceDeclaration *id = parent->isInterfaceDeclaration(); - if (id) - { - error("field not allowed in interface"); - } - - /* Templates cannot add fields to aggregates - */ - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - AggregateDeclaration *ad2 = ti->tempdecl->isMember(); - if (ad2 && storage_class != STCundefined) - { - error("cannot use template to add field to aggregate '%s'", ad2->toChars()); - } - } - } - -#if DMDV2 - if ((storage_class & (STCref | STCparameter | STCforeach)) == STCref && - ident != Id::This) - { - error("only parameters or foreach declarations can be ref"); - } - - if (type->hasWild() && - !(type->ty == Tpointer && type->nextOf()->ty == Tfunction || type->ty == Tdelegate)) - { - if (storage_class & (STCstatic | STCextern | STCtls | STCgshared | STCmanifest | STCfield) || - isDataseg() - ) - { - error("only parameters or stack based variables can be inout"); - } - FuncDeclaration *func = sc->func; - if (func) - { - if (func->fes) - func = func->fes->func; - if (!func->type->hasWild()) - { - error("inout variables can only be declared inside inout functions"); - } - } - } - - if (!(storage_class & (STCctfe | STCref)) && tb->ty == Tstruct && - ((TypeStruct *)tb)->sym->noDefaultCtor) - { - if (!init) - { if (storage_class & STCfield) - /* For fields, we'll check the constructor later to make sure it is initialized - */ - storage_class |= STCnodefaultctor; - else if (storage_class & STCparameter) - ; - else - error("initializer required for type %s", type->toChars()); - } - } -#endif - - if (type->isscope() && !noscope) - { - if (storage_class & (STCfield | STCout | STCref | STCstatic | STCmanifest | STCtls | STCgshared) || !fd) - { - error("globals, statics, fields, manifest constants, ref and out parameters cannot be scope"); - } - - if (!(storage_class & STCscope)) - { - if (!(storage_class & STCparameter) && ident != Id::withSym) - error("reference to scope class must be scope"); - } - } - - if (!init && !fd) - { // If not mutable, initializable by constructor only - storage_class |= STCctorinit; - } - - if (init) - storage_class |= STCinit; // remember we had an explicit initializer - else if (storage_class & STCmanifest) - error("manifest constants must have initializers"); - - enum TOK op = TOKconstruct; - if (!init && !sc->inunion && !isStatic() && fd && - (!(storage_class & (STCfield | STCin | STCforeach | STCparameter | STCresult)) - || (storage_class & STCout)) && - type->size() != 0) - { - // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); - if (type->ty == Tstruct && - ((TypeStruct *)type)->sym->zeroInit == 1) - { /* If a struct is all zeros, as a special case - * set it's initializer to the integer 0. - * In AssignExp::toElem(), we check for this and issue - * a memset() to initialize the struct. - * Must do same check in interpreter. - */ - Expression *e = new IntegerExp(loc, 0, Type::tint32); - Expression *e1; - e1 = new VarExp(loc, this); - e = new ConstructExp(loc, e1, e); - e->type = e1->type; // don't type check this, it would fail - init = new ExpInitializer(loc, e); - goto Ldtor; - } - else if (type->ty == Ttypedef) - { TypeTypedef *td = (TypeTypedef *)type; - if (td->sym->init) - { init = td->sym->init; - ExpInitializer *ie = init->isExpInitializer(); - if (ie) - // Make copy so we can modify it - init = new ExpInitializer(ie->loc, ie->exp); - } - else - init = getExpInitializer(); - } - else - { - init = getExpInitializer(); - } - // Default initializer is always a blit - op = TOKblit; - } - - if (init) - { - sc = sc->push(); - sc->stc &= ~(STC_TYPECTOR | STCpure | STCnothrow | STCref | STCdisable); - - ArrayInitializer *ai = init->isArrayInitializer(); - if (ai && tb->ty == Taarray) - { - Expression *e = ai->toAssocArrayLiteral(); - init = new ExpInitializer(e->loc, e); - } - - StructInitializer *si = init->isStructInitializer(); - ExpInitializer *ei = init->isExpInitializer(); - - if (ei && ei->exp->op == TOKfunction && !inferred) - ((FuncExp *)ei->exp)->setType(type); - - if (ei && isScope()) - { - // See if initializer is a NewExp that can be allocated on the stack - if (ei->exp->op == TOKnew) - { NewExp *ne = (NewExp *)ei->exp; - if (!(ne->newargs && ne->newargs->dim)) - { ne->onstack = 1; - onstack = 1; - if (type->isBaseOf(ne->newtype->semantic(loc, sc), NULL)) - onstack = 2; - } - } - // or a delegate that doesn't escape a reference to the function - else if (ei->exp->op == TOKfunction) - { FuncDeclaration *f = ((FuncExp *)ei->exp)->fd; - f->tookAddressOf--; - } - } - - // If inside function, there is no semantic3() call - if (sc->func) - { - // If local variable, use AssignExp to handle all the various - // possibilities. - if (fd && - !(storage_class & (STCmanifest | STCstatic | STCtls | STCgshared | STCextern)) && - !init->isVoidInitializer()) - { - //printf("fd = '%s', var = '%s'\n", fd->toChars(), toChars()); - if (!ei) - { - Expression *e = init->toExpression(); - if (!e) - { - init = init->semantic(sc, type, 0); // Don't need to interpret - e = init->toExpression(); - if (!e) - { error("is not a static and cannot have static initializer"); - return; - } - } - ei = new ExpInitializer(init->loc, e); - init = ei; - } - - Expression *e1 = new VarExp(loc, this); - - Type *t = type->toBasetype(); - - Linit2: - if (t->ty == Tsarray && !(storage_class & (STCref | STCout))) - { - ei->exp = ei->exp->semantic(sc); - if (!ei->exp->implicitConvTo(type)) - { - dinteger_t dim = ((TypeSArray *)t)->dim->toInteger(); - // If multidimensional static array, treat as one large array - while (1) - { - t = t->nextOf()->toBasetype(); - if (t->ty != Tsarray) - break; - dim *= ((TypeSArray *)t)->dim->toInteger(); - e1->type = new TypeSArray(t->nextOf(), new IntegerExp(0, dim, Type::tindex)); - } - } - e1 = new SliceExp(loc, e1, NULL, NULL); - } - else if (t->ty == Tstruct) - { - ei->exp = ei->exp->semantic(sc); - ei->exp = resolveProperties(sc, ei->exp); - StructDeclaration *sd = ((TypeStruct *)t)->sym; -#if DMDV2 - Expression** pinit = &ei->exp; - while ((*pinit)->op == TOKcomma) - { - pinit = &((CommaExp *)*pinit)->e2; - } - - /* Look to see if initializer is a call to the constructor - */ - if (sd->ctor && // there are constructors - (*pinit)->type->ty == Tstruct && // rvalue is the same struct - ((TypeStruct *)(*pinit)->type)->sym == sd && - (*pinit)->op == TOKcall) - { - /* Look for form of constructor call which is: - * *__ctmp.ctor(arguments...) - */ - if (1) - { CallExp *ce = (CallExp *)(*pinit); - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { /* It's a constructor call, currently constructing - * a temporary __ctmp. - */ - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - - /* Remove ref if this declaration is ref binding. - * ref Type __self = (__ctmp = 0, __ctmp).this(...); - * -> Type __self = (__self = 0, __self.this(...)); - */ - storage_class &= ~(STCref | STCforeach | STCparameter); - - Expression *e; - if (sd->zeroInit == 1) - { - e = new ConstructExp(loc, new VarExp(loc, this), new IntegerExp(loc, 0, Type::tint32)); - } - else - { e = new AssignExp(loc, new VarExp(loc, this), t->defaultInit(loc)); - e->op = TOKblit; - } - e->type = t; - (*pinit) = new CommaExp(loc, e, (*pinit)); - - /* Replace __ctmp being constructed with e1 - */ - dve->e1 = e1; - (*pinit) = (*pinit)->semantic(sc); - goto Ldtor; - } - } - } - } - - /* Look for ((S tmp = S()),tmp) and replace it with just S() - */ - Expression *e2 = ei->exp->isTemp(); - if (e2) - { - ei->exp = e2; - goto Linit2; - } -#endif - if (!ei->exp->implicitConvTo(type)) - { - Type *ti = ei->exp->type->toBasetype(); - // Look for constructor first - if (sd->ctor && - /* Initializing with the same type is done differently - */ - !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) - { - // Rewrite as e1.ctor(arguments) - Expression *ector = new DotIdExp(loc, e1, Id::ctor); - ei->exp = new CallExp(loc, ector, ei->exp); - /* Before calling the constructor, initialize - * variable with a bit copy of the default - * initializer - */ - Expression *e = new AssignExp(loc, e1, t->defaultInit(loc)); - e->op = TOKblit; - e->type = t; - ei->exp = new CommaExp(loc, e, ei->exp); - } - else - /* Look for opCall - * See bugzilla 2702 for more discussion - */ - // Don't cast away invariant or mutability in initializer - if (search_function(sd, Id::call) && - /* Initializing with the same type is done differently - */ - !(ti->ty == Tstruct && t->toDsymbol(sc) == ti->toDsymbol(sc))) - { // Rewrite as e1.call(arguments) - Expression * eCall = new DotIdExp(loc, e1, Id::call); - ei->exp = new CallExp(loc, eCall, ei->exp); - } - } - } - ei->exp = new AssignExp(loc, e1, ei->exp); - ei->exp->op = op; - canassign++; - ei->exp = ei->exp->semantic(sc); - canassign--; - ei->exp->optimize(WANTvalue); - } - else - { - init = init->semantic(sc, type, WANTinterpret); - } - } - else if (storage_class & (STCconst | STCimmutable | STCmanifest) || - type->isConst() || type->isImmutable() || - parent->isAggregateDeclaration()) - { - /* Because we may need the results of a const declaration in a - * subsequent type, such as an array dimension, before semantic2() - * gets ordinarily run, try to run semantic2() now. - * Ignore failure. - */ - - if (!global.errors && !inferred) - { - unsigned errors = global.startGagging(); - Expression *e; - Initializer *i2 = init; - inuse++; - if (ei) - { - e = ei->exp->syntaxCopy(); - e = e->semantic(sc); - e = resolveProperties(sc, e); -#if DMDV2 - /* The problem is the following code: - * struct CopyTest { - * double x; - * this(double a) { x = a * 10.0;} - * this(this) { x += 2.0; } - * } - * const CopyTest z = CopyTest(5.3); // ok - * const CopyTest w = z; // not ok, postblit not run - * static assert(w.x == 55.0); - * because the postblit doesn't get run on the initialization of w. - */ - - Type *tb2 = e->type->toBasetype(); - if (tb2->ty == Tstruct) - { StructDeclaration *sd = ((TypeStruct *)tb2)->sym; - Type *typeb = type->toBasetype(); - /* Look to see if initializer involves a copy constructor - * (which implies a postblit) - */ - if (sd->cpctor && // there is a copy constructor - typeb->equals(tb2)) // rvalue is the same struct - { - // The only allowable initializer is a (non-copy) constructor - if (e->op == TOKcall) - { - CallExp *ce = (CallExp *)e; - if (ce->e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - goto LNoCopyConstruction; - } - } - global.gag--; - error("of type struct %s uses this(this), which is not allowed in static initialization", typeb->toChars()); - global.gag++; - - LNoCopyConstruction: - ; - } - } -#endif - e = e->implicitCastTo(sc, type); - } - else if (si || ai) - { i2 = init->syntaxCopy(); - i2 = i2->semantic(sc, type, WANTinterpret); - } - inuse--; - if (global.endGagging(errors)) // if errors happened - { -#if DMDV2 - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); -#endif - } - else if (ei) - { - if (isDataseg() || (storage_class & STCmanifest)) - e = e->optimize(WANTvalue | WANTinterpret); - else - e = e->optimize(WANTvalue); - switch (e->op) - { - case TOKint64: - case TOKfloat64: - case TOKstring: - case TOKarrayliteral: - case TOKassocarrayliteral: - case TOKstructliteral: - case TOKnull: - ei->exp = e; // no errors, keep result - break; - - default: -#if DMDV2 - /* Save scope for later use, to try again - */ - scope = new Scope(*sc); - scope->setNoFree(); -#endif - break; - } - } - else - init = i2; // no errors, keep result - } - } - sc = sc->pop(); - } - -Ldtor: - /* Build code to execute destruction, if necessary - */ - edtor = callScopeDtor(sc); - if (edtor) - { - edtor = edtor->semantic(sc); - -#if 0 // currently disabled because of std.stdio.stdin, stdout and stderr - if (isDataseg() && !(storage_class & STCextern)) - error("static storage variables cannot have destructors"); -#endif - } - - sem = SemanticDone; -} - -void VarDeclaration::semantic2(Scope *sc) -{ - //printf("VarDeclaration::semantic2('%s')\n", toChars()); - if (init && !toParent()->isFuncDeclaration()) - { inuse++; -#if 0 - ExpInitializer *ei = init->isExpInitializer(); - if (ei) - { - ei->exp->dump(0); - printf("type = %p\n", ei->exp->type); - } -#endif - init = init->semantic(sc, type, WANTinterpret); - inuse--; - } - sem = Semantic2Done; -} - -void VarDeclaration::semantic3(Scope *sc) -{ - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - if (aliassym) - aliassym->semantic3(sc); - - // Preserve call chain - Declaration::semantic3(sc); -} - -const char *VarDeclaration::kind() -{ - return "variable"; -} - -Dsymbol *VarDeclaration::toAlias() -{ - //printf("VarDeclaration::toAlias('%s', this = %p, aliassym = %p)\n", toChars(), this, aliassym); - assert(this != aliassym); - Dsymbol *s = aliassym ? aliassym->toAlias() : this; - return s; -} - -void VarDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - - /* If changing, be sure and fix CompoundDeclarationStatement::toCBuffer() - * too. - */ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - init->toCBuffer(buf, hgs); - } - buf->writeByte(';'); - buf->writenl(); -} - -AggregateDeclaration *VarDeclaration::isThis() -{ - AggregateDeclaration *ad = NULL; - - if (!(storage_class & (STCstatic | STCextern | STCmanifest | STCtemplateparameter | - STCtls | STCgshared | STCctfe))) - { - if ((storage_class & (STCconst | STCimmutable | STCwild)) && init) - return NULL; - - for (Dsymbol *s = this; s; s = s->parent) - { - ad = s->isMember(); - if (ad) - break; - if (!s->parent || !s->parent->isTemplateMixin()) break; - } - } - return ad; -} - -int VarDeclaration::needThis() -{ - //printf("VarDeclaration::needThis(%s, x%x)\n", toChars(), storage_class); - return storage_class & STCfield; -} - -int VarDeclaration::isImportedSymbol() -{ - if (protection == PROTexport && !init && - (storage_class & STCstatic || parent->isModule())) - return TRUE; - return FALSE; -} - -void VarDeclaration::checkCtorConstInit() -{ -#if 0 /* doesn't work if more than one static ctor */ - if (ctorinit == 0 && isCtorinit() && !(storage_class & STCfield)) - error("missing initializer in static constructor for const variable"); -#endif -} - -/************************************ - * Check to see if this variable is actually in an enclosing function - * rather than the current one. - */ - -void VarDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - //printf("VarDeclaration::checkNestedReference() %s\n", toChars()); - if (parent && !isDataseg() && parent != sc->parent && - !(storage_class & STCmanifest)) - { - // The function that this variable is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - if (fdv && fdthis && fdv != fdthis && fdthis->ident != Id::ensure && fdthis->ident != Id::require) - { - /* __ensure is always called directly, - * so it never becomes closure. - */ - - //printf("\tfdv = %s\n", fdv->toChars()); - //printf("\tfdthis = %s\n", fdthis->toChars()); - - if (loc.filename) - fdthis->getLevel(loc, sc, fdv); - - // Function literals from fdthis to fdv must be delegates - for (Dsymbol *s = fdthis; s && s != fdv; s = s->toParent2()) - { - // function literal has reference to enclosing scope is delegate - if (FuncLiteralDeclaration *fld = s->isFuncLiteralDeclaration()) - { - fld->tok = TOKdelegate; - } - } - - // Add fdthis to nestedrefs[] if not already there - for (size_t i = 0; 1; i++) - { - if (i == nestedrefs.dim) - { - nestedrefs.push(fdthis); - break; - } - if (nestedrefs[i] == fdthis) - break; - } - - // Add this to fdv->closureVars[] if not already there - for (size_t i = 0; 1; i++) - { - if (i == fdv->closureVars.dim) - { - fdv->closureVars.push(this); - break; - } - if (fdv->closureVars[i] == this) - break; - } - - //printf("fdthis is %s\n", fdthis->toChars()); - //printf("var %s in function %s is nested ref\n", toChars(), fdv->toChars()); - // __dollar creates problems because it isn't a real variable Bugzilla 3326 - if (ident == Id::dollar) - ::error(loc, "cannnot use $ inside a function literal"); - } - } -} - -/**************************** - * Get ExpInitializer for a variable, if there is one. - */ - -ExpInitializer *VarDeclaration::getExpInitializer() -{ - ExpInitializer *ei; - - if (init) - ei = init->isExpInitializer(); - else - { - Expression *e = type->defaultInit(loc); - if (e) - ei = new ExpInitializer(loc, e); - else - ei = NULL; - } - return ei; -} - -/******************************************* - * If variable has a constant expression initializer, get it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::getConstInitializer() -{ - if ((isConst() || isImmutable() || storage_class & STCmanifest) && - storage_class & STCinit) - { - ExpInitializer *ei = getExpInitializer(); - if (ei) - return ei->exp; - } - - return NULL; -} - -/************************************* - * Return !=0 if we can take the address of this variable. - */ - -int VarDeclaration::canTakeAddressOf() -{ -#if 0 - /* Global variables and struct/class fields of the form: - * const int x = 3; - * are not stored and hence cannot have their address taken. - */ - if ((isConst() || isImmutable()) && - storage_class & STCinit && - (!(storage_class & (STCstatic | STCextern)) || (storage_class & STCfield)) && - (!parent || toParent()->isModule() || toParent()->isTemplateInstance()) && - type->toBasetype()->isTypeBasic() - ) - { - return 0; - } -#else - if (storage_class & STCmanifest) - return 0; -#endif - return 1; -} - - -/******************************* - * Does symbol go into data segment? - * Includes extern variables. - */ - -int VarDeclaration::isDataseg() -{ -#if 0 - printf("VarDeclaration::isDataseg(%p, '%s')\n", this, toChars()); - printf("%llx, isModule: %p, isTemplateInstance: %p\n", storage_class & (STCstatic | STCconst), parent->isModule(), parent->isTemplateInstance()); - printf("parent = '%s'\n", parent->toChars()); -#endif - if (storage_class & STCmanifest) - return 0; - Dsymbol *parent = this->toParent(); - if (!parent && !(storage_class & STCstatic)) - { error("forward referenced"); - type = Type::terror; - return 0; - } - return canTakeAddressOf() && - (storage_class & (STCstatic | STCextern | STCtls | STCgshared) || - toParent()->isModule() || - toParent()->isTemplateInstance()); -} - -/************************************ - * Does symbol go into thread local storage? - */ - -int VarDeclaration::isThreadlocal() -{ - //printf("VarDeclaration::isThreadlocal(%p, '%s')\n", this, toChars()); -#if 0 //|| TARGET_OSX - /* To be thread-local, must use the __thread storage class. - * BUG: OSX doesn't support thread local yet. - */ - return isDataseg() && - (storage_class & (STCtls | STCconst | STCimmutable | STCshared | STCgshared)) == STCtls; -#else - /* Data defaults to being thread-local. It is not thread-local - * if it is immutable, const or shared. - */ - int i = isDataseg() && - !(storage_class & (STCimmutable | STCconst | STCshared | STCgshared)); - //printf("\treturn %d\n", i); - return i; -#endif -} - -/******************************************** - * Can variable be read and written by CTFE? - */ - -int VarDeclaration::isCTFE() -{ - return (storage_class & STCctfe) != 0; // || !isDataseg(); -} - -int VarDeclaration::hasPointers() -{ - //printf("VarDeclaration::hasPointers() %s, ty = %d\n", toChars(), type->ty); - return (!isDataseg() && type->hasPointers()); -} - -/****************************************** - * Return TRUE if variable needs to call the destructor. - */ - -int VarDeclaration::needsAutoDtor() -{ - //printf("VarDeclaration::needsAutoDtor() %s\n", toChars()); - - if (noscope || !edtor) - return FALSE; - - return TRUE; -} - - -/****************************************** - * If a variable has a scope destructor call, return call for it. - * Otherwise, return NULL. - */ - -Expression *VarDeclaration::callScopeDtor(Scope *sc) -{ Expression *e = NULL; - - //printf("VarDeclaration::callScopeDtor() %s\n", toChars()); - - // Destruction of STCfield's is handled by buildDtor() - if (noscope || storage_class & (STCnodtor | STCref | STCout | STCfield)) - { - return NULL; - } - - // Destructors for structs and arrays of structs - bool array = false; - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - array = true; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { - if (array) - { - // Typeinfo.destroy(cast(void*)&v); -#if IN_LLVM - Expression *ea = new AddrExp(loc, new DsymbolExp(loc, this)); -#else - Expression *ea = new SymOffExp(loc, this, 0, 0); -#endif - ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); - Expressions *args = new Expressions(); - args->push(ea); - - Expression *et = type->getTypeInfo(sc); - et = new DotIdExp(loc, et, Id::destroy); - - e = new CallExp(loc, et, args); - } - else - { - e = new VarExp(loc, this); - /* This is a hack so we can call destructors on const/immutable objects. - * Need to add things like "const ~this()" and "immutable ~this()" to - * fix properly. - */ - e->type = e->type->mutableOf(); - e = new DotVarExp(loc, e, sd->dtor, 0); - e = new CallExp(loc, e); - } - return e; - } - } - - // Destructors for classes - if (storage_class & (STCauto | STCscope)) - { - for (ClassDeclaration *cd = type->isClassHandle(); - cd; - cd = cd->baseClass) - { - /* We can do better if there's a way with onstack - * classes to determine if there's no way the monitor - * could be set. - */ - //if (cd->isInterfaceDeclaration()) - //error("interface %s cannot be scope", cd->toChars()); - if (1 || onstack || cd->dtors.dim) // if any destructors - { - // delete this; - Expression *ec; - - ec = new VarExp(loc, this); - e = new DeleteExp(loc, ec); - e->type = Type::tvoid; - break; - } - } - } - return e; -} - -/****************************************** - */ - -void ObjectNotFound(Identifier *id) -{ - Type::error(0, "%s not found. object.d may be incorrectly installed or corrupt.", id->toChars()); - fatal(); -} - - -/********************************* ClassInfoDeclaration ****************************/ - -ClassInfoDeclaration::ClassInfoDeclaration(ClassDeclaration *cd) - : VarDeclaration(0, ClassDeclaration::classinfo->type, cd->ident, NULL) -{ - this->cd = cd; - storage_class = STCstatic | STCgshared; -} - -Dsymbol *ClassInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ClassInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* ModuleInfoDeclaration ****************************/ - -ModuleInfoDeclaration::ModuleInfoDeclaration(Module *mod) - : VarDeclaration(0, Module::moduleinfo->type, mod->ident, NULL) -{ - this->mod = mod; - storage_class = STCstatic | STCgshared; -} - -Dsymbol *ModuleInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void ModuleInfoDeclaration::semantic(Scope *sc) -{ -} - -/********************************* TypeInfoDeclaration ****************************/ - -TypeInfoDeclaration::TypeInfoDeclaration(Type *tinfo, int internal) - : VarDeclaration(0, Type::typeinfo->type, tinfo->getTypeInfoIdent(internal), NULL) -{ - this->tinfo = tinfo; - storage_class = STCstatic | STCgshared; - protection = PROTpublic; - linkage = LINKc; -} - -Dsymbol *TypeInfoDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -void TypeInfoDeclaration::semantic(Scope *sc) -{ - assert(linkage == LINKc); -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif -} - -/***************************** TypeInfoConstDeclaration **********************/ - -#if DMDV2 -TypeInfoConstDeclaration::TypeInfoConstDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoconst) - { - ObjectNotFound(Id::TypeInfo_Const); - } - type = Type::typeinfoconst->type; -} -#endif - -/***************************** TypeInfoInvariantDeclaration **********************/ - -#if DMDV2 -TypeInfoInvariantDeclaration::TypeInfoInvariantDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoinvariant) - { - ObjectNotFound(Id::TypeInfo_Invariant); - } - type = Type::typeinfoinvariant->type; -} -#endif - -/***************************** TypeInfoSharedDeclaration **********************/ - -#if DMDV2 -TypeInfoSharedDeclaration::TypeInfoSharedDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoshared) - { - ObjectNotFound(Id::TypeInfo_Shared); - } - type = Type::typeinfoshared->type; -} -#endif - -/***************************** TypeInfoWildDeclaration **********************/ - -#if DMDV2 -TypeInfoWildDeclaration::TypeInfoWildDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfowild) - { - ObjectNotFound(Id::TypeInfo_Wild); - } - type = Type::typeinfowild->type; -} -#endif - -/***************************** TypeInfoStructDeclaration **********************/ - -TypeInfoStructDeclaration::TypeInfoStructDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfostruct) - { - ObjectNotFound(Id::TypeInfo_Struct); - } - type = Type::typeinfostruct->type; -} - -/***************************** TypeInfoClassDeclaration ***********************/ - -TypeInfoClassDeclaration::TypeInfoClassDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoclass) - { - ObjectNotFound(Id::TypeInfo_Class); - } - type = Type::typeinfoclass->type; -} - -/***************************** TypeInfoInterfaceDeclaration *******************/ - -TypeInfoInterfaceDeclaration::TypeInfoInterfaceDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfointerface) - { - ObjectNotFound(Id::TypeInfo_Interface); - } - type = Type::typeinfointerface->type; -} - -/***************************** TypeInfoTypedefDeclaration *********************/ - -TypeInfoTypedefDeclaration::TypeInfoTypedefDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfotypedef) - { - ObjectNotFound(Id::TypeInfo_Typedef); - } - type = Type::typeinfotypedef->type; -} - -/***************************** TypeInfoPointerDeclaration *********************/ - -TypeInfoPointerDeclaration::TypeInfoPointerDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfopointer) - { - ObjectNotFound(Id::TypeInfo_Pointer); - } - type = Type::typeinfopointer->type; -} - -/***************************** TypeInfoArrayDeclaration ***********************/ - -TypeInfoArrayDeclaration::TypeInfoArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoarray) - { - ObjectNotFound(Id::TypeInfo_Array); - } - type = Type::typeinfoarray->type; -} - -/***************************** TypeInfoStaticArrayDeclaration *****************/ - -TypeInfoStaticArrayDeclaration::TypeInfoStaticArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfostaticarray) - { - ObjectNotFound(Id::TypeInfo_StaticArray); - } - type = Type::typeinfostaticarray->type; -} - -/***************************** TypeInfoAssociativeArrayDeclaration ************/ - -TypeInfoAssociativeArrayDeclaration::TypeInfoAssociativeArrayDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoassociativearray) - { - ObjectNotFound(Id::TypeInfo_AssociativeArray); - } - type = Type::typeinfoassociativearray->type; -} - -/***************************** TypeInfoVectorDeclaration ***********************/ - -TypeInfoVectorDeclaration::TypeInfoVectorDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoarray) - { - ObjectNotFound(Id::TypeInfo_Vector); - } - type = Type::typeinfovector->type; -} - -/***************************** TypeInfoEnumDeclaration ***********************/ - -TypeInfoEnumDeclaration::TypeInfoEnumDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfoenum) - { - ObjectNotFound(Id::TypeInfo_Enum); - } - type = Type::typeinfoenum->type; -} - -/***************************** TypeInfoFunctionDeclaration ********************/ - -TypeInfoFunctionDeclaration::TypeInfoFunctionDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfofunction) - { - ObjectNotFound(Id::TypeInfo_Function); - } - type = Type::typeinfofunction->type; -} - -/***************************** TypeInfoDelegateDeclaration ********************/ - -TypeInfoDelegateDeclaration::TypeInfoDelegateDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfodelegate) - { - ObjectNotFound(Id::TypeInfo_Delegate); - } - type = Type::typeinfodelegate->type; -} - -/***************************** TypeInfoTupleDeclaration **********************/ - -TypeInfoTupleDeclaration::TypeInfoTupleDeclaration(Type *tinfo) - : TypeInfoDeclaration(tinfo, 0) -{ - if (!Type::typeinfotypelist) - { - ObjectNotFound(Id::TypeInfo_Tuple); - } - type = Type::typeinfotypelist->type; -} - -/********************************* ThisDeclaration ****************************/ - -// For the "this" parameter to member functions - -ThisDeclaration::ThisDeclaration(Loc loc, Type *t) - : VarDeclaration(loc, t, Id::This, NULL) -{ - noscope = 1; -} - -Dsymbol *ThisDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(0); // should never be produced by syntax - return NULL; -} - -/********************** StaticStructInitDeclaration ***************************/ - -StaticStructInitDeclaration::StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym) - : Declaration(new Identifier("", TOKidentifier)) -{ - this->loc = loc; - this->dsym = dsym; - storage_class |= STCconst; -} diff --git a/dmd2/declaration.h b/dmd2/declaration.h deleted file mode 100644 index 079adfdf..00000000 --- a/dmd2/declaration.h +++ /dev/null @@ -1,1107 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DECLARATION_H -#define DMD_DECLARATION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#if IN_LLVM -#include -#include -#include -#include -#endif - -#include "dsymbol.h" -#include "lexer.h" -#include "mtype.h" - -struct Expression; -struct Statement; -struct LabelDsymbol; -#if IN_LLVM -struct LabelStatement; -#endif -struct Initializer; -struct Module; -struct InlineScanState; -struct ForeachStatement; -struct FuncDeclaration; -struct ExpInitializer; -struct StructDeclaration; -struct TupleType; -struct InterState; -struct IRState; -#if IN_LLVM -struct AnonDeclaration; -#endif - -enum PROT; -enum LINK; -enum TOK; -enum MATCH; -enum PURE; - -#define STCundefined 0LL -#define STCstatic 1LL -#define STCextern 2LL -#define STCconst 4LL -#define STCfinal 8LL -#define STCabstract 0x10LL -#define STCparameter 0x20LL -#define STCfield 0x40LL -#define STCoverride 0x80LL -#define STCauto 0x100LL -#define STCsynchronized 0x200LL -#define STCdeprecated 0x400LL -#define STCin 0x800LL // in parameter -#define STCout 0x1000LL // out parameter -#define STClazy 0x2000LL // lazy parameter -#define STCforeach 0x4000LL // variable for foreach loop -#define STCcomdat 0x8000LL // should go into COMDAT record -#define STCvariadic 0x10000LL // variadic function argument -#define STCctorinit 0x20000LL // can only be set inside constructor -#define STCtemplateparameter 0x40000LL // template parameter -#define STCscope 0x80000LL // template parameter -#define STCimmutable 0x100000LL -#define STCref 0x200000LL -#define STCinit 0x400000LL // has explicit initializer -#define STCmanifest 0x800000LL // manifest constant -#define STCnodtor 0x1000000LL // don't run destructor -#define STCnothrow 0x2000000LL // never throws exceptions -#define STCpure 0x4000000LL // pure function -#define STCtls 0x8000000LL // thread local -#define STCalias 0x10000000LL // alias parameter -#define STCshared 0x20000000LL // accessible from multiple threads -#define STCgshared 0x40000000LL // accessible from multiple threads - // but not typed as "shared" -#define STCwild 0x80000000LL // for "wild" type constructor -#define STC_TYPECTOR (STCconst | STCimmutable | STCshared | STCwild) -#define STC_FUNCATTR (STCref | STCnothrow | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem) - -#define STCproperty 0x100000000LL -#define STCsafe 0x200000000LL -#define STCtrusted 0x400000000LL -#define STCsystem 0x800000000LL -#define STCctfe 0x1000000000LL // can be used in CTFE, even if it is static -#define STCdisable 0x2000000000LL // for functions that are not callable -#define STCresult 0x4000000000LL // for result variables passed to out contracts -#define STCnodefaultctor 0x8000000000LL // must be set inside constructor - -struct Match -{ - int count; // number of matches found - MATCH last; // match level of lastf - FuncDeclaration *lastf; // last matching function we found - FuncDeclaration *nextf; // current matching function - FuncDeclaration *anyf; // pick a func, any func, to use for error recovery -}; - -void overloadResolveX(Match *m, FuncDeclaration *f, - Expression *ethis, Expressions *arguments, Module* from); -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param); - -enum Semantic -{ - SemanticStart, // semantic has not been run - SemanticIn, // semantic() is in progress - SemanticDone, // semantic() has been run - Semantic2Done, // semantic2() has been run -}; - -/**************************************************************/ - -struct Declaration : Dsymbol -{ - Type *type; - Type *originalType; // before semantic analysis - StorageClass storage_class; - enum PROT protection; - enum LINK linkage; - int inuse; // used to detect cycles - - enum Semantic sem; - - Declaration(Identifier *id); - void semantic(Scope *sc); - const char *kind(); - unsigned size(Loc loc); - void checkModify(Loc loc, Scope *sc, Type *t); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - char *mangle(); - int isStatic() { return storage_class & STCstatic; } - virtual int isDelete(); - virtual int isDataseg(); - virtual int isThreadlocal(); - virtual int isCodeseg(); - int isCtorinit() { return storage_class & STCctorinit; } - int isFinal() { return storage_class & STCfinal; } - int isAbstract() { return storage_class & STCabstract; } - int isConst() { return storage_class & STCconst; } - int isImmutable() { return storage_class & STCimmutable; } - int isWild() { return storage_class & STCwild; } - int isAuto() { return storage_class & STCauto; } - int isScope() { return storage_class & STCscope; } - int isSynchronized() { return storage_class & STCsynchronized; } - int isParameter() { return storage_class & STCparameter; } - int isDeprecated() { return storage_class & STCdeprecated; } - int isOverride() { return storage_class & STCoverride; } - StorageClass isResult() { return storage_class & STCresult; } - - int isIn() { return storage_class & STCin; } - int isOut() { return storage_class & STCout; } - int isRef() { return storage_class & STCref; } - - enum PROT prot(); - - Declaration *isDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TupleDeclaration : Declaration -{ - Objects *objects; - int isexp; // 1: expression tuple - - TypeTuple *tupletype; // !=NULL if this is a type tuple - - TupleDeclaration(Loc loc, Identifier *ident, Objects *objects); - Dsymbol *syntaxCopy(Dsymbol *); - const char *kind(); - Type *getType(); - int needThis(); - - TupleDeclaration *isTupleDeclaration() { return this; } - -#if IN_LLVM - void semantic3(Scope *sc); - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct TypedefDeclaration : Declaration -{ - Type *basetype; - Initializer *init; - - TypedefDeclaration(Loc loc, Identifier *ident, Type *basetype, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - char *mangle(); - const char *kind(); - Type *getType(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Type *hbasetype; - - void toDocBuffer(OutBuffer *buf); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); -#endif - - TypedefDeclaration *isTypedefDeclaration() { return this; } - -#if IN_DMD - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); -#endif -}; - -/**************************************************************/ - -struct AliasDeclaration : Declaration -{ - Dsymbol *aliassym; - Dsymbol *overnext; // next in overload list - int inSemantic; - PROT importprot; // if generated by import, store its protection - - AliasDeclaration(Loc loc, Identifier *ident, Type *type); - AliasDeclaration(Loc loc, Identifier *ident, Dsymbol *s); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - const char *kind(); - Type *getType(); - Dsymbol *toAlias(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Dsymbol *haliassym; - - void toDocBuffer(OutBuffer *buf); - - AliasDeclaration *isAliasDeclaration() { return this; } -}; - -/**************************************************************/ - -struct VarDeclaration : Declaration -{ - Initializer *init; - unsigned offset; - int noscope; // no auto semantics -#if DMDV2 - FuncDeclarations nestedrefs; // referenced by these lexically nested functions - bool isargptr; // if parameter that _argptr points to -#else - int nestedref; // referenced by a lexically nested function -#endif - int ctorinit; // it has been initialized in a ctor - int onstack; // 1: it has been allocated on the stack - // 2: on stack, run destructor anyway - int canassign; // it can be assigned to - Dsymbol *aliassym; // if redone as alias to another symbol - - // When interpreting, these point to the value (NULL if value not determinable) - // The index of this variable on the CTFE stack, -1 if not allocated - size_t ctfeAdrOnStack; - // The various functions are used only to detect compiler CTFE bugs - Expression *getValue(); - bool hasValue(); - void setValueNull(); - void setValueWithoutChecking(Expression *newval); - void setValue(Expression *newval); - -#if DMDV2 - VarDeclaration *rundtor; // if !NULL, rundtor is tested at runtime to see - // if the destructor should be run. Used to prevent - // dtor calls on postblitted vars - Expression *edtor; // if !=NULL, does the destruction of the variable -#endif - - VarDeclaration(Loc loc, Type *t, Identifier *id, Initializer *init); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *htype; - Initializer *hinit; - AggregateDeclaration *isThis(); - int needThis(); - int isImportedSymbol(); - int isDataseg(); - int isThreadlocal(); - int isCTFE(); - int hasPointers(); -#if DMDV2 - int canTakeAddressOf(); - int needsAutoDtor(); -#endif - Expression *callScopeDtor(Scope *sc); - ExpInitializer *getExpInitializer(); - Expression *getConstInitializer(); - void checkCtorConstInit(); - void checkNestedReference(Scope *sc, Loc loc); - Dsymbol *toAlias(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - int cvMember(unsigned char *p); -#endif - - // Eliminate need for dynamic_cast - VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; } - -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - /// Index into parent aggregate. - /// Set during type generation. - unsigned aggrIndex; - - /// Variables that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - /// Override added to set above flag. - void semantic3(Scope *sc); - - /// This var is used by a naked function. - bool nakedUse; - - // debug description - llvm::DIVariable debugVariable; - llvm::DISubprogram debugFunc; -#endif -}; - -/**************************************************************/ - -// LDC uses this to denote static struct initializers - -struct StaticStructInitDeclaration : Declaration -{ - StructDeclaration *dsym; - - StaticStructInitDeclaration(Loc loc, StructDeclaration *dsym); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - // Eliminate need for dynamic_cast - StaticStructInitDeclaration *isStaticStructInitDeclaration() { return (StaticStructInitDeclaration *)this; } -}; - -struct ClassInfoDeclaration : VarDeclaration -{ - ClassDeclaration *cd; - - ClassInfoDeclaration(ClassDeclaration *cd); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - Symbol *toSymbol(); -#endif - - ClassInfoDeclaration* isClassInfoDeclaration() { return this; } -}; - -struct ModuleInfoDeclaration : VarDeclaration -{ - Module *mod; - - ModuleInfoDeclaration(Module *mod); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct TypeInfoDeclaration : VarDeclaration -{ - Type *tinfo; - - TypeInfoDeclaration(Type *tinfo, int internal); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - Symbol *toSymbol(); - virtual void toDt(dt_t **pdt); -#endif - - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return this; } - -#if IN_LLVM - /// Codegen traversal - void codegen(Ir* ir); - virtual void llvmDefine(); -#endif -}; - -struct TypeInfoStructDeclaration : TypeInfoDeclaration -{ - TypeInfoStructDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoClassDeclaration : TypeInfoDeclaration -{ - TypeInfoClassDeclaration(Type *tinfo); - -#if IN_DMD - Symbol *toSymbol(); - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void codegen(Ir*); - void llvmDefine(); -#endif -}; - -struct TypeInfoInterfaceDeclaration : TypeInfoDeclaration -{ - TypeInfoInterfaceDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTypedefDeclaration : TypeInfoDeclaration -{ - TypeInfoTypedefDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoPointerDeclaration : TypeInfoDeclaration -{ - TypeInfoPointerDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoStaticArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoStaticArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoAssociativeArrayDeclaration : TypeInfoDeclaration -{ - TypeInfoAssociativeArrayDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoEnumDeclaration : TypeInfoDeclaration -{ - TypeInfoEnumDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoFunctionDeclaration : TypeInfoDeclaration -{ - TypeInfoFunctionDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoDelegateDeclaration : TypeInfoDeclaration -{ - TypeInfoDelegateDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoTupleDeclaration : TypeInfoDeclaration -{ - TypeInfoTupleDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -#if DMDV2 -struct TypeInfoConstDeclaration : TypeInfoDeclaration -{ - TypeInfoConstDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoInvariantDeclaration : TypeInfoDeclaration -{ - TypeInfoInvariantDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoSharedDeclaration : TypeInfoDeclaration -{ - TypeInfoSharedDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoWildDeclaration : TypeInfoDeclaration -{ - TypeInfoWildDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; - -struct TypeInfoVectorDeclaration : TypeInfoDeclaration -{ - TypeInfoVectorDeclaration(Type *tinfo); - -#if IN_DMD - void toDt(dt_t **pdt); -#endif - -#if IN_LLVM - void llvmDefine(); -#endif -}; -#endif - -/**************************************************************/ - -struct ThisDeclaration : VarDeclaration -{ - ThisDeclaration(Loc loc, Type *t); - Dsymbol *syntaxCopy(Dsymbol *); - ThisDeclaration *isThisDeclaration() { return this; } -}; - -enum ILS -{ - ILSuninitialized, // not computed yet - ILSno, // cannot inline - ILSyes, // can inline -}; - -/**************************************************************/ -#if DMDV2 - -enum BUILTIN -{ - BUILTINunknown = -1, // not known if this is a builtin - BUILTINnot, // this is not a builtin - BUILTINsin, // std.math.sin - BUILTINcos, // std.math.cos - BUILTINtan, // std.math.tan - BUILTINsqrt, // std.math.sqrt - BUILTINfabs, // std.math.fabs - BUILTINatan2, // std.math.atan2 - BUILTINrndtol, // std.math.rndtol - BUILTINexpm1, // std.math.expm1 - BUILTINexp2, // std.math.exp2 - BUILTINyl2x, // std.math.yl2x - BUILTINyl2xp1, // std.math.yl2xp1 - BUILTINbsr, // core.bitop.bsr - BUILTINbsf, // core.bitop.bsf - BUILTINbswap, // core.bitop.bswap -}; - -Expression *eval_builtin(Loc loc, enum BUILTIN builtin, Expressions *arguments); - -#else -enum BUILTIN { }; -#endif - -struct FuncDeclaration : Declaration -{ - Types *fthrows; // Array of Type's of exceptions (not used) - Statement *frequire; - Statement *fensure; - Statement *fbody; - - FuncDeclarations foverrides; // functions this function overrides - FuncDeclaration *fdrequire; // function that does the in contract - FuncDeclaration *fdensure; // function that does the out contract - - Expressions *fdrequireParams; - Expressions *fdensureParams; - - Identifier *outId; // identifier for out statement - VarDeclaration *vresult; // variable corresponding to outId - LabelDsymbol *returnLabel; // where the return goes - - DsymbolTable *localsymtab; // used to prevent symbols in different - // scopes from having the same name - VarDeclaration *vthis; // 'this' parameter (member and nested) - VarDeclaration *v_arguments; // '_arguments' parameter -#if IN_GCC - VarDeclaration *v_argptr; // '_argptr' variable -#endif - VarDeclaration *v_argsave; // save area for args passed in registers for variadic functions - VarDeclarations *parameters; // Array of VarDeclaration's for parameters - DsymbolTable *labtab; // statement label symbol table - Declaration *overnext; // next in overload list - Loc endloc; // location of closing curly bracket - int vtblIndex; // for member functions, index into vtbl[] - int naked; // !=0 if naked - ILS inlineStatusStmt; - ILS inlineStatusExp; - int inlineNest; // !=0 if nested inline - int isArrayOp; // !=0 if array operation - enum PASS semanticRun; - int semantic3Errors; // !=0 if errors in semantic3 - // this function's frame ptr - ForeachStatement *fes; // if foreach body, this is the foreach - int introducing; // !=0 if 'introducing' function - Type *tintro; // if !=NULL, then this is the type - // of the 'introducing' function - // this one is overriding - int inferRetType; // !=0 if return type is to be inferred - StorageClass storage_class2; // storage class for template onemember's - - // Things that should really go into Scope - int hasReturnExp; // 1 if there's a return exp; statement - // 2 if there's a throw statement - // 4 if there's an assert(0) - // 8 if there's inline asm - - // Support for NRVO (named return value optimization) - int nrvo_can; // !=0 means we can do it - VarDeclaration *nrvo_var; // variable to replace with shidden -#if IN_DMD - Symbol *shidden; // hidden pointer passed to function -#endif - -#if DMDV2 - enum BUILTIN builtin; // set if this is a known, builtin - // function we can evaluate at compile - // time - - int tookAddressOf; // set if someone took the address of - // this function - VarDeclarations closureVars; // local variables in this function - // which are referenced by nested - // functions - - unsigned flags; - #define FUNCFLAGpurityInprocess 1 // working on determining purity - #define FUNCFLAGsafetyInprocess 2 // working on determining safety - #define FUNCFLAGnothrowInprocess 4 // working on determining nothrow -#else - int nestedFrameRef; // !=0 if nested variables referenced -#endif - - FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - // called from semantic3 - void varArgs(Scope *sc, TypeFunction*, VarDeclaration *&, VarDeclaration *&); - VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); - int equals(Object *o); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs); - int overrides(FuncDeclaration *fd); - int findVtblIndex(Dsymbols *vtbl, int dim); - int overloadInsert(Dsymbol *s); - FuncDeclaration *overloadExactMatch(Type *t, Module* from); - FuncDeclaration *overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags = 0, Module* from=NULL); - MATCH leastAsSpecialized(FuncDeclaration *g); - LabelDsymbol *searchLabel(Identifier *ident); - AggregateDeclaration *isThis(); - AggregateDeclaration *isMember2(); - int getLevel(Loc loc, Scope *sc, FuncDeclaration *fd); // lexical nesting level difference - void appendExp(Expression *e); - void appendState(Statement *s); - char *mangle(); - const char *toPrettyChars(); - int isMain(); - int isWinMain(); - int isDllMain(); - enum BUILTIN isBuiltin(); - int isExport(); - int isImportedSymbol(); - int isAbstract(); - int isCodeseg(); - int isOverloadable(); - enum PURE isPure(); - enum PURE isPureBypassingInference(); - bool setImpure(); - int isSafe(); - int isTrusted(); - bool setUnsafe(); - virtual int isNested(); - int needThis(); - int isVirtualMethod(); - virtual int isVirtual(); - virtual int isFinal(); - virtual int addPreInvariant(); - virtual int addPostInvariant(); - Expression *interpret(InterState *istate, Expressions *arguments, Expression *thisexp = NULL); - void inlineScan(); - int canInline(int hasthis, int hdrscan = false, int statementsToo = true); - Expression *expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps); - const char *kind(); - void toDocBuffer(OutBuffer *buf); - FuncDeclaration *isUnique(); - void checkNestedReference(Scope *sc, Loc loc); - int needsClosure(); - int hasNestedFrameRefs(); - Statement *mergeFrequire(Statement *, Expressions *params = 0); - Statement *mergeFensure(Statement *, Expressions *params = 0); - Parameters *getParameters(int *pvarargs); - -// LDC: give argument types to runtime functions - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name); - static FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id); - -#if IN_DMD - Symbol *toSymbol(); - Symbol *toThunkSymbol(int offset); // thunk version - void toObjFile(int multiobj); // compile to .obj file - int cvMember(unsigned char *p); - void buildClosure(IRState *irs); // Should this be inside or outside the #if IN_DMD? -#endif - FuncDeclaration *isFuncDeclaration() { return this; } - -#if IN_LLVM - // LDC stuff - - /// Codegen traversal - void codegen(Ir* ir); - - // vars declared in this function that nested funcs reference - // is this is not empty, nestedFrameRef is set and these VarDecls - // probably have nestedref set too, see VarDeclaration::checkNestedReference - std::set nestedVars; - - std::string intrinsicName; - - bool isIntrinsic(); - bool isVaIntrinsic(); - - // we keep our own table of label statements as LabelDsymbolS - // don't always carry their corresponding statement along ... - typedef std::map LabelMap; - LabelMap labmap; - - // Functions that wouldn't have gotten semantic3'ed if we weren't inlining set this flag. - bool availableExternally; - - // true if overridden with the pragma(allow_inline); stmt - bool allowInlining; - - // true if has inline assembler - bool inlineAsm; -#endif -}; - -#if DMDV2 -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags); -#endif - -struct FuncAliasDeclaration : FuncDeclaration -{ - FuncDeclaration *funcalias; - PROT importprot; // if generated by import, store its protection - - FuncAliasDeclaration(FuncDeclaration *funcalias); - - FuncAliasDeclaration *isFuncAliasDeclaration() { return this; } - const char *kind(); -#if IN_DMD - Symbol *toSymbol(); -#endif -}; - -struct FuncLiteralDeclaration : FuncDeclaration -{ - enum TOK tok; // TOKfunction or TOKdelegate - - FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, enum TOK tok, - ForeachStatement *fes); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *syntaxCopy(Dsymbol *); - int isNested(); - int isVirtual(); - - FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; } - const char *kind(); -}; - -struct CtorDeclaration : FuncDeclaration -{ - CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - CtorDeclaration *isCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct PostBlitDeclaration : FuncDeclaration -{ - PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc = STCundefined); - PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - PostBlitDeclaration *isPostBlitDeclaration() { return this; } -}; -#endif - -struct DtorDeclaration : FuncDeclaration -{ - DtorDeclaration(Loc loc, Loc endloc); - DtorDeclaration(Loc loc, Loc endloc, Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - char *toChars(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - int overloadInsert(Dsymbol *s); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - - DtorDeclaration *isDtorDeclaration() { return this; } -}; - -struct StaticCtorDeclaration : FuncDeclaration -{ - StaticCtorDeclaration(Loc loc, Loc endloc); - StaticCtorDeclaration(Loc loc, Loc endloc, const char *name); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - bool hasStaticCtorOrDtor(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticCtorDeclaration *isStaticCtorDeclaration() { return this; } -}; - -#if DMDV2 -struct SharedStaticCtorDeclaration : StaticCtorDeclaration -{ - SharedStaticCtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; } -}; -#endif - -struct StaticDtorDeclaration : FuncDeclaration -{ VarDeclaration *vgate; // 'gate' variable - - StaticDtorDeclaration(Loc loc, Loc endloc); - StaticDtorDeclaration(Loc loc, Loc endloc, const char *name); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - bool hasStaticCtorOrDtor(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - StaticDtorDeclaration *isStaticDtorDeclaration() { return this; } -}; - -#if DMDV2 -struct SharedStaticDtorDeclaration : StaticDtorDeclaration -{ - SharedStaticDtorDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; } -}; -#endif - -struct InvariantDeclaration : FuncDeclaration -{ - InvariantDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - InvariantDeclaration *isInvariantDeclaration() { return this; } -}; - -struct UnitTestDeclaration : FuncDeclaration -{ - UnitTestDeclaration(Loc loc, Loc endloc); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - AggregateDeclaration *isThis(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - - UnitTestDeclaration *isUnitTestDeclaration() { return this; } -}; - -struct NewDeclaration : FuncDeclaration -{ Parameters *arguments; - int varargs; - - NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - - NewDeclaration *isNewDeclaration() { return this; } -}; - - -struct DeleteDeclaration : FuncDeclaration -{ Parameters *arguments; - - DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - int isDelete(); - int isVirtual(); - int addPreInvariant(); - int addPostInvariant(); - DeleteDeclaration *isDeleteDeclaration() { return this; } -}; - -#endif /* DMD_DECLARATION_H */ diff --git a/dmd2/delegatize.c b/dmd2/delegatize.c deleted file mode 100644 index a4d37152..00000000 --- a/dmd2/delegatize.c +++ /dev/null @@ -1,140 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" - -/******************************************** - * Convert from expression to delegate that returns the expression, - * i.e. convert: - * expr - * to: - * t delegate() { return expr; } - */ - -int lambdaSetParent(Expression *e, void *param); -int lambdaCheckForNestedRef(Expression *e, void *param); - -Expression *Expression::toDelegate(Scope *sc, Type *t) -{ - //printf("Expression::toDelegate(t = %s) %s\n", t->toChars(), toChars()); - TypeFunction *tf = new TypeFunction(NULL, t, 0, LINKd); - FuncLiteralDeclaration *fld = - new FuncLiteralDeclaration(loc, loc, tf, TOKdelegate, NULL); - Expression *e; - sc = sc->push(); - sc->parent = fld; // set current function to be the delegate - e = this; - e->apply(&lambdaSetParent, sc); - e->apply(&lambdaCheckForNestedRef, sc); - sc = sc->pop(); - Statement *s; - if (t->ty == Tvoid) - s = new ExpStatement(loc, e); - else - s = new ReturnStatement(loc, e); - fld->fbody = s; - e = new FuncExp(loc, fld); - e = e->semantic(sc); - return e; -} - -/****************************************** - * Patch the parent of declarations to be the new function literal. - */ -int lambdaSetParent(Expression *e, void *param) -{ - Scope *sc = (Scope *)param; - /* We could use virtual functions instead of a switch, - * but it doesn't seem worth the bother. - */ - switch (e->op) - { - case TOKdeclaration: - { DeclarationExp *de = (DeclarationExp *)e; - de->declaration->parent = sc->parent; - break; - } - - case TOKindex: - { IndexExp *de = (IndexExp *)e; - if (de->lengthVar) - { //printf("lengthVar\n"); - de->lengthVar->parent = sc->parent; - } - break; - } - - case TOKslice: - { SliceExp *se = (SliceExp *)e; - if (se->lengthVar) - { //printf("lengthVar\n"); - se->lengthVar->parent = sc->parent; - } - break; - } - - default: - break; - } - return 0; -} - -/******************************************* - * Look for references to variables in a scope enclosing the new function literal. - */ -int lambdaCheckForNestedRef(Expression *e, void *param) -{ - Scope *sc = (Scope *)param; - /* We could use virtual functions instead of a switch, - * but it doesn't seem worth the bother. - */ - switch (e->op) - { - case TOKsymoff: - { SymOffExp *se = (SymOffExp *)e; - VarDeclaration *v = se->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - case TOKvar: - { VarExp *ve = (VarExp *)e; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - case TOKthis: - case TOKsuper: - { ThisExp *te = (ThisExp *)e; - VarDeclaration *v = te->var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, 0); - break; - } - - default: - break; - } - return 0; -} - diff --git a/dmd2/doc.c b/dmd2/doc.c deleted file mode 100644 index ed405f24..00000000 --- a/dmd2/doc.c +++ /dev/null @@ -1,2226 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the Ddoc capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "doc.h" -#include "mtype.h" -#include "utf.h" - -struct Escape -{ - const char *strings[256]; - - static const char *escapeChar(unsigned c); -}; - -struct Section -{ - unsigned char *name; - unsigned namelen; - - unsigned char *body; - unsigned bodylen; - - int nooutput; - - virtual void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct ParamSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -struct MacroSection : Section -{ - void write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - -typedef ArrayBase
Sections; - -struct DocComment -{ - Sections sections; // Section*[] - - Section *summary; - Section *copyright; - Section *macros; - Macro **pmacrotable; - Escape **pescapetable; - - DocComment(); - - static DocComment *parse(Scope *sc, Dsymbol *s, unsigned char *comment); - static void parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen); - static void parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen); - - void parseSections(unsigned char *comment); - void writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf); -}; - - -int cmp(const char *stringz, void *s, size_t slen); -int icmp(const char *stringz, void *s, size_t slen); -int isDitto(unsigned char *comment); -unsigned char *skipwhitespace(unsigned char *p); -unsigned skiptoident(OutBuffer *buf, size_t i); -unsigned skippastident(OutBuffer *buf, size_t i); -unsigned skippastURL(OutBuffer *buf, size_t i); -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset); -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len); - -int isIdStart(unsigned char *p); -int isIdTail(unsigned char *p); -int utfStride(unsigned char *p); - -static unsigned char ddoc_default[] = "\ -DDOC = \n\ - \n\ - $(TITLE)\n\ - \n\ -

$(TITLE)

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

$0

\n\ -DL =
$0
\n\ -DT =
$0
\n\ -DD =
$0
\n\ -TABLE = $0
\n\ -TR = $0\n\ -TH = $0\n\ -TD = $0\n\ -OL =
    $0
\n\ -UL =
    $0
\n\ -LI =
  • $0
  • \n\ -BIG = $0\n\ -SMALL = $0\n\ -BR =
    \n\ -LINK = $0\n\ -LINK2 = $+\n\ -LPAREN= (\n\ -RPAREN= )\n\ -DOLLAR= $\n\ -\n\ -RED = $0\n\ -BLUE = $0\n\ -GREEN = $0\n\ -YELLOW =$0\n\ -BLACK = $0\n\ -WHITE = $0\n\ -\n\ -D_CODE =
    $0
    \n\ -D_COMMENT = $(GREEN $0)\n\ -D_STRING = $(RED $0)\n\ -D_KEYWORD = $(BLUE $0)\n\ -D_PSYMBOL = $(U $0)\n\ -D_PARAM = $(I $0)\n\ -\n\ -DDOC_COMMENT = \n\ -DDOC_DECL = $(DT $(BIG $0))\n\ -DDOC_DECL_DD = $(DD $0)\n\ -DDOC_DITTO = $(BR)$0\n\ -DDOC_SECTIONS = $0\n\ -DDOC_SUMMARY = $0$(BR)$(BR)\n\ -DDOC_DESCRIPTION = $0$(BR)$(BR)\n\ -DDOC_AUTHORS = $(B Authors:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_BUGS = $(RED BUGS:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_COPYRIGHT = $(B Copyright:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DATE = $(B Date:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_DEPRECATED = $(RED Deprecated:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_EXAMPLES = $(B Examples:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_HISTORY = $(B History:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_LICENSE = $(B License:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_RETURNS = $(B Returns:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SEE_ALSO = $(B See Also:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_STANDARDS = $(B Standards:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_THROWS = $(B Throws:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_VERSION = $(B Version:)$(BR)\n$0$(BR)$(BR)\n\ -DDOC_SECTION_H = $(B $0)$(BR)\n\ -DDOC_SECTION = $0$(BR)$(BR)\n\ -DDOC_MEMBERS = $(DL $0)\n\ -DDOC_MODULE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_CLASS_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_STRUCT_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_ENUM_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_TEMPLATE_MEMBERS = $(DDOC_MEMBERS $0)\n\ -DDOC_PARAMS = $(B Params:)$(BR)\n$(TABLE $0)$(BR)\n\ -DDOC_PARAM_ROW = $(TR $0)\n\ -DDOC_PARAM_ID = $(TD $0)\n\ -DDOC_PARAM_DESC = $(TD $0)\n\ -DDOC_BLANKLINE = $(BR)$(BR)\n\ -\n\ -DDOC_PSYMBOL = $(U $0)\n\ -DDOC_KEYWORD = $(B $0)\n\ -DDOC_PARAM = $(I $0)\n\ -\n\ -ESCAPES = //>/\n\ - /&/&/\n\ -"; - -static char ddoc_decl_s[] = "$(DDOC_DECL "; -static char ddoc_decl_e[] = ")\n"; - -static char ddoc_decl_dd_s[] = "$(DDOC_DECL_DD "; -static char ddoc_decl_dd_e[] = ")\n"; - - -/**************************************************** - */ - -void Module::gendocfile() -{ - static OutBuffer mbuf; - static int mbuf_done; - - OutBuffer buf; - - //printf("Module::gendocfile()\n"); - - if (!mbuf_done) // if not already read the ddoc files - { mbuf_done = 1; - - // Use our internal default - mbuf.write(ddoc_default, sizeof(ddoc_default) - 1); - - // Override with DDOCFILE specified in the sc.ini file - char *p = getenv("DDOCFILE"); - if (p) - global.params.ddocfiles->shift(p); - - // Override with the ddoc macro files from the command line - for (size_t i = 0; i < global.params.ddocfiles->dim; i++) - { - FileName f(global.params.ddocfiles->tdata()[i], 0); - File file(&f); - file.readv(); - // BUG: convert file contents to UTF-8 before use - - //printf("file: '%.*s'\n", file.len, file.buffer); - mbuf.write(file.buffer, file.len); - } - } - DocComment::parseMacros(&escapetable, ¯otable, mbuf.data, mbuf.offset); - - Scope *sc = Scope::createGlobal(this); // create root scope - sc->docbuf = &buf; - - DocComment *dc = DocComment::parse(sc, this, comment); - dc->pmacrotable = ¯otable; - dc->pescapetable = &escapetable; - - // Generate predefined macros - - // Set the title to be the name of the module - { const char *p = toPrettyChars(); - Macro::define(¯otable, (unsigned char *)"TITLE", 5, (unsigned char *)p, strlen(p)); - } - - // Set time macros - { time_t t; - time(&t); - char *p = ctime(&t); - p = mem.strdup(p); - Macro::define(¯otable, (unsigned char *)"DATETIME", 8, (unsigned char *)p, strlen(p)); - Macro::define(¯otable, (unsigned char *)"YEAR", 4, (unsigned char *)p + 20, 4); - } - - char *docfilename = docfile->toChars(); - Macro::define(¯otable, (unsigned char *)"DOCFILENAME", 11, (unsigned char *)docfilename, strlen(docfilename)); - - if (dc->copyright) - { - dc->copyright->nooutput = 1; - Macro::define(¯otable, (unsigned char *)"COPYRIGHT", 9, dc->copyright->body, dc->copyright->bodylen); - } - - buf.printf("$(DDOC_COMMENT Generated by Ddoc from %s)\n", srcfile->toChars()); - if (isDocFile) - { - size_t commentlen = strlen((char *)comment); - if (dc->macros) - { - commentlen = dc->macros->name - comment; - dc->macros->write(dc, sc, this, sc->docbuf); - } - sc->docbuf->write(comment, commentlen); - highlightText(NULL, this, sc->docbuf, 0); - } - else - { - dc->writeSections(sc, this, sc->docbuf); - emitMemberComments(sc); - } - - //printf("BODY= '%.*s'\n", buf.offset, buf.data); - Macro::define(¯otable, (unsigned char *)"BODY", 4, buf.data, buf.offset); - - OutBuffer buf2; - buf2.writestring("$(DDOC)\n"); - unsigned end = buf2.offset; - macrotable->expand(&buf2, 0, &end, NULL, 0); - -#if 1 - /* Remove all the escape sequences from buf2, - * and make CR-LF the newline. - */ - { - buf.setsize(0); - buf.reserve(buf2.offset); - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - unsigned char c = p[j]; - if (c == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - if (c == '\n') - buf.writeByte('\r'); - else if (c == '\r') - { - buf.writestring("\r\n"); - if (j + 1 < buf2.offset && p[j + 1] == '\n') - { - j++; - } - continue; - } - buf.writeByte(c); - } - } - - // Transfer image to file - assert(docfile); - docfile->setbuffer(buf.data, buf.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#else - /* Remove all the escape sequences from buf2 - */ - { unsigned i = 0; - unsigned char *p = buf2.data; - for (unsigned j = 0; j < buf2.offset; j++) - { - if (p[j] == 0xFF && j + 1 < buf2.offset) - { - j++; - continue; - } - p[i] = p[j]; - i++; - } - buf2.setsize(i); - } - - // Transfer image to file - docfile->setbuffer(buf2.data, buf2.offset); - docfile->ref = 1; - char *pt = FileName::path(docfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - docfile->writev(); -#endif -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - * This function replaces all ( with $(LPAREN) and ) with $(RPAREN) - * to preserve text literally. This also means macros in the - * text won't be expanded. - */ -void escapeDdocString(OutBuffer *buf, unsigned start) -{ - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '$': - buf->remove(u, 1); - buf->insert(u, "$(DOLLAR)", 9); - u += 8; - break; - - case '(': - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - - case ')': - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - break; - } - } -} - -/**************************************************** - * Having unmatched parentheses can hose the output of Ddoc, - * as the macros depend on properly nested parentheses. - - * Fix by replacing unmatched ( with $(LPAREN) and unmatched ) with $(RPAREN). - */ -void escapeStrayParenthesis(OutBuffer *buf, unsigned start, Loc loc) -{ - unsigned par_open = 0; - - for (unsigned u = start; u < buf->offset; u++) - { - unsigned char c = buf->data[u]; - switch(c) - { - case '(': - par_open++; - break; - - case ')': - if (par_open == 0) - { - //stray ')' - if (global.params.warnings) - warning(loc, "Ddoc: Stray ')'. This may cause incorrect Ddoc output." - " Use $(RPAREN) instead for unpaired right parentheses."); - buf->remove(u, 1); //remove the ) - buf->insert(u, "$(RPAREN)", 9); //insert this instead - u += 8; //skip over newly inserted macro - } - else - par_open--; - break; -#if 0 - // For this to work, loc must be set to the beginning of the passed - // text which is currently not possible - // (loc is set to the Loc of the Dsymbol) - case '\n': - loc.linnum++; - break; -#endif - } - } - - if (par_open) // if any unmatched lparens - { par_open = 0; - for (unsigned u = buf->offset; u > start;) - { u--; - unsigned char c = buf->data[u]; - switch(c) - { - case ')': - par_open++; - break; - - case '(': - if (par_open == 0) - { - //stray '(' - if (global.params.warnings) - warning(loc, "Ddoc: Stray '('. This may cause incorrect Ddoc output." - " Use $(LPAREN) instead for unpaired left parentheses."); - buf->remove(u, 1); //remove the ( - buf->insert(u, "$(LPAREN)", 9); //insert this instead - } - else - par_open--; - break; - } - } - } -} - -/******************************* emitComment **********************************/ - -/* - * Emit doc comment to documentation file - */ - -void Dsymbol::emitDitto(Scope *sc) -{ - //printf("Dsymbol::emitDitto() %s %s\n", kind(), toChars()); - OutBuffer *buf = sc->docbuf; - unsigned o; - OutBuffer b; - - b.writestring("$(DDOC_DITTO "); - o = b.offset; - toDocBuffer(&b); - //printf("b: '%.*s'\n", b.offset, b.data); - /* If 'this' is a function template, then highlightCode() was - * already run by FuncDeclaration::toDocbuffer(). - */ - TemplateDeclaration *td; - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { - } - else - highlightCode(sc, this, &b, o); - b.writeByte(')'); - buf->spread(sc->lastoffset, b.offset); - memcpy(buf->data + sc->lastoffset, b.data, b.offset); - sc->lastoffset += b.offset; -} - -void ScopeDsymbol::emitMemberComments(Scope *sc) -{ - //printf("ScopeDsymbol::emitMemberComments() %s\n", toChars()); - OutBuffer *buf = sc->docbuf; - - if (members) - { const char *m = "$(DDOC_MEMBERS \n"; - - if (isModule()) - m = "$(DDOC_MODULE_MEMBERS \n"; - else if (isClassDeclaration()) - m = "$(DDOC_CLASS_MEMBERS \n"; - else if (isStructDeclaration()) - m = "$(DDOC_STRUCT_MEMBERS \n"; - else if (isEnumDeclaration()) - m = "$(DDOC_ENUM_MEMBERS \n"; - else if (isTemplateDeclaration()) - m = "$(DDOC_TEMPLATE_MEMBERS \n"; - - 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 (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - //printf("\ts = '%s'\n", s->toChars()); - s->emitComment(sc); - } - sc->pop(); - if (buf->offset == offset2) - { - /* Didn't write out any members, so back out last write - */ - buf->offset = offset1; - } - else - buf->writestring(")\n"); - } -} - -void emitProtection(OutBuffer *buf, PROT prot) -{ - const char *p; - - switch (prot) - { - case PROTpackage: p = "package"; break; - case PROTprotected: p = "protected"; break; - case PROTexport: p = "export"; break; - default: p = NULL; break; - } - if (p) - buf->printf("%s ", p); -} - -void Dsymbol::emitComment(Scope *sc) { } -void InvariantDeclaration::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) { } -void ClassInfoDeclaration::emitComment(Scope *sc) { } -void ModuleInfoDeclaration::emitComment(Scope *sc) { } -void TypeInfoDeclaration::emitComment(Scope *sc) { } - - -void Declaration::emitComment(Scope *sc) -{ - //printf("Declaration::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - //printf("type = %p\n", type); - - if (protection == PROTprivate || !ident || - (!type && !isCtorDeclaration() && !isAliasDeclaration())) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -void AggregateDeclaration::emitComment(Scope *sc) -{ - //printf("AggregateDeclaration::emitComment() '%s'\n", toChars()); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void TemplateDeclaration::emitComment(Scope *sc) -{ - //printf("TemplateDeclaration::emitComment() '%s', kind = %s\n", toChars(), kind()); - if (prot() == PROTprivate) - return; - - unsigned char *com = comment; - int hasmembers = 1; - - Dsymbol *ss = this; - - if (onemember) - { - ss = onemember->isAggregateDeclaration(); - if (!ss) - { - ss = onemember->isFuncDeclaration(); - if (ss) - { hasmembers = 0; - if (com != ss->comment) - com = Lexer::combineComments(com, ss->comment); - } - else - ss = this; - } - } - - if (!com) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, com); - unsigned o; - - if (!dc) - { - ss->emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - ss->toDocBuffer(buf); - if (ss == this) - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - if (hasmembers) - ((ScopeDsymbol *)ss)->emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumDeclaration::emitComment(Scope *sc) -{ - if (prot() == PROTprivate) - return; -// if (!comment) - { if (isAnonymous() && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[i]; - s->emitComment(sc); - } - return; - } - } - if (!comment) - return; - if (isAnonymous()) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - toDocBuffer(buf); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - emitMemberComments(sc); - buf->writestring(ddoc_decl_dd_e); -} - -void EnumMember::emitComment(Scope *sc) -{ - //printf("EnumMember::emitComment(%p '%s'), comment = '%s'\n", this, toChars(), comment); - if (prot() == PROTprivate) - return; - if (!comment) - return; - - OutBuffer *buf = sc->docbuf; - DocComment *dc = DocComment::parse(sc, this, comment); - unsigned o; - - if (!dc) - { - emitDitto(sc); - return; - } - dc->pmacrotable = &sc->module->macrotable; - - buf->writestring(ddoc_decl_s); - o = buf->offset; - toDocBuffer(buf); - highlightCode(sc, this, buf, o); - sc->lastoffset = buf->offset; - buf->writestring(ddoc_decl_e); - - buf->writestring(ddoc_decl_dd_s); - dc->writeSections(sc, this, buf); - buf->writestring(ddoc_decl_dd_e); -} - -/******************************* toDocBuffer **********************************/ - -void Dsymbol::toDocBuffer(OutBuffer *buf) -{ - //printf("Dsymbol::toDocbuffer() %s\n", toChars()); - HdrGenState hgs; - - hgs.ddoc = 1; - toCBuffer(buf, &hgs); -} - -void prefix(OutBuffer *buf, Dsymbol *s) -{ - if (s->isDeprecated()) - buf->writestring("deprecated "); - Declaration *d = s->isDeclaration(); - if (d) - { - emitProtection(buf, d->protection); - if (d->isAbstract()) - buf->writestring("abstract "); - if (d->isStatic()) - buf->writestring("static "); - if (d->isConst()) - buf->writestring("const "); -#if DMDV2 - if (d->isImmutable()) - buf->writestring("immutable "); -#endif - if (d->isFinal()) - buf->writestring("final "); - if (d->isSynchronized()) - buf->writestring("synchronized "); - } -} - -void declarationToDocBuffer(Declaration *decl, OutBuffer *buf, TemplateDeclaration *td) -{ - //printf("declarationToDocBuffer() %s, originalType = %s, td = %s\n", decl->toChars(), decl->originalType ? decl->originalType->toChars() : "--", td ? td->toChars() : "--"); - if (decl->ident) - { - prefix(buf, decl); - - if (decl->type) - { HdrGenState hgs; - hgs.ddoc = 1; - Type *origType = decl->originalType ? decl->originalType : decl->type; - if (origType->ty == Tfunction) - { - TypeFunction *attrType = (TypeFunction*)(decl->ident == Id::ctor ? origType : decl->type); - ((TypeFunction*)origType)->toCBufferWithAttributes(buf, decl->ident, &hgs, attrType, td); - } - else - origType->toCBuffer(buf, decl->ident, &hgs); - } - else - buf->writestring(decl->ident->toChars()); - buf->writestring(";\n"); - } -} - -void Declaration::toDocBuffer(OutBuffer *buf) -{ - declarationToDocBuffer(this, buf, NULL); -} - -void AliasDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("AliasDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("alias "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void TypedefDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - if (isDeprecated()) - buf->writestring("deprecated "); - - emitProtection(buf, protection); - buf->writestring("typedef "); - buf->writestring(toChars()); - buf->writestring(";\n"); - } -} - - -void FuncDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("FuncDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { /* It's a function template - */ - unsigned o = buf->offset; - - declarationToDocBuffer(this, buf, td); - - highlightCode(NULL, this, buf, o); - } - else - { - Declaration::toDocBuffer(buf); - } - } -} - -#if DMDV1 -void CtorDeclaration::toDocBuffer(OutBuffer *buf) -{ - HdrGenState hgs; - - buf->writestring("this"); - Parameter::argsToCBuffer(buf, &hgs, arguments, varargs); - buf->writestring(";\n"); -} -#endif - -void AggregateDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void StructDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("StructDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - buf->writestring(";\n"); - } -} - -void ClassDeclaration::toDocBuffer(OutBuffer *buf) -{ - //printf("ClassDeclaration::toDocbuffer() %s\n", toChars()); - if (ident) - { -#if 0 - emitProtection(buf, protection); -#endif - TemplateDeclaration *td; - - if (parent && - (td = parent->isTemplateDeclaration()) != NULL && - td->onemember == this) - { unsigned o = buf->offset; - td->toDocBuffer(buf); - highlightCode(NULL, this, buf, o); - } - else - { - if (isAbstract()) - buf->writestring("abstract "); - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - } - int any = 0; - for (size_t i = 0; i < baseclasses->dim; i++) - { BaseClass *bc = (*baseclasses)[i]; - - if (bc->protection == PROTprivate) - continue; - if (bc->base && bc->base->ident == Id::Object) - continue; - - if (any) - buf->writestring(", "); - else - { buf->writestring(": "); - any = 1; - } - emitProtection(buf, bc->protection); - if (bc->base) - { - buf->writestring(bc->base->toPrettyChars()); - } - else - { - HdrGenState hgs; - bc->type->toCBuffer(buf, NULL, &hgs); - } - } - buf->writestring(";\n"); - } -} - - -void EnumDeclaration::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->printf("%s $(DDOC_PSYMBOL %s)", kind(), toChars()); - buf->writestring(";\n"); - } -} - -void EnumMember::toDocBuffer(OutBuffer *buf) -{ - if (ident) - { - buf->writestring(toChars()); - } -} - - -/********************************* DocComment *********************************/ - -DocComment::DocComment() -{ - memset(this, 0, sizeof(DocComment)); -} - -DocComment *DocComment::parse(Scope *sc, Dsymbol *s, unsigned char *comment) -{ - //printf("parse(%s): '%s'\n", s->toChars(), comment); - if (sc->lastdc && isDitto(comment)) - return NULL; - - DocComment *dc = new DocComment(); - if (!comment) - return dc; - - dc->parseSections(comment); - - for (size_t i = 0; i < dc->sections.dim; i++) - { Section *sec = dc->sections[i]; - - if (icmp("copyright", sec->name, sec->namelen) == 0) - { - dc->copyright = sec; - } - if (icmp("macros", sec->name, sec->namelen) == 0) - { - dc->macros = sec; - } - } - - sc->lastdc = dc; - return dc; -} - -/***************************************** - * Parse next paragraph out of *pcomment. - * Update *pcomment to point past paragraph. - * Returns NULL if no more paragraphs. - * If paragraph ends in 'identifier:', - * then (*pcomment)[0 .. idlen] is the identifier. - */ - -void DocComment::parseSections(unsigned char *comment) -{ unsigned char *p; - unsigned char *pstart; - unsigned char *pend; - unsigned char *idstart; - unsigned idlen; - - unsigned char *name = NULL; - unsigned namelen = 0; - - //printf("parseSections('%s')\n", comment); - p = comment; - while (*p) - { - p = skipwhitespace(p); - pstart = p; - pend = p; - - /* Find end of section, which is ended by one of: - * 'identifier:' (but not inside a code section) - * '\0' - */ - idlen = 0; - int inCode = 0; - while (1) - { - // Check for start/end of a code section - if (*p == '-') - { - int numdash = 0; - while (*p == '-') - { - ++numdash; - p++; - } - // BUG: handle UTF PS and LS too - if (!*p || *p == '\r' || *p == '\n' && numdash >= 3) - inCode ^= 1; - pend = p; - } - - if (!inCode && isIdStart(p)) - { - unsigned char *q = p + utfStride(p); - while (isIdTail(q)) - q += utfStride(q); - if (*q == ':') // identifier: ends it - { idlen = q - p; - idstart = p; - for (pend = p; pend > pstart; pend--) - { if (pend[-1] == '\n') - break; - } - p = q + 1; - break; - } - } - while (1) - { - if (!*p) - goto L1; - if (*p == '\n') - { p++; - if (*p == '\n' && !summary && !namelen && !inCode) - { - pend = p; - p++; - goto L1; - } - break; - } - p++; - pend = p; - } - p = skipwhitespace(p); - } - L1: - - if (namelen || pstart < pend) - { - Section *s; - if (icmp("Params", name, namelen) == 0) - s = new ParamSection(); - else if (icmp("Macros", name, namelen) == 0) - s = new MacroSection(); - else - s = new Section(); - s->name = name; - s->namelen = namelen; - s->body = pstart; - s->bodylen = pend - pstart; - s->nooutput = 0; - - //printf("Section: '%.*s' = '%.*s'\n", s->namelen, s->name, s->bodylen, s->body); - - sections.push(s); - - if (!summary && !namelen) - summary = s; - } - - if (idlen) - { name = idstart; - namelen = idlen; - } - else - { name = NULL; - namelen = 0; - if (!*p) - break; - } - } -} - -void DocComment::writeSections(Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("DocComment::writeSections()\n"); - if (sections.dim) - { - buf->writestring("$(DDOC_SECTIONS \n"); - for (size_t i = 0; i < sections.dim; i++) - { Section *sec = sections[i]; - - if (sec->nooutput) - continue; - //printf("Section: '%.*s' = '%.*s'\n", sec->namelen, sec->name, sec->bodylen, sec->body); - if (sec->namelen || i) - sec->write(this, sc, s, buf); - else - { - buf->writestring("$(DDOC_SUMMARY "); - unsigned o = buf->offset; - buf->write(sec->body, sec->bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); - } - } - buf->writestring(")\n"); - } - else - { - buf->writestring("$(DDOC_BLANKLINE)\n"); - } -} - -/*************************************************** - */ - -void Section::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - if (namelen) - { - static const char *table[] = - { "AUTHORS", "BUGS", "COPYRIGHT", "DATE", - "DEPRECATED", "EXAMPLES", "HISTORY", "LICENSE", - "RETURNS", "SEE_ALSO", "STANDARDS", "THROWS", - "VERSION" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (icmp(table[i], name, namelen) == 0) - { - buf->printf("$(DDOC_%s ", table[i]); - goto L1; - } - } - - buf->writestring("$(DDOC_SECTION "); - // Replace _ characters with spaces - buf->writestring("$(DDOC_SECTION_H "); - unsigned o = buf->offset; - for (unsigned u = 0; u < namelen; u++) - { unsigned char c = name[u]; - buf->writeByte((c == '_') ? ' ' : c); - } - escapeStrayParenthesis(buf, o, s->loc); - buf->writestring(":)\n"); - } - else - { - buf->writestring("$(DDOC_DESCRIPTION "); - } - L1: - unsigned o = buf->offset; - buf->write(body, bodylen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void ParamSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - unsigned char *p = body; - unsigned len = bodylen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - unsigned o; - Parameter *arg; - - buf->writestring("$(DDOC_PARAMS \n"); - while (p < pend) - { - // Skip to start of macro - while (1) - { - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (isIdTail(p)) - p += utfStride(p); - templen = p - tempstart; - - while (*p == ' ' || *p == '\t') - p++; - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - - if (namelen) - { // Output existing param - - L1: - //printf("param '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - HdrGenState hgs; - buf->writestring("$(DDOC_PARAM_ROW "); - buf->writestring("$(DDOC_PARAM_ID "); - o = buf->offset; - arg = isFunctionParameter(s, namestart, namelen); - if (arg && arg->type && arg->ident) - arg->type->toCBuffer(buf, arg->ident, &hgs); - else - buf->write(namestart, namelen); - escapeStrayParenthesis(buf, o, s->loc); - highlightCode(sc, s, buf, o); - buf->writestring(")\n"); - - buf->writestring("$(DDOC_PARAM_DESC "); - o = buf->offset; - buf->write(textstart, textlen); - escapeStrayParenthesis(buf, o, s->loc); - highlightText(sc, s, buf, o); - buf->writestring(")"); - buf->writestring(")\n"); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (*p == ' ' || *p == '\t') - p++; - textstart = p; - - Ltext: - while (*p != '\n') - p++; - textlen = p - textstart; - p++; - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (*p++ != '\n') - ; - } - if (namelen) - goto L1; // write out last one - buf->writestring(")\n"); -} - -/*************************************************** - */ - -void MacroSection::write(DocComment *dc, Scope *sc, Dsymbol *s, OutBuffer *buf) -{ - //printf("MacroSection::write()\n"); - DocComment::parseMacros(dc->pescapetable, dc->pmacrotable, body, bodylen); -} - -/************************************************ - * Parse macros out of Macros: section. - * Macros are of the form: - * name1 = value1 - * - * name2 = value2 - */ - -void DocComment::parseMacros(Escape **pescapetable, Macro **pmacrotable, unsigned char *m, unsigned mlen) -{ - unsigned char *p = m; - unsigned len = mlen; - unsigned char *pend = p + len; - - unsigned char *tempstart; - unsigned templen; - - unsigned char *namestart; - unsigned namelen = 0; // !=0 if line continuation - - unsigned char *textstart; - unsigned textlen; - - while (p < pend) - { - // Skip to start of macro - while (1) - { - if (p >= pend) - goto Ldone; - switch (*p) - { - case ' ': - case '\t': - p++; - continue; - - case '\n': - p++; - goto Lcont; - - default: - if (isIdStart(p)) - break; - if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - break; - } - tempstart = p; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!isIdTail(p)) - break; - p += utfStride(p); - } - templen = p - tempstart; - - while (1) - { - if (p >= pend) - goto Ldone; - if (!(*p == ' ' || *p == '\t')) - break; - p++; - } - - if (*p != '=') - { if (namelen) - goto Ltext; // continuation of prev macro - goto Lskipline; - } - p++; - if (p >= pend) - goto Ldone; - - if (namelen) - { // Output existing macro - L1: - //printf("macro '%.*s' = '%.*s'\n", namelen, namestart, textlen, textstart); - if (icmp("ESCAPES", namestart, namelen) == 0) - parseEscapes(pescapetable, textstart, textlen); - else - Macro::define(pmacrotable, namestart, namelen, textstart, textlen); - namelen = 0; - if (p >= pend) - break; - } - - namestart = tempstart; - namelen = templen; - - while (p < pend && (*p == ' ' || *p == '\t')) - p++; - textstart = p; - - Ltext: - while (p < pend && *p != '\n') - p++; - textlen = p - textstart; - - // Remove trailing \r if there is one - if (p > m && p[-1] == '\r') - textlen--; - - p++; - //printf("p = %p, pend = %p\n", p, pend); - - Lcont: - continue; - - Lskipline: - // Ignore this line - while (p < pend && *p++ != '\n') - ; - } -Ldone: - if (namelen) - goto L1; // write out last one -} - -/************************************** - * Parse escapes of the form: - * /c/string/ - * where c is a single character. - * Multiple escapes can be separated - * by whitespace and/or commas. - */ - -void DocComment::parseEscapes(Escape **pescapetable, unsigned char *textstart, unsigned textlen) -{ Escape *escapetable = *pescapetable; - - if (!escapetable) - { escapetable = new Escape; - *pescapetable = escapetable; - } - unsigned char *p = textstart; - unsigned char *pend = p + textlen; - - while (1) - { - while (1) - { - if (p + 4 >= pend) - return; - if (!(*p == ' ' || *p == '\t' || *p == '\n' || *p == ',')) - break; - p++; - } - if (p[0] != '/' || p[2] != '/') - return; - unsigned char c = p[1]; - p += 3; - unsigned char *start = p; - while (1) - { - if (p >= pend) - return; - if (*p == '/') - break; - p++; - } - size_t len = p - start; - char *s = (char *)memcpy(mem.malloc(len + 1), start, len); - s[len] = 0; - escapetable->strings[c] = s; - //printf("%c = '%s'\n", c, s); - p++; - } -} - - -/****************************************** - * Compare 0-terminated string with length terminated string. - * Return < 0, ==0, > 0 - */ - -int cmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memcmp(stringz, s, slen); -} - -int icmp(const char *stringz, void *s, size_t slen) -{ - size_t len1 = strlen(stringz); - - if (len1 != slen) - return len1 - slen; - return memicmp(stringz, (char *)s, slen); -} - -/***************************************** - * Return !=0 if comment consists entirely of "ditto". - */ - -int isDitto(unsigned char *comment) -{ - if (comment) - { - unsigned char *p = skipwhitespace(comment); - - if (memicmp((char *)p, "ditto", 5) == 0 && *skipwhitespace(p + 5) == 0) - return 1; - } - return 0; -} - -/********************************************** - * Skip white space. - */ - -unsigned char *skipwhitespace(unsigned char *p) -{ - for (; 1; p++) - { switch (*p) - { - case ' ': - case '\t': - case '\n': - continue; - } - break; - } - return p; -} - - -/************************************************ - * Scan forward to one of: - * start of identifier - * beginning of next line - * end of buf - */ - -unsigned skiptoident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (!isUniAlpha(c)) - continue; - } - else if (!(isalpha(c) || c == '_' || c == '\n')) - continue; - i = oi; - break; - } - return i; -} - -/************************************************ - * Scan forward past end of identifier. - */ - -unsigned skippastident(OutBuffer *buf, size_t i) -{ - while (i < buf->offset) - { dchar_t c; - - size_t oi = i; - if (utf_decodeChar((unsigned char *)buf->data, buf->offset, &i, &c)) - /* Ignore UTF errors, but still consume input - */ - break; - if (c >= 0x80) - { - if (isUniAlpha(c)) - continue; - } - else if (isalnum(c) || c == '_') - continue; - i = oi; - break; - } - return i; -} - - -/************************************************ - * Scan forward past URL starting at i. - * We don't want to highlight parts of a URL. - * Returns: - * i if not a URL - * index just past it if it is a URL - */ - -unsigned skippastURL(OutBuffer *buf, size_t i) -{ unsigned length = buf->offset - i; - unsigned char *p = &buf->data[i]; - unsigned j; - unsigned sawdot = 0; - - if (length > 7 && memicmp((char *)p, "http://", 7) == 0) - { - j = 7; - } - else if (length > 8 && memicmp((char *)p, "https://", 8) == 0) - { - j = 8; - } - else - goto Lno; - - for (; j < length; j++) - { unsigned char c = p[j]; - if (isalnum(c)) - continue; - if (c == '-' || c == '_' || c == '?' || - c == '=' || c == '%' || c == '&' || - c == '/' || c == '+' || c == '#' || - c == '~') - continue; - if (c == '.') - { - sawdot = 1; - continue; - } - break; - } - if (sawdot) - return i + j; - -Lno: - return i; -} - - -/**************************************************** - */ - -int isKeyword(unsigned char *p, unsigned len) -{ - static const char *table[] = { "true", "false", "null" }; - - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (cmp(table[i], p, len) == 0) - return 1; - } - return 0; -} - -/**************************************************** - */ - -Parameter *isFunctionParameter(Dsymbol *s, unsigned char *p, unsigned len) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - - /* f->type may be NULL for template members. - */ - if (f && f->type) - { - TypeFunction *tf; - if (f->originalType) - { - tf = (TypeFunction *)f->originalType; - } - else - tf = (TypeFunction *)f->type; - - if (tf->parameters) - { - for (size_t k = 0; k < tf->parameters->dim; k++) - { Parameter *arg = (*tf->parameters)[k]; - - if (arg->ident && cmp(arg->ident->toChars(), p, len) == 0) - { - return arg; - } - } - } - } - return NULL; -} - -/************************************************** - * Highlight text section. - */ - -void highlightText(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - //printf("highlightText()\n"); - const char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned char *p; - const char *se; - - int leadingBlank = 1; - int inCode = 0; - int inComment = 0; // in comment - unsigned iCodeStart; // start of code section - - unsigned iLineStart = offset; - - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - - Lcont: - switch (c) - { - case ' ': - case '\t': - break; - - case '\n': - if (sc && !inCode && i == iLineStart && i + 1 < buf->offset) // if "\n\n" - { - static char blankline[] = "$(DDOC_BLANKLINE)\n"; - - i = buf->insert(i, blankline, sizeof(blankline) - 1); - } - leadingBlank = 1; - iLineStart = i + 1; - break; - - case '<': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - - // Skip over comments - if (p[1] == '!' && p[2] == '-' && p[3] == '-') - { unsigned j = i + 4; - p += 4; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '-' && p[1] == '-' && p[2] == '>') - { - i = j + 2; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - // Skip over HTML tag - if (isalpha(p[1]) || (p[1] == '/' && isalpha(p[2]))) - { unsigned j = i + 2; - p += 2; - while (1) - { - if (j == buf->offset) - goto L1; - if (p[0] == '>') - { - i = j; // place on closing '>' - break; - } - j++; - p++; - } - break; - } - - L1: - // Replace '<' with '<' character entity - se = Escape::escapeChar('<'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '>': - leadingBlank = 0; - if (inCode) - break; - // Replace '>' with '>' character entity - se = Escape::escapeChar('>'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '&': - leadingBlank = 0; - if (inCode) - break; - p = &buf->data[i]; - if (p[1] == '#' || isalpha(p[1])) - break; // already a character entity - // Replace '&' with '&' character entity - se = Escape::escapeChar('&'); - if (se) - { size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - break; - - case '-': - /* A line beginning with --- delimits a code section. - * inCode tells us if it is start or end of a code section. - */ - if (leadingBlank) - { int istart = i; - int eollen = 0; - - leadingBlank = 0; - while (1) - { - ++i; - if (i >= buf->offset) - break; - c = buf->data[i]; - if (c == '\n') - { eollen = 1; - break; - } - if (c == '\r') - { - eollen = 1; - if (i + 1 >= buf->offset) - break; - if (buf->data[i + 1] == '\n') - { eollen = 2; - break; - } - } - // BUG: handle UTF PS and LS too - if (c != '-') - goto Lcont; - } - if (i - istart < 3) - goto Lcont; - - // We have the start/end of a code section - - // Remove the entire --- line, including blanks and \n - buf->remove(iLineStart, i - iLineStart + eollen); - i = iLineStart; - - if (inCode && (i <= iCodeStart)) - { // Empty code section, just remove it completely. - inCode = 0; - break; - } - - if (inCode) - { - inCode = 0; - // The code section is from iCodeStart to i - OutBuffer codebuf; - - codebuf.write(buf->data + iCodeStart, i - iCodeStart); - codebuf.writeByte(0); - highlightCode2(sc, s, &codebuf, 0); - buf->remove(iCodeStart, i - iCodeStart); - i = buf->insert(iCodeStart, codebuf.data, codebuf.offset); - i = buf->insert(i, ")\n", 2); - i--; - } - else - { static char pre[] = "$(D_CODE \n"; - - inCode = 1; - i = buf->insert(i, pre, sizeof(pre) - 1); - iCodeStart = i; - i--; // place i on > - leadingBlank = true; - } - } - break; - - default: - leadingBlank = 0; - if (sc && !inCode && isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - unsigned k = skippastURL(buf, i); - if (k > i) - { i = k - 1; - break; - } - - if (buf->data[i] == '_') // leading '_' means no highlight - { - buf->remove(i, 1); - i = j - 1; - } - else - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - break; - } - else if (isKeyword(buf->data + i, j - i)) - { - i = buf->bracket(i, "$(DDOC_KEYWORD ", j, ")") - 1; - break; - } - else - { - if (f && isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - break; - } - } - i = j - 1; - } - } - } - break; - } - } - if (inCode) - s->error("unmatched --- in DDoc comment"); - ; -} - -/************************************************** - * Highlight code for DDOC section. - */ - -void highlightCode(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - - //printf("highlightCode(s = '%s', kind = %s)\n", sid, s->kind()); - for (unsigned i = offset; i < buf->offset; i++) - { unsigned char c = buf->data[i]; - const char *se; - - se = Escape::escapeChar(c); - if (se) - { - size_t len = strlen(se); - buf->remove(i, 1); - i = buf->insert(i, se, len); - i--; // point to ';' - } - else if (isIdStart(&buf->data[i])) - { unsigned j; - - j = skippastident(buf, i); - if (j > i) - { - if (cmp(sid, buf->data + i, j - i) == 0) - { - i = buf->bracket(i, "$(DDOC_PSYMBOL ", j, ")") - 1; - continue; - } - else if (f) - { - if (isFunctionParameter(f, buf->data + i, j - i)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - i = buf->bracket(i, "$(DDOC_PARAM ", j, ")") - 1; - continue; - } - } - i = j - 1; - } - } - } -} - -/**************************************** - */ - -void highlightCode3(OutBuffer *buf, unsigned char *p, unsigned char *pend) -{ - for (; p < pend; p++) - { const char *s = Escape::escapeChar(*p); - if (s) - buf->writestring(s); - else - buf->writeByte(*p); - } -} - -/************************************************** - * Highlight code for CODE section. - */ - - -void highlightCode2(Scope *sc, Dsymbol *s, OutBuffer *buf, unsigned offset) -{ - char *sid = s->ident->toChars(); - FuncDeclaration *f = s->isFuncDeclaration(); - unsigned errorsave = global.errors; - Lexer lex(NULL, buf->data, 0, buf->offset - 1, 0, 1); - Token tok; - OutBuffer res; - unsigned char *lastp = buf->data; - const char *highlight; - - //printf("highlightCode2('%.*s')\n", buf->offset - 1, buf->data); - res.reserve(buf->offset); - while (1) - { - lex.scan(&tok); - highlightCode3(&res, lastp, tok.ptr); - highlight = NULL; - switch (tok.value) - { - case TOKidentifier: - if (!sc) - break; - if (cmp(sid, tok.ptr, lex.p - tok.ptr) == 0) - { - highlight = "$(D_PSYMBOL "; - break; - } - else if (f) - { - if (isFunctionParameter(f, tok.ptr, lex.p - tok.ptr)) - { - //printf("highlighting arg '%s', i = %d, j = %d\n", arg->ident->toChars(), i, j); - highlight = "$(D_PARAM "; - break; - } - } - break; - - case TOKcomment: - highlight = "$(D_COMMENT "; - break; - - case TOKstring: - highlight = "$(D_STRING "; - break; - - default: - if (tok.isKeyword()) - highlight = "$(D_KEYWORD "; - break; - } - if (highlight) - res.writestring(highlight); - highlightCode3(&res, tok.ptr, lex.p); - if (highlight) - res.writeByte(')'); - if (tok.value == TOKeof) - break; - lastp = lex.p; - } - buf->setsize(offset); - buf->write(&res); - global.errors = errorsave; -} - -/*************************************** - * Find character string to replace c with. - */ - -const char *Escape::escapeChar(unsigned c) -{ const char *s; - - switch (c) - { - case '<': - s = "<"; - break; - case '>': - s = ">"; - break; - case '&': - s = "&"; - break; - default: - s = NULL; - break; - } - return s; -} - -/**************************************** - * Determine if p points to the start of an identifier. - */ - -int isIdStart(unsigned char *p) -{ - unsigned c = *p; - if (isalpha(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/**************************************** - * Determine if p points to the rest of an identifier. - */ - -int isIdTail(unsigned char *p) -{ - unsigned c = *p; - if (isalnum(c) || c == '_') - return 1; - if (c >= 0x80) - { size_t i = 0; - if (utf_decodeChar(p, 4, &i, &c)) - return 0; // ignore errors - if (isUniAlpha(c)) - return 1; - } - return 0; -} - -/***************************************** - * Return number of bytes in UTF character. - */ - -int utfStride(unsigned char *p) -{ - unsigned c = *p; - if (c < 0x80) - return 1; - size_t i = 0; - utf_decodeChar(p, 4, &i, &c); // ignore errors, but still consume input - return i; -} diff --git a/dmd2/doc.h b/dmd2/doc.h deleted file mode 100644 index ffa97fb9..00000000 --- a/dmd2/doc.h +++ /dev/null @@ -1,20 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_DOC_H -#define DMD_DOC_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -void escapeDdocString(OutBuffer *buf, unsigned start); - -#endif diff --git a/dmd2/dsymbol.c b/dmd2/dsymbol.c deleted file mode 100644 index 45c2641c..00000000 --- a/dmd2/dsymbol.c +++ /dev/null @@ -1,1476 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" -#include "speller.h" -#include "aav.h" - -#include "mars.h" -#include "dsymbol.h" -#include "aggregate.h" -#include "identifier.h" -#include "module.h" -#include "mtype.h" -#include "expression.h" -#include "statement.h" -#include "declaration.h" -#include "id.h" -#include "scope.h" -#include "init.h" -#include "import.h" -#include "template.h" -#include "attrib.h" -#if IN_LLVM -#include "../gen/pragma.h" -#endif - -/****************************** Dsymbol ******************************/ - -Dsymbol::Dsymbol() -{ - //printf("Dsymbol::Dsymbol(%p)\n", this); - this->ident = NULL; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -Dsymbol::Dsymbol(Identifier *ident) -{ - //printf("Dsymbol::Dsymbol(%p, ident)\n", this); - this->ident = ident; - this->c_ident = NULL; - this->parent = NULL; -#if IN_DMD - this->csym = NULL; - this->isym = NULL; -#endif - this->loc = 0; - this->comment = NULL; - this->scope = NULL; - -#if IN_LLVM - this->llvmInternal = LLVMnone; - this->irsym = NULL; -#endif -} - -int Dsymbol::equals(Object *o) -{ Dsymbol *s; - - if (this == o) - return TRUE; - s = (Dsymbol *)(o); - // Overload sets don't have an ident - if (s && ident && s->ident && ident->equals(s->ident)) - return TRUE; - return FALSE; -} - -/************************************** - * Copy the syntax. - * Used for template instantiations. - * If s is NULL, allocate the new object, otherwise fill it in. - */ - -Dsymbol *Dsymbol::syntaxCopy(Dsymbol *s) -{ - print(); - printf("%s %s\n", kind(), toChars()); - assert(0); - return NULL; -} - -/************************************** - * Determine if this symbol is only one. - * Returns: - * FALSE, *ps = NULL: There are 2 or more symbols - * TRUE, *ps = NULL: There are zero symbols - * TRUE, *ps = symbol: The one and only one symbol - */ - -int Dsymbol::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMember()\n"); - *ps = this; - return TRUE; -} - -/***************************************** - * Same as Dsymbol::oneMember(), but look at an array of Dsymbols. - */ - -int Dsymbol::oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident) -{ - //printf("Dsymbol::oneMembers() %d\n", members ? members->dim : 0); - Dsymbol *s = NULL; - - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *sx = (*members)[i]; - - int x = sx->oneMember(ps, ident); - //printf("\t[%d] kind %s = %d, s = %p\n", i, sx->kind(), x, *ps); - if (!x) - { - //printf("\tfalse 1\n"); - assert(*ps == NULL); - return FALSE; - } - if (*ps) - { - if (ident) - { - if (!(*ps)->ident || !(*ps)->ident->equals(ident)) - continue; - } - if (s) // more than one symbol - { *ps = NULL; - //printf("\tfalse 2\n"); - return FALSE; - } - s = *ps; - } - } - } - *ps = s; // s is the one symbol, NULL if none - //printf("\ttrue\n"); - return TRUE; -} - -/***************************************** - * Is Dsymbol a variable that contains pointers? - */ - -int Dsymbol::hasPointers() -{ - //printf("Dsymbol::hasPointers() %s\n", toChars()); - return 0; -} - -bool Dsymbol::hasStaticCtorOrDtor() -{ - //printf("Dsymbol::hasStaticCtorOrDtor() %s\n", toChars()); - return FALSE; -} - -char *Dsymbol::toChars() -{ - return ident ? ident->toChars() : (char *)"__anonymous"; -} - -const char *Dsymbol::toPrettyChars() -{ Dsymbol *p; - char *s; - char *q; - size_t len; - - //printf("Dsymbol::toPrettyChars() '%s'\n", toChars()); - if (!parent) - return toChars(); - - len = 0; - for (p = this; p; p = p->parent) - len += strlen(p->toChars()) + 1; - - s = (char *)mem.malloc(len); - q = s + len - 1; - *q = 0; - for (p = this; p; p = p->parent) - { - char *t = p->toChars(); - len = strlen(t); - q -= len; - memcpy(q, t, len); - if (q == s) - break; - q--; -#if TARGET_NET - if (AggregateDeclaration* ad = p->isAggregateDeclaration()) - { - if (ad->isNested() && p->parent && p->parent->isAggregateDeclaration()) - { - *q = '/'; - continue; - } - } -#endif - *q = '.'; - } - return s; -} - -char *Dsymbol::locToChars() -{ - OutBuffer buf; - - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - return loc.toChars(); -} - -const char *Dsymbol::kind() -{ - return "symbol"; -} - -/********************************* - * If this symbol is really an alias for another, - * return that other. - */ - -Dsymbol *Dsymbol::toAlias() -{ - return this; -} - -Dsymbol *Dsymbol::toParent() -{ - return parent ? parent->pastMixin() : NULL; -} - -Dsymbol *Dsymbol::pastMixin() -{ - Dsymbol *s = this; - - //printf("Dsymbol::pastMixin() %s\n", toChars()); - while (s && s->isTemplateMixin()) - s = s->parent; - return s; -} - -/********************************** - * Use this instead of toParent() when looking for the - * 'this' pointer of the enclosing function/class. - */ - -Dsymbol *Dsymbol::toParent2() -{ - Dsymbol *s = parent; - while (s && s->isTemplateInstance()) - s = s->parent; - 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() -{ - return ident ? 0 : 1; -} - -/************************************* - * Set scope for future semantic analysis so we can - * deal better with forward references. - */ - -void Dsymbol::setScope(Scope *sc) -{ - //printf("Dsymbol::setScope() %p %s\n", this, toChars()); - if (!sc->nofree) - sc->setNoFree(); // may need it even after semantic() finishes - scope = sc; -} - -void Dsymbol::importAll(Scope *sc) -{ -} - -/************************************* - * Does semantic analysis on the public face of declarations. - */ - -void Dsymbol::semantic0(Scope *sc) -{ -} - -void Dsymbol::semantic(Scope *sc) -{ - error("%p has no semantic routine", this); -} - -/************************************* - * Does semantic analysis on initializers and members of aggregates. - */ - -void Dsymbol::semantic2(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Does semantic analysis on function bodies. - */ - -void Dsymbol::semantic3(Scope *sc) -{ - // Most Dsymbols have no further semantic analysis needed -} - -/************************************* - * Look for function inlining possibilities. - */ - -void Dsymbol::inlineScan() -{ - // Most Dsymbols aren't functions -} - -/********************************************* - * 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()); - return NULL; -} - -/*************************************************** - * Search for symbol with correct spelling. - */ - -void *symbol_search_fp(void *arg, const char *seed) -{ - Dsymbol *s = (Dsymbol *)arg; - Identifier id(seed, 0); - Module::clearCache(); - s = s->search(0, &id, 4|2); - return s; -} - -Dsymbol *Dsymbol::search_correct(Identifier *ident) -{ - if (global.gag) - return NULL; // don't do it for speculative compiles; too time consuming - - return (Dsymbol *)speller(ident->toChars(), &symbol_search_fp, this, idchars); -} - -/*************************************** - * Search for identifier id as a member of 'this'. - * id may be a template instance. - * Returns: - * symbol found, NULL if not - */ - -Dsymbol *Dsymbol::searchX(Loc loc, Scope *sc, Identifier *id) -{ - //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident->toChars()); - Dsymbol *s = toAlias(); - Dsymbol *sm; - - switch (id->dyncast()) - { - case DYNCAST_IDENTIFIER: - sm = s->search(loc, id, 0); - break; - - case DYNCAST_DSYMBOL: - { // It's a template instance - //printf("\ttemplate instance id\n"); - Dsymbol *st = (Dsymbol *)id; - TemplateInstance *ti = st->isTemplateInstance(); - id = ti->name; - sm = s->search(loc, id, 0); - if (!sm) - { error("template identifier %s is not a member of %s %s", - id->toChars(), s->kind(), s->toChars()); - return NULL; - } - sm = sm->toAlias(); - TemplateDeclaration *td = sm->isTemplateDeclaration(); - if (!td) - { - error("%s is not a template, it is a %s", id->toChars(), sm->kind()); - return NULL; - } - ti->tempdecl = td; - if (!ti->semanticRun) - ti->semantic(sc); - sm = ti->toAlias(); - break; - } - - default: - assert(0); - } - return sm; -} - -int Dsymbol::overloadInsert(Dsymbol *s) -{ - //printf("Dsymbol::overloadInsert('%s')\n", s->toChars()); - return FALSE; -} - -void Dsymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(toChars()); -} - -unsigned Dsymbol::size(Loc loc) -{ - error("Dsymbol '%s' has no size\n", toChars()); - return 0; -} - -int Dsymbol::isforwardRef() -{ - return FALSE; -} - -AggregateDeclaration *Dsymbol::isThis() -{ - return NULL; -} - -AggregateDeclaration *Dsymbol::isAggregateMember() // are we a member of an aggregate? -{ - Dsymbol *parent = toParent(); - if (parent && parent->isAggregateDeclaration()) - return (AggregateDeclaration *)parent; - return NULL; -} - -ClassDeclaration *Dsymbol::isClassMember() // are we a member of a class? -{ - AggregateDeclaration *ad = isAggregateMember(); - return ad ? ad->isClassDeclaration() : NULL; -} - -void Dsymbol::defineRef(Dsymbol *s) -{ - assert(0); -} - -int Dsymbol::isExport() -{ - return FALSE; -} - -int Dsymbol::isImportedSymbol() -{ - return FALSE; -} - -int Dsymbol::isDeprecated() -{ - return FALSE; -} - -#if DMDV2 -int Dsymbol::isOverloadable() -{ - return 0; -} -#endif - -LabelDsymbol *Dsymbol::isLabel() // is this a LabelDsymbol()? -{ - return NULL; -} - -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; -} - -Type *Dsymbol::getType() -{ - return NULL; -} - -int Dsymbol::needThis() -{ - return FALSE; -} - -int Dsymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sd->toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sd = %p, sd->symtab = %p)\n", this, toChars(), sd, sd->symtab); - parent = sd; - if (!isAnonymous()) // no name, so can't add it to symbol table - { - if (!sd->symtabInsert(this)) // if name is already defined - { - Dsymbol *s2; - - s2 = sd->symtab->lookup(ident); - if (!s2->overloadInsert(this)) - { - sd->multiplyDefined(0, this, s2); - } - } - if (sd->isAggregateDeclaration() || sd->isEnumDeclaration()) - { - if (ident == Id::__sizeof || ident == Id::__xalignof || ident == Id::mangleof) - error(".%s property cannot be redefined", ident->toChars()); - } - return 1; - } - return 0; -} - -void Dsymbol::error(const char *format, ...) -{ - //printf("Dsymbol::error()\n"); - if (!loc.filename) // avoid bug 5861. - { - Module *m = getModule(); - - if (m && m->srcfile) - loc.filename = m->srcfile->toChars(); - } - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Dsymbol::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Dsymbol::verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - if (!*p) - p = locToChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - fprintf(stdmsg, "%s %s ", kind(), toPrettyChars()); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); -halt(); - } - else - { - global.gaggedErrors++; - } - - global.errors++; - - //fatal(); -} - -void Dsymbol::checkDeprecated(Loc loc, Scope *sc) -{ - if (!global.params.useDeprecated && isDeprecated()) - { - // Don't complain if we're inside a deprecated symbol's scope - for (Dsymbol *sp = sc->parent; sp; sp = sp->parent) - { if (sp->isDeprecated()) - goto L1; - } - - for (Scope *sc2 = sc; sc2; sc2 = sc2->enclosing) - { - if (sc2->scopesym && sc2->scopesym->isDeprecated()) - goto L1; - - // If inside a StorageClassDeclaration that is deprecated - if (sc2->stc & STCdeprecated) - goto L1; - } - - error(loc, "is deprecated"); - } - - L1: - Declaration *d = isDeclaration(); - if (d && d->storage_class & STCdisable) - { - if (!(sc->func && sc->func->storage_class & STCdisable)) - { - if (d->ident == Id::cpctor && d->toParent()) - d->toParent()->error(loc, "is not copyable because it is annotated with @disable"); - else - error(loc, "is not callable because it is annotated with @disable"); - } - } -} - -/********************************** - * Determine which Module a Dsymbol is in. - */ - -Module *Dsymbol::getModule() -{ - //printf("Dsymbol::getModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - s = s->parent; - } - return NULL; -} - -/********************************** - * Determine which Module a Dsymbol is in, as far as access rights go. - */ - -Module *Dsymbol::getAccessModule() -{ - //printf("Dsymbol::getAccessModule()\n"); - TemplateDeclaration *td = getFuncTemplateDecl(this); - if (td) - return td->getAccessModule(); - - Dsymbol *s = this; - while (s) - { - //printf("\ts = %s '%s'\n", s->kind(), s->toPrettyChars()); - Module *m = s->isModule(); - if (m) - return m; - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && ti->isnested) - /* Because of local template instantiation, the parent isn't where the access - * rights come from - it's the template declaration - */ - s = ti->tempdecl; - else - s = s->parent; - } - return NULL; -} - -/************************************* - */ - -enum PROT Dsymbol::prot() -{ - return PROTpublic; -} - -/************************************* - * Do syntax copy of an array of Dsymbol's. - */ - - -Dsymbols *Dsymbol::arraySyntaxCopy(Dsymbols *a) -{ - - Dsymbols *b = NULL; - if (a) - { - b = a->copy(); - for (size_t i = 0; i < b->dim; i++) - { - Dsymbol *s = (*b)[i]; - - s = s->syntaxCopy(NULL); - (*b)[i] = s; - } - } - return b; -} - - -/**************************************** - * Add documentation comment to Dsymbol. - * Ignore NULL comments. - */ - -void Dsymbol::addComment(unsigned char *comment) -{ - //if (comment) - //printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - - if (!this->comment) - this->comment = comment; -#if 1 - else if (comment && strcmp((char *)comment, (char *)this->comment)) - { // Concatenate the two - this->comment = Lexer::combineComments(this->comment, comment); - } -#endif -} - -/********************************* OverloadSet ****************************/ - -#if DMDV2 -OverloadSet::OverloadSet() - : Dsymbol() -{ -} - -void OverloadSet::push(Dsymbol *s) -{ - a.push(s); -} - -const char *OverloadSet::kind() -{ - return "overloadset"; -} -#endif - - -/********************************* ScopeDsymbol ****************************/ - -ScopeDsymbol::ScopeDsymbol() - : Dsymbol() -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -ScopeDsymbol::ScopeDsymbol(Identifier *id) - : Dsymbol(id) -{ - members = NULL; - symtab = NULL; - imports = NULL; - prots = NULL; -} - -Dsymbol *ScopeDsymbol::syntaxCopy(Dsymbol *s) -{ - //printf("ScopeDsymbol::syntaxCopy('%s')\n", toChars()); - - ScopeDsymbol *sd; - if (s) - sd = (ScopeDsymbol *)s; - else - sd = new ScopeDsymbol(ident); - sd->members = arraySyntaxCopy(members); - return sd; -} - -Dsymbol *ScopeDsymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s->ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident->toChars(), flags); - //if (strcmp(ident->toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - Dsymbol *s = symtab ? symtab->lookup(ident) : NULL; - //printf("\ts = %p, imports = %p, %d\n", s, imports, imports ? imports->dim : 0); - // hide the aliases generated by selective or renamed private imports - if (s && flags & 1) - if (AliasDeclaration* ad = s->isAliasDeclaration()) - // may be a private alias to a function that is overloaded. these - // are sorted out during overload resolution, accept them here - if (ad->importprot == PROTprivate && !ad->aliassym->isFuncAliasDeclaration()) - s = NULL; - - if (s) - { - //printf("\ts = '%s.%s'\n",toChars(),s->toChars()); - } - else if (imports) - { - OverloadSet *a = NULL; - - // Look in imported modules - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - Dsymbol *s2; - - // If private import, don't search it - if (flags & 1 && prots[i] == PROTprivate) - continue; - - //printf("\tscanning import '%s', prots = %d, isModule = %p, isImport = %p\n", ss->toChars(), prots[i], ss->isModule(), ss->isImport()); - /* Don't find private members if ss is a module - */ - s2 = ss->search(loc, ident, ss->isModule() ? 1 : 0); - if (!s) - s = s2; - else if (s2 && s != s2) - { - if (s->toAlias() == s2->toAlias()) - { - /* After following aliases, we found the same - * symbol, so it's not an ambiguity. But if one - * alias is deprecated or less accessible, prefer - * the other. - */ - if (s->isDeprecated() || - s2->prot() > s->prot() && s2->prot() != PROTnone) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import *i1 = s->isImport(); - Import *i2 = s2->isImport(); - if (!(i1 && i2 && - (i1->mod == i2->mod || - (!i1->parent->isImport() && !i2->parent->isImport() && - i1->ident->equals(i2->ident)) - ) - ) - ) - { - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - if (s2->isOverloadable() && (a || s->isOverloadable())) - { if (!a) - a = new OverloadSet(); - /* Don't add to a[] if s2 is alias of previous sym - */ - for (size_t j = 0; j < a->a.dim; j++) - { Dsymbol *s3 = a->a[j]; - if (s2->toAlias() == s3->toAlias()) - { - if (s3->isDeprecated() || - s2->prot() > s3->prot() && s2->prot() != PROTnone) - a->a[j] = s2; - goto Lcontinue; - } - } - a->push(s2); - Lcontinue: - continue; - } - if (flags & 4) // if return NULL on ambiguity - return NULL; - if (!(flags & 2)) - ScopeDsymbol::multiplyDefined(loc, s, s2); - break; - } - } - } - } - - /* Build special symbol if we had multiple finds - */ - if (a) - { assert(s); - a->push(s); - s = a; - } - - if (s) - { - Declaration *d = s->isDeclaration(); - if (d && d->protection == PROTprivate && - !d->parent->isTemplateMixin() && - !(flags & 2)) - error(loc, "%s is private", d->toPrettyChars()); - } - } - return s; -} - -void ScopeDsymbol::importScope(Dsymbol *s, enum PROT protection) -{ - //printf("%s->ScopeDsymbol::importScope(%s, %d)\n", toChars(), s->toChars(), protection); - - // No circular or redundant import's - if (s != this) - { - if (!imports) - imports = new Dsymbols(); - else - { - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *ss = (*imports)[i]; - if (ss == s) // if already imported - { - if (protection > prots[i]) - prots[i] = protection; // upgrade access - return; - } - } - } - imports->push(s); - prots = (unsigned char *)mem.realloc(prots, imports->dim * sizeof(prots[0])); - prots[imports->dim - 1] = protection; - } -} - -int ScopeDsymbol::isforwardRef() -{ - return (members == NULL); -} - -void ScopeDsymbol::defineRef(Dsymbol *s) -{ - ScopeDsymbol *ss; - - ss = s->isScopeDsymbol(); - members = ss->members; - ss->members = NULL; -} - -void ScopeDsymbol::multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2) -{ -#if 0 - printf("ScopeDsymbol::multiplyDefined()\n"); - printf("s1 = %p, '%s' kind = '%s', parent = %s\n", s1, s1->toChars(), s1->kind(), s1->parent ? s1->parent->toChars() : ""); - printf("s2 = %p, '%s' kind = '%s', parent = %s\n", s2, s2->toChars(), s2->kind(), s2->parent ? s2->parent->toChars() : ""); -#endif - if (loc.filename) - { ::error(loc, "%s at %s conflicts with %s at %s", - s1->toPrettyChars(), - s1->locToChars(), - s2->toPrettyChars(), - s2->locToChars()); - } - else - { - s1->error(loc, "conflicts with %s %s at %s", - s2->kind(), - s2->toPrettyChars(), - s2->locToChars()); - } -} - -Dsymbol *ScopeDsymbol::nameCollision(Dsymbol *s) -{ - Dsymbol *sprev; - - // Look to see if we are defining a forward referenced symbol - - sprev = symtab->lookup(s->ident); - assert(sprev); - if (s->equals(sprev)) // if the same symbol - { - if (s->isforwardRef()) // if second declaration is a forward reference - return sprev; - if (sprev->isforwardRef()) - { - sprev->defineRef(s); // copy data from s into sprev - return sprev; - } - } - multiplyDefined(0, s, sprev); - return sprev; -} - -const char *ScopeDsymbol::kind() -{ - return "ScopeDsymbol"; -} - -Dsymbol *ScopeDsymbol::symtabInsert(Dsymbol *s) -{ - return symtab->insert(s); -} - -/**************************************** - * Return true if any of the members are static ctors or static dtors, or if - * any members have members that are. - */ - -bool ScopeDsymbol::hasStaticCtorOrDtor() -{ - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *member = (*members)[i]; - - if (member->hasStaticCtorOrDtor()) - return TRUE; - } - } - return FALSE; -} - -/*************************************** - * Determine number of Dsymbols, folding in AttribDeclaration members. - */ - -#if DMDV2 -static int dimDg(void *ctx, size_t n, Dsymbol *) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t ScopeDsymbol::dim(Dsymbols *members) -{ - size_t n = 0; - foreach(members, &dimDg, &n); - return n; -} -#endif - -/*************************************** - * Get nth Dsymbol, folding in AttribDeclaration members. - * Returns: - * Dsymbol* nth Dsymbol - * NULL not found, *pn gets incremented by the number - * of Dsymbols - */ - -#if DMDV2 -struct GetNthSymbolCtx -{ - size_t nth; - Dsymbol *sym; -}; - -static int getNthSymbolDg(void *ctx, size_t n, Dsymbol *sym) -{ - GetNthSymbolCtx *p = (GetNthSymbolCtx *)ctx; - if (n == p->nth) - { p->sym = sym; - return 1; - } - return 0; -} - -Dsymbol *ScopeDsymbol::getNth(Dsymbols *members, size_t nth, size_t *pn) -{ - GetNthSymbolCtx ctx = { nth, NULL }; - int res = foreach(members, &getNthSymbolDg, &ctx); - return res ? ctx.sym : NULL; -} -#endif - -/*************************************** - * Expands attribute declarations in members in depth first - * order. Calls dg(void *ctx, size_t symidx, Dsymbol *sym) for each - * member. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -#if DMDV2 -int ScopeDsymbol::foreach(Dsymbols *members, ScopeDsymbol::ForeachDg dg, void *ctx, size_t *pn) -{ - assert(dg); - if (!members) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - - if (AttribDeclaration *a = s->isAttribDeclaration()) - result = foreach(a->decl, dg, ctx, &n); - else if (TemplateMixin *tm = s->isTemplateMixin()) - result = foreach(tm->members, dg, ctx, &n); - else if (s->isTemplateInstance()) - ; - else - result = dg(ctx, n++, s); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} -#endif - -/******************************************* - * Look for member of the form: - * const(MemberInfo)[] getMembers(string); - * Returns NULL if not found - */ - -#if DMDV2 -FuncDeclaration *ScopeDsymbol::findGetMembers() -{ - Dsymbol *s = search_function(this, Id::getmembers); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - -#if 0 // Finish - static TypeFunction *tfgetmembers; - - if (!tfgetmembers) - { - Scope sc; - Parameters *arguments = new Parameters; - Parameters *arg = new Parameter(STCin, Type::tchar->constOf()->arrayOf(), NULL, NULL); - arguments->push(arg); - - Type *tret = NULL; - tfgetmembers = new TypeFunction(arguments, tret, 0, LINKd); - tfgetmembers = (TypeFunction *)tfgetmembers->semantic(0, &sc); - } - if (fdx) - fdx = fdx->overloadExactMatch(tfgetmembers); -#endif - if (fdx && fdx->isVirtual()) - fdx = NULL; - - return fdx; -} -#endif - - -/****************************** WithScopeSymbol ******************************/ - -WithScopeSymbol::WithScopeSymbol(WithStatement *withstate) - : ScopeDsymbol() -{ - this->withstate = withstate; -} - -Dsymbol *WithScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - // Acts as proxy to the with class declaration - return withstate->exp->type->toDsymbol(NULL)->search(loc, ident, 0); -} - -/****************************** ArrayScopeSymbol ******************************/ - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, Expression *e) - : ScopeDsymbol() -{ - assert(e->op == TOKindex || e->op == TOKslice || e->op == TOKarray); - exp = e; - type = NULL; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TypeTuple *t) - : ScopeDsymbol() -{ - exp = NULL; - type = t; - td = NULL; - this->sc = sc; -} - -ArrayScopeSymbol::ArrayScopeSymbol(Scope *sc, TupleDeclaration *s) - : ScopeDsymbol() -{ - exp = NULL; - type = NULL; - td = s; - this->sc = sc; -} - -Dsymbol *ArrayScopeSymbol::search(Loc loc, Identifier *ident, int flags) -{ - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident->toChars(), flags); - if (ident == Id::length || ident == Id::dollar) - { VarDeclaration **pvar; - Expression *ce; - - if (ident == Id::length && !global.params.useDeprecated) - error("using 'length' inside [ ] is deprecated, use '$' instead"); - - L1: - - if (td) - { /* $ gives the number of elements in the tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, td->objects->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (type) - { /* $ gives the number of type entries in the type tuple - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - Expression *e = new IntegerExp(0, type->arguments->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - v->semantic(sc); - return v; - } - - if (exp->op == TOKindex) - { /* array[index] where index is some function of $ - */ - IndexExp *ie = (IndexExp *)exp; - - pvar = &ie->lengthVar; - ce = ie->e1; - } - else if (exp->op == TOKslice) - { /* array[lwr .. upr] where lwr or upr is some function of $ - */ - SliceExp *se = (SliceExp *)exp; - - pvar = &se->lengthVar; - ce = se->e1; - } - else if (exp->op == TOKarray) - { /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ - * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) - */ - ArrayExp *ae = (ArrayExp *)exp; - AggregateDeclaration *ad = NULL; - - Type *t = ae->e1->type->toBasetype(); - if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - } - assert(ad); - - Dsymbol *dsym = search_function(ad, Id::opDollar); - if (!dsym) // no dollar exists -- search in higher scope - return NULL; - VarDeclaration *v = ae->lengthVar; - if (!v) - { // $ is lazily initialized. Create it now. - TemplateDeclaration *td = dsym->isTemplateDeclaration(); - if (td) - { // Instantiate opDollar!(dim) with the index as a template argument - Objects *tdargs = new Objects(); - tdargs->setDim(1); - - Expression *x = new IntegerExp(0, ae->currentDimension, Type::tsize_t); - x = x->semantic(sc); - tdargs->data[0] = x; - - //TemplateInstance *ti = new TemplateInstance(loc, td, tdargs); - //ti->semantic(sc); - - DotTemplateInstanceExp *dte = new DotTemplateInstanceExp(loc, ae->e1, td->ident, tdargs); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, dte)); - } - else - { /* opDollar exists, but it's a function, not a template. - * This is acceptable ONLY for single-dimension indexing. - * Note that it's impossible to have both template & function opDollar, - * because both take no arguments. - */ - if (ae->arguments->dim != 1) { - ae->error("%s only defines opDollar for one dimension", ad->toChars()); - return NULL; - } - FuncDeclaration *fd = dsym->isFuncDeclaration(); - assert(fd); - Expression * x = new DotVarExp(loc, ae->e1, fd); - - v = new VarDeclaration(loc, NULL, Id::dollar, new ExpInitializer(0, x)); - } - v->semantic(sc); - ae->lengthVar = v; - } - return v; - } - else - /* Didn't find $, look in enclosing scope(s). - */ - return NULL; - - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (ce->op == TOKtype) - { - Type *t = ((TypeExp *)ce)->type; - if (t->ty == Ttuple) - { type = (TypeTuple *)t; - goto L1; - } - } - - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { /* Create variable v and set it to the value of $ - */ - VarDeclaration *v = new VarDeclaration(loc, Type::tsize_t, Id::dollar, NULL); - if (ce->op == TOKtuple) - { /* It is for an expression tuple, so the - * length will be a const. - */ - Expression *e = new IntegerExp(0, ((TupleExp *)ce)->exps->dim, Type::tsize_t); - v->init = new ExpInitializer(0, e); - v->storage_class |= STCstatic | STCconst; - } - else - { /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - VoidInitializer *e = new VoidInitializer(0); - e->type = Type::tsize_t; - v->init = e; - } - *pvar = v; - } - (*pvar)->semantic(sc); - return (*pvar); - } - return NULL; -} - - -/****************************** DsymbolTable ******************************/ - -DsymbolTable::DsymbolTable() -{ -#if STRINGTABLE - tab = new StringTable; - tab->init(); -#else - tab = NULL; -#endif -} - -DsymbolTable::~DsymbolTable() -{ -#if STRINGTABLE - delete tab; -#endif -} - -Dsymbol *DsymbolTable::lookup(Identifier *ident) -{ -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - StringValue *sv = tab->lookup((char*)ident->string, ident->len); - return (Dsymbol *)(sv ? sv->ptrvalue : NULL); -#else - //printf("DsymbolTable::lookup(%s)\n", (char*)ident->string); - return (Dsymbol *)_aaGetRvalue(tab, ident); -#endif -} - -Dsymbol *DsymbolTable::insert(Dsymbol *s) -{ - //printf("DsymbolTable::insert(this = %p, '%s')\n", this, s->ident->toChars()); - Identifier *ident = s->ident; -#if STRINGTABLE -#ifdef DEBUG - assert(ident); - assert(tab); -#endif - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::insert(Identifier *ident, Dsymbol *s) -{ - //printf("DsymbolTable::insert()\n"); -#if STRINGTABLE - StringValue *sv = tab->insert(ident->toChars(), ident->len); - if (!sv) - return NULL; // already in table - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - if (*ps) - return NULL; // already in table - *ps = s; - return s; -#endif -} - -Dsymbol *DsymbolTable::update(Dsymbol *s) -{ - Identifier *ident = s->ident; -#if STRINGTABLE - StringValue *sv = tab->update(ident->toChars(), ident->len); - sv->ptrvalue = s; - return s; -#else - Dsymbol **ps = (Dsymbol **)_aaGet(&tab, ident); - *ps = s; - return s; -#endif -} - - - - diff --git a/dmd2/dsymbol.h b/dmd2/dsymbol.h deleted file mode 100644 index 2b16eecb..00000000 --- a/dmd2/dsymbol.h +++ /dev/null @@ -1,389 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 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_DSYMBOL_H -#define DMD_DSYMBOL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "mars.h" -#include "arraytypes.h" - -#if IN_LLVM -#if defined(_MSC_VER) -#undef min -#undef max -#endif -#include "../ir/irdsymbol.h" -#endif - -struct Identifier; -struct Scope; -struct DsymbolTable; -struct Declaration; -struct ThisDeclaration; -struct TupleDeclaration; -struct TypedefDeclaration; -struct AliasDeclaration; -struct AggregateDeclaration; -struct EnumDeclaration; -struct ClassDeclaration; -struct InterfaceDeclaration; -struct StructDeclaration; -struct UnionDeclaration; -struct FuncDeclaration; -struct FuncAliasDeclaration; -struct FuncLiteralDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct VarDeclaration; -struct AttribDeclaration; -#if IN_DMD -struct Symbol; -#endif -struct Package; -struct Module; -struct Import; -struct Type; -struct TypeTuple; -struct WithStatement; -struct LabelDsymbol; -struct ScopeDsymbol; -struct TemplateDeclaration; -struct TemplateInstance; -struct TemplateMixin; -struct EnumMember; -struct ScopeDsymbol; -struct WithScopeSymbol; -struct ArrayScopeSymbol; -struct StaticStructInitDeclaration; -struct Expression; -struct DeleteDeclaration; -struct HdrGenState; -struct OverloadSet; -struct AA; -#if TARGET_NET -struct PragmaScope; -#endif -#if IN_LLVM -struct TypeInfoDeclaration; -struct ClassInfoDeclaration; -#endif - -#if IN_GCC -union tree_node; -typedef union tree_node TYPE; -#else -struct TYPE; -#endif - -#if IN_LLVM -class Ir; -class IrSymbol; -namespace llvm -{ - class Value; -} -#endif -#if IN_DMD -// Back end -struct Classsym; -#endif - -enum PROT -{ - PROTundefined, - PROTnone, // no access - PROTprivate, - PROTpackage, - PROTprotected, - PROTpublic, - PROTexport, -}; - -/* State of symbol in winding its way through the passes of the compiler - */ -enum PASS -{ - PASSinit, // initial state - PASSsemantic, // semantic() started - PASSsemanticdone, // semantic() done - PASSsemantic2, // semantic2() run - PASSsemantic3, // semantic3() started - PASSsemantic3done, // semantic3() done - PASSobj, // toObjFile() run -}; - -struct Dsymbol : Object -{ - Identifier *ident; - Identifier *c_ident; - Dsymbol *parent; -#if IN_DMD - Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym -#endif - unsigned char *comment; // documentation comment for this Dsymbol - Loc loc; // where defined - Scope *scope; // !=NULL means context to use for semantic() - - Dsymbol(); - Dsymbol(Identifier *); - char *toChars(); - char *locToChars(); - int equals(Object *o); - int isAnonymous(); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void error(const char *format, ...) IS_PRINTF(2); - void verror(Loc loc, const char *format, va_list ap); - void checkDeprecated(Loc loc, Scope *sc); - Module *getModule(); // module where declared - Module *getAccessModule(); - Dsymbol *pastMixin(); - Dsymbol *toParent(); - Dsymbol *toParent2(); - TemplateInstance *inTemplateInstance(); - - int dyncast() { return DYNCAST_DSYMBOL; } // kludge for template.isSymbol() - - static Dsymbols *arraySyntaxCopy(Dsymbols *a); - - virtual const char *toPrettyChars(); - virtual const char *kind(); - virtual Dsymbol *toAlias(); // resolve real symbol - virtual int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - virtual void setScope(Scope *sc); - virtual void importAll(Scope *sc); - virtual void semantic0(Scope *sc); - virtual void semantic(Scope *sc); - virtual void semantic2(Scope *sc); - virtual void semantic3(Scope *sc); - virtual void inlineScan(); - virtual Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *search_correct(Identifier *id); - Dsymbol *searchX(Loc loc, Scope *sc, Identifier *id); - virtual int overloadInsert(Dsymbol *s); - char *toHChars(); - virtual void toHBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toDocBuffer(OutBuffer *buf); - virtual void toJsonBuffer(OutBuffer *buf); - virtual unsigned size(Loc loc); - virtual int isforwardRef(); - virtual void defineRef(Dsymbol *s); - virtual AggregateDeclaration *isThis(); // is a 'this' required to access the member - AggregateDeclaration *isAggregateMember(); // are we a member of an aggregate? - ClassDeclaration *isClassMember(); // are we a member of a class? - virtual int isExport(); // is Dsymbol exported? - virtual int isImportedSymbol(); // is Dsymbol imported? - virtual int isDeprecated(); // is Dsymbol deprecated? -#if DMDV2 - virtual int isOverloadable(); -#endif - virtual LabelDsymbol *isLabel(); // is this a LabelDsymbol? - virtual AggregateDeclaration *isMember(); // is this symbol a member of an AggregateDeclaration? - virtual Type *getType(); // is this a type? - virtual char *mangle(); - virtual int needThis(); // need a 'this' pointer? - virtual enum PROT prot(); - virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - virtual int oneMember(Dsymbol **ps, Identifier *ident); - static int oneMembers(Dsymbols *members, Dsymbol **ps, Identifier *ident = NULL); - virtual int hasPointers(); - virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(ClassDeclarations *) { } - virtual void checkCtorConstInit() { } - - virtual void addComment(unsigned char *comment); - virtual void emitComment(Scope *sc); - void emitDitto(Scope *sc); - -#if IN_DMD - // Backend - - virtual Symbol *toSymbol(); // to backend symbol - virtual void toObjFile(int multiobj); // compile to .obj file - virtual int cvMember(unsigned char *p); // emit cv debug info for member - - Symbol *toImport(); // to backend import symbol - static Symbol *toImport(Symbol *s); // to backend import symbol - - Symbol *toSymbolX(const char *prefix, int sclass, TYPE *t, const char *suffix); // helper -#endif - - // Eliminate need for dynamic_cast - virtual Package *isPackage() { return NULL; } - virtual Module *isModule() { return NULL; } - virtual EnumMember *isEnumMember() { return NULL; } - virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; } - virtual TemplateInstance *isTemplateInstance() { return NULL; } - virtual TemplateMixin *isTemplateMixin() { return NULL; } - virtual Declaration *isDeclaration() { return NULL; } - virtual ThisDeclaration *isThisDeclaration() { return NULL; } - virtual TupleDeclaration *isTupleDeclaration() { return NULL; } - virtual TypedefDeclaration *isTypedefDeclaration() { return NULL; } - virtual AliasDeclaration *isAliasDeclaration() { return NULL; } - virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; } - virtual FuncDeclaration *isFuncDeclaration() { return NULL; } - virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; } - virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; } - virtual CtorDeclaration *isCtorDeclaration() { return NULL; } - virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; } - virtual DtorDeclaration *isDtorDeclaration() { return NULL; } - virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; } - virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; } - virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; } - virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; } - virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; } - virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; } - virtual NewDeclaration *isNewDeclaration() { return NULL; } - virtual VarDeclaration *isVarDeclaration() { return NULL; } - virtual ClassDeclaration *isClassDeclaration() { return NULL; } - virtual StructDeclaration *isStructDeclaration() { return NULL; } - virtual UnionDeclaration *isUnionDeclaration() { return NULL; } - virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; } - virtual ScopeDsymbol *isScopeDsymbol() { return NULL; } - virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; } - virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; } - virtual Import *isImport() { return NULL; } - virtual EnumDeclaration *isEnumDeclaration() { return NULL; } - virtual DeleteDeclaration *isDeleteDeclaration() { return NULL; } - virtual StaticStructInitDeclaration *isStaticStructInitDeclaration() { return NULL; } - virtual AttribDeclaration *isAttribDeclaration() { return NULL; } - virtual OverloadSet *isOverloadSet() { return NULL; } - virtual TypeInfoDeclaration* isTypeInfoDeclaration() { return NULL; } - virtual ClassInfoDeclaration* isClassInfoDeclaration() { return NULL; } -#if TARGET_NET - virtual PragmaScope* isPragmaScope() { return NULL; } -#endif -#if IN_LLVM - /// Codegen traversal - virtual void codegen(Ir* ir); - - // llvm stuff - int llvmInternal; - - IrDsymbol ir; - IrSymbol* irsym; -#endif -}; - -// Dsymbol that generates a scope - -struct ScopeDsymbol : Dsymbol -{ - Dsymbols *members; // all Dsymbol's in this scope - DsymbolTable *symtab; // members[] sorted into table - - Dsymbols *imports; // imported Dsymbol's - unsigned char *prots; // array of PROT, one for each import - - ScopeDsymbol(); - ScopeDsymbol(Identifier *id); - Dsymbol *syntaxCopy(Dsymbol *s); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - void importScope(Dsymbol *s, enum PROT protection); - int isforwardRef(); - void defineRef(Dsymbol *s); - static void multiplyDefined(Loc loc, Dsymbol *s1, Dsymbol *s2); - Dsymbol *nameCollision(Dsymbol *s); - const char *kind(); - FuncDeclaration *findGetMembers(); - virtual Dsymbol *symtabInsert(Dsymbol *s); - bool hasStaticCtorOrDtor(); - - void emitMemberComments(Scope *sc); - - static size_t dim(Dsymbols *members); - static Dsymbol *getNth(Dsymbols *members, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t idx, Dsymbol *s); - static int foreach(Dsymbols *members, ForeachDg dg, void *ctx, size_t *pn=NULL); - - ScopeDsymbol *isScopeDsymbol() { return this; } -}; - -// With statement scope - -struct WithScopeSymbol : ScopeDsymbol -{ - WithStatement *withstate; - - WithScopeSymbol(WithStatement *withstate); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - WithScopeSymbol *isWithScopeSymbol() { return this; } -}; - -// Array Index/Slice scope - -struct ArrayScopeSymbol : ScopeDsymbol -{ - Expression *exp; // IndexExp or SliceExp - TypeTuple *type; // for tuple[length] - TupleDeclaration *td; // for tuples of objects - Scope *sc; - - ArrayScopeSymbol(Scope *sc, Expression *e); - ArrayScopeSymbol(Scope *sc, TypeTuple *t); - ArrayScopeSymbol(Scope *sc, TupleDeclaration *td); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - - ArrayScopeSymbol *isArrayScopeSymbol() { return this; } -}; - -// Overload Sets - -#if DMDV2 -struct OverloadSet : Dsymbol -{ - Dsymbols a; // array of Dsymbols - - OverloadSet(); - void push(Dsymbol *s); - OverloadSet *isOverloadSet() { return this; } - const char *kind(); -}; -#endif - -// Table of Dsymbol's - -struct DsymbolTable : Object -{ - AA *tab; - - DsymbolTable(); - ~DsymbolTable(); - - // Look up Identifier. Return Dsymbol if found, NULL if not. - Dsymbol *lookup(Identifier *ident); - - // Insert Dsymbol in table. Return NULL if already there. - Dsymbol *insert(Dsymbol *s); - - // Look for Dsymbol in table. If there, return it. If not, insert s and return that. - Dsymbol *update(Dsymbol *s); - Dsymbol *insert(Identifier *ident, Dsymbol *s); // when ident and s are not the same -}; - -#endif /* DMD_DSYMBOL_H */ diff --git a/dmd2/dump.c b/dmd2/dump.c deleted file mode 100644 index 4fd0d04e..00000000 --- a/dmd2/dump.c +++ /dev/null @@ -1,152 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "mars.h" -#include "mtype.h" -#include "declaration.h" -#include "expression.h" -#include "template.h" - -static void indent(int indent) -{ - int i; - - for (i = 0; i < indent; i++) - printf(" "); -} - -static char *type_print(Type *type) -{ - return type ? type->toChars() : (char *) "null"; -} - -void dumpExpressions(int i, Expressions *exps) -{ - if (exps) - { - for (size_t j = 0; j < exps->dim; j++) - { Expression *e = exps->tdata()[j]; - indent(i); - printf("(\n"); - e->dump(i + 2); - indent(i); - printf(")\n"); - } - } -} - -void Expression::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, Token::toChars(op), type_print(type)); -} - -void IntegerExp::dump(int i) -{ - indent(i); - printf("%p %jd type=%s\n", this, (intmax_t)value, type_print(type)); -} - -void IdentifierExp::dump(int i) -{ - indent(i); - printf("%p ident '%s' type=%s\n", this, ident->toChars(), type_print(type)); -} - -void DsymbolExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s\n", this, s->toChars(), type_print(type)); -} - -void VarExp::dump(int i) -{ - indent(i); - printf("%p %s var=%s type=%s\n", this, Token::toChars(op), var->toChars(), type_print(type)); -} - -void UnaExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void CallExp::dump(int i) -{ - UnaExp::dump(i); - dumpExpressions(i, arguments); -} - -void SliceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s e1=%p\n", this, Token::toChars(op), type_print(type), e1); - if (e1) - e1->dump(i + 2); - if (lwr) - lwr->dump(i + 2); - if (upr) - upr->dump(i + 2); -} - -void DotIdExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ident=%s e1=%p\n", this, Token::toChars(op), type_print(type), ident->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotVarExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s var='%s' e1=%p\n", this, Token::toChars(op), type_print(type), var->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DotTemplateInstanceExp::dump(int i) -{ - indent(i); - printf("%p %s type=%s ti='%s' e1=%p\n", this, Token::toChars(op), type_print(type), ti->toChars(), e1); - if (e1) - e1->dump(i + 2); -} - -void DelegateExp::dump(int i) -{ - indent(i); - printf("%p %s func=%s type=%s e1=%p\n", this, Token::toChars(op), func->toChars(), type_print(type), e1); - if (e1) - e1->dump(i + 2); -} - -void BinExp::dump(int i) -{ - indent(i); - const char *sop = Token::toChars(op); - if (op == TOKblit) - sop = "blit"; - else if (op == TOKconstruct) - sop = "construct"; - printf("%p %s type=%s e1=%p e2=%p\n", this, sop, type_print(type), e1, e2); - if (e1) - e1->dump(i + 2); - if (e2) - e2->dump(i + 2); -} - - diff --git a/dmd2/entity.c b/dmd2/entity.c deleted file mode 100644 index 98b81141..00000000 --- a/dmd2/entity.c +++ /dev/null @@ -1,2391 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include - -/********************************************* - * Convert from named entity to its encoding. - * For reference: - * http://www.htmlhelp.com/reference/html40/entities/ - * http://www.w3.org/2003/entities/2007/w3centities-f.ent - */ - -struct NameId -{ - const char *name; - unsigned value; -}; - -static NameId namesA[]={ - "Aacgr", 0x00386, // GREEK CAPITAL LETTER ALPHA WITH TONOS - "aacgr", 0x003AC, // GREEK SMALL LETTER ALPHA WITH TONOS - "Aacute", 0x000C1, // LATIN CAPITAL LETTER A WITH ACUTE - "aacute", 0x000E1, // LATIN SMALL LETTER A WITH ACUTE - "Abreve", 0x00102, // LATIN CAPITAL LETTER A WITH BREVE - "abreve", 0x00103, // LATIN SMALL LETTER A WITH BREVE - "ac", 0x0223E, // INVERTED LAZY S - "acd", 0x0223F, // SINE WAVE -// "acE", 0x0223E;0x00333, // INVERTED LAZY S with double underline - "Acirc", 0x000C2, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX - "acirc", 0x000E2, // LATIN SMALL LETTER A WITH CIRCUMFLEX - "acute", 0x000B4, // ACUTE ACCENT - "Acy", 0x00410, // CYRILLIC CAPITAL LETTER A - "acy", 0x00430, // CYRILLIC SMALL LETTER A - "AElig", 0x000C6, // LATIN CAPITAL LETTER AE - "aelig", 0x000E6, // LATIN SMALL LETTER AE - "af", 0x02061, // FUNCTION APPLICATION - "Afr", 0x1D504, // MATHEMATICAL FRAKTUR CAPITAL A - "afr", 0x1D51E, // MATHEMATICAL FRAKTUR SMALL A - "Agr", 0x00391, // GREEK CAPITAL LETTER ALPHA - "agr", 0x003B1, // GREEK SMALL LETTER ALPHA - "Agrave", 0x000C0, // LATIN CAPITAL LETTER A WITH GRAVE - "agrave", 0x000E0, // LATIN SMALL LETTER A WITH GRAVE - "alefsym", 0x02135, // ALEF SYMBOL - "aleph", 0x02135, // ALEF SYMBOL - "Alpha", 0x00391, // GREEK CAPITAL LETTER ALPHA - "alpha", 0x003B1, // GREEK SMALL LETTER ALPHA - "Amacr", 0x00100, // LATIN CAPITAL LETTER A WITH MACRON - "amacr", 0x00101, // LATIN SMALL LETTER A WITH MACRON - "amalg", 0x02A3F, // AMALGAMATION OR COPRODUCT - "amp", 0x00026, // AMPERSAND - "AMP", 0x00026, // AMPERSAND - "and", 0x02227, // LOGICAL AND - "And", 0x02A53, // DOUBLE LOGICAL AND - "andand", 0x02A55, // TWO INTERSECTING LOGICAL AND - "andd", 0x02A5C, // LOGICAL AND WITH HORIZONTAL DASH - "andslope", 0x02A58, // SLOPING LARGE AND - "andv", 0x02A5A, // LOGICAL AND WITH MIDDLE STEM - "ang", 0x02220, // ANGLE - "ange", 0x029A4, // ANGLE WITH UNDERBAR - "angle", 0x02220, // ANGLE - "angmsd", 0x02221, // MEASURED ANGLE - "angmsdaa", 0x029A8, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND RIGHT - "angmsdab", 0x029A9, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING UP AND LEFT - "angmsdac", 0x029AA, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND RIGHT - "angmsdad", 0x029AB, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING DOWN AND LEFT - "angmsdae", 0x029AC, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND UP - "angmsdaf", 0x029AD, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND UP - "angmsdag", 0x029AE, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING RIGHT AND DOWN - "angmsdah", 0x029AF, // MEASURED ANGLE WITH OPEN ARM ENDING IN ARROW POINTING LEFT AND DOWN - "angrt", 0x0221F, // RIGHT ANGLE - "angrtvb", 0x022BE, // RIGHT ANGLE WITH ARC - "angrtvbd", 0x0299D, // MEASURED RIGHT ANGLE WITH DOT - "angsph", 0x02222, // SPHERICAL ANGLE - "angst", 0x000C5, // LATIN CAPITAL LETTER A WITH RING ABOVE - "angzarr", 0x0237C, // RIGHT ANGLE WITH DOWNWARDS ZIGZAG ARROW - "Aogon", 0x00104, // LATIN CAPITAL LETTER A WITH OGONEK - "aogon", 0x00105, // LATIN SMALL LETTER A WITH OGONEK - "Aopf", 0x1D538, // MATHEMATICAL DOUBLE-STRUCK CAPITAL A - "aopf", 0x1D552, // MATHEMATICAL DOUBLE-STRUCK SMALL A - "ap", 0x02248, // ALMOST EQUAL TO - "apacir", 0x02A6F, // ALMOST EQUAL TO WITH CIRCUMFLEX ACCENT - "ape", 0x0224A, // ALMOST EQUAL OR EQUAL TO - "apE", 0x02A70, // APPROXIMATELY EQUAL OR EQUAL TO - "apid", 0x0224B, // TRIPLE TILDE - "apos", 0x00027, // APOSTROPHE - "ApplyFunction", 0x02061, // FUNCTION APPLICATION - "approx", 0x02248, // ALMOST EQUAL TO - "approxeq", 0x0224A, // ALMOST EQUAL OR EQUAL TO - "Aring", 0x000C5, // LATIN CAPITAL LETTER A WITH RING ABOVE - "aring", 0x000E5, // LATIN SMALL LETTER A WITH RING ABOVE - "Ascr", 0x1D49C, // MATHEMATICAL SCRIPT CAPITAL A - "ascr", 0x1D4B6, // MATHEMATICAL SCRIPT SMALL A - "Assign", 0x02254, // COLON EQUALS - "ast", 0x0002A, // ASTERISK - "asymp", 0x02248, // ALMOST EQUAL TO - "asympeq", 0x0224D, // EQUIVALENT TO - "Atilde", 0x000C3, // LATIN CAPITAL LETTER A WITH TILDE - "atilde", 0x000E3, // LATIN SMALL LETTER A WITH TILDE - "Auml", 0x000C4, // LATIN CAPITAL LETTER A WITH DIAERESIS - "auml", 0x000E4, // LATIN SMALL LETTER A WITH DIAERESIS - "awconint", 0x02233, // ANTICLOCKWISE CONTOUR INTEGRAL - "awint", 0x02A11, // ANTICLOCKWISE INTEGRATION - NULL, 0 -}; - -static NameId namesB[]={ - "backcong", 0x0224C, // ALL EQUAL TO - "backepsilon", 0x003F6, // GREEK REVERSED LUNATE EPSILON SYMBOL - "backprime", 0x02035, // REVERSED PRIME - "backsim", 0x0223D, // REVERSED TILDE - "backsimeq", 0x022CD, // REVERSED TILDE EQUALS - "Backslash", 0x02216, // SET MINUS -// "b.alpha", 0x1D6C2, // MATHEMATICAL BOLD SMALL ALPHA - "Barv", 0x02AE7, // SHORT DOWN TACK WITH OVERBAR - "barvee", 0x022BD, // NOR - "barwed", 0x02305, // PROJECTIVE - "Barwed", 0x02306, // PERSPECTIVE - "barwedge", 0x02305, // PROJECTIVE -// "b.beta", 0x1D6C3, // MATHEMATICAL BOLD SMALL BETA - "bbrk", 0x023B5, // BOTTOM SQUARE BRACKET - "bbrktbrk", 0x023B6, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET -// "b.chi", 0x1D6D8, // MATHEMATICAL BOLD SMALL CHI - "bcong", 0x0224C, // ALL EQUAL TO - "Bcy", 0x00411, // CYRILLIC CAPITAL LETTER BE - "bcy", 0x00431, // CYRILLIC SMALL LETTER BE -// "b.Delta", 0x1D6AB, // MATHEMATICAL BOLD CAPITAL DELTA -// "b.delta", 0x1D6C5, // MATHEMATICAL BOLD SMALL DELTA - "bdquo", 0x0201E, // DOUBLE LOW-9 QUOTATION MARK - "becaus", 0x02235, // BECAUSE - "because", 0x02235, // BECAUSE - "Because", 0x02235, // BECAUSE - "bemptyv", 0x029B0, // REVERSED EMPTY SET - "bepsi", 0x003F6, // GREEK REVERSED LUNATE EPSILON SYMBOL -// "b.epsi", 0x1D6C6, // MATHEMATICAL BOLD SMALL EPSILON -// "b.epsiv", 0x1D6DC, // MATHEMATICAL BOLD EPSILON SYMBOL - "bernou", 0x0212C, // SCRIPT CAPITAL B - "Bernoullis", 0x0212C, // SCRIPT CAPITAL B - "Beta", 0x00392, // GREEK CAPITAL LETTER BETA - "beta", 0x003B2, // GREEK SMALL LETTER BETA -// "b.eta", 0x1D6C8, // MATHEMATICAL BOLD SMALL ETA - "beth", 0x02136, // BET SYMBOL - "between", 0x0226C, // BETWEEN - "Bfr", 0x1D505, // MATHEMATICAL FRAKTUR CAPITAL B - "bfr", 0x1D51F, // MATHEMATICAL FRAKTUR SMALL B -// "b.Gamma", 0x1D6AA, // MATHEMATICAL BOLD CAPITAL GAMMA -// "b.gamma", 0x1D6C4, // MATHEMATICAL BOLD SMALL GAMMA -// "b.Gammad", 0x1D7CA, // MATHEMATICAL BOLD CAPITAL DIGAMMA -// "b.gammad", 0x1D7CB, // MATHEMATICAL BOLD SMALL DIGAMMA - "Bgr", 0x00392, // GREEK CAPITAL LETTER BETA - "bgr", 0x003B2, // GREEK SMALL LETTER BETA - "bigcap", 0x022C2, // N-ARY INTERSECTION - "bigcirc", 0x025EF, // LARGE CIRCLE - "bigcup", 0x022C3, // N-ARY UNION - "bigodot", 0x02A00, // N-ARY CIRCLED DOT OPERATOR - "bigoplus", 0x02A01, // N-ARY CIRCLED PLUS OPERATOR - "bigotimes", 0x02A02, // N-ARY CIRCLED TIMES OPERATOR - "bigsqcup", 0x02A06, // N-ARY SQUARE UNION OPERATOR - "bigstar", 0x02605, // BLACK STAR - "bigtriangledown", 0x025BD, // WHITE DOWN-POINTING TRIANGLE - "bigtriangleup", 0x025B3, // WHITE UP-POINTING TRIANGLE - "biguplus", 0x02A04, // N-ARY UNION OPERATOR WITH PLUS - "bigvee", 0x022C1, // N-ARY LOGICAL OR - "bigwedge", 0x022C0, // N-ARY LOGICAL AND -// "b.iota", 0x1D6CA, // MATHEMATICAL BOLD SMALL IOTA -// "b.kappa", 0x1D6CB, // MATHEMATICAL BOLD SMALL KAPPA -// "b.kappav", 0x1D6DE, // MATHEMATICAL BOLD KAPPA SYMBOL - "bkarow", 0x0290D, // RIGHTWARDS DOUBLE DASH ARROW - "blacklozenge", 0x029EB, // BLACK LOZENGE - "blacksquare", 0x025AA, // BLACK SMALL SQUARE - "blacktriangle", 0x025B4, // BLACK UP-POINTING SMALL TRIANGLE - "blacktriangledown", 0x025BE, // BLACK DOWN-POINTING SMALL TRIANGLE - "blacktriangleleft", 0x025C2, // BLACK LEFT-POINTING SMALL TRIANGLE - "blacktriangleright", 0x025B8, // BLACK RIGHT-POINTING SMALL TRIANGLE -// "b.Lambda", 0x1D6B2, // MATHEMATICAL BOLD CAPITAL LAMDA -// "b.lambda", 0x1D6CC, // MATHEMATICAL BOLD SMALL LAMDA - "blank", 0x02423, // OPEN BOX - "blk12", 0x02592, // MEDIUM SHADE - "blk14", 0x02591, // LIGHT SHADE - "blk34", 0x02593, // DARK SHADE - "block", 0x02588, // FULL BLOCK -// "b.mu", 0x1D6CD, // MATHEMATICAL BOLD SMALL MU -// "bne", 0x0003D;0x020E5, // EQUALS SIGN with reverse slash -// "bnequiv", 0x02261;0x020E5, // IDENTICAL TO with reverse slash - "bnot", 0x02310, // REVERSED NOT SIGN - "bNot", 0x02AED, // REVERSED DOUBLE STROKE NOT SIGN -// "b.nu", 0x1D6CE, // MATHEMATICAL BOLD SMALL NU -// "b.Omega", 0x1D6C0, // MATHEMATICAL BOLD CAPITAL OMEGA -// "b.omega", 0x1D6DA, // MATHEMATICAL BOLD SMALL OMEGA - "Bopf", 0x1D539, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B - "bopf", 0x1D553, // MATHEMATICAL DOUBLE-STRUCK SMALL B - "bot", 0x022A5, // UP TACK - "bottom", 0x022A5, // UP TACK - "bowtie", 0x022C8, // BOWTIE - "boxbox", 0x029C9, // TWO JOINED SQUARES - "boxdl", 0x02510, // BOX DRAWINGS LIGHT DOWN AND LEFT - "boxdL", 0x02555, // BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE - "boxDl", 0x02556, // BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE - "boxDL", 0x02557, // BOX DRAWINGS DOUBLE DOWN AND LEFT - "boxdr", 0x0250C, // BOX DRAWINGS LIGHT DOWN AND RIGHT - "boxdR", 0x02552, // BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE - "boxDr", 0x02553, // BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE - "boxDR", 0x02554, // BOX DRAWINGS DOUBLE DOWN AND RIGHT - "boxh", 0x02500, // BOX DRAWINGS LIGHT HORIZONTAL - "boxH", 0x02550, // BOX DRAWINGS DOUBLE HORIZONTAL - "boxhd", 0x0252C, // BOX DRAWINGS LIGHT DOWN AND HORIZONTAL - "boxHd", 0x02564, // BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE - "boxhD", 0x02565, // BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE - "boxHD", 0x02566, // BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL - "boxhu", 0x02534, // BOX DRAWINGS LIGHT UP AND HORIZONTAL - "boxHu", 0x02567, // BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE - "boxhU", 0x02568, // BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE - "boxHU", 0x02569, // BOX DRAWINGS DOUBLE UP AND HORIZONTAL - "boxminus", 0x0229F, // SQUARED MINUS - "boxplus", 0x0229E, // SQUARED PLUS - "boxtimes", 0x022A0, // SQUARED TIMES - "boxul", 0x02518, // BOX DRAWINGS LIGHT UP AND LEFT - "boxuL", 0x0255B, // BOX DRAWINGS UP SINGLE AND LEFT DOUBLE - "boxUl", 0x0255C, // BOX DRAWINGS UP DOUBLE AND LEFT SINGLE - "boxUL", 0x0255D, // BOX DRAWINGS DOUBLE UP AND LEFT - "boxur", 0x02514, // BOX DRAWINGS LIGHT UP AND RIGHT - "boxuR", 0x02558, // BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE - "boxUr", 0x02559, // BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE - "boxUR", 0x0255A, // BOX DRAWINGS DOUBLE UP AND RIGHT - "boxv", 0x02502, // BOX DRAWINGS LIGHT VERTICAL - "boxV", 0x02551, // BOX DRAWINGS DOUBLE VERTICAL - "boxvh", 0x0253C, // BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL - "boxvH", 0x0256A, // BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE - "boxVh", 0x0256B, // BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE - "boxVH", 0x0256C, // BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL - "boxvl", 0x02524, // BOX DRAWINGS LIGHT VERTICAL AND LEFT - "boxvL", 0x02561, // BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE - "boxVl", 0x02562, // BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE - "boxVL", 0x02563, // BOX DRAWINGS DOUBLE VERTICAL AND LEFT - "boxvr", 0x0251C, // BOX DRAWINGS LIGHT VERTICAL AND RIGHT - "boxvR", 0x0255E, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE - "boxVr", 0x0255F, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE - "boxVR", 0x02560, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -// "b.Phi", 0x1D6BD, // MATHEMATICAL BOLD CAPITAL PHI -// "b.phi", 0x1D6D7, // MATHEMATICAL BOLD SMALL PHI -// "b.phiv", 0x1D6DF, // MATHEMATICAL BOLD PHI SYMBOL -// "b.Pi", 0x1D6B7, // MATHEMATICAL BOLD CAPITAL PI -// "b.pi", 0x1D6D1, // MATHEMATICAL BOLD SMALL PI -// "b.piv", 0x1D6E1, // MATHEMATICAL BOLD PI SYMBOL - "bprime", 0x02035, // REVERSED PRIME -// "b.Psi", 0x1D6BF, // MATHEMATICAL BOLD CAPITAL PSI -// "b.psi", 0x1D6D9, // MATHEMATICAL BOLD SMALL PSI - "breve", 0x002D8, // BREVE - "Breve", 0x002D8, // BREVE -// "b.rho", 0x1D6D2, // MATHEMATICAL BOLD SMALL RHO -// "b.rhov", 0x1D6E0, // MATHEMATICAL BOLD RHO SYMBOL - "brvbar", 0x000A6, // BROKEN BAR - "Bscr", 0x0212C, // SCRIPT CAPITAL B - "bscr", 0x1D4B7, // MATHEMATICAL SCRIPT SMALL B - "bsemi", 0x0204F, // REVERSED SEMICOLON -// "b.Sigma", 0x1D6BA, // MATHEMATICAL BOLD CAPITAL SIGMA -// "b.sigma", 0x1D6D4, // MATHEMATICAL BOLD SMALL SIGMA -// "b.sigmav", 0x1D6D3, // MATHEMATICAL BOLD SMALL FINAL SIGMA - "bsim", 0x0223D, // REVERSED TILDE - "bsime", 0x022CD, // REVERSED TILDE EQUALS - "bsol", 0x0005C, // REVERSE SOLIDUS - "bsolb", 0x029C5, // SQUARED FALLING DIAGONAL SLASH - "bsolhsub", 0x027C8, // REVERSE SOLIDUS PRECEDING SUBSET -// "b.tau", 0x1D6D5, // MATHEMATICAL BOLD SMALL TAU -// "b.Theta", 0x1D6AF, // MATHEMATICAL BOLD CAPITAL THETA -// "b.thetas", 0x1D6C9, // MATHEMATICAL BOLD SMALL THETA -// "b.thetav", 0x1D6DD, // MATHEMATICAL BOLD THETA SYMBOL - "bull", 0x02022, // BULLET - "bullet", 0x02022, // BULLET - "bump", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "bumpe", 0x0224F, // DIFFERENCE BETWEEN - "bumpE", 0x02AAE, // EQUALS SIGN WITH BUMPY ABOVE - "Bumpeq", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "bumpeq", 0x0224F, // DIFFERENCE BETWEEN -// "b.Upsi", 0x1D6BC, // MATHEMATICAL BOLD CAPITAL UPSILON -// "b.upsi", 0x1D6D6, // MATHEMATICAL BOLD SMALL UPSILON -// "b.Xi", 0x1D6B5, // MATHEMATICAL BOLD CAPITAL XI -// "b.xi", 0x1D6CF, // MATHEMATICAL BOLD SMALL XI -// "b.zeta", 0x1D6C7, // MATHEMATICAL BOLD SMALL ZETA - NULL, 0 -}; - -static NameId namesC[]={ - "Cacute", 0x00106, // LATIN CAPITAL LETTER C WITH ACUTE - "cacute", 0x00107, // LATIN SMALL LETTER C WITH ACUTE - "cap", 0x02229, // INTERSECTION - "Cap", 0x022D2, // DOUBLE INTERSECTION - "capand", 0x02A44, // INTERSECTION WITH LOGICAL AND - "capbrcup", 0x02A49, // INTERSECTION ABOVE BAR ABOVE UNION - "capcap", 0x02A4B, // INTERSECTION BESIDE AND JOINED WITH INTERSECTION - "capcup", 0x02A47, // INTERSECTION ABOVE UNION - "capdot", 0x02A40, // INTERSECTION WITH DOT - "CapitalDifferentialD", 0x02145, // DOUBLE-STRUCK ITALIC CAPITAL D -// "caps", 0x02229;0x0FE00, // INTERSECTION with serifs - "caret", 0x02041, // CARET INSERTION POINT - "caron", 0x002C7, // CARON - "Cayleys", 0x0212D, // BLACK-LETTER CAPITAL C - "ccaps", 0x02A4D, // CLOSED INTERSECTION WITH SERIFS - "Ccaron", 0x0010C, // LATIN CAPITAL LETTER C WITH CARON - "ccaron", 0x0010D, // LATIN SMALL LETTER C WITH CARON - "Ccedil", 0x000C7, // LATIN CAPITAL LETTER C WITH CEDILLA - "ccedil", 0x000E7, // LATIN SMALL LETTER C WITH CEDILLA - "Ccirc", 0x00108, // LATIN CAPITAL LETTER C WITH CIRCUMFLEX - "ccirc", 0x00109, // LATIN SMALL LETTER C WITH CIRCUMFLEX - "Cconint", 0x02230, // VOLUME INTEGRAL - "ccups", 0x02A4C, // CLOSED UNION WITH SERIFS - "ccupssm", 0x02A50, // CLOSED UNION WITH SERIFS AND SMASH PRODUCT - "Cdot", 0x0010A, // LATIN CAPITAL LETTER C WITH DOT ABOVE - "cdot", 0x0010B, // LATIN SMALL LETTER C WITH DOT ABOVE - "cedil", 0x000B8, // CEDILLA - "Cedilla", 0x000B8, // CEDILLA - "cemptyv", 0x029B2, // EMPTY SET WITH SMALL CIRCLE ABOVE - "cent", 0x000A2, // CENT SIGN - "centerdot", 0x000B7, // MIDDLE DOT - "CenterDot", 0x000B7, // MIDDLE DOT - "Cfr", 0x0212D, // BLACK-LETTER CAPITAL C - "cfr", 0x1D520, // MATHEMATICAL FRAKTUR SMALL C - "CHcy", 0x00427, // CYRILLIC CAPITAL LETTER CHE - "chcy", 0x00447, // CYRILLIC SMALL LETTER CHE - "check", 0x02713, // CHECK MARK - "checkmark", 0x02713, // CHECK MARK - "Chi", 0x003A7, // GREEK CAPITAL LETTER CHI - "chi", 0x003C7, // GREEK SMALL LETTER CHI - "cir", 0x025CB, // WHITE CIRCLE - "circ", 0x002C6, // MODIFIER LETTER CIRCUMFLEX ACCENT - "circeq", 0x02257, // RING EQUAL TO - "circlearrowleft", 0x021BA, // ANTICLOCKWISE OPEN CIRCLE ARROW - "circlearrowright", 0x021BB, // CLOCKWISE OPEN CIRCLE ARROW - "circledast", 0x0229B, // CIRCLED ASTERISK OPERATOR - "circledcirc", 0x0229A, // CIRCLED RING OPERATOR - "circleddash", 0x0229D, // CIRCLED DASH - "CircleDot", 0x02299, // CIRCLED DOT OPERATOR - "circledR", 0x000AE, // REGISTERED SIGN - "circledS", 0x024C8, // CIRCLED LATIN CAPITAL LETTER S - "CircleMinus", 0x02296, // CIRCLED MINUS - "CirclePlus", 0x02295, // CIRCLED PLUS - "CircleTimes", 0x02297, // CIRCLED TIMES - "cire", 0x02257, // RING EQUAL TO - "cirE", 0x029C3, // CIRCLE WITH TWO HORIZONTAL STROKES TO THE RIGHT - "cirfnint", 0x02A10, // CIRCULATION FUNCTION - "cirmid", 0x02AEF, // VERTICAL LINE WITH CIRCLE ABOVE - "cirscir", 0x029C2, // CIRCLE WITH SMALL CIRCLE TO THE RIGHT - "ClockwiseContourIntegral", 0x02232, // CLOCKWISE CONTOUR INTEGRAL - "CloseCurlyDoubleQuote", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "CloseCurlyQuote", 0x02019, // RIGHT SINGLE QUOTATION MARK - "clubs", 0x02663, // BLACK CLUB SUIT - "clubsuit", 0x02663, // BLACK CLUB SUIT - "colon", 0x0003A, // COLON - "Colon", 0x02237, // PROPORTION - "colone", 0x02254, // COLON EQUALS - "Colone", 0x02A74, // DOUBLE COLON EQUAL - "coloneq", 0x02254, // COLON EQUALS - "comma", 0x0002C, // COMMA - "commat", 0x00040, // COMMERCIAL AT - "comp", 0x02201, // COMPLEMENT - "compfn", 0x02218, // RING OPERATOR - "complement", 0x02201, // COMPLEMENT - "complexes", 0x02102, // DOUBLE-STRUCK CAPITAL C - "cong", 0x02245, // APPROXIMATELY EQUAL TO - "congdot", 0x02A6D, // CONGRUENT WITH DOT ABOVE - "Congruent", 0x02261, // IDENTICAL TO - "conint", 0x0222E, // CONTOUR INTEGRAL - "Conint", 0x0222F, // SURFACE INTEGRAL - "ContourIntegral", 0x0222E, // CONTOUR INTEGRAL - "Copf", 0x02102, // DOUBLE-STRUCK CAPITAL C - "copf", 0x1D554, // MATHEMATICAL DOUBLE-STRUCK SMALL C - "coprod", 0x02210, // N-ARY COPRODUCT - "Coproduct", 0x02210, // N-ARY COPRODUCT - "copy", 0x000A9, // COPYRIGHT SIGN - "COPY", 0x000A9, // COPYRIGHT SIGN - "copysr", 0x02117, // SOUND RECORDING COPYRIGHT - "CounterClockwiseContourIntegral", 0x02233, // ANTICLOCKWISE CONTOUR INTEGRAL - "crarr", 0x021B5, // DOWNWARDS ARROW WITH CORNER LEFTWARDS - "cross", 0x02717, // BALLOT X - "Cross", 0x02A2F, // VECTOR OR CROSS PRODUCT - "Cscr", 0x1D49E, // MATHEMATICAL SCRIPT CAPITAL C - "cscr", 0x1D4B8, // MATHEMATICAL SCRIPT SMALL C - "csub", 0x02ACF, // CLOSED SUBSET - "csube", 0x02AD1, // CLOSED SUBSET OR EQUAL TO - "csup", 0x02AD0, // CLOSED SUPERSET - "csupe", 0x02AD2, // CLOSED SUPERSET OR EQUAL TO - "ctdot", 0x022EF, // MIDLINE HORIZONTAL ELLIPSIS - "cudarrl", 0x02938, // RIGHT-SIDE ARC CLOCKWISE ARROW - "cudarrr", 0x02935, // ARROW POINTING RIGHTWARDS THEN CURVING DOWNWARDS - "cuepr", 0x022DE, // EQUAL TO OR PRECEDES - "cuesc", 0x022DF, // EQUAL TO OR SUCCEEDS - "cularr", 0x021B6, // ANTICLOCKWISE TOP SEMICIRCLE ARROW - "cularrp", 0x0293D, // TOP ARC ANTICLOCKWISE ARROW WITH PLUS - "cup", 0x0222A, // UNION - "Cup", 0x022D3, // DOUBLE UNION - "cupbrcap", 0x02A48, // UNION ABOVE BAR ABOVE INTERSECTION - "CupCap", 0x0224D, // EQUIVALENT TO - "cupcap", 0x02A46, // UNION ABOVE INTERSECTION - "cupcup", 0x02A4A, // UNION BESIDE AND JOINED WITH UNION - "cupdot", 0x0228D, // MULTISET MULTIPLICATION - "cupor", 0x02A45, // UNION WITH LOGICAL OR -// "cups", 0x0222A;0x0FE00, // UNION with serifs - "curarr", 0x021B7, // CLOCKWISE TOP SEMICIRCLE ARROW - "curarrm", 0x0293C, // TOP ARC CLOCKWISE ARROW WITH MINUS - "curlyeqprec", 0x022DE, // EQUAL TO OR PRECEDES - "curlyeqsucc", 0x022DF, // EQUAL TO OR SUCCEEDS - "curlyvee", 0x022CE, // CURLY LOGICAL OR - "curlywedge", 0x022CF, // CURLY LOGICAL AND - "curren", 0x000A4, // CURRENCY SIGN - "curvearrowleft", 0x021B6, // ANTICLOCKWISE TOP SEMICIRCLE ARROW - "curvearrowright", 0x021B7, // CLOCKWISE TOP SEMICIRCLE ARROW - "cuvee", 0x022CE, // CURLY LOGICAL OR - "cuwed", 0x022CF, // CURLY LOGICAL AND - "cwconint", 0x02232, // CLOCKWISE CONTOUR INTEGRAL - "cwint", 0x02231, // CLOCKWISE INTEGRAL - "cylcty", 0x0232D, // CYLINDRICITY - NULL, 0 -}; - -static NameId namesD[]={ - "dagger", 0x02020, // DAGGER - "Dagger", 0x02021, // DOUBLE DAGGER - "daleth", 0x02138, // DALET SYMBOL - "darr", 0x02193, // DOWNWARDS ARROW - "Darr", 0x021A1, // DOWNWARDS TWO HEADED ARROW - "dArr", 0x021D3, // DOWNWARDS DOUBLE ARROW - "dash", 0x02010, // HYPHEN - "dashv", 0x022A3, // LEFT TACK - "Dashv", 0x02AE4, // VERTICAL BAR DOUBLE LEFT TURNSTILE - "dbkarow", 0x0290F, // RIGHTWARDS TRIPLE DASH ARROW - "dblac", 0x002DD, // DOUBLE ACUTE ACCENT - "Dcaron", 0x0010E, // LATIN CAPITAL LETTER D WITH CARON - "dcaron", 0x0010F, // LATIN SMALL LETTER D WITH CARON - "Dcy", 0x00414, // CYRILLIC CAPITAL LETTER DE - "dcy", 0x00434, // CYRILLIC SMALL LETTER DE - "DD", 0x02145, // DOUBLE-STRUCK ITALIC CAPITAL D - "dd", 0x02146, // DOUBLE-STRUCK ITALIC SMALL D - "ddagger", 0x02021, // DOUBLE DAGGER - "ddarr", 0x021CA, // DOWNWARDS PAIRED ARROWS - "DDotrahd", 0x02911, // RIGHTWARDS ARROW WITH DOTTED STEM - "ddotseq", 0x02A77, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - "deg", 0x000B0, // DEGREE SIGN - "Del", 0x02207, // NABLA - "Delta", 0x00394, // GREEK CAPITAL LETTER DELTA - "delta", 0x003B4, // GREEK SMALL LETTER DELTA - "demptyv", 0x029B1, // EMPTY SET WITH OVERBAR - "dfisht", 0x0297F, // DOWN FISH TAIL - "Dfr", 0x1D507, // MATHEMATICAL FRAKTUR CAPITAL D - "dfr", 0x1D521, // MATHEMATICAL FRAKTUR SMALL D - "Dgr", 0x00394, // GREEK CAPITAL LETTER DELTA - "dgr", 0x003B4, // GREEK SMALL LETTER DELTA - "dHar", 0x02965, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "dharl", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "dharr", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "DiacriticalAcute", 0x000B4, // ACUTE ACCENT - "DiacriticalDot", 0x002D9, // DOT ABOVE - "DiacriticalDoubleAcute", 0x002DD, // DOUBLE ACUTE ACCENT - "DiacriticalGrave", 0x00060, // GRAVE ACCENT - "DiacriticalTilde", 0x002DC, // SMALL TILDE - "diam", 0x022C4, // DIAMOND OPERATOR - "diamond", 0x022C4, // DIAMOND OPERATOR - "Diamond", 0x022C4, // DIAMOND OPERATOR - "diamondsuit", 0x02666, // BLACK DIAMOND SUIT - "diams", 0x02666, // BLACK DIAMOND SUIT - "die", 0x000A8, // DIAERESIS - "DifferentialD", 0x02146, // DOUBLE-STRUCK ITALIC SMALL D - "digamma", 0x003DD, // GREEK SMALL LETTER DIGAMMA - "disin", 0x022F2, // ELEMENT OF WITH LONG HORIZONTAL STROKE - "div", 0x000F7, // DIVISION SIGN - "divide", 0x000F7, // DIVISION SIGN - "divideontimes", 0x022C7, // DIVISION TIMES - "divonx", 0x022C7, // DIVISION TIMES - "DJcy", 0x00402, // CYRILLIC CAPITAL LETTER DJE - "djcy", 0x00452, // CYRILLIC SMALL LETTER DJE - "dlcorn", 0x0231E, // BOTTOM LEFT CORNER - "dlcrop", 0x0230D, // BOTTOM LEFT CROP - "dollar", 0x00024, // DOLLAR SIGN - "Dopf", 0x1D53B, // MATHEMATICAL DOUBLE-STRUCK CAPITAL D - "dopf", 0x1D555, // MATHEMATICAL DOUBLE-STRUCK SMALL D - "Dot", 0x000A8, // DIAERESIS - "dot", 0x002D9, // DOT ABOVE - "DotDot", 0x020DC, // COMBINING FOUR DOTS ABOVE - "doteq", 0x02250, // APPROACHES THE LIMIT - "doteqdot", 0x02251, // GEOMETRICALLY EQUAL TO - "DotEqual", 0x02250, // APPROACHES THE LIMIT - "dotminus", 0x02238, // DOT MINUS - "dotplus", 0x02214, // DOT PLUS - "dotsquare", 0x022A1, // SQUARED DOT OPERATOR - "doublebarwedge", 0x02306, // PERSPECTIVE - "DoubleContourIntegral", 0x0222F, // SURFACE INTEGRAL - "DoubleDot", 0x000A8, // DIAERESIS - "DoubleDownArrow", 0x021D3, // DOWNWARDS DOUBLE ARROW - "DoubleLeftArrow", 0x021D0, // LEFTWARDS DOUBLE ARROW - "DoubleLeftRightArrow", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "DoubleLeftTee", 0x02AE4, // VERTICAL BAR DOUBLE LEFT TURNSTILE - "DoubleLongLeftArrow", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "DoubleLongLeftRightArrow", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "DoubleLongRightArrow", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "DoubleRightArrow", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "DoubleRightTee", 0x022A8, // TRUE - "DoubleUpArrow", 0x021D1, // UPWARDS DOUBLE ARROW - "DoubleUpDownArrow", 0x021D5, // UP DOWN DOUBLE ARROW - "DoubleVerticalBar", 0x02225, // PARALLEL TO - "downarrow", 0x02193, // DOWNWARDS ARROW - "DownArrow", 0x02193, // DOWNWARDS ARROW - "Downarrow", 0x021D3, // DOWNWARDS DOUBLE ARROW - "DownArrowBar", 0x02913, // DOWNWARDS ARROW TO BAR - "DownArrowUpArrow", 0x021F5, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - "DownBreve", 0x00311, // COMBINING INVERTED BREVE - "downdownarrows", 0x021CA, // DOWNWARDS PAIRED ARROWS - "downharpoonleft", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "downharpoonright", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "DownLeftRightVector", 0x02950, // LEFT BARB DOWN RIGHT BARB DOWN HARPOON - "DownLeftTeeVector", 0x0295E, // LEFTWARDS HARPOON WITH BARB DOWN FROM BAR - "DownLeftVector", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "DownLeftVectorBar", 0x02956, // LEFTWARDS HARPOON WITH BARB DOWN TO BAR - "DownRightTeeVector", 0x0295F, // RIGHTWARDS HARPOON WITH BARB DOWN FROM BAR - "DownRightVector", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "DownRightVectorBar", 0x02957, // RIGHTWARDS HARPOON WITH BARB DOWN TO BAR - "DownTee", 0x022A4, // DOWN TACK - "DownTeeArrow", 0x021A7, // DOWNWARDS ARROW FROM BAR - "drbkarow", 0x02910, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - "drcorn", 0x0231F, // BOTTOM RIGHT CORNER - "drcrop", 0x0230C, // BOTTOM RIGHT CROP - "Dscr", 0x1D49F, // MATHEMATICAL SCRIPT CAPITAL D - "dscr", 0x1D4B9, // MATHEMATICAL SCRIPT SMALL D - "DScy", 0x00405, // CYRILLIC CAPITAL LETTER DZE - "dscy", 0x00455, // CYRILLIC SMALL LETTER DZE - "dsol", 0x029F6, // SOLIDUS WITH OVERBAR - "Dstrok", 0x00110, // LATIN CAPITAL LETTER D WITH STROKE - "dstrok", 0x00111, // LATIN SMALL LETTER D WITH STROKE - "dtdot", 0x022F1, // DOWN RIGHT DIAGONAL ELLIPSIS - "dtri", 0x025BF, // WHITE DOWN-POINTING SMALL TRIANGLE - "dtrif", 0x025BE, // BLACK DOWN-POINTING SMALL TRIANGLE - "duarr", 0x021F5, // DOWNWARDS ARROW LEFTWARDS OF UPWARDS ARROW - "duhar", 0x0296F, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "dwangle", 0x029A6, // OBLIQUE ANGLE OPENING UP - "DZcy", 0x0040F, // CYRILLIC CAPITAL LETTER DZHE - "dzcy", 0x0045F, // CYRILLIC SMALL LETTER DZHE - "dzigrarr", 0x027FF, // LONG RIGHTWARDS SQUIGGLE ARROW - NULL, 0 -}; - -static NameId namesE[]={ - "Eacgr", 0x00388, // GREEK CAPITAL LETTER EPSILON WITH TONOS - "eacgr", 0x003AD, // GREEK SMALL LETTER EPSILON WITH TONOS - "Eacute", 0x000C9, // LATIN CAPITAL LETTER E WITH ACUTE - "eacute", 0x000E9, // LATIN SMALL LETTER E WITH ACUTE - "easter", 0x02A6E, // EQUALS WITH ASTERISK - "Ecaron", 0x0011A, // LATIN CAPITAL LETTER E WITH CARON - "ecaron", 0x0011B, // LATIN SMALL LETTER E WITH CARON - "ecir", 0x02256, // RING IN EQUAL TO - "Ecirc", 0x000CA, // LATIN CAPITAL LETTER E WITH CIRCUMFLEX - "ecirc", 0x000EA, // LATIN SMALL LETTER E WITH CIRCUMFLEX - "ecolon", 0x02255, // EQUALS COLON - "Ecy", 0x0042D, // CYRILLIC CAPITAL LETTER E - "ecy", 0x0044D, // CYRILLIC SMALL LETTER E - "eDDot", 0x02A77, // EQUALS SIGN WITH TWO DOTS ABOVE AND TWO DOTS BELOW - "Edot", 0x00116, // LATIN CAPITAL LETTER E WITH DOT ABOVE - "edot", 0x00117, // LATIN SMALL LETTER E WITH DOT ABOVE - "eDot", 0x02251, // GEOMETRICALLY EQUAL TO - "ee", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - "EEacgr", 0x00389, // GREEK CAPITAL LETTER ETA WITH TONOS - "eeacgr", 0x003AE, // GREEK SMALL LETTER ETA WITH TONOS - "EEgr", 0x00397, // GREEK CAPITAL LETTER ETA - "eegr", 0x003B7, // GREEK SMALL LETTER ETA - "efDot", 0x02252, // APPROXIMATELY EQUAL TO OR THE IMAGE OF - "Efr", 0x1D508, // MATHEMATICAL FRAKTUR CAPITAL E - "efr", 0x1D522, // MATHEMATICAL FRAKTUR SMALL E - "eg", 0x02A9A, // DOUBLE-LINE EQUAL TO OR GREATER-THAN - "Egr", 0x00395, // GREEK CAPITAL LETTER EPSILON - "egr", 0x003B5, // GREEK SMALL LETTER EPSILON - "Egrave", 0x000C8, // LATIN CAPITAL LETTER E WITH GRAVE - "egrave", 0x000E8, // LATIN SMALL LETTER E WITH GRAVE - "egs", 0x02A96, // SLANTED EQUAL TO OR GREATER-THAN - "egsdot", 0x02A98, // SLANTED EQUAL TO OR GREATER-THAN WITH DOT INSIDE - "el", 0x02A99, // DOUBLE-LINE EQUAL TO OR LESS-THAN - "Element", 0x02208, // ELEMENT OF - "elinters", 0x023E7, // ELECTRICAL INTERSECTION - "ell", 0x02113, // SCRIPT SMALL L - "els", 0x02A95, // SLANTED EQUAL TO OR LESS-THAN - "elsdot", 0x02A97, // SLANTED EQUAL TO OR LESS-THAN WITH DOT INSIDE - "Emacr", 0x00112, // LATIN CAPITAL LETTER E WITH MACRON - "emacr", 0x00113, // LATIN SMALL LETTER E WITH MACRON - "empty", 0x02205, // EMPTY SET - "emptyset", 0x02205, // EMPTY SET - "EmptySmallSquare", 0x025FB, // WHITE MEDIUM SQUARE - "emptyv", 0x02205, // EMPTY SET - "EmptyVerySmallSquare", 0x025AB, // WHITE SMALL SQUARE - "emsp", 0x02003, // EM SPACE - "emsp13", 0x02004, // THREE-PER-EM SPACE - "emsp14", 0x02005, // FOUR-PER-EM SPACE - "ENG", 0x0014A, // LATIN CAPITAL LETTER ENG - "eng", 0x0014B, // LATIN SMALL LETTER ENG - "ensp", 0x02002, // EN SPACE - "Eogon", 0x00118, // LATIN CAPITAL LETTER E WITH OGONEK - "eogon", 0x00119, // LATIN SMALL LETTER E WITH OGONEK - "Eopf", 0x1D53C, // MATHEMATICAL DOUBLE-STRUCK CAPITAL E - "eopf", 0x1D556, // MATHEMATICAL DOUBLE-STRUCK SMALL E - "epar", 0x022D5, // EQUAL AND PARALLEL TO - "eparsl", 0x029E3, // EQUALS SIGN AND SLANTED PARALLEL - "eplus", 0x02A71, // EQUALS SIGN ABOVE PLUS SIGN - "epsi", 0x003B5, // GREEK SMALL LETTER EPSILON - "Epsilon", 0x00395, // GREEK CAPITAL LETTER EPSILON - "epsilon", 0x003B5, // GREEK SMALL LETTER EPSILON - "epsiv", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "eqcirc", 0x02256, // RING IN EQUAL TO - "eqcolon", 0x02255, // EQUALS COLON - "eqsim", 0x02242, // MINUS TILDE - "eqslantgtr", 0x02A96, // SLANTED EQUAL TO OR GREATER-THAN - "eqslantless", 0x02A95, // SLANTED EQUAL TO OR LESS-THAN - "Equal", 0x02A75, // TWO CONSECUTIVE EQUALS SIGNS - "equals", 0x0003D, // EQUALS SIGN - "EqualTilde", 0x02242, // MINUS TILDE - "equest", 0x0225F, // QUESTIONED EQUAL TO - "Equilibrium", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "equiv", 0x02261, // IDENTICAL TO - "equivDD", 0x02A78, // EQUIVALENT WITH FOUR DOTS ABOVE - "eqvparsl", 0x029E5, // IDENTICAL TO AND SLANTED PARALLEL - "erarr", 0x02971, // EQUALS SIGN ABOVE RIGHTWARDS ARROW - "erDot", 0x02253, // IMAGE OF OR APPROXIMATELY EQUAL TO - "escr", 0x0212F, // SCRIPT SMALL E - "Escr", 0x02130, // SCRIPT CAPITAL E - "esdot", 0x02250, // APPROACHES THE LIMIT - "esim", 0x02242, // MINUS TILDE - "Esim", 0x02A73, // EQUALS SIGN ABOVE TILDE OPERATOR - "Eta", 0x00397, // GREEK CAPITAL LETTER ETA - "eta", 0x003B7, // GREEK SMALL LETTER ETA - "ETH", 0x000D0, // LATIN CAPITAL LETTER ETH - "eth", 0x000F0, // LATIN SMALL LETTER ETH - "Euml", 0x000CB, // LATIN CAPITAL LETTER E WITH DIAERESIS - "euml", 0x000EB, // LATIN SMALL LETTER E WITH DIAERESIS - "euro", 0x020AC, // EURO SIGN - "excl", 0x00021, // EXCLAMATION MARK - "exist", 0x02203, // THERE EXISTS - "Exists", 0x02203, // THERE EXISTS - "expectation", 0x02130, // SCRIPT CAPITAL E - "exponentiale", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - "ExponentialE", 0x02147, // DOUBLE-STRUCK ITALIC SMALL E - NULL, 0 -}; - -static NameId namesF[]={ - "fallingdotseq", 0x02252, // APPROXIMATELY EQUAL TO OR THE IMAGE OF - "Fcy", 0x00424, // CYRILLIC CAPITAL LETTER EF - "fcy", 0x00444, // CYRILLIC SMALL LETTER EF - "female", 0x02640, // FEMALE SIGN - "ffilig", 0x0FB03, // LATIN SMALL LIGATURE FFI - "fflig", 0x0FB00, // LATIN SMALL LIGATURE FF - "ffllig", 0x0FB04, // LATIN SMALL LIGATURE FFL - "Ffr", 0x1D509, // MATHEMATICAL FRAKTUR CAPITAL F - "ffr", 0x1D523, // MATHEMATICAL FRAKTUR SMALL F - "filig", 0x0FB01, // LATIN SMALL LIGATURE FI - "FilledSmallSquare", 0x025FC, // BLACK MEDIUM SQUARE - "FilledVerySmallSquare", 0x025AA, // BLACK SMALL SQUARE -// "fjlig", 0x00066;0x0006A, // fj ligature - "flat", 0x0266D, // MUSIC FLAT SIGN - "fllig", 0x0FB02, // LATIN SMALL LIGATURE FL - "fltns", 0x025B1, // WHITE PARALLELOGRAM - "fnof", 0x00192, // LATIN SMALL LETTER F WITH HOOK - "Fopf", 0x1D53D, // MATHEMATICAL DOUBLE-STRUCK CAPITAL F - "fopf", 0x1D557, // MATHEMATICAL DOUBLE-STRUCK SMALL F - "forall", 0x02200, // FOR ALL - "ForAll", 0x02200, // FOR ALL - "fork", 0x022D4, // PITCHFORK - "forkv", 0x02AD9, // ELEMENT OF OPENING DOWNWARDS - "Fouriertrf", 0x02131, // SCRIPT CAPITAL F - "fpartint", 0x02A0D, // FINITE PART INTEGRAL - "frac12", 0x000BD, // VULGAR FRACTION ONE HALF - "frac13", 0x02153, // VULGAR FRACTION ONE THIRD - "frac14", 0x000BC, // VULGAR FRACTION ONE QUARTER - "frac15", 0x02155, // VULGAR FRACTION ONE FIFTH - "frac16", 0x02159, // VULGAR FRACTION ONE SIXTH - "frac18", 0x0215B, // VULGAR FRACTION ONE EIGHTH - "frac23", 0x02154, // VULGAR FRACTION TWO THIRDS - "frac25", 0x02156, // VULGAR FRACTION TWO FIFTHS - "frac34", 0x000BE, // VULGAR FRACTION THREE QUARTERS - "frac35", 0x02157, // VULGAR FRACTION THREE FIFTHS - "frac38", 0x0215C, // VULGAR FRACTION THREE EIGHTHS - "frac45", 0x02158, // VULGAR FRACTION FOUR FIFTHS - "frac56", 0x0215A, // VULGAR FRACTION FIVE SIXTHS - "frac58", 0x0215D, // VULGAR FRACTION FIVE EIGHTHS - "frac78", 0x0215E, // VULGAR FRACTION SEVEN EIGHTHS - "frasl", 0x02044, // FRACTION SLASH - "frown", 0x02322, // FROWN - "Fscr", 0x02131, // SCRIPT CAPITAL F - "fscr", 0x1D4BB, // MATHEMATICAL SCRIPT SMALL F - NULL, 0 -}; - -static NameId namesG[]={ - "gacute", 0x001F5, // LATIN SMALL LETTER G WITH ACUTE - "Gamma", 0x00393, // GREEK CAPITAL LETTER GAMMA - "gamma", 0x003B3, // GREEK SMALL LETTER GAMMA - "Gammad", 0x003DC, // GREEK LETTER DIGAMMA - "gammad", 0x003DD, // GREEK SMALL LETTER DIGAMMA - "gap", 0x02A86, // GREATER-THAN OR APPROXIMATE - "Gbreve", 0x0011E, // LATIN CAPITAL LETTER G WITH BREVE - "gbreve", 0x0011F, // LATIN SMALL LETTER G WITH BREVE - "Gcedil", 0x00122, // LATIN CAPITAL LETTER G WITH CEDILLA - "Gcirc", 0x0011C, // LATIN CAPITAL LETTER G WITH CIRCUMFLEX - "gcirc", 0x0011D, // LATIN SMALL LETTER G WITH CIRCUMFLEX - "Gcy", 0x00413, // CYRILLIC CAPITAL LETTER GHE - "gcy", 0x00433, // CYRILLIC SMALL LETTER GHE - "Gdot", 0x00120, // LATIN CAPITAL LETTER G WITH DOT ABOVE - "gdot", 0x00121, // LATIN SMALL LETTER G WITH DOT ABOVE - "ge", 0x02265, // GREATER-THAN OR EQUAL TO - "gE", 0x02267, // GREATER-THAN OVER EQUAL TO - "gel", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "gEl", 0x02A8C, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - "geq", 0x02265, // GREATER-THAN OR EQUAL TO - "geqq", 0x02267, // GREATER-THAN OVER EQUAL TO - "geqslant", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "ges", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "gescc", 0x02AA9, // GREATER-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - "gesdot", 0x02A80, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - "gesdoto", 0x02A82, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - "gesdotol", 0x02A84, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT -// "gesl", 0x022DB;0x0FE00, // GREATER-THAN slanted EQUAL TO OR LESS-THAN - "gesles", 0x02A94, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL - "Gfr", 0x1D50A, // MATHEMATICAL FRAKTUR CAPITAL G - "gfr", 0x1D524, // MATHEMATICAL FRAKTUR SMALL G - "gg", 0x0226B, // MUCH GREATER-THAN - "Gg", 0x022D9, // VERY MUCH GREATER-THAN - "ggg", 0x022D9, // VERY MUCH GREATER-THAN - "Ggr", 0x00393, // GREEK CAPITAL LETTER GAMMA - "ggr", 0x003B3, // GREEK SMALL LETTER GAMMA - "gimel", 0x02137, // GIMEL SYMBOL - "GJcy", 0x00403, // CYRILLIC CAPITAL LETTER GJE - "gjcy", 0x00453, // CYRILLIC SMALL LETTER GJE - "gl", 0x02277, // GREATER-THAN OR LESS-THAN - "gla", 0x02AA5, // GREATER-THAN BESIDE LESS-THAN - "glE", 0x02A92, // GREATER-THAN ABOVE LESS-THAN ABOVE DOUBLE-LINE EQUAL - "glj", 0x02AA4, // GREATER-THAN OVERLAPPING LESS-THAN - "gnap", 0x02A8A, // GREATER-THAN AND NOT APPROXIMATE - "gnapprox", 0x02A8A, // GREATER-THAN AND NOT APPROXIMATE - "gnE", 0x02269, // GREATER-THAN BUT NOT EQUAL TO - "gne", 0x02A88, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - "gneq", 0x02A88, // GREATER-THAN AND SINGLE-LINE NOT EQUAL TO - "gneqq", 0x02269, // GREATER-THAN BUT NOT EQUAL TO - "gnsim", 0x022E7, // GREATER-THAN BUT NOT EQUIVALENT TO - "Gopf", 0x1D53E, // MATHEMATICAL DOUBLE-STRUCK CAPITAL G - "gopf", 0x1D558, // MATHEMATICAL DOUBLE-STRUCK SMALL G - "grave", 0x00060, // GRAVE ACCENT - "GreaterEqual", 0x02265, // GREATER-THAN OR EQUAL TO - "GreaterEqualLess", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "GreaterFullEqual", 0x02267, // GREATER-THAN OVER EQUAL TO - "GreaterGreater", 0x02AA2, // DOUBLE NESTED GREATER-THAN - "GreaterLess", 0x02277, // GREATER-THAN OR LESS-THAN - "GreaterSlantEqual", 0x02A7E, // GREATER-THAN OR SLANTED EQUAL TO - "GreaterTilde", 0x02273, // GREATER-THAN OR EQUIVALENT TO - "gscr", 0x0210A, // SCRIPT SMALL G - "Gscr", 0x1D4A2, // MATHEMATICAL SCRIPT CAPITAL G - "gsim", 0x02273, // GREATER-THAN OR EQUIVALENT TO - "gsime", 0x02A8E, // GREATER-THAN ABOVE SIMILAR OR EQUAL - "gsiml", 0x02A90, // GREATER-THAN ABOVE SIMILAR ABOVE LESS-THAN - "gt", 0x0003E, // GREATER-THAN SIGN - "GT", 0x0003E, // GREATER-THAN SIGN - "Gt", 0x0226B, // MUCH GREATER-THAN - "gtcc", 0x02AA7, // GREATER-THAN CLOSED BY CURVE - "gtcir", 0x02A7A, // GREATER-THAN WITH CIRCLE INSIDE - "gtdot", 0x022D7, // GREATER-THAN WITH DOT - "gtlPar", 0x02995, // DOUBLE LEFT ARC GREATER-THAN BRACKET - "gtquest", 0x02A7C, // GREATER-THAN WITH QUESTION MARK ABOVE - "gtrapprox", 0x02A86, // GREATER-THAN OR APPROXIMATE - "gtrarr", 0x02978, // GREATER-THAN ABOVE RIGHTWARDS ARROW - "gtrdot", 0x022D7, // GREATER-THAN WITH DOT - "gtreqless", 0x022DB, // GREATER-THAN EQUAL TO OR LESS-THAN - "gtreqqless", 0x02A8C, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN - "gtrless", 0x02277, // GREATER-THAN OR LESS-THAN - "gtrsim", 0x02273, // GREATER-THAN OR EQUIVALENT TO -// "gvertneqq", 0x02269;0x0FE00, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke -// "gvnE", 0x02269;0x0FE00, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke - NULL, 0 -}; - -static NameId namesH[]={ - "Hacek", 0x002C7, // CARON - "hairsp", 0x0200A, // HAIR SPACE - "half", 0x000BD, // VULGAR FRACTION ONE HALF - "hamilt", 0x0210B, // SCRIPT CAPITAL H - "HARDcy", 0x0042A, // CYRILLIC CAPITAL LETTER HARD SIGN - "hardcy", 0x0044A, // CYRILLIC SMALL LETTER HARD SIGN - "harr", 0x02194, // LEFT RIGHT ARROW - "hArr", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "harrcir", 0x02948, // LEFT RIGHT ARROW THROUGH SMALL CIRCLE - "harrw", 0x021AD, // LEFT RIGHT WAVE ARROW - "Hat", 0x0005E, // CIRCUMFLEX ACCENT - "hbar", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "Hcirc", 0x00124, // LATIN CAPITAL LETTER H WITH CIRCUMFLEX - "hcirc", 0x00125, // LATIN SMALL LETTER H WITH CIRCUMFLEX - "hearts", 0x02665, // BLACK HEART SUIT - "heartsuit", 0x02665, // BLACK HEART SUIT - "hellip", 0x02026, // HORIZONTAL ELLIPSIS - "hercon", 0x022B9, // HERMITIAN CONJUGATE MATRIX - "Hfr", 0x0210C, // BLACK-LETTER CAPITAL H - "hfr", 0x1D525, // MATHEMATICAL FRAKTUR SMALL H - "HilbertSpace", 0x0210B, // SCRIPT CAPITAL H - "hksearow", 0x02925, // SOUTH EAST ARROW WITH HOOK - "hkswarow", 0x02926, // SOUTH WEST ARROW WITH HOOK - "hoarr", 0x021FF, // LEFT RIGHT OPEN-HEADED ARROW - "homtht", 0x0223B, // HOMOTHETIC - "hookleftarrow", 0x021A9, // LEFTWARDS ARROW WITH HOOK - "hookrightarrow", 0x021AA, // RIGHTWARDS ARROW WITH HOOK - "Hopf", 0x0210D, // DOUBLE-STRUCK CAPITAL H - "hopf", 0x1D559, // MATHEMATICAL DOUBLE-STRUCK SMALL H - "horbar", 0x02015, // HORIZONTAL BAR - "HorizontalLine", 0x02500, // BOX DRAWINGS LIGHT HORIZONTAL - "Hscr", 0x0210B, // SCRIPT CAPITAL H - "hscr", 0x1D4BD, // MATHEMATICAL SCRIPT SMALL H - "hslash", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "Hstrok", 0x00126, // LATIN CAPITAL LETTER H WITH STROKE - "hstrok", 0x00127, // LATIN SMALL LETTER H WITH STROKE - "HumpDownHump", 0x0224E, // GEOMETRICALLY EQUIVALENT TO - "HumpEqual", 0x0224F, // DIFFERENCE BETWEEN - "hybull", 0x02043, // HYPHEN BULLET - "hyphen", 0x02010, // HYPHEN - NULL, 0 -}; - -static NameId namesI[]={ - "Iacgr", 0x0038A, // GREEK CAPITAL LETTER IOTA WITH TONOS - "iacgr", 0x003AF, // GREEK SMALL LETTER IOTA WITH TONOS - "Iacute", 0x000CD, // LATIN CAPITAL LETTER I WITH ACUTE - "iacute", 0x000ED, // LATIN SMALL LETTER I WITH ACUTE - "ic", 0x02063, // INVISIBLE SEPARATOR - "Icirc", 0x000CE, // LATIN CAPITAL LETTER I WITH CIRCUMFLEX - "icirc", 0x000EE, // LATIN SMALL LETTER I WITH CIRCUMFLEX - "Icy", 0x00418, // CYRILLIC CAPITAL LETTER I - "icy", 0x00438, // CYRILLIC SMALL LETTER I - "idiagr", 0x00390, // GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS - "Idigr", 0x003AA, // GREEK CAPITAL LETTER IOTA WITH DIALYTIKA - "idigr", 0x003CA, // GREEK SMALL LETTER IOTA WITH DIALYTIKA - "Idot", 0x00130, // LATIN CAPITAL LETTER I WITH DOT ABOVE - "IEcy", 0x00415, // CYRILLIC CAPITAL LETTER IE - "iecy", 0x00435, // CYRILLIC SMALL LETTER IE - "iexcl", 0x000A1, // INVERTED EXCLAMATION MARK - "iff", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "Ifr", 0x02111, // BLACK-LETTER CAPITAL I - "ifr", 0x1D526, // MATHEMATICAL FRAKTUR SMALL I - "Igr", 0x00399, // GREEK CAPITAL LETTER IOTA - "igr", 0x003B9, // GREEK SMALL LETTER IOTA - "Igrave", 0x000CC, // LATIN CAPITAL LETTER I WITH GRAVE - "igrave", 0x000EC, // LATIN SMALL LETTER I WITH GRAVE - "ii", 0x02148, // DOUBLE-STRUCK ITALIC SMALL I - "iiiint", 0x02A0C, // QUADRUPLE INTEGRAL OPERATOR - "iiint", 0x0222D, // TRIPLE INTEGRAL - "iinfin", 0x029DC, // INCOMPLETE INFINITY - "iiota", 0x02129, // TURNED GREEK SMALL LETTER IOTA - "IJlig", 0x00132, // LATIN CAPITAL LIGATURE IJ - "ijlig", 0x00133, // LATIN SMALL LIGATURE IJ - "Im", 0x02111, // BLACK-LETTER CAPITAL I - "Imacr", 0x0012A, // LATIN CAPITAL LETTER I WITH MACRON - "imacr", 0x0012B, // LATIN SMALL LETTER I WITH MACRON - "image", 0x02111, // BLACK-LETTER CAPITAL I - "ImaginaryI", 0x02148, // DOUBLE-STRUCK ITALIC SMALL I - "imagline", 0x02110, // SCRIPT CAPITAL I - "imagpart", 0x02111, // BLACK-LETTER CAPITAL I - "imath", 0x00131, // LATIN SMALL LETTER DOTLESS I - "imof", 0x022B7, // IMAGE OF - "imped", 0x001B5, // LATIN CAPITAL LETTER Z WITH STROKE - "Implies", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "in", 0x02208, // ELEMENT OF - "incare", 0x02105, // CARE OF - "infin", 0x0221E, // INFINITY - "infintie", 0x029DD, // TIE OVER INFINITY - "inodot", 0x00131, // LATIN SMALL LETTER DOTLESS I - "int", 0x0222B, // INTEGRAL - "Int", 0x0222C, // DOUBLE INTEGRAL - "intcal", 0x022BA, // INTERCALATE - "integers", 0x02124, // DOUBLE-STRUCK CAPITAL Z - "Integral", 0x0222B, // INTEGRAL - "intercal", 0x022BA, // INTERCALATE - "Intersection", 0x022C2, // N-ARY INTERSECTION - "intlarhk", 0x02A17, // INTEGRAL WITH LEFTWARDS ARROW WITH HOOK - "intprod", 0x02A3C, // INTERIOR PRODUCT - "InvisibleComma", 0x02063, // INVISIBLE SEPARATOR - "InvisibleTimes", 0x02062, // INVISIBLE TIMES - "IOcy", 0x00401, // CYRILLIC CAPITAL LETTER IO - "iocy", 0x00451, // CYRILLIC SMALL LETTER IO - "Iogon", 0x0012E, // LATIN CAPITAL LETTER I WITH OGONEK - "iogon", 0x0012F, // LATIN SMALL LETTER I WITH OGONEK - "Iopf", 0x1D540, // MATHEMATICAL DOUBLE-STRUCK CAPITAL I - "iopf", 0x1D55A, // MATHEMATICAL DOUBLE-STRUCK SMALL I - "Iota", 0x00399, // GREEK CAPITAL LETTER IOTA - "iota", 0x003B9, // GREEK SMALL LETTER IOTA - "iprod", 0x02A3C, // INTERIOR PRODUCT - "iquest", 0x000BF, // INVERTED QUESTION MARK - "Iscr", 0x02110, // SCRIPT CAPITAL I - "iscr", 0x1D4BE, // MATHEMATICAL SCRIPT SMALL I - "isin", 0x02208, // ELEMENT OF - "isindot", 0x022F5, // ELEMENT OF WITH DOT ABOVE - "isinE", 0x022F9, // ELEMENT OF WITH TWO HORIZONTAL STROKES - "isins", 0x022F4, // SMALL ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "isinsv", 0x022F3, // ELEMENT OF WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "isinv", 0x02208, // ELEMENT OF - "it", 0x02062, // INVISIBLE TIMES - "Itilde", 0x00128, // LATIN CAPITAL LETTER I WITH TILDE - "itilde", 0x00129, // LATIN SMALL LETTER I WITH TILDE - "Iukcy", 0x00406, // CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I - "iukcy", 0x00456, // CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I - "Iuml", 0x000CF, // LATIN CAPITAL LETTER I WITH DIAERESIS - "iuml", 0x000EF, // LATIN SMALL LETTER I WITH DIAERESIS - NULL, 0 -}; - -static NameId namesJ[]={ - "Jcirc", 0x00134, // LATIN CAPITAL LETTER J WITH CIRCUMFLEX - "jcirc", 0x00135, // LATIN SMALL LETTER J WITH CIRCUMFLEX - "Jcy", 0x00419, // CYRILLIC CAPITAL LETTER SHORT I - "jcy", 0x00439, // CYRILLIC SMALL LETTER SHORT I - "Jfr", 0x1D50D, // MATHEMATICAL FRAKTUR CAPITAL J - "jfr", 0x1D527, // MATHEMATICAL FRAKTUR SMALL J - "jmath", 0x00237, // LATIN SMALL LETTER DOTLESS J - "Jopf", 0x1D541, // MATHEMATICAL DOUBLE-STRUCK CAPITAL J - "jopf", 0x1D55B, // MATHEMATICAL DOUBLE-STRUCK SMALL J - "Jscr", 0x1D4A5, // MATHEMATICAL SCRIPT CAPITAL J - "jscr", 0x1D4BF, // MATHEMATICAL SCRIPT SMALL J - "Jsercy", 0x00408, // CYRILLIC CAPITAL LETTER JE - "jsercy", 0x00458, // CYRILLIC SMALL LETTER JE - "Jukcy", 0x00404, // CYRILLIC CAPITAL LETTER UKRAINIAN IE - "jukcy", 0x00454, // CYRILLIC SMALL LETTER UKRAINIAN IE - NULL, 0 -}; - -static NameId namesK[]={ - "Kappa", 0x0039A, // GREEK CAPITAL LETTER KAPPA - "kappa", 0x003BA, // GREEK SMALL LETTER KAPPA - "kappav", 0x003F0, // GREEK KAPPA SYMBOL - "Kcedil", 0x00136, // LATIN CAPITAL LETTER K WITH CEDILLA - "kcedil", 0x00137, // LATIN SMALL LETTER K WITH CEDILLA - "Kcy", 0x0041A, // CYRILLIC CAPITAL LETTER KA - "kcy", 0x0043A, // CYRILLIC SMALL LETTER KA - "Kfr", 0x1D50E, // MATHEMATICAL FRAKTUR CAPITAL K - "kfr", 0x1D528, // MATHEMATICAL FRAKTUR SMALL K - "Kgr", 0x0039A, // GREEK CAPITAL LETTER KAPPA - "kgr", 0x003BA, // GREEK SMALL LETTER KAPPA - "kgreen", 0x00138, // LATIN SMALL LETTER KRA - "KHcy", 0x00425, // CYRILLIC CAPITAL LETTER HA - "khcy", 0x00445, // CYRILLIC SMALL LETTER HA - "KHgr", 0x003A7, // GREEK CAPITAL LETTER CHI - "khgr", 0x003C7, // GREEK SMALL LETTER CHI - "KJcy", 0x0040C, // CYRILLIC CAPITAL LETTER KJE - "kjcy", 0x0045C, // CYRILLIC SMALL LETTER KJE - "Kopf", 0x1D542, // MATHEMATICAL DOUBLE-STRUCK CAPITAL K - "kopf", 0x1D55C, // MATHEMATICAL DOUBLE-STRUCK SMALL K - "Kscr", 0x1D4A6, // MATHEMATICAL SCRIPT CAPITAL K - "kscr", 0x1D4C0, // MATHEMATICAL SCRIPT SMALL K - NULL, 0 -}; - -static NameId namesL[]={ - "lAarr", 0x021DA, // LEFTWARDS TRIPLE ARROW - "Lacute", 0x00139, // LATIN CAPITAL LETTER L WITH ACUTE - "lacute", 0x0013A, // LATIN SMALL LETTER L WITH ACUTE - "laemptyv", 0x029B4, // EMPTY SET WITH LEFT ARROW ABOVE - "lagran", 0x02112, // SCRIPT CAPITAL L - "Lambda", 0x0039B, // GREEK CAPITAL LETTER LAMDA - "lambda", 0x003BB, // GREEK SMALL LETTER LAMDA - "lang", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "Lang", 0x027EA, // MATHEMATICAL LEFT DOUBLE ANGLE BRACKET - "langd", 0x02991, // LEFT ANGLE BRACKET WITH DOT - "langle", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "lap", 0x02A85, // LESS-THAN OR APPROXIMATE - "Laplacetrf", 0x02112, // SCRIPT CAPITAL L - "laquo", 0x000AB, // LEFT-POINTING DOUBLE ANGLE QUOTATION MARK - "larr", 0x02190, // LEFTWARDS ARROW - "Larr", 0x0219E, // LEFTWARDS TWO HEADED ARROW - "lArr", 0x021D0, // LEFTWARDS DOUBLE ARROW - "larrb", 0x021E4, // LEFTWARDS ARROW TO BAR - "larrbfs", 0x0291F, // LEFTWARDS ARROW FROM BAR TO BLACK DIAMOND - "larrfs", 0x0291D, // LEFTWARDS ARROW TO BLACK DIAMOND - "larrhk", 0x021A9, // LEFTWARDS ARROW WITH HOOK - "larrlp", 0x021AB, // LEFTWARDS ARROW WITH LOOP - "larrpl", 0x02939, // LEFT-SIDE ARC ANTICLOCKWISE ARROW - "larrsim", 0x02973, // LEFTWARDS ARROW ABOVE TILDE OPERATOR - "larrtl", 0x021A2, // LEFTWARDS ARROW WITH TAIL - "lat", 0x02AAB, // LARGER THAN - "latail", 0x02919, // LEFTWARDS ARROW-TAIL - "lAtail", 0x0291B, // LEFTWARDS DOUBLE ARROW-TAIL - "late", 0x02AAD, // LARGER THAN OR EQUAL TO -// "lates", 0x02AAD;0x0FE00, // LARGER THAN OR slanted EQUAL - "lbarr", 0x0290C, // LEFTWARDS DOUBLE DASH ARROW - "lBarr", 0x0290E, // LEFTWARDS TRIPLE DASH ARROW - "lbbrk", 0x02772, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT - "lbrace", 0x0007B, // LEFT CURLY BRACKET - "lbrack", 0x0005B, // LEFT SQUARE BRACKET - "lbrke", 0x0298B, // LEFT SQUARE BRACKET WITH UNDERBAR - "lbrksld", 0x0298F, // LEFT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - "lbrkslu", 0x0298D, // LEFT SQUARE BRACKET WITH TICK IN TOP CORNER - "Lcaron", 0x0013D, // LATIN CAPITAL LETTER L WITH CARON - "lcaron", 0x0013E, // LATIN SMALL LETTER L WITH CARON - "Lcedil", 0x0013B, // LATIN CAPITAL LETTER L WITH CEDILLA - "lcedil", 0x0013C, // LATIN SMALL LETTER L WITH CEDILLA - "lceil", 0x02308, // LEFT CEILING - "lcub", 0x0007B, // LEFT CURLY BRACKET - "Lcy", 0x0041B, // CYRILLIC CAPITAL LETTER EL - "lcy", 0x0043B, // CYRILLIC SMALL LETTER EL - "ldca", 0x02936, // ARROW POINTING DOWNWARDS THEN CURVING LEFTWARDS - "ldquo", 0x0201C, // LEFT DOUBLE QUOTATION MARK - "ldquor", 0x0201E, // DOUBLE LOW-9 QUOTATION MARK - "ldrdhar", 0x02967, // LEFTWARDS HARPOON WITH BARB DOWN ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - "ldrushar", 0x0294B, // LEFT BARB DOWN RIGHT BARB UP HARPOON - "ldsh", 0x021B2, // DOWNWARDS ARROW WITH TIP LEFTWARDS - "le", 0x02264, // LESS-THAN OR EQUAL TO - "lE", 0x02266, // LESS-THAN OVER EQUAL TO - "LeftAngleBracket", 0x027E8, // MATHEMATICAL LEFT ANGLE BRACKET - "leftarrow", 0x02190, // LEFTWARDS ARROW - "LeftArrow", 0x02190, // LEFTWARDS ARROW - "Leftarrow", 0x021D0, // LEFTWARDS DOUBLE ARROW - "LeftArrowBar", 0x021E4, // LEFTWARDS ARROW TO BAR - "LeftArrowRightArrow", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "leftarrowtail", 0x021A2, // LEFTWARDS ARROW WITH TAIL - "LeftCeiling", 0x02308, // LEFT CEILING - "LeftDoubleBracket", 0x027E6, // MATHEMATICAL LEFT WHITE SQUARE BRACKET - "LeftDownTeeVector", 0x02961, // DOWNWARDS HARPOON WITH BARB LEFT FROM BAR - "LeftDownVector", 0x021C3, // DOWNWARDS HARPOON WITH BARB LEFTWARDS - "LeftDownVectorBar", 0x02959, // DOWNWARDS HARPOON WITH BARB LEFT TO BAR - "LeftFloor", 0x0230A, // LEFT FLOOR - "leftharpoondown", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "leftharpoonup", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "leftleftarrows", 0x021C7, // LEFTWARDS PAIRED ARROWS - "leftrightarrow", 0x02194, // LEFT RIGHT ARROW - "LeftRightArrow", 0x02194, // LEFT RIGHT ARROW - "Leftrightarrow", 0x021D4, // LEFT RIGHT DOUBLE ARROW - "leftrightarrows", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "leftrightharpoons", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "leftrightsquigarrow", 0x021AD, // LEFT RIGHT WAVE ARROW - "LeftRightVector", 0x0294E, // LEFT BARB UP RIGHT BARB UP HARPOON - "LeftTee", 0x022A3, // LEFT TACK - "LeftTeeArrow", 0x021A4, // LEFTWARDS ARROW FROM BAR - "LeftTeeVector", 0x0295A, // LEFTWARDS HARPOON WITH BARB UP FROM BAR - "leftthreetimes", 0x022CB, // LEFT SEMIDIRECT PRODUCT - "LeftTriangle", 0x022B2, // NORMAL SUBGROUP OF - "LeftTriangleBar", 0x029CF, // LEFT TRIANGLE BESIDE VERTICAL BAR - "LeftTriangleEqual", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "LeftUpDownVector", 0x02951, // UP BARB LEFT DOWN BARB LEFT HARPOON - "LeftUpTeeVector", 0x02960, // UPWARDS HARPOON WITH BARB LEFT FROM BAR - "LeftUpVector", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "LeftUpVectorBar", 0x02958, // UPWARDS HARPOON WITH BARB LEFT TO BAR - "LeftVector", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "LeftVectorBar", 0x02952, // LEFTWARDS HARPOON WITH BARB UP TO BAR - "leg", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "lEg", 0x02A8B, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - "leq", 0x02264, // LESS-THAN OR EQUAL TO - "leqq", 0x02266, // LESS-THAN OVER EQUAL TO - "leqslant", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "les", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "lescc", 0x02AA8, // LESS-THAN CLOSED BY CURVE ABOVE SLANTED EQUAL - "lesdot", 0x02A7F, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE - "lesdoto", 0x02A81, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE - "lesdotor", 0x02A83, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT -// "lesg", 0x022DA;0x0FE00, // LESS-THAN slanted EQUAL TO OR GREATER-THAN - "lesges", 0x02A93, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL - "lessapprox", 0x02A85, // LESS-THAN OR APPROXIMATE - "lessdot", 0x022D6, // LESS-THAN WITH DOT - "lesseqgtr", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "lesseqqgtr", 0x02A8B, // LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN - "LessEqualGreater", 0x022DA, // LESS-THAN EQUAL TO OR GREATER-THAN - "LessFullEqual", 0x02266, // LESS-THAN OVER EQUAL TO - "LessGreater", 0x02276, // LESS-THAN OR GREATER-THAN - "lessgtr", 0x02276, // LESS-THAN OR GREATER-THAN - "LessLess", 0x02AA1, // DOUBLE NESTED LESS-THAN - "lesssim", 0x02272, // LESS-THAN OR EQUIVALENT TO - "LessSlantEqual", 0x02A7D, // LESS-THAN OR SLANTED EQUAL TO - "LessTilde", 0x02272, // LESS-THAN OR EQUIVALENT TO - "lfisht", 0x0297C, // LEFT FISH TAIL - "lfloor", 0x0230A, // LEFT FLOOR - "Lfr", 0x1D50F, // MATHEMATICAL FRAKTUR CAPITAL L - "lfr", 0x1D529, // MATHEMATICAL FRAKTUR SMALL L - "lg", 0x02276, // LESS-THAN OR GREATER-THAN - "lgE", 0x02A91, // LESS-THAN ABOVE GREATER-THAN ABOVE DOUBLE-LINE EQUAL - "Lgr", 0x0039B, // GREEK CAPITAL LETTER LAMDA - "lgr", 0x003BB, // GREEK SMALL LETTER LAMDA - "lHar", 0x02962, // LEFTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB DOWN - "lhard", 0x021BD, // LEFTWARDS HARPOON WITH BARB DOWNWARDS - "lharu", 0x021BC, // LEFTWARDS HARPOON WITH BARB UPWARDS - "lharul", 0x0296A, // LEFTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - "lhblk", 0x02584, // LOWER HALF BLOCK - "LJcy", 0x00409, // CYRILLIC CAPITAL LETTER LJE - "ljcy", 0x00459, // CYRILLIC SMALL LETTER LJE - "ll", 0x0226A, // MUCH LESS-THAN - "Ll", 0x022D8, // VERY MUCH LESS-THAN - "llarr", 0x021C7, // LEFTWARDS PAIRED ARROWS - "llcorner", 0x0231E, // BOTTOM LEFT CORNER - "Lleftarrow", 0x021DA, // LEFTWARDS TRIPLE ARROW - "llhard", 0x0296B, // LEFTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - "lltri", 0x025FA, // LOWER LEFT TRIANGLE - "Lmidot", 0x0013F, // LATIN CAPITAL LETTER L WITH MIDDLE DOT - "lmidot", 0x00140, // LATIN SMALL LETTER L WITH MIDDLE DOT - "lmoust", 0x023B0, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - "lmoustache", 0x023B0, // UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION - "lnap", 0x02A89, // LESS-THAN AND NOT APPROXIMATE - "lnapprox", 0x02A89, // LESS-THAN AND NOT APPROXIMATE - "lnE", 0x02268, // LESS-THAN BUT NOT EQUAL TO - "lne", 0x02A87, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - "lneq", 0x02A87, // LESS-THAN AND SINGLE-LINE NOT EQUAL TO - "lneqq", 0x02268, // LESS-THAN BUT NOT EQUAL TO - "lnsim", 0x022E6, // LESS-THAN BUT NOT EQUIVALENT TO - "loang", 0x027EC, // MATHEMATICAL LEFT WHITE TORTOISE SHELL BRACKET - "loarr", 0x021FD, // LEFTWARDS OPEN-HEADED ARROW - "lobrk", 0x027E6, // MATHEMATICAL LEFT WHITE SQUARE BRACKET - "longleftarrow", 0x027F5, // LONG LEFTWARDS ARROW - "LongLeftArrow", 0x027F5, // LONG LEFTWARDS ARROW - "Longleftarrow", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "longleftrightarrow", 0x027F7, // LONG LEFT RIGHT ARROW - "LongLeftRightArrow", 0x027F7, // LONG LEFT RIGHT ARROW - "Longleftrightarrow", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "longmapsto", 0x027FC, // LONG RIGHTWARDS ARROW FROM BAR - "longrightarrow", 0x027F6, // LONG RIGHTWARDS ARROW - "LongRightArrow", 0x027F6, // LONG RIGHTWARDS ARROW - "Longrightarrow", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "looparrowleft", 0x021AB, // LEFTWARDS ARROW WITH LOOP - "looparrowright", 0x021AC, // RIGHTWARDS ARROW WITH LOOP - "lopar", 0x02985, // LEFT WHITE PARENTHESIS - "Lopf", 0x1D543, // MATHEMATICAL DOUBLE-STRUCK CAPITAL L - "lopf", 0x1D55D, // MATHEMATICAL DOUBLE-STRUCK SMALL L - "loplus", 0x02A2D, // PLUS SIGN IN LEFT HALF CIRCLE - "lotimes", 0x02A34, // MULTIPLICATION SIGN IN LEFT HALF CIRCLE - "lowast", 0x02217, // ASTERISK OPERATOR - "lowbar", 0x0005F, // LOW LINE - "LowerLeftArrow", 0x02199, // SOUTH WEST ARROW - "LowerRightArrow", 0x02198, // SOUTH EAST ARROW - "loz", 0x025CA, // LOZENGE - "lozenge", 0x025CA, // LOZENGE - "lozf", 0x029EB, // BLACK LOZENGE - "lpar", 0x00028, // LEFT PARENTHESIS - "lparlt", 0x02993, // LEFT ARC LESS-THAN BRACKET - "lrarr", 0x021C6, // LEFTWARDS ARROW OVER RIGHTWARDS ARROW - "lrcorner", 0x0231F, // BOTTOM RIGHT CORNER - "lrhar", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "lrhard", 0x0296D, // RIGHTWARDS HARPOON WITH BARB DOWN BELOW LONG DASH - "lrm", 0x0200E, // LEFT-TO-RIGHT MARK - "lrtri", 0x022BF, // RIGHT TRIANGLE - "lsaquo", 0x02039, // SINGLE LEFT-POINTING ANGLE QUOTATION MARK - "Lscr", 0x02112, // SCRIPT CAPITAL L - "lscr", 0x1D4C1, // MATHEMATICAL SCRIPT SMALL L - "lsh", 0x021B0, // UPWARDS ARROW WITH TIP LEFTWARDS - "Lsh", 0x021B0, // UPWARDS ARROW WITH TIP LEFTWARDS - "lsim", 0x02272, // LESS-THAN OR EQUIVALENT TO - "lsime", 0x02A8D, // LESS-THAN ABOVE SIMILAR OR EQUAL - "lsimg", 0x02A8F, // LESS-THAN ABOVE SIMILAR ABOVE GREATER-THAN - "lsqb", 0x0005B, // LEFT SQUARE BRACKET - "lsquo", 0x02018, // LEFT SINGLE QUOTATION MARK - "lsquor", 0x0201A, // SINGLE LOW-9 QUOTATION MARK - "Lstrok", 0x00141, // LATIN CAPITAL LETTER L WITH STROKE - "lstrok", 0x00142, // LATIN SMALL LETTER L WITH STROKE - "lt", 0x0003C, // LESS-THAN SIGN - "LT", 0x0003C, // LESS-THAN SIGN - "Lt", 0x0226A, // MUCH LESS-THAN - "ltcc", 0x02AA6, // LESS-THAN CLOSED BY CURVE - "ltcir", 0x02A79, // LESS-THAN WITH CIRCLE INSIDE - "ltdot", 0x022D6, // LESS-THAN WITH DOT - "lthree", 0x022CB, // LEFT SEMIDIRECT PRODUCT - "ltimes", 0x022C9, // LEFT NORMAL FACTOR SEMIDIRECT PRODUCT - "ltlarr", 0x02976, // LESS-THAN ABOVE LEFTWARDS ARROW - "ltquest", 0x02A7B, // LESS-THAN WITH QUESTION MARK ABOVE - "ltri", 0x025C3, // WHITE LEFT-POINTING SMALL TRIANGLE - "ltrie", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "ltrif", 0x025C2, // BLACK LEFT-POINTING SMALL TRIANGLE - "ltrPar", 0x02996, // DOUBLE RIGHT ARC LESS-THAN BRACKET - "lurdshar", 0x0294A, // LEFT BARB UP RIGHT BARB DOWN HARPOON - "luruhar", 0x02966, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP -// "lvertneqq", 0x02268;0x0FE00, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke -// "lvnE", 0x02268;0x0FE00, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke - NULL, 0 -}; - -static NameId namesM[]={ - "macr", 0x000AF, // MACRON - "male", 0x02642, // MALE SIGN - "malt", 0x02720, // MALTESE CROSS - "maltese", 0x02720, // MALTESE CROSS - "map", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "Map", 0x02905, // RIGHTWARDS TWO-HEADED ARROW FROM BAR - "mapsto", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "mapstodown", 0x021A7, // DOWNWARDS ARROW FROM BAR - "mapstoleft", 0x021A4, // LEFTWARDS ARROW FROM BAR - "mapstoup", 0x021A5, // UPWARDS ARROW FROM BAR - "marker", 0x025AE, // BLACK VERTICAL RECTANGLE - "mcomma", 0x02A29, // MINUS SIGN WITH COMMA ABOVE - "Mcy", 0x0041C, // CYRILLIC CAPITAL LETTER EM - "mcy", 0x0043C, // CYRILLIC SMALL LETTER EM - "mdash", 0x02014, // EM DASH - "mDDot", 0x0223A, // GEOMETRIC PROPORTION - "measuredangle", 0x02221, // MEASURED ANGLE - "MediumSpace", 0x0205F, // MEDIUM MATHEMATICAL SPACE - "Mellintrf", 0x02133, // SCRIPT CAPITAL M - "Mfr", 0x1D510, // MATHEMATICAL FRAKTUR CAPITAL M - "mfr", 0x1D52A, // MATHEMATICAL FRAKTUR SMALL M - "Mgr", 0x0039C, // GREEK CAPITAL LETTER MU - "mgr", 0x003BC, // GREEK SMALL LETTER MU - "mho", 0x02127, // INVERTED OHM SIGN - "micro", 0x000B5, // MICRO SIGN - "mid", 0x02223, // DIVIDES - "midast", 0x0002A, // ASTERISK - "midcir", 0x02AF0, // VERTICAL LINE WITH CIRCLE BELOW - "middot", 0x000B7, // MIDDLE DOT - "minus", 0x02212, // MINUS SIGN - "minusb", 0x0229F, // SQUARED MINUS - "minusd", 0x02238, // DOT MINUS - "minusdu", 0x02A2A, // MINUS SIGN WITH DOT BELOW - "MinusPlus", 0x02213, // MINUS-OR-PLUS SIGN - "mlcp", 0x02ADB, // TRANSVERSAL INTERSECTION - "mldr", 0x02026, // HORIZONTAL ELLIPSIS - "mnplus", 0x02213, // MINUS-OR-PLUS SIGN - "models", 0x022A7, // MODELS - "Mopf", 0x1D544, // MATHEMATICAL DOUBLE-STRUCK CAPITAL M - "mopf", 0x1D55E, // MATHEMATICAL DOUBLE-STRUCK SMALL M - "mp", 0x02213, // MINUS-OR-PLUS SIGN - "Mscr", 0x02133, // SCRIPT CAPITAL M - "mscr", 0x1D4C2, // MATHEMATICAL SCRIPT SMALL M - "mstpos", 0x0223E, // INVERTED LAZY S - "Mu", 0x0039C, // GREEK CAPITAL LETTER MU - "mu", 0x003BC, // GREEK SMALL LETTER MU - "multimap", 0x022B8, // MULTIMAP - "mumap", 0x022B8, // MULTIMAP - NULL, 0 -}; - -static NameId namesN[]={ - "nabla", 0x02207, // NABLA - "Nacute", 0x00143, // LATIN CAPITAL LETTER N WITH ACUTE - "nacute", 0x00144, // LATIN SMALL LETTER N WITH ACUTE -// "nang", 0x02220;0x020D2, // ANGLE with vertical line - "nap", 0x02249, // NOT ALMOST EQUAL TO -// "napE", 0x02A70;0x00338, // APPROXIMATELY EQUAL OR EQUAL TO with slash -// "napid", 0x0224B;0x00338, // TRIPLE TILDE with slash - "napos", 0x00149, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE - "napprox", 0x02249, // NOT ALMOST EQUAL TO - "natur", 0x0266E, // MUSIC NATURAL SIGN - "natural", 0x0266E, // MUSIC NATURAL SIGN - "naturals", 0x02115, // DOUBLE-STRUCK CAPITAL N - "nbsp", 0x000A0, // NO-BREAK SPACE -// "nbump", 0x0224E;0x00338, // GEOMETRICALLY EQUIVALENT TO with slash -// "nbumpe", 0x0224F;0x00338, // DIFFERENCE BETWEEN with slash - "ncap", 0x02A43, // INTERSECTION WITH OVERBAR - "Ncaron", 0x00147, // LATIN CAPITAL LETTER N WITH CARON - "ncaron", 0x00148, // LATIN SMALL LETTER N WITH CARON - "Ncedil", 0x00145, // LATIN CAPITAL LETTER N WITH CEDILLA - "ncedil", 0x00146, // LATIN SMALL LETTER N WITH CEDILLA - "ncong", 0x02247, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO -// "ncongdot", 0x02A6D;0x00338, // CONGRUENT WITH DOT ABOVE with slash - "ncup", 0x02A42, // UNION WITH OVERBAR - "Ncy", 0x0041D, // CYRILLIC CAPITAL LETTER EN - "ncy", 0x0043D, // CYRILLIC SMALL LETTER EN - "ndash", 0x02013, // EN DASH - "ne", 0x02260, // NOT EQUAL TO - "nearhk", 0x02924, // NORTH EAST ARROW WITH HOOK - "nearr", 0x02197, // NORTH EAST ARROW - "neArr", 0x021D7, // NORTH EAST DOUBLE ARROW - "nearrow", 0x02197, // NORTH EAST ARROW -// "nedot", 0x02250;0x00338, // APPROACHES THE LIMIT with slash - "NegativeMediumSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeThickSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeThinSpace", 0x0200B, // ZERO WIDTH SPACE - "NegativeVeryThinSpace", 0x0200B, // ZERO WIDTH SPACE - "nequiv", 0x02262, // NOT IDENTICAL TO - "nesear", 0x02928, // NORTH EAST ARROW AND SOUTH EAST ARROW -// "nesim", 0x02242;0x00338, // MINUS TILDE with slash - "NestedGreaterGreater", 0x0226B, // MUCH GREATER-THAN - "NestedLessLess", 0x0226A, // MUCH LESS-THAN - "NewLine", 0x0000A, // LINE FEED (LF) - "nexist", 0x02204, // THERE DOES NOT EXIST - "nexists", 0x02204, // THERE DOES NOT EXIST - "Nfr", 0x1D511, // MATHEMATICAL FRAKTUR CAPITAL N - "nfr", 0x1D52B, // MATHEMATICAL FRAKTUR SMALL N -// "ngE", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash - "nge", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO - "ngeq", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO -// "ngeqq", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash -// "ngeqslant", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nges", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nGg", 0x022D9;0x00338, // VERY MUCH GREATER-THAN with slash - "Ngr", 0x0039D, // GREEK CAPITAL LETTER NU - "ngr", 0x003BD, // GREEK SMALL LETTER NU - "ngsim", 0x02275, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "nGt", 0x0226B;0x020D2, // MUCH GREATER THAN with vertical line - "ngt", 0x0226F, // NOT GREATER-THAN - "ngtr", 0x0226F, // NOT GREATER-THAN -// "nGtv", 0x0226B;0x00338, // MUCH GREATER THAN with slash - "nharr", 0x021AE, // LEFT RIGHT ARROW WITH STROKE - "nhArr", 0x021CE, // LEFT RIGHT DOUBLE ARROW WITH STROKE - "nhpar", 0x02AF2, // PARALLEL WITH HORIZONTAL STROKE - "ni", 0x0220B, // CONTAINS AS MEMBER - "nis", 0x022FC, // SMALL CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "nisd", 0x022FA, // CONTAINS WITH LONG HORIZONTAL STROKE - "niv", 0x0220B, // CONTAINS AS MEMBER - "NJcy", 0x0040A, // CYRILLIC CAPITAL LETTER NJE - "njcy", 0x0045A, // CYRILLIC SMALL LETTER NJE - "nlarr", 0x0219A, // LEFTWARDS ARROW WITH STROKE - "nlArr", 0x021CD, // LEFTWARDS DOUBLE ARROW WITH STROKE - "nldr", 0x02025, // TWO DOT LEADER -// "nlE", 0x02266;0x00338, // LESS-THAN OVER EQUAL TO with slash - "nle", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO - "nleftarrow", 0x0219A, // LEFTWARDS ARROW WITH STROKE - "nLeftarrow", 0x021CD, // LEFTWARDS DOUBLE ARROW WITH STROKE - "nleftrightarrow", 0x021AE, // LEFT RIGHT ARROW WITH STROKE - "nLeftrightarrow", 0x021CE, // LEFT RIGHT DOUBLE ARROW WITH STROKE - "nleq", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO -// "nleqq", 0x02266;0x00338, // LESS-THAN OVER EQUAL TO with slash -// "nleqslant", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash -// "nles", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash - "nless", 0x0226E, // NOT LESS-THAN -// "nLl", 0x022D8;0x00338, // VERY MUCH LESS-THAN with slash - "nlsim", 0x02274, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "nLt", 0x0226A;0x020D2, // MUCH LESS THAN with vertical line - "nlt", 0x0226E, // NOT LESS-THAN - "nltri", 0x022EA, // NOT NORMAL SUBGROUP OF - "nltrie", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO -// "nLtv", 0x0226A;0x00338, // MUCH LESS THAN with slash - "nmid", 0x02224, // DOES NOT DIVIDE - "NoBreak", 0x02060, // WORD JOINER - "NonBreakingSpace", 0x000A0, // NO-BREAK SPACE - "Nopf", 0x02115, // DOUBLE-STRUCK CAPITAL N - "nopf", 0x1D55F, // MATHEMATICAL DOUBLE-STRUCK SMALL N - "not", 0x000AC, // NOT SIGN - "Not", 0x02AEC, // DOUBLE STROKE NOT SIGN - "NotCongruent", 0x02262, // NOT IDENTICAL TO - "NotCupCap", 0x0226D, // NOT EQUIVALENT TO - "NotDoubleVerticalBar", 0x02226, // NOT PARALLEL TO - "NotElement", 0x02209, // NOT AN ELEMENT OF - "NotEqual", 0x02260, // NOT EQUAL TO -// "NotEqualTilde", 0x02242;0x00338, // MINUS TILDE with slash - "NotExists", 0x02204, // THERE DOES NOT EXIST - "NotGreater", 0x0226F, // NOT GREATER-THAN - "NotGreaterEqual", 0x02271, // NEITHER GREATER-THAN NOR EQUAL TO -// "NotGreaterFullEqual", 0x02267;0x00338, // GREATER-THAN OVER EQUAL TO with slash -// "NotGreaterGreater", 0x0226B;0x00338, // MUCH GREATER THAN with slash - "NotGreaterLess", 0x02279, // NEITHER GREATER-THAN NOR LESS-THAN -// "NotGreaterSlantEqual", 0x02A7E;0x00338, // GREATER-THAN OR SLANTED EQUAL TO with slash - "NotGreaterTilde", 0x02275, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "NotHumpDownHump", 0x0224E;0x00338, // GEOMETRICALLY EQUIVALENT TO with slash -// "NotHumpEqual", 0x0224F;0x00338, // DIFFERENCE BETWEEN with slash - "notin", 0x02209, // NOT AN ELEMENT OF -// "notindot", 0x022F5;0x00338, // ELEMENT OF WITH DOT ABOVE with slash -// "notinE", 0x022F9;0x00338, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash - "notinva", 0x02209, // NOT AN ELEMENT OF - "notinvb", 0x022F7, // SMALL ELEMENT OF WITH OVERBAR - "notinvc", 0x022F6, // ELEMENT OF WITH OVERBAR - "NotLeftTriangle", 0x022EA, // NOT NORMAL SUBGROUP OF -// "NotLeftTriangleBar", 0x029CF;0x00338, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash - "NotLeftTriangleEqual", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO - "NotLess", 0x0226E, // NOT LESS-THAN - "NotLessEqual", 0x02270, // NEITHER LESS-THAN NOR EQUAL TO - "NotLessGreater", 0x02278, // NEITHER LESS-THAN NOR GREATER-THAN -// "NotLessLess", 0x0226A;0x00338, // MUCH LESS THAN with slash -// "NotLessSlantEqual", 0x02A7D;0x00338, // LESS-THAN OR SLANTED EQUAL TO with slash - "NotLessTilde", 0x02274, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "NotNestedGreaterGreater", 0x02AA2;0x00338, // DOUBLE NESTED GREATER-THAN with slash -// "NotNestedLessLess", 0x02AA1;0x00338, // DOUBLE NESTED LESS-THAN with slash - "notni", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "notniva", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "notnivb", 0x022FE, // SMALL CONTAINS WITH OVERBAR - "notnivc", 0x022FD, // CONTAINS WITH OVERBAR - "NotPrecedes", 0x02280, // DOES NOT PRECEDE -// "NotPrecedesEqual", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "NotPrecedesSlantEqual", 0x022E0, // DOES NOT PRECEDE OR EQUAL - "NotReverseElement", 0x0220C, // DOES NOT CONTAIN AS MEMBER - "NotRightTriangle", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP -// "NotRightTriangleBar", 0x029D0;0x00338, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash - "NotRightTriangleEqual", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL -// "NotSquareSubset", 0x0228F;0x00338, // SQUARE IMAGE OF with slash - "NotSquareSubsetEqual", 0x022E2, // NOT SQUARE IMAGE OF OR EQUAL TO -// "NotSquareSuperset", 0x02290;0x00338, // SQUARE ORIGINAL OF with slash - "NotSquareSupersetEqual", 0x022E3, // NOT SQUARE ORIGINAL OF OR EQUAL TO -// "NotSubset", 0x02282;0x020D2, // SUBSET OF with vertical line - "NotSubsetEqual", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO - "NotSucceeds", 0x02281, // DOES NOT SUCCEED -// "NotSucceedsEqual", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "NotSucceedsSlantEqual", 0x022E1, // DOES NOT SUCCEED OR EQUAL -// "NotSucceedsTilde", 0x0227F;0x00338, // SUCCEEDS OR EQUIVALENT TO with slash -// "NotSuperset", 0x02283;0x020D2, // SUPERSET OF with vertical line - "NotSupersetEqual", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO - "NotTilde", 0x02241, // NOT TILDE - "NotTildeEqual", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "NotTildeFullEqual", 0x02247, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO - "NotTildeTilde", 0x02249, // NOT ALMOST EQUAL TO - "NotVerticalBar", 0x02224, // DOES NOT DIVIDE - "npar", 0x02226, // NOT PARALLEL TO - "nparallel", 0x02226, // NOT PARALLEL TO -// "nparsl", 0x02AFD;0x020E5, // DOUBLE SOLIDUS OPERATOR with reverse slash -// "npart", 0x02202;0x00338, // PARTIAL DIFFERENTIAL with slash - "npolint", 0x02A14, // LINE INTEGRATION NOT INCLUDING THE POLE - "npr", 0x02280, // DOES NOT PRECEDE - "nprcue", 0x022E0, // DOES NOT PRECEDE OR EQUAL -// "npre", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "nprec", 0x02280, // DOES NOT PRECEDE -// "npreceq", 0x02AAF;0x00338, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash - "nrarr", 0x0219B, // RIGHTWARDS ARROW WITH STROKE - "nrArr", 0x021CF, // RIGHTWARDS DOUBLE ARROW WITH STROKE -// "nrarrc", 0x02933;0x00338, // WAVE ARROW POINTING DIRECTLY RIGHT with slash -// "nrarrw", 0x0219D;0x00338, // RIGHTWARDS WAVE ARROW with slash - "nrightarrow", 0x0219B, // RIGHTWARDS ARROW WITH STROKE - "nRightarrow", 0x021CF, // RIGHTWARDS DOUBLE ARROW WITH STROKE - "nrtri", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP - "nrtrie", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - "nsc", 0x02281, // DOES NOT SUCCEED - "nsccue", 0x022E1, // DOES NOT SUCCEED OR EQUAL -// "nsce", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "Nscr", 0x1D4A9, // MATHEMATICAL SCRIPT CAPITAL N - "nscr", 0x1D4C3, // MATHEMATICAL SCRIPT SMALL N - "nshortmid", 0x02224, // DOES NOT DIVIDE - "nshortparallel", 0x02226, // NOT PARALLEL TO - "nsim", 0x02241, // NOT TILDE - "nsime", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "nsimeq", 0x02244, // NOT ASYMPTOTICALLY EQUAL TO - "nsmid", 0x02224, // DOES NOT DIVIDE - "nspar", 0x02226, // NOT PARALLEL TO - "nsqsube", 0x022E2, // NOT SQUARE IMAGE OF OR EQUAL TO - "nsqsupe", 0x022E3, // NOT SQUARE ORIGINAL OF OR EQUAL TO - "nsub", 0x02284, // NOT A SUBSET OF - "nsube", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubE", 0x02AC5;0x00338, // SUBSET OF ABOVE EQUALS SIGN with slash -// "nsubset", 0x02282;0x020D2, // SUBSET OF with vertical line - "nsubseteq", 0x02288, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubseteqq", 0x02AC5;0x00338, // SUBSET OF ABOVE EQUALS SIGN with slash - "nsucc", 0x02281, // DOES NOT SUCCEED -// "nsucceq", 0x02AB0;0x00338, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash - "nsup", 0x02285, // NOT A SUPERSET OF - "nsupe", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupE", 0x02AC6;0x00338, // SUPERSET OF ABOVE EQUALS SIGN with slash -// "nsupset", 0x02283;0x020D2, // SUPERSET OF with vertical line - "nsupseteq", 0x02289, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupseteqq", 0x02AC6;0x00338, // SUPERSET OF ABOVE EQUALS SIGN with slash - "ntgl", 0x02279, // NEITHER GREATER-THAN NOR LESS-THAN - "Ntilde", 0x000D1, // LATIN CAPITAL LETTER N WITH TILDE - "ntilde", 0x000F1, // LATIN SMALL LETTER N WITH TILDE - "ntlg", 0x02278, // NEITHER LESS-THAN NOR GREATER-THAN - "ntriangleleft", 0x022EA, // NOT NORMAL SUBGROUP OF - "ntrianglelefteq", 0x022EC, // NOT NORMAL SUBGROUP OF OR EQUAL TO - "ntriangleright", 0x022EB, // DOES NOT CONTAIN AS NORMAL SUBGROUP - "ntrianglerighteq", 0x022ED, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL - "Nu", 0x0039D, // GREEK CAPITAL LETTER NU - "nu", 0x003BD, // GREEK SMALL LETTER NU - "num", 0x00023, // NUMBER SIGN - "numero", 0x02116, // NUMERO SIGN - "numsp", 0x02007, // FIGURE SPACE -// "nvap", 0x0224D;0x020D2, // EQUIVALENT TO with vertical line - "nvdash", 0x022AC, // DOES NOT PROVE - "nvDash", 0x022AD, // NOT TRUE - "nVdash", 0x022AE, // DOES NOT FORCE - "nVDash", 0x022AF, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE -// "nvge", 0x02265;0x020D2, // GREATER-THAN OR EQUAL TO with vertical line -// "nvgt", 0x0003E;0x020D2, // GREATER-THAN SIGN with vertical line - "nvHarr", 0x02904, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE - "nvinfin", 0x029DE, // INFINITY NEGATED WITH VERTICAL BAR - "nvlArr", 0x02902, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvle", 0x02264;0x020D2, // LESS-THAN OR EQUAL TO with vertical line -// "nvlt", 0x0003C;0x020D2, // LESS-THAN SIGN with vertical line -// "nvltrie", 0x022B4;0x020D2, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line - "nvrArr", 0x02903, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvrtrie", 0x022B5;0x020D2, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line -// "nvsim", 0x0223C;0x020D2, // TILDE OPERATOR with vertical line - "nwarhk", 0x02923, // NORTH WEST ARROW WITH HOOK - "nwarr", 0x02196, // NORTH WEST ARROW - "nwArr", 0x021D6, // NORTH WEST DOUBLE ARROW - "nwarrow", 0x02196, // NORTH WEST ARROW - "nwnear", 0x02927, // NORTH WEST ARROW AND NORTH EAST ARROW - NULL, 0 -}; - -static NameId namesO[]={ - "Oacgr", 0x0038C, // GREEK CAPITAL LETTER OMICRON WITH TONOS - "oacgr", 0x003CC, // GREEK SMALL LETTER OMICRON WITH TONOS - "Oacute", 0x000D3, // LATIN CAPITAL LETTER O WITH ACUTE - "oacute", 0x000F3, // LATIN SMALL LETTER O WITH ACUTE - "oast", 0x0229B, // CIRCLED ASTERISK OPERATOR - "ocir", 0x0229A, // CIRCLED RING OPERATOR - "Ocirc", 0x000D4, // LATIN CAPITAL LETTER O WITH CIRCUMFLEX - "ocirc", 0x000F4, // LATIN SMALL LETTER O WITH CIRCUMFLEX - "Ocy", 0x0041E, // CYRILLIC CAPITAL LETTER O - "ocy", 0x0043E, // CYRILLIC SMALL LETTER O - "odash", 0x0229D, // CIRCLED DASH - "Odblac", 0x00150, // LATIN CAPITAL LETTER O WITH DOUBLE ACUTE - "odblac", 0x00151, // LATIN SMALL LETTER O WITH DOUBLE ACUTE - "odiv", 0x02A38, // CIRCLED DIVISION SIGN - "odot", 0x02299, // CIRCLED DOT OPERATOR - "odsold", 0x029BC, // CIRCLED ANTICLOCKWISE-ROTATED DIVISION SIGN - "OElig", 0x00152, // LATIN CAPITAL LIGATURE OE - "oelig", 0x00153, // LATIN SMALL LIGATURE OE - "ofcir", 0x029BF, // CIRCLED BULLET - "Ofr", 0x1D512, // MATHEMATICAL FRAKTUR CAPITAL O - "ofr", 0x1D52C, // MATHEMATICAL FRAKTUR SMALL O - "ogon", 0x002DB, // OGONEK - "Ogr", 0x0039F, // GREEK CAPITAL LETTER OMICRON - "ogr", 0x003BF, // GREEK SMALL LETTER OMICRON - "Ograve", 0x000D2, // LATIN CAPITAL LETTER O WITH GRAVE - "ograve", 0x000F2, // LATIN SMALL LETTER O WITH GRAVE - "ogt", 0x029C1, // CIRCLED GREATER-THAN - "OHacgr", 0x0038F, // GREEK CAPITAL LETTER OMEGA WITH TONOS - "ohacgr", 0x003CE, // GREEK SMALL LETTER OMEGA WITH TONOS - "ohbar", 0x029B5, // CIRCLE WITH HORIZONTAL BAR - "OHgr", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "ohgr", 0x003C9, // GREEK SMALL LETTER OMEGA - "ohm", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "oint", 0x0222E, // CONTOUR INTEGRAL - "olarr", 0x021BA, // ANTICLOCKWISE OPEN CIRCLE ARROW - "olcir", 0x029BE, // CIRCLED WHITE BULLET - "olcross", 0x029BB, // CIRCLE WITH SUPERIMPOSED X - "oline", 0x0203E, // OVERLINE - "olt", 0x029C0, // CIRCLED LESS-THAN - "Omacr", 0x0014C, // LATIN CAPITAL LETTER O WITH MACRON - "omacr", 0x0014D, // LATIN SMALL LETTER O WITH MACRON - "Omega", 0x003A9, // GREEK CAPITAL LETTER OMEGA - "omega", 0x003C9, // GREEK SMALL LETTER OMEGA - "Omicron", 0x0039F, // GREEK CAPITAL LETTER OMICRON - "omicron", 0x003BF, // GREEK SMALL LETTER OMICRON - "omid", 0x029B6, // CIRCLED VERTICAL BAR - "ominus", 0x02296, // CIRCLED MINUS - "Oopf", 0x1D546, // MATHEMATICAL DOUBLE-STRUCK CAPITAL O - "oopf", 0x1D560, // MATHEMATICAL DOUBLE-STRUCK SMALL O - "opar", 0x029B7, // CIRCLED PARALLEL - "OpenCurlyDoubleQuote", 0x0201C, // LEFT DOUBLE QUOTATION MARK - "OpenCurlyQuote", 0x02018, // LEFT SINGLE QUOTATION MARK - "operp", 0x029B9, // CIRCLED PERPENDICULAR - "oplus", 0x02295, // CIRCLED PLUS - "or", 0x02228, // LOGICAL OR - "Or", 0x02A54, // DOUBLE LOGICAL OR - "orarr", 0x021BB, // CLOCKWISE OPEN CIRCLE ARROW - "ord", 0x02A5D, // LOGICAL OR WITH HORIZONTAL DASH - "order", 0x02134, // SCRIPT SMALL O - "orderof", 0x02134, // SCRIPT SMALL O - "ordf", 0x000AA, // FEMININE ORDINAL INDICATOR - "ordm", 0x000BA, // MASCULINE ORDINAL INDICATOR - "origof", 0x022B6, // ORIGINAL OF - "oror", 0x02A56, // TWO INTERSECTING LOGICAL OR - "orslope", 0x02A57, // SLOPING LARGE OR - "orv", 0x02A5B, // LOGICAL OR WITH MIDDLE STEM - "oS", 0x024C8, // CIRCLED LATIN CAPITAL LETTER S - "oscr", 0x02134, // SCRIPT SMALL O - "Oscr", 0x1D4AA, // MATHEMATICAL SCRIPT CAPITAL O - "Oslash", 0x000D8, // LATIN CAPITAL LETTER O WITH STROKE - "oslash", 0x000F8, // LATIN SMALL LETTER O WITH STROKE - "osol", 0x02298, // CIRCLED DIVISION SLASH - "Otilde", 0x000D5, // LATIN CAPITAL LETTER O WITH TILDE - "otilde", 0x000F5, // LATIN SMALL LETTER O WITH TILDE - "otimes", 0x02297, // CIRCLED TIMES - "Otimes", 0x02A37, // MULTIPLICATION SIGN IN DOUBLE CIRCLE - "otimesas", 0x02A36, // CIRCLED MULTIPLICATION SIGN WITH CIRCUMFLEX ACCENT - "Ouml", 0x000D6, // LATIN CAPITAL LETTER O WITH DIAERESIS - "ouml", 0x000F6, // LATIN SMALL LETTER O WITH DIAERESIS - "ovbar", 0x0233D, // APL FUNCTIONAL SYMBOL CIRCLE STILE - "OverBar", 0x0203E, // OVERLINE - "OverBrace", 0x023DE, // TOP CURLY BRACKET - "OverBracket", 0x023B4, // TOP SQUARE BRACKET - "OverParenthesis", 0x023DC, // TOP PARENTHESIS - NULL, 0 -}; - -static NameId namesP[]={ - "par", 0x02225, // PARALLEL TO - "para", 0x000B6, // PILCROW SIGN - "parallel", 0x02225, // PARALLEL TO - "parsim", 0x02AF3, // PARALLEL WITH TILDE OPERATOR - "parsl", 0x02AFD, // DOUBLE SOLIDUS OPERATOR - "part", 0x02202, // PARTIAL DIFFERENTIAL - "PartialD", 0x02202, // PARTIAL DIFFERENTIAL - "Pcy", 0x0041F, // CYRILLIC CAPITAL LETTER PE - "pcy", 0x0043F, // CYRILLIC SMALL LETTER PE - "percnt", 0x00025, // PERCENT SIGN - "period", 0x0002E, // FULL STOP - "permil", 0x02030, // PER MILLE SIGN - "perp", 0x022A5, // UP TACK - "pertenk", 0x02031, // PER TEN THOUSAND SIGN - "Pfr", 0x1D513, // MATHEMATICAL FRAKTUR CAPITAL P - "pfr", 0x1D52D, // MATHEMATICAL FRAKTUR SMALL P - "Pgr", 0x003A0, // GREEK CAPITAL LETTER PI - "pgr", 0x003C0, // GREEK SMALL LETTER PI - "PHgr", 0x003A6, // GREEK CAPITAL LETTER PHI - "phgr", 0x003C6, // GREEK SMALL LETTER PHI - "Phi", 0x003A6, // GREEK CAPITAL LETTER PHI - "phi", 0x003C6, // GREEK SMALL LETTER PHI - "phiv", 0x003D5, // GREEK PHI SYMBOL - "phmmat", 0x02133, // SCRIPT CAPITAL M - "phone", 0x0260E, // BLACK TELEPHONE - "Pi", 0x003A0, // GREEK CAPITAL LETTER PI - "pi", 0x003C0, // GREEK SMALL LETTER PI - "pitchfork", 0x022D4, // PITCHFORK - "piv", 0x003D6, // GREEK PI SYMBOL - "planck", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "planckh", 0x0210E, // PLANCK CONSTANT - "plankv", 0x0210F, // PLANCK CONSTANT OVER TWO PI - "plus", 0x0002B, // PLUS SIGN - "plusacir", 0x02A23, // PLUS SIGN WITH CIRCUMFLEX ACCENT ABOVE - "plusb", 0x0229E, // SQUARED PLUS - "pluscir", 0x02A22, // PLUS SIGN WITH SMALL CIRCLE ABOVE - "plusdo", 0x02214, // DOT PLUS - "plusdu", 0x02A25, // PLUS SIGN WITH DOT BELOW - "pluse", 0x02A72, // PLUS SIGN ABOVE EQUALS SIGN - "PlusMinus", 0x000B1, // PLUS-MINUS SIGN - "plusmn", 0x000B1, // PLUS-MINUS SIGN - "plussim", 0x02A26, // PLUS SIGN WITH TILDE BELOW - "plustwo", 0x02A27, // PLUS SIGN WITH SUBSCRIPT TWO - "pm", 0x000B1, // PLUS-MINUS SIGN - "Poincareplane", 0x0210C, // BLACK-LETTER CAPITAL H - "pointint", 0x02A15, // INTEGRAL AROUND A POINT OPERATOR - "Popf", 0x02119, // DOUBLE-STRUCK CAPITAL P - "popf", 0x1D561, // MATHEMATICAL DOUBLE-STRUCK SMALL P - "pound", 0x000A3, // POUND SIGN - "pr", 0x0227A, // PRECEDES - "Pr", 0x02ABB, // DOUBLE PRECEDES - "prap", 0x02AB7, // PRECEDES ABOVE ALMOST EQUAL TO - "prcue", 0x0227C, // PRECEDES OR EQUAL TO - "pre", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "prE", 0x02AB3, // PRECEDES ABOVE EQUALS SIGN - "prec", 0x0227A, // PRECEDES - "precapprox", 0x02AB7, // PRECEDES ABOVE ALMOST EQUAL TO - "preccurlyeq", 0x0227C, // PRECEDES OR EQUAL TO - "Precedes", 0x0227A, // PRECEDES - "PrecedesEqual", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "PrecedesSlantEqual", 0x0227C, // PRECEDES OR EQUAL TO - "PrecedesTilde", 0x0227E, // PRECEDES OR EQUIVALENT TO - "preceq", 0x02AAF, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN - "precnapprox", 0x02AB9, // PRECEDES ABOVE NOT ALMOST EQUAL TO - "precneqq", 0x02AB5, // PRECEDES ABOVE NOT EQUAL TO - "precnsim", 0x022E8, // PRECEDES BUT NOT EQUIVALENT TO - "precsim", 0x0227E, // PRECEDES OR EQUIVALENT TO - "prime", 0x02032, // PRIME - "Prime", 0x02033, // DOUBLE PRIME - "primes", 0x02119, // DOUBLE-STRUCK CAPITAL P - "prnap", 0x02AB9, // PRECEDES ABOVE NOT ALMOST EQUAL TO - "prnE", 0x02AB5, // PRECEDES ABOVE NOT EQUAL TO - "prnsim", 0x022E8, // PRECEDES BUT NOT EQUIVALENT TO - "prod", 0x0220F, // N-ARY PRODUCT - "Product", 0x0220F, // N-ARY PRODUCT - "profalar", 0x0232E, // ALL AROUND-PROFILE - "profline", 0x02312, // ARC - "profsurf", 0x02313, // SEGMENT - "prop", 0x0221D, // PROPORTIONAL TO - "Proportion", 0x02237, // PROPORTION - "Proportional", 0x0221D, // PROPORTIONAL TO - "propto", 0x0221D, // PROPORTIONAL TO - "prsim", 0x0227E, // PRECEDES OR EQUIVALENT TO - "prurel", 0x022B0, // PRECEDES UNDER RELATION - "Pscr", 0x1D4AB, // MATHEMATICAL SCRIPT CAPITAL P - "pscr", 0x1D4C5, // MATHEMATICAL SCRIPT SMALL P - "PSgr", 0x003A8, // GREEK CAPITAL LETTER PSI - "psgr", 0x003C8, // GREEK SMALL LETTER PSI - "Psi", 0x003A8, // GREEK CAPITAL LETTER PSI - "psi", 0x003C8, // GREEK SMALL LETTER PSI - "puncsp", 0x02008, // PUNCTUATION SPACE - NULL, 0 -}; - -static NameId namesQ[]={ - "Qfr", 0x1D514, // MATHEMATICAL FRAKTUR CAPITAL Q - "qfr", 0x1D52E, // MATHEMATICAL FRAKTUR SMALL Q - "qint", 0x02A0C, // QUADRUPLE INTEGRAL OPERATOR - "Qopf", 0x0211A, // DOUBLE-STRUCK CAPITAL Q - "qopf", 0x1D562, // MATHEMATICAL DOUBLE-STRUCK SMALL Q - "qprime", 0x02057, // QUADRUPLE PRIME - "Qscr", 0x1D4AC, // MATHEMATICAL SCRIPT CAPITAL Q - "qscr", 0x1D4C6, // MATHEMATICAL SCRIPT SMALL Q - "quaternions", 0x0210D, // DOUBLE-STRUCK CAPITAL H - "quatint", 0x02A16, // QUATERNION INTEGRAL OPERATOR - "quest", 0x0003F, // QUESTION MARK - "questeq", 0x0225F, // QUESTIONED EQUAL TO - "quot", 0x00022, // QUOTATION MARK - "QUOT", 0x00022, // QUOTATION MARK - NULL, 0 -}; - -static NameId namesR[]={ - "rAarr", 0x021DB, // RIGHTWARDS TRIPLE ARROW -// "race", 0x0223D;0x00331, // REVERSED TILDE with underline - "Racute", 0x00154, // LATIN CAPITAL LETTER R WITH ACUTE - "racute", 0x00155, // LATIN SMALL LETTER R WITH ACUTE - "radic", 0x0221A, // SQUARE ROOT - "raemptyv", 0x029B3, // EMPTY SET WITH RIGHT ARROW ABOVE - "rang", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "Rang", 0x027EB, // MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET - "rangd", 0x02992, // RIGHT ANGLE BRACKET WITH DOT - "range", 0x029A5, // REVERSED ANGLE WITH UNDERBAR - "rangle", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "raquo", 0x000BB, // RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK - "rarr", 0x02192, // RIGHTWARDS ARROW - "Rarr", 0x021A0, // RIGHTWARDS TWO HEADED ARROW - "rArr", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "rarrap", 0x02975, // RIGHTWARDS ARROW ABOVE ALMOST EQUAL TO - "rarrb", 0x021E5, // RIGHTWARDS ARROW TO BAR - "rarrbfs", 0x02920, // RIGHTWARDS ARROW FROM BAR TO BLACK DIAMOND - "rarrc", 0x02933, // WAVE ARROW POINTING DIRECTLY RIGHT - "rarrfs", 0x0291E, // RIGHTWARDS ARROW TO BLACK DIAMOND - "rarrhk", 0x021AA, // RIGHTWARDS ARROW WITH HOOK - "rarrlp", 0x021AC, // RIGHTWARDS ARROW WITH LOOP - "rarrpl", 0x02945, // RIGHTWARDS ARROW WITH PLUS BELOW - "rarrsim", 0x02974, // RIGHTWARDS ARROW ABOVE TILDE OPERATOR - "rarrtl", 0x021A3, // RIGHTWARDS ARROW WITH TAIL - "Rarrtl", 0x02916, // RIGHTWARDS TWO-HEADED ARROW WITH TAIL - "rarrw", 0x0219D, // RIGHTWARDS WAVE ARROW - "ratail", 0x0291A, // RIGHTWARDS ARROW-TAIL - "rAtail", 0x0291C, // RIGHTWARDS DOUBLE ARROW-TAIL - "ratio", 0x02236, // RATIO - "rationals", 0x0211A, // DOUBLE-STRUCK CAPITAL Q - "rbarr", 0x0290D, // RIGHTWARDS DOUBLE DASH ARROW - "rBarr", 0x0290F, // RIGHTWARDS TRIPLE DASH ARROW - "RBarr", 0x02910, // RIGHTWARDS TWO-HEADED TRIPLE DASH ARROW - "rbbrk", 0x02773, // LIGHT RIGHT TORTOISE SHELL BRACKET ORNAMENT - "rbrace", 0x0007D, // RIGHT CURLY BRACKET - "rbrack", 0x0005D, // RIGHT SQUARE BRACKET - "rbrke", 0x0298C, // RIGHT SQUARE BRACKET WITH UNDERBAR - "rbrksld", 0x0298E, // RIGHT SQUARE BRACKET WITH TICK IN BOTTOM CORNER - "rbrkslu", 0x02990, // RIGHT SQUARE BRACKET WITH TICK IN TOP CORNER - "Rcaron", 0x00158, // LATIN CAPITAL LETTER R WITH CARON - "rcaron", 0x00159, // LATIN SMALL LETTER R WITH CARON - "Rcedil", 0x00156, // LATIN CAPITAL LETTER R WITH CEDILLA - "rcedil", 0x00157, // LATIN SMALL LETTER R WITH CEDILLA - "rceil", 0x02309, // RIGHT CEILING - "rcub", 0x0007D, // RIGHT CURLY BRACKET - "Rcy", 0x00420, // CYRILLIC CAPITAL LETTER ER - "rcy", 0x00440, // CYRILLIC SMALL LETTER ER - "rdca", 0x02937, // ARROW POINTING DOWNWARDS THEN CURVING RIGHTWARDS - "rdldhar", 0x02969, // RIGHTWARDS HARPOON WITH BARB DOWN ABOVE LEFTWARDS HARPOON WITH BARB DOWN - "rdquo", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "rdquor", 0x0201D, // RIGHT DOUBLE QUOTATION MARK - "rdsh", 0x021B3, // DOWNWARDS ARROW WITH TIP RIGHTWARDS - "Re", 0x0211C, // BLACK-LETTER CAPITAL R - "real", 0x0211C, // BLACK-LETTER CAPITAL R - "realine", 0x0211B, // SCRIPT CAPITAL R - "realpart", 0x0211C, // BLACK-LETTER CAPITAL R - "reals", 0x0211D, // DOUBLE-STRUCK CAPITAL R - "rect", 0x025AD, // WHITE RECTANGLE - "reg", 0x000AE, // REGISTERED SIGN - "REG", 0x000AE, // REGISTERED SIGN - "ReverseElement", 0x0220B, // CONTAINS AS MEMBER - "ReverseEquilibrium", 0x021CB, // LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON - "ReverseUpEquilibrium", 0x0296F, // DOWNWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "rfisht", 0x0297D, // RIGHT FISH TAIL - "rfloor", 0x0230B, // RIGHT FLOOR - "Rfr", 0x0211C, // BLACK-LETTER CAPITAL R - "rfr", 0x1D52F, // MATHEMATICAL FRAKTUR SMALL R - "Rgr", 0x003A1, // GREEK CAPITAL LETTER RHO - "rgr", 0x003C1, // GREEK SMALL LETTER RHO - "rHar", 0x02964, // RIGHTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB DOWN - "rhard", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "rharu", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "rharul", 0x0296C, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LONG DASH - "Rho", 0x003A1, // GREEK CAPITAL LETTER RHO - "rho", 0x003C1, // GREEK SMALL LETTER RHO - "rhov", 0x003F1, // GREEK RHO SYMBOL - "RightAngleBracket", 0x027E9, // MATHEMATICAL RIGHT ANGLE BRACKET - "rightarrow", 0x02192, // RIGHTWARDS ARROW - "RightArrow", 0x02192, // RIGHTWARDS ARROW - "Rightarrow", 0x021D2, // RIGHTWARDS DOUBLE ARROW - "RightArrowBar", 0x021E5, // RIGHTWARDS ARROW TO BAR - "RightArrowLeftArrow", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rightarrowtail", 0x021A3, // RIGHTWARDS ARROW WITH TAIL - "RightCeiling", 0x02309, // RIGHT CEILING - "RightDoubleBracket", 0x027E7, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - "RightDownTeeVector", 0x0295D, // DOWNWARDS HARPOON WITH BARB RIGHT FROM BAR - "RightDownVector", 0x021C2, // DOWNWARDS HARPOON WITH BARB RIGHTWARDS - "RightDownVectorBar", 0x02955, // DOWNWARDS HARPOON WITH BARB RIGHT TO BAR - "RightFloor", 0x0230B, // RIGHT FLOOR - "rightharpoondown", 0x021C1, // RIGHTWARDS HARPOON WITH BARB DOWNWARDS - "rightharpoonup", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "rightleftarrows", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rightleftharpoons", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "rightrightarrows", 0x021C9, // RIGHTWARDS PAIRED ARROWS - "rightsquigarrow", 0x0219D, // RIGHTWARDS WAVE ARROW - "RightTee", 0x022A2, // RIGHT TACK - "RightTeeArrow", 0x021A6, // RIGHTWARDS ARROW FROM BAR - "RightTeeVector", 0x0295B, // RIGHTWARDS HARPOON WITH BARB UP FROM BAR - "rightthreetimes", 0x022CC, // RIGHT SEMIDIRECT PRODUCT - "RightTriangle", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "RightTriangleBar", 0x029D0, // VERTICAL BAR BESIDE RIGHT TRIANGLE - "RightTriangleEqual", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "RightUpDownVector", 0x0294F, // UP BARB RIGHT DOWN BARB RIGHT HARPOON - "RightUpTeeVector", 0x0295C, // UPWARDS HARPOON WITH BARB RIGHT FROM BAR - "RightUpVector", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "RightUpVectorBar", 0x02954, // UPWARDS HARPOON WITH BARB RIGHT TO BAR - "RightVector", 0x021C0, // RIGHTWARDS HARPOON WITH BARB UPWARDS - "RightVectorBar", 0x02953, // RIGHTWARDS HARPOON WITH BARB UP TO BAR - "ring", 0x002DA, // RING ABOVE - "risingdotseq", 0x02253, // IMAGE OF OR APPROXIMATELY EQUAL TO - "rlarr", 0x021C4, // RIGHTWARDS ARROW OVER LEFTWARDS ARROW - "rlhar", 0x021CC, // RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON - "rlm", 0x0200F, // RIGHT-TO-LEFT MARK - "rmoust", 0x023B1, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - "rmoustache", 0x023B1, // UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION - "rnmid", 0x02AEE, // DOES NOT DIVIDE WITH REVERSED NEGATION SLASH - "roang", 0x027ED, // MATHEMATICAL RIGHT WHITE TORTOISE SHELL BRACKET - "roarr", 0x021FE, // RIGHTWARDS OPEN-HEADED ARROW - "robrk", 0x027E7, // MATHEMATICAL RIGHT WHITE SQUARE BRACKET - "ropar", 0x02986, // RIGHT WHITE PARENTHESIS - "Ropf", 0x0211D, // DOUBLE-STRUCK CAPITAL R - "ropf", 0x1D563, // MATHEMATICAL DOUBLE-STRUCK SMALL R - "roplus", 0x02A2E, // PLUS SIGN IN RIGHT HALF CIRCLE - "rotimes", 0x02A35, // MULTIPLICATION SIGN IN RIGHT HALF CIRCLE - "RoundImplies", 0x02970, // RIGHT DOUBLE ARROW WITH ROUNDED HEAD - "rpar", 0x00029, // RIGHT PARENTHESIS - "rpargt", 0x02994, // RIGHT ARC GREATER-THAN BRACKET - "rppolint", 0x02A12, // LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE - "rrarr", 0x021C9, // RIGHTWARDS PAIRED ARROWS - "Rrightarrow", 0x021DB, // RIGHTWARDS TRIPLE ARROW - "rsaquo", 0x0203A, // SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - "Rscr", 0x0211B, // SCRIPT CAPITAL R - "rscr", 0x1D4C7, // MATHEMATICAL SCRIPT SMALL R - "rsh", 0x021B1, // UPWARDS ARROW WITH TIP RIGHTWARDS - "Rsh", 0x021B1, // UPWARDS ARROW WITH TIP RIGHTWARDS - "rsqb", 0x0005D, // RIGHT SQUARE BRACKET - "rsquo", 0x02019, // RIGHT SINGLE QUOTATION MARK - "rsquor", 0x02019, // RIGHT SINGLE QUOTATION MARK - "rthree", 0x022CC, // RIGHT SEMIDIRECT PRODUCT - "rtimes", 0x022CA, // RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT - "rtri", 0x025B9, // WHITE RIGHT-POINTING SMALL TRIANGLE - "rtrie", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "rtrif", 0x025B8, // BLACK RIGHT-POINTING SMALL TRIANGLE - "rtriltri", 0x029CE, // RIGHT TRIANGLE ABOVE LEFT TRIANGLE - "RuleDelayed", 0x029F4, // RULE-DELAYED - "ruluhar", 0x02968, // RIGHTWARDS HARPOON WITH BARB UP ABOVE LEFTWARDS HARPOON WITH BARB UP - "rx", 0x0211E, // PRESCRIPTION TAKE - NULL, 0 -}; - -static NameId namesS[]={ - "Sacute", 0x0015A, // LATIN CAPITAL LETTER S WITH ACUTE - "sacute", 0x0015B, // LATIN SMALL LETTER S WITH ACUTE - "sbquo", 0x0201A, // SINGLE LOW-9 QUOTATION MARK - "sc", 0x0227B, // SUCCEEDS - "Sc", 0x02ABC, // DOUBLE SUCCEEDS - "scap", 0x02AB8, // SUCCEEDS ABOVE ALMOST EQUAL TO - "Scaron", 0x00160, // LATIN CAPITAL LETTER S WITH CARON - "scaron", 0x00161, // LATIN SMALL LETTER S WITH CARON - "sccue", 0x0227D, // SUCCEEDS OR EQUAL TO - "sce", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "scE", 0x02AB4, // SUCCEEDS ABOVE EQUALS SIGN - "Scedil", 0x0015E, // LATIN CAPITAL LETTER S WITH CEDILLA - "scedil", 0x0015F, // LATIN SMALL LETTER S WITH CEDILLA - "Scirc", 0x0015C, // LATIN CAPITAL LETTER S WITH CIRCUMFLEX - "scirc", 0x0015D, // LATIN SMALL LETTER S WITH CIRCUMFLEX - "scnap", 0x02ABA, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - "scnE", 0x02AB6, // SUCCEEDS ABOVE NOT EQUAL TO - "scnsim", 0x022E9, // SUCCEEDS BUT NOT EQUIVALENT TO - "scpolint", 0x02A13, // LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE - "scsim", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "Scy", 0x00421, // CYRILLIC CAPITAL LETTER ES - "scy", 0x00441, // CYRILLIC SMALL LETTER ES - "sdot", 0x022C5, // DOT OPERATOR - "sdotb", 0x022A1, // SQUARED DOT OPERATOR - "sdote", 0x02A66, // EQUALS SIGN WITH DOT BELOW - "searhk", 0x02925, // SOUTH EAST ARROW WITH HOOK - "searr", 0x02198, // SOUTH EAST ARROW - "seArr", 0x021D8, // SOUTH EAST DOUBLE ARROW - "searrow", 0x02198, // SOUTH EAST ARROW - "sect", 0x000A7, // SECTION SIGN - "semi", 0x0003B, // SEMICOLON - "seswar", 0x02929, // SOUTH EAST ARROW AND SOUTH WEST ARROW - "setminus", 0x02216, // SET MINUS - "setmn", 0x02216, // SET MINUS - "sext", 0x02736, // SIX POINTED BLACK STAR - "sfgr", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "Sfr", 0x1D516, // MATHEMATICAL FRAKTUR CAPITAL S - "sfr", 0x1D530, // MATHEMATICAL FRAKTUR SMALL S - "sfrown", 0x02322, // FROWN - "Sgr", 0x003A3, // GREEK CAPITAL LETTER SIGMA - "sgr", 0x003C3, // GREEK SMALL LETTER SIGMA - "sharp", 0x0266F, // MUSIC SHARP SIGN - "SHCHcy", 0x00429, // CYRILLIC CAPITAL LETTER SHCHA - "shchcy", 0x00449, // CYRILLIC SMALL LETTER SHCHA - "SHcy", 0x00428, // CYRILLIC CAPITAL LETTER SHA - "shcy", 0x00448, // CYRILLIC SMALL LETTER SHA - "ShortDownArrow", 0x02193, // DOWNWARDS ARROW - "ShortLeftArrow", 0x02190, // LEFTWARDS ARROW - "shortmid", 0x02223, // DIVIDES - "shortparallel", 0x02225, // PARALLEL TO - "ShortRightArrow", 0x02192, // RIGHTWARDS ARROW - "ShortUpArrow", 0x02191, // UPWARDS ARROW - "shy", 0x000AD, // SOFT HYPHEN - "Sigma", 0x003A3, // GREEK CAPITAL LETTER SIGMA - "sigma", 0x003C3, // GREEK SMALL LETTER SIGMA - "sigmaf", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "sigmav", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA - "sim", 0x0223C, // TILDE OPERATOR - "simdot", 0x02A6A, // TILDE OPERATOR WITH DOT ABOVE - "sime", 0x02243, // ASYMPTOTICALLY EQUAL TO - "simeq", 0x02243, // ASYMPTOTICALLY EQUAL TO - "simg", 0x02A9E, // SIMILAR OR GREATER-THAN - "simgE", 0x02AA0, // SIMILAR ABOVE GREATER-THAN ABOVE EQUALS SIGN - "siml", 0x02A9D, // SIMILAR OR LESS-THAN - "simlE", 0x02A9F, // SIMILAR ABOVE LESS-THAN ABOVE EQUALS SIGN - "simne", 0x02246, // APPROXIMATELY BUT NOT ACTUALLY EQUAL TO - "simplus", 0x02A24, // PLUS SIGN WITH TILDE ABOVE - "simrarr", 0x02972, // TILDE OPERATOR ABOVE RIGHTWARDS ARROW - "slarr", 0x02190, // LEFTWARDS ARROW - "SmallCircle", 0x02218, // RING OPERATOR - "smallsetminus", 0x02216, // SET MINUS - "smashp", 0x02A33, // SMASH PRODUCT - "smeparsl", 0x029E4, // EQUALS SIGN AND SLANTED PARALLEL WITH TILDE ABOVE - "smid", 0x02223, // DIVIDES - "smile", 0x02323, // SMILE - "smt", 0x02AAA, // SMALLER THAN - "smte", 0x02AAC, // SMALLER THAN OR EQUAL TO -// "smtes", 0x02AAC;0x0FE00, // SMALLER THAN OR slanted EQUAL - "SOFTcy", 0x0042C, // CYRILLIC CAPITAL LETTER SOFT SIGN - "softcy", 0x0044C, // CYRILLIC SMALL LETTER SOFT SIGN - "sol", 0x0002F, // SOLIDUS - "solb", 0x029C4, // SQUARED RISING DIAGONAL SLASH - "solbar", 0x0233F, // APL FUNCTIONAL SYMBOL SLASH BAR - "Sopf", 0x1D54A, // MATHEMATICAL DOUBLE-STRUCK CAPITAL S - "sopf", 0x1D564, // MATHEMATICAL DOUBLE-STRUCK SMALL S - "spades", 0x02660, // BLACK SPADE SUIT - "spadesuit", 0x02660, // BLACK SPADE SUIT - "spar", 0x02225, // PARALLEL TO - "sqcap", 0x02293, // SQUARE CAP -// "sqcaps", 0x02293;0x0FE00, // SQUARE CAP with serifs - "sqcup", 0x02294, // SQUARE CUP -// "sqcups", 0x02294;0x0FE00, // SQUARE CUP with serifs - "Sqrt", 0x0221A, // SQUARE ROOT - "sqsub", 0x0228F, // SQUARE IMAGE OF - "sqsube", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "sqsubset", 0x0228F, // SQUARE IMAGE OF - "sqsubseteq", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "sqsup", 0x02290, // SQUARE ORIGINAL OF - "sqsupe", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "sqsupset", 0x02290, // SQUARE ORIGINAL OF - "sqsupseteq", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "squ", 0x025A1, // WHITE SQUARE - "square", 0x025A1, // WHITE SQUARE - "Square", 0x025A1, // WHITE SQUARE - "SquareIntersection", 0x02293, // SQUARE CAP - "SquareSubset", 0x0228F, // SQUARE IMAGE OF - "SquareSubsetEqual", 0x02291, // SQUARE IMAGE OF OR EQUAL TO - "SquareSuperset", 0x02290, // SQUARE ORIGINAL OF - "SquareSupersetEqual", 0x02292, // SQUARE ORIGINAL OF OR EQUAL TO - "SquareUnion", 0x02294, // SQUARE CUP - "squarf", 0x025AA, // BLACK SMALL SQUARE - "squf", 0x025AA, // BLACK SMALL SQUARE - "srarr", 0x02192, // RIGHTWARDS ARROW - "Sscr", 0x1D4AE, // MATHEMATICAL SCRIPT CAPITAL S - "sscr", 0x1D4C8, // MATHEMATICAL SCRIPT SMALL S - "ssetmn", 0x02216, // SET MINUS - "ssmile", 0x02323, // SMILE - "sstarf", 0x022C6, // STAR OPERATOR - "Star", 0x022C6, // STAR OPERATOR - "star", 0x02606, // WHITE STAR - "starf", 0x02605, // BLACK STAR - "straightepsilon", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "straightphi", 0x003D5, // GREEK PHI SYMBOL - "strns", 0x000AF, // MACRON - "sub", 0x02282, // SUBSET OF - "Sub", 0x022D0, // DOUBLE SUBSET - "subdot", 0x02ABD, // SUBSET WITH DOT - "sube", 0x02286, // SUBSET OF OR EQUAL TO - "subE", 0x02AC5, // SUBSET OF ABOVE EQUALS SIGN - "subedot", 0x02AC3, // SUBSET OF OR EQUAL TO WITH DOT ABOVE - "submult", 0x02AC1, // SUBSET WITH MULTIPLICATION SIGN BELOW - "subne", 0x0228A, // SUBSET OF WITH NOT EQUAL TO - "subnE", 0x02ACB, // SUBSET OF ABOVE NOT EQUAL TO - "subplus", 0x02ABF, // SUBSET WITH PLUS SIGN BELOW - "subrarr", 0x02979, // SUBSET ABOVE RIGHTWARDS ARROW - "subset", 0x02282, // SUBSET OF - "Subset", 0x022D0, // DOUBLE SUBSET - "subseteq", 0x02286, // SUBSET OF OR EQUAL TO - "subseteqq", 0x02AC5, // SUBSET OF ABOVE EQUALS SIGN - "SubsetEqual", 0x02286, // SUBSET OF OR EQUAL TO - "subsetneq", 0x0228A, // SUBSET OF WITH NOT EQUAL TO - "subsetneqq", 0x02ACB, // SUBSET OF ABOVE NOT EQUAL TO - "subsim", 0x02AC7, // SUBSET OF ABOVE TILDE OPERATOR - "subsub", 0x02AD5, // SUBSET ABOVE SUBSET - "subsup", 0x02AD3, // SUBSET ABOVE SUPERSET - "succ", 0x0227B, // SUCCEEDS - "succapprox", 0x02AB8, // SUCCEEDS ABOVE ALMOST EQUAL TO - "succcurlyeq", 0x0227D, // SUCCEEDS OR EQUAL TO - "Succeeds", 0x0227B, // SUCCEEDS - "SucceedsEqual", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "SucceedsSlantEqual", 0x0227D, // SUCCEEDS OR EQUAL TO - "SucceedsTilde", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "succeq", 0x02AB0, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN - "succnapprox", 0x02ABA, // SUCCEEDS ABOVE NOT ALMOST EQUAL TO - "succneqq", 0x02AB6, // SUCCEEDS ABOVE NOT EQUAL TO - "succnsim", 0x022E9, // SUCCEEDS BUT NOT EQUIVALENT TO - "succsim", 0x0227F, // SUCCEEDS OR EQUIVALENT TO - "SuchThat", 0x0220B, // CONTAINS AS MEMBER - "sum", 0x02211, // N-ARY SUMMATION - "Sum", 0x02211, // N-ARY SUMMATION - "sung", 0x0266A, // EIGHTH NOTE - "sup", 0x02283, // SUPERSET OF - "Sup", 0x022D1, // DOUBLE SUPERSET - "sup1", 0x000B9, // SUPERSCRIPT ONE - "sup2", 0x000B2, // SUPERSCRIPT TWO - "sup3", 0x000B3, // SUPERSCRIPT THREE - "supdot", 0x02ABE, // SUPERSET WITH DOT - "supdsub", 0x02AD8, // SUPERSET BESIDE AND JOINED BY DASH WITH SUBSET - "supe", 0x02287, // SUPERSET OF OR EQUAL TO - "supE", 0x02AC6, // SUPERSET OF ABOVE EQUALS SIGN - "supedot", 0x02AC4, // SUPERSET OF OR EQUAL TO WITH DOT ABOVE - "Superset", 0x02283, // SUPERSET OF - "SupersetEqual", 0x02287, // SUPERSET OF OR EQUAL TO - "suphsol", 0x027C9, // SUPERSET PRECEDING SOLIDUS - "suphsub", 0x02AD7, // SUPERSET BESIDE SUBSET - "suplarr", 0x0297B, // SUPERSET ABOVE LEFTWARDS ARROW - "supmult", 0x02AC2, // SUPERSET WITH MULTIPLICATION SIGN BELOW - "supne", 0x0228B, // SUPERSET OF WITH NOT EQUAL TO - "supnE", 0x02ACC, // SUPERSET OF ABOVE NOT EQUAL TO - "supplus", 0x02AC0, // SUPERSET WITH PLUS SIGN BELOW - "supset", 0x02283, // SUPERSET OF - "Supset", 0x022D1, // DOUBLE SUPERSET - "supseteq", 0x02287, // SUPERSET OF OR EQUAL TO - "supseteqq", 0x02AC6, // SUPERSET OF ABOVE EQUALS SIGN - "supsetneq", 0x0228B, // SUPERSET OF WITH NOT EQUAL TO - "supsetneqq", 0x02ACC, // SUPERSET OF ABOVE NOT EQUAL TO - "supsim", 0x02AC8, // SUPERSET OF ABOVE TILDE OPERATOR - "supsub", 0x02AD4, // SUPERSET ABOVE SUBSET - "supsup", 0x02AD6, // SUPERSET ABOVE SUPERSET - "swarhk", 0x02926, // SOUTH WEST ARROW WITH HOOK - "swarr", 0x02199, // SOUTH WEST ARROW - "swArr", 0x021D9, // SOUTH WEST DOUBLE ARROW - "swarrow", 0x02199, // SOUTH WEST ARROW - "swnwar", 0x0292A, // SOUTH WEST ARROW AND NORTH WEST ARROW - "szlig", 0x000DF, // LATIN SMALL LETTER SHARP S - NULL, 0 -}; - -static NameId namesT[]={ - "Tab", 0x00009, // CHARACTER TABULATION - "target", 0x02316, // POSITION INDICATOR - "Tau", 0x003A4, // GREEK CAPITAL LETTER TAU - "tau", 0x003C4, // GREEK SMALL LETTER TAU - "tbrk", 0x023B4, // TOP SQUARE BRACKET - "Tcaron", 0x00164, // LATIN CAPITAL LETTER T WITH CARON - "tcaron", 0x00165, // LATIN SMALL LETTER T WITH CARON - "Tcedil", 0x00162, // LATIN CAPITAL LETTER T WITH CEDILLA - "tcedil", 0x00163, // LATIN SMALL LETTER T WITH CEDILLA - "Tcy", 0x00422, // CYRILLIC CAPITAL LETTER TE - "tcy", 0x00442, // CYRILLIC SMALL LETTER TE - "tdot", 0x020DB, // COMBINING THREE DOTS ABOVE - "telrec", 0x02315, // TELEPHONE RECORDER - "Tfr", 0x1D517, // MATHEMATICAL FRAKTUR CAPITAL T - "tfr", 0x1D531, // MATHEMATICAL FRAKTUR SMALL T - "Tgr", 0x003A4, // GREEK CAPITAL LETTER TAU - "tgr", 0x003C4, // GREEK SMALL LETTER TAU - "there4", 0x02234, // THEREFORE - "therefore", 0x02234, // THEREFORE - "Therefore", 0x02234, // THEREFORE - "Theta", 0x00398, // GREEK CAPITAL LETTER THETA - "theta", 0x003B8, // GREEK SMALL LETTER THETA - "thetasym", 0x003D1, // GREEK THETA SYMBOL - "thetav", 0x003D1, // GREEK THETA SYMBOL - "THgr", 0x00398, // GREEK CAPITAL LETTER THETA - "thgr", 0x003B8, // GREEK SMALL LETTER THETA - "thickapprox", 0x02248, // ALMOST EQUAL TO - "thicksim", 0x0223C, // TILDE OPERATOR -// "ThickSpace", 0x0205F;0x0200A, // space of width 5/18 em - "thinsp", 0x02009, // THIN SPACE - "ThinSpace", 0x02009, // THIN SPACE - "thkap", 0x02248, // ALMOST EQUAL TO - "thksim", 0x0223C, // TILDE OPERATOR - "THORN", 0x000DE, // LATIN CAPITAL LETTER THORN - "thorn", 0x000FE, // LATIN SMALL LETTER THORN - "tilde", 0x002DC, // SMALL TILDE - "Tilde", 0x0223C, // TILDE OPERATOR - "TildeEqual", 0x02243, // ASYMPTOTICALLY EQUAL TO - "TildeFullEqual", 0x02245, // APPROXIMATELY EQUAL TO - "TildeTilde", 0x02248, // ALMOST EQUAL TO - "times", 0x000D7, // MULTIPLICATION SIGN - "timesb", 0x022A0, // SQUARED TIMES - "timesbar", 0x02A31, // MULTIPLICATION SIGN WITH UNDERBAR - "timesd", 0x02A30, // MULTIPLICATION SIGN WITH DOT ABOVE - "tint", 0x0222D, // TRIPLE INTEGRAL - "toea", 0x02928, // NORTH EAST ARROW AND SOUTH EAST ARROW - "top", 0x022A4, // DOWN TACK - "topbot", 0x02336, // APL FUNCTIONAL SYMBOL I-BEAM - "topcir", 0x02AF1, // DOWN TACK WITH CIRCLE BELOW - "Topf", 0x1D54B, // MATHEMATICAL DOUBLE-STRUCK CAPITAL T - "topf", 0x1D565, // MATHEMATICAL DOUBLE-STRUCK SMALL T - "topfork", 0x02ADA, // PITCHFORK WITH TEE TOP - "tosa", 0x02929, // SOUTH EAST ARROW AND SOUTH WEST ARROW - "tprime", 0x02034, // TRIPLE PRIME - "trade", 0x02122, // TRADE MARK SIGN - "TRADE", 0x02122, // TRADE MARK SIGN - "triangle", 0x025B5, // WHITE UP-POINTING SMALL TRIANGLE - "triangledown", 0x025BF, // WHITE DOWN-POINTING SMALL TRIANGLE - "triangleleft", 0x025C3, // WHITE LEFT-POINTING SMALL TRIANGLE - "trianglelefteq", 0x022B4, // NORMAL SUBGROUP OF OR EQUAL TO - "triangleq", 0x0225C, // DELTA EQUAL TO - "triangleright", 0x025B9, // WHITE RIGHT-POINTING SMALL TRIANGLE - "trianglerighteq", 0x022B5, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO - "tridot", 0x025EC, // WHITE UP-POINTING TRIANGLE WITH DOT - "trie", 0x0225C, // DELTA EQUAL TO - "triminus", 0x02A3A, // MINUS SIGN IN TRIANGLE - "TripleDot", 0x020DB, // COMBINING THREE DOTS ABOVE - "triplus", 0x02A39, // PLUS SIGN IN TRIANGLE - "trisb", 0x029CD, // TRIANGLE WITH SERIFS AT BOTTOM - "tritime", 0x02A3B, // MULTIPLICATION SIGN IN TRIANGLE - "trpezium", 0x023E2, // WHITE TRAPEZIUM - "Tscr", 0x1D4AF, // MATHEMATICAL SCRIPT CAPITAL T - "tscr", 0x1D4C9, // MATHEMATICAL SCRIPT SMALL T - "TScy", 0x00426, // CYRILLIC CAPITAL LETTER TSE - "tscy", 0x00446, // CYRILLIC SMALL LETTER TSE - "TSHcy", 0x0040B, // CYRILLIC CAPITAL LETTER TSHE - "tshcy", 0x0045B, // CYRILLIC SMALL LETTER TSHE - "Tstrok", 0x00166, // LATIN CAPITAL LETTER T WITH STROKE - "tstrok", 0x00167, // LATIN SMALL LETTER T WITH STROKE - "twixt", 0x0226C, // BETWEEN - "twoheadleftarrow", 0x0219E, // LEFTWARDS TWO HEADED ARROW - "twoheadrightarrow", 0x021A0, // RIGHTWARDS TWO HEADED ARROW - NULL, 0 -}; - -static NameId namesU[]={ - "Uacgr", 0x0038E, // GREEK CAPITAL LETTER UPSILON WITH TONOS - "uacgr", 0x003CD, // GREEK SMALL LETTER UPSILON WITH TONOS - "Uacute", 0x000DA, // LATIN CAPITAL LETTER U WITH ACUTE - "uacute", 0x000FA, // LATIN SMALL LETTER U WITH ACUTE - "uarr", 0x02191, // UPWARDS ARROW - "Uarr", 0x0219F, // UPWARDS TWO HEADED ARROW - "uArr", 0x021D1, // UPWARDS DOUBLE ARROW - "Uarrocir", 0x02949, // UPWARDS TWO-HEADED ARROW FROM SMALL CIRCLE - "Ubrcy", 0x0040E, // CYRILLIC CAPITAL LETTER SHORT U - "ubrcy", 0x0045E, // CYRILLIC SMALL LETTER SHORT U - "Ubreve", 0x0016C, // LATIN CAPITAL LETTER U WITH BREVE - "ubreve", 0x0016D, // LATIN SMALL LETTER U WITH BREVE - "Ucirc", 0x000DB, // LATIN CAPITAL LETTER U WITH CIRCUMFLEX - "ucirc", 0x000FB, // LATIN SMALL LETTER U WITH CIRCUMFLEX - "Ucy", 0x00423, // CYRILLIC CAPITAL LETTER U - "ucy", 0x00443, // CYRILLIC SMALL LETTER U - "udarr", 0x021C5, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - "Udblac", 0x00170, // LATIN CAPITAL LETTER U WITH DOUBLE ACUTE - "udblac", 0x00171, // LATIN SMALL LETTER U WITH DOUBLE ACUTE - "udhar", 0x0296E, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "udiagr", 0x003B0, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS - "Udigr", 0x003AB, // GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA - "udigr", 0x003CB, // GREEK SMALL LETTER UPSILON WITH DIALYTIKA - "ufisht", 0x0297E, // UP FISH TAIL - "Ufr", 0x1D518, // MATHEMATICAL FRAKTUR CAPITAL U - "ufr", 0x1D532, // MATHEMATICAL FRAKTUR SMALL U - "Ugr", 0x003A5, // GREEK CAPITAL LETTER UPSILON - "ugr", 0x003C5, // GREEK SMALL LETTER UPSILON - "Ugrave", 0x000D9, // LATIN CAPITAL LETTER U WITH GRAVE - "ugrave", 0x000F9, // LATIN SMALL LETTER U WITH GRAVE - "uHar", 0x02963, // UPWARDS HARPOON WITH BARB LEFT BESIDE UPWARDS HARPOON WITH BARB RIGHT - "uharl", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "uharr", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "uhblk", 0x02580, // UPPER HALF BLOCK - "ulcorn", 0x0231C, // TOP LEFT CORNER - "ulcorner", 0x0231C, // TOP LEFT CORNER - "ulcrop", 0x0230F, // TOP LEFT CROP - "ultri", 0x025F8, // UPPER LEFT TRIANGLE - "Umacr", 0x0016A, // LATIN CAPITAL LETTER U WITH MACRON - "umacr", 0x0016B, // LATIN SMALL LETTER U WITH MACRON - "uml", 0x000A8, // DIAERESIS - "UnderBar", 0x0005F, // LOW LINE - "UnderBrace", 0x023DF, // BOTTOM CURLY BRACKET - "UnderBracket", 0x023B5, // BOTTOM SQUARE BRACKET - "UnderParenthesis", 0x023DD, // BOTTOM PARENTHESIS - "Union", 0x022C3, // N-ARY UNION - "UnionPlus", 0x0228E, // MULTISET UNION - "Uogon", 0x00172, // LATIN CAPITAL LETTER U WITH OGONEK - "uogon", 0x00173, // LATIN SMALL LETTER U WITH OGONEK - "Uopf", 0x1D54C, // MATHEMATICAL DOUBLE-STRUCK CAPITAL U - "uopf", 0x1D566, // MATHEMATICAL DOUBLE-STRUCK SMALL U - "uparrow", 0x02191, // UPWARDS ARROW - "UpArrow", 0x02191, // UPWARDS ARROW - "Uparrow", 0x021D1, // UPWARDS DOUBLE ARROW - "UpArrowBar", 0x02912, // UPWARDS ARROW TO BAR - "UpArrowDownArrow", 0x021C5, // UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW - "updownarrow", 0x02195, // UP DOWN ARROW - "UpDownArrow", 0x02195, // UP DOWN ARROW - "Updownarrow", 0x021D5, // UP DOWN DOUBLE ARROW - "UpEquilibrium", 0x0296E, // UPWARDS HARPOON WITH BARB LEFT BESIDE DOWNWARDS HARPOON WITH BARB RIGHT - "upharpoonleft", 0x021BF, // UPWARDS HARPOON WITH BARB LEFTWARDS - "upharpoonright", 0x021BE, // UPWARDS HARPOON WITH BARB RIGHTWARDS - "uplus", 0x0228E, // MULTISET UNION - "UpperLeftArrow", 0x02196, // NORTH WEST ARROW - "UpperRightArrow", 0x02197, // NORTH EAST ARROW - "upsi", 0x003C5, // GREEK SMALL LETTER UPSILON - "Upsi", 0x003D2, // GREEK UPSILON WITH HOOK SYMBOL - "upsih", 0x003D2, // GREEK UPSILON WITH HOOK SYMBOL - "Upsilon", 0x003A5, // GREEK CAPITAL LETTER UPSILON - "upsilon", 0x003C5, // GREEK SMALL LETTER UPSILON - "UpTee", 0x022A5, // UP TACK - "UpTeeArrow", 0x021A5, // UPWARDS ARROW FROM BAR - "upuparrows", 0x021C8, // UPWARDS PAIRED ARROWS - "urcorn", 0x0231D, // TOP RIGHT CORNER - "urcorner", 0x0231D, // TOP RIGHT CORNER - "urcrop", 0x0230E, // TOP RIGHT CROP - "Uring", 0x0016E, // LATIN CAPITAL LETTER U WITH RING ABOVE - "uring", 0x0016F, // LATIN SMALL LETTER U WITH RING ABOVE - "urtri", 0x025F9, // UPPER RIGHT TRIANGLE - "Uscr", 0x1D4B0, // MATHEMATICAL SCRIPT CAPITAL U - "uscr", 0x1D4CA, // MATHEMATICAL SCRIPT SMALL U - "utdot", 0x022F0, // UP RIGHT DIAGONAL ELLIPSIS - "Utilde", 0x00168, // LATIN CAPITAL LETTER U WITH TILDE - "utilde", 0x00169, // LATIN SMALL LETTER U WITH TILDE - "utri", 0x025B5, // WHITE UP-POINTING SMALL TRIANGLE - "utrif", 0x025B4, // BLACK UP-POINTING SMALL TRIANGLE - "uuarr", 0x021C8, // UPWARDS PAIRED ARROWS - "Uuml", 0x000DC, // LATIN CAPITAL LETTER U WITH DIAERESIS - "uuml", 0x000FC, // LATIN SMALL LETTER U WITH DIAERESIS - "uwangle", 0x029A7, // OBLIQUE ANGLE OPENING DOWN - NULL, 0 -}; - -static NameId namesV[]={ - "vangrt", 0x0299C, // RIGHT ANGLE VARIANT WITH SQUARE - "varepsilon", 0x003F5, // GREEK LUNATE EPSILON SYMBOL - "varkappa", 0x003F0, // GREEK KAPPA SYMBOL - "varnothing", 0x02205, // EMPTY SET - "varphi", 0x003D5, // GREEK PHI SYMBOL - "varpi", 0x003D6, // GREEK PI SYMBOL - "varpropto", 0x0221D, // PROPORTIONAL TO - "varr", 0x02195, // UP DOWN ARROW - "vArr", 0x021D5, // UP DOWN DOUBLE ARROW - "varrho", 0x003F1, // GREEK RHO SYMBOL - "varsigma", 0x003C2, // GREEK SMALL LETTER FINAL SIGMA -// "varsubsetneq", 0x0228A;0x0FE00, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsubsetneqq", 0x02ACB;0x0FE00, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneq", 0x0228B;0x0FE00, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneqq", 0x02ACC;0x0FE00, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - "vartheta", 0x003D1, // GREEK THETA SYMBOL - "vartriangleleft", 0x022B2, // NORMAL SUBGROUP OF - "vartriangleright", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "vBar", 0x02AE8, // SHORT UP TACK WITH UNDERBAR - "Vbar", 0x02AEB, // DOUBLE UP TACK - "vBarv", 0x02AE9, // SHORT UP TACK ABOVE SHORT DOWN TACK - "Vcy", 0x00412, // CYRILLIC CAPITAL LETTER VE - "vcy", 0x00432, // CYRILLIC SMALL LETTER VE - "vdash", 0x022A2, // RIGHT TACK - "vDash", 0x022A8, // TRUE - "Vdash", 0x022A9, // FORCES - "VDash", 0x022AB, // DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE - "Vdashl", 0x02AE6, // LONG DASH FROM LEFT MEMBER OF DOUBLE VERTICAL - "vee", 0x02228, // LOGICAL OR - "Vee", 0x022C1, // N-ARY LOGICAL OR - "veebar", 0x022BB, // XOR - "veeeq", 0x0225A, // EQUIANGULAR TO - "vellip", 0x022EE, // VERTICAL ELLIPSIS - "verbar", 0x0007C, // VERTICAL LINE - "Verbar", 0x02016, // DOUBLE VERTICAL LINE - "vert", 0x0007C, // VERTICAL LINE - "Vert", 0x02016, // DOUBLE VERTICAL LINE - "VerticalBar", 0x02223, // DIVIDES - "VerticalLine", 0x0007C, // VERTICAL LINE - "VerticalSeparator", 0x02758, // LIGHT VERTICAL BAR - "VerticalTilde", 0x02240, // WREATH PRODUCT - "VeryThinSpace", 0x0200A, // HAIR SPACE - "Vfr", 0x1D519, // MATHEMATICAL FRAKTUR CAPITAL V - "vfr", 0x1D533, // MATHEMATICAL FRAKTUR SMALL V - "vltri", 0x022B2, // NORMAL SUBGROUP OF -// "vnsub", 0x02282;0x020D2, // SUBSET OF with vertical line -// "vnsup", 0x02283;0x020D2, // SUPERSET OF with vertical line - "Vopf", 0x1D54D, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V - "vopf", 0x1D567, // MATHEMATICAL DOUBLE-STRUCK SMALL V - "vprop", 0x0221D, // PROPORTIONAL TO - "vrtri", 0x022B3, // CONTAINS AS NORMAL SUBGROUP - "Vscr", 0x1D4B1, // MATHEMATICAL SCRIPT CAPITAL V - "vscr", 0x1D4CB, // MATHEMATICAL SCRIPT SMALL V -// "vsubne", 0x0228A;0x0FE00, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsubnE", 0x02ACB;0x0FE00, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "vsupne", 0x0228B;0x0FE00, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsupnE", 0x02ACC;0x0FE00, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members - "Vvdash", 0x022AA, // TRIPLE VERTICAL BAR RIGHT TURNSTILE - "vzigzag", 0x0299A, // VERTICAL ZIGZAG LINE - NULL, 0 -}; - -static NameId namesW[]={ - "Wcirc", 0x00174, // LATIN CAPITAL LETTER W WITH CIRCUMFLEX - "wcirc", 0x00175, // LATIN SMALL LETTER W WITH CIRCUMFLEX - "wedbar", 0x02A5F, // LOGICAL AND WITH UNDERBAR - "wedge", 0x02227, // LOGICAL AND - "Wedge", 0x022C0, // N-ARY LOGICAL AND - "wedgeq", 0x02259, // ESTIMATES - "weierp", 0x02118, // SCRIPT CAPITAL P - "Wfr", 0x1D51A, // MATHEMATICAL FRAKTUR CAPITAL W - "wfr", 0x1D534, // MATHEMATICAL FRAKTUR SMALL W - "Wopf", 0x1D54E, // MATHEMATICAL DOUBLE-STRUCK CAPITAL W - "wopf", 0x1D568, // MATHEMATICAL DOUBLE-STRUCK SMALL W - "wp", 0x02118, // SCRIPT CAPITAL P - "wr", 0x02240, // WREATH PRODUCT - "wreath", 0x02240, // WREATH PRODUCT - "Wscr", 0x1D4B2, // MATHEMATICAL SCRIPT CAPITAL W - "wscr", 0x1D4CC, // MATHEMATICAL SCRIPT SMALL W - NULL, 0 -}; - -static NameId namesX[]={ - "xcap", 0x022C2, // N-ARY INTERSECTION - "xcirc", 0x025EF, // LARGE CIRCLE - "xcup", 0x022C3, // N-ARY UNION - "xdtri", 0x025BD, // WHITE DOWN-POINTING TRIANGLE - "Xfr", 0x1D51B, // MATHEMATICAL FRAKTUR CAPITAL X - "xfr", 0x1D535, // MATHEMATICAL FRAKTUR SMALL X - "Xgr", 0x0039E, // GREEK CAPITAL LETTER XI - "xgr", 0x003BE, // GREEK SMALL LETTER XI - "xharr", 0x027F7, // LONG LEFT RIGHT ARROW - "xhArr", 0x027FA, // LONG LEFT RIGHT DOUBLE ARROW - "Xi", 0x0039E, // GREEK CAPITAL LETTER XI - "xi", 0x003BE, // GREEK SMALL LETTER XI - "xlarr", 0x027F5, // LONG LEFTWARDS ARROW - "xlArr", 0x027F8, // LONG LEFTWARDS DOUBLE ARROW - "xmap", 0x027FC, // LONG RIGHTWARDS ARROW FROM BAR - "xnis", 0x022FB, // CONTAINS WITH VERTICAL BAR AT END OF HORIZONTAL STROKE - "xodot", 0x02A00, // N-ARY CIRCLED DOT OPERATOR - "Xopf", 0x1D54F, // MATHEMATICAL DOUBLE-STRUCK CAPITAL X - "xopf", 0x1D569, // MATHEMATICAL DOUBLE-STRUCK SMALL X - "xoplus", 0x02A01, // N-ARY CIRCLED PLUS OPERATOR - "xotime", 0x02A02, // N-ARY CIRCLED TIMES OPERATOR - "xrarr", 0x027F6, // LONG RIGHTWARDS ARROW - "xrArr", 0x027F9, // LONG RIGHTWARDS DOUBLE ARROW - "Xscr", 0x1D4B3, // MATHEMATICAL SCRIPT CAPITAL X - "xscr", 0x1D4CD, // MATHEMATICAL SCRIPT SMALL X - "xsqcup", 0x02A06, // N-ARY SQUARE UNION OPERATOR - "xuplus", 0x02A04, // N-ARY UNION OPERATOR WITH PLUS - "xutri", 0x025B3, // WHITE UP-POINTING TRIANGLE - "xvee", 0x022C1, // N-ARY LOGICAL OR - "xwedge", 0x022C0, // N-ARY LOGICAL AND - NULL, 0 -}; - -static NameId namesY[]={ - "Yacute", 0x000DD, // LATIN CAPITAL LETTER Y WITH ACUTE - "yacute", 0x000FD, // LATIN SMALL LETTER Y WITH ACUTE - "YAcy", 0x0042F, // CYRILLIC CAPITAL LETTER YA - "yacy", 0x0044F, // CYRILLIC SMALL LETTER YA - "Ycirc", 0x00176, // LATIN CAPITAL LETTER Y WITH CIRCUMFLEX - "ycirc", 0x00177, // LATIN SMALL LETTER Y WITH CIRCUMFLEX - "Ycy", 0x0042B, // CYRILLIC CAPITAL LETTER YERU - "ycy", 0x0044B, // CYRILLIC SMALL LETTER YERU - "yen", 0x000A5, // YEN SIGN - "Yfr", 0x1D51C, // MATHEMATICAL FRAKTUR CAPITAL Y - "yfr", 0x1D536, // MATHEMATICAL FRAKTUR SMALL Y - "YIcy", 0x00407, // CYRILLIC CAPITAL LETTER YI - "yicy", 0x00457, // CYRILLIC SMALL LETTER YI - "Yopf", 0x1D550, // MATHEMATICAL DOUBLE-STRUCK CAPITAL Y - "yopf", 0x1D56A, // MATHEMATICAL DOUBLE-STRUCK SMALL Y - "Yscr", 0x1D4B4, // MATHEMATICAL SCRIPT CAPITAL Y - "yscr", 0x1D4CE, // MATHEMATICAL SCRIPT SMALL Y - "YUcy", 0x0042E, // CYRILLIC CAPITAL LETTER YU - "yucy", 0x0044E, // CYRILLIC SMALL LETTER YU - "yuml", 0x000FF, // LATIN SMALL LETTER Y WITH DIAERESIS - "Yuml", 0x00178, // LATIN CAPITAL LETTER Y WITH DIAERESIS - NULL, 0 -}; - -static NameId namesZ[]={ - "Zacute", 0x00179, // LATIN CAPITAL LETTER Z WITH ACUTE - "zacute", 0x0017A, // LATIN SMALL LETTER Z WITH ACUTE - "Zcaron", 0x0017D, // LATIN CAPITAL LETTER Z WITH CARON - "zcaron", 0x0017E, // LATIN SMALL LETTER Z WITH CARON - "Zcy", 0x00417, // CYRILLIC CAPITAL LETTER ZE - "zcy", 0x00437, // CYRILLIC SMALL LETTER ZE - "Zdot", 0x0017B, // LATIN CAPITAL LETTER Z WITH DOT ABOVE - "zdot", 0x0017C, // LATIN SMALL LETTER Z WITH DOT ABOVE - "zeetrf", 0x02128, // BLACK-LETTER CAPITAL Z - "ZeroWidthSpace", 0x0200B, // ZERO WIDTH SPACE - "Zeta", 0x00396, // GREEK CAPITAL LETTER ZETA - "zeta", 0x003B6, // GREEK SMALL LETTER ZETA - "Zfr", 0x02128, // BLACK-LETTER CAPITAL Z - "zfr", 0x1D537, // MATHEMATICAL FRAKTUR SMALL Z - "Zgr", 0x00396, // GREEK CAPITAL LETTER ZETA - "zgr", 0x003B6, // GREEK SMALL LETTER ZETA - "ZHcy", 0x00416, // CYRILLIC CAPITAL LETTER ZHE - "zhcy", 0x00436, // CYRILLIC SMALL LETTER ZHE - "zigrarr", 0x021DD, // RIGHTWARDS SQUIGGLE ARROW - "Zopf", 0x02124, // DOUBLE-STRUCK CAPITAL Z - "zopf", 0x1D56B, // MATHEMATICAL DOUBLE-STRUCK SMALL Z - "Zscr", 0x1D4B5, // MATHEMATICAL SCRIPT CAPITAL Z - "zscr", 0x1D4CF, // MATHEMATICAL SCRIPT SMALL Z - "zwj", 0x0200D, // ZERO WIDTH JOINER - "zwnj", 0x0200C, // ZERO WIDTH NON-JOINER - NULL, 0 -}; - -// @todo@ order namesTable and names? by frequency -static NameId* namesTable[] = { - namesA, namesB, namesC, namesD, namesE, namesF, namesG, namesH, namesI, - namesJ, namesK, namesL, namesM, namesN, namesO, namesP, namesQ, namesR, - namesS, namesT, namesU, namesV, namesW, namesX, namesY, namesZ, NULL -}; - -int HtmlNamedEntity(unsigned char *p, int length) -{ - int tableIndex = tolower(*p) - 'a'; - if (tableIndex >= 0 && tableIndex < 26) - { - NameId* names = namesTable[tableIndex]; - int i; - - for (i = 0; names[i].name; i++) - { - if (strncmp(names[i].name, (char *)p, length) == 0) - return names[i].value; - } - } - return -1; -} - diff --git a/dmd2/enum.c b/dmd2/enum.c deleted file mode 100644 index a92e9ef9..00000000 --- a/dmd2/enum.c +++ /dev/null @@ -1,427 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "enum.h" -#include "mtype.h" -#include "scope.h" -#include "id.h" -#include "expression.h" -#include "module.h" -#include "declaration.h" - -/********************************* EnumDeclaration ****************************/ - -EnumDeclaration::EnumDeclaration(Loc loc, Identifier *id, Type *memtype) - : ScopeDsymbol(id) -{ - this->loc = loc; - type = new TypeEnum(this); - this->memtype = memtype; - maxval = NULL; - minval = NULL; - defaultval = NULL; -#if IN_DMD - sinit = NULL; -#endif - isdeprecated = 0; - isdone = 0; -} - -Dsymbol *EnumDeclaration::syntaxCopy(Dsymbol *s) -{ - Type *t = NULL; - if (memtype) - t = memtype->syntaxCopy(); - - EnumDeclaration *ed; - if (s) - { ed = (EnumDeclaration *)s; - ed->memtype = t; - } - else - ed = new EnumDeclaration(loc, ident, t); - ScopeDsymbol::syntaxCopy(ed); - return ed; -} - -void EnumDeclaration::semantic0(Scope *sc) -{ - /* This function is a hack to get around a significant problem. - * The members of anonymous enums, like: - * enum { A, B, C } - * don't get installed into the symbol table until after they are - * semantically analyzed, yet they're supposed to go into the enclosing - * scope's table. Hence, when forward referenced, they come out as - * 'undefined'. The real fix is to add them in at addSymbol() time. - * But to get code to compile, we'll just do this quick hack at the moment - * to compile it if it doesn't depend on anything else. - */ - - if (isdone || !scope) - return; - if (!isAnonymous() || memtype) - return; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - if (em && (em->type || em->value)) - return; - } - - // Can do it - semantic(sc); -} - -void EnumDeclaration::semantic(Scope *sc) -{ - Type *t; - Scope *sce; - - //printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc->scopesym, sc->scopesym->toChars(), toChars()); - //printf("EnumDeclaration::semantic() %s\n", toChars()); - if (!members) // enum ident; - return; - - if (!memtype && !isAnonymous()) - { // Set memtype if we can to reduce fwd reference errors - memtype = Type::tint32; // case 1) enum ident { ... } - } - - if (symtab) // if already done - { if (isdone || !scope) - return; // semantic() already completed - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - unsigned dprogress_save = Module::dprogress; - - if (sc->stc & STCdeprecated) - isdeprecated = 1; - - parent = sc->parent; - - /* The separate, and distinct, cases are: - * 1. enum { ... } - * 2. enum : memtype { ... } - * 3. enum ident { ... } - * 4. enum ident : memtype { ... } - */ - - if (memtype) - { - memtype = memtype->semantic(loc, sc); - - /* Check to see if memtype is forward referenced - */ - if (memtype->ty == Tenum) - { EnumDeclaration *sym = (EnumDeclaration *)memtype->toDsymbol(sc); - if (!sym->memtype || !sym->members || !sym->symtab || sym->scope) - { // memtype is forward referenced, so try again later - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - Module::dprogress = dprogress_save; - //printf("\tdeferring %s\n", toChars()); - return; - } - } -#if 0 // Decided to abandon this restriction for D 2.0 - if (!memtype->isintegral()) - { error("base type must be of integral type, not %s", memtype->toChars()); - memtype = Type::tint32; - } -#endif - } - - isdone = 1; - Module::dprogress++; - - type = type->semantic(loc, sc); - if (isAnonymous()) - sce = sc; - else - { sce = sc->push(this); - sce->parent = this; - } - if (members->dim == 0) - error("enum %s must have at least one member", toChars()); - int first = 1; - Expression *elast = NULL; - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - Expression *e; - - if (!em) - /* The e->semantic(sce) can insert other symbols, such as - * template instances and function literals. - */ - continue; - - //printf(" Enum member '%s'\n",em->toChars()); - if (em->type) - em->type = em->type->semantic(em->loc, sce); - e = em->value; - if (e) - { - assert(e->dyncast() == DYNCAST_EXPRESSION); - e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); - if (memtype) - { - e = e->implicitCastTo(sce, memtype); - e = e->optimize(WANTvalue | WANTinterpret); - if (!isAnonymous()) - e = e->castTo(sce, type); - t = memtype; - } - else if (em->type) - { - e = e->implicitCastTo(sce, em->type); - e = e->optimize(WANTvalue | WANTinterpret); - assert(isAnonymous()); - t = e->type; - } - else - t = e->type; - } - else if (first) - { - if (memtype) - t = memtype; - else if (em->type) - t = em->type; - else - t = Type::tint32; - e = new IntegerExp(em->loc, 0, Type::tint32); - e = e->implicitCastTo(sce, t); - e = e->optimize(WANTvalue | WANTinterpret); - if (!isAnonymous()) - e = e->castTo(sce, type); - } - else - { - // Set value to (elast + 1). - // But first check that (elast != t.max) - assert(elast); - e = new EqualExp(TOKequal, em->loc, elast, t->getProperty(0, Id::max)); - e = e->semantic(sce); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->toInteger()) - error("overflow of enum value %s", elast->toChars()); - - // Now set e to (elast + 1) - e = new AddExp(em->loc, elast, new IntegerExp(em->loc, 1, Type::tint32)); - e = e->semantic(sce); - e = e->castTo(sce, elast->type); - e = e->optimize(WANTvalue | WANTinterpret); - } - elast = e; - em->value = e; - - // Add to symbol table only after evaluating 'value' - if (isAnonymous()) - { - /* Anonymous enum members get added to enclosing scope. - */ - for (Scope *sct = sce; sct; sct = sct->enclosing) - { - if (sct->scopesym) - { - if (!sct->scopesym->symtab) - sct->scopesym->symtab = new DsymbolTable(); - em->addMember(sce, sct->scopesym, 1); - break; - } - } - } - else - em->addMember(sc, this, 1); - - /* Compute .min, .max and .default values. - * If enum doesn't have a name, we can never identify the enum type, - * so there is no purpose for a .min, .max or .default - */ - if (!isAnonymous()) - { - if (first) - { defaultval = e; - minval = e; - maxval = e; - } - else - { Expression *ec; - - /* In order to work successfully with UDTs, - * build expressions to do the comparisons, - * and let the semantic analyzer and constant - * folder give us the result. - */ - - // Compute if(e < minval) - ec = new CmpExp(TOKlt, em->loc, e, minval); - ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); - if (ec->toInteger()) - minval = e; - - ec = new CmpExp(TOKgt, em->loc, e, maxval); - ec = ec->semantic(sce); - ec = ec->optimize(WANTvalue | WANTinterpret); - if (ec->toInteger()) - maxval = e; - } - } - first = 0; - } - //printf("defaultval = %lld\n", defaultval); - - //if (defaultval) printf("defaultval: %s %s\n", defaultval->toChars(), defaultval->type->toChars()); - if (sc != sce) - sce->pop(); - //members->print(); -} - -int EnumDeclaration::oneMember(Dsymbol **ps, Identifier *ident) -{ - if (isAnonymous()) - return Dsymbol::oneMembers(members, ps, ident); - return Dsymbol::oneMember(ps, ident); -} - -void EnumDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("enum "); - if (ident) - { buf->writestring(ident->toChars()); - buf->writeByte(' '); - } - if (memtype) - { - buf->writestring(": "); - memtype->toCBuffer(buf, NULL, hgs); - } - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - EnumMember *em = (*members)[i]->isEnumMember(); - if (!em) - continue; - //buf->writestring(" "); - em->toCBuffer(buf, hgs); - buf->writeByte(','); - buf->writenl(); - } - buf->writeByte('}'); - buf->writenl(); -} - -Type *EnumDeclaration::getType() -{ - return type; -} - -const char *EnumDeclaration::kind() -{ - return "enum"; -} - -int EnumDeclaration::isDeprecated() -{ - return isdeprecated; -} - -Dsymbol *EnumDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident->toChars()); - if (scope) - // Try one last time to resolve this enum - semantic(scope); - - if (!members || !symtab || scope) - { error("is forward referenced when looking for '%s'", ident->toChars()); - //*(char*)0=0; - return NULL; - } - - Dsymbol *s = ScopeDsymbol::search(loc, ident, flags); - return s; -} - -/********************************* EnumMember ****************************/ - -EnumMember::EnumMember(Loc loc, Identifier *id, Expression *value, Type *type) - : Dsymbol(id) -{ - this->value = value; - this->type = type; - this->loc = loc; -} - -Dsymbol *EnumMember::syntaxCopy(Dsymbol *s) -{ - Expression *e = NULL; - if (value) - e = value->syntaxCopy(); - - Type *t = NULL; - if (type) - t = type->syntaxCopy(); - - EnumMember *em; - if (s) - { em = (EnumMember *)s; - em->loc = loc; - em->value = e; - em->type = t; - } - else - em = new EnumMember(loc, ident, e, t); - return em; -} - -void EnumMember::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (type) - type->toCBuffer(buf, ident, hgs); - else - buf->writestring(ident->toChars()); - if (value) - { - buf->writestring(" = "); - value->toCBuffer(buf, hgs); - } -} - -const char *EnumMember::kind() -{ - return "enum member"; -} - - diff --git a/dmd2/enum.h b/dmd2/enum.h deleted file mode 100644 index b8b3290e..00000000 --- a/dmd2/enum.h +++ /dev/null @@ -1,97 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_ENUM_H -#define DMD_ENUM_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct Identifier; -struct Type; -struct Expression; -struct HdrGenState; - - -struct EnumDeclaration : ScopeDsymbol -{ /* enum ident : memtype { ... } - */ - Type *type; // the TypeEnum - Type *memtype; // type of the members - -#if DMDV1 - dinteger_t maxval; - dinteger_t minval; - dinteger_t defaultval; // default initializer -#else - Expression *maxval; - Expression *minval; - Expression *defaultval; // default initializer -#endif - int isdeprecated; - int isdone; // 0: not done - // 1: semantic() successfully completed - - EnumDeclaration(Loc loc, Identifier *id, Type *memtype); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic0(Scope *sc); - void semantic(Scope *sc); - int oneMember(Dsymbol **ps, Identifier *ident = NULL); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Type *getType(); - const char *kind(); -#if DMDV2 - Dsymbol *search(Loc, Identifier *ident, int flags); -#endif - int isDeprecated(); // is Dsymbol deprecated? - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - EnumDeclaration *isEnumDeclaration() { return this; } - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file - void toDebug(); - int cvMember(unsigned char *p); - - Symbol *sinit; - Symbol *toInitializer(); -#endif - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - - -struct EnumMember : Dsymbol -{ - Expression *value; - Type *type; - - EnumMember(Loc loc, Identifier *id, Expression *value, Type *type); - Dsymbol *syntaxCopy(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); - void toDocBuffer(OutBuffer *buf); - - EnumMember *isEnumMember() { return this; } -}; - -#endif /* DMD_ENUM_H */ diff --git a/dmd2/expression.c b/dmd2/expression.c deleted file mode 100644 index e2daf426..00000000 --- a/dmd2/expression.c +++ /dev/null @@ -1,12570 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#if _MSC_VER -#include -#else -#if IN_DMD -#include -#endif -#endif - -#if _WIN32 && __DMC__ -extern "C" char * __cdecl __locale_decpoint; -#endif - -#if __MINGW32__ -#ifndef isnan -#define isnan _isnan -#endif -#endif - -#ifdef __APPLE__ -#ifndef isnan -int isnan(double); -#endif -#endif - -#include "rmem.h" -#if IN_DMD -#include "port.h" -#include "root.h" -#endif - -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "utf.h" -#include "enum.h" -#include "scope.h" -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "import.h" -#include "id.h" -#include "dsymbol.h" -#include "module.h" -#include "attrib.h" -#include "hdrgen.h" -#include "parse.h" -#include "doc.h" - -#if IN_DMD -Expression *createTypeInfoArray(Scope *sc, Expression *args[], unsigned dim); -#endif -Expression *expandVar(int result, VarDeclaration *v); - -#define LOGSEMANTIC 0 - -/************************************************************* - * Given var, we need to get the - * right 'this' pointer if var is in an outer class, but our - * existing 'this' pointer is in an inner class. - * Input: - * e1 existing 'this' - * ad struct or class we need the correct 'this' for - * var the specific member of ad we're accessing - */ - -Expression *getRightThis(Loc loc, Scope *sc, AggregateDeclaration *ad, - Expression *e1, Declaration *var) -{ - //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1->toChars(), ad->toChars(), var->toChars()); - L1: - Type *t = e1->type->toBasetype(); - //printf("e1->type = %s, var->type = %s\n", e1->type->toChars(), var->type->toChars()); - - /* If e1 is not the 'this' pointer for ad - */ - if (ad && - !(t->ty == Tpointer && t->nextOf()->ty == Tstruct && - ((TypeStruct *)t->nextOf())->sym == ad) - && - !(t->ty == Tstruct && - ((TypeStruct *)t)->sym == ad) - ) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - ClassDeclaration *tcd = t->isClassHandle(); - - /* e1 is the right this if ad is a base class of e1 - */ - if (!cd || !tcd || - !(tcd == cd || cd->isBaseOf(tcd, NULL)) - ) - { - /* Only classes can be inner classes with an 'outer' - * member pointing to the enclosing class instance - */ - if (tcd && tcd->isNested()) - { /* e1 is the 'this' pointer for an inner class: tcd. - * Rewrite it as the 'this' pointer for the outer class. - */ - - e1 = new DotVarExp(loc, e1, tcd->vthis); - e1->type = tcd->vthis->type; - // Do not call checkNestedRef() - //e1 = e1->semantic(sc); - - // Skip up over nested functions, and get the enclosing - // class type. - int n = 0; - Dsymbol *s; - for (s = tcd->toParent(); - s && s->isFuncDeclaration(); - s = s->toParent()) - { FuncDeclaration *f = s->isFuncDeclaration(); - if (f->vthis) - { - //printf("rewriting e1 to %s's this\n", f->toChars()); - n++; - - // LDC seems dmd misses it sometimes here :/ - if (f->isMember2()) { - f->vthis->nestedrefs.push(sc->parent->isFuncDeclaration()); - f->closureVars.push(f->vthis); - } - - e1 = new VarExp(loc, f->vthis); - } - else - { - e1->error("need 'this' of type %s to access member %s" - " from static function %s", - ad->toChars(), var->toChars(), f->toChars()); - e1 = new ErrorExp(); - return e1; - } - } - if (s && s->isClassDeclaration()) - { e1->type = s->isClassDeclaration()->type; - if (n > 1) - e1 = e1->semantic(sc); - } - else - e1 = e1->semantic(sc); - goto L1; - } - /* Can't find a path from e1 to ad - */ - e1->error("this for %s needs to be type %s not type %s", - var->toChars(), ad->toChars(), t->toChars()); - e1 = new ErrorExp(); - } - } - return e1; -} - -/***************************************** - * Determine if 'this' is available. - * If it is, return the FuncDeclaration that has it. - */ - -FuncDeclaration *hasThis(Scope *sc) -{ FuncDeclaration *fd; - FuncDeclaration *fdthis; - - //printf("hasThis()\n"); - fdthis = sc->parent->isFuncDeclaration(); - //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis->toChars() : ""); - - /* Special case for inside template constraint - */ - if (fdthis && (sc->flags & SCOPEstaticif) && fdthis->parent->isTemplateDeclaration()) - { - //TemplateDeclaration *td = fdthis->parent->isTemplateDeclaration(); - //printf("[%s] td = %s, fdthis->vthis = %p\n", td->loc.toChars(), td->toChars(), fdthis->vthis); - return fdthis->vthis ? fdthis : NULL; - } - - // Go upwards until we find the enclosing member function - fd = fdthis; - while (1) - { - if (!fd) - { - goto Lno; - } - if (!fd->isNested()) - break; - - Dsymbol *parent = fd->parent; - while (1) - { - if (!parent) - goto Lno; - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - parent = ti->parent; - else - break; - } - fd = parent->isFuncDeclaration(); - } - - if (!fd->isThis()) - { //printf("test '%s'\n", fd->toChars()); - goto Lno; - } - - assert(fd->vthis); - return fd; - -Lno: - return NULL; // don't have 'this' available -} - - -/*************************************** - * Pull out any properties. - */ - -Expression *resolveProperties(Scope *sc, Expression *e) -{ - //printf("resolveProperties(%s)\n", e->toChars()); - - TemplateDeclaration *td; - Objects *targsi; - Expression *ethis; - if (e->op == TOKdotti) - { - DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e; - td = dti->getTempdecl(sc); - dti->ti->semanticTiargs(sc); - targsi = dti->ti->tiargs; - ethis = dti->e1; - goto L1; - } - else if (e->op == TOKdottd) - { - DotTemplateExp *dte = (DotTemplateExp *)e; - td = dte->td; - targsi = NULL; - ethis = dte->e1; - goto L1; - } - else if (e->op == TOKtemplate) - { - td = ((TemplateExp *)e)->td; - targsi = NULL; - ethis = NULL; - L1: - assert(td); - unsigned errors = global.startGagging(); - FuncDeclaration *fd = td->deduceFunctionTemplate(sc, e->loc, targsi, ethis, NULL, 1); - if (global.endGagging(errors)) - fd = NULL; // eat "is not a function template" error - if (fd && fd->type) - { assert(fd->type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)fd->type; - if (!tf->isproperty && global.params.enforcePropertySyntax) - { error(e->loc, "not a property %s", e->toChars()); - return new ErrorExp(); - } - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - goto return_expr; - } - - if (e->type) - { - Type *t = e->type->toBasetype(); - - if (t->ty == Tfunction || e->op == TOKoverloadset) - { - if (t->ty == Tfunction && !((TypeFunction *)t)->isproperty && - global.params.enforcePropertySyntax) - { - error(e->loc, "not a property %s", e->toChars()); - return new ErrorExp(); - } - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - - /* Look for e being a lazy parameter; rewrite as delegate call - */ - else if (e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - - if (ve->var->storage_class & STClazy) - { - e = new CallExp(e->loc, e); - e = e->semantic(sc); - } - } - - else if (e->op == TOKdotexp) - { - e->error("expression has no value"); - return new ErrorExp(); - } - - } - -return_expr: - if (!e->type) - { - error(e->loc, "cannot resolve type for %s", e->toChars()); - e->type = new TypeError(); - } - return e; -} - -/****************************** - * Perform semantic() on an array of Expressions. - */ - -Expressions *arrayExpressionSemantic(Expressions *exps, Scope *sc) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - if (e) - { e = e->semantic(sc); - (*exps)[i] = e; - } - } - } - return exps; -} - - -/****************************** - * Perform canThrow() on an array of Expressions. - */ - -#if DMDV2 -int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow) -{ - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - if (e && e->canThrow(mustNotThrow)) - return 1; - } - } - return 0; -} -#endif - -/**************************************** - * Expand tuples. - */ - -void expandTuples(Expressions *exps) -{ - //printf("expandTuples()\n"); - if (exps) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (*exps)[i]; - if (!arg) - continue; - - // Look for tuple with 0 members - if (arg->op == TOKtype) - { TypeExp *e = (TypeExp *)arg; - if (e->type->toBasetype()->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)e->type->toBasetype(); - - if (!tt->arguments || tt->arguments->dim == 0) - { - exps->remove(i); - if (i == exps->dim) - return; - i--; - continue; - } - } - } - - // Inline expand all the tuples - while (arg->op == TOKtuple) - { TupleExp *te = (TupleExp *)arg; - - exps->remove(i); // remove arg - exps->insert(i, te->exps); // replace with tuple contents - if (i == exps->dim) - return; // empty tuple, no more arguments - arg = (*exps)[i]; - } - } - } -} - -/**************************************** - * Expand alias this tuples. - */ - -TupleDeclaration *isAliasThisTuple(Expression *e) -{ - if (e->type) - { - Type *t = e->type->toBasetype(); - AggregateDeclaration *ad; - if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - goto L1; - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - L1: - Dsymbol *s = ad->aliasthis; - if (s && s->isVarDeclaration()) - { - TupleDeclaration *td = s->isVarDeclaration()->toAlias()->isTupleDeclaration(); - if (td && td->isexp) - return td; - } - } - } - return NULL; -} - -int expandAliasThisTuples(Expressions *exps, int starti) -{ - if (!exps || exps->dim == 0) - return -1; - - for (size_t u = starti; u < exps->dim; u++) - { - Expression *exp = exps->tdata()[u]; - TupleDeclaration *td = isAliasThisTuple(exp); - if (td) - { - exps->remove(u); - for (size_t i = 0; iobjects->dim; ++i) - { - Expression *e = isExpression(td->objects->tdata()[i]); - assert(e); - assert(e->op == TOKdsymbol); - DsymbolExp *se = (DsymbolExp *)e; - Declaration *d = se->s->isDeclaration(); - assert(d); - e = new DotVarExp(exp->loc, exp, d); - assert(d->type); - e->type = d->type; - exps->insert(u + i, e); - } - #if 0 - printf("expansion ->\n"); - for (size_t i = 0; idim; ++i) - { - Expression *e = exps->tdata()[i]; - printf("\texps[%d] e = %s %s\n", i, Token::tochars[e->op], e->toChars()); - } - #endif - return u; - } - } - - return -1; -} - -Expressions *arrayExpressionToCommonType(Scope *sc, Expressions *exps, Type **pt) -{ -#if DMDV1 - /* The first element sets the type - */ - Type *t0 = NULL; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - if (!e->type) - { error("%s has no value", e->toChars()); - e = new ErrorExp(); - } - e = resolveProperties(sc, e); - - if (!t0) - t0 = e->type; - else - e = e->implicitCastTo(sc, t0); - (*exps)[i] = e; - } - - if (!t0) - t0 = Type::tvoid; - if (pt) - *pt = t0; - - // Eventually, we want to make this copy-on-write - return exps; -#endif -#if DMDV2 - /* The type is determined by applying ?: to each pair. - */ - /* Still have a problem with: - * ubyte[][] = [ cast(ubyte[])"hello", [1]]; - * which works if the array literal is initialized top down with the ubyte[][] - * type, but fails with this function doing bottom up typing. - */ - //printf("arrayExpressionToCommonType()\n"); - IntegerExp integerexp(0); - CondExp condexp(0, &integerexp, NULL, NULL); - - Type *t0 = NULL; - Expression *e0; - int j0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - e = resolveProperties(sc, e); - if (!e->type) - { error("%s has no value", e->toChars()); - e = new ErrorExp(); - } - - if (t0) - { if (t0 != e->type) - { - /* This applies ?: to merge the types. It's backwards; - * ?: should call this function to merge types. - */ - condexp.type = NULL; - condexp.e1 = e0; - condexp.e2 = e; - condexp.loc = e->loc; - condexp.semantic(sc); - (*exps)[j0] = condexp.e1; - e = condexp.e2; - j0 = i; - e0 = e; - t0 = e0->type; - } - } - else - { j0 = i; - e0 = e; - t0 = e->type; - } - (*exps)[i] = e; - } - - if (t0) - { - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - e = e->implicitCastTo(sc, t0); - (*exps)[i] = e; - } - } - else - t0 = Type::tvoid; // [] is typed as void[] - if (pt) - *pt = t0; - - // Eventually, we want to make this copy-on-write - return exps; -#endif -} - -/**************************************** - * Get TemplateDeclaration enclosing FuncDeclaration. - */ - -TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s) -{ - FuncDeclaration *f = s->isFuncDeclaration(); - if (f && f->parent) - { TemplateInstance *ti = f->parent->isTemplateInstance(); - - if (ti && - !ti->isTemplateMixin() && - (ti->name == f->ident || - ti->toAlias()->ident == f->ident) - && - ti->tempdecl && ti->tempdecl->onemember) - { - return ti->tempdecl; - } - } - return NULL; -} - -/**************************************** - * Preprocess arguments to function. - */ - -void preFunctionParameters(Loc loc, Scope *sc, Expressions *exps) -{ - if (exps) - { - expandTuples(exps); - - for (size_t i = 0; i < exps->dim; i++) - { Expression *arg = (*exps)[i]; - - arg = resolveProperties(sc, arg); - (*exps)[i] = arg; - - //arg->rvalue(); -#if 0 - if (arg->type->ty == Tfunction) - { - arg = new AddrExp(arg->loc, arg); - arg = arg->semantic(sc); - (*exps)[i] = arg; - } -#endif - } - } -} - -/************************************************ - * If we want the value of this expression, but do not want to call - * the destructor on it. - */ - -void valueNoDtor(Expression *e) -{ - if (e->op == TOKcall) - { - /* The struct value returned from the function is transferred - * so do not call the destructor on it. - * Recognize: - * ((S _ctmp = S.init), _ctmp).this(...) - * and make sure the destructor is not called on _ctmp - * BUG: if e is a CommaExp, we should go down the right side. - */ - CallExp *ce = (CallExp *)e; - if (ce->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)ce->e1; - if (dve->var->isCtorDeclaration()) - { // It's a constructor call - if (dve->e1->op == TOKcomma) - { CommaExp *comma = (CommaExp *)dve->e1; - if (comma->e2->op == TOKvar) - { VarExp *ve = (VarExp *)comma->e2; - VarDeclaration *ctmp = ve->var->isVarDeclaration(); - if (ctmp) - ctmp->noscope = 1; - } - } - } - } - } -} - -/********************************************* - * Call copy constructor for struct value argument. - */ -#if DMDV2 -Expression *callCpCtor(Loc loc, Scope *sc, Expression *e, int noscope) -{ - 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("__cpcttmp"); - VarDeclaration *tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(0, e)); - tmp->storage_class |= STCctfe; - tmp->noscope = noscope; - Expression *ae = new DeclarationExp(loc, tmp); - e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - } - return e; -} -#endif - -// Check if this function is a member of a template which has only been -// instantiated speculatively, eg from inside is(typeof()). -// Return the speculative template instance it is part of, -// or NULL if not speculative. -TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd) -{ - Dsymbol * par = fd->parent; - while (par) - { - TemplateInstance *ti = par->isTemplateInstance(); - if (ti && ti->speculative) - return ti; - par = par->toParent(); - } - return NULL; -} - -/**************************************** - * Now that we know the exact type of the function we're calling, - * the arguments[] need to be adjusted: - * 1. implicitly convert argument to the corresponding parameter type - * 2. add default arguments for any missing arguments - * 3. do default promotions on arguments corresponding to ... - * 4. add hidden _arguments[] argument - * 5. call copy constructor for struct value arguments - * Returns: - * return type from function - */ - -Type *functionParameters(Loc loc, Scope *sc, TypeFunction *tf, - Expression *ethis, Expressions *arguments, FuncDeclaration *fd) -{ - //printf("functionParameters()\n"); - assert(arguments); - assert(fd || tf->next); - size_t nargs = arguments ? arguments->dim : 0; - size_t nparams = Parameter::dim(tf->parameters); - - if (nargs > nparams && tf->varargs == 0) - { error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf->toChars()); - return Type::terror; - } - - // If inferring return type, and semantic3() needs to be run if not already run - if (!tf->next && fd->inferRetType) - { - TemplateInstance *spec = isSpeculativeFunction(fd); - int olderrs = global.errors; - fd->semantic3(fd->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } - - unsigned n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - - unsigned wildmatch = 0; - if (ethis && tf->isWild()) - { - Type *t = ethis->type; - if (t->isWild()) - wildmatch |= MODwild; - else if (t->isConst()) - wildmatch |= MODconst; - else if (t->isImmutable()) - wildmatch |= MODimmutable; - else - wildmatch |= MODmutable; - } - - int done = 0; - for (size_t i = 0; i < n; i++) - { - Expression *arg; - - if (i < nargs) - arg = arguments->tdata()[i]; - else - arg = NULL; - - if (i < nparams) - { - Parameter *p = Parameter::getNth(tf->parameters, i); - - if (!arg) - { - if (!p->defaultArg) - { - if (tf->varargs == 2 && i + 1 == nparams) - goto L2; - error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return Type::terror; - } - arg = p->defaultArg; - arg = arg->inlineCopy(sc); -#if DMDV2 - arg = arg->resolveLoc(loc, sc); // __FILE__ and __LINE__ -#endif - arguments->push(arg); - nargs++; - } - else if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *pt = p->type; - if (tf->varargs == 2 && i + 1 == nparams && pt->nextOf()) - pt = pt->nextOf(); - fe->setType(pt); - arg = fe->semantic(sc); - arguments->tdata()[i] = arg; - } - - if (tf->varargs == 2 && i + 1 == nparams) - { - //printf("\t\tvarargs == 2, p->type = '%s'\n", p->type->toChars()); - if (arg->implicitConvTo(p->type)) - { - if (p->type->nextOf() && arg->implicitConvTo(p->type->nextOf())) - goto L2; - else if (nargs != nparams) - { error(loc, "expected %zu function arguments, not %zu", nparams, nargs); - return Type::terror; - } - goto L1; - } - L2: - Type *tb = p->type->toBasetype(); - Type *tret = p->isLazyArray(); - switch (tb->ty) - { - case Tsarray: - case Tarray: - { // Create a static array variable v of type arg->type -#ifdef IN_GCC - /* GCC 4.0 does not like zero length arrays used like - this; pass a null array value instead. Could also - just make a one-element array. */ - if (nargs - i == 0) - { - arg = new NullExp(loc); - break; - } -#endif - Identifier *id = Lexer::uniqueId("__arrayArg"); - Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); - t = t->semantic(loc, sc); - bool isSafe = fd ? fd->isSafe() : tf->trust == TRUSTsafe; - VarDeclaration *v = new VarDeclaration(loc, t, id, - isSafe ? NULL : new VoidInitializer(loc)); - v->storage_class |= STCctfe; - v->semantic(sc); - v->parent = sc->parent; - //sc->insert(v); - - Expression *c = new DeclarationExp(0, v); - c->type = v->type; - - for (size_t u = i; u < nargs; u++) - { Expression *a = arguments->tdata()[u]; - if (tret && !((TypeArray *)tb)->next->equals(a->type)) - a = a->toDelegate(sc, tret); - - Expression *e = new VarExp(loc, v); - e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - ConstructExp *ae = new ConstructExp(loc, e, a); - if (c) - c = new CommaExp(loc, c, ae); - else - c = ae; - } - arg = new VarExp(loc, v); - if (c) - arg = new CommaExp(loc, c, arg); - break; - } - case Tclass: - { /* Set arg to be: - * new Tclass(arg0, arg1, ..., argn) - */ - Expressions *args = new Expressions(); - args->setDim(nargs - i); - for (size_t u = i; u < nargs; u++) - args->tdata()[u - i] = arguments->tdata()[u]; - arg = new NewExp(loc, NULL, NULL, p->type, args); - break; - } - default: - if (!arg) - { error(loc, "not enough arguments"); - return Type::terror; - } - break; - } - arg = arg->semantic(sc); - //printf("\targ = '%s'\n", arg->toChars()); - arguments->setDim(i + 1); - arguments->tdata()[i] = arg; - nargs = i + 1; - done = 1; - } - - L1: - if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - { - unsigned mod = arg->type->wildConvTo(p->type); - if (mod) - { - wildmatch |= mod; - } - } - } - if (done) - break; - } - if (wildmatch) - { /* Calculate wild matching modifier - */ - if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) - wildmatch = MODconst; - else if (wildmatch & MODimmutable) - wildmatch = MODimmutable; - else if (wildmatch & MODwild) - wildmatch = MODwild; - else - { assert(wildmatch & MODmutable); - wildmatch = MODmutable; - } - } - - assert(nargs >= nparams); - for (size_t i = 0; i < nargs; i++) - { - Expression *arg = arguments->tdata()[i]; - assert(arg); - - if (i < nparams) - { - Parameter *p = Parameter::getNth(tf->parameters, i); - - if (!(p->storageClass & STClazy && p->type->ty == Tvoid)) - { - if (p->type->hasWild()) - { - arg = arg->implicitCastTo(sc, p->type->substWildTo(wildmatch)); - arg = arg->optimize(WANTvalue); - } - else if (p->type != arg->type) - { - //printf("arg->type = %s, p->type = %s\n", arg->type->toChars(), p->type->toChars()); - if (arg->op == TOKtype) - { arg->error("cannot pass type %s as function argument", arg->toChars()); - arg = new ErrorExp(); - goto L3; - } - else - arg = arg->implicitCastTo(sc, p->type); - arg = arg->optimize(WANTvalue); - } - } - if (p->storageClass & STCref) - { - arg = arg->toLvalue(sc, arg); - } - else if (p->storageClass & STCout) - { - arg = arg->modifiableLvalue(sc, arg); - } - - Type *tb = arg->type->toBasetype(); -// LDC we don't want this! -#if !IN_LLVM -#if !SARRAYVALUE - // Convert static arrays to pointers - if (tb->ty == Tsarray) - { - arg = arg->checkToPointer(); - } -#endif -#endif -#if DMDV2 - if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) - { - if (arg->op == TOKcall) - { - /* The struct value returned from the function is transferred - * to the function, so the callee should not call the destructor - * on it. - */ - valueNoDtor(arg); - } - else - { /* Not transferring it, so call the copy constructor - */ - arg = callCpCtor(loc, sc, arg, 1); - } - } -#endif - - //printf("arg: %s\n", arg->toChars()); - //printf("type: %s\n", arg->type->toChars()); - - // Convert lazy argument to a delegate - if (p->storageClass & STClazy) - { - arg = arg->toDelegate(sc, p->type); - } -#if DMDV2 - /* Look for arguments that cannot 'escape' from the called - * function. - */ - if (!tf->parameterEscapes(p)) - { - Expression *a = arg; - if (a->op == TOKcast) - a = ((CastExp *)a)->e1; - - /* Function literals can only appear once, so if this - * appearance was scoped, there cannot be any others. - */ - if (a->op == TOKfunction) - { FuncExp *fe = (FuncExp *)a; - fe->fd->tookAddressOf = 0; - } - - /* For passing a delegate to a scoped parameter, - * this doesn't count as taking the address of it. - * We only worry about 'escaping' references to the function. - */ - else if (a->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)a; - if (de->e1->op == TOKvar) - { VarExp *ve = (VarExp *)de->e1; - FuncDeclaration *f = ve->var->isFuncDeclaration(); - if (f) - { f->tookAddressOf--; - //printf("tookAddressOf = %d\n", f->tookAddressOf); - } - } - } - } -#endif - } - else - { - - // If not D linkage, do promotions - // LDC: don't do promotions on intrinsics - if (tf->linkage != LINKd && tf->linkage != LINKintrinsic) - { - // Promote bytes, words, etc., to ints - arg = arg->integralPromotions(sc); - - // Promote floats to doubles - switch (arg->type->ty) - { - case Tfloat32: - arg = arg->castTo(sc, Type::tfloat64); - break; - - case Timaginary32: - arg = arg->castTo(sc, Type::timaginary64); - break; - } - } - - // Do not allow types that need destructors - if (arg->type->needsDestruction()) - { arg->error("cannot pass types that need destruction as variadic arguments"); - arg = new ErrorExp(); - } - - // Convert static arrays to dynamic arrays - // BUG: I don't think this is right for D2 - Type *tb = arg->type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - Type *ta = ts->next->arrayOf(); - if (ts->size(arg->loc) == 0) - arg = new NullExp(arg->loc, ta); - else - arg = arg->castTo(sc, ta); - } -#if DMDV2 - if (tb->ty == Tstruct) - { - arg = callCpCtor(loc, sc, arg, 1); - } -#endif - - // Give error for overloaded function addresses -#if IN_LLVM - if (arg->op == TOKaddress) - { AddrExp *ae = (AddrExp *)arg; - if (ae->e1->op == TOKvar) { - VarExp *ve = (VarExp*)ae->e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - if (fd && -#if DMDV2 - ve->hasOverloads && -#endif - !fd->isUnique()) - { - arg->error("function %s is overloaded", arg->toChars()); - } - } - } -#else - if (arg->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)arg; - if ( -#if DMDV2 - se->hasOverloads && -#endif - !se->var->isFuncDeclaration()->isUnique()) - { arg->error("function %s is overloaded", arg->toChars()); - arg = new ErrorExp(); - } - } -#endif - arg->rvalue(); - } - arg = arg->optimize(WANTvalue); - L3: - arguments->tdata()[i] = arg; - } - -#if !IN_LLVM - // If D linkage and variadic, add _arguments[] as first argument - if (tf->linkage == LINKd && tf->varargs == 1) - { - assert(arguments->dim >= nparams); - Expression *e = createTypeInfoArray(sc, (Expression **)&arguments->tdata()[nparams], - arguments->dim - nparams); - arguments->insert(0, e); - } -#endif - Type *tret = tf->next; - if (wildmatch) - { /* Adjust function return type based on wildmatch - */ - //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret->toChars()); - tret = tret->substWildTo(wildmatch); - } - return tret; -} - -/************************************************** - * Write expression out to buf, but wrap it - * in ( ) if its precedence is less than pr. - */ - -void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) -{ -#if !IN_LLVM -#ifdef DEBUG - if (precedence[e->op] == PREC_zero) - printf("precedence not defined for token '%s'\n",Token::tochars[e->op]); -#endif - assert(precedence[e->op] != PREC_zero); - assert(pr != PREC_zero); -#endif - - //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr || - /* Despite precedence, we don't allow aop] == pr)) - { - buf->writeByte('('); - e->toCBuffer(buf, hgs); - buf->writeByte(')'); - } - else - e->toCBuffer(buf, hgs); -} - -/************************************************** - * Write out argument list to buf. - */ - -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = arguments->tdata()[i]; - - if (arg) - { if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, arg, PREC_assign); - } - } - } -} - -/************************************************** - * Write out argument types to buf. - */ - -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs) -{ - if (arguments) - { OutBuffer argbuf; - - for (size_t i = 0; i < arguments->dim; i++) - { Expression *arg = arguments->tdata()[i]; - - if (i) - buf->writeByte(','); - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, hgs, 0); - buf->write(&argbuf); - } - } -} - -/******************************** Expression **************************/ - -Expression::Expression(Loc loc, enum TOK op, int size) - : loc(loc) -{ - //printf("Expression::Expression(op = %d) this = %p\n", op, this); - this->loc = loc; - this->op = op; - this->size = size; - this->parens = 0; - type = NULL; - -#if IN_LLVM - cachedLvalue = NULL; -#endif -} - -Expression *Expression::syntaxCopy() -{ - //printf("Expression::syntaxCopy()\n"); - //dump(0); - return copy(); -} - -/********************************* - * Does *not* do a deep copy. - */ - -Expression *Expression::copy() -{ - Expression *e; - if (!size) - { -#ifdef DEBUG - fprintf(stdmsg, "No expression copy for: %s\n", toChars()); - printf("op = %d\n", op); - dump(0); -#endif - assert(0); - } - e = (Expression *)mem.malloc(size); - //printf("Expression::copy(op = %d) e = %p\n", op, e); - return (Expression *)memcpy(e, this, size); -} - -/************************** - * Semantically analyze Expression. - * Determine types, fold constants, etc. - */ - -Expression *Expression::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("Expression::semantic() %s\n", toChars()); -#endif - if (type) - type = type->semantic(loc, sc); - else - type = Type::tvoid; - return this; -} - -/********************************** - * Try to run semantic routines. - * If they fail, return NULL. - */ - -Expression *Expression::trySemantic(Scope *sc) -{ - //printf("+trySemantic(%s)\n", toChars()); - unsigned errors = global.startGagging(); - Expression *e = semantic(sc); - if (global.endGagging(errors)) - { - e = NULL; - } - //printf("-trySemantic(%s)\n", toChars()); - return e; -} - -void Expression::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Expression::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - memset(&hgs, 0, sizeof(hgs)); - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Expression::error(const char *format, ...) -{ - if (type != Type::terror) - { - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); - } -} - -void Expression::warning(const char *format, ...) -{ - if (type != Type::terror) - { - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); - } -} - -int Expression::rvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - { error("expression %s is void and has no value", toChars()); -#if 0 - dump(0); - halt(); -#endif - if (!global.gag) - type = Type::terror; - return 0; - } - return 1; -} - -Expression *Expression::combine(Expression *e1, Expression *e2) -{ - if (e1) - { - if (e2) - { - e1 = new CommaExp(e1->loc, e1, e2); - e1->type = e2->type; - } - } - else - e1 = e2; - return e1; -} - -dinteger_t Expression::toInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - error("Integer constant expression expected instead of %s", toChars()); - return 0; -} - -uinteger_t Expression::toUInteger() -{ - //printf("Expression %s\n", Token::toChars(op)); - return (uinteger_t)toInteger(); -} - -real_t Expression::toReal() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -real_t Expression::toImaginary() -{ - error("Floating point constant expression expected instead of %s", toChars()); - return 0; -} - -complex_t Expression::toComplex() -{ - error("Floating point constant expression expected instead of %s", toChars()); -#ifdef IN_GCC - return complex_t(real_t(0)); // %% nicer -#else - return 0; -#endif -} - -StringExp *Expression::toString() -{ - return NULL; -} - -void Expression::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); -} - -void Expression::toMangleBuffer(OutBuffer *buf) -{ - error("expression %s is not a valid template value argument", toChars()); -#ifdef DEBUG -dump(0); -#endif -} - -/*************************************** - * Return !=0 if expression is an lvalue. - */ -#if DMDV2 -int Expression::isLvalue() -{ - return 0; -} -#endif - -/******************************* - * Give error if we're not an lvalue. - * If we can, convert expression to be an lvalue. - */ - -Expression *Expression::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - error("%s is not an lvalue", e->toChars()); - return new ErrorExp(); -} - -Expression *Expression::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); - - // See if this expression is a modifiable lvalue (i.e. not const) -#if DMDV2 - if (type && (!type->isMutable() || !type->isAssignable())) - { error("%s is not mutable", e->toChars()); - return new ErrorExp(); - } -#endif - return toLvalue(sc, e); -} - - -/************************************ - * Detect cases where pointers to the stack can 'escape' the - * lifetime of the stack frame. - */ - -void Expression::checkEscape() -{ -} - -void Expression::checkEscapeRef() -{ -} - -void Expression::checkScalar() -{ - if (!type->isscalar() && type->toBasetype() != Type::terror) - error("'%s' is not a scalar, it is a %s", toChars(), type->toChars()); - rvalue(); -} - -void Expression::checkNoBool() -{ - if (type->toBasetype()->ty == Tbool) - error("operation not allowed on bool '%s'", toChars()); -} - -Expression *Expression::checkIntegral() -{ - if (!type->isintegral()) - { if (type->toBasetype() != Type::terror) - error("'%s' is not of integral type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - if (!rvalue()) - return new ErrorExp(); - return this; -} - -Expression *Expression::checkArithmetic() -{ - if (!type->isintegral() && !type->isfloating()) - { if (type->toBasetype() != Type::terror) - error("'%s' is not of arithmetic type, it is a %s", toChars(), type->toChars()); - return new ErrorExp(); - } - if (!rvalue()) - return new ErrorExp(); - return this; -} - -void Expression::checkDeprecated(Scope *sc, Dsymbol *s) -{ - s->checkDeprecated(loc, sc); -} - -#if DMDV2 -/********************************************* - * Calling function f. - * Check the purity, i.e. if we're in a pure function - * we can only call other pure functions. - */ -void Expression::checkPurity(Scope *sc, FuncDeclaration *f) -{ -#if 1 - if (sc->func) - { - /* Given: - * void f() - * { pure void g() - * { - * void h() - * { - * void i() { } - * } - * } - * } - * g() can call h() but not f() - * i() can call h() and g() but not f() - */ - FuncDeclaration *outerfunc = sc->func; - // Find the closest pure parent of the calling function - while (outerfunc->toParent2() && - !outerfunc->isPureBypassingInference() && - outerfunc->toParent2()->isFuncDeclaration()) - { - outerfunc = outerfunc->toParent2()->isFuncDeclaration(); - } - // Find the closest pure parent of the called function - FuncDeclaration *calledparent = f; - while (calledparent->toParent2() && !calledparent->isPureBypassingInference() - && calledparent->toParent2()->isFuncDeclaration() ) - { - calledparent = calledparent->toParent2()->isFuncDeclaration(); - } - // If the caller has a pure parent, then either the called func must be pure, - // OR, they must have the same pure parent. - if (/*outerfunc->isPure() &&*/ // comment out because we deduce purity now - !sc->intypeof && - !(sc->flags & SCOPEdebug) && - !(f->isPure() || (calledparent == outerfunc))) - { - if (outerfunc->setImpure()) - error("pure function '%s' cannot call impure function '%s'", - outerfunc->toChars(), f->toChars()); - } - } -#else - if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) - error("pure function '%s' cannot call impure function '%s'", - sc->func->toChars(), f->toChars()); -#endif -} - -/******************************************* - * Accessing variable v. - * Check for purity and safety violations. - * If ethis is not NULL, then ethis is the 'this' pointer as in ethis.v - */ - -void Expression::checkPurity(Scope *sc, VarDeclaration *v, Expression *ethis) -{ - /* Look for purity and safety violations when accessing variable v - * from current function. - */ - if (sc->func && - !sc->intypeof && // allow violations inside typeof(expression) - !(sc->flags & SCOPEdebug) && // allow violations inside debug conditionals - v->ident != Id::ctfe && // magic variable never violates pure and safe - !v->isImmutable() && // always safe and pure to access immutables... - !(v->isConst() && v->isDataseg() && !v->type->hasPointers()) && // const global value types are immutable - !(v->storage_class & STCmanifest) // ...or manifest constants - ) - { - if (v->isDataseg()) - { - /* Accessing global mutable state. - * Therefore, this function and all its immediately enclosing - * functions must be pure. - */ - bool msg = FALSE; - for (Dsymbol *s = sc->func; s; s = s->toParent2()) - { - FuncDeclaration *ff = s->isFuncDeclaration(); - if (!ff) - break; - if (ff->setImpure() && !msg) - { error("pure function '%s' cannot access mutable static data '%s'", - sc->func->toChars(), v->toChars()); - msg = TRUE; // only need the innermost message - } - } - } - else - { - /* Given: - * void f() - * { int fx; - * pure void g() - * { int gx; - * void h() - * { int hx; - * void i() { } - * } - * } - * } - * i() can modify hx and gx but not fx - */ - - Dsymbol *vparent = v->toParent2(); - for (Dsymbol *s = sc->func; s; s = s->toParent2()) - { - if (s == vparent) - break; - FuncDeclaration *ff = s->isFuncDeclaration(); - if (!ff) - break; - if (ff->setImpure()) - { error("pure nested function '%s' cannot access mutable data '%s'", - ff->toChars(), v->toChars()); - break; - } - } - } - - /* Do not allow safe functions to access __gshared data - */ - if (v->storage_class & STCgshared) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot access __gshared data '%s'", - sc->func->toChars(), v->toChars()); - } - } -} - -void Expression::checkSafety(Scope *sc, FuncDeclaration *f) -{ - if (sc->func && !sc->intypeof && - !f->isSafe() && !f->isTrusted()) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system function '%s'", - sc->func->toChars(), f->toChars()); - } -} -#endif - - -/***************************** - * Check that expression can be tested for true or false. - */ - -Expression *Expression::checkToBoolean(Scope *sc) -{ - // Default is 'yes' - do nothing - -#ifdef DEBUG - if (!type) - dump(0); -#endif - - // Structs can be converted to bool using opCast(bool)() - Type *tb = type->toBasetype(); - if (tb->ty == Tstruct) - { AggregateDeclaration *ad = ((TypeStruct *)tb)->sym; - /* Don't really need to check for opCast first, but by doing so we - * get better error messages if it isn't there. - */ - Dsymbol *fd = search_function(ad, Id::cast); - if (fd) - { - Expression *e = new CastExp(loc, this, Type::tbool); - e = e->semantic(sc); - return e; - } - - // Forward to aliasthis. - if (ad->aliasthis) - { - Expression *e = new DotIdExp(loc, this, ad->aliasthis->ident); - e = e->semantic(sc); - e = resolveProperties(sc, e); - e = e->checkToBoolean(sc); - return e; - } - } - - if (!type->checkBoolean()) - { if (type->toBasetype() != Type::terror) - error("expression %s of type %s does not have a boolean value", toChars(), type->toChars()); - return new ErrorExp(); - } - return this; -} - -/**************************** - */ - -Expression *Expression::checkToPointer() -{ - //printf("Expression::checkToPointer()\n"); - Expression *e = this; - -#if !SARRAYVALUE - // If C static array, convert to pointer - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray) - { TypeSArray *ts = (TypeSArray *)tb; - if (ts->size(loc) == 0) - e = new NullExp(loc); - else - e = new AddrExp(loc, this); - e->type = ts->next->pointerTo(); - } -#endif - return e; -} - -/****************************** - * Take address of expression. - */ - -Expression *Expression::addressOf(Scope *sc) -{ - Expression *e; - Type *t = type; - - //printf("Expression::addressOf()\n"); - e = toLvalue(sc, NULL); - e = new AddrExp(loc, e); - e->type = t->pointerTo(); - return e; -} - -/****************************** - * If this is a reference, dereference it. - */ - -Expression *Expression::deref() -{ - //printf("Expression::deref()\n"); - // type could be null if forward referencing an 'auto' variable - if (type && type->ty == Treference) - { - Expression *e = new PtrExp(loc, this); - e->type = ((TypeReference *)type)->next; - return e; - } - return this; -} - -/******************************** - * Does this expression statically evaluate to a boolean TRUE or FALSE? - */ - -int Expression::isBool(int result) -{ - return FALSE; -} - -/******************************** - * Does this expression result in either a 1 or a 0? - */ - -int Expression::isBit() -{ - return FALSE; -} - -/**************************************** - * Resolve __LINE__ and __FILE__ to loc. - */ - -Expression *Expression::resolveLoc(Loc loc, Scope *sc) -{ - return this; -} - -Expressions *Expression::arraySyntaxCopy(Expressions *exps) -{ Expressions *a = NULL; - - if (exps) - { - a = new Expressions(); - a->setDim(exps->dim); - for (size_t i = 0; i < a->dim; i++) - { Expression *e = (*exps)[i]; - - if (e) - e = e->syntaxCopy(); - a->tdata()[i] = e; - } - } - return a; -} - -/*************************************************** - * Recognize expressions of the form: - * ((T v = init), v) - * where v is a temp. - * This is used in optimizing out unnecessary temporary generation. - * Returns initializer expression of v if so, NULL if not. - */ - -Expression *Expression::isTemp() -{ - //printf("isTemp() %s\n", toChars()); - if (op == TOKcomma) - { CommaExp *ec = (CommaExp *)this; - if (ec->e1->op == TOKdeclaration && - ec->e2->op == TOKvar) - { DeclarationExp *de = (DeclarationExp *)ec->e1; - VarExp *ve = (VarExp *)ec->e2; - if (ve->var == de->declaration && ve->var->storage_class & STCctfe) - { VarDeclaration *v = ve->var->isVarDeclaration(); - if (v && v->init) - { - ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { Expression *e = ei->exp; - if (e->op == TOKconstruct) - { ConstructExp *ce = (ConstructExp *)e; - if (ce->e1->op == TOKvar && ((VarExp *)ce->e1)->var == ve->var) - e = ce->e2; - } - return e; - } - } - } - } - } - return NULL; -} - -/************************************************ - * Destructors are attached to VarDeclarations. - * Hence, if expression returns a temp that needs a destructor, - * make sure and create a VarDeclaration for that temp. - */ - -Expression *Expression::addDtorHook(Scope *sc) -{ - return this; -} - -/******************************** IntegerExp **************************/ - -IntegerExp::IntegerExp(Loc loc, dinteger_t value, Type *type) - : Expression(loc, TOKint64, sizeof(IntegerExp)) -{ - //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type->toChars() : ""); - if (type && !type->isscalar()) - { - //printf("%s, loc = %d\n", toChars(), loc.linnum); - if (type->ty != Terror) - error("integral constant must be scalar type, not %s", type->toChars()); - type = Type::terror; - } - this->type = type; - this->value = value; -} - -IntegerExp::IntegerExp(dinteger_t value) - : Expression(0, TOKint64, sizeof(IntegerExp)) -{ - this->type = Type::tint32; - this->value = value; -} - -int IntegerExp::equals(Object *o) -{ IntegerExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKint64 && - ((ne = (IntegerExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - value == ne->value)) - return 1; - return 0; -} - -char *IntegerExp::toChars() -{ -#if 1 - return Expression::toChars(); -#else - static char buffer[sizeof(value) * 3 + 1]; - - sprintf(buffer, "%jd", value); - return buffer; -#endif -} - -dinteger_t IntegerExp::toInteger() -{ Type *t; - - t = type; - while (t) - { - switch (t->ty) - { - case Tbool: value = (value != 0); break; - case Tint8: value = (d_int8) value; break; - case Tchar: - case Tuns8: value = (d_uns8) value; break; - case Tint16: value = (d_int16) value; break; - case Twchar: - case Tuns16: value = (d_uns16) value; break; - case Tint32: value = (d_int32) value; break; - case Tdchar: - case Tuns32: value = (d_uns32) value; break; - case Tint64: value = (d_int64) value; break; - case Tuns64: value = (d_uns64) value; break; - case Tpointer: - if (PTRSIZE == 4) - value = (d_uns32) value; - else if (PTRSIZE == 8) - value = (d_uns64) value; - else - assert(0); - break; - - case Tenum: - { - TypeEnum *te = (TypeEnum *)t; - t = te->sym->memtype; - continue; - } - - case Ttypedef: - { - TypeTypedef *tt = (TypeTypedef *)t; - t = tt->sym->basetype; - continue; - } - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { - printf("e = %p, ty = %d\n", this, type->ty); - type->print(); - assert(0); - } - break; - } - break; - } - return value; -} - -real_t IntegerExp::toReal() -{ - Type *t; - - toInteger(); - t = type->toBasetype(); - if (t->ty == Tuns64) - return (real_t)(d_uns64)value; - else - return (real_t)(d_int64)value; -} - -real_t IntegerExp::toImaginary() -{ - return (real_t) 0; -} - -complex_t IntegerExp::toComplex() -{ - return toReal(); -} - -int IntegerExp::isBool(int result) -{ - int r = toInteger() != 0; - return result ? r : !r; -} - -Expression *IntegerExp::semantic(Scope *sc) -{ - if (!type) - { - // Determine what the type of this number is - dinteger_t number = value; - - if (number & 0x8000000000000000LL) - type = Type::tuns64; - else if (number & 0xFFFFFFFF80000000LL) - type = Type::tint64; - else - type = Type::tint32; - } - else - { if (!type->deco) - type = type->semantic(loc, sc); - } - return this; -} - -Expression *IntegerExp::toLvalue(Scope *sc, Expression *e) -{ - if (!e) - e = this; - else if (!loc.filename) - loc = e->loc; - e->error("constant %s is not an lvalue", e->toChars()); - return new ErrorExp(); -} - -void IntegerExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - dinteger_t v = toInteger(); - - if (type) - { Type *t = type; - - L1: - switch (t->ty) - { - case Tenum: - { TypeEnum *te = (TypeEnum *)t; - buf->printf("cast(%s)", te->sym->toChars()); - t = te->sym->memtype; - goto L1; - } - - case Ttypedef: - { TypeTypedef *tt = (TypeTypedef *)t; - buf->printf("cast(%s)", tt->sym->toChars()); - t = tt->sym->basetype; - goto L1; - } - - case Twchar: // BUG: need to cast(wchar) - case Tdchar: // BUG: need to cast(dchar) - if ((uinteger_t)v > 0xFF) - { - buf->printf("'\\U%08x'", (unsigned)v); - break; - } - case Tchar: - { - unsigned o = buf->offset; - if (v == '\'') - buf->writestring("'\\''"); - else if (isprint(v) && v != '\\') - buf->printf("'%c'", (int)v); - else - buf->printf("'\\x%02x'", (int)v); - if (hgs->ddoc) - escapeDdocString(buf, o); - break; - } - - case Tint8: - buf->writestring("cast(byte)"); - goto L2; - - case Tint16: - buf->writestring("cast(short)"); - goto L2; - - case Tint32: - L2: - buf->printf("%d", (int)v); - break; - - case Tuns8: - buf->writestring("cast(ubyte)"); - goto L3; - - case Tuns16: - buf->writestring("cast(ushort)"); - goto L3; - - case Tuns32: - L3: - buf->printf("%du", (unsigned)v); - break; - - case Tint64: - buf->printf("%jdL", v); - break; - - case Tuns64: - L4: - buf->printf("%juLU", v); - break; - - case Tbool: - buf->writestring((char *)(v ? "true" : "false")); - break; - - case Tpointer: - buf->writestring("cast("); - buf->writestring(t->toChars()); - buf->writeByte(')'); - if (PTRSIZE == 4) - goto L3; - else if (PTRSIZE == 8) - goto L4; - else - assert(0); - - default: - /* This can happen if errors, such as - * the type is painted on like in fromConstInitializer(). - */ - if (!global.errors) - { -#ifdef DEBUG - t->print(); -#endif - assert(0); - } - break; - } - } - else if (v & 0x8000000000000000LL) - buf->printf("0x%jx", v); - else - buf->printf("%jd", v); -} - -void IntegerExp::toMangleBuffer(OutBuffer *buf) -{ - if ((sinteger_t)value < 0) - buf->printf("N%jd", -value); - else - { - /* This is an awful hack to maintain backwards compatibility. - * There really always should be an 'i' before a number, but - * there wasn't in earlier implementations, so to maintain - * backwards compatibility it is only done if necessary to disambiguate. - * See bugzilla 3029 - */ - if (buf->offset > 0 && isdigit(buf->data[buf->offset - 1])) - buf->writeByte('i'); - - buf->printf("%jd", value); - } -} - -/******************************** ErrorExp **************************/ - -/* Use this expression for error recovery. - * It should behave as a 'sink' to prevent further cascaded error messages. - */ - -ErrorExp::ErrorExp() - : IntegerExp(0, 0, Type::terror) -{ - op = TOKerror; -} - -Expression *ErrorExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -void ErrorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__error"); -} - -/******************************** RealExp **************************/ - -RealExp::RealExp(Loc loc, real_t value, Type *type) - : Expression(loc, TOKfloat64, sizeof(RealExp)) -{ - //printf("RealExp::RealExp(%Lg)\n", value); - this->value = value; - this->type = type; -} - -char *RealExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1 + 1]; - -#ifdef IN_GCC - value.format(buffer, sizeof(buffer)); - if (type->isimaginary()) - strcat(buffer, "i"); -#else - sprintf(buffer, type->isimaginary() ? "%Lgi" : "%Lg", value); -#endif - assert(strlen(buffer) < sizeof(buffer)); - return mem.strdup(buffer); -} - -dinteger_t RealExp::toInteger() -{ -#ifdef IN_GCC - return toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t RealExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t RealExp::toReal() -{ - return type->isreal() ? value : 0; -} - -real_t RealExp::toImaginary() -{ - return type->isreal() ? 0 : value; -} - -complex_t RealExp::toComplex() -{ -#ifdef __DMC__ - return toReal() + toImaginary() * I; -#else - return complex_t(toReal(), toImaginary()); -#endif -} - -/******************************** - * Test to see if two reals are the same. - * Regard NaN's as equivalent. - * Regard +0 and -0 as different. - */ - -int RealEquals(real_t x1, real_t x2) -{ -// return (Port::isNan(x1) && Port::isNan(x2)) || -#if __APPLE__ - return (__inline_isnan(x1) && __inline_isnan(x2)) || -#else - return // special case nans - (isnan(x1) && isnan(x2)) || -#endif - // and zero, in order to distinguish +0 from -0 - (x1 == 0 && x2 == 0 && 1./x1 == 1./x2) || - // otherwise just compare - (x1 != 0. && x1 == x2); -} - -int RealExp::equals(Object *o) -{ RealExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKfloat64 && - ((ne = (RealExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(value, ne->value) - ) - ) - return 1; - return 0; -} - -Expression *RealExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tfloat64; - else - type = type->semantic(loc, sc); - return this; -} - -int RealExp::isBool(int result) -{ -#ifdef IN_GCC - return result ? (! value.isZero()) : (value.isZero()); -#else - return result ? (value != 0) - : (value == 0); -#endif -} - -void floatToBuffer(OutBuffer *buf, Type *type, real_t value) -{ - /* In order to get an exact representation, try converting it - * to decimal then back again. If it matches, use it. - * If it doesn't, fall back to hex, which is - * always exact. - */ - char buffer[25]; - sprintf(buffer, "%Lg", value); - assert(strlen(buffer) < sizeof(buffer)); -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; - real_t r = strtold(buffer, NULL); - __locale_decpoint = save; -#else - real_t r = strtold(buffer, NULL); -#endif - if (r == value) // if exact duplication - buf->writestring(buffer); - else - { -#ifdef __HAIKU__ // broken printf workaround - char buffer2[25]; - char *ptr = (char *)&value; - for(int i = 0; i < sizeof(value); i++) - snprintf(buffer2, sizeof(char), "%x", ptr[i]); - - buf->writestring(buffer2); -#else - buf->printf("%La", value); // ensure exact duplication -#endif - } - - if (type) - { - Type *t = type->toBasetype(); - switch (t->ty) - { - case Tfloat32: - case Timaginary32: - case Tcomplex32: - buf->writeByte('F'); - break; - - case Tfloat80: - case Timaginary80: - case Tcomplex80: - buf->writeByte('L'); - break; - - default: - break; - } - if (t->isimaginary()) - buf->writeByte('i'); - } -} - -void RealExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - floatToBuffer(buf, type, value); -} - -void realToMangleBuffer(OutBuffer *buf, real_t value) -{ - /* Rely on %A to get portable mangling. - * Must munge result to get only identifier characters. - * - * Possible values from %A => mangled result - * NAN => NAN - * -INF => NINF - * INF => INF - * -0X1.1BC18BA997B95P+79 => N11BC18BA997B95P79 - * 0X1.9P+2 => 19P2 - */ - -// if (Port::isNan(value)) -#if __APPLE__ - if (__inline_isnan(value)) -#else - if (isnan(value)) -#endif - buf->writestring("NAN"); // no -NAN bugs - else - { - char buffer[32]; - int n = sprintf(buffer, "%LA", value); - assert(n > 0 && n < sizeof(buffer)); - for (int i = 0; i < n; i++) - { char c = buffer[i]; - - switch (c) - { - case '-': - buf->writeByte('N'); - break; - - case '+': - case 'X': - case '.': - break; - - case '0': - if (i < 2) - break; // skip leading 0X - default: - buf->writeByte(c); - break; - } - } - } -} - -void RealExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('e'); - realToMangleBuffer(buf, value); -} - - -/******************************** ComplexExp **************************/ - -ComplexExp::ComplexExp(Loc loc, complex_t value, Type *type) - : Expression(loc, TOKcomplex80, sizeof(ComplexExp)) -{ - this->value = value; - this->type = type; - //printf("ComplexExp::ComplexExp(%s)\n", toChars()); -} - -char *ComplexExp::toChars() -{ - char buffer[sizeof(value) * 3 + 8 + 1]; - -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - sprintf(buffer, "(%s+%si)", buf1, buf2); -#else - sprintf(buffer, "(%Lg+%Lgi)", creall(value), cimagl(value)); - assert(strlen(buffer) < sizeof(buffer)); -#endif - return mem.strdup(buffer); -} - -dinteger_t ComplexExp::toInteger() -{ -#ifdef IN_GCC - return (sinteger_t) toReal().toInt(); -#else - return (sinteger_t) toReal(); -#endif -} - -uinteger_t ComplexExp::toUInteger() -{ -#ifdef IN_GCC - return (uinteger_t) toReal().toInt(); -#else - return (uinteger_t) toReal(); -#endif -} - -real_t ComplexExp::toReal() -{ - return creall(value); -} - -real_t ComplexExp::toImaginary() -{ - return cimagl(value); -} - -complex_t ComplexExp::toComplex() -{ - return value; -} - -int ComplexExp::equals(Object *o) -{ ComplexExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKcomplex80 && - ((ne = (ComplexExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - RealEquals(creall(value), creall(ne->value)) && - RealEquals(cimagl(value), cimagl(ne->value)) - ) - ) - return 1; - return 0; -} - -Expression *ComplexExp::semantic(Scope *sc) -{ - if (!type) - type = Type::tcomplex80; - else - type = type->semantic(loc, sc); - return this; -} - -int ComplexExp::isBool(int result) -{ - if (result) - return (bool)(value); - else - return !value; -} - -void ComplexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - /* Print as: - * (re+imi) - */ -#ifdef IN_GCC - char buf1[sizeof(value) * 3 + 8 + 1]; - char buf2[sizeof(value) * 3 + 8 + 1]; - creall(value).format(buf1, sizeof(buf1)); - cimagl(value).format(buf2, sizeof(buf2)); - buf->printf("(%s+%si)", buf1, buf2); -#else - buf->writeByte('('); - floatToBuffer(buf, type, creall(value)); - buf->writeByte('+'); - floatToBuffer(buf, type, cimagl(value)); - buf->writestring("i)"); -#endif -} - -void ComplexExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('c'); - real_t r = toReal(); - realToMangleBuffer(buf, r); - buf->writeByte('c'); // separate the two - r = toImaginary(); - realToMangleBuffer(buf, r); -} - -/******************************** IdentifierExp **************************/ - -IdentifierExp::IdentifierExp(Loc loc, Identifier *ident) - : Expression(loc, TOKidentifier, sizeof(IdentifierExp)) -{ - this->ident = ident; -} - -Expression *IdentifierExp::semantic(Scope *sc) -{ - Dsymbol *s; - Dsymbol *scopesym; - -#if LOGSEMANTIC - printf("IdentifierExp::semantic('%s')\n", ident->toChars()); -#endif - s = sc->search(loc, ident, &scopesym); - if (s) - { Expression *e; - WithScopeSymbol *withsym; - - /* See if the symbol was a member of an enclosing 'with' - */ - withsym = scopesym->isWithScopeSymbol(); - if (withsym) - { -#if DMDV2 - /* Disallow shadowing - */ - // First find the scope of the with - Scope *scwith = sc; - while (scwith->scopesym != scopesym) - { scwith = scwith->enclosing; - assert(scwith); - } - // Look at enclosing scopes for symbols with the same name, - // in the same function - for (Scope *scx = scwith; scx && scx->func == scwith->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("with symbol %s is shadowing local symbol %s", s->toPrettyChars(), s2->toPrettyChars()); - return new ErrorExp(); - } - } -#endif - s = s->toAlias(); - - // Same as wthis.ident - if (s->needThis() || s->isTemplateDeclaration()) - { - e = new VarExp(loc, withsym->withstate->wthis); - e = new DotIdExp(loc, e, ident); - } - else - { Type *t = withsym->withstate->wthis->type; - if (t->ty == Tpointer) - t = ((TypePointer *)t)->next; - e = typeDotIdExp(loc, t, ident); - } - } - else - { - /* If f is really a function template, - * then replace f with the function template declaration. - */ - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { TemplateDeclaration *tempdecl = getFuncTemplateDecl(f); - if (tempdecl) - { - if (tempdecl->overroot) // if not start of overloaded list of TemplateDeclaration's - tempdecl = tempdecl->overroot; // then get the start - e = new TemplateExp(loc, tempdecl); - e = e->semantic(sc); - return e; - } - } - // Haven't done overload resolution yet, so pass 1 - e = new DsymbolExp(loc, s, 1); - } - return e->semantic(sc); - } -#if DMDV2 - if (hasThis(sc)) - { - AggregateDeclaration *ad = sc->getStructClassScope(); - if (ad && ad->aliasthis) - { - Expression *e; - e = new IdentifierExp(loc, Id::This); - e = new DotIdExp(loc, e, ad->aliasthis->ident); - e = new DotIdExp(loc, e, ident); - e = e->trySemantic(sc); - if (e) - return e; - } - } - if (ident == Id::ctfe) - { // Create the magic __ctfe bool variable - VarDeclaration *vd = new VarDeclaration(loc, Type::tbool, Id::ctfe, NULL); - Expression *e = new VarExp(loc, vd); - e = e->semantic(sc); - return e; - } -#endif - const char *n = importHint(ident->toChars()); - if (n) - error("'%s' is not defined, perhaps you need to import %s; ?", ident->toChars(), n); - else - { - s = sc->search_correct(ident); - if (s) - error("undefined identifier %s, did you mean %s %s?", ident->toChars(), s->kind(), s->toChars()); - else - error("undefined identifier %s", ident->toChars()); - } - return new ErrorExp(); -} - -char *IdentifierExp::toChars() -{ - return ident->toChars(); -} - -void IdentifierExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - buf->writestring(ident->toHChars2()); - else - buf->writestring(ident->toChars()); -} - -#if DMDV2 -int IdentifierExp::isLvalue() -{ - return 1; -} -#endif - -Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** DollarExp **************************/ - -DollarExp::DollarExp(Loc loc) - : IdentifierExp(loc, Id::dollar) -{ -} - -/******************************** DsymbolExp **************************/ - -DsymbolExp::DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads) - : Expression(loc, TOKdsymbol, sizeof(DsymbolExp)) -{ - this->s = s; - this->hasOverloads = hasOverloads; -} - -Expression *DsymbolExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DsymbolExp::semantic('%s')\n", s->toChars()); -#endif - -Lagain: - EnumMember *em; - Expression *e; - VarDeclaration *v; - FuncDeclaration *f; - FuncLiteralDeclaration *fld; - OverloadSet *o; - ClassDeclaration *cd; - ClassDeclaration *thiscd = NULL; - Import *imp; - Package *pkg; - Type *t; - - //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars()); - //printf("s = '%s', s->kind = '%s'\n", s->toChars(), s->kind()); - if (type) - return this; - if (!s->isFuncDeclaration()) // functions are checked after overloading - checkDeprecated(sc, s); - Dsymbol *olds = s; - s = s->toAlias(); - //printf("s = '%s', s->kind = '%s', s->needThis() = %p\n", s->toChars(), s->kind(), s->needThis()); - if (s != olds && !s->isFuncDeclaration()) - checkDeprecated(sc, s); - - if (sc->func) - thiscd = sc->func->parent->isClassDeclaration(); - - // BUG: This should happen after overload resolution for functions, not before - if (s->needThis()) - { - if (hasThis(sc) -#if DMDV2 - && !s->isFuncDeclaration() -#endif - ) - { - // Supply an implicit 'this', as in - // this.ident - - DotVarExp *de; - - de = new DotVarExp(loc, new ThisExp(loc), s->isDeclaration()); - return de->semantic(sc); - } - } - - em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - v = s->isVarDeclaration(); - if (v) - { - //printf("Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (!type) - { if ((!v->type || !v->type->deco) && v->scope) - v->semantic(v->scope); - type = v->type; - if (!v->type) - { error("forward reference of %s %s", v->kind(), v->toChars()); - return new ErrorExp(); - } - } - - if ((v->storage_class & STCmanifest) && v->init) - { - e = v->init->toExpression(); - if (!e) - { error("cannot make expression out of initializer for %s", v->toChars()); - return new ErrorExp(); - } - e = e->copy(); - e->loc = loc; // for better error message - e = e->semantic(sc); - return e; - } - - e = new VarExp(loc, v); - e->type = type; - e = e->semantic(sc); - return e->deref(); - } - fld = s->isFuncLiteralDeclaration(); - if (fld) - { //printf("'%s' is a function literal\n", fld->toChars()); - e = new FuncExp(loc, fld); - return e->semantic(sc); - } - f = s->isFuncDeclaration(); - if (f) - { //printf("'%s' is a function\n", f->toChars()); - - if (!f->originalType && f->scope) // semantic not yet run - f->semantic(f->scope); - - // if inferring return type, sematic3 needs to be run - if (f->inferRetType && f->scope && f->type && !f->type->nextOf()) - { - TemplateInstance *spec = isSpeculativeFunction(f); - int olderrs = global.errors; - f->semantic3(f->scope); - // Update the template instantiation with the number - // of errors which occured. - if (spec && global.errors != olderrs) - spec->errors = global.errors - olderrs; - } - - if (f->isUnitTestDeclaration()) - { - error("cannot call unittest function %s", toChars()); - return new ErrorExp(); - } - if (!f->type->deco) - { - error("forward reference to %s", toChars()); - return new ErrorExp(); - } - return new VarExp(loc, f, hasOverloads); - } - o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } - cd = s->isClassDeclaration(); - if (cd && thiscd && cd->isBaseOf(thiscd, NULL) && sc->func->needThis()) - { - // We need to add an implicit 'this' if cd is this class or a base class. - DotTypeExp *dte; - - dte = new DotTypeExp(loc, new ThisExp(loc), s); - return dte->semantic(sc); - } - imp = s->isImport(); - if (imp) - { - if (!imp->pkg) - { error("forward reference of import %s", imp->toChars()); - return new ErrorExp(); - } - ScopeExp *ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - pkg = s->isPackage(); - if (pkg) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, pkg); - return ie->semantic(sc); - } - Module *mod = s->isModule(); - if (mod) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, mod); - return ie->semantic(sc); - } - - t = s->getType(); - if (t) - { - TypeExp *te = new TypeExp(loc, t); - return te->semantic(sc); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti && !global.errors) - { if (!ti->semanticRun) - ti->semantic(sc); - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto Lagain; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { -#if 0 // This was the fix for Bugzilla 6738, but it breaks 7498 - Dsymbol *p = td->toParent2(); - if (hasThis(sc) && p && p->isAggregateDeclaration()) - e = new DotTemplateExp(loc, new ThisExp(loc), td); - else -#endif - e = new TemplateExp(loc, td); - e = e->semantic(sc); - return e; - } - - error("%s '%s' is not a variable", s->kind(), s->toChars()); - return new ErrorExp(); -} - -char *DsymbolExp::toChars() -{ - return s->toChars(); -} - -void DsymbolExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(s->toChars()); -} - -#if DMDV2 -int DsymbolExp::isLvalue() -{ - return 1; -} -#endif - -Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -/******************************** ThisExp **************************/ - -ThisExp::ThisExp(Loc loc) - : Expression(loc, TOKthis, sizeof(ThisExp)) -{ - //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); - var = NULL; -} - -Expression *ThisExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("ThisExp::semantic()\n"); -#endif - if (type && var) - { //assert(global.errors || var); -#if IN_LLVM - var->isVarDeclaration()->checkNestedReference(sc, loc); -#endif - return this; - } - - FuncDeclaration *fd = hasThis(sc); // fd is the uplevel function with the 'this' variable - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (!fd && sc->intypeof) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) - { - if (!s) - { - error("%s is not in a class or struct scope", toChars()); - goto Lerr; - } - ClassDeclaration *cd = s->isClassDeclaration(); - if (cd) - { - type = cd->type; - return this; - } - StructDeclaration *sd = s->isStructDeclaration(); - if (sd) - { -#if STRUCTTHISREF - type = sd->type; -#else - type = sd->type->pointerTo(); -#endif - return this; - } - } - } - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - if (!type) - type = var->type; - var->isVarDeclaration()->checkNestedReference(sc, loc); - if (!sc->intypeof) - sc->callSuper |= CSXthis; - return this; - -Lerr: - error("'this' is only defined in non-static member functions, not %s", sc->parent->toChars()); - return new ErrorExp(); -} - -int ThisExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void ThisExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this"); -} - -#if DMDV2 -int ThisExp::isLvalue() -{ - return 1; -} -#endif - -Expression *ThisExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -/******************************** SuperExp **************************/ - -SuperExp::SuperExp(Loc loc) - : ThisExp(loc) -{ - op = TOKsuper; -} - -Expression *SuperExp::semantic(Scope *sc) -{ - ClassDeclaration *cd; - Dsymbol *s; - -#if LOGSEMANTIC - printf("SuperExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - FuncDeclaration *fd = hasThis(sc); - - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (!fd && sc->intypeof) - { - // Find enclosing class - for (Dsymbol *s = sc->getStructClassScope(); 1; s = s->parent) - { - if (!s) - { - error("%s is not in a class scope", toChars()); - goto Lerr; - } - ClassDeclaration *cd = s->isClassDeclaration(); - if (cd) - { - cd = cd->baseClass; - if (!cd) - { error("class %s has no 'super'", s->toChars()); - goto Lerr; - } - type = cd->type; - return this; - } - } - } - if (!fd) - goto Lerr; - - assert(fd->vthis); - var = fd->vthis; - assert(var->parent); - - s = fd->toParent(); - while (s && s->isTemplateInstance()) - s = s->toParent(); - assert(s); - cd = s->isClassDeclaration(); -//printf("parent is %s %s\n", fd->toParent()->kind(), fd->toParent()->toChars()); - if (!cd) - goto Lerr; - if (!cd->baseClass) - { - error("no base class for %s", cd->toChars()); - type = fd->vthis->type; - } - else - { - type = cd->baseClass->type; - type = type->castMod(var->type->mod); - } - - var->isVarDeclaration()->checkNestedReference(sc, loc); - - if (!sc->intypeof) - sc->callSuper |= CSXsuper; - return this; - - -Lerr: - error("'super' is only allowed in non-static class member functions"); - return new ErrorExp(); -} - -void SuperExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("super"); -} - - -/******************************** NullExp **************************/ - -NullExp::NullExp(Loc loc, Type *type) - : Expression(loc, TOKnull, sizeof(NullExp)) -{ - committed = 0; - this->type = type; -} - -int NullExp::equals(Object *o) -{ - if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - - if (e->op == TOKnull) - return TRUE; - } - return FALSE; -} - -Expression *NullExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NullExp::semantic('%s')\n", toChars()); -#endif - // NULL is the same as (void *)0 - if (!type) - type = Type::tnull; - return this; -} - -int NullExp::isBool(int result) -{ - return result ? FALSE : TRUE; -} - -StringExp *NullExp::toString() -{ - if (implicitConvTo(Type::tstring)) - { - StringExp *se = new StringExp(loc, (char*)mem.calloc(1, 1), 0); - se->type = Type::tstring; - return se; - } - return NULL; -} - -void NullExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("null"); -} - -void NullExp::toMangleBuffer(OutBuffer *buf) -{ - buf->writeByte('n'); -} - -/******************************** StringExp **************************/ - -StringExp::StringExp(Loc loc, char *string) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = strlen(string); - this->sz = 1; - this->committed = 0; - this->postfix = 0; - this->ownedByCtfe = false; -} - -StringExp::StringExp(Loc loc, void *string, size_t len) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = 0; - this->ownedByCtfe = false; -} - -StringExp::StringExp(Loc loc, void *string, size_t len, unsigned char postfix) - : Expression(loc, TOKstring, sizeof(StringExp)) -{ - this->string = string; - this->len = len; - this->sz = 1; - this->committed = 0; - this->postfix = postfix; - this->ownedByCtfe = false; -} - -#if 0 -Expression *StringExp::syntaxCopy() -{ - printf("StringExp::syntaxCopy() %s\n", toChars()); - return copy(); -} -#endif - -int StringExp::equals(Object *o) -{ - //printf("StringExp::equals('%s') %s\n", o->toChars(), toChars()); - if (o && o->dyncast() == DYNCAST_EXPRESSION) - { Expression *e = (Expression *)o; - - if (e->op == TOKstring) - { - return compare(o) == 0; - } - } - return FALSE; -} - -char *StringExp::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *p; - - memset(&hgs, 0, sizeof(hgs)); - toCBuffer(&buf, &hgs); - buf.writeByte(0); - p = (char *)buf.data; - buf.data = NULL; - return p; -} - -Expression *StringExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("StringExp::semantic() %s\n", toChars()); -#endif - if (!type) - { OutBuffer buffer; - size_t newlen = 0; - const char *p; - size_t u; - unsigned c; - - switch (postfix) - { - case 'd': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return new ErrorExp(); - } - else - { buffer.write4(c); - newlen++; - } - } - buffer.write4(0); - string = buffer.extractData(); - len = newlen; - sz = 4; - //type = new TypeSArray(Type::tdchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::tdchar->invariantOf()); - committed = 1; - break; - - case 'w': - for (u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return new ErrorExp(); - } - else - { buffer.writeUTF16(c); - newlen++; - if (c >= 0x10000) - newlen++; - } - } - buffer.writeUTF16(0); - string = buffer.extractData(); - len = newlen; - sz = 2; - //type = new TypeSArray(Type::twchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::twchar->invariantOf()); - committed = 1; - break; - - case 'c': - committed = 1; - default: - //type = new TypeSArray(Type::tchar, new IntegerExp(loc, len, Type::tindex)); - type = new TypeDArray(Type::tchar->invariantOf()); - break; - } - type = type->semantic(loc, sc); - //type = type->invariantOf(); - //printf("type = %s\n", type->toChars()); - } - return this; -} - -/********************************** - * Return length of string. - */ - -size_t StringExp::length() -{ - size_t result = 0; - dchar_t c; - const char *p; - - switch (sz) - { - case 1: - for (size_t u = 0; u < len;) - { - p = utf_decodeChar((unsigned char *)string, len, &u, &c); - if (p) - { error("%s", p); - return 0; - } - else - result++; - } - break; - - case 2: - for (size_t u = 0; u < len;) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - { error("%s", p); - return 0; - } - else - result++; - } - break; - - case 4: - result = len; - break; - - default: - assert(0); - } - return result; -} - -StringExp *StringExp::toString() -{ - return this; -} - -/**************************************** - * Convert string to char[]. - */ - -StringExp *StringExp::toUTF8(Scope *sc) -{ - if (sz != 1) - { // Convert to UTF-8 string - committed = 0; - Expression *e = castTo(sc, Type::tchar->arrayOf()); - e = e->optimize(WANTvalue); - assert(e->op == TOKstring); - StringExp *se = (StringExp *)e; - assert(se->sz == 1); - return se; - } - return this; -} - -int StringExp::compare(Object *obj) -{ - //printf("StringExp::compare()\n"); - // Used to sort case statement expressions so we can do an efficient lookup - StringExp *se2 = (StringExp *)(obj); - - // This is a kludge so isExpression() in template.c will return 5 - // for StringExp's. - if (!se2) - return 5; - - assert(se2->op == TOKstring); - - int len1 = len; - int len2 = se2->len; - - //printf("sz = %d, len1 = %d, len2 = %d\n", sz, len1, len2); - if (len1 == len2) - { - switch (sz) - { - case 1: - return memcmp((char *)string, (char *)se2->string, len1); - - case 2: - { unsigned u; - d_wchar *s1 = (d_wchar *)string; - d_wchar *s2 = (d_wchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - - case 4: - { unsigned u; - d_dchar *s1 = (d_dchar *)string; - d_dchar *s2 = (d_dchar *)se2->string; - - for (u = 0; u < len; u++) - { - if (s1[u] != s2[u]) - return s1[u] - s2[u]; - } - } - break; - - default: - assert(0); - } - } - return len1 - len2; -} - -int StringExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -#if DMDV2 -int StringExp::isLvalue() -{ - /* string literal is rvalue in default, but - * conversion to reference of static array is only allowed. - */ - return 0; -} -#endif - -Expression *StringExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("StringExp::toLvalue(%s)\n", toChars()); - return this; -} - -Expression *StringExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("Cannot modify '%s'", toChars()); - return new ErrorExp(); -} - -unsigned StringExp::charAt(size_t i) -{ unsigned value; - - switch (sz) - { - case 1: - value = ((unsigned char *)string)[i]; - break; - - case 2: - value = ((unsigned short *)string)[i]; - break; - - case 4: - value = ((unsigned int *)string)[i]; - break; - - default: - assert(0); - break; - } - return value; -} - -void StringExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('"'); - unsigned o = buf->offset; - for (size_t i = 0; i < len; i++) - { unsigned c = charAt(i); - - switch (c) - { - case '"': - case '\\': - if (!hgs->console) - buf->writeByte('\\'); - default: - if (c <= 0xFF) - { if (c <= 0x7F && (isprint(c) || hgs->console)) - buf->writeByte(c); - else - buf->printf("\\x%02x", c); - } - else if (c <= 0xFFFF) - buf->printf("\\x%02x\\x%02x", c & 0xFF, c >> 8); - else - buf->printf("\\x%02x\\x%02x\\x%02x\\x%02x", - c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24); - break; - } - } - if (hgs->ddoc) - escapeDdocString(buf, o); - buf->writeByte('"'); - if (postfix) - buf->writeByte(postfix); -} - -void StringExp::toMangleBuffer(OutBuffer *buf) -{ char m; - OutBuffer tmp; - const char *p; - unsigned c; - size_t u; - unsigned char *q; - unsigned qlen; - - /* Write string in UTF-8 format - */ - switch (sz) - { case 1: - m = 'a'; - q = (unsigned char *)string; - qlen = len; - break; - case 2: - m = 'w'; - for (u = 0; u < len; ) - { - p = utf_decodeWchar((unsigned short *)string, len, &u, &c); - if (p) - error("%s", p); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - case 4: - m = 'd'; - for (u = 0; u < len; u++) - { - c = ((unsigned *)string)[u]; - if (!utf_isValidDchar(c)) - error("invalid UCS-32 char \\U%08x", c); - else - tmp.writeUTF8(c); - } - q = tmp.data; - qlen = tmp.offset; - break; - default: - assert(0); - } - buf->reserve(1 + 11 + 2 * qlen); - buf->writeByte(m); - buf->printf("%d_", qlen); // nbytes <= 11 - - for (unsigned char *p = buf->data + buf->offset, *pend = p + 2 * qlen; - p < pend; p += 2, ++q) - { - unsigned char hi = *q >> 4 & 0xF; - p[0] = (hi < 10 ? hi + '0' : hi - 10 + 'a'); - unsigned char lo = *q & 0xF; - p[1] = (lo < 10 ? lo + '0' : lo - 10 + 'a'); - } - buf->offset += 2 * qlen; -} - -/************************ ArrayLiteralExp ************************************/ - -// [ e1, e2, e3, ... ] - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expressions *elements) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - this->elements = elements; - this->ownedByCtfe = false; -} - -ArrayLiteralExp::ArrayLiteralExp(Loc loc, Expression *e) - : Expression(loc, TOKarrayliteral, sizeof(ArrayLiteralExp)) -{ - elements = new Expressions; - elements->push(e); -} - -Expression *ArrayLiteralExp::syntaxCopy() -{ - return new ArrayLiteralExp(loc, arraySyntaxCopy(elements)); -} - -Expression *ArrayLiteralExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("ArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - /* Perhaps an empty array literal [ ] should be rewritten as null? - */ - - arrayExpressionSemantic(elements, sc); // run semantic() on each element - expandTuples(elements); - - Type *t0; - elements = arrayExpressionToCommonType(sc, elements, &t0); - - type = t0->arrayOf(); - //type = new TypeSArray(t0, new IntegerExp(elements->dim)); - type = type->semantic(loc, sc); - - /* Disallow array literals of type void being used. - */ - if (elements->dim > 0 && t0->ty == Tvoid) - { error("%s of type %s has no value", toChars(), type->toChars()); - return new ErrorExp(); - } - - return this; -} - -int ArrayLiteralExp::isBool(int result) -{ - size_t dim = elements ? elements->dim : 0; - return result ? (dim != 0) : (dim == 0); -} - -StringExp *ArrayLiteralExp::toString() -{ - TY telem = type->nextOf()->toBasetype()->ty; - - if (telem == Tchar || telem == Twchar || telem == Tdchar || - (telem == Tvoid && (!elements || elements->dim == 0))) - { - OutBuffer buf; - if (elements) - for (int i = 0; i < elements->dim; ++i) - { - Expression *ch = elements->tdata()[i]; - if (ch->op != TOKint64) - return NULL; - buf.writedchar(ch->toInteger()); - } - buf.writebyte(0); - - char prefix = 'c'; - if (telem == Twchar) prefix = 'w'; - else if (telem == Tdchar) prefix = 'd'; - - StringExp *se = new StringExp(loc, buf.extractData(), buf.size - 1, prefix); - se->type = type; - return se; - } - return NULL; -} - -void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(']'); -} - -void ArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("A%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; - e->toMangleBuffer(buf); - } -} - -/************************ AssocArrayLiteralExp ************************************/ - -// [ key0 : value0, key1 : value1, ... ] - -AssocArrayLiteralExp::AssocArrayLiteralExp(Loc loc, - Expressions *keys, Expressions *values) - : Expression(loc, TOKassocarrayliteral, sizeof(AssocArrayLiteralExp)) -{ - assert(keys->dim == values->dim); - this->keys = keys; - this->values = values; - this->ownedByCtfe = false; -} - -Expression *AssocArrayLiteralExp::syntaxCopy() -{ - return new AssocArrayLiteralExp(loc, - arraySyntaxCopy(keys), arraySyntaxCopy(values)); -} - -Expression *AssocArrayLiteralExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssocArrayLiteralExp::semantic('%s')\n", toChars()); -#endif - - if (type) - return this; - - // Run semantic() on each element - arrayExpressionSemantic(keys, sc); - arrayExpressionSemantic(values, sc); - expandTuples(keys); - expandTuples(values); - if (keys->dim != values->dim) - { - error("number of keys is %u, must match number of values %u", keys->dim, values->dim); - return new ErrorExp(); - } - - Type *tkey = NULL; - Type *tvalue = NULL; - keys = arrayExpressionToCommonType(sc, keys, &tkey); - values = arrayExpressionToCommonType(sc, values, &tvalue); - - type = new TypeAArray(tvalue, tkey); - type = type->semantic(loc, sc); - return this; -} - - -int AssocArrayLiteralExp::isBool(int result) -{ - size_t dim = keys->dim; - return result ? (dim != 0) : (dim == 0); -} - -void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('['); - for (size_t i = 0; i < keys->dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; - - if (i) - buf->writeByte(','); - expToCBuffer(buf, hgs, key, PREC_assign); - buf->writeByte(':'); - expToCBuffer(buf, hgs, value, PREC_assign); - } - buf->writeByte(']'); -} - -void AssocArrayLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = keys->dim; - buf->printf("A%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *key = keys->tdata()[i]; - Expression *value = values->tdata()[i]; - - key->toMangleBuffer(buf); - value->toMangleBuffer(buf); - } -} - -/************************ StructLiteralExp ************************************/ - -// sd( e1, e2, e3, ... ) - -StructLiteralExp::StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype) - : Expression(loc, TOKstructliteral, sizeof(StructLiteralExp)) -{ - this->sd = sd; - this->elements = elements; - this->stype = stype; -#if IN_DMD - this->sym = NULL; -#endif - this->soffset = 0; - this->fillHoles = 1; - this->ownedByCtfe = false; -#if IN_LLVM - constType = NULL; -#endif -} - -Expression *StructLiteralExp::syntaxCopy() -{ - return new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), stype); -} - -Expression *StructLiteralExp::semantic(Scope *sc) -{ Expression *e; - size_t nfields = sd->fields.dim - sd->isnested; - -#if LOGSEMANTIC - printf("StructLiteralExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - elements = arrayExpressionSemantic(elements, sc); // run semantic() on each element - expandTuples(elements); - size_t offset = 0; - for (size_t i = 0; i < elements->dim; i++) - { e = elements->tdata()[i]; - if (!e) - continue; - - e = resolveProperties(sc, e); - if (i >= nfields) - { error("more initializers than fields of %s", sd->toChars()); - return new ErrorExp(); - } - Dsymbol *s = sd->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - if (v->offset < offset) - { error("overlapping initialization for %s", v->toChars()); - return new ErrorExp(); - } - offset = v->offset + v->type->size(); - - Type *telem = v->type; - if (stype) - telem = telem->addMod(stype->mod); - while (!e->implicitConvTo(telem) && telem->toBasetype()->ty == Tsarray) - { /* Static array initialization, as in: - * T[3][5] = e; - */ - telem = telem->toBasetype()->nextOf(); - } - - if (e->op == TOKfunction) - { e = ((FuncExp *)e)->inferType(sc, telem); - if (!e) - { error("cannot infer function literal type from %s", telem->toChars()); - e = new ErrorExp(); - } - } - - e = e->implicitCastTo(sc, telem); - - elements->tdata()[i] = e; - } - - /* Fill out remainder of elements[] with default initializers for fields[] - */ - for (size_t i = elements->dim; i < nfields; i++) - { Dsymbol *s = sd->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - assert(!v->isThisDeclaration()); - - if (v->offset < offset) - { e = NULL; - sd->hasUnions = 1; - } - else - { - if (v->init) - { if (v->init->isVoidInitializer()) - e = NULL; - else - { e = v->init->toExpression(); - if (!e) - { error("cannot make expression out of initializer for %s", v->toChars()); - return new ErrorExp(); - } - else if (v->scope) - { // Do deferred semantic analysis - Initializer *i2 = v->init->syntaxCopy(); - i2 = i2->semantic(v->scope, v->type, WANTinterpret); - e = i2->toExpression(); - // remove v->scope (see bug 3426) - // but not if gagged, for we might be called again. - if (!global.gag) - v->scope = NULL; - } - } - } - else - e = v->type->defaultInitLiteral(loc); - offset = v->offset + v->type->size(); - } - elements->push(e); - } - - type = stype ? stype : sd->type; - - /* If struct requires a destructor, rewrite as: - * (S tmp = S()),tmp - * so that the destructor can be hung on tmp. - */ - if (sd->dtor && sc->func) - { - Identifier *idtmp = Lexer::uniqueId("__sl"); - VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(0, this)); - tmp->storage_class |= STCctfe; - Expression *ae = new DeclarationExp(loc, tmp); - Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - return e; - } - - return this; -} - -/************************************** - * Gets expression at offset of type. - * Returns NULL if not found. - */ - -Expression *StructLiteralExp::getField(Type *type, unsigned offset) -{ - //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n", -// /*toChars()*/"", type->toChars(), offset); - Expression *e = NULL; - int i = getFieldIndex(type, offset); - - if (i != -1) - { - //printf("\ti = %d\n", i); - assert(i < elements->dim); - e = elements->tdata()[i]; - if (e) - { - //printf("e = %s, e->type = %s\n", e->toChars(), e->type->toChars()); - - /* If type is a static array, and e is an initializer for that array, - * then the field initializer should be an array literal of e. - */ - if (e->type->castMod(0) != type->castMod(0) && type->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)type; - uinteger_t length = tsa->dim->toInteger(); - Expressions *z = new Expressions; - z->setDim(length); - for (int q = 0; q < length; ++q) - z->tdata()[q] = e->copy(); - e = new ArrayLiteralExp(loc, z); - e->type = type; - } - else - { - e = e->copy(); - e->type = type; - } - } - } - return e; -} - -/************************************ - * Get index of field. - * Returns -1 if not found. - */ - -int StructLiteralExp::getFieldIndex(Type *type, unsigned offset) -{ - /* Find which field offset is by looking at the field offsets - */ - if (elements->dim) - { - for (size_t i = 0; i < sd->fields.dim; i++) - { - Dsymbol *s = sd->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - - if (offset == v->offset && - type->size() == v->type->size()) - { Expression *e = elements->tdata()[i]; - if (e) - { - return i; - } - break; - } - } - } - return -1; -} - -#if DMDV2 -int StructLiteralExp::isLvalue() -{ - return 1; -} -#endif - -Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - - -void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(sd->toChars()); - buf->writeByte('('); - argsToCBuffer(buf, elements, hgs); - buf->writeByte(')'); -} - -void StructLiteralExp::toMangleBuffer(OutBuffer *buf) -{ - size_t dim = elements ? elements->dim : 0; - buf->printf("S%zu", dim); - for (size_t i = 0; i < dim; i++) - { Expression *e = elements->tdata()[i]; - if (e) - e->toMangleBuffer(buf); - else - buf->writeByte('v'); // 'v' for void - } -} - -/************************ TypeDotIdExp ************************************/ - -/* Things like: - * int.size - * foo.size - * (foo).size - * cast(foo).size - */ - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident) -{ - return new DotIdExp(loc, new TypeExp(loc, type), ident); -} - - -/************************************************************/ - -// Mainly just a placeholder - -TypeExp::TypeExp(Loc loc, Type *type) - : Expression(loc, TOKtype, sizeof(TypeExp)) -{ - //printf("TypeExp::TypeExp(%s)\n", type->toChars()); - this->type = type; -} - -Expression *TypeExp::syntaxCopy() -{ - //printf("TypeExp::syntaxCopy()\n"); - return new TypeExp(loc, type->syntaxCopy()); -} - -Expression *TypeExp::semantic(Scope *sc) -{ - //printf("TypeExp::semantic(%s)\n", type->toChars()); - type = type->semantic(loc, sc); - return this; -} - -int TypeExp::rvalue() -{ - error("type %s has no value", toChars()); - return 0; -} - -void TypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - type->toCBuffer(buf, NULL, hgs); -} - -/************************************************************/ - -// Mainly just a placeholder - -ScopeExp::ScopeExp(Loc loc, ScopeDsymbol *pkg) - : Expression(loc, TOKimport, sizeof(ScopeExp)) -{ - //printf("ScopeExp::ScopeExp(pkg = '%s')\n", pkg->toChars()); - //static int count; if (++count == 38) *(char*)0=0; - this->sds = pkg; -} - -Expression *ScopeExp::syntaxCopy() -{ - ScopeExp *se = new ScopeExp(loc, (ScopeDsymbol *)sds->syntaxCopy(NULL)); - return se; -} - -Expression *ScopeExp::semantic(Scope *sc) -{ - TemplateInstance *ti; - ScopeDsymbol *sds2; - -#if LOGSEMANTIC - printf("+ScopeExp::semantic('%s')\n", toChars()); -#endif -Lagain: - ti = sds->isTemplateInstance(); - if (ti && !global.errors) - { - if (!ti->semanticRun) - ti->semantic(sc); - if (ti->inst) - { - Dsymbol *s = ti->inst->toAlias(); - sds2 = s->isScopeDsymbol(); - if (!sds2) - { Expression *e; - - //printf("s = %s, '%s'\n", s->kind(), s->toChars()); - if (ti->withsym) - { - // Same as wthis.s - e = new VarExp(loc, ti->withsym->withstate->wthis); - e = new DotVarExp(loc, e, s->isDeclaration()); - } - else - e = new DsymbolExp(loc, s); - e = e->semantic(sc); - //printf("-1ScopeExp::semantic()\n"); - return e; - } - if (sds2 != sds) - { - sds = sds2; - goto Lagain; - } - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - } - if (global.errors) - return new ErrorExp(); - } - else - { - //printf("sds = %s, '%s'\n", sds->kind(), sds->toChars()); - //printf("\tparent = '%s'\n", sds->parent->toChars()); - sds->semantic(sc); - - AggregateDeclaration *ad = sds->isAggregateDeclaration(); - if (ad) - return (new TypeExp(loc, ad->type))->semantic(sc); - } - type = Type::tvoid; - //printf("-2ScopeExp::semantic() %s\n", toChars()); - return this; -} - -void ScopeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (sds->isTemplateInstance()) - { - sds->toCBuffer(buf, hgs); - } - else if (hgs != NULL && hgs->ddoc) - { // fixes bug 6491 - Module *module = sds->isModule(); - if (module) - buf->writestring(module->md->toChars()); - else - buf->writestring(sds->toChars()); - } - else - { - buf->writestring(sds->kind()); - buf->writestring(" "); - buf->writestring(sds->toChars()); - } -} - -/********************** TemplateExp **************************************/ - -// Mainly just a placeholder - -TemplateExp::TemplateExp(Loc loc, TemplateDeclaration *td) - : Expression(loc, TOKtemplate, sizeof(TemplateExp)) -{ - //printf("TemplateExp(): %s\n", td->toChars()); - this->td = td; -} - -void TemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(td->toChars()); -} - -int TemplateExp::rvalue() -{ - error("template %s has no value", toChars()); - return 0; -} - -/********************** NewExp **************************************/ - -/* thisexp.new(newargs) newtype(arguments) */ - -NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments) - : Expression(loc, TOKnew, sizeof(NewExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->newtype = newtype; - this->arguments = arguments; - member = NULL; - allocator = NULL; - onstack = 0; -} - -Expression *NewExp::syntaxCopy() -{ - return new NewExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - newtype->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *NewExp::semantic(Scope *sc) -{ - Type *tb; - ClassDeclaration *cdthis = NULL; - -#if LOGSEMANTIC - printf("NewExp::semantic() %s\n", toChars()); - if (thisexp) - printf("\tthisexp = %s\n", thisexp->toChars()); - printf("\tnewtype: %s\n", newtype->toChars()); -#endif - if (type) // if semantic() already run - return this; - -Lagain: - if (thisexp) - { thisexp = thisexp->semantic(sc); - cdthis = thisexp->type->isClassHandle(); - if (cdthis) - { - sc = sc->push(cdthis); - type = newtype->semantic(loc, sc); - sc = sc->pop(); - } - else - { - error("'this' for nested class must be a class type, not %s", thisexp->type->toChars()); - goto Lerr; - } - } - else - type = newtype->semantic(loc, sc); - newtype = type; // in case type gets cast to something else - tb = type->toBasetype(); - //printf("tb: %s, deco = %s\n", tb->toChars(), tb->deco); - - arrayExpressionSemantic(newargs, sc); - preFunctionParameters(loc, sc, newargs); - arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - - if (thisexp && tb->ty != Tclass) - { error("e.new is only for allocating nested classes, not %s", tb->toChars()); - goto Lerr; - } - - if (tb->ty == Tclass) - { - TypeClass *tc = (TypeClass *)(tb); - ClassDeclaration *cd = tc->sym->isClassDeclaration(); - if (cd->isInterfaceDeclaration()) - { error("cannot create instance of interface %s", cd->toChars()); - goto Lerr; - } - else if (cd->isAbstract()) - { error("cannot create instance of abstract class %s", cd->toChars()); - for (size_t i = 0; i < cd->vtbl.dim; i++) - { FuncDeclaration *fd = cd->vtbl.tdata()[i]->isFuncDeclaration(); - if (fd && fd->isAbstract()) - error("function %s is abstract", fd->toChars()); - } - goto Lerr; - } - - if (cd->noDefaultCtor && (!arguments || !arguments->dim)) - { error("default construction is disabled for type %s", cd->toChars()); - goto Lerr; - } - checkDeprecated(sc, cd); - if (cd->isNested()) - { /* We need a 'this' pointer for the nested class. - * Ensure we have the right one. - */ - Dsymbol *s = cd->toParent2(); - ClassDeclaration *cdn = s->isClassDeclaration(); - FuncDeclaration *fdn = s->isFuncDeclaration(); - - //printf("cd isNested, cdn = %s\n", cdn ? cdn->toChars() : "null"); - if (cdn) - { - if (!cdthis) - { - // Supply an implicit 'this' and try again - thisexp = new ThisExp(loc); - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { if (!sp) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - goto Lerr; - } - ClassDeclaration *cdp = sp->isClassDeclaration(); - if (!cdp) - continue; - if (cdp == cdn || cdn->isBaseOf(cdp, NULL)) - break; - // Add a '.outer' and try again - thisexp = new DotIdExp(loc, thisexp, Id::outer); - } - if (!global.errors) - goto Lagain; - } - if (cdthis) - { - //printf("cdthis = %s\n", cdthis->toChars()); - if (cdthis != cdn && !cdn->isBaseOf(cdthis, NULL)) - { error("'this' for nested class must be of type %s, not %s", cdn->toChars(), thisexp->type->toChars()); - goto Lerr; - } - } -#if 0 - else - { - for (Dsymbol *sf = sc->func; 1; sf= sf->toParent2()->isFuncDeclaration()) - { - if (!sf) - { - error("outer class %s 'this' needed to 'new' nested class %s", cdn->toChars(), cd->toChars()); - goto Lerr; - } - printf("sf = %s\n", sf->toChars()); - AggregateDeclaration *ad = sf->isThis(); - if (ad && (ad == cdn || cdn->isBaseOf(ad->isClassDeclaration(), NULL))) - break; - } - } -#endif - } -#if 1 - else if (thisexp) - { error("e.new is only for allocating nested classes"); - goto Lerr; - } - else if (fdn) - { - // make sure the parent context fdn of cd is reachable from sc - for (Dsymbol *sp = sc->parent; 1; sp = sp->parent) - { - if (fdn == sp) - break; - FuncDeclaration *fsp = sp ? sp->isFuncDeclaration() : NULL; - if (!sp || (fsp && fsp->isStatic())) - { - error("outer function context of %s is needed to 'new' nested class %s", fdn->toPrettyChars(), cd->toPrettyChars()); - goto Lerr; - } - } - } -#else - else if (fdn) - { /* The nested class cd is nested inside a function, - * we'll let getEthis() look for errors. - */ - //printf("nested class %s is nested inside function %s, we're in %s\n", cd->toChars(), fdn->toChars(), sc->func->toChars()); - if (thisexp) - { // Because thisexp cannot be a function frame pointer - error("e.new is only for allocating nested classes"); - goto Lerr; - } - } -#endif - else - assert(0); - } - else if (thisexp) - { error("e.new is only for allocating nested classes"); - goto Lerr; - } - - FuncDeclaration *f = NULL; - if (cd->ctor) - f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); - if (f) - { - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - cd->accessCheck(loc, sc, member); - - TypeFunction *tf = (TypeFunction *)f->type; - - if (!arguments) - arguments = new Expressions(); - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, arguments, f); - if (olderrors != global.errors) - return new ErrorExp(); - type = type->addMod(tf->nextOf()->mod); - } - else - { - if (arguments && arguments->dim) - { error("no constructor for %s", cd->toChars()); - goto Lerr; - } - } - - if (cd->aggNew) - { - // Prepend the size argument to newargs[] - Expression *e = new IntegerExp(loc, cd->size(loc), Type::tsize_t); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = cd->aggNew->overloadResolve(loc, NULL, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - TypeFunction *tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, newargs, f); - if (olderrors != global.errors) - return new ErrorExp(); - - } - else - { - if (newargs && newargs->dim) - { error("no allocator for %s", cd->toChars()); - goto Lerr; - } - } - } - else if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - TypeFunction *tf; - - if (sd->noDefaultCtor && (!arguments || !arguments->dim)) - { error("default construction is disabled for type %s", sd->toChars()); - goto Lerr; - } - FuncDeclaration *f = NULL; - if (sd->ctor) - f = resolveFuncCall(sc, loc, sd->ctor, NULL, NULL, arguments, 0); - if (f) - { - checkDeprecated(sc, f); - member = f->isCtorDeclaration(); - assert(member); - - sd->accessCheck(loc, sc, member); - - tf = (TypeFunction *)f->type; - type = tf->next; - - if (!arguments) - arguments = new Expressions(); - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, arguments, f); - if (olderrors != global.errors) - return new ErrorExp(); - - } - else - { - if (arguments && arguments->dim) - { error("no constructor for %s", sd->toChars()); - goto Lerr; - } - } - - - if (sd->aggNew) - { - // Prepend the uint size argument to newargs[] - Expression *e = new IntegerExp(loc, sd->size(loc), Type::tuns32); - if (!newargs) - newargs = new Expressions(); - newargs->shift(e); - - f = sd->aggNew->overloadResolve(loc, NULL, newargs); - allocator = f->isNewDeclaration(); - assert(allocator); - - tf = (TypeFunction *)f->type; - unsigned olderrors = global.errors; - functionParameters(loc, sc, tf, NULL, newargs, f); - if (olderrors != global.errors) - return new ErrorExp(); - -#if 0 - e = new VarExp(loc, f); - e = new CallExp(loc, e, newargs); - e = e->semantic(sc); - e->type = type->pointerTo(); - return e; -#endif - } - else - { - if (newargs && newargs->dim) - { error("no allocator for %s", sd->toChars()); - goto Lerr; - } - } - - type = type->pointerTo(); - } - else if (tb->ty == Tarray && (arguments && arguments->dim)) - { - for (size_t i = 0; i < arguments->dim; i++) - { - if (tb->ty != Tarray) - { error("too many arguments for array"); - goto Lerr; - } - - Expression *arg = arguments->tdata()[i]; - arg = resolveProperties(sc, arg); - arg = arg->implicitCastTo(sc, Type::tsize_t); - arg = arg->optimize(WANTvalue); - if (arg->op == TOKint64 && (sinteger_t)arg->toInteger() < 0) - { error("negative array index %s", arg->toChars()); - goto Lerr; - } - arguments->tdata()[i] = arg; - tb = ((TypeDArray *)tb)->next->toBasetype(); - } - } - else if (tb->isscalar()) - { - if (arguments && arguments->dim) - { error("no constructor for %s", type->toChars()); - goto Lerr; - } - - type = type->pointerTo(); - } - else - { - error("new can only create structs, dynamic arrays or class objects, not %s's", type->toChars()); - goto Lerr; - } - -//printf("NewExp: '%s'\n", toChars()); -//printf("NewExp:type '%s'\n", type->toChars()); - - return this; - -Lerr: - return new ErrorExp(); -} - - -void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new "); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - newtype->toCBuffer(buf, NULL, hgs); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } -} - -/********************** NewAnonClassExp **************************************/ - -NewAnonClassExp::NewAnonClassExp(Loc loc, Expression *thisexp, - Expressions *newargs, ClassDeclaration *cd, Expressions *arguments) - : Expression(loc, TOKnewanonclass, sizeof(NewAnonClassExp)) -{ - this->thisexp = thisexp; - this->newargs = newargs; - this->cd = cd; - this->arguments = arguments; -} - -Expression *NewAnonClassExp::syntaxCopy() -{ - return new NewAnonClassExp(loc, - thisexp ? thisexp->syntaxCopy() : NULL, - arraySyntaxCopy(newargs), - (ClassDeclaration *)cd->syntaxCopy(NULL), - arraySyntaxCopy(arguments)); -} - - -Expression *NewAnonClassExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("NewAnonClassExp::semantic() %s\n", toChars()); - //printf("thisexp = %p\n", thisexp); - //printf("type: %s\n", type->toChars()); -#endif - - Expression *d = new DeclarationExp(loc, cd); - d = d->semantic(sc); - - Expression *n = new NewExp(loc, thisexp, newargs, cd->type, arguments); - - Expression *c = new CommaExp(loc, d, n); - return c->semantic(sc); -} - - -void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (thisexp) - { expToCBuffer(buf, hgs, thisexp, PREC_primary); - buf->writeByte('.'); - } - buf->writestring("new"); - if (newargs && newargs->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, newargs, hgs); - buf->writeByte(')'); - } - buf->writestring(" class "); - if (arguments && arguments->dim) - { - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); - } - //buf->writestring(" { }"); - if (cd) - { - cd->toCBuffer(buf, hgs); - } -} - -/********************** SymbolExp **************************************/ - -#if DMDV2 -SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) - : Expression(loc, op, size) -{ - assert(var); - this->var = var; - this->hasOverloads = hasOverloads; -} -#endif - -/********************** SymOffExp **************************************/ - -SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads) - : SymbolExp(loc, TOKsymoff, sizeof(SymOffExp), var, hasOverloads) -{ - this->offset = offset; - m = NULL; - VarDeclaration *v = var->isVarDeclaration(); - if (v && v->needThis()) - error("need 'this' for address of %s", v->toChars()); -} - -Expression *SymOffExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("SymOffExp::semantic('%s')\n", toChars()); -#endif - //var->semantic(sc); - m = sc->module; - if (!type) - type = var->type->pointerTo(); - VarDeclaration *v = var->isVarDeclaration(); - if (v) - v->checkNestedReference(sc, loc); - FuncDeclaration *f = var->isFuncDeclaration(); - if (f) - f->checkNestedReference(sc, loc); - return this; -} - -int SymOffExp::isBool(int result) -{ - return result ? TRUE : FALSE; -} - -void SymOffExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - { /* BUG: This should be allowed: - * void foo() - * { int a; - * int* bar() { return &a; } - * } - */ - error("escaping reference to local %s", v->toChars()); - } - } -} - -void SymOffExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (offset) - buf->printf("(& %s+%u)", var->toChars(), offset); - else - buf->printf("& %s", var->toChars()); -} - -/******************************** VarExp **************************/ - -VarExp::VarExp(Loc loc, Declaration *var, int hasOverloads) - : SymbolExp(loc, TOKvar, sizeof(VarExp), var, hasOverloads) -{ - //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var->toChars(), loc.toChars()); - //if (strcmp(var->ident->toChars(), "func") == 0) halt(); - this->type = var->type; -} - -int VarExp::equals(Object *o) -{ VarExp *ne; - - if (this == o || - (((Expression *)o)->op == TOKvar && - ((ne = (VarExp *)o), type->toHeadMutable()->equals(ne->type->toHeadMutable())) && - var == ne->var)) - return 1; - return 0; -} - -Expression *VarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("VarExp::semantic(%s)\n", toChars()); -#endif -// if (var->sem == SemanticStart && var->scope) // if forward referenced -// var->semantic(sc); - if (!type) - { type = var->type; -#if 0 - if (var->storage_class & STClazy) - { - TypeFunction *tf = new TypeFunction(NULL, type, 0, LINKd); - type = new TypeDelegate(tf); - type = type->semantic(loc, sc); - } -#endif - } - - if (type && !type->deco) - type = type->semantic(loc, sc); - - /* Fix for 1161 doesn't work because it causes protection - * problems when instantiating imported templates passing private - * variables as alias template parameters. - */ - //accessCheck(loc, sc, NULL, var); - - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - v->checkNestedReference(sc, loc); -#if DMDV2 - checkPurity(sc, v, NULL); -#endif - } - FuncDeclaration *f = var->isFuncDeclaration(); - if (f) - f->checkNestedReference(sc, loc); -#if 0 - else if ((fd = var->isFuncLiteralDeclaration()) != NULL) - { Expression *e; - e = new FuncExp(loc, fd); - e->type = type; - return e; - } -#endif - - return this; -} - -char *VarExp::toChars() -{ - return var->toChars(); -} - -void VarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(var->toChars()); -} - -void VarExp::checkEscape() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { Type *tb = v->type->toBasetype(); - // if reference type - if (tb->ty == Tarray || tb->ty == Tsarray || tb->ty == Tclass || tb->ty == Tdelegate) - { - if (v->isScope() && (!v->noscope || tb->ty == Tclass)) - error("escaping reference to scope local %s", v->toChars()); - else if (v->storage_class & STCvariadic) - error("escaping reference to variadic parameter %s", v->toChars()); - } - } -} - -void VarExp::checkEscapeRef() -{ - VarDeclaration *v = var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - error("escaping reference to local variable %s", v->toChars()); - } -} - -#if DMDV2 -int VarExp::isLvalue() -{ - if (var->storage_class & STClazy) - return 0; - return 1; -} -#endif - -Expression *VarExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - if (var->storage_class & STClazy) - { error("lazy variables cannot be lvalues"); - return new ErrorExp(); - } - return this; -} - -Expression *VarExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("VarExp::modifiableLvalue('%s')\n", var->toChars()); - //if (type && type->toBasetype()->ty == Tsarray) - //error("cannot change reference to static array '%s'", var->toChars()); - - var->checkModify(loc, sc, type); - - // See if this expression is a modifiable lvalue (i.e. not const) - return toLvalue(sc, e); -} - - -/******************************** OverExp **************************/ - -#if DMDV2 -OverExp::OverExp(OverloadSet *s) - : Expression(loc, TOKoverloadset, sizeof(OverExp)) -{ - //printf("OverExp(this = %p, '%s')\n", this, var->toChars()); - vars = s; - type = Type::tvoid; -} - -int OverExp::isLvalue() -{ - return 1; -} - -Expression *OverExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} -#endif - - -/******************************** TupleExp **************************/ - -TupleExp::TupleExp(Loc loc, Expressions *exps) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - //printf("TupleExp(this = %p)\n", this); - this->exps = exps; - this->type = NULL; -} - - -TupleExp::TupleExp(Loc loc, TupleDeclaration *tup) - : Expression(loc, TOKtuple, sizeof(TupleExp)) -{ - exps = new Expressions(); - type = NULL; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; - if (o->dyncast() == DYNCAST_EXPRESSION) - { - Expression *e = (Expression *)o; - if (e->op == TOKdsymbol) - e = e->syntaxCopy(); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_DSYMBOL) - { - Dsymbol *s = (Dsymbol *)o; - Expression *e = new DsymbolExp(loc, s); - exps->push(e); - } - else if (o->dyncast() == DYNCAST_TYPE) - { - Type *t = (Type *)o; - Expression *e = new TypeExp(loc, t); - exps->push(e); - } - else - { - error("%s is not an expression", o->toChars()); - } - } -} - -int TupleExp::equals(Object *o) -{ - if (this == o) - return 1; - if (((Expression *)o)->op == TOKtuple) - { - TupleExp *te = (TupleExp *)o; - if (exps->dim != te->exps->dim) - return 0; - for (size_t i = 0; i < exps->dim; i++) - { Expression *e1 = (*exps)[i]; - Expression *e2 = (*te->exps)[i]; - - if (!e1->equals(e2)) - return 0; - } - return 1; - } - return 0; -} - -Expression *TupleExp::syntaxCopy() -{ - return new TupleExp(loc, arraySyntaxCopy(exps)); -} - -Expression *TupleExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("+TupleExp::semantic(%s)\n", toChars()); -#endif - if (type) - return this; - - // Run semantic() on each argument - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - - e = e->semantic(sc); - if (!e->type) - { error("%s has no value", e->toChars()); - return new ErrorExp(); - } - (*exps)[i] = e; - } - - expandTuples(exps); - type = new TypeTuple(exps); - type = type->semantic(loc, sc); - //printf("-TupleExp::semantic(%s)\n", toChars()); - return this; -} - -void TupleExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("tuple("); - argsToCBuffer(buf, exps, hgs); - buf->writeByte(')'); -} - - -void TupleExp::checkEscape() -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*exps)[i]; - e->checkEscape(); - } -} - -/******************************** FuncExp *********************************/ - -FuncExp::FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td) - : Expression(loc, TOKfunction, sizeof(FuncExp)) -{ - this->fd = fd; - this->td = td; - tok = fd->tok; // save original kind of function/delegate/(infer) - tded = NULL; - scope = NULL; -} - -Expression *FuncExp::syntaxCopy() -{ - return new FuncExp(loc, (FuncLiteralDeclaration *)fd->syntaxCopy(NULL)); -} - -Expression *FuncExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("FuncExp::semantic(%s)\n", toChars()); -#endif - if (!type || type == Type::tvoid) - { - // save for later use - scope = sc; - - //printf("td = %p, tded = %p\n", td, tded); - if (td) - { - assert(td->parameters && td->parameters->dim); - td->semantic(sc); - - if (!tded) - { // defer type determination - type = Type::tvoid; // temporary type - return this; - } - else - { - Expression *e = inferType(sc, tded); - if (e) - { e = e->castTo(sc, tded); - e = e->semantic(sc); - } - if (!e) - { error("cannot infer function literal type"); - e = new ErrorExp(); - } - return e; - } - } - - unsigned olderrors = global.errors; - fd->semantic(sc); - //fd->parent = sc->parent; - if (olderrors != global.errors) - { - } - else - { - fd->semantic2(sc); - if ( (olderrors == global.errors) || - // need to infer return type - (fd->type && fd->type->ty == Tfunction && !fd->type->nextOf())) - { - fd->semantic3(sc); - - if ( (olderrors == global.errors) && global.params.useInline) - fd->inlineScan(); - } - } - - // need to infer return type - if ((olderrors != global.errors) && fd->type && fd->type->ty == Tfunction && !fd->type->nextOf()) - ((TypeFunction *)fd->type)->next = Type::terror; - - // Type is a "delegate to" or "pointer to" the function literal - if ((fd->isNested() && fd->tok == TOKdelegate) || - (tok == TOKreserved && tded && tded->ty == Tdelegate)) - { - type = new TypeDelegate(fd->type); - type = type->semantic(loc, sc); - } - else - { - type = fd->type->pointerTo(); - } - fd->tookAddressOf++; - } - return this; -} - -// used from CallExp::semantic() -Expression *FuncExp::semantic(Scope *sc, Expressions *arguments) -{ - assert(!tded); - assert(!scope); - - if ((!type || type == Type::tvoid) && td && arguments && arguments->dim) - { - for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; - if (checkarg->op == TOKerror) - return checkarg; - } - - assert(td->parameters && td->parameters->dim); - td->semantic(sc); - - TypeFunction *tfl = (TypeFunction *)fd->type; - size_t dim = Parameter::dim(tfl->parameters); - - if ((!tfl->varargs && arguments->dim == dim) || - ( tfl->varargs && arguments->dim >= dim)) - { - Objects *tiargs = new Objects(); - tiargs->reserve(td->parameters->dim); - - for (size_t i = 0; i < td->parameters->dim; i++) - { - TemplateParameter *tp = (*td->parameters)[i]; - for (size_t u = 0; u < dim; u++) - { Parameter *p = Parameter::getNth(tfl->parameters, u); - if (p->type->ty == Tident && - ((TypeIdentifier *)p->type)->ident == tp->ident) - { Expression *e = (*arguments)[u]; - tiargs->push(e->type); - u = dim; // break inner loop - } - } - } - - TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - return (new ScopeExp(loc, ti))->semantic(sc); - } - error("cannot infer function literal type"); - return new ErrorExp(); - } - return semantic(sc); -} - -Expression *FuncExp::inferType(Scope *sc, Type *to) -{ - //printf("inferType sc = %p, to = %s\n", sc, to->toChars()); - if (!sc) - { // used from TypeFunction::callMatch() - assert(scope); - sc = scope; - } - -#if IN_LLVM - if (fd->tok == TOKreserved && to->ty == Tpointer && to->nextOf()->ty == Tfunction) - fd->tok = TOKfunction; -#endif - - Expression *e = NULL; - if (td) - { /// Parameter types inference from - assert(!type || type == Type::tvoid); - Type *t = to; - if (t->ty == Tdelegate || - t->ty == Tpointer && t->nextOf()->ty == Tfunction) - { t = t->nextOf(); - } - if (t->ty == Tfunction) - { - TypeFunction *tfv = (TypeFunction *)t; - TypeFunction *tfl = (TypeFunction *)fd->type; - size_t dim = Parameter::dim(tfl->parameters); - - if (Parameter::dim(tfv->parameters) == dim && - tfv->varargs == tfl->varargs) - { - Objects *tiargs = new Objects(); - tiargs->reserve(td->parameters->dim); - - for (size_t i = 0; i < td->parameters->dim; i++) - { - TemplateParameter *tp = (*td->parameters)[i]; - for (size_t u = 0; u < dim; u++) - { Parameter *p = Parameter::getNth(tfl->parameters, u); - if (p->type->ty == Tident && - ((TypeIdentifier *)p->type)->ident == tp->ident) - { p = Parameter::getNth(tfv->parameters, u); - if (p->type->ty == Tident) - return NULL; - tiargs->push(p->type); - u = dim; // break inner loop - } - } - } - - TemplateInstance *ti = new TemplateInstance(loc, td, tiargs); - e = (new ScopeExp(loc, ti))->semantic(sc); - } - } - } - else - { - assert(type && type != Type::tvoid); // semantic is already done - e = this; - } - - if (e) - { // Check implicit function to delegate conversion - if (e->implicitConvTo(to)) - e = e->castTo(sc, to); - else - e = NULL; - } - return e; -} - -void FuncExp::setType(Type *t) -{ - assert(t); - - if (t->ty == Tdelegate || - t->ty == Tpointer && t->nextOf()->ty == Tfunction) - { tded = t; - } -} - -char *FuncExp::toChars() -{ - return fd->toChars(); -} - -void FuncExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - fd->toCBuffer(buf, hgs); - //buf->writestring(fd->toChars()); -} - - -/******************************** DeclarationExp **************************/ - -DeclarationExp::DeclarationExp(Loc loc, Dsymbol *declaration) - : Expression(loc, TOKdeclaration, sizeof(DeclarationExp)) -{ - this->declaration = declaration; -} - -Expression *DeclarationExp::syntaxCopy() -{ - return new DeclarationExp(loc, declaration->syntaxCopy(NULL)); -} - -Expression *DeclarationExp::semantic(Scope *sc) -{ - if (type) - return this; - -#if LOGSEMANTIC - printf("DeclarationExp::semantic() %s\n", toChars()); -#endif - - unsigned olderrors = global.errors; - - /* This is here to support extern(linkage) declaration, - * where the extern(linkage) winds up being an AttribDeclaration - * wrapper. - */ - Dsymbol *s = declaration; - - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad) - { - if (ad->decl && ad->decl->dim == 1) - s = ad->decl->tdata()[0]; - } - - if (s->isVarDeclaration()) - { // Do semantic() on initializer first, so: - // int a = a; - // will be illegal. - declaration->semantic(sc); - s->parent = sc->parent; - } - - //printf("inserting '%s' %p into sc = %p\n", s->toChars(), s, sc); - // Insert into both local scope and function scope. - // Must be unique in both. - if (s->ident) - { - if (!sc->insert(s)) - { error("declaration %s is already defined", s->toPrettyChars()); - return new ErrorExp(); - } - else if (sc->func) - { VarDeclaration *v = s->isVarDeclaration(); - if ( (s->isFuncDeclaration() || s->isTypedefDeclaration() || - s->isAggregateDeclaration() || s->isEnumDeclaration() || - s->isInterfaceDeclaration()) && - !sc->func->localsymtab->insert(s)) - { - error("declaration %s is already defined in another scope in %s", - s->toPrettyChars(), sc->func->toChars()); - return new ErrorExp(); - } - else if (!global.params.useDeprecated) - { // Disallow shadowing - - for (Scope *scx = sc->enclosing; scx && scx->func == sc->func; scx = scx->enclosing) - { Dsymbol *s2; - - if (scx->scopesym && scx->scopesym->symtab && - (s2 = scx->scopesym->symtab->lookup(s->ident)) != NULL && - s != s2) - { - error("shadowing declaration %s is deprecated", s->toPrettyChars()); - return new ErrorExp(); - } - } - } - } - } - if (!s->isVarDeclaration()) - { - Scope *sc2 = sc; - if (sc2->stc & (STCpure | STCnothrow)) - sc2 = sc->push(); - sc2->stc &= ~(STCpure | STCnothrow); - declaration->semantic(sc2); - if (sc2 != sc) - sc2->pop(); - s->parent = sc->parent; - } - if (global.errors == olderrors) - { - declaration->semantic2(sc); - if (global.errors == olderrors) - { - declaration->semantic3(sc); - - if ((global.errors == olderrors) && global.params.useInline) - declaration->inlineScan(); - } - } - - type = Type::tvoid; - return this; -} - - -void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - declaration->toCBuffer(buf, hgs); -} - - -/************************ TypeidExp ************************************/ - -/* - * typeid(int) - */ - -TypeidExp::TypeidExp(Loc loc, Object *o) - : Expression(loc, TOKtypeid, sizeof(TypeidExp)) -{ - this->obj = o; -} - - -Expression *TypeidExp::syntaxCopy() -{ - return new TypeidExp(loc, objectSyntaxCopy(obj)); -} - - -Expression *TypeidExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("TypeidExp::semantic() %s\n", toChars()); -#endif - Type *ta = isType(obj); - Expression *ea = isExpression(obj); - Dsymbol *sa = isDsymbol(obj); - - //printf("ta %p ea %p sa %p\n", ta, ea, sa); - - if (ta) - { - ta->resolve(loc, sc, &ea, &ta, &sa); - } - - if (ea) - { - ea = ea->semantic(sc); - ea = resolveProperties(sc, ea); - ta = ea->type; - if (ea->op == TOKtype) - ea = NULL; - } - - if (!ta) - { - //printf("ta %p ea %p sa %p\n", ta, ea, sa); - error("no type for typeid(%s)", ea ? ea->toChars() : (sa ? sa->toChars() : "")); - return new ErrorExp(); - } - - if (ea && ta->toBasetype()->ty == Tclass) - { /* Get the dynamic type, which is .classinfo - */ - e = new DotIdExp(ea->loc, ea, Id::classinfo); - e = e->semantic(sc); - } - else - { /* Get the static type - */ - e = ta->getTypeInfo(sc); - if (e->loc.linnum == 0) - e->loc = loc; // so there's at least some line number info - if (ea) - { - e = new CommaExp(loc, ea, e); // execute ea - e = e->semantic(sc); - } - } - return e; -} - -void TypeidExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("typeid("); - ObjectToCBuffer(buf, hgs, obj); - buf->writeByte(')'); -} - -/************************ TraitsExp ************************************/ -#if DMDV2 -/* - * __traits(identifier, args...) - */ - -TraitsExp::TraitsExp(Loc loc, Identifier *ident, Objects *args) - : Expression(loc, TOKtraits, sizeof(TraitsExp)) -{ - this->ident = ident; - this->args = args; -} - - -Expression *TraitsExp::syntaxCopy() -{ - return new TraitsExp(loc, ident, TemplateInstance::arraySyntaxCopy(args)); -} - - -void TraitsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("__traits("); - buf->writestring(ident->toChars()); - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - buf->writeByte(','); - Object *oarg = args->tdata()[i]; - ObjectToCBuffer(buf, hgs, oarg); - } - } - buf->writeByte(')'); -} -#endif - -/************************************************************/ - -HaltExp::HaltExp(Loc loc) - : Expression(loc, TOKhalt, sizeof(HaltExp)) -{ -} - -Expression *HaltExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("HaltExp::semantic()\n"); -#endif - type = Type::tvoid; - return this; -} - - -void HaltExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("halt"); -} - -/************************************************************/ - -IsExp::IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, - Type *tspec, enum TOK tok2, TemplateParameters *parameters) - : Expression(loc, TOKis, sizeof(IsExp)) -{ - this->targ = targ; - this->id = id; - this->tok = tok; - this->tspec = tspec; - this->tok2 = tok2; - this->parameters = parameters; -} - -Expression *IsExp::syntaxCopy() -{ - // This section is identical to that in TemplateDeclaration::syntaxCopy() - TemplateParameters *p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - p->tdata()[i] = tp->syntaxCopy(); - } - } - - return new IsExp(loc, - targ->syntaxCopy(), - id, - tok, - tspec ? tspec->syntaxCopy() : NULL, - tok2, - p); -} - -Expression *IsExp::semantic(Scope *sc) -{ Type *tded; - - /* is(targ id tok tspec) - * is(targ id : tok2) - * is(targ id == tok2) - */ - - //printf("IsExp::semantic(%s)\n", toChars()); - if (id && !(sc->flags & (SCOPEstaticif | SCOPEstaticassert))) - { error("can only declare type aliases within static if conditionals or static asserts"); - return new ErrorExp(); - } - - Type *t = targ->trySemantic(loc, sc); - if (!t) - goto Lno; // errors, so condition is false - targ = t; - if (tok2 != TOKreserved) - { - switch (tok2) - { - case TOKtypedef: - if (targ->ty != Ttypedef) - goto Lno; - tded = ((TypeTypedef *)targ)->sym->basetype; - break; - - case TOKstruct: - if (targ->ty != Tstruct) - goto Lno; - if (((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKunion: - if (targ->ty != Tstruct) - goto Lno; - if (!((TypeStruct *)targ)->sym->isUnionDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKclass: - if (targ->ty != Tclass) - goto Lno; - if (((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; - - case TOKinterface: - if (targ->ty != Tclass) - goto Lno; - if (!((TypeClass *)targ)->sym->isInterfaceDeclaration()) - goto Lno; - tded = targ; - break; -#if DMDV2 - case TOKconst: - if (!targ->isConst()) - goto Lno; - tded = targ; - break; - - case TOKinvariant: - if (!global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - case TOKimmutable: - if (!targ->isImmutable()) - goto Lno; - tded = targ; - break; - - case TOKshared: - if (!targ->isShared()) - goto Lno; - tded = targ; - break; - - case TOKwild: - if (!targ->isWild()) - goto Lno; - tded = targ; - break; -#endif - - case TOKsuper: - // If class or interface, get the base class and interfaces - if (targ->ty != Tclass) - goto Lno; - else - { ClassDeclaration *cd = ((TypeClass *)targ)->sym; - Parameters *args = new Parameters; - args->reserve(cd->baseclasses->dim); - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { BaseClass *b = cd->baseclasses->tdata()[i]; - args->push(new Parameter(STCin, b->type, NULL, NULL)); - } - tded = new TypeTuple(args); - } - break; - - case TOKenum: - if (targ->ty != Tenum) - goto Lno; - tded = ((TypeEnum *)targ)->sym->memtype; - break; - - case TOKdelegate: - if (targ->ty != Tdelegate) - goto Lno; - tded = ((TypeDelegate *)targ)->next; // the underlying function type - break; - - case TOKfunction: - { - if (targ->ty != Tfunction) - goto Lno; - tded = targ; - - /* Generate tuple from function parameter types. - */ - assert(tded->ty == Tfunction); - Parameters *params = ((TypeFunction *)tded)->parameters; - size_t dim = Parameter::dim(params); - Parameters *args = new Parameters; - args->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = Parameter::getNth(params, i); - assert(arg && arg->type); - args->push(new Parameter(arg->storageClass, arg->type, NULL, NULL)); - } - tded = new TypeTuple(args); - break; - } - case TOKreturn: - /* Get the 'return type' for the function, - * delegate, or pointer to function. - */ - if (targ->ty == Tfunction) - tded = ((TypeFunction *)targ)->next; - else if (targ->ty == Tdelegate) - { tded = ((TypeDelegate *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else if (targ->ty == Tpointer && - ((TypePointer *)targ)->next->ty == Tfunction) - { tded = ((TypePointer *)targ)->next; - tded = ((TypeFunction *)tded)->next; - } - else - goto Lno; - break; - - case TOKargTypes: - /* Generate a type tuple of the equivalent types used to determine if a - * function argument of this type can be passed in registers. - * The results of this are highly platform dependent, and intended - * primarly for use in implementing va_arg(). - */ - tded = targ->toArgTypes(); - if (!tded) - goto Lno; // not valid for a parameter - break; - - default: - assert(0); - } - goto Lyes; - } - else if (id && tspec) - { - /* Evaluate to TRUE if targ matches tspec. - * If TRUE, declare id as an alias for the specialized type. - */ - - assert(parameters && parameters->dim); - - Objects dedtypes; - dedtypes.setDim(parameters->dim); - dedtypes.zero(); - - MATCH m = targ->deduceType(sc, tspec, parameters, &dedtypes); -//printf("targ: %s\n", targ->toChars()); -//printf("tspec: %s\n", tspec->toChars()); - if (m == MATCHnomatch || - (m != MATCHexact && tok == TOKequal)) - { - goto Lno; - } - else - { - tded = (Type *)dedtypes.tdata()[0]; - if (!tded) - tded = targ; -#if DMDV2 - Objects tiargs; - tiargs.setDim(1); - tiargs.tdata()[0] = targ; - - /* Declare trailing parameters - */ - for (size_t i = 1; i < parameters->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - Declaration *s = NULL; - - m = tp->matchArg(sc, &tiargs, i, parameters, &dedtypes, &s); - if (m == MATCHnomatch) - goto Lno; - s->semantic(sc); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - else if (!sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - } -#endif - goto Lyes; - } - } - else if (id) - { - /* Declare id as an alias for type targ. Evaluate to TRUE - */ - tded = targ; - goto Lyes; - } - else if (tspec) - { - /* Evaluate to TRUE if targ matches tspec - * is(targ == tspec) - * is(targ : tspec) - */ - tspec = tspec->semantic(loc, sc); - //printf("targ = %s, %s\n", targ->toChars(), targ->deco); - //printf("tspec = %s, %s\n", tspec->toChars(), tspec->deco); - if (tok == TOKcolon) - { if (targ->implicitConvTo(tspec)) - goto Lyes; - else - goto Lno; - } - else /* == */ - { if (targ->equals(tspec)) - goto Lyes; - else - goto Lno; - } - } - -Lyes: - if (id) - { - Dsymbol *s; - Tuple *tup = isTuple(tded); - if (tup) - s = new TupleDeclaration(loc, id, &(tup->objects)); - else - s = new AliasDeclaration(loc, id, tded); - s->semantic(sc); - /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there. - * More investigation is needed. - */ - if (!tup && !sc->insert(s)) - error("declaration %s is already defined", s->toChars()); - if (sc->sd) - s->addMember(sc, sc->sd, 1); - } - //printf("Lyes\n"); - return new IntegerExp(loc, 1, Type::tbool); - -Lno: - //printf("Lno\n"); - return new IntegerExp(loc, 0, Type::tbool); -} - -void IsExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("is("); - targ->toCBuffer(buf, id, hgs); - if (tok2 != TOKreserved) - { - buf->printf(" %s %s", Token::toChars(tok), Token::toChars(tok2)); - } - else if (tspec) - { - if (tok == TOKcolon) - buf->writestring(" : "); - else - buf->writestring(" == "); - tspec->toCBuffer(buf, NULL, hgs); - } -#if DMDV2 - if (parameters) - { // First parameter is already output, so start with second - for (size_t i = 1; i < parameters->dim; i++) - { - buf->writeByte(','); - TemplateParameter *tp = parameters->tdata()[i]; - tp->toCBuffer(buf, hgs); - } - } -#endif - buf->writeByte(')'); -} - - -/************************************************************/ - -UnaExp::UnaExp(Loc loc, enum TOK op, int size, Expression *e1) - : Expression(loc, op, size) -{ - this->e1 = e1; -} - -Expression *UnaExp::syntaxCopy() -{ - UnaExp *e = (UnaExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - return e; -} - -Expression *UnaExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("UnaExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); -// if (!e1->type) -// error("%s has no value", e1->toChars()); - return this; -} - -Expression *UnaExp::resolveLoc(Loc loc, Scope *sc) -{ - e1 = e1->resolveLoc(loc, sc); - return this; -} - -void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -BinExp::BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : Expression(loc, op, size) -{ - this->e1 = e1; - this->e2 = e2; -} - -Expression *BinExp::syntaxCopy() -{ - BinExp *e = (BinExp *)copy(); - e->type = NULL; - e->e1 = e->e1->syntaxCopy(); - e->e2 = e->e2->syntaxCopy(); - return e; -} - -Expression *BinExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("BinExp::semantic('%s')\n", toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e1->op == TOKerror || e2->op == TOKerror) - return new ErrorExp(); - return this; -} - -Expression *BinExp::semanticp(Scope *sc) -{ - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e2 = resolveProperties(sc, e2); - return this; -} - - -// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary -void BinExp::checkComplexMulAssign() -{ - // Any multiplication by an imaginary or complex number yields a complex result. - // r *= c, i*=c, r*=i, i*=i are all forbidden operations. - const char *opstr = Token::toChars(op); - if ( e1->type->isreal() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.re ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if (e1->type->isimaginary() && e2->type->iscomplex()) - { - error("%s %s %s is undefined. Did you mean %s %s %s.im ?", - e1->type->toChars(), opstr, e2->type->toChars(), - e1->type->toChars(), opstr, e2->type->toChars()); - } - else if ((e1->type->isreal() || e1->type->isimaginary()) && - e2->type->isimaginary()) - { - error("%s %s %s is an undefined operation", e1->type->toChars(), - opstr, e2->type->toChars()); - } -} - -// generate an error if this is a nonsensical += or -=, eg real += imaginary -void BinExp::checkComplexAddAssign() -{ - // Addition or subtraction of a real and an imaginary is a complex result. - // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations. - if ( (e1->type->isreal() && (e2->type->isimaginary() || e2->type->iscomplex())) || - (e1->type->isimaginary() && (e2->type->isreal() || e2->type->iscomplex())) - ) - { - error("%s %s %s is undefined (result is complex)", - e1->type->toChars(), Token::toChars(op), e2->type->toChars()); - } -} - -void BinExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte(' '); - buf->writestring(Token::toChars(op)); - buf->writeByte(' '); - expToCBuffer(buf, hgs, e2, (enum PREC)(precedence[op] + 1)); -} - -int BinExp::isunsigned() -{ - return e1->type->isunsigned() || e2->type->isunsigned(); -} - -Expression *BinExp::incompatibleTypes() -{ - if (e1->type->toBasetype() != Type::terror && - e2->type->toBasetype() != Type::terror - ) - { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", - e1->toChars(), Token::toChars(op), e2->toChars(), - e1->type->toChars(), e2->type->toChars()); - return new ErrorExp(); - } - return this; -} - -/********************** BinAssignExp **************************************/ - -/*************************** - * Common semantic routine for some xxxAssignExp's. - */ - -Expression *BinAssignExp::commonSemanticAssign(Scope *sc) -{ Expression *e; - - if (!type) - { - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - error("operator not allowed on bool expression %s", toChars()); - return new ErrorExp(); - } - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - - if (op == TOKmodass) - { - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - else if (type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - } - } - return this; -} - -Expression *BinAssignExp::commonSemanticAssignIntegral(Scope *sc) -{ Expression *e; - - if (!type) - { - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] op= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - type = e1->type; - if (type->toBasetype()->ty == Tbool) - { - e2 = e2->implicitCastTo(sc, type); - } - - typeCombine(sc); - e1->checkIntegral(); - e2->checkIntegral(); - } - return this; -} - -#if DMDV2 -int BinAssignExp::isLvalue() -{ - return 1; -} - -Expression *BinAssignExp::toLvalue(Scope *sc, Expression *ex) -{ Expression *e; - - if (e1->op == TOKvar) - { - /* Convert (e1 op= e2) to - * e1 op= e2; - * e1 - */ - e = e1->copy(); - e = new CommaExp(loc, this, e); - e = e->semantic(sc); - } - else - { - /* Convert (e1 op= e2) to - * ref v = e1; - * v op= e2; - * v - */ - - // ref v = e1; - Identifier *id = Lexer::uniqueId("__assignop"); - ExpInitializer *ei = new ExpInitializer(loc, e1); - VarDeclaration *v = new VarDeclaration(loc, e1->type, id, ei); - v->storage_class |= STCref | STCforeach; - Expression *de = new DeclarationExp(loc, v); - - // v op= e2 - e1 = new VarExp(e1->loc, v); - - e = new CommaExp(loc, de, this); - e = new CommaExp(loc, e, new VarExp(loc, v)); - e = e->semantic(sc); - } - return e; -} - -Expression *BinAssignExp::modifiableLvalue(Scope *sc, Expression *e) -{ - return toLvalue(sc, this); -} - -#endif - -/************************************************************/ - -CompileExp::CompileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(CompileExp), e) -{ -} - -Expression *CompileExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CompileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - if (e1->op == TOKerror) - return e1; - if (!e1->type->isString()) - { - error("argument to mixin must be a string type, not %s\n", e1->type->toChars()); - return new ErrorExp(); - } - e1 = e1->optimize(WANTvalue | WANTinterpret); - StringExp *se = e1->toString(); - if (!se) - { error("argument to mixin must be a string, not (%s)", e1->toChars()); - return new ErrorExp(); - } - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - //printf("p.loc.linnum = %d\n", p.loc.linnum); - Expression *e = p.parseExpression(); - if (p.token.value != TOKeof) - { error("incomplete mixin expression (%s)", se->toChars()); - return new ErrorExp(); - } - return e->semantic(sc); -} - -void CompileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -FileExp::FileExp(Loc loc, Expression *e) - : UnaExp(loc, TOKmixin, sizeof(FileExp), e) -{ -} - -Expression *FileExp::semantic(Scope *sc) -{ char *name; - StringExp *se; - -#if LOGSEMANTIC - printf("FileExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->optimize(WANTvalue | WANTinterpret); - if (e1->op != TOKstring) - { error("file name argument must be a string, not (%s)", e1->toChars()); - goto Lerror; - } - se = (StringExp *)e1; - se = se->toUTF8(sc); - name = (char *)se->string; - - if (!global.params.fileImppath) - { error("need -Jpath switch to import text file %s", name); - goto Lerror; - } - - /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory - * ('Path Traversal') attacks. - * http://cwe.mitre.org/data/definitions/22.html - */ - - name = FileName::safeSearchPath(global.filePath, name); - if (!name) - { error("file %s cannot be found or not in a path specified with -J", se->toChars()); - goto Lerror; - } - - if (global.params.verbose) - printf("file %s\t(%s)\n", (char *)se->string, name); - - { File f(name); - if (f.read()) - { error("cannot read file %s", f.toChars()); - goto Lerror; - } - else - { - f.ref = 1; - se = new StringExp(loc, f.buffer, f.len); - } - } - return se->semantic(sc); - - Lerror: - return new ErrorExp(); -} - -void FileExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("import("); - expToCBuffer(buf, hgs, e1, PREC_assign); - buf->writeByte(')'); -} - -/************************************************************/ - -AssertExp::AssertExp(Loc loc, Expression *e, Expression *msg) - : UnaExp(loc, TOKassert, sizeof(AssertExp), e) -{ - this->msg = msg; -} - -Expression *AssertExp::syntaxCopy() -{ - AssertExp *ae = new AssertExp(loc, e1->syntaxCopy(), - msg ? msg->syntaxCopy() : NULL); - return ae; -} - -Expression *AssertExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AssertExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - // BUG: see if we can do compile time elimination of the Assert - e1 = e1->optimize(WANTvalue); - e1 = e1->checkToBoolean(sc); - if (msg) - { - msg = msg->semantic(sc); - msg = resolveProperties(sc, msg); - msg = msg->implicitCastTo(sc, Type::tchar->constOf()->arrayOf()); - msg = msg->optimize(WANTvalue); - } - if (e1->isBool(FALSE)) - { - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - if (fd) - fd->hasReturnExp |= 4; - - if (!global.params.useAssert) - { Expression *e = new HaltExp(loc); - e = e->semantic(sc); - return e; - } - } - type = Type::tvoid; - return this; -} - - -void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("assert("); - expToCBuffer(buf, hgs, e1, PREC_assign); - if (msg) - { - buf->writeByte(','); - expToCBuffer(buf, hgs, msg, PREC_assign); - } - buf->writeByte(')'); -} - -/************************************************************/ - -DotIdExp::DotIdExp(Loc loc, Expression *e, Identifier *ident) - : UnaExp(loc, TOKdot, sizeof(DotIdExp), e) -{ - this->ident = ident; -} - -Expression *DotIdExp::semantic(Scope *sc) -{ - // Indicate we didn't come from CallExp::semantic() - return semantic(sc, 0); -} - -Expression *DotIdExp::semantic(Scope *sc, int flag) -{ Expression *e; - Expression *eleft; - Expression *eright; - -#if LOGSEMANTIC - printf("DotIdExp::semantic(this = %p, '%s')\n", this, toChars()); - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); -#endif - -//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } - -#if 0 - /* Don't do semantic analysis if we'll be converting - * it to a string. - */ - if (ident == Id::stringof) - { char *s = e1->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } -#endif - - /* Special case: rewrite this.id and super.id - * to be classtype.id and baseclasstype.id - * if we have no this pointer. - */ - if ((e1->op == TOKthis || e1->op == TOKsuper) && !hasThis(sc)) - { ClassDeclaration *cd; - StructDeclaration *sd; - AggregateDeclaration *ad; - - ad = sc->getStructClassScope(); - if (ad) - { - cd = ad->isClassDeclaration(); - if (cd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, cd->type, ident); - return e->semantic(sc); - } - else if (cd->baseClass && e1->op == TOKsuper) - { - e = typeDotIdExp(loc, cd->baseClass->type, ident); - return e->semantic(sc); - } - } - else - { - sd = ad->isStructDeclaration(); - if (sd) - { - if (e1->op == TOKthis) - { - e = typeDotIdExp(loc, sd->type, ident); - return e->semantic(sc); - } - } - } - } - } - - UnaExp::semantic(sc); - - if (ident == Id::mangleof) - { // symbol.mangleof - Dsymbol *ds; - switch (e1->op) - { - case TOKimport: ds = ((ScopeExp *)e1)->sds; goto L1; - case TOKvar: ds = ((VarExp *)e1)->var; goto L1; - case TOKdotvar: ds = ((DotVarExp *)e1)->var; goto L1; - L1: - char* s = ds->mangle(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - } - - if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *)e1; - eleft = de->e1; - eright = de->e2; - } - else - { - if (e1->op != TOKtype) - e1 = resolveProperties(sc, e1); - eleft = NULL; - eright = e1; - } -#if DMDV2 - if (e1->op == TOKtuple && ident == Id::offsetof) - { /* 'distribute' the .offsetof to each of the tuple elements. - */ - TupleExp *te = (TupleExp *)e1; - Expressions *exps = new Expressions(); - exps->setDim(te->exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = (*te->exps)[i]; - e = e->semantic(sc); - e = new DotIdExp(e->loc, e, Id::offsetof); - (*exps)[i] = e; - } - e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKtuple && ident == Id::length) - { - TupleExp *te = (TupleExp *)e1; - e = new IntegerExp(loc, te->exps->dim, Type::tsize_t); - return e; - } - - if (e1->op == TOKdottd) - { - error("template %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (!e1->type) - { - error("expression %s does not have property %s", e1->toChars(), ident->toChars()); - return new ErrorExp(); - } - - Type *t1b = e1->type->toBasetype(); - - if (eright->op == TOKimport) // also used for template alias's - { - ScopeExp *ie = (ScopeExp *)eright; - - /* Disable access to another module's private imports. - * The check for 'is sds our current module' is because - * the current module should have access to its own imports. - */ - Dsymbol *s = ie->sds->search(loc, ident, - (ie->sds->isModule() && ie->sds != sc->module) ? 1 : 0); - if (s) - { - /* Check for access before resolving aliases because public - * aliases to private symbols are public. - */ - if (Declaration *d = s->isDeclaration()) - accessCheck(loc, sc, 0, d); - - s = s->toAlias(); - checkDeprecated(sc, s); - - EnumMember *em = s->isEnumMember(); - if (em) - { - e = em->value; - e = e->semantic(sc); - return e; - } - - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v->type->toChars()); - if (v->inuse) - { - error("circular reference to '%s'", v->toChars()); - return new ErrorExp(); - } - type = v->type; - if (v->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, v); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = v->type; - } - } - e = e->deref(); - return e->semantic(sc); - } - - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - //printf("it's a function\n"); - if (f->needThis()) - { - if (!eleft) - eleft = new ThisExp(loc); - e = new DotVarExp(loc, eleft, f); - e = e->semantic(sc); - } - else - { - e = new VarExp(loc, f, 1); - if (eleft) - { e = new CommaExp(loc, eleft, e); - e->type = f->type; - } - } - return e; - } -#if DMDV2 - OverloadSet *o = s->isOverloadSet(); - if (o) - { //printf("'%s' is an overload set\n", o->toChars()); - return new OverExp(o); - } -#endif - - Type *t = s->getType(); - if (t) - { - return new TypeExp(loc, t); - } - - TupleDeclaration *tup = s->isTupleDeclaration(); - if (tup) - { - if (eleft) - { error("cannot have e.tuple"); - return new ErrorExp(); - } - e = new TupleExp(loc, tup); - e = e->semantic(sc); - return e; - } - - ScopeDsymbol *sds = s->isScopeDsymbol(); - if (sds) - { - //printf("it's a ScopeDsymbol\n"); - e = new ScopeExp(loc, sds); - e = e->semantic(sc); - if (eleft) - e = new DotExp(loc, eleft, e); - return e; - } - - Import *imp = s->isImport(); - if (imp) - { - ScopeExp *ie; - - ie = new ScopeExp(loc, imp->pkg); - return ie->semantic(sc); - } - - // BUG: handle other cases like in IdentifierExp::semantic() -#ifdef DEBUG - printf("s = '%s', kind = '%s'\n", s->toChars(), s->kind()); -#endif - assert(0); - } - else if (ident == Id::stringof) - { char *s = ie->toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - e = e->semantic(sc); - return e; - } - error("undefined identifier %s", toChars()); - return new ErrorExp(); - } - else if (t1b->ty == Tpointer && - ident != Id::init && ident != Id::__sizeof && - ident != Id::__xalignof && ident != Id::offsetof && - ident != Id::mangleof && ident != Id::stringof) - { /* Rewrite: - * p.ident - * as: - * (*p).ident - */ - e = new PtrExp(loc, e1); - e->type = ((TypePointer *)t1b)->next; - return e->type->dotExp(sc, e, ident); - } -#if DMDV2 - else if ((t1b->ty == Tarray || t1b->ty == Tsarray || - t1b->ty == Taarray) && - ident != Id::sort && ident != Id::reverse && - ident != Id::dup && ident != Id::idup) - { /* If ident is not a valid property, rewrite: - * e1.ident - * as: - * .ident(e1) - */ - unsigned errors = global.startGagging(); - Type *t1 = e1->type; - e = e1->type->dotExp(sc, e1, ident); - if (global.endGagging(errors)) // if failed to find the property - { - e1->type = t1; // kludge to restore type - e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); - e = new CallExp(loc, e, e1); - } - e = e->semantic(sc); - return e; - } -#endif - else - { - e = e1->type->dotExp(sc, e1, ident); - if (!(flag && e->op == TOKdotti)) // let CallExp::semantic() handle this - e = e->semantic(sc); - return e; - } -} - -void DotIdExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("DotIdExp::toCBuffer()\n"); - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -/********************** DotTemplateExp ***********************************/ - -// Mainly just a placeholder - -DotTemplateExp::DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td) - : UnaExp(loc, TOKdottd, sizeof(DotTemplateExp), e) - -{ - this->td = td; -} - -void DotTemplateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(td->toChars()); -} - - -/************************************************************/ - -DotVarExp::DotVarExp(Loc loc, Expression *e, Declaration *v, int hasOverloads) - : UnaExp(loc, TOKdotvar, sizeof(DotVarExp), e) -{ - //printf("DotVarExp()\n"); - this->var = v; - this->hasOverloads = hasOverloads; -} - -Expression *DotVarExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotVarExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - var = var->toAlias()->isDeclaration(); - - TupleDeclaration *tup = var->isTupleDeclaration(); - if (tup) - { /* Replace: - * e1.tuple(a, b, c) - * with: - * tuple(e1.a, e1.b, e1.c) - */ - Expressions *exps = new Expressions; - Expression *ev = e1; - - exps->reserve(tup->objects->dim); - for (size_t i = 0; i < tup->objects->dim; i++) - { Object *o = tup->objects->tdata()[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - { - error("%s is not an expression", o->toChars()); - goto Lerr; - } - - Expression *e = (Expression *)o; - if (e->op != TOKdsymbol) - { error("%s is not a member", e->toChars()); - goto Lerr; - } - - Dsymbol *s = ((DsymbolExp *)e)->s; - if (i == 0 && sc->func && tup->objects->dim > 1 && - e1->hasSideEffect()) - { - Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e1->loc, e1); - VarDeclaration *v = new VarDeclaration(e1->loc, NULL, id, ei); - v->storage_class |= STCctfe | STCref | STCforeach; - - ev = new VarExp(e->loc, v); - e = new CommaExp(e1->loc, new DeclarationExp(e1->loc, v), ev); - e = new DotVarExp(loc, e, s->isDeclaration()); - } - else - e = new DotVarExp(loc, ev, s->isDeclaration()); - exps->push(e); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - - e1 = e1->semantic(sc); - e1 = e1->addDtorHook(sc); - type = var->type; - if (!type && global.errors) - { // var is goofed up, just return 0 - return new ErrorExp(); - } - assert(type); - - Type *t1 = e1->type; - if (!var->isFuncDeclaration()) // for functions, do checks after overload resolution - { - if (t1->ty == Tpointer) - t1 = t1->nextOf(); - - type = type->addMod(t1->mod); - - Dsymbol *vparent = var->toParent(); - AggregateDeclaration *ad = vparent ? vparent->isAggregateDeclaration() : NULL; - e1 = getRightThis(loc, sc, ad, e1, var); - if (!sc->noaccesscheck) - accessCheck(loc, sc, e1, var); - - VarDeclaration *v = var->isVarDeclaration(); - Expression *e = expandVar(WANTvalue, v); - if (e) - return e; - } - Dsymbol *s; - if (sc->func && !sc->intypeof && t1->hasPointers() && - (s = t1->toDsymbol(sc)) != NULL) - { - AggregateDeclaration *ad = s->isAggregateDeclaration(); - if (ad && ad->hasUnions) - { - if (sc->func->setUnsafe()) - { error("union %s containing pointers are not allowed in @safe functions", t1->toChars()); - goto Lerr; - } - } - } - } - - //printf("-DotVarExp::semantic('%s')\n", toChars()); - return this; - -Lerr: - return new ErrorExp(); -} - -#if DMDV2 -int DotVarExp::isLvalue() -{ - return 1; -} -#endif - -Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) -{ - //printf("DotVarExp::toLvalue(%s)\n", toChars()); - return this; -} - -/*********************************************** - * Mark variable v as modified if it is inside a constructor that var - * is a field in. - */ -void modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1) -{ - //printf("modifyFieldVar(var = %s)\n", var->toChars()); - Dsymbol *s = sc->func; - while (1) - { - FuncDeclaration *fd = NULL; - if (s) - fd = s->isFuncDeclaration(); - if (fd && - ((fd->isCtorDeclaration() && var->storage_class & STCfield) || - (fd->isStaticCtorDeclaration() && !(var->storage_class & STCfield))) && - fd->toParent2() == var->toParent2() && - (!e1 || e1->op == TOKthis) - ) - { - var->ctorinit = 1; - //printf("setting ctorinit\n"); - } - else - { - if (s) - { s = s->toParent2(); - continue; - } - else if (var->storage_class & STCctorinit) - { - const char *p = var->isStatic() ? "static " : ""; - error(loc, "can only initialize %sconst member %s inside %sconstructor", - p, var->toChars(), p); - } - } - break; - } -} - -Expression *DotVarExp::modifiableLvalue(Scope *sc, Expression *e) -{ -#if 0 - printf("DotVarExp::modifiableLvalue(%s)\n", toChars()); - printf("e1->type = %s\n", e1->type->toChars()); - printf("var->type = %s\n", var->type->toChars()); -#endif - - Type *t1 = e1->type->toBasetype(); - - if (!t1->isMutable() || - (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || - !var->type->isMutable() || - !var->type->isAssignable() || - var->storage_class & STCmanifest - ) - { - if (var->isCtorinit()) - { // It's only modifiable if inside the right constructor - modifyFieldVar(loc, sc, var->isVarDeclaration(), e1); - } - else - { - error("cannot modify const/immutable/inout expression %s", toChars()); - } - } - else if (var->storage_class & STCnodefaultctor) - { - modifyFieldVar(loc, sc, var->isVarDeclaration(), e1); - } - return this; -} - -void DotVarExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(var->toChars()); -} - -/************************************************************/ - -/* Things like: - * foo.bar!(args) - */ - -DotTemplateInstanceExp::DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs) - : UnaExp(loc, TOKdotti, sizeof(DotTemplateInstanceExp), e) -{ - //printf("DotTemplateInstanceExp()\n"); - this->ti = new TemplateInstance(loc, name); - this->ti->tiargs = tiargs; -} - -Expression *DotTemplateInstanceExp::syntaxCopy() -{ - DotTemplateInstanceExp *de = new DotTemplateInstanceExp(loc, - e1->syntaxCopy(), - ti->name, - TemplateInstance::arraySyntaxCopy(ti->tiargs)); - return de; -} - -TemplateDeclaration *DotTemplateInstanceExp::getTempdecl(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::getTempdecl('%s')\n", toChars()); -#endif - if (!ti->tempdecl) - { - Expression *e = new DotIdExp(loc, e1, ti->name); - e = e->semantic(sc); - if (e->op == TOKdottd) - { - DotTemplateExp *dte = (DotTemplateExp *)e; - ti->tempdecl = dte->td; - } - else if (e->op == TOKimport) - { ScopeExp *se = (ScopeExp *)e; - ti->tempdecl = se->sds->isTemplateDeclaration(); - } - } - return ti->tempdecl; -} - -Expression *DotTemplateInstanceExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTemplateInstanceExp::semantic('%s')\n", toChars()); -#endif - Expression *eleft; - Expression *e = new DotIdExp(loc, e1, ti->name); -L1: - e = e->semantic(sc); - if (e->op == TOKerror) - return e; - if (e->op == TOKdottd) - { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway - DotTemplateExp *dte = (DotTemplateExp *)e; - TemplateDeclaration *td = dte->td; - eleft = dte->e1; - ti->tempdecl = td; - if (ti->needsTypeInference(sc)) - { - e1 = eleft; // save result of semantic() - return this; - } - else - ti->semantic(sc); - if (!ti->inst) // if template failed to expand - return new ErrorExp(); - Dsymbol *s = ti->inst->toAlias(); - Declaration *v = s->isDeclaration(); - if (v) - { - /* Fix for Bugzilla 4003 - * The problem is a class template member function v returning a reference to the same - * type as the enclosing template instantiation. This results in a nested instantiation, - * which of course gets short circuited. The return type then gets set to - * the template instance type before instantiation, rather than after. - * We can detect this by the deco not being set. If so, go ahead and retry - * the return type semantic. - * The offending code is the return type from std.typecons.Tuple.slice: - * ref Tuple!(Types[from .. to]) slice(uint from, uint to)() - * { - * return *cast(typeof(return) *) &(field[from]); - * } - * and this line from the following unittest: - * auto s = a.slice!(1, 3); - * where s's type wound up not having semantic() run on it. - */ - if (v->type && !v->type->deco) - v->type = v->type->semantic(v->loc, sc); - - e = new DotVarExp(loc, eleft, v); - e = e->semantic(sc); - return e; - } - e = new ScopeExp(loc, ti); - e = new DotExp(loc, eleft, e); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKimport) - { ScopeExp *se = (ScopeExp *)e; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (!td) - { error("%s is not a template", e->toChars()); - return new ErrorExp(); - } - ti->tempdecl = td; - e = new ScopeExp(loc, ti); - e = e->semantic(sc); - return e; - } - else if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e2->op == TOKoverloadset) - { - return e; - } - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e = new DotTemplateExp(loc,de->e1,te->td); - } - goto L1; - } - error("%s isn't a template", e->toChars()); - return new ErrorExp(); -} - -void DotTemplateInstanceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - ti->toCBuffer(buf, hgs); -} - -/************************************************************/ - -DelegateExp::DelegateExp(Loc loc, Expression *e, FuncDeclaration *f, int hasOverloads) - : UnaExp(loc, TOKdelegate, sizeof(DelegateExp), e) -{ - this->func = f; - this->hasOverloads = hasOverloads; -} - -Expression *DelegateExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DelegateExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - m = sc->module; - e1 = e1->semantic(sc); -#if IN_LLVM - // LDC we need a copy as we store the LLVM type in TypeFunction, - // and delegate/members have different types for 'this' - Type *funcType = func->type->syntaxCopy(); - funcType->deco = func->type->deco; - type = new TypeDelegate(funcType); -#else - type = new TypeDelegate(func->type); -#endif - type = type->semantic(loc, sc); - AggregateDeclaration *ad = func->toParent()->isAggregateDeclaration(); - if (func->needThis()) - e1 = getRightThis(loc, sc, ad, e1, func); - if (ad && ad->isClassDeclaration() && ad->type != e1->type) - { // A downcast is required for interfaces, see Bugzilla 3706 - e1 = new CastExp(loc, e1, ad->type); - e1 = e1->semantic(sc); - } - } - return this; -} - -void DelegateExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('&'); - if (!func->isNested()) - { - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - } - buf->writestring(func->toChars()); -} - -/************************************************************/ - -DotTypeExp::DotTypeExp(Loc loc, Expression *e, Dsymbol *s) - : UnaExp(loc, TOKdottype, sizeof(DotTypeExp), e) -{ - this->sym = s; - this->type = s->getType(); -} - -Expression *DotTypeExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotTypeExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - return this; -} - -void DotTypeExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(sym->toChars()); -} - -/************************************************************/ - -CallExp::CallExp(Loc loc, Expression *e, Expressions *exps) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = exps; - this->f = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - this->arguments = NULL; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - if (earg1) - { arguments->setDim(1); - arguments->tdata()[0] = earg1; - } - this->arguments = arguments; -} - -CallExp::CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2) - : UnaExp(loc, TOKcall, sizeof(CallExp), e) -{ - Expressions *arguments = new Expressions(); - arguments->setDim(2); - arguments->tdata()[0] = earg1; - arguments->tdata()[1] = earg2; - - this->arguments = arguments; -} - -Expression *CallExp::syntaxCopy() -{ - return new CallExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - - -Expression *CallExp::resolveUFCS(Scope *sc) -{ - Expression *ethis = NULL; - DotIdExp *dotid; - DotTemplateInstanceExp *dotti; - Identifier *ident; - - if (e1->op == TOKdot) - { - dotid = (DotIdExp *)e1; - ident = dotid->ident; - ethis = dotid->e1 = dotid->e1->semantic(sc); - if (ethis->op == TOKdotexp) - return NULL; - ethis = resolveProperties(sc, ethis); - } - else if (e1->op == TOKdotti) - { - dotti = (DotTemplateInstanceExp *)e1; - ident = dotti->ti->name; - ethis = dotti->e1 = dotti->e1->semantic(sc); - if (ethis->op == TOKdotexp) - return NULL; - ethis = resolveProperties(sc, ethis); - } - - if (ethis && ethis->type) - { - AggregateDeclaration *ad; -Lagain: - Type *tthis = ethis->type->toBasetype(); - if (tthis->ty == Tclass) - { - ad = ((TypeClass *)tthis)->sym; - if (search_function(ad, ident)) - return NULL; - goto L1; - } - else if (tthis->ty == Tstruct) - { - ad = ((TypeStruct *)tthis)->sym; - if (search_function(ad, ident)) - return NULL; - L1: - if (ad->aliasthis) - { - ethis = new DotIdExp(ethis->loc, ethis, ad->aliasthis->ident); - ethis = ethis->semantic(sc); - ethis = resolveProperties(sc, ethis); - goto Lagain; - } - } - else if (tthis->ty == Taarray && e1->op == TOKdot) - { - if (ident == Id::remove) - { - /* Transform: - * aa.remove(arg) into delete aa[arg] - */ - if (!arguments || arguments->dim != 1) - { error("expected key as argument to aa.remove()"); - return new ErrorExp(); - } - Expression *key = arguments->tdata()[0]; - key = key->semantic(sc); - key = resolveProperties(sc, key); - if (!key->rvalue()) - return new ErrorExp(); - - TypeAArray *taa = (TypeAArray *)tthis; - key = key->implicitCastTo(sc, taa->index); - - return new RemoveExp(loc, ethis, key); - } - else if (ident == Id::apply || ident == Id::applyReverse) - { - return NULL; - } - else - { TypeAArray *taa = (TypeAArray *)tthis; - assert(taa->ty == Taarray); - StructDeclaration *sd = taa->getImpl(); - Dsymbol *s = sd->search(0, ident, 2); - if (s) - return NULL; - goto Lshift; - } - } - else if (tthis->ty == Tarray || tthis->ty == Tsarray) - { -Lshift: - if (!arguments) - arguments = new Expressions(); - arguments->shift(ethis); - if (e1->op == TOKdot) - { - /* Transform: - * array.id(args) into .id(array,args) - */ -#if DMDV2 - e1 = new DotIdExp(dotid->loc, - new IdentifierExp(dotid->loc, Id::empty), - ident); -#else - e1 = new IdentifierExp(dotid->loc, ident); -#endif - } - else if (e1->op == TOKdotti) - { - /* Transform: - * array.foo!(tiargs)(args) into .foo!(tiargs)(array,args) - */ -#if DMDV2 - e1 = new DotTemplateInstanceExp(dotti->loc, - new IdentifierExp(dotti->loc, Id::empty), - dotti->ti->name, dotti->ti->tiargs); -#else - e1 = new ScopeExp(dotti->loc, dotti->ti); -#endif - } - //printf("-> this = %s\n", toChars()); - } - } - return NULL; -} - -Expression *CallExp::semantic(Scope *sc) -{ - TypeFunction *tf; - Type *t1; - int istemp; - Objects *targsi = NULL; // initial list of template arguments - TemplateInstance *tierror = NULL; - Expression *ethis = NULL; - -#if LOGSEMANTIC - printf("CallExp::semantic() %s\n", toChars()); -#endif - if (type) - return this; // semantic() already run -#if 0 - if (arguments && arguments->dim) - { - Expression *earg = arguments->tdata()[0]; - earg->print(); - if (earg->type) earg->type->print(); - } -#endif - - if (e1->op == TOKcomma) - { /* Rewrite (a,b)(args) as (a,(b(args))) - */ - CommaExp *ce = (CommaExp *)e1; - - e1 = ce->e2; - e1->type = ce->type; - ce->e2 = this; - ce->type = NULL; - return ce->semantic(sc); - } - - if (e1->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)e1; - - e1 = new DotVarExp(de->loc, de->e1, de->func); - return semantic(sc); - } - - if (e1->op == TOKfunction) - { FuncExp *fe = (FuncExp *)e1; - - arguments = arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - e1 = fe->semantic(sc, arguments); - if (e1->op == TOKerror) - return e1; - } - - Expression *e = resolveUFCS(sc); - if (e) - return e; - -#if 1 - /* This recognizes: - * foo!(tiargs)(funcargs) - */ - if (e1->op == TOKimport && !e1->type) - { ScopeExp *se = (ScopeExp *)e1; - TemplateInstance *ti = se->sds->isTemplateInstance(); - if (ti && !ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); - if (ti->needsTypeInference(sc)) - { - /* Go with partial explicit specialization - */ - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new IdentifierExp(loc, ti->name); - } - else - { - ti->semantic(sc); - } - } - } - - /* This recognizes: - * expr.foo!(tiargs)(funcargs) - */ -Ldotti: - if (e1->op == TOKdotti && !e1->type) - { DotTemplateInstanceExp *se = (DotTemplateInstanceExp *)e1; - TemplateInstance *ti = se->ti; - if (!ti->semanticRun) - { - /* Attempt to instantiate ti. If that works, go with it. - * If not, go with partial explicit specialization. - */ - ti->semanticTiargs(sc); -#if 0 - Expression *etmp = e1->trySemantic(sc); - if (etmp) - e1 = etmp; // it worked - else // didn't work - { - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new DotIdExp(loc, se->e1, ti->name); - } -#else - if (!ti->tempdecl) - { - se->getTempdecl(sc); - } - if (ti->tempdecl && ti->needsTypeInference(sc)) - { - /* Go with partial explicit specialization - */ - targsi = ti->tiargs; - tierror = ti; // for error reporting - e1 = new DotIdExp(loc, se->e1, ti->name); - } - else - { - e1 = e1->semantic(sc); - } -#endif - } - } -#endif - - istemp = 0; -Lagain: - //printf("Lagain: %s\n", toChars()); - f = NULL; - if (e1->op == TOKthis || e1->op == TOKsuper) - { - // semantic() run later for these - } - else - { - if (e1->op == TOKdot) - { DotIdExp *die = (DotIdExp *)e1; - e1 = die->semantic(sc, 1); - /* Look for e1 having been rewritten to expr.opDispatch!(string) - * We handle such earlier, so go back. - * Note that in the rewrite, we carefully did not run semantic() on e1 - */ - if (e1->op == TOKdotti && !e1->type) - { - goto Ldotti; - } - } - else - { - static int nest; - if (++nest > 500) - { - error("recursive evaluation of %s", toChars()); - --nest; - return new ErrorExp(); - } - UnaExp::semantic(sc); - --nest; - } - - /* Look for e1 being a lazy parameter - */ - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - - if (ve->var->storage_class & STClazy) - { - // lazy paramaters can be called without violating purity and safety - TypeFunction *tf = new TypeFunction(NULL, ve->var->type, 0, LINKd, STCsafe | STCpure); - TypeDelegate *t = new TypeDelegate(tf); - ve->type = t->semantic(loc, sc); - } - } - - if (e1->op == TOKimport) - { // Perhaps this should be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)e1; - e1 = new DsymbolExp(loc, se->sds); - e1 = e1->semantic(sc); - } -#if IN_LLVM - else if (e1->op == TOKaddress) - { - AddrExp *ae = (AddrExp *)e1; - if (ae->e1->op == TOKvar) { - VarExp *ve = (VarExp*)ae->e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol() && ve->hasOverloads) - { - e1 = ve; - } - } - - - } -#else - else if (e1->op == TOKsymoff && ((SymOffExp *)e1)->hasOverloads) - { - SymOffExp *se = (SymOffExp *)e1; - e1 = new VarExp(se->loc, se->var, 1); - e1 = e1->semantic(sc); - } -#endif -#if 1 // patch for #540 by Oskar Linde - else if (e1->op == TOKdotexp) - { - DotExp *de = (DotExp *) e1; - - if (de->e2->op == TOKoverloadset) - { - ethis = de->e1; - e1 = de->e2; - } - - if (de->e2->op == TOKimport) - { // This should *really* be moved to ScopeExp::semantic() - ScopeExp *se = (ScopeExp *)de->e2; - de->e2 = new DsymbolExp(loc, se->sds); - de->e2 = de->e2->semantic(sc); - } - - if (de->e2->op == TOKtemplate) - { TemplateExp *te = (TemplateExp *) de->e2; - e1 = new DotTemplateExp(loc,de->e1,te->td); - } - } -#endif - } - - t1 = NULL; - if (e1->type) - t1 = e1->type->toBasetype(); - - // Check for call operator overload - if (t1) - { AggregateDeclaration *ad; - - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; -#if DMDV2 - // First look for constructor - if (ad->ctor && arguments && arguments->dim) - { - // Create variable that will get constructed - Identifier *idtmp = Lexer::uniqueId("__ctmp"); - VarDeclaration *tmp = new VarDeclaration(loc, t1, idtmp, NULL); - tmp->storage_class |= STCctfe; - Expression *av = new DeclarationExp(loc, tmp); - av = new CommaExp(loc, av, new VarExp(loc, tmp)); - - Expression *e; - CtorDeclaration *cf = ad->ctor->isCtorDeclaration(); - if (cf) - e = new DotVarExp(loc, av, cf, 1); - else - { TemplateDeclaration *td = ad->ctor->isTemplateDeclaration(); - assert(td); - e = new DotTemplateExp(loc, av, td); - } - e = new CallExp(loc, e, arguments); -#if !STRUCTTHISREF - /* Constructors return a pointer to the instance - */ - e = new PtrExp(loc, e); -#endif - e = e->semantic(sc); - return e; - } -#endif - // No constructor, look for overload of opCall - if (search_function(ad, Id::call)) - goto L1; // overload of opCall, therefore it's a call - - if (e1->op != TOKtype) - { error("%s %s does not overload ()", ad->kind(), ad->toChars()); - return new ErrorExp(); - } - - /* It's a struct literal - */ - Expression *e = new StructLiteralExp(loc, (StructDeclaration *)ad, arguments, e1->type); - e = e->semantic(sc); - return e; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - goto L1; - L1: - // Rewrite as e1.call(arguments) - Expression *e = new DotIdExp(loc, e1, Id::call); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - } - - arguments = arrayExpressionSemantic(arguments, sc); - preFunctionParameters(loc, sc, arguments); - - // If there was an error processing any argument, or the call, - // return an error without trying to resolve the function call. - if (arguments && arguments->dim) - { - for (size_t k = 0; k < arguments->dim; k++) - { Expression *checkarg = arguments->tdata()[k]; - if (checkarg->op == TOKerror) - return checkarg; - } - } - if (e1->op == TOKerror) - return e1; - - if (e1->op == TOKdotvar && t1->ty == Tfunction || - e1->op == TOKdottd) - { - DotVarExp *dve; - DotTemplateExp *dte; - AggregateDeclaration *ad; - UnaExp *ue = (UnaExp *)(e1); - - if (e1->op == TOKdotvar) - { // Do overload resolution - dve = (DotVarExp *)(e1); - - f = dve->var->isFuncDeclaration(); - assert(f); - f = f->overloadResolve(loc, ue->e1, arguments); - - ad = f->toParent()->isAggregateDeclaration(); - } - else - { dte = (DotTemplateExp *)(e1); - TemplateDeclaration *td = dte->td; - assert(td); - if (!arguments) - // Should fix deduceFunctionTemplate() so it works on NULL argument - arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, targsi, ue->e1, arguments); - if (!f) - return new ErrorExp(); - ad = td->toParent()->isAggregateDeclaration(); - } - if (f->needThis()) - { - ue->e1 = getRightThis(loc, sc, ad, ue->e1, f); - ethis = ue->e1; - } - - /* Cannot call public functions from inside invariant - * (because then the invariant would have infinite recursion) - */ - if (sc->func && sc->func->isInvariantDeclaration() && - ue->e1->op == TOKthis && - f->addPostInvariant() - ) - { - error("cannot call public/export function %s from invariant", f->toChars()); - return new ErrorExp(); - } - - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - accessCheck(loc, sc, ue->e1, f); - if (!f->needThis()) - { - VarExp *ve = new VarExp(loc, f); - if ((ue->e1)->op == TOKtype) // just a FQN - e1 = ve; - else // things like (new Foo).bar() - e1 = new CommaExp(loc, ue->e1, ve); - e1->type = f->type; - } - else - { - if (e1->op == TOKdotvar) - { - dve->var = f; - e1->type = f->type; - } - else - { - e1 = new DotVarExp(loc, dte->e1, f); - e1 = e1->semantic(sc); - } -#if 0 - printf("ue->e1 = %s\n", ue->e1->toChars()); - printf("f = %s\n", f->toChars()); - printf("t = %s\n", t->toChars()); - printf("e1 = %s\n", e1->toChars()); - printf("e1->type = %s\n", e1->type->toChars()); -#endif - // Const member function can take const/immutable/mutable/inout this - if (!(f->type->isConst())) - { - // Check for const/immutable compatibility - Type *tthis = ue->e1->type->toBasetype(); - if (tthis->ty == Tpointer) - tthis = tthis->nextOf()->toBasetype(); -#if 0 // this checking should have been already done - if (f->type->isImmutable()) - { - if (tthis->mod != MODimmutable) - error("%s can only be called with an immutable object", e1->toChars()); - } - else if (f->type->isShared()) - { - if (tthis->mod != MODimmutable && - tthis->mod != MODshared && - tthis->mod != (MODshared | MODconst)) - error("shared %s can only be called with a shared or immutable object", e1->toChars()); - } - else - { - if (tthis->mod != 0) - { //printf("mod = %x\n", tthis->mod); - error("%s can only be called with a mutable object, not %s", e1->toChars(), tthis->toChars()); - } - } -#endif - /* Cannot call mutable method on a final struct - */ - if (tthis->ty == Tstruct && - ue->e1->op == TOKvar) - { VarExp *v = (VarExp *)ue->e1; - if (v->var->storage_class & STCfinal) - error("cannot call mutable method on final struct"); - } - } - - // See if we need to adjust the 'this' pointer - AggregateDeclaration *ad = f->isThis(); - ClassDeclaration *cd = ue->e1->type->isClassHandle(); - if (ad && cd && ad->isClassDeclaration() && ad != cd && - ue->e1->op != TOKsuper) - { - ue->e1 = ue->e1->castTo(sc, ad->type); //new CastExp(loc, ue->e1, ad->type); - ue->e1 = ue->e1->semantic(sc); - } - } - t1 = e1->type; - } - else if (e1->op == TOKsuper) - { - // Base class constructor call - ClassDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isClassDeclaration(); - if (!cd || !cd->baseClass || !sc->func->isCtorDeclaration()) - { - error("super class constructor call must be in a constructor"); - return new ErrorExp(); - } - else - { - if (!cd->baseClass->ctor) - { error("no super class constructor for %s", cd->baseClass->toChars()); - return new ErrorExp(); - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXsuper_ctor; - } - - f = resolveFuncCall(sc, loc, cd->baseClass->ctor, NULL, NULL, arguments, 0); - accessCheck(loc, sc, NULL, f); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - } - } - } - else if (e1->op == TOKthis) - { - // same class constructor call - AggregateDeclaration *cd = NULL; - - if (sc->func) - cd = sc->func->toParent()->isAggregateDeclaration(); - if (!cd || !sc->func->isCtorDeclaration()) - { - error("constructor call must be in a constructor"); - return new ErrorExp(); - } - else - { - if (!sc->intypeof) - { -#if 0 - if (sc->callSuper & (CSXthis | CSXsuper)) - error("reference to this before super()"); -#endif - if (sc->noctor || sc->callSuper & CSXlabel) - error("constructor calls not allowed in loops or after labels"); - if (sc->callSuper & (CSXsuper_ctor | CSXthis_ctor)) - error("multiple constructor calls"); - sc->callSuper |= CSXany_ctor | CSXthis_ctor; - } - - f = resolveFuncCall(sc, loc, cd->ctor, NULL, NULL, arguments, 0); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - e1 = new DotVarExp(e1->loc, e1, f); - e1 = e1->semantic(sc); - t1 = e1->type; - - // BUG: this should really be done by checking the static - // call graph - if (f == sc->func) - { error("cyclic constructor call"); - return new ErrorExp(); - } - } - } - else if (e1->op == TOKoverloadset) - { - OverExp *eo = (OverExp *)e1; - FuncDeclaration *f = NULL; - Dsymbol *s = NULL; - for (size_t i = 0; i < eo->vars->a.dim; i++) - { s = eo->vars->a.tdata()[i]; - FuncDeclaration *f2 = s->isFuncDeclaration(); - if (f2) - { - f2 = f2->overloadResolve(loc, ethis, arguments, 1); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f2 = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments, 1); - } - if (f2) - { if (f) - /* Error if match in more than one overload set, - * even if one is a 'better' match than the other. - */ - ScopeDsymbol::multiplyDefined(loc, f, f2); - else - f = f2; - } - } - if (!f) - { /* No overload matches - */ - error("no overload matches for %s", s->toChars()); - return new ErrorExp(); - } - if (ethis) - e1 = new DotVarExp(loc, ethis, f); - else - e1 = new VarExp(loc, f); - goto Lagain; - } - else if (!t1) - { - error("function expected before (), not '%s'", e1->toChars()); - return new ErrorExp(); - } - else if (t1->ty != Tfunction) - { - if (t1->ty == Tdelegate) - { TypeDelegate *td = (TypeDelegate *)t1; - assert(td->next->ty == Tfunction); - tf = (TypeFunction *)(td->next); - if (sc->func && !tf->purity && !(sc->flags & SCOPEdebug)) - { - if (sc->func->setImpure()) - error("pure function '%s' cannot call impure delegate '%s'", sc->func->toChars(), e1->toChars()); - } - if (sc->func && tf->trust <= TRUSTsystem) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system delegate '%s'", sc->func->toChars(), e1->toChars()); - } - goto Lcheckargs; - } - else if (t1->ty == Tpointer && ((TypePointer *)t1)->next->ty == Tfunction) - { - Expression *e = new PtrExp(loc, e1); - t1 = ((TypePointer *)t1)->next; - if (sc->func && !((TypeFunction *)t1)->purity && !(sc->flags & SCOPEdebug)) - { - if (sc->func->setImpure()) - error("pure function '%s' cannot call impure function pointer '%s'", sc->func->toChars(), e1->toChars()); - } - if (sc->func && ((TypeFunction *)t1)->trust <= TRUSTsystem) - { - if (sc->func->setUnsafe()) - error("safe function '%s' cannot call system function pointer '%s'", sc->func->toChars(), e1->toChars()); - } - e->type = t1; - e1 = e; - } - else if (e1->op == TOKtemplate) - { - TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); - if (!f) - { if (tierror) - tierror->error("errors instantiating template"); // give better error message - return new ErrorExp(); - } - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotTemplateExp(loc, (new ThisExp(loc))->semantic(sc), te->td); - goto Lagain; - } - - e1 = new VarExp(loc, f); - goto Lagain; - } - else - { error("function expected before (), not %s of type %s", e1->toChars(), e1->type->toChars()); - return new ErrorExp(); - } - } - else if (e1->op == TOKvar) - { - // Do overload resolution - VarExp *ve = (VarExp *)e1; - - f = ve->var->isFuncDeclaration(); - assert(f); - - if (ve->hasOverloads) - f = f->overloadResolve(loc, NULL, arguments); - checkDeprecated(sc, f); -#if DMDV2 - checkPurity(sc, f); - checkSafety(sc, f); -#endif - f->checkNestedReference(sc, loc); - - if (f->needThis() && hasThis(sc)) - { - // Supply an implicit 'this', as in - // this.ident - - e1 = new DotVarExp(loc, new ThisExp(loc), f); - goto Lagain; - } - - accessCheck(loc, sc, NULL, f); - - ethis = NULL; - - ve->var = f; -// ve->hasOverloads = 0; - ve->type = f->type; - t1 = f->type; - } - assert(t1->ty == Tfunction); - tf = (TypeFunction *)(t1); - -Lcheckargs: - assert(tf->ty == Tfunction); - - if (!arguments) - arguments = new Expressions(); - int olderrors = global.errors; - type = functionParameters(loc, sc, tf, ethis, arguments, f); - if (olderrors != global.errors) - return new ErrorExp(); - - if (!type) - { - error("forward reference to inferred return type of function call %s", toChars()); - return new ErrorExp(); - } - - if (f && f->tintro) - { - Type *t = type; - int offset = 0; - TypeFunction *tf = (TypeFunction *)f->tintro; - - if (tf->next->isBaseOf(t, &offset) && offset) - { - type = tf->next; - return castTo(sc, t); - } - } - - return this; -} - - -#if DMDV2 -int CallExp::isLvalue() -{ -// if (type->toBasetype()->ty == Tstruct) -// return 1; - Type *tb = e1->type->toBasetype(); - if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) - return 1; // function returns a reference - return 0; -} -#endif - -Expression *CallExp::toLvalue(Scope *sc, Expression *e) -{ - if (isLvalue()) - return this; - return Expression::toLvalue(sc, e); -} - -Expression *CallExp::addDtorHook(Scope *sc) -{ - /* Only need to add dtor hook if it's a type that needs destruction. - * Use same logic as VarDeclaration::callScopeDtor() - */ - - if (e1->type && e1->type->ty == Tfunction) - { - TypeFunction *tf = (TypeFunction *)e1->type; - if (tf->isref) - return this; - } - - Type *tv = type->toBasetype(); - while (tv->ty == Tsarray) - { TypeSArray *ta = (TypeSArray *)tv; - tv = tv->nextOf()->toBasetype(); - } - if (tv->ty == Tstruct) - { TypeStruct *ts = (TypeStruct *)tv; - StructDeclaration *sd = ts->sym; - if (sd->dtor) - { /* Type needs destruction, so declare a tmp - * which the back end will recognize and call dtor on - */ - Identifier *idtmp = Lexer::uniqueId("__tmpfordtor"); - VarDeclaration *tmp = new VarDeclaration(loc, type, idtmp, new ExpInitializer(loc, this)); - tmp->storage_class |= STCctfe; - Expression *ae = new DeclarationExp(loc, tmp); - Expression *e = new CommaExp(loc, ae, new VarExp(loc, tmp)); - e = e->semantic(sc); - return e; - } - } -Lnone: - return this; -} - -void CallExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (e1->op == TOKtype) - /* Avoid parens around type to prevent forbidden cast syntax: - * (sometype)(arg1) - * This is ok since types in constructor calls - * can never depend on parens anyway - */ - e1->toCBuffer(buf, hgs); - else - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('('); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(')'); -} - - -/************************************************************/ - -AddrExp::AddrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKaddress, sizeof(AddrExp), e) -{ -#if IN_LLVM - m = NULL; -#endif -} - -Expression *AddrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("AddrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { -#if IN_LLVM - m = sc->module; -#endif - UnaExp::semantic(sc); - if (e1->type == Type::terror) - return new ErrorExp(); - e1 = e1->toLvalue(sc, NULL); - if (e1->op == TOKerror) - return e1; - if (!e1->type) - { - error("cannot take address of %s", e1->toChars()); - return new ErrorExp(); - } - if (!e1->type->deco) - { - /* No deco means semantic() was not run on the type. - * We have to run semantic() on the symbol to get the right type: - * auto x = &bar; - * pure: int bar() { return 1;} - * otherwise the 'pure' is missing from the type assigned to x. - */ - - error("forward reference to %s", e1->toChars()); - return new ErrorExp(); - } - - type = e1->type->pointerTo(); - - // See if this should really be a delegate - if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *f = dve->var->isFuncDeclaration(); - - if (f) - { - if (!dve->hasOverloads) - f->tookAddressOf++; - Expression *e = new DelegateExp(loc, dve->e1, f, dve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - else if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->canTakeAddressOf()) - { error("cannot take address of %s", e1->toChars()); - return new ErrorExp(); - } - - if (sc->func && !sc->intypeof && !v->isDataseg()) - { - if (sc->func->setUnsafe()) - { - error("cannot take address of %s %s in @safe function %s", - v->isParameter() ? "parameter" : "local", - v->toChars(), - sc->func->toChars()); - } - } - } - - FuncDeclaration *f = ve->var->isFuncDeclaration(); - - if (f) - { -#if IN_LLVM - if (f->isIntrinsic()) - { - error("cannot take the address of intrinsic function %s", e1->toChars()); - return this; - } -#endif - - if (!ve->hasOverloads || - /* Because nested functions cannot be overloaded, - * mark here that we took its address because castTo() - * may not be called with an exact match. - */ - f->toParent2()->isFuncDeclaration()) - f->tookAddressOf++; - if (f->isNested()) - { - Expression *e = new DelegateExp(loc, e1, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - if (f->needThis() && hasThis(sc)) - { - /* Should probably supply 'this' after overload resolution, - * not before. - */ - Expression *ethis = new ThisExp(loc); - Expression *e = new DelegateExp(loc, ethis, f, ve->hasOverloads); - e = e->semantic(sc); - return e; - } - } - } - return optimize(WANTvalue); - } - return this; -} - -void AddrExp::checkEscape() -{ - e1->checkEscapeRef(); -} - -/************************************************************/ - -PtrExp::PtrExp(Loc loc, Expression *e) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ -// if (e->type) -// type = ((TypePointer *)e->type)->next; -} - -PtrExp::PtrExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKstar, sizeof(PtrExp), e) -{ - type = t; -} - -Expression *PtrExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("PtrExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - Expression *e = op_overload(sc); - if (e) - return e; - Type *tb = e1->type->toBasetype(); - switch (tb->ty) - { - case Tpointer: - type = ((TypePointer *)tb)->next; - break; - - case Tsarray: - case Tarray: - if (!global.params.useDeprecated) - error("using * on an array is deprecated; use *(%s).ptr instead", e1->toChars()); - type = ((TypeArray *)tb)->next; - e1 = e1->castTo(sc, type->pointerTo()); - break; - - default: - error("can only * a pointer, not a '%s'", e1->type->toChars()); - case Terror: - return new ErrorExp(); - } - if (!rvalue()) - return new ErrorExp(); - } - return this; -} - -#if DMDV2 -int PtrExp::isLvalue() -{ - return 1; -} -#endif - -void PtrExp::checkEscapeRef() -{ - e1->checkEscape(); -} - -Expression *PtrExp::toLvalue(Scope *sc, Expression *e) -{ -#if 0 - tym = tybasic(e1->ET->Tty); - if (!(tyscalar(tym) || - tym == TYstruct || - tym == TYarray && e->Eoper == TOKaddr)) - synerr(EM_lvalue); // lvalue expected -#endif - return this; -} - -#if DMDV2 -Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - se->var->checkModify(loc, sc, type); - //return toLvalue(sc, e); - } - - return Expression::modifiableLvalue(sc, e); -} -#endif - -void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('*'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -NegExp::NegExp(Loc loc, Expression *e) - : UnaExp(loc, TOKneg, sizeof(NegExp), e) -{ -} - -Expression *NegExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("NegExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -UAddExp::UAddExp(Loc loc, Expression *e) - : UnaExp(loc, TOKuadd, sizeof(UAddExp), e) -{ -} - -Expression *UAddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("UAddExp::semantic('%s')\n", toChars()); -#endif - assert(!type); - e = op_overload(sc); - if (e) - return e; - e1->checkNoBool(); - e1->checkArithmetic(); - return e1; -} - -/************************************************************/ - -ComExp::ComExp(Loc loc, Expression *e) - : UnaExp(loc, TOKtilde, sizeof(ComExp), e) -{ -} - -Expression *ComExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { - e = op_overload(sc); - if (e) - return e; - - e1->checkNoBool(); - if (!e1->isArrayOperand()) - e1 = e1->checkIntegral(); - type = e1->type; - } - return this; -} - -/************************************************************/ - -NotExp::NotExp(Loc loc, Expression *e) - : UnaExp(loc, TOKnot, sizeof(NotExp), e) -{ -} - -Expression *NotExp::semantic(Scope *sc) -{ - if (!type) - { // Note there is no operator overload - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(sc); - type = Type::tboolean; - } - return this; -} - -int NotExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -BoolExp::BoolExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKtobool, sizeof(BoolExp), e) -{ - type = t; -} - -Expression *BoolExp::semantic(Scope *sc) -{ - if (!type) - { // Note there is no operator overload - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToBoolean(sc); - type = Type::tboolean; - } - return this; -} - -int BoolExp::isBit() -{ - return TRUE; -} - -/************************************************************/ - -DeleteExp::DeleteExp(Loc loc, Expression *e) - : UnaExp(loc, TOKdelete, sizeof(DeleteExp), e) -{ -} - -Expression *DeleteExp::semantic(Scope *sc) -{ - Type *tb; - - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->modifiableLvalue(sc, NULL); - if (e1->op == TOKerror) - return e1; - type = Type::tvoid; - - tb = e1->type->toBasetype(); - switch (tb->ty) - { case Tclass: - { TypeClass *tc = (TypeClass *)tb; - ClassDeclaration *cd = tc->sym; - - if (cd->isCOMinterface()) - { /* Because COM classes are deleted by IUnknown.Release() - */ - error("cannot delete instance of COM interface %s", cd->toChars()); - } - break; - } - case Tpointer: - tb = ((TypePointer *)tb)->next->toBasetype(); - if (tb->ty == Tstruct) - { - TypeStruct *ts = (TypeStruct *)tb; - StructDeclaration *sd = ts->sym; - FuncDeclaration *f = sd->aggDelete; - FuncDeclaration *fd = sd->dtor; - - if (!f && !fd) - break; - - /* Construct: - * ea = copy e1 to a tmp to do side effects only once - * eb = call destructor - * ec = call deallocator - */ - Expression *ea = NULL; - Expression *eb = NULL; - Expression *ec = NULL; - VarDeclaration *v; - - if (fd && f) - { Identifier *id = Lexer::idPool("__tmp"); - v = new VarDeclaration(loc, e1->type, id, new ExpInitializer(loc, e1)); - v->semantic(sc); - v->parent = sc->parent; - ea = new DeclarationExp(loc, v); - ea->type = v->type; - } - - if (fd) - { Expression *e = ea ? new VarExp(loc, v) : e1; - e = new DotVarExp(0, e, fd, 0); - eb = new CallExp(loc, e); - eb = eb->semantic(sc); - } - - if (f) - { - Type *tpv = Type::tvoid->pointerTo(); - Expression *e = ea ? new VarExp(loc, v) : e1->castTo(sc, tpv); - e = new CallExp(loc, new VarExp(loc, f), e); - ec = e->semantic(sc); - } - ea = combine(ea, eb); - ea = combine(ea, ec); - assert(ea); - return ea; - } - break; - - case Tarray: - /* BUG: look for deleting arrays of structs with dtors. - */ - break; - - default: - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - break; - } - error("cannot delete type %s", e1->type->toChars()); - return new ErrorExp(); - } - - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)(e1); - Type *tb1 = ae->e1->type->toBasetype(); - if (tb1->ty == Taarray) - { if (!global.params.useDeprecated) - error("delete aa[key] deprecated, use aa.remove(key)"); - } - } - - return this; -} - - -Expression *DeleteExp::checkToBoolean(Scope *sc) -{ - error("delete does not give a boolean result"); - return new ErrorExp(); -} - -void DeleteExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete "); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -CastExp::CastExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = t; - this->mod = ~0; -#if IN_LLVM - disableOptimization = false; -#endif -} - -#if DMDV2 -/* For cast(const) and cast(immutable) - */ -CastExp::CastExp(Loc loc, Expression *e, unsigned mod) - : UnaExp(loc, TOKcast, sizeof(CastExp), e) -{ - to = NULL; - this->mod = mod; -#if IN_LLVM - disableOptimization = false; -#endif -} -#endif - -Expression *CastExp::syntaxCopy() -{ - return to ? new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()) - : new CastExp(loc, e1->syntaxCopy(), mod); -} - - -Expression *CastExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("CastExp::semantic('%s')\n", toChars()); -#endif - -//static int x; assert(++x < 10); - - if (type) - return this; - UnaExp::semantic(sc); - if (e1->type) // if not a tuple - { - e1 = resolveProperties(sc, e1); - - if (!to) - { - /* Handle cast(const) and cast(immutable), etc. - */ - to = e1->type->castMod(mod); - } - else - to = to->semantic(loc, sc); - - if (!to->equals(e1->type)) - { -#if 0 // attempt at fixing 6720 - if (e1->type->ty == Tvoid) - { - error("cannot cast from void to %s", to->toChars()); - return new ErrorExp(); - } -#endif - Expression *e = op_overload(sc); - if (e) - { - return e->implicitCastTo(sc, to); - } - } - - if (e1->op == TOKtemplate) - { - error("cannot cast template %s to type %s", e1->toChars(), to->toChars()); - return new ErrorExp(); - } - - Type *t1b = e1->type->toBasetype(); - Type *tob = to->toBasetype(); - - if (e1->op == TOKfunction && - (tob->ty == Tdelegate || tob->ty == Tpointer && tob->nextOf()->ty == Tfunction)) - { - FuncExp *fe = (FuncExp *)e1; - Expression *e = NULL; - if (e1->type == Type::tvoid) - { - e = fe->inferType(sc, tob); - } - else if (e1->type->ty == Tpointer && e1->type->nextOf()->ty == Tfunction && - fe->tok == TOKreserved && - tob->ty == Tdelegate) - { - if (fe->implicitConvTo(tob)) - e = fe->castTo(sc, tob); - } - if (e) - e1 = e->semantic(sc); - } - - if (tob->ty == Tstruct && - !tob->equals(t1b) - ) - { - /* Look to replace: - * cast(S)t - * with: - * S(t) - */ - - // Rewrite as to.call(e1) - Expression *e = new TypeExp(loc, to); - e = new CallExp(loc, e, e1); - e = e->trySemantic(sc); - if (e) - return e; - } - - // Struct casts are possible only when the sizes match - // Same with static array -> static array - if (tob->ty == Tstruct || t1b->ty == Tstruct || - (tob->ty == Tsarray && t1b->ty == Tsarray)) - { - size_t fromsize = t1b->size(loc); - size_t tosize = tob->size(loc); - if (fromsize != tosize) - { - error("cannot cast from %s to %s", e1->type->toChars(), to->toChars()); - return new ErrorExp(); - } - } - - // Look for casting to a vector type - if (tob->ty == Tvector && t1b->ty != Tvector) - { - return new VectorExp(loc, e1, to); - } - } - else if (!to) - { error("cannot cast tuple"); - return new ErrorExp(); - } - - if (!e1->type) - { error("cannot cast %s", e1->toChars()); - return new ErrorExp(); - } - - // Check for unsafe casts - if (sc->func && !sc->intypeof) - { // Disallow unsafe casts - Type *tob = to->toBasetype(); - Type *t1b = e1->type->toBasetype(); - - // Implicit conversions are always safe - if (t1b->implicitConvTo(tob)) - goto Lsafe; - - if (!t1b->isMutable() && tob->isMutable()) - goto Lunsafe; - - if (t1b->isShared() && !tob->isShared()) - // Cast away shared - goto Lunsafe; - - if (!tob->hasPointers()) - goto Lsafe; - - if (tob->ty == Tclass && t1b->ty == Tclass) - { - ClassDeclaration *cdfrom = t1b->isClassHandle(); - ClassDeclaration *cdto = tob->isClassHandle(); - - int offset; - if (!cdfrom->isBaseOf(cdto, &offset)) - goto Lunsafe; - - if (cdfrom->isCPPinterface() || - cdto->isCPPinterface()) - goto Lunsafe; - - goto Lsafe; - } - - if (tob->ty == Tarray && t1b->ty == Tarray) - { - Type* tobn = tob->nextOf()->toBasetype(); - Type* t1bn = t1b->nextOf()->toBasetype(); - if (!tobn->hasPointers() && MODimplicitConv(t1bn->mod, tobn->mod)) - goto Lsafe; - } - if (tob->ty == Tpointer && t1b->ty == Tpointer) - { - Type* tobn = tob->nextOf()->toBasetype(); - Type* t1bn = t1b->nextOf()->toBasetype(); - if (!tobn->hasPointers() && - tobn->ty != Tfunction && t1bn->ty != Tfunction && - tobn->size() <= t1bn->size() && - MODimplicitConv(t1bn->mod, tobn->mod)) - goto Lsafe; - } - - Lunsafe: - if (sc->func->setUnsafe()) - { error("cast from %s to %s not allowed in safe code", e1->type->toChars(), to->toChars()); - return new ErrorExp(); - } - } - -Lsafe: - Expression *e = e1->castTo(sc, to); - return e; -} - - -void CastExp::checkEscape() -{ Type *tb = type->toBasetype(); - -#if IN_LLVM - if (e1->op == TOKvar && - tb->ty == Tpointer && - e1->type->toBasetype()->ty == Tsarray) - { - VarDeclaration *v = ((VarExp*)e1)->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !(v->storage_class & (STCref | STCout))) - error("escaping reference to local variable %s", v->toChars()); - } - } -#endif - - if (tb->ty == Tarray && e1->op == TOKvar && - e1->type->toBasetype()->ty == Tsarray) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v) - { - if (!v->isDataseg() && !v->isParameter()) - error("escaping reference to local %s", v->toChars()); - } - } -} - -void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); -#if DMDV1 - to->toCBuffer(buf, NULL, hgs); -#else - if (to) - to->toCBuffer(buf, NULL, hgs); - else - { - MODtoBuffer(buf, mod); - } -#endif - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -VectorExp::VectorExp(Loc loc, Expression *e, Type *t) - : UnaExp(loc, TOKvector, sizeof(VectorExp), e) -{ - assert(t->ty == Tvector); - to = t; - dim = ~0; -} - -Expression *VectorExp::syntaxCopy() -{ - return new VectorExp(loc, e1->syntaxCopy(), to->syntaxCopy()); -} - -Expression *VectorExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("VectorExp::semantic('%s')\n", toChars()); -#endif - - if (type) - return this; - e1 = e1->semantic(sc); - type = to->semantic(loc, sc); - if (e1->op == TOKerror || type->ty == Terror) - return e1; - Type *tb = type->toBasetype(); - assert(tb->ty == Tvector); - TypeVector *tv = (TypeVector *)tb; - Type *te = tv->elementType(); - dim = tv->size(loc) / te->size(loc); - return this; -} - -void VectorExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("cast("); - to->toCBuffer(buf, NULL, hgs); - buf->writeByte(')'); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -SliceExp::SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr) - : UnaExp(loc, TOKslice, sizeof(SliceExp), e1) -{ - this->upr = upr; - this->lwr = lwr; - lengthVar = NULL; -} - -Expression *SliceExp::syntaxCopy() -{ - Expression *lwr = NULL; - if (this->lwr) - lwr = this->lwr->syntaxCopy(); - - Expression *upr = NULL; - if (this->upr) - upr = this->upr->syntaxCopy(); - - return new SliceExp(loc, e1->syntaxCopy(), lwr, upr); -} - -Expression *SliceExp::semantic(Scope *sc) -{ Expression *e; - AggregateDeclaration *ad; - //FuncDeclaration *fd; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("SliceExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - -Lagain: - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = this; - - Type *t = e1->type->toBasetype(); - if (t->ty == Tpointer) - { - if (!lwr || !upr) - { error("need upper and lower bound to slice pointer"); - return new ErrorExp(); - } - } - else if (t->ty == Tarray) - { - } - else if (t->ty == Tsarray) - { - } - else if (t->ty == Tclass) - { - ad = ((TypeClass *)t)->sym; - goto L1; - } - else if (t->ty == Tstruct) - { - ad = ((TypeStruct *)t)->sym; - - L1: - if (search_function(ad, Id::slice)) - { - // Rewrite as e1.slice(lwr, upr) - e = new DotIdExp(loc, e1, Id::slice); - - if (lwr) - { - assert(upr); - e = new CallExp(loc, e, lwr, upr); - } - else - { assert(!upr); - e = new CallExp(loc, e); - } - e = e->semantic(sc); - return e; - } - if (ad->aliasthis) - { - e1 = new DotIdExp(e1->loc, e1, ad->aliasthis->ident); - goto Lagain; - } - goto Lerror; - } - else if (t->ty == Ttuple) - { - if (!lwr && !upr) - return e1; - if (!lwr || !upr) - { error("need upper and lower bound to slice tuple"); - goto Lerror; - } - } - else if (t == Type::terror) - goto Lerr; - else - goto Lerror; - - { - Scope *sc2 = sc; - if (t->ty == Tsarray || t->ty == Tarray || t->ty == Ttuple) - { - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc2 = sc->push(sym); - } - - if (lwr) - { lwr = lwr->semantic(sc2); - lwr = resolveProperties(sc2, lwr); - lwr = lwr->implicitCastTo(sc2, Type::tsize_t); - if (lwr->type == Type::terror) - goto Lerr; - } - if (upr) - { upr = upr->semantic(sc2); - upr = resolveProperties(sc2, upr); - upr = upr->implicitCastTo(sc2, Type::tsize_t); - if (upr->type == Type::terror) - goto Lerr; - } - - if (sc2 != sc) - sc2->pop(); - } - - if (t->ty == Ttuple) - { - lwr = lwr->optimize(WANTvalue | WANTinterpret); - upr = upr->optimize(WANTvalue | WANTinterpret); - uinteger_t i1 = lwr->toUInteger(); - uinteger_t i2 = upr->toUInteger(); - - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) // slicing an expression tuple - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) // slicing a type tuple - { tup = (TypeTuple *)t; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (i1 <= i2 && i2 <= length) - { size_t j1 = (size_t) i1; - size_t j2 = (size_t) i2; - - if (e1->op == TOKtuple) - { Expressions *exps = new Expressions; - exps->setDim(j2 - j1); - for (size_t i = 0; i < j2 - j1; i++) - { Expression *e = (*te->exps)[j1 + i]; - (*exps)[i] = e; - } - if (j1 > 0 && j2 - j1 > 0 && sc->func && (*te->exps)[0]->op == TOKdotvar) - { - Expression *einit = ((DotVarExp *)(*te->exps)[0])->e1->isTemp(); - if (einit) - ((DotVarExp *)(*exps)[0])->e1 = einit; - } - e = new TupleExp(loc, exps); - } - else - { Parameters *args = new Parameters; - args->reserve(j2 - j1); - for (size_t i = j1; i < j2; i++) - { Parameter *arg = Parameter::getNth(tup->arguments, i); - args->push(arg); - } - e = new TypeExp(e1->loc, new TypeTuple(args)); - } - e = e->semantic(sc); - } - else - { - error("string slice [%ju .. %ju] is out of bounds", i1, i2); - goto Lerr; - } - return e; - } - - type = t->nextOf()->arrayOf(); - // Allow typedef[] -> typedef[] - if (type->equals(t)) - type = e1->type; - - return e; - -Lerror: - if (e1->op == TOKerror) - return e1; - char *s; - if (t->ty == Tvoid) - s = e1->toChars(); - else - s = t->toChars(); - error("%s cannot be sliced with []", s); -Lerr: - e = new ErrorExp(); - return e; -} - -void SliceExp::checkEscape() -{ - e1->checkEscape(); -} - -void SliceExp::checkEscapeRef() -{ - e1->checkEscapeRef(); -} - -#if DMDV2 -int SliceExp::isLvalue() -{ - return 1; -} -#endif - -Expression *SliceExp::toLvalue(Scope *sc, Expression *e) -{ - return this; -} - -Expression *SliceExp::modifiableLvalue(Scope *sc, Expression *e) -{ - error("slice expression %s is not a modifiable lvalue", toChars()); - return this; -} - -int SliceExp::isBool(int result) -{ - return e1->isBool(result); -} - -void SliceExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writeByte('['); - if (upr || lwr) - { - if (lwr) - expToCBuffer(buf, hgs, lwr, PREC_assign); - else - buf->writeByte('0'); - buf->writestring(".."); - if (upr) - expToCBuffer(buf, hgs, upr, PREC_assign); - else - buf->writestring("length"); // BUG: should be array.length - } - buf->writeByte(']'); -} - -/********************** ArrayLength **************************************/ - -ArrayLengthExp::ArrayLengthExp(Loc loc, Expression *e1) - : UnaExp(loc, TOKarraylength, sizeof(ArrayLengthExp), e1) -{ -} - -Expression *ArrayLengthExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("ArrayLengthExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - type = Type::tsize_t; - } - return this; -} - -Expression *opAssignToOp(Loc loc, enum TOK op, Expression *e1, Expression *e2) -{ Expression *e; - - switch (op) - { - case TOKaddass: e = new AddExp(loc, e1, e2); break; - case TOKminass: e = new MinExp(loc, e1, e2); break; - case TOKmulass: e = new MulExp(loc, e1, e2); break; - case TOKdivass: e = new DivExp(loc, e1, e2); break; - case TOKmodass: e = new ModExp(loc, e1, e2); break; - case TOKandass: e = new AndExp(loc, e1, e2); break; - case TOKorass: e = new OrExp (loc, e1, e2); break; - case TOKxorass: e = new XorExp(loc, e1, e2); break; - case TOKshlass: e = new ShlExp(loc, e1, e2); break; - case TOKshrass: e = new ShrExp(loc, e1, e2); break; - case TOKushrass: e = new UshrExp(loc, e1, e2); break; - default: assert(0); - } - return e; -} - -/********************* - * Rewrite: - * array.length op= e2 - * as: - * array.length = array.length op e2 - * or: - * auto tmp = &array; - * (*tmp).length = (*tmp).length op e2 - */ - -Expression *ArrayLengthExp::rewriteOpAssign(BinExp *exp) -{ Expression *e; - - assert(exp->e1->op == TOKarraylength); - ArrayLengthExp *ale = (ArrayLengthExp *)exp->e1; - if (ale->e1->op == TOKvar) - { e = opAssignToOp(exp->loc, exp->op, ale, exp->e2); - e = new AssignExp(exp->loc, ale->syntaxCopy(), e); - } - else - { - /* auto tmp = &array; - * (*tmp).length = (*tmp).length op e2 - */ - Identifier *id = Lexer::uniqueId("__arraylength"); - ExpInitializer *ei = new ExpInitializer(ale->loc, new AddrExp(ale->loc, ale->e1)); - VarDeclaration *tmp = new VarDeclaration(ale->loc, ale->e1->type->pointerTo(), id, ei); - - Expression *e1 = new ArrayLengthExp(ale->loc, new PtrExp(ale->loc, new VarExp(ale->loc, tmp))); - Expression *elvalue = e1->syntaxCopy(); - e = opAssignToOp(exp->loc, exp->op, e1, exp->e2); - e = new AssignExp(exp->loc, elvalue, e); - e = new CommaExp(exp->loc, new DeclarationExp(ale->loc, tmp), e); - } - return e; -} - -void ArrayLengthExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".length"); -} - -/*********************** ArrayExp *************************************/ - -// e1 [ i1, i2, i3, ... ] - -ArrayExp::ArrayExp(Loc loc, Expression *e1, Expressions *args) - : UnaExp(loc, TOKarray, sizeof(ArrayExp), e1) -{ - arguments = args; - lengthVar = NULL; - currentDimension = 0; -} - -Expression *ArrayExp::syntaxCopy() -{ - return new ArrayExp(loc, e1->syntaxCopy(), arraySyntaxCopy(arguments)); -} - -Expression *ArrayExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - -#if LOGSEMANTIC - printf("ArrayExp::semantic('%s')\n", toChars()); -#endif - UnaExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - t1 = e1->type->toBasetype(); - if (t1->ty != Tclass && t1->ty != Tstruct) - { // Convert to IndexExp - if (arguments->dim != 1) - { error("only one index allowed to index %s", t1->toChars()); - goto Lerr; - } - e = new IndexExp(loc, e1, arguments->tdata()[0]); - return e->semantic(sc); - } - - e = op_overload(sc); - if (!e) - { error("no [] operator overload for type %s", e1->type->toChars()); - goto Lerr; - } - return e; - -Lerr: - return new ErrorExp(); -} - -#if DMDV2 -int ArrayExp::isLvalue() -{ - if (type && type->toBasetype()->ty == Tvoid) - return 0; - return 1; -} -#endif - -Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) -{ - if (type && type->toBasetype()->ty == Tvoid) - error("voids have no value"); - return this; -} - - -void ArrayExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - argsToCBuffer(buf, arguments, hgs); - buf->writeByte(']'); -} - -/************************* DotExp ***********************************/ - -DotExp::DotExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdotexp, sizeof(DotExp), e1, e2) -{ -} - -Expression *DotExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("DotExp::semantic('%s')\n", toChars()); - if (type) printf("\ttype = %s\n", type->toChars()); -#endif - e1 = e1->semantic(sc); - e2 = e2->semantic(sc); - if (e2->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)e2; - TemplateDeclaration *td = se->sds->isTemplateDeclaration(); - if (td) - { Expression *e = new DotTemplateExp(loc, e1, td); - e = e->semantic(sc); - return e; - } - } - if (!type) - type = e2->type; - return this; -} - -void DotExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - expToCBuffer(buf, hgs, e2, PREC_primary); -} - -/************************* CommaExp ***********************************/ - -CommaExp::CommaExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcomma, sizeof(CommaExp), e1, e2) -{ -} - -Expression *CommaExp::semantic(Scope *sc) -{ - if (!type) - { BinExp::semanticp(sc); - e1 = e1->addDtorHook(sc); - type = e2->type; - } - return this; -} - -void CommaExp::checkEscape() -{ - e2->checkEscape(); -} - -void CommaExp::checkEscapeRef() -{ - e2->checkEscapeRef(); -} - -#if DMDV2 -int CommaExp::isLvalue() -{ - return e2->isLvalue(); -} -#endif - -Expression *CommaExp::toLvalue(Scope *sc, Expression *e) -{ - e2 = e2->toLvalue(sc, NULL); - return this; -} - -Expression *CommaExp::modifiableLvalue(Scope *sc, Expression *e) -{ - e2 = e2->modifiableLvalue(sc, e); - return this; -} - -int CommaExp::isBool(int result) -{ - return e2->isBool(result); -} - - -Expression *CommaExp::addDtorHook(Scope *sc) -{ - e2 = e2->addDtorHook(sc); - return this; -} - -/************************** IndexExp **********************************/ - -// e1 [ e2 ] - -IndexExp::IndexExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKindex, sizeof(IndexExp), e1, e2) -{ - //printf("IndexExp::IndexExp('%s')\n", toChars()); - lengthVar = NULL; - modifiable = 0; // assume it is an rvalue -} - -Expression *IndexExp::semantic(Scope *sc) -{ Expression *e; - Type *t1; - ScopeDsymbol *sym; - -#if LOGSEMANTIC - printf("IndexExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - if (!e1->type) - e1 = e1->semantic(sc); - assert(e1->type); // semantic() should already be run on it - if (e1->op == TOKerror) - goto Lerr; - e = this; - - // Note that unlike C we do not implement the int[ptr] - - t1 = e1->type->toBasetype(); - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - { // Create scope for 'length' variable - sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - } - - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - if (e2->type == Type::terror) - goto Lerr; - if (e2->type->ty == Ttuple && ((TupleExp *)e2)->exps->dim == 1) // bug 4444 fix - e2 = ((TupleExp *)e2)->exps->tdata()[0]; - - if (t1->ty == Tsarray || t1->ty == Tarray || t1->ty == Ttuple) - sc = sc->pop(); - - switch (t1->ty) - { - case Tpointer: - case Tarray: - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e->type = ((TypeNext *)t1)->next; - break; - - case Tsarray: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - - TypeSArray *tsa = (TypeSArray *)t1; - -#if 0 // Don't do now, because it might be short-circuit evaluated - // Do compile time array bounds checking if possible - e2 = e2->optimize(WANTvalue); - if (e2->op == TOKint64) - { - dinteger_t index = e2->toInteger(); - dinteger_t length = tsa->dim->toInteger(); - if (index < 0 || index >= length) - error("array index [%lld] is outside array bounds [0 .. %lld]", - index, length); - } -#endif - e->type = t1->nextOf(); - break; - } - - case Taarray: - { TypeAArray *taa = (TypeAArray *)t1; - /* We can skip the implicit conversion if they differ only by - * constness (Bugzilla 2684, see also bug 2954b) - */ - if (!arrayTypeCompatibleWithoutCasting(e2->loc, e2->type, taa->index)) - { - e2 = e2->implicitCastTo(sc, taa->index); // type checking - } - type = taa->next; - break; - } - - case Ttuple: - { - e2 = e2->implicitCastTo(sc, Type::tsize_t); - e2 = e2->optimize(WANTvalue | WANTinterpret); - uinteger_t index = e2->toUInteger(); - size_t length; - TupleExp *te; - TypeTuple *tup; - - if (e1->op == TOKtuple) - { te = (TupleExp *)e1; - length = te->exps->dim; - } - else if (e1->op == TOKtype) - { - tup = (TypeTuple *)t1; - length = Parameter::dim(tup->arguments); - } - else - assert(0); - - if (index < length) - { - - if (e1->op == TOKtuple) - { - e = (*te->exps)[(size_t)index]; - if (sc->func && (*te->exps)[0]->op == TOKdotvar) - { - Expression *einit = ((DotVarExp *)(*te->exps)[0])->e1->isTemp(); - if (einit) - ((DotVarExp *)e)->e1 = einit; - } - } - else - e = new TypeExp(e1->loc, Parameter::getNth(tup->arguments, (size_t)index)->type); - } - else - { - error("array index [%ju] is outside array bounds [0 .. %zu]", - index, length); - e = e1; - } - break; - } - - default: - if (e1->op == TOKerror) - goto Lerr; - error("%s must be an array or pointer type, not %s", - e1->toChars(), e1->type->toChars()); - case Terror: - goto Lerr; - } - return e; - -Lerr: - return new ErrorExp(); -} - -#if DMDV2 -int IndexExp::isLvalue() -{ - return 1; -} -#endif - -Expression *IndexExp::toLvalue(Scope *sc, Expression *e) -{ -// if (type && type->toBasetype()->ty == Tvoid) -// error("voids have no value"); - return this; -} - -Expression *IndexExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //printf("IndexExp::modifiableLvalue(%s)\n", toChars()); - modifiable = 1; - if (e1->op == TOKstring) - error("string literals are immutable"); - if (type && (!type->isMutable() || !type->isAssignable())) - error("%s isn't mutable", e->toChars()); - Type *t1 = e1->type->toBasetype(); - if (t1->ty == Taarray) - { TypeAArray *taa = (TypeAArray *)t1; - Type *t2b = e2->type->toBasetype(); - if (t2b->ty == Tarray && t2b->nextOf()->isMutable()) - error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars()); - e1 = e1->modifiableLvalue(sc, e1); - } - return toLvalue(sc, e); -} - -void IndexExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('['); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writeByte(']'); -} - - -/************************* PostExp ***********************************/ - -PostExp::PostExp(enum TOK op, Loc loc, Expression *e) - : BinExp(loc, op, sizeof(PostExp), e, - new IntegerExp(loc, 1, Type::tint32)) -{ -} - -Expression *PostExp::semantic(Scope *sc) -{ Expression *e = this; - - if (!type) - { - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - - e = op_overload(sc); - if (e) - return e; - - e1 = e1->modifiableLvalue(sc, e1); - - Type *t1 = e1->type->toBasetype(); - if (t1->ty == Tclass || t1->ty == Tstruct) - { /* Check for operator overloading, - * but rewrite in terms of ++e instead of e++ - */ - - /* If e1 is not trivial, take a reference to it - */ - Expression *de = NULL; - if (e1->op != TOKvar) - { - // ref v = e1; - Identifier *id = Lexer::uniqueId("__postref"); - ExpInitializer *ei = new ExpInitializer(loc, e1); - VarDeclaration *v = new VarDeclaration(loc, e1->type, id, ei); - v->storage_class |= STCref | STCforeach; - de = new DeclarationExp(loc, v); - e1 = new VarExp(e1->loc, v); - } - - /* Rewrite as: - * auto tmp = e1; ++e1; tmp - */ - Identifier *id = Lexer::uniqueId("__pitmp"); - ExpInitializer *ei = new ExpInitializer(loc, e1); - VarDeclaration *tmp = new VarDeclaration(loc, e1->type, id, ei); - Expression *ea = new DeclarationExp(loc, tmp); - - Expression *eb = e1->syntaxCopy(); - eb = new PreExp(op == TOKplusplus ? TOKpreplusplus : TOKpreminusminus, loc, eb); - - Expression *ec = new VarExp(loc, tmp); - - // Combine de,ea,eb,ec - if (de) - ea = new CommaExp(loc, de, ea); - e = new CommaExp(loc, ea, eb); - e = new CommaExp(loc, e, ec); - e = e->semantic(sc); - return e; - } - - e = this; - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer) - e = scaleFactor(sc); - else - e2 = e2->castTo(sc, e1->type); - e->type = e1->type; - } - return e; -} - -void PostExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, precedence[op]); - buf->writestring(Token::toChars(op)); -} - -/************************* PreExp ***********************************/ - -PreExp::PreExp(enum TOK op, Loc loc, Expression *e) - : UnaExp(loc, op, sizeof(PreExp), e) -{ -} - -Expression *PreExp::semantic(Scope *sc) -{ - Expression *e; - - e = op_overload(sc); - if (e) - return e; - - // Rewrite as e1+=1 or e1-=1 - if (op == TOKpreplusplus) - e = new AddAssignExp(loc, e1, new IntegerExp(loc, 1, Type::tint32)); - else - e = new MinAssignExp(loc, e1, new IntegerExp(loc, 1, Type::tint32)); - return e->semantic(sc); -} - -void PreExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - expToCBuffer(buf, hgs, e1, precedence[op]); -} - -/************************************************************/ - -/* op can be TOKassign, TOKconstruct, or TOKblit */ - -AssignExp::AssignExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKassign, sizeof(AssignExp), e1, e2) -{ - ismemset = 0; -} - -Expression *AssignExp::semantic(Scope *sc) -{ - Expression *e1old = e1; - -#if LOGSEMANTIC - printf("AssignExp::semantic('%s')\n", toChars()); -#endif - //printf("e1->op = %d, '%s'\n", e1->op, Token::toChars(e1->op)); - //printf("e2->op = %d, '%s'\n", e2->op, Token::toChars(e2->op)); - - if (type) - return this; - - if (e2->op == TOKcomma) - { /* Rewrite to get rid of the comma from rvalue - */ - AssignExp *ea = new AssignExp(loc, e1, ((CommaExp *)e2)->e2); - ea->op = op; - Expression *e = new CommaExp(loc, ((CommaExp *)e2)->e1, ea); - return e->semantic(sc); - } - - /* Look for operator overloading of a[i]=value. - * Do it before semantic() otherwise the a[i] will have been - * converted to a.opIndex() already. - */ - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - Type *t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L1; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L1: - // Rewrite (a[i] = value) to (a.opIndexAssign(value, i)) - if (search_function(ad, Id::indexass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::indexass); - // Deal with $ - for (size_t i = 0; i < ae->arguments->dim; i++) - { Expression *x = ae->arguments->tdata()[i]; - // Create scope for '$' variable for this dimension - ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, ae); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - ae->lengthVar = NULL; // Create it only if required - ae->currentDimension = i; // Dimension for $, if required - - x = x->semantic(sc); - if (!x->type) - ae->error("%s has no value", x->toChars()); - if (ae->lengthVar) - { // If $ was used, declare it now - Expression *av = new DeclarationExp(ae->loc, ae->lengthVar); - x = new CommaExp(0, av, x); - x->semantic(sc); - } - ae->arguments->tdata()[i] = x; - sc = sc->pop(); - } - Expressions *a = (Expressions *)ae->arguments->copy(); - - a->insert(0, e2); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } -#if 0 // Turned off to allow rewriting (a[i]=value) to (a.opIndex(i)=value) - else - { - // Rewrite (a[i] = value) to (a.opIndex(i, value)) - if (search_function(ad, id)) - { Expression *e = new DotIdExp(loc, ae->e1, id); - - if (1 || !global.params.useDeprecated) - { error("operator [] assignment overload with opIndex(i, value) illegal, use opIndexAssign(value, i)"); - return new ErrorExp(); - } - - e = new CallExp(loc, e, ae->arguments->tdata()[0], e2); - e = e->semantic(sc); - return e; - } - } -#endif - } - - // No opIndexAssign found yet, but there might be an alias this to try. - if (ad && ad->aliasthis) - { Expression *at = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - at = at->semantic(sc); - Type *attype = at->type->toBasetype(); - - if (attype->ty == Tstruct) - { - ad = ((TypeStruct *)attype)->sym; - goto L1; - } - else if (attype->ty == Tclass) - { - ad = ((TypeClass *)attype)->sym; - goto L1; - } - } - } - /* Look for operator overloading of a[i..j]=value. - * Do it before semantic() otherwise the a[i..j] will have been - * converted to a.opSlice() already. - */ - if (e1->op == TOKslice) - { Type *t1; - SliceExp *ae = (SliceExp *)e1; - AggregateDeclaration *ad = NULL; - Identifier *id = Id::index; - - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - t1 = ae->e1->type->toBasetype(); - if (t1->ty == Tstruct) - { - ad = ((TypeStruct *)t1)->sym; - goto L2; - } - else if (t1->ty == Tclass) - { - ad = ((TypeClass *)t1)->sym; - L2: - // Rewrite (a[i..j] = value) to (a.opSliceAssign(value, i, j)) - if (search_function(ad, Id::sliceass)) - { Expression *e = new DotIdExp(loc, ae->e1, Id::sliceass); - Expressions *a = new Expressions(); - - a->push(e2); - if (ae->lwr) - { a->push(ae->lwr); - assert(ae->upr); - a->push(ae->upr); - } - else - assert(!ae->upr); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - } - - // No opSliceAssign found yet, but there might be an alias this to try. - if (ad && ad->aliasthis) - { Expression *at = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - at = at->semantic(sc); - Type *attype = at->type->toBasetype(); - - if (attype->ty == Tstruct) - { - ad = ((TypeStruct *)attype)->sym; - goto L2; - } - else if (attype->ty == Tclass) - { - ad = ((TypeClass *)attype)->sym; - goto L2; - } - } - } - - { - Expression *e = BinExp::semantic(sc); - if (e->op == TOKerror) - return e; - } - - e2 = resolveProperties(sc, e2); - - /* We have f = value. - * Could mean: - * f(value) - * or: - * f() = value - */ - TemplateDeclaration *td; - Objects *targsi; - FuncDeclaration *fd; - Expression *ethis; - if (e1->op == TOKdotti) - { - DotTemplateInstanceExp* dti = (DotTemplateInstanceExp *)e1; - td = dti->getTempdecl(sc); - dti->ti->semanticTiargs(sc); - targsi = dti->ti->tiargs; - ethis = dti->e1; - goto L3; - } - else if (e1->op == TOKdottd) - { - DotTemplateExp *dte = (DotTemplateExp *)e1; - td = dte->td; - targsi = NULL; - ethis = dte->e1; - goto L3; - } - else if (e1->op == TOKtemplate) - { - td = ((TemplateExp *)e1)->td; - targsi = NULL; - ethis = NULL; - L3: - { - assert(td); - Expressions a; - a.push(e2); - - fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, &a, 1); - if (fd && fd->type) - goto Lsetter; - - fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, NULL, 1); - if (fd && fd->type) - goto Lgetter; - } - goto Leprop; - } - else if (e1->op == TOKdotvar && e1->type->toBasetype()->ty == Tfunction) - { - DotVarExp *dve = (DotVarExp *)e1; - fd = dve->var->isFuncDeclaration(); - ethis = dve->e1; - goto L4; - } - else if (e1->op == TOKvar && e1->type->toBasetype()->ty == Tfunction) - { - fd = ((VarExp *)e1)->var->isFuncDeclaration(); - ethis = NULL; - L4: - { - assert(fd); - FuncDeclaration *f = fd; - Expressions a; - a.push(e2); - - fd = f->overloadResolve(loc, ethis, &a, 1); - if (fd && fd->type) - goto Lsetter; - - fd = f->overloadResolve(loc, ethis, NULL, 1); - if (fd && fd->type) - goto Lgetter; - - goto Leprop; - } - - Expression *e; - TypeFunction *tf; - - Lsetter: - assert(fd->type->ty == Tfunction); - tf = (TypeFunction *)fd->type; - if (!tf->isproperty && global.params.enforcePropertySyntax) - goto Leprop; - e = new CallExp(loc, e1, e2); - return e->semantic(sc); - - Lgetter: - assert(fd->type->ty == Tfunction); - tf = (TypeFunction *)fd->type; - if (!tf->isref) - goto Leprop; - if (!tf->isproperty && global.params.enforcePropertySyntax) - goto Leprop; - e = new CallExp(loc, e1); - e = new AssignExp(loc, e, e2); - return e->semantic(sc); - - Leprop: - ::error(e1->loc, "not a property %s", e1->toChars()); - return new ErrorExp(); - } - - assert(e1->type); - - /* Rewrite tuple assignment as a tuple of assignments. - */ -Ltupleassign: - if (e1->op == TOKtuple && e2->op == TOKtuple) - { TupleExp *tup1 = (TupleExp *)e1; - TupleExp *tup2 = (TupleExp *)e2; - size_t dim = tup1->exps->dim; - if (dim != tup2->exps->dim) - { - error("mismatched tuple lengths, %d and %d", (int)dim, (int)tup2->exps->dim); - return new ErrorExp(); - } - else - { Expressions *exps = new Expressions; - exps->setDim(dim); - - for (size_t i = 0; i < dim; i++) - { Expression *ex1 = (*tup1->exps)[i]; - Expression *ex2 = (*tup2->exps)[i]; - (*exps)[i] = new AssignExp(loc, ex1, ex2); - } - Expression *e = new TupleExp(loc, exps); - e = e->semantic(sc); - return e; - } - } - - if (e1->op == TOKtuple) - { - if (TupleDeclaration *td = isAliasThisTuple(e2)) - { - assert(e1->type->ty == Ttuple); - TypeTuple *tt = (TypeTuple *)e1->type; - - Identifier *id = Lexer::uniqueId("__tup"); - VarDeclaration *v = new VarDeclaration(e2->loc, NULL, id, new ExpInitializer(e2->loc, e2)); - v->storage_class = STCctfe | STCref | STCforeach; - Expression *ve = new VarExp(e2->loc, v); - ve->type = e2->type; - - Expressions *iexps = new Expressions(); - iexps->push(ve); - - for (size_t u = 0; u < iexps->dim ; u++) - { - Lexpand: - Expression *e = iexps->tdata()[u]; - - Parameter *arg = Parameter::getNth(tt->arguments, u); - //printf("[%d] iexps->dim = %d, ", u, iexps->dim); - //printf("e = (%s %s, %s), ", Token::tochars[e->op], e->toChars(), e->type->toChars()); - //printf("arg = (%s, %s)\n", arg->toChars(), arg->type->toChars()); - - if (!e->type->implicitConvTo(arg->type)) - { - // expand initializer to tuple - if (expandAliasThisTuples(iexps, u) != -1) - goto Lexpand; - - goto Lnomatch; - } - } - iexps->tdata()[0] = new CommaExp(loc, new DeclarationExp(e2->loc, v), iexps->tdata()[0]); - e2 = new TupleExp(e2->loc, iexps); - e2 = e2->semantic(sc); - goto Ltupleassign; - - Lnomatch: - ; - } - } - - // Determine if this is an initialization of a reference - int refinit = 0; - if (op == TOKconstruct && e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->storage_class & (STCout | STCref)) - refinit = 1; - } - - Type *t1 = e1->type->toBasetype(); - - if (t1->ty == Tdelegate || (t1->ty == Tpointer && t1->nextOf()->ty == Tfunction) - && e2->op == TOKfunction) - { - FuncExp *fe = (FuncExp *)e2; - if (e2->type == Type::tvoid) - { - e2 = fe->inferType(sc, t1); - } - else if (e2->type->ty == Tpointer && e2->type->nextOf()->ty == Tfunction && - fe->tok == TOKreserved && - t1->ty == Tdelegate) - { - if (fe->implicitConvTo(t1)) - e2 = fe->castTo(sc, t1); - } - if (!e2) - { error("cannot infer function literal type from %s", t1->toChars()); - e2 = new ErrorExp(); - } - } - - /* If it is an assignment from a 'foreign' type, - * check for operator overloading. - */ - if (t1->ty == Tstruct) - { - StructDeclaration *sd = ((TypeStruct *)t1)->sym; - if (op == TOKassign) - { - /* See if we need to set ctorinit, i.e. track - * assignments to fields. An assignment to a field counts even - * if done through an opAssign overload. - */ - if (e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)e1; - VarDeclaration *v = dve->var->isVarDeclaration(); - if (v && v->storage_class & STCnodefaultctor) - modifyFieldVar(loc, sc, v, dve->e1); - } - - Expression *e = op_overload(sc); - if (e && e1->op == TOKindex && - ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - // Deal with AAs (Bugzilla 2451) - // Rewrite as: - // e1 = (typeof(aa.value) tmp = void, tmp = e2, tmp); - Type * aaValueType = ((TypeAArray *)((IndexExp*)e1)->e1->type->toBasetype())->next; - Identifier *id = Lexer::uniqueId("__aatmp"); - VarDeclaration *v = new VarDeclaration(loc, aaValueType, - id, new VoidInitializer(0)); - v->storage_class |= STCctfe; - v->semantic(sc); - v->parent = sc->parent; - - Expression *de = new DeclarationExp(loc, v); - VarExp *ve = new VarExp(loc, v); - - AssignExp *ae = new AssignExp(loc, ve, e2); - e = ae->op_overload(sc); - e2 = new CommaExp(loc, new CommaExp(loc, de, e), ve); - e2 = e2->semantic(sc); - } - else if (e) - return e; - } - else if (op == TOKconstruct && !refinit) - { Type *t2 = e2->type->toBasetype(); - if (t2->ty == Tstruct && - sd == ((TypeStruct *)t2)->sym && - sd->cpctor) - { /* We have a copy constructor for this - */ - // Scan past commma's - Expression *ec = NULL; - while (e2->op == TOKcomma) - { CommaExp *ecomma = (CommaExp *)e2; - e2 = ecomma->e2; - if (ec) - ec = new CommaExp(ecomma->loc, ec, ecomma->e1); - else - ec = ecomma->e1; - } - if (e2->op == TOKquestion) - { /* Write as: - * a ? e1 = b : e1 = c; - */ - CondExp *econd = (CondExp *)e2; - AssignExp *ea1 = new AssignExp(econd->e1->loc, e1, econd->e1); - ea1->op = op; - AssignExp *ea2 = new AssignExp(econd->e1->loc, e1, econd->e2); - ea2->op = op; - Expression *e = new CondExp(loc, econd->econd, ea1, ea2); - if (ec) - e = new CommaExp(loc, ec, e); - return e->semantic(sc); - } - else if (e2->op == TOKvar || - e2->op == TOKdotvar || - e2->op == TOKstar || - e2->op == TOKthis || - e2->op == TOKindex) - { /* Write as: - * e1.cpctor(e2); - */ - if (!e2->type->implicitConvTo(e1->type)) - error("conversion error from %s to %s", e2->type->toChars(), e1->type->toChars()); - - Expression *e = new DotVarExp(loc, e1, sd->cpctor, 0); - e = new CallExp(loc, e, e2); - if (ec) - e = new CommaExp(loc, ec, e); - return e->semantic(sc); - } - else if (e2->op == TOKcall) - { - /* The struct value returned from the function is transferred - * so should not call the destructor on it. - */ - valueNoDtor(e2); - } - } - } - } - else if (t1->ty == Tclass) - { // Disallow assignment operator overloads for same type - if (!e2->implicitConvTo(e1->type)) - { - Expression *e = op_overload(sc); - if (e) - return e; - } - } - - if (t1->ty == Tsarray && !refinit) - { - if (e1->op == TOKindex && - ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - // Assignment to an AA of fixed-length arrays. - // Convert T[n][U] = T[] into T[n][U] = T[n] - e2 = e2->implicitCastTo(sc, e1->type); - if (e2->type == Type::terror) - return e2; - } - else - { - Type *t2 = e2->type->toBasetype(); - // Convert e2 to e2[], unless e2-> e1[0] - if (t2->ty == Tsarray && !t2->implicitConvTo(t1->nextOf())) - { - e2 = new SliceExp(e2->loc, e2, NULL, NULL); - e2 = e2->semantic(sc); - } - - // Convert e1 to e1[] - Expression *e = new SliceExp(e1->loc, e1, NULL, NULL); - e1 = e->semantic(sc); - t1 = e1->type->toBasetype(); - } - } - - if (!e2->rvalue()) - return new ErrorExp(); - - if (e1->op == TOKarraylength) - { - // e1 is not an lvalue, but we let code generator handle it - ArrayLengthExp *ale = (ArrayLengthExp *)e1; - - ale->e1 = ale->e1->modifiableLvalue(sc, e1); - } - else if (e1->op == TOKslice) - { - Type *tn = e1->type->nextOf(); - if (op == TOKassign && tn && (!tn->isMutable() || !tn->isAssignable())) - { error("slice %s is not mutable", e1->toChars()); - return new ErrorExp(); - } - } - else - { // Try to do a decent error message with the expression - // before it got constant folded - if (e1->op != TOKvar) - e1 = e1->optimize(WANTvalue); - - if (op != TOKconstruct) - e1 = e1->modifiableLvalue(sc, e1old); - } - - Type *t2 = e2->type->toBasetype(); -#if 0 - if (t1->ty == Tvector && t2->ty != Tvector && - e2->implicitConvTo(((TypeVector *)t1)->basetype->nextOf()) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, ((TypeVector *)t1)->basetype->nextOf()); - } - else -#endif - if (e1->op == TOKslice && - t1->nextOf() && - e2->implicitConvTo(t1->nextOf()) - ) - { // memset - ismemset = 1; // make it easy for back end to tell what this is - e2 = e2->implicitCastTo(sc, t1->nextOf()); - } - else if (t1->ty == Tsarray) - { - /* Should have already converted e1 => e1[] - * unless it is an AA - */ - if (!(e1->op == TOKindex && t2->ty == Tsarray && - ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray)) - { - assert(op == TOKconstruct); - } - //error("cannot assign to static array %s", e1->toChars()); - } - else if (e1->op == TOKslice && t2->ty == Tarray && - t2->nextOf()->implicitConvTo(t1->nextOf())) - { - e2 = e2->implicitCastTo(sc, e1->type->constOf()); - } - else - { - e2 = e2->implicitCastTo(sc, e1->type); - } - - /* Look for array operations - */ - if (e1->op == TOKslice && !ismemset && - (e2->op == TOKadd || e2->op == TOKmin || - e2->op == TOKmul || e2->op == TOKdiv || - e2->op == TOKmod || e2->op == TOKxor || - e2->op == TOKand || e2->op == TOKor || -#if DMDV2 - e2->op == TOKpow || -#endif - e2->op == TOKtilde || e2->op == TOKneg)) - { - type = e1->type; - return arrayOp(sc); - } - - if (e1->op == TOKvar && - (((VarExp *)e1)->var->storage_class & STCscope) && - op == TOKassign) - { - error("cannot rebind scope variables"); - } - - type = e1->type; - assert(type); - return this; -} - -Expression *AssignExp::checkToBoolean(Scope *sc) -{ - // Things like: - // if (a = b) ... - // are usually mistakes. - - error("assignment cannot be used as a condition, perhaps == was meant?"); - return new ErrorExp(); -} - -/************************************************************/ - -ConstructExp::ConstructExp(Loc loc, Expression *e1, Expression *e2) - : AssignExp(loc, e1, e2) -{ - op = TOKconstruct; -} - -/************************************************************/ - -AddAssignExp::AddAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKaddass, sizeof(AddAssignExp), e1, e2) -{ -} - -Expression *AddAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - typeCombine(sc); - e = this; - } - else - { - e1->checkScalar(); - e1->checkNoBool(); - if (tb1->ty == Tpointer && tb2->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tbool) - { -#if 0 - // Need to rethink this - if (e1->op != TOKvar) - { // Rewrite e1+=e2 to (v=&e1),*v=*v+e2 - VarDeclaration *v; - Expression *ea; - Expression *ex; - - Identifier *id = Lexer::uniqueId("__name"); - - v = new VarDeclaration(loc, tb1->pointerTo(), id, NULL); - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - - ea = new AddrExp(loc, e1); - ea = new AssignExp(loc, new VarExp(loc, v), ea); - - ex = new VarExp(loc, v); - ex = new PtrExp(loc, ex); - e = new AddExp(loc, ex, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, ex->syntaxCopy(), e); - - e = new CommaExp(loc, ea, e); - } - else -#endif - { // Rewrite e1+=e2 to e1=e1+e2 - // BUG: doesn't account for side effects in e1 - // BUG: other assignment operators for bits aren't handled at all - e = new AddExp(loc, e1, e2); - e = new CastExp(loc, e, e1->type); - e = new AssignExp(loc, e1->syntaxCopy(), e); - } - e = e->semantic(sc); - } - else - { - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexAddAssign(); - if (type->isreal() || type->isimaginary()) - { - assert(global.errors || e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - } - return e; -} - -/************************************************************/ - -MinAssignExp::MinAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKminass, sizeof(MinAssignExp), e1, e2) -{ -} - -Expression *MinAssignExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - if (e1->op == TOKslice) - { // T[] -= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - if (e1->type->ty == Tpointer && e2->type->isintegral()) - e = scaleFactor(sc); - else - { - e1 = e1->checkArithmetic(); - e2 = e2->checkArithmetic(); - checkComplexAddAssign(); - type = e1->type; - typeCombine(sc); - if (type->isreal() || type->isimaginary()) - { - assert(e2->type->isfloating()); - e2 = e2->castTo(sc, e1->type); - } - e = this; - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - return e; -} - -/************************************************************/ - -CatAssignExp::CatAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKcatass, sizeof(CatAssignExp), e1, e2) -{ -} - -Expression *CatAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatAssignExp::semantic() %s\n", toChars()); - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKslice) - { SliceExp *se = (SliceExp *)e1; - - if (se->e1->type->toBasetype()->ty == Tsarray) - { error("cannot append to static array %s", se->e1->type->toChars()); - return new ErrorExp(); - } - } - - e1 = e1->modifiableLvalue(sc, e1); - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if (!e2->rvalue()) - return new ErrorExp(); - - Type *tb1next = tb1->nextOf(); - - if ((tb1->ty == Tarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - (e2->implicitConvTo(e1->type) -#if DMDV2 - || tb2->nextOf()->implicitConvTo(tb1next) -#endif - ) - ) - { // Append array - e2 = e2->castTo(sc, e1->type); - type = e1->type; - e = this; - } - else if ((tb1->ty == Tarray) && - e2->implicitConvTo(tb1next) - ) - { // Append element - e2 = e2->castTo(sc, tb1next); - type = e1->type; - e = this; - } - else if (tb1->ty == Tarray && - (tb1next->ty == Tchar || tb1next->ty == Twchar) && - e2->type->ty != tb1next->ty && - e2->implicitConvTo(Type::tdchar) - ) - { // Append dchar to char[] or wchar[] - e2 = e2->castTo(sc, Type::tdchar); - type = e1->type; - e = this; - - /* Do not allow appending wchar to char[] because if wchar happens - * to be a surrogate pair, nothing good can result. - */ - } - else - { - if (tb1 != Type::terror && tb2 != Type::terror) - error("cannot append type %s to type %s", tb2->toChars(), tb1->toChars()); - e = new ErrorExp(); - } - return e; -} - -/************************************************************/ - -MulAssignExp::MulAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKmulass, sizeof(MulAssignExp), e1, e2) -{ -} - -Expression *MulAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] *= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isfloating()) - { - Type *t1 = e1->type; - Type *t2 = e2->type; - if (t1->isreal()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - e2 = e2->castTo(sc, t1); - } - } - else if (t1->isimaginary()) - { - if (t2->isimaginary() || t2->iscomplex()) - { - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - } - } - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - } - else if (type->toBasetype()->ty == Tvector && - ((TypeVector *)type->toBasetype())->elementType()->size(loc) != 2) - { // Only short[8] and ushort[8] work with multiply - return incompatibleTypes(); - } - return this; -} - -/************************************************************/ - -DivAssignExp::DivAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKdivass, sizeof(DivAssignExp), e1, e2) -{ -} - -Expression *DivAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - -#if DMDV2 - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } -#endif - - if (e1->op == TOKslice) - { // T[] /= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - type = e1->type; - return arrayOp(sc); - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - typeCombine(sc); - e1->checkArithmetic(); - e2->checkArithmetic(); - checkComplexMulAssign(); - if (e2->type->isimaginary()) - { - Type *t1 = e1->type; - if (t1->isreal()) - { // x/iv = i(-x/v) - // Therefore, the result is 0 - e2 = new CommaExp(loc, e2, new RealExp(loc, 0, t1)); - e2->type = t1; - e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - else if (t1->isimaginary()) - { Type *t2; - - switch (t1->ty) - { - case Timaginary32: t2 = Type::tfloat32; break; - case Timaginary64: t2 = Type::tfloat64; break; - case Timaginary80: t2 = Type::tfloat80; break; - default: - assert(0); - } - e2 = e2->castTo(sc, t2); - Expression *e = new AssignExp(loc, e1, e2); - e->type = t1; - return e; - } - } - else if (type->toBasetype()->ty == Tvector && !e1->type->isfloating()) - return incompatibleTypes(); - - if (e2->type->iscomplex() && !type->iscomplex()) - error("Cannot assign %s to %s", e2->type->toChars(), type->toChars()); - - return this; -} - -/************************************************************/ - -ModAssignExp::ModAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKmodass, sizeof(ModAssignExp), e1, e2) -{ -} - -Expression *ModAssignExp::semantic(Scope *sc) -{ - if (!type) - { - Expression *e = op_overload(sc); - if (e) - return e; - - checkComplexMulAssign(); - return commonSemanticAssign(sc); - } - return this; -} - -/************************************************************/ - -ShlAssignExp::ShlAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshlass, sizeof(ShlAssignExp), e1, e2) -{ -} - -Expression *ShlAssignExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlAssignExp::semantic()\n"); - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -/************************************************************/ - -ShrAssignExp::ShrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKshrass, sizeof(ShrAssignExp), e1, e2) -{ -} - -Expression *ShrAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); -#if IN_DMD - e2 = e2->castTo(sc, Type::tshiftcnt); -#elif IN_LLVM - e2 = e2->castTo(sc, e1->type); -#endif - return this; -} - -/************************************************************/ - -UshrAssignExp::UshrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKushrass, sizeof(UshrAssignExp), e1, e2) -{ -} - -Expression *UshrAssignExp::semantic(Scope *sc) -{ Expression *e; - - e = op_overload(sc); - if (e) - return e; - - if (e1->op == TOKarraylength) - { - e = ArrayLengthExp::rewriteOpAssign(this); - e = e->semantic(sc); - return e; - } - - e1 = e1->modifiableLvalue(sc, e1); - e1->checkScalar(); - e1->checkNoBool(); - type = e1->type; - if (e1->type->toBasetype()->ty == Tvector || e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - typeCombine(sc); - e1->checkIntegral(); - e2 = e2->checkIntegral(); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - return this; -} - -/************************************************************/ - -AndAssignExp::AndAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKandass, sizeof(AndAssignExp), e1, e2) -{ -} - -Expression *AndAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -OrAssignExp::OrAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKorass, sizeof(OrAssignExp), e1, e2) -{ -} - -Expression *OrAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/************************************************************/ - -XorAssignExp::XorAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKxorass, sizeof(XorAssignExp), e1, e2) -{ -} - -Expression *XorAssignExp::semantic(Scope *sc) -{ - return commonSemanticAssignIntegral(sc); -} - -/***************** PowAssignExp *******************************************/ - -PowAssignExp::PowAssignExp(Loc loc, Expression *e1, Expression *e2) - : BinAssignExp(loc, TOKpowass, sizeof(PowAssignExp), e1, e2) -{ -} - -Expression *PowAssignExp::semantic(Scope *sc) -{ - Expression *e; - - if (type) - return this; - - e = op_overload(sc); - if (e) - return e; - - assert(e1->type && e2->type); - if (e1->op == TOKslice) - { // T[] ^^= ... - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - - // Check element types are arithmetic - Type *tb1 = e1->type->nextOf()->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - if (tb2->ty == Tarray || tb2->ty == Tsarray) - tb2 = tb2->nextOf()->toBasetype(); - - if ( (tb1->isintegral() || tb1->isfloating()) && - (tb2->isintegral() || tb2->isfloating())) - { - type = e1->type; - return arrayOp(sc); - } - } - else - { - e1 = e1->modifiableLvalue(sc, e1); - } - - if ( (e1->type->isintegral() || e1->type->isfloating()) && - (e2->type->isintegral() || e2->type->isfloating())) - { - if (e1->op == TOKvar) - { // Rewrite: e1 = e1 ^^ e2 - e = new PowExp(loc, e1->syntaxCopy(), e2); - e = new AssignExp(loc, e1, e); - } - else - { // Rewrite: ref tmp = e1; tmp = tmp ^^ e2 - Identifier *id = Lexer::uniqueId("__powtmp"); - VarDeclaration *v = new VarDeclaration(e1->loc, e1->type, id, new ExpInitializer(loc, e1)); - v->storage_class |= STCref | STCforeach; - Expression *de = new DeclarationExp(e1->loc, v); - VarExp *ve = new VarExp(e1->loc, v); - e = new PowExp(loc, ve, e2); - e = new AssignExp(loc, new VarExp(e1->loc, v), e); - e = new CommaExp(loc, de, e); - } - e = e->semantic(sc); - if (e->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - return e; - } - return incompatibleTypes(); -} - - -/************************* AddExp *****************************/ - -AddExp::AddExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKadd, sizeof(AddExp), e1, e2) -{ -} - -Expression *AddExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("AddExp::semantic('%s')\n", toChars()); -#endif - if (!type) - { - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - if ((tb1->ty == Tarray || tb1->ty == Tsarray) && - (tb2->ty == Tarray || tb2->ty == Tsarray) && - tb1->nextOf()->equals(tb2->nextOf()) - ) - { - type = e1->type; - e = this; - } - else if (tb1->ty == Tpointer && e2->type->isintegral() || - tb2->ty == Tpointer && e1->type->isintegral()) - e = scaleFactor(sc); - else if (tb1->ty == Tpointer && tb2->ty == Tpointer) - { - return incompatibleTypes(); - } - else - { - typeCombine(sc); - Type *tb1 = e1->type->toBasetype(); - if (tb1->ty == Tvector && !tb1->isscalar()) - { - return incompatibleTypes(); - } - if ((tb1->isreal() && e2->type->isimaginary()) || - (tb1->isimaginary() && e2->type->isreal())) - { - switch (type->toBasetype()->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - e = this; - } - return e; - } - return this; -} - -/************************************************************/ - -MinExp::MinExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmin, sizeof(MinExp), e1, e2) -{ -} - -Expression *MinExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("MinExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - e = op_overload(sc); - if (e) - return e; - - e = this; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tpointer) - { - if (t2->ty == Tpointer) - { // Need to divide the result by the stride - // Replace (ptr - ptr) with (ptr - ptr) / stride - d_int64 stride; - Expression *e; - - typeCombine(sc); // make sure pointer types are compatible - type = Type::tptrdiff_t; - stride = t2->nextOf()->size(); - if (stride == 0) - { - e = new IntegerExp(loc, 0, Type::tptrdiff_t); - } - else - { - e = new DivExp(loc, this, new IntegerExp(0, stride, Type::tptrdiff_t)); - e->type = Type::tptrdiff_t; - } - return e; - } - else if (t2->isintegral()) - e = scaleFactor(sc); - else - { error("can't subtract %s from pointer", t2->toChars()); - return new ErrorExp(); - } - } - else if (t2->ty == Tpointer) - { - type = e2->type; - error("can't subtract pointer from %s", e1->type->toChars()); - return new ErrorExp(); - } - else - { - typeCombine(sc); - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if (t1->ty == Tvector && !t1->isscalar()) - { - return incompatibleTypes(); - } - if ((t1->isreal() && t2->isimaginary()) || - (t1->isimaginary() && t2->isreal())) - { - switch (type->ty) - { - case Tfloat32: - case Timaginary32: - type = Type::tcomplex32; - break; - - case Tfloat64: - case Timaginary64: - type = Type::tcomplex64; - break; - - case Tfloat80: - case Timaginary80: - type = Type::tcomplex80; - break; - - default: - assert(0); - } - } - } - return e; -} - -/************************* CatExp *****************************/ - -CatExp::CatExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKcat, sizeof(CatExp), e1, e2) -{ -} - -Expression *CatExp::semantic(Scope *sc) -{ Expression *e; - - //printf("CatExp::semantic() %s\n", toChars()); - if (!type) - { - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - Type *tb1 = e1->type->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - - - /* BUG: Should handle things like: - * char c; - * c ~ ' ' - * ' ' ~ c; - */ - -#if 0 - e1->type->print(); - e2->type->print(); -#endif - Type *tb1next = tb1->nextOf(); - Type *tb2next = tb2->nextOf(); - - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - e2->implicitConvTo(tb1next) >= MATCHconvert) - { - e2 = e2->implicitCastTo(sc, tb1next); - type = tb1next->arrayOf(); - if (tb2->ty == Tarray) - { // Make e2 into [e2] - e2 = new ArrayLiteralExp(e2->loc, e2); - e2->type = type; - } - return this; - } - else if ((tb2->ty == Tsarray || tb2->ty == Tarray) && - e1->implicitConvTo(tb2next) >= MATCHconvert) - { - e1 = e1->implicitCastTo(sc, tb2next); - type = tb2next->arrayOf(); - if (tb1->ty == Tarray) - { // Make e1 into [e1] - e1 = new ArrayLiteralExp(e1->loc, e1); - e1->type = type; - } - return this; - } - - if ((tb1->ty == Tsarray || tb1->ty == Tarray) && - (tb2->ty == Tsarray || tb2->ty == Tarray) && - (tb1next->mod || tb2next->mod) && - (tb1next->mod != tb2next->mod) - ) - { - Type *t1 = tb1next->mutableOf()->constOf()->arrayOf(); - Type *t2 = tb2next->mutableOf()->constOf()->arrayOf(); - if (e1->op == TOKstring && !((StringExp *)e1)->committed) - e1->type = t1; - else - e1 = e1->castTo(sc, t1); - if (e2->op == TOKstring && !((StringExp *)e2)->committed) - e2->type = t2; - else - e2 = e2->castTo(sc, t2); - } - - typeCombine(sc); - type = type->toHeadMutable(); - - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray) - type = tb->nextOf()->arrayOf(); - if (type->ty == Tarray && tb1next && tb2next && - tb1next->mod != tb2next->mod) - { - type = type->nextOf()->toHeadMutable()->arrayOf(); - } -#if 0 - e1->type->print(); - e2->type->print(); - type->print(); - print(); -#endif - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (e1->op == TOKstring && e2->op == TOKstring) - e = optimize(WANTvalue); - else if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - e = this; - } - else - { - //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); - incompatibleTypes(); - return new ErrorExp(); - } - e->type = e->type->semantic(loc, sc); - return e; - } - return this; -} - -/************************************************************/ - -MulExp::MulExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmul, sizeof(MulExp), e1, e2) -{ -} - -Expression *MulExp::semantic(Scope *sc) -{ Expression *e; - -#if 0 - printf("MulExp::semantic() %s\n", toChars()); -#endif - if (type) - { - return this; - } - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { Expression *e; - - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - - // iy * iv = -yv - e1->type = type; - e2->type = type; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - else if (type->toBasetype()->ty == Tvector && - ((TypeVector *)type->toBasetype())->elementType()->size(loc) != 2) - { // Only short[8] and ushort[8] work with multiply - return incompatibleTypes(); - } - return this; -} - -/************************************************************/ - -DivExp::DivExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKdiv, sizeof(DivExp), e1, e2) -{ -} - -Expression *DivExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->isfloating()) - { Type *t1 = e1->type; - Type *t2 = e2->type; - - if (t1->isreal()) - { - type = t2; - if (t2->isimaginary()) - { Expression *e; - - // x/iv = i(-x/v) - e2->type = t1; - e = new NegExp(loc, this); - e = e->semantic(sc); - return e; - } - } - else if (t2->isreal()) - { - type = t1; - } - else if (t1->isimaginary()) - { - if (t2->isimaginary()) - { - switch (t1->toBasetype()->ty) - { - case Timaginary32: type = Type::tfloat32; break; - case Timaginary64: type = Type::tfloat64; break; - case Timaginary80: type = Type::tfloat80; break; - default: assert(0); - } - } - else - type = t2; // t2 is complex - } - else if (t2->isimaginary()) - { - type = t1; // t1 is complex - } - } - else if (type->toBasetype()->ty == Tvector) - { incompatibleTypes(); - return new ErrorExp(); - } - return this; -} - -/************************************************************/ - -ModExp::ModExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKmod, sizeof(ModExp), e1, e2) -{ -} - -Expression *ModExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkArithmetic(); - if (!e2->isArrayOperand()) - e2->checkArithmetic(); - if (type->toBasetype()->ty == Tvector) - { incompatibleTypes(); - return new ErrorExp(); - } - if (type->isfloating()) - { type = e1->type; - if (e2->type->iscomplex()) - { error("cannot perform modulo complex arithmetic"); - return new ErrorExp(); - } - } - return this; -} - -/************************************************************/ - -PowExp::PowExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKpow, sizeof(PowExp), e1, e2) -{ -} - -Expression *PowExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - //printf("PowExp::semantic() %s\n", toChars()); - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - assert(e1->type && e2->type); - typeCombine(sc); - - if (e1->op == TOKslice) - { - // Check element types are arithmetic - Type *tb1 = e1->type->nextOf()->toBasetype(); - Type *tb2 = e2->type->toBasetype(); - if (tb2->ty == Tarray || tb2->ty == Tsarray) - tb2 = tb2->nextOf()->toBasetype(); - - if ( (tb1->isintegral() || tb1->isfloating()) && - (tb2->isintegral() || tb2->isfloating())) - { - type = e1->type; - return this; - } - } - - if ( (e1->type->isintegral() || e1->type->isfloating()) && - (e2->type->isintegral() || e2->type->isfloating())) - { - // For built-in numeric types, there are several cases. - // TODO: backend support, especially for e1 ^^ 2. - - bool wantSqrt = false; - - // First, attempt to fold the expression. - e = optimize(WANTvalue); - if (e->op != TOKpow) - { - e = e->semantic(sc); - return e; - } - - // Determine if we're raising to an integer power. - sinteger_t intpow = 0; - if (e2->op == TOKint64 && ((sinteger_t)e2->toInteger() == 2 || (sinteger_t)e2->toInteger() == 3)) - intpow = e2->toInteger(); - else if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal()))) - intpow = (sinteger_t)(e2->toReal()); - - // Deal with x^^2, x^^3 immediately, since they are of practical importance. - if (intpow == 2 || intpow == 3) - { - // Replace x^^2 with (tmp = x, tmp*tmp) - // Replace x^^3 with (tmp = x, tmp*tmp*tmp) - Identifier *idtmp = Lexer::uniqueId("__powtmp"); - VarDeclaration *tmp = new VarDeclaration(loc, e1->type->toBasetype(), idtmp, new ExpInitializer(0, e1)); - tmp->storage_class = STCctfe; - Expression *ve = new VarExp(loc, tmp); - Expression *ae = new DeclarationExp(loc, tmp); - /* Note that we're reusing ve. This should be ok. - */ - Expression *me = new MulExp(loc, ve, ve); - if (intpow == 3) - me = new MulExp(loc, me, ve); - e = new CommaExp(loc, ae, me); - e = e->semantic(sc); - return e; - } - - static int importMathChecked = 0; - if (!importMathChecked) - { - importMathChecked = 1; - for (size_t i = 0; i < Module::amodules.dim; i++) - { Module *mi = Module::amodules.tdata()[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - if (mi->ident == Id::math && - mi->parent->ident == Id::std && - !mi->parent->parent) - goto L1; - } - error("must import std.math to use ^^ operator"); - return new ErrorExp(); - - L1: ; - } - - e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::std); - e = new DotIdExp(loc, e, Id::math); - if (e2->op == TOKfloat64 && e2->toReal() == 0.5) - { // Replace e1 ^^ 0.5 with .std.math.sqrt(x) - e = new CallExp(loc, new DotIdExp(loc, e, Id::_sqrt), e1); - } - else - { - // Replace e1 ^^ e2 with .std.math.pow(e1, e2) - e = new CallExp(loc, new DotIdExp(loc, e, Id::_pow), e1, e2); - } - e = e->semantic(sc); - return e; - } - return incompatibleTypes(); -} - -/************************************************************/ - -ShlExp::ShlExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshl, sizeof(ShlExp), e1, e2) -{ -} - -Expression *ShlExp::semantic(Scope *sc) -{ Expression *e; - - //printf("ShlExp::semantic(), type = %p\n", type); - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - if (e1->type->toBasetype()->ty == Tvector || - e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -ShrExp::ShrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKshr, sizeof(ShrExp), e1, e2) -{ -} - -Expression *ShrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - if (e1->type->toBasetype()->ty == Tvector || - e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -UshrExp::UshrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKushr, sizeof(UshrExp), e1, e2) -{ -} - -Expression *UshrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - e1 = e1->checkIntegral(); - e2 = e2->checkIntegral(); - if (e1->type->toBasetype()->ty == Tvector || - e2->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - e1 = e1->integralPromotions(sc); - //e2 = e2->castTo(sc, Type::tshiftcnt); - e2 = e2->castTo(sc, e1->type); // LDC - type = e1->type; - } - return this; -} - -/************************************************************/ - -AndExp::AndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKand, sizeof(AndExp), e1, e2) -{ -} - -Expression *AndExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -OrExp::OrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKor, sizeof(OrExp), e1, e2) -{ -} - -Expression *OrExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - -/************************************************************/ - -XorExp::XorExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKxor, sizeof(XorExp), e1, e2) -{ -} - -Expression *XorExp::semantic(Scope *sc) -{ Expression *e; - - if (!type) - { BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - if (e1->type->toBasetype()->ty == Tbool && - e2->type->toBasetype()->ty == Tbool) - { - type = e1->type; - e = this; - } - else - { - typeCombine(sc); - if (!e1->isArrayOperand()) - e1->checkIntegral(); - if (!e2->isArrayOperand()) - e2->checkIntegral(); - } - } - return this; -} - - -/************************************************************/ - -OrOrExp::OrOrExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKoror, sizeof(OrOrExp), e1, e2) -{ -} - -Expression *OrOrExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for AndAnd - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(sc); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(TRUE)) - { - return new IntegerExp(loc, 1, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - if (e2->type->ty == Tvoid) - type = Type::tvoid; - else - { - e2 = e2->checkToBoolean(sc); - type = Type::tboolean; - } - if (e2->op == TOKtype || e2->op == TOKimport) - { error("%s is not an expression", e2->toChars()); - return new ErrorExp(); - } - if (e1->op == TOKerror) - return e1; - if (e2->op == TOKerror) - return e2; - return this; -} - -Expression *OrOrExp::checkToBoolean(Scope *sc) -{ - e2 = e2->checkToBoolean(sc); - return this; -} - -int OrOrExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -AndAndExp::AndAndExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKandand, sizeof(AndAndExp), e1, e2) -{ -} - -Expression *AndAndExp::semantic(Scope *sc) -{ - unsigned cs1; - - // same as for OrOr - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - e1 = e1->checkToPointer(); - e1 = e1->checkToBoolean(sc); - cs1 = sc->callSuper; - - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate e2 if we don't have to. - */ - e1 = e1->optimize(WANTflags); - if (e1->isBool(FALSE)) - { - return new IntegerExp(loc, 0, Type::tboolean); - } - } - - e2 = e2->semantic(sc); - sc->mergeCallSuper(loc, cs1); - e2 = resolveProperties(sc, e2); - e2 = e2->checkToPointer(); - - if (e2->type->ty == Tvoid) - type = Type::tvoid; - else - { - e2 = e2->checkToBoolean(sc); - type = Type::tboolean; - } - if (e2->op == TOKtype || e2->op == TOKimport) - { error("%s is not an expression", e2->toChars()); - return new ErrorExp(); - } - if (e1->op == TOKerror) - return e1; - if (e2->op == TOKerror) - return e2; - return this; -} - -Expression *AndAndExp::checkToBoolean(Scope *sc) -{ - e2 = e2->checkToBoolean(sc); - return this; -} - -int AndAndExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -InExp::InExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKin, sizeof(InExp), e1, e2) -{ -} - -Expression *InExp::semantic(Scope *sc) -{ Expression *e; - - if (type) - return this; - - BinExp::semanticp(sc); - e = op_overload(sc); - if (e) - return e; - - //type = Type::tboolean; - Type *t2b = e2->type->toBasetype(); - switch (t2b->ty) - { - case Taarray: - { - TypeAArray *ta = (TypeAArray *)t2b; - -#if DMDV2 - // Special handling for array keys - if (!arrayTypeCompatible(e1->loc, e1->type, ta->index)) -#endif - { - // Convert key to type of key - e1 = e1->implicitCastTo(sc, ta->index); - } - - // Return type is pointer to value - type = ta->nextOf()->pointerTo(); - break; - } - - default: - error("rvalue of in expression must be an associative array, not %s", e2->type->toChars()); - case Terror: - return new ErrorExp(); - } - return this; -} - -int InExp::isBit() -{ - return FALSE; -} - - -/************************************************************/ - -/* This deletes the key e1 from the associative array e2 - */ - -RemoveExp::RemoveExp(Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, TOKremove, sizeof(RemoveExp), e1, e2) -{ - type = Type::tboolean; -} - -void RemoveExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writestring(".remove("); - expToCBuffer(buf, hgs, e2, PREC_assign); - buf->writestring(")"); -} - -/************************************************************/ - -CmpExp::CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(CmpExp), e1, e2) -{ -} - -Expression *CmpExp::semantic(Scope *sc) -{ Expression *e; - -#if LOGSEMANTIC - printf("CmpExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - BinExp::semanticp(sc); - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && e2->op == TOKnull || - t2->ty == Tclass && e1->op == TOKnull) - { - error("do not use null when comparing class types"); - return new ErrorExp(); - } - - e = op_overload(sc); - if (e) - { - if (!e->type->isscalar() && e->type->equals(e1->type)) - { - error("recursive opCmp expansion"); - e = new ErrorExp(); - } - else if (e->op == TOKcall) - { e = new CmpExp(op, loc, e, new IntegerExp(loc, 0, Type::tint32)); - e = e->semantic(sc); - } - return e; - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - Expression *eb1 = e1; - Expression *eb2 = e2; - - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - -#if 0 - // For integer comparisons, ensure the combined type can hold both arguments. - if (type && type->isintegral() && (op == TOKlt || op == TOKle || - op == TOKgt || op == TOKge)) - { - IntRange trange = IntRange::fromType(type); - - Expression *errorexp = 0; - if (!trange.contains(eb1->getIntRange())) - errorexp = eb1; - if (!trange.contains(eb2->getIntRange())) - errorexp = eb2; - - if (errorexp) - { - error("implicit conversion of '%s' to '%s' is unsafe in '(%s) %s (%s)'", - errorexp->toChars(), type->toChars(), eb1->toChars(), Token::toChars(op), eb2->toChars()); - return new ErrorExp(); - } - } -#endif - - type = Type::tboolean; - - // Special handling for array comparisons - t1 = e1->type->toBasetype(); - t2 = e2->type->toBasetype(); - if ((t1->ty == Tarray || t1->ty == Tsarray || t1->ty == Tpointer) && - (t2->ty == Tarray || t2->ty == Tsarray || t2->ty == Tpointer)) - { - if (t1->nextOf()->implicitConvTo(t2->nextOf()) < MATCHconst && - t2->nextOf()->implicitConvTo(t1->nextOf()) < MATCHconst && - (t1->nextOf()->ty != Tvoid && t2->nextOf()->ty != Tvoid)) - error("array comparison type mismatch, %s vs %s", t1->nextOf()->toChars(), t2->nextOf()->toChars()); - e = this; - } - else if (t1->ty == Tstruct || t2->ty == Tstruct || - (t1->ty == Tclass && t2->ty == Tclass)) - { - if (t2->ty == Tstruct) - error("need member function opCmp() for %s %s to compare", t2->toDsymbol(sc)->kind(), t2->toChars()); - else - error("need member function opCmp() for %s %s to compare", t1->toDsymbol(sc)->kind(), t1->toChars()); - e = new ErrorExp(); - } -#if 1 - else if (t1->iscomplex() || t2->iscomplex()) - { - error("compare not defined for complex operands"); - e = new ErrorExp(); - } -#endif - else if (t1->ty == Tvector) - return incompatibleTypes(); - else - { if (!e1->rvalue() || !e2->rvalue()) - return new ErrorExp(); - e = this; - } - //printf("CmpExp: %s, type = %s\n", e->toChars(), e->type->toChars()); - return e; -} - -int CmpExp::isBit() -{ - return TRUE; -} - - -/************************************************************/ - -EqualExp::EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(EqualExp), e1, e2) -{ - assert(op == TOKequal || op == TOKnotequal); -} - -int needDirectEq(Type *t1, Type *t2) -{ - assert(t1->ty == Tarray || t1->ty == Tsarray); - assert(t2->ty == Tarray || t2->ty == Tsarray); - - Type *t1n = t1->nextOf()->toBasetype(); - Type *t2n = t2->nextOf()->toBasetype(); - - if (((t1n->ty == Tchar || t1n->ty == Twchar || t1n->ty == Tdchar) && - (t2n->ty == Tchar || t2n->ty == Twchar || t2n->ty == Tdchar)) || - (t1n->ty == Tvoid || t2n->ty == Tvoid)) - { - return FALSE; - } - - if (t1n->constOf() != t2n->constOf()) - return TRUE; - - Type *t = t1n; - while (t->toBasetype()->nextOf()) - t = t->nextOf()->toBasetype(); - if (t->ty != Tstruct) - return FALSE; - - return ((TypeStruct *)t)->sym->xeq == StructDeclaration::xerreq; -} - -Expression *EqualExp::semantic(Scope *sc) -{ Expression *e; - - //printf("EqualExp::semantic('%s')\n", toChars()); - if (type) - return this; - - BinExp::semanticp(sc); - - /* Before checking for operator overloading, check to see if we're - * comparing the addresses of two statics. If so, we can just see - * if they are the same symbol. - */ - if (e1->op == TOKaddress && e2->op == TOKaddress) - { AddrExp *ae1 = (AddrExp *)e1; - AddrExp *ae2 = (AddrExp *)e2; - - if (ae1->e1->op == TOKvar && ae2->e1->op == TOKvar) - { VarExp *ve1 = (VarExp *)ae1->e1; - VarExp *ve2 = (VarExp *)ae2->e1; - - if (ve1->var == ve2->var /*|| ve1->var->toSymbol() == ve2->var->toSymbol()*/) - { - // They are the same, result is 'true' for ==, 'false' for != - e = new IntegerExp(loc, (op == TOKequal), Type::tboolean); - return e; - } - } - } - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && e2->op == TOKnull || - t2->ty == Tclass && e1->op == TOKnull) - { - error("use '%s' instead of '%s' when comparing with null", - Token::toChars(op == TOKequal ? TOKidentity : TOKnotidentity), - Token::toChars(op)); - return new ErrorExp(); - } - - if ((t1->ty == Tarray || t1->ty == Tsarray) && - (t2->ty == Tarray || t2->ty == Tsarray)) - { - if (needDirectEq(t1, t2)) - { /* Rewrite as: - * _ArrayEq(e1, e2) - */ - Expression *eq = new IdentifierExp(loc, Id::_ArrayEq); - Expressions *args = new Expressions(); - args->push(e1); - args->push(e2); - e = new CallExp(loc, eq, args); - if (op == TOKnotequal) - e = new NotExp(loc, e); - e = e->trySemantic(sc); // for better error message - if (!e) - { error("cannot compare %s and %s", t1->toChars(), t2->toChars()); - return new ErrorExp(); - } - return e; - } - } - - //if (e2->op != TOKnull) - { - e = op_overload(sc); - if (e) - { - if (e->op == TOKcall && op == TOKnotequal) - { - e = new NotExp(e->loc, e); - e = e->semantic(sc); - } - return e; - } - } - - /* Disallow comparing T[]==T and T==T[] - */ - if (e1->op == TOKslice && t1->ty == Tarray && e2->implicitConvTo(t1->nextOf()) || - e2->op == TOKslice && t2->ty == Tarray && e1->implicitConvTo(t2->nextOf())) - { - incompatibleTypes(); - return new ErrorExp(); - } - - e = typeCombine(sc); - if (e->op == TOKerror) - return e; - - type = Type::tboolean; - - // Special handling for array comparisons - if (!arrayTypeCompatible(loc, e1->type, e2->type)) - { - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - } - - if (e1->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - - return e; -} - -int EqualExp::isBit() -{ - return TRUE; -} - - - -/************************************************************/ - -IdentityExp::IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2) - : BinExp(loc, op, sizeof(IdentityExp), e1, e2) -{ -} - -Expression *IdentityExp::semantic(Scope *sc) -{ - if (type) - return this; - - BinExp::semanticp(sc); - type = Type::tboolean; - - Expression *e = typeCombine(sc); - if (e->op == TOKerror) - return e; - - if (e1->type != e2->type && e1->type->isfloating() && e2->type->isfloating()) - { - // Cast both to complex - e1 = e1->castTo(sc, Type::tcomplex80); - e2 = e2->castTo(sc, Type::tcomplex80); - } - - if (e1->type->toBasetype()->ty == Tvector) - return incompatibleTypes(); - - return this; -} - -int IdentityExp::isBit() -{ - return TRUE; -} - - -/****************************************************************/ - -CondExp::CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2) - : BinExp(loc, TOKquestion, sizeof(CondExp), e1, e2) -{ - this->econd = econd; -} - -Expression *CondExp::syntaxCopy() -{ - return new CondExp(loc, econd->syntaxCopy(), e1->syntaxCopy(), e2->syntaxCopy()); -} - - -Expression *CondExp::semantic(Scope *sc) -{ Type *t1; - Type *t2; - unsigned cs0; - unsigned cs1; - -#if LOGSEMANTIC - printf("CondExp::semantic('%s')\n", toChars()); -#endif - if (type) - return this; - - econd = econd->semantic(sc); - econd = resolveProperties(sc, econd); - econd = econd->checkToPointer(); - econd = econd->checkToBoolean(sc); - -#if 0 /* this cannot work right because the types of e1 and e2 - * both contribute to the type of the result. - */ - if (sc->flags & SCOPEstaticif) - { - /* If in static if, don't evaluate what we don't have to. - */ - econd = econd->optimize(WANTflags); - if (econd->isBool(TRUE)) - { - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - return e1; - } - else if (econd->isBool(FALSE)) - { - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - return e2; - } - } -#endif - - - cs0 = sc->callSuper; - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - cs1 = sc->callSuper; - sc->callSuper = cs0; - e2 = e2->semantic(sc); - e2 = resolveProperties(sc, e2); - sc->mergeCallSuper(loc, cs1); - - - // If either operand is void, the result is void - t1 = e1->type; - t2 = e2->type; - if (t1->ty == Tvoid || t2->ty == Tvoid) - type = Type::tvoid; - else if (t1 == t2) - type = t1; - else - { - typeCombine(sc); - switch (e1->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e2 = e2->castTo(sc, e1->type); - break; - } - switch (e2->type->toBasetype()->ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - e1 = e1->castTo(sc, e2->type); - break; - } - if (type->toBasetype()->ty == Tarray) - { - e1 = e1->castTo(sc, type); - e2 = e2->castTo(sc, type); - } - } -#if 0 - printf("res: %s\n", type->toChars()); - printf("e1 : %s\n", e1->type->toChars()); - printf("e2 : %s\n", e2->type->toChars()); -#endif - return this; -} - -#if DMDV2 -int CondExp::isLvalue() -{ - return e1->isLvalue() && e2->isLvalue(); -} -#endif - -Expression *CondExp::toLvalue(Scope *sc, Expression *ex) -{ - PtrExp *e; - - // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) - e = new PtrExp(loc, this, type); - - e1 = e1->addressOf(sc); - e2 = e2->addressOf(sc); - - typeCombine(sc); - - type = e2->type; - return e; -} - -Expression *CondExp::modifiableLvalue(Scope *sc, Expression *e) -{ - //error("conditional expression %s is not a modifiable lvalue", toChars()); - e1 = e1->modifiableLvalue(sc, e1); - e2 = e2->modifiableLvalue(sc, e1); - return toLvalue(sc, this); -} - -void CondExp::checkEscape() -{ - e1->checkEscape(); - e2->checkEscape(); -} - -void CondExp::checkEscapeRef() -{ - e1->checkEscapeRef(); - e2->checkEscapeRef(); -} - - -Expression *CondExp::checkToBoolean(Scope *sc) -{ - e1 = e1->checkToBoolean(sc); - e2 = e2->checkToBoolean(sc); - return this; -} - - -void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, econd, PREC_oror); - buf->writestring(" ? "); - expToCBuffer(buf, hgs, e1, PREC_expr); - buf->writestring(" : "); - expToCBuffer(buf, hgs, e2, PREC_cond); -} - -/************************************************************/ - -#if IN_LLVM - -// Strictly LDC specific stuff - -GEPExp::GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx) - : UnaExp(loc, TOKgep, sizeof(GEPExp), e) -{ - index = idx; - ident = id; -} - -void GEPExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - expToCBuffer(buf, hgs, e1, PREC_primary); - buf->writeByte('.'); - buf->writestring(ident->toChars()); -} - -Expression* GEPExp::toLvalue(Scope* sc, Expression* e) -{ - // GEP's are always lvalues, at least in the "LLVM sense" ... - return this; -} - -#endif - -/****************************************************************/ - -DefaultInitExp::DefaultInitExp(Loc loc, enum TOK subop, int size) - : Expression(loc, TOKdefault, size) -{ - this->subop = subop; -} - -void DefaultInitExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(subop)); -} - -/****************************************************************/ - -FileInitExp::FileInitExp(Loc loc) - : DefaultInitExp(loc, TOKfile, sizeof(FileInitExp)) -{ -} - -Expression *FileInitExp::semantic(Scope *sc) -{ - //printf("FileInitExp::semantic()\n"); - type = Type::tchar->invariantOf()->arrayOf(); - return this; -} - -Expression *FileInitExp::resolveLoc(Loc loc, Scope *sc) -{ - //printf("FileInitExp::resolve() %s\n", toChars()); - const char *s = loc.filename ? loc.filename : sc->module->ident->toChars(); - Expression *e = new StringExp(loc, (char *)s); - e = e->semantic(sc); - e = e->castTo(sc, type); - return e; -} - -/****************************************************************/ - -LineInitExp::LineInitExp(Loc loc) - : DefaultInitExp(loc, TOKline, sizeof(LineInitExp)) -{ -} - -Expression *LineInitExp::semantic(Scope *sc) -{ - type = Type::tint32; - return this; -} - -Expression *LineInitExp::resolveLoc(Loc loc, Scope *sc) -{ - Expression *e = new IntegerExp(loc, loc.linnum, Type::tint32); - e = e->castTo(sc, type); - return e; -} - - diff --git a/dmd2/expression.h b/dmd2/expression.h deleted file mode 100644 index b2fbb4a6..00000000 --- a/dmd2/expression.h +++ /dev/null @@ -1,2141 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_EXPRESSION_H -#define DMD_EXPRESSION_H - -#include "mars.h" -#include "identifier.h" -#include "lexer.h" -#include "arraytypes.h" -#include "intrange.h" - -struct Type; -struct Scope; -struct TupleDeclaration; -struct VarDeclaration; -struct FuncDeclaration; -struct FuncLiteralDeclaration; -struct Declaration; -struct CtorDeclaration; -struct NewDeclaration; -struct Dsymbol; -struct Import; -struct Module; -struct ScopeDsymbol; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct Expression; -struct Declaration; -struct AggregateDeclaration; -struct StructDeclaration; -struct TemplateInstance; -struct TemplateDeclaration; -struct ClassDeclaration; -struct HdrGenState; -struct BinExp; -struct InterState; -#if IN_DMD -struct Symbol; // back end symbol -#endif -struct OverloadSet; -struct Initializer; -struct StringExp; -#if IN_LLVM -struct AssignExp; -#endif - -enum TOK; - -#if IN_DMD -// Back end -struct IRState; -struct dt_t; -#endif - -#ifdef IN_GCC -union tree_node; typedef union tree_node elem; -#endif -#if IN_DMD -struct elem; -#endif - -#if IN_LLVM -struct IRState; -struct DValue; -namespace llvm { - class Constant; - class ConstantInt; - class StructType; -} -#endif - -void initPrecedence(); - -typedef int (*apply_fp_t)(Expression *, void *); - -Expression *resolveProperties(Scope *sc, Expression *e); -void accessCheck(Loc loc, Scope *sc, Expression *e, Declaration *d); -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, Dsymbol *d); -Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid); -void argExpTypesToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); -void expandTuples(Expressions *exps); -TupleDeclaration *isAliasThisTuple(Expression *e); -int expandAliasThisTuples(Expressions *exps, int starti = 0); -FuncDeclaration *hasThis(Scope *sc); -Expression *fromConstInitializer(int result, Expression *e); -int arrayExpressionCanThrow(Expressions *exps, bool mustNotThrow); -TemplateDeclaration *getFuncTemplateDecl(Dsymbol *s); -void valueNoDtor(Expression *e); -void modifyFieldVar(Loc loc, Scope *sc, VarDeclaration *var, Expression *e1); - - -/* Interpreter: what form of return value expression is required? - */ -enum CtfeGoal -{ ctfeNeedRvalue, // Must return an Rvalue - ctfeNeedLvalue, // Must return an Lvalue - ctfeNeedAnyValue, // Can return either an Rvalue or an Lvalue - ctfeNeedLvalueRef,// Must return a reference to an Lvalue (for ref types) - ctfeNeedNothing // The return value is not required -}; - -struct Expression : Object -{ - Loc loc; // file location - enum TOK op; // handy to minimize use of dynamic_cast - Type *type; // !=NULL means that semantic() has been run - unsigned char size; // # of bytes in Expression so we can copy() it - unsigned char parens; // if this is a parenthesized expression - - Expression(Loc loc, enum TOK op, int size); - Expression *copy(); - virtual Expression *syntaxCopy(); - virtual int apply(apply_fp_t fp, void *param); - virtual Expression *semantic(Scope *sc); - Expression *trySemantic(Scope *sc); - - int dyncast() { return DYNCAST_EXPRESSION; } // kludge for template.isExpression() - - void print(); - char *toChars(); - virtual void dump(int indent); - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual int rvalue(); - - static Expression *combine(Expression *e1, Expression *e2); - static Expressions *arraySyntaxCopy(Expressions *exps); - - virtual dinteger_t toInteger(); - virtual uinteger_t toUInteger(); - virtual real_t toReal(); - virtual real_t toImaginary(); - virtual complex_t toComplex(); - virtual StringExp *toString(); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual void toMangleBuffer(OutBuffer *buf); - virtual int isLvalue(); - virtual Expression *toLvalue(Scope *sc, Expression *e); - virtual Expression *modifiableLvalue(Scope *sc, Expression *e); - virtual Expression *implicitCastTo(Scope *sc, Type *t); - virtual MATCH implicitConvTo(Type *t); - virtual IntRange getIntRange(); - virtual Expression *castTo(Scope *sc, Type *t); - virtual void checkEscape(); - virtual void checkEscapeRef(); - virtual Expression *resolveLoc(Loc loc, Scope *sc); - void checkScalar(); - void checkNoBool(); - Expression *checkIntegral(); - Expression *checkArithmetic(); - void checkDeprecated(Scope *sc, Dsymbol *s); - void checkPurity(Scope *sc, FuncDeclaration *f); - void checkPurity(Scope *sc, VarDeclaration *v, Expression *e1); - void checkSafety(Scope *sc, FuncDeclaration *f); - virtual Expression *checkToBoolean(Scope *sc); - virtual Expression *addDtorHook(Scope *sc); - Expression *checkToPointer(); - Expression *addressOf(Scope *sc); - Expression *deref(); - Expression *integralPromotions(Scope *sc); - Expression *isTemp(); - - Expression *toDelegate(Scope *sc, Type *t); - - virtual Expression *optimize(int result); - #define WANTflags 1 - #define WANTvalue 2 - // A compile-time result is required. Give an error if not possible - #define WANTinterpret 4 - // Same as WANTvalue, but also expand variables as far as possible - #define WANTexpand 8 - - virtual Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - virtual int isConst(); - virtual int isBool(int result); - virtual int isBit(); - bool hasSideEffect(); - void discardValue(); - void useValue(); - int canThrow(bool mustNotThrow); - - virtual int inlineCost3(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Expression *inlineScan(InlineScanState *iss); - Expression *inlineCopy(Scope *sc); - - // For operator overloading - virtual int isCommutative(); - virtual Identifier *opId(); - virtual Identifier *opId_r(); - - // For array ops - virtual void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - virtual Expression *buildArrayLoop(Parameters *fparams); - int isArrayOperand(); - -#if IN_DMD - // Back end - virtual elem *toElem(IRState *irs); - elem *toElemDtor(IRState *irs); - virtual dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - virtual DValue* toElem(IRState* irs); - DValue *toElemDtor(IRState *irs); - virtual llvm::Constant *toConstElem(IRState *irs); - virtual void cacheLvalue(IRState* irs); - - llvm::Value* cachedLvalue; - - virtual AssignExp* isAssignExp() { return NULL; } -#endif -}; - -struct IntegerExp : Expression -{ - dinteger_t value; - - IntegerExp(Loc loc, dinteger_t value, Type *type); - IntegerExp(dinteger_t value); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - void dump(int indent); - IntRange getIntRange(); - dinteger_t toInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - int isConst(); - int isBool(int result); - MATCH implicitConvTo(Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *toLvalue(Scope *sc, Expression *e); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ErrorExp : IntegerExp -{ - ErrorExp(); - - Expression *implicitCastTo(Scope *sc, Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct RealExp : Expression -{ - real_t value; - - RealExp(Loc loc, real_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ComplexExp : Expression -{ - complex_t value; - - ComplexExp(Loc loc, complex_t value, Type *type); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - char *toChars(); - dinteger_t toInteger(); - uinteger_t toUInteger(); - real_t toReal(); - real_t toImaginary(); - complex_t toComplex(); - Expression *castTo(Scope *sc, Type *t); - int isConst(); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - OutBuffer hexp; -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct IdentifierExp : Expression -{ - Identifier *ident; - Declaration *var; - - IdentifierExp(Loc loc, Identifier *ident); - IdentifierExp(Loc loc, Declaration *var); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct DollarExp : IdentifierExp -{ - DollarExp(Loc loc); -}; - -struct DsymbolExp : Expression -{ - Dsymbol *s; - int hasOverloads; - - DsymbolExp(Loc loc, Dsymbol *s, int hasOverloads = 0); - Expression *semantic(Scope *sc); - char *toChars(); - void dump(int indent); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; - -struct ThisExp : Expression -{ - Declaration *var; - - ThisExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct SuperExp : ThisExp -{ - SuperExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); -}; - -struct NullExp : Expression -{ - unsigned char committed; // !=0 if type is committed - - NullExp(Loc loc, Type *t = NULL); - int equals(Object *o); - Expression *semantic(Scope *sc); - int isBool(int result); - int isConst(); - StringExp *toString(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StringExp : Expression -{ - void *string; // char, wchar, or dchar data - size_t len; // number of chars, wchars, or dchars - unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - unsigned char postfix; // 'c', 'w', 'd' - bool ownedByCtfe; // true = created in CTFE - - StringExp(Loc loc, char *s); - StringExp(Loc loc, void *s, size_t len); - StringExp(Loc loc, void *s, size_t len, unsigned char postfix); - //Expression *syntaxCopy(); - int equals(Object *o); - char *toChars(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - size_t length(); - StringExp *toString(); - StringExp *toUTF8(Scope *sc); - Expression *implicitCastTo(Scope *sc, Type *t); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - int compare(Object *obj); - int isBool(int result); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - unsigned charAt(size_t i); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Tuple - -struct TupleExp : Expression -{ - Expressions *exps; - - TupleExp(Loc loc, Expressions *exps); - TupleExp(Loc loc, TupleDeclaration *tup); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - int equals(Object *o); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *castTo(Scope *sc, Type *t); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ArrayLiteralExp : Expression -{ - Expressions *elements; - bool ownedByCtfe; // true = created in CTFE - - ArrayLiteralExp(Loc loc, Expressions *elements); - ArrayLiteralExp(Loc loc, Expression *e); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isBool(int result); - StringExp *toString(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct AssocArrayLiteralExp : Expression -{ - Expressions *keys; - Expressions *values; - bool ownedByCtfe; // true = created in CTFE - - AssocArrayLiteralExp(Loc loc, Expressions *keys, Expressions *values); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isBool(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct StructLiteralExp : Expression -{ - StructDeclaration *sd; // which aggregate this is for - Expressions *elements; // parallels sd->fields[] with - // NULL entries for fields to skip - Type *stype; // final type of result (can be different from sd's type) - -#if IN_DMD - Symbol *sym; // back end symbol to initialize with literal -#endif - size_t soffset; // offset from start of s - int fillHoles; // fill alignment 'holes' with zero - bool ownedByCtfe; // true = created in CTFE - - StructLiteralExp(Loc loc, StructDeclaration *sd, Expressions *elements, Type *stype = NULL); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *getField(Type *type, unsigned offset); - int getFieldIndex(Type *type, unsigned offset); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toMangleBuffer(OutBuffer *buf); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - MATCH implicitConvTo(Type *t); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - llvm::StructType *constType; -#endif -}; - -Expression *typeDotIdExp(Loc loc, Type *type, Identifier *ident); -#if IN_DMD -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif - -struct TypeExp : Expression -{ - TypeExp(Loc loc, Type *type); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - int rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ScopeExp : Expression -{ - ScopeDsymbol *sds; - - ScopeExp(Loc loc, ScopeDsymbol *sds); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TemplateExp : Expression -{ - TemplateDeclaration *td; - - TemplateExp(Loc loc, TemplateDeclaration *td); - int rvalue(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct NewExp : Expression -{ - /* thisexp.new(newargs) newtype(arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - Type *newtype; - Expressions *arguments; // Array of Expression's - - CtorDeclaration *member; // constructor function - NewDeclaration *allocator; // allocator function - int onstack; // allocate on stack - - NewExp(Loc loc, Expression *thisexp, Expressions *newargs, - Type *newtype, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *optimize(int result); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - //int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NewAnonClassExp : Expression -{ - /* thisexp.new(newargs) class baseclasses { } (arguments) - */ - Expression *thisexp; // if !NULL, 'this' for class being allocated - Expressions *newargs; // Array of Expression's to call new operator - ClassDeclaration *cd; // class being instantiated - Expressions *arguments; // Array of Expression's to call class constructor - - NewAnonClassExp(Loc loc, Expression *thisexp, Expressions *newargs, - ClassDeclaration *cd, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct SymbolExp : Expression -{ - Declaration *var; - int hasOverloads; - - SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; -#endif - -// Offset from symbol - -struct SymOffExp : SymbolExp -{ - unsigned offset; - Module* m; // starting point for overload resolution - - SymOffExp(Loc loc, Declaration *var, unsigned offset, int hasOverloads = 0); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int isConst(); - int isBool(int result); - Expression *doInline(InlineDoState *ids); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// Variable - -struct VarExp : SymbolExp -{ - VarExp(Loc loc, Declaration *var, int hasOverloads = 0); - int equals(Object *o); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void dump(int indent); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -#if DMDV2 -// Overload Set - -struct OverExp : Expression -{ - OverloadSet *vars; - - OverExp(OverloadSet *s); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); -}; -#endif - -// Function/Delegate literal - -struct FuncExp : Expression -{ - FuncLiteralDeclaration *fd; - TemplateDeclaration *td; - enum TOK tok; - Type *tded; - Scope *scope; - - FuncExp(Loc loc, FuncLiteralDeclaration *fd, TemplateDeclaration *td = NULL); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *semantic(Scope *sc, Expressions *arguments); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *inferType(Scope *sc, Type *t); - void setType(Type *t); - char *toChars(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); - dt_t **toDt(dt_t **pdt); -#endif - - int inlineCost3(InlineCostState *ics); - //Expression *doInline(InlineDoState *ids); - //Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -// Declaration of a symbol - -struct DeclarationExp : Expression -{ - Dsymbol *declaration; - - DeclarationExp(Loc loc, Dsymbol *declaration); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct TypeidExp : Expression -{ - Object *obj; - - TypeidExp(Loc loc, Object *obj); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#if DMDV2 -struct TraitsExp : Expression -{ - Identifier *ident; - Objects *args; - - TraitsExp(Loc loc, Identifier *ident, Objects *args); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct HaltExp : Expression -{ - HaltExp(Loc loc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct IsExp : Expression -{ - /* is(targ id tok tspec) - * is(targ id == tok2) - */ - Type *targ; - Identifier *id; // can be NULL - enum TOK tok; // ':' or '==' - Type *tspec; // can be NULL - enum TOK tok2; // 'struct', 'union', 'typedef', etc. - TemplateParameters *parameters; - - IsExp(Loc loc, Type *targ, Identifier *id, enum TOK tok, Type *tspec, - enum TOK tok2, TemplateParameters *parameters); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/****************************************************************/ - -struct UnaExp : Expression -{ - Expression *e1; - - UnaExp(Loc loc, enum TOK op, int size, Expression *e1); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - void dump(int indent); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *)); - Expression *resolveLoc(Loc loc, Scope *sc); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - virtual Expression *op_overload(Scope *sc); -}; - -struct BinExp : Expression -{ - Expression *e1; - Expression *e2; - - BinExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *semanticp(Scope *sc); - void checkComplexMulAssign(); - void checkComplexAddAssign(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *scaleFactor(Scope *sc); - Expression *typeCombine(Scope *sc); - Expression *optimize(int result); - int isunsigned(); - Expression *incompatibleTypes(); - void dump(int indent); - Expression *interpretCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *)); - Expression *interpretCommon2(InterState *istate, CtfeGoal goal, - Expression *(*fp)(TOK, Type *, Expression *, Expression *)); - Expression *interpretAssignCommon(InterState *istate, CtfeGoal goal, - Expression *(*fp)(Type *, Expression *, Expression *), int post = 0); - Expression *arrayOp(Scope *sc); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - - Expression *op_overload(Scope *sc); - Expression *compare_overload(Scope *sc, Identifier *id); - -#if IN_DMD - elem *toElemBin(IRState *irs, int op); -#endif -}; - -struct BinAssignExp : BinExp -{ - BinAssignExp(Loc loc, enum TOK op, int size, Expression *e1, Expression *e2) - : BinExp(loc, op, size, e1, e2) - { - } - - Expression *commonSemanticAssign(Scope *sc); - Expression *commonSemanticAssignIntegral(Scope *sc); - - Expression *op_overload(Scope *sc); - - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *ex); - Expression *modifiableLvalue(Scope *sc, Expression *e); -}; - -/****************************************************************/ - -struct CompileExp : UnaExp -{ - CompileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileExp : UnaExp -{ - FileExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssertExp : UnaExp -{ - Expression *msg; - - AssertExp(Loc loc, Expression *e, Expression *msg = NULL); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotIdExp : UnaExp -{ - Identifier *ident; - - DotIdExp(Loc loc, Expression *e, Identifier *ident); - Expression *semantic(Scope *sc); - Expression *semantic(Scope *sc, int flag); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int i); -}; - -struct DotTemplateExp : UnaExp -{ - TemplateDeclaration *td; - - DotTemplateExp(Loc loc, Expression *e, TemplateDeclaration *td); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct DotVarExp : UnaExp -{ - Declaration *var; - int hasOverloads; - - DotVarExp(Loc loc, Expression *e, Declaration *var, int hasOverloads = 0); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct DotTemplateInstanceExp : UnaExp -{ - TemplateInstance *ti; - - DotTemplateInstanceExp(Loc loc, Expression *e, Identifier *name, Objects *tiargs); - Expression *syntaxCopy(); - TemplateDeclaration *getTempdecl(Scope *sc); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -}; - -struct DelegateExp : UnaExp -{ - FuncDeclaration *func; - Module* m; // starting point for overload resolution - int hasOverloads; - - DelegateExp(Loc loc, Expression *e, FuncDeclaration *func, int hasOverloads = 0); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); - - int inlineCost3(InlineCostState *ics); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DotTypeExp : UnaExp -{ - Dsymbol *sym; // symbol that represents a type - - DotTypeExp(Loc loc, Expression *e, Dsymbol *sym); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CallExp : UnaExp -{ - Expressions *arguments; // function arguments - FuncDeclaration *f; // symbol to call - - CallExp(Loc loc, Expression *e, Expressions *exps); - CallExp(Loc loc, Expression *e); - CallExp(Loc loc, Expression *e, Expression *earg1); - CallExp(Loc loc, Expression *e, Expression *earg1, Expression *earg2); - - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *resolveUFCS(Scope *sc); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *addDtorHook(Scope *sc); - MATCH implicitConvTo(Type *t); - - int inlineCost3(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* p); -#endif -}; - -struct AddrExp : UnaExp -{ - Module* m; // starting point for overload resolution - - AddrExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void checkEscape(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct PtrExp : UnaExp -{ - PtrExp(Loc loc, Expression *e); - PtrExp(Loc loc, Expression *e, Type *t); - Expression *semantic(Scope *sc); - int isLvalue(); - void checkEscapeRef(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct NegExp : UnaExp -{ - NegExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UAddExp : UnaExp -{ - UAddExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - - // For operator overloading - Identifier *opId(); -}; - -struct ComExp : UnaExp -{ - ComExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct NotExp : UnaExp -{ - NotExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct BoolExp : UnaExp -{ - BoolExp(Loc loc, Expression *e, Type *type); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DeleteExp : UnaExp -{ - DeleteExp(Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CastExp : UnaExp -{ - // Possible to cast to one type while painting to another type - Type *to; // type to cast to - unsigned mod; // MODxxxxx - - CastExp(Loc loc, Expression *e, Type *t); - CastExp(Loc loc, Expression *e, unsigned mod); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void checkEscape(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - // For operator overloading - Identifier *opId(); - Expression *op_overload(Scope *sc); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - bool disableOptimization; -#endif -}; - -struct VectorExp : UnaExp -{ - Type *to; - unsigned dim; // number of elements in the vector - - VectorExp(Loc loc, Expression *e, Type *t); - Expression *syntaxCopy(); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct SliceExp : UnaExp -{ - Expression *upr; // NULL if implicit 0 - Expression *lwr; // NULL if implicit [length - 1] - VarDeclaration *lengthVar; - - SliceExp(Loc loc, Expression *e1, Expression *lwr, Expression *upr); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void dump(int indent); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -#endif -}; - -struct ArrayLengthExp : UnaExp -{ - ArrayLengthExp(Loc loc, Expression *e1); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - - static Expression *rewriteOpAssign(BinExp *exp); - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// e1[a0,a1,a2,a3,...] - -struct ArrayExp : UnaExp -{ - Expressions *arguments; // Array of Expression's - size_t currentDimension; // for opDollar - VarDeclaration *lengthVar; - - ArrayExp(Loc loc, Expression *e1, Expressions *arguments); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - // For operator overloading - Identifier *opId(); - Expression *op_overload(Scope *sc); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); -}; - -/****************************************************************/ - -struct DotExp : BinExp -{ - DotExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct CommaExp : BinExp -{ - CommaExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - void checkEscape(); - void checkEscapeRef(); - IntRange getIntRange(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - int isBool(int result); - MATCH implicitConvTo(Type *t); - Expression *addDtorHook(Scope *sc); - Expression *castTo(Scope *sc, Type *t); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - void cacheLvalue(IRState* irs); -#endif -}; - -struct IndexExp : BinExp -{ - VarDeclaration *lengthVar; - int modifiable; - - IndexExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Expression *doInline(InlineDoState *ids); - -#if IN_DMD - elem *toElem(IRState *irs); -#elif IN_LLVM - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); - void cacheLvalue(IRState* irs); -#endif -}; - -/* For both i++ and i-- - */ -struct PostExp : BinExp -{ - PostExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Identifier *opId(); // For operator overloading -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -/* For both ++i and --i - */ -struct PreExp : UnaExp -{ - PreExp(enum TOK op, Loc loc, Expression *e); - Expression *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct AssignExp : BinExp -{ int ismemset; // !=0 if setting the contents of an array - - AssignExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - Identifier *opId(); // For operator overloading - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); - virtual AssignExp* isAssignExp() { return this; } -#endif -}; - -struct ConstructExp : AssignExp -{ - ConstructExp(Loc loc, Expression *e1, Expression *e2); -}; - -#if IN_DMD -#define ASSIGNEXP_TOELEM elem *toElem(IRState *irs); -#elif IN_LLVM -#define ASSIGNEXP_TOELEM DValue* toElem(IRState *irs); -#else -#define ASSIGNEXP_TOELEM -#endif - -#define ASSIGNEXP(op) \ -struct op##AssignExp : BinAssignExp \ -{ \ - op##AssignExp(Loc loc, Expression *e1, Expression *e2); \ - Expression *semantic(Scope *sc); \ - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); \ - X(void buildArrayIdent(OutBuffer *buf, Expressions *arguments);) \ - X(Expression *buildArrayLoop(Parameters *fparams);) \ - \ - Identifier *opId(); /* For operator overloading */ \ - \ - ASSIGNEXP_TOELEM \ -}; - -#define X(a) a -ASSIGNEXP(Add) -ASSIGNEXP(Min) -ASSIGNEXP(Mul) -ASSIGNEXP(Div) -ASSIGNEXP(Mod) -ASSIGNEXP(And) -ASSIGNEXP(Or) -ASSIGNEXP(Xor) -#if DMDV2 -ASSIGNEXP(Pow) -#endif -#undef X - -#define X(a) - -ASSIGNEXP(Shl) -ASSIGNEXP(Shr) -ASSIGNEXP(Ushr) -ASSIGNEXP(Cat) - -#undef X -#undef ASSIGNEXP -#undef ASSIGNEXP_TOELEM - -struct AddExp : BinExp -{ - AddExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - llvm::Constant *toConstElem(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct MinExp : BinExp -{ - MinExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - llvm::Constant *toConstElem(IRState* p); - DValue* toElem(IRState* irs); -#endif -}; - -struct CatExp : BinExp -{ - CatExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct MulExp : BinExp -{ - MulExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct DivExp : BinExp -{ - DivExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ModExp : BinExp -{ - ModExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -struct PowExp : BinExp -{ - PowExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; -#endif - -struct ShlExp : BinExp -{ - ShlExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct ShrExp : BinExp -{ - ShrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct UshrExp : BinExp -{ - UshrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - IntRange getIntRange(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndExp : BinExp -{ - AndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrExp : BinExp -{ - OrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct XorExp : BinExp -{ - XorExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void buildArrayIdent(OutBuffer *buf, Expressions *arguments); - Expression *buildArrayLoop(Parameters *fparams); - MATCH implicitConvTo(Type *t); - IntRange getIntRange(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct OrOrExp : BinExp -{ - OrOrExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct AndAndExp : BinExp -{ - AndAndExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *checkToBoolean(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct CmpExp : BinExp -{ - CmpExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Expression *op_overload(Scope *sc); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct InExp : BinExp -{ - InExp(Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - Identifier *opId(); - Identifier *opId_r(); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -struct RemoveExp : BinExp -{ - RemoveExp(Loc loc, Expression *e1, Expression *e2); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// == and != - -struct EqualExp : BinExp -{ - EqualExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - int isBit(); - - // For operator overloading - int isCommutative(); - Identifier *opId(); - Expression *op_overload(Scope *sc); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -// === and !=== - -struct IdentityExp : BinExp -{ - IdentityExp(enum TOK op, Loc loc, Expression *e1, Expression *e2); - Expression *semantic(Scope *sc); - int isBit(); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -/****************************************************************/ - -struct CondExp : BinExp -{ - Expression *econd; - - CondExp(Loc loc, Expression *econd, Expression *e1, Expression *e2); - Expression *syntaxCopy(); - int apply(apply_fp_t fp, void *param); - Expression *semantic(Scope *sc); - Expression *optimize(int result); - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue); - void checkEscape(); - void checkEscapeRef(); - int isLvalue(); - Expression *toLvalue(Scope *sc, Expression *e); - Expression *modifiableLvalue(Scope *sc, Expression *e); - Expression *checkToBoolean(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - MATCH implicitConvTo(Type *t); - Expression *castTo(Scope *sc, Type *t); - - Expression *doInline(InlineDoState *ids); - Expression *inlineScan(InlineScanState *iss); - -#if IN_DMD - elem *toElem(IRState *irs); -#endif - -#if IN_LLVM - DValue* toElem(IRState* irs); -#endif -}; - -#if DMDV2 -/****************************************************************/ - -struct DefaultInitExp : Expression -{ - enum TOK subop; // which of the derived classes this is - - DefaultInitExp(Loc loc, enum TOK subop, int size); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct FileInitExp : DefaultInitExp -{ - FileInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolveLoc(Loc loc, Scope *sc); -}; - -struct LineInitExp : DefaultInitExp -{ - LineInitExp(Loc loc); - Expression *semantic(Scope *sc); - Expression *resolveLoc(Loc loc, Scope *sc); -}; -#endif - -/****************************************************************/ - -#if IN_LLVM - -// this stuff is strictly LDC - -struct GEPExp : UnaExp -{ - unsigned index; - Identifier* ident; - - GEPExp(Loc loc, Expression* e, Identifier* id, unsigned idx); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Expression *toLvalue(Scope *sc, Expression *e); - - DValue* toElem(IRState* irs); - llvm::Constant *toConstElem(IRState *irs); -}; - -#endif - -/****************************************************************/ - -/* Special values used by the interpreter - */ -#define EXP_CANT_INTERPRET ((Expression *)1) -#define EXP_CONTINUE_INTERPRET ((Expression *)2) -#define EXP_BREAK_INTERPRET ((Expression *)3) -#define EXP_GOTO_INTERPRET ((Expression *)4) -#define EXP_VOID_INTERPRET ((Expression *)5) - -Expression *expType(Type *type, Expression *e); - -Expression *Neg(Type *type, Expression *e1); -Expression *Com(Type *type, Expression *e1); -Expression *Not(Type *type, Expression *e1); -Expression *Bool(Type *type, Expression *e1); -Expression *Cast(Type *type, Type *to, Expression *e1); -Expression *ArrayLength(Type *type, Expression *e1); -Expression *Ptr(Type *type, Expression *e1); - -Expression *Add(Type *type, Expression *e1, Expression *e2); -Expression *Min(Type *type, Expression *e1, Expression *e2); -Expression *Mul(Type *type, Expression *e1, Expression *e2); -Expression *Div(Type *type, Expression *e1, Expression *e2); -Expression *Mod(Type *type, Expression *e1, Expression *e2); -Expression *Pow(Type *type, Expression *e1, Expression *e2); -Expression *Shl(Type *type, Expression *e1, Expression *e2); -Expression *Shr(Type *type, Expression *e1, Expression *e2); -Expression *Ushr(Type *type, Expression *e1, Expression *e2); -Expression *And(Type *type, Expression *e1, Expression *e2); -Expression *Or(Type *type, Expression *e1, Expression *e2); -Expression *Xor(Type *type, Expression *e1, Expression *e2); -Expression *Index(Type *type, Expression *e1, Expression *e2); -Expression *Cat(Type *type, Expression *e1, Expression *e2); - -Expression *Equal(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Cmp(enum TOK op, Type *type, Expression *e1, Expression *e2); -Expression *Identity(enum TOK op, Type *type, Expression *e1, Expression *e2); - -Expression *Slice(Type *type, Expression *e1, Expression *lwr, Expression *upr); - -// Const-folding functions used by CTFE - -void sliceAssignArrayLiteralFromString(ArrayLiteralExp *existingAE, StringExp *newval, int firstIndex); -void sliceAssignStringFromArrayLiteral(StringExp *existingSE, ArrayLiteralExp *newae, int firstIndex); -void sliceAssignStringFromString(StringExp *existingSE, StringExp *newstr, int firstIndex); - - -#endif /* DMD_EXPRESSION_H */ diff --git a/dmd2/func.c b/dmd2/func.c deleted file mode 100644 index 2671023b..00000000 --- a/dmd2/func.c +++ /dev/null @@ -1,4236 +0,0 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "declaration.h" -#include "attrib.h" -#include "expression.h" -#include "scope.h" -#include "mtype.h" -#include "aggregate.h" -#include "identifier.h" -#include "id.h" -#include "module.h" -#include "statement.h" -#include "template.h" -#include "hdrgen.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -/********************************* FuncDeclaration ****************************/ - -FuncDeclaration::FuncDeclaration(Loc loc, Loc endloc, Identifier *id, StorageClass storage_class, Type *type) - : Declaration(id) -{ - //printf("FuncDeclaration(id = '%s', type = %p)\n", id->toChars(), type); - //printf("storage_class = x%x\n", storage_class); - this->storage_class = storage_class; - this->type = type; - if (type) - this->storage_class &= ~(STC_TYPECTOR | STC_FUNCATTR); - this->loc = loc; - this->endloc = endloc; - fthrows = NULL; - frequire = NULL; - fdrequire = NULL; - fdensure = NULL; - fdrequireParams = NULL; - fdensureParams = NULL; - outId = NULL; - vresult = NULL; - returnLabel = NULL; - fensure = NULL; - fbody = NULL; - localsymtab = NULL; - vthis = NULL; - v_arguments = NULL; -#if IN_GCC - v_argptr = NULL; -#endif - v_argsave = NULL; - parameters = NULL; - labtab = NULL; - overnext = NULL; - vtblIndex = -1; - hasReturnExp = 0; - naked = 0; - inlineStatusExp = ILSuninitialized; - inlineStatusStmt = ILSuninitialized; - inlineNest = 0; - isArrayOp = 0; - semanticRun = PASSinit; - semantic3Errors = 0; -#if DMDV1 - nestedFrameRef = 0; -#endif - fes = NULL; - introducing = 0; - tintro = NULL; - /* The type given for "infer the return type" is a TypeFunction with - * NULL for the return type. - */ - inferRetType = (type && type->nextOf() == NULL); - storage_class2 = 0; - hasReturnExp = 0; - nrvo_can = 1; - nrvo_var = NULL; -#if IN_DMD - shidden = NULL; -#endif -#if DMDV2 - builtin = BUILTINunknown; - tookAddressOf = 0; - flags = 0; -#endif -#if IN_LLVM - // LDC - isArrayOp = false; - allowInlining = false; - availableExternally = true; // assume this unless proven otherwise - - // function types in ldc don't merge if the context parameter differs - // so we actually don't care about the function declaration, but only - // what kind of context parameter it has. - // however, this constructor is usually called from the parser, which - // unfortunately doesn't provide the information needed to get to the - // aggregate type. So we have to stick with the FuncDeclaration and - // just be sure we don't actually rely on the symbol it points to, - // but rather just the type of its context parameter. - // this means some function might have a function type pointing to - // another function declaration - - if (type) - { - assert(type->ty == Tfunction && "invalid function type"); - TypeFunction* tf = (TypeFunction*)type; - if (tf->funcdecl == NULL) - tf->funcdecl = this; - } -#endif -} - -Dsymbol *FuncDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncDeclaration *f; - - //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncDeclaration *)s; - else - f = new FuncDeclaration(loc, endloc, ident, storage_class, type->syntaxCopy()); - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - -#if IN_LLVM - f->intrinsicName = intrinsicName; -#endif - - return f; -} - - -// Do the semantic analysis on the external interface to the function. - -void FuncDeclaration::semantic(Scope *sc) -{ TypeFunction *f; - AggregateDeclaration *ad; - StructDeclaration *sd; - ClassDeclaration *cd; - InterfaceDeclaration *id; - Dsymbol *pd; - bool doesoverride; - -#if 0 - printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, this, toPrettyChars(), sc->linkage); - if (isFuncLiteralDeclaration()) - printf("\tFuncLiteralDeclaration()\n"); - printf("sc->parent = %s, parent = %s\n", sc->parent->toChars(), parent ? parent->toChars() : ""); - printf("type: %p, %s\n", type, type->toChars()); -#endif - - if (semanticRun != PASSinit && isFuncLiteralDeclaration()) - { - /* Member functions that have return types that are - * forward references can have semantic() run more than - * once on them. - * See test\interface2.d, test20 - */ - return; - } - - parent = sc->parent; - Dsymbol *parent = toParent(); - - if (semanticRun >= PASSsemanticdone) - { - if (!parent->isClassDeclaration()) - { - return; - } - // need to re-run semantic() in order to set the class's vtbl[] - } - else - { - assert(semanticRun <= PASSsemantic); - semanticRun = PASSsemantic; - } - - unsigned dprogress_save = Module::dprogress; - - foverrides.setDim(0); // reset in case semantic() is being retried for this function - - storage_class |= sc->stc & ~STCref; - ad = isThis(); - if (ad) - storage_class |= ad->storage_class & (STC_TYPECTOR | STCsynchronized); - - //printf("function storage_class = x%llx, sc->stc = x%llx, %x\n", storage_class, sc->stc, Declaration::isFinal()); - - if (!originalType) - originalType = type; - if (!type->deco) - { - sc = sc->push(); - sc->stc |= storage_class & STCdisable; // forward to function type - TypeFunction *tf = (TypeFunction *)type; - if (tf->isref) sc->stc |= STCref; - if (tf->isnothrow) sc->stc |= STCnothrow; - if (tf->isproperty) sc->stc |= STCproperty; - if (tf->purity == PUREfwdref) sc->stc |= STCpure; - if (tf->trust == TRUSTsafe) sc->stc |= STCsafe; - if (tf->trust == TRUSTsystem) sc->stc |= STCsystem; - if (tf->trust == TRUSTtrusted) sc->stc |= STCtrusted; - - if (isCtorDeclaration()) - sc->flags |= SCOPEctor; - type = type->semantic(loc, sc); - sc = sc->pop(); - - /* Apply const, immutable and shared storage class - * to the function type - */ - StorageClass stc = storage_class; - if (type->isImmutable()) - stc |= STCimmutable; - if (type->isConst()) - stc |= STCconst; - if (type->isShared() || storage_class & STCsynchronized) - stc |= STCshared; - if (type->isWild()) - stc |= STCwild; - switch (stc & STC_TYPECTOR) - { - case STCimmutable: - case STCimmutable | STCconst: - case STCimmutable | STCconst | STCshared: - case STCimmutable | STCshared: - case STCimmutable | STCwild: - case STCimmutable | STCconst | STCwild: - case STCimmutable | STCconst | STCshared | STCwild: - case STCimmutable | STCshared | STCwild: - // Don't use toInvariant(), as that will do a merge() - type = type->makeInvariant(); - goto Lmerge; - - case STCconst: - case STCconst | STCwild: - type = type->makeConst(); - goto Lmerge; - - case STCshared | STCconst: - case STCshared | STCconst | STCwild: - type = type->makeSharedConst(); - goto Lmerge; - - case STCshared: - type = type->makeShared(); - goto Lmerge; - - case STCwild: - type = type->makeWild(); - goto Lmerge; - - case STCshared | STCwild: - type = type->makeSharedWild(); - goto Lmerge; - - Lmerge: - if (!(type->ty == Tfunction && !type->nextOf())) - /* Can't do merge if return type is not known yet - */ - type->deco = type->merge()->deco; - break; - - case 0: - break; - - default: - assert(0); - } - } - storage_class &= ~STCref; - if (type->ty != Tfunction) - { - error("%s must be a function instead of %s", toChars(), type->toChars()); - return; - } - f = (TypeFunction *)(type); - size_t nparams = Parameter::dim(f->parameters); - - linkage = sc->linkage; - protection = sc->protection; - - /* Purity and safety can be inferred for some functions by examining - * the function body. - */ - if (fbody && - (isFuncLiteralDeclaration() || parent->isTemplateInstance())) - { - if (f->purity == PUREimpure) // purity not specified - flags |= FUNCFLAGpurityInprocess; - - if (f->trust == TRUSTdefault) - flags |= FUNCFLAGsafetyInprocess; - - if (!f->isnothrow) - flags |= FUNCFLAGnothrowInprocess; - } - - if (storage_class & STCscope) - error("functions cannot be scope"); - - if (isAbstract() && !isVirtual()) - error("non-virtual functions cannot be abstract"); - - if (isOverride() && !isVirtual()) - error("cannot override a non-virtual function"); - - if ((f->isConst() || f->isImmutable()) && !isThis()) - error("without 'this' cannot be const/immutable"); - - if (isAbstract() && isFinal()) - error("cannot be both final and abstract"); -#if 0 - if (isAbstract() && fbody) - error("abstract functions cannot have bodies"); -#endif - -#if 0 - if (isStaticConstructor() || isStaticDestructor()) - { - if (!isStatic() || type->nextOf()->ty != Tvoid) - error("static constructors / destructors must be static void"); - if (f->arguments && f->arguments->dim) - error("static constructors / destructors must have empty parameter list"); - // BUG: check for invalid storage classes - } -#endif - -#ifdef IN_GCC - { - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (ad) - ad->methods.push(this); - } -#endif - sd = parent->isStructDeclaration(); - if (sd) - { - if (isCtorDeclaration()) - { - goto Ldone; - } -#if 0 - // Verify no constructors, destructors, etc. - if (isCtorDeclaration() - //||isDtorDeclaration() - //|| isInvariantDeclaration() - //|| isUnitTestDeclaration() - ) - { - error("special member functions not allowed for %ss", sd->kind()); - } - - if (!sd->inv) - sd->inv = isInvariantDeclaration(); - - if (!sd->aggNew) - sd->aggNew = isNewDeclaration(); - - if (isDelete()) - { - if (sd->aggDelete) - error("multiple delete's for struct %s", sd->toChars()); - sd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - } - - id = parent->isInterfaceDeclaration(); - if (id) - { - storage_class |= STCabstract; - - if (isCtorDeclaration() || -#if DMDV2 - isPostBlitDeclaration() || -#endif - isDtorDeclaration() || - isInvariantDeclaration() || - isUnitTestDeclaration() || isNewDeclaration() || isDelete()) - error("constructors, destructors, postblits, invariants, unittests, new and delete functions are not allowed in interface %s", id->toChars()); - if (fbody && isVirtual()) - error("function body is not abstract in interface %s", id->toChars()); - } - - /* Contracts can only appear without a body when they are virtual interface functions - */ - if (!fbody && (fensure || frequire) && !(id && isVirtual())) - error("in and out contracts require function body"); - - /* Template member functions aren't virtual: - * interface TestInterface { void tpl(T)(); } - * and so won't work in interfaces - */ - if ((pd = toParent()) != NULL && - pd->isTemplateInstance() && - (pd = toParent2()) != NULL && - (id = pd->isInterfaceDeclaration()) != NULL) - { - error("template member functions are not allowed in interface %s", id->toChars()); - } - - cd = parent->isClassDeclaration(); - if (cd) - { int vi; - CtorDeclaration *ctor; - DtorDeclaration *dtor; - InvariantDeclaration *inv; - - if (isCtorDeclaration()) - { -// ctor = (CtorDeclaration *)this; -// if (!cd->ctor) -// cd->ctor = ctor; - goto Ldone; - } - -#if 0 - dtor = isDtorDeclaration(); - if (dtor) - { - if (cd->dtor) - error("multiple destructors for class %s", cd->toChars()); - cd->dtor = dtor; - } - - inv = isInvariantDeclaration(); - if (inv) - { - cd->inv = inv; - } - - if (isNewDeclaration()) - { - if (!cd->aggNew) - cd->aggNew = (NewDeclaration *)(this); - } - - if (isDelete()) - { - if (cd->aggDelete) - error("multiple delete's for class %s", cd->toChars()); - cd->aggDelete = (DeleteDeclaration *)(this); - } -#endif - - if (storage_class & STCabstract) - cd->isabstract = 1; - - // if static function, do not put in vtbl[] - if (!isVirtual()) - { - //printf("\tnot virtual\n"); - goto Ldone; - } - - /* Find index of existing function in base class's vtbl[] to override - * (the index will be the same as in cd's current vtbl[]) - */ - vi = cd->baseClass ? findVtblIndex((Dsymbols*)&cd->baseClass->vtbl, cd->baseClass->vtbl.dim) - : -1; - - doesoverride = FALSE; - switch (vi) - { - case -1: - /* Didn't find one, so - * This is an 'introducing' function which gets a new - * slot in the vtbl[]. - */ - - // Verify this doesn't override previous final function - if (cd->baseClass) - { Dsymbol *s = cd->baseClass->search(loc, ident, 0); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s", f->toPrettyChars()); - } - } - - if (isFinal()) - { - // Don't check here, as it may override an interface function - //if (isOverride()) - //error("is marked as override, but does not override any function"); - cd->vtblFinal.push(this); - } - else - { - // Append to end of vtbl[] - //printf("\tintroducing function\n"); - introducing = 1; - vi = cd->vtbl.dim; - cd->vtbl.push(this); - vtblIndex = vi; - } - break; - - case -2: // can't determine because of fwd refs - cd->sizeok = 2; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)cd->baseClass->vtbl[vi]; - // This function is covariant with fdv - if (fdv->isFinal()) - error("cannot override final function %s", fdv->toPrettyChars()); - - doesoverride = TRUE; -#if DMDV2 - if (!isOverride()) - warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - FuncDeclaration *fdc = ((Dsymbol *)cd->vtbl.data[vi])->isFuncDeclaration(); - if (fdc->toParent() == parent) - { - // If both are mixins, then error. - // If either is not, the one that is not overrides the other. - - if (this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) - error("multiple overrides of same function"); - - // if (this is mixin) && (fdc is not mixin) then fdc overrides - else if (!this->parent->isClassDeclaration() && fdc->parent->isClassDeclaration()) - break; - - else if (!this->parent->isClassDeclaration() // if both are mixins then error -#if !BREAKABI - && !isDtorDeclaration() -#endif -#if DMDV2 - && !isPostBlitDeclaration() -#endif - ) - error("multiple overrides of same function"); - } - cd->vtbl[vi] = this; - vtblIndex = vi; - - /* Remember which functions this overrides - */ - foverrides.push(fdv); - - /* This works by whenever this function is called, - * it actually returns tintro, which gets dynamically - * cast to type. But we know that tintro is a base - * of type, so we could optimize it by not doing a - * dynamic cast, but just subtracting the isBaseOf() - * offset if the value is != null. - */ - - if (fdv->tintro) - tintro = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - int offset; - if (fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset)) - { - tintro = fdv->type; - } - } - break; - } - } - - /* Go through all the interface bases. - * If this function is covariant with any members of those interface - * functions, set the tintro. - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { - BaseClass *b = cd->interfaces[i]; - vi = findVtblIndex((Dsymbols *)&b->base->vtbl, b->base->vtbl.dim); - switch (vi) - { - case -1: - break; - - case -2: - cd->sizeok = 2; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - - default: - { FuncDeclaration *fdv = (FuncDeclaration *)b->base->vtbl.tdata()[vi]; - Type *ti = NULL; - - /* Remember which functions this overrides - */ - foverrides.push(fdv); - -#if DMDV2 - /* Should we really require 'override' when implementing - * an interface function? - */ - //if (!isOverride()) - //warning(loc, "overrides base class function %s, but is not marked with 'override'", fdv->toPrettyChars()); -#endif - - if (fdv->tintro) - ti = fdv->tintro; - else if (!type->equals(fdv->type)) - { - /* Only need to have a tintro if the vptr - * offsets differ - */ - unsigned errors = global.errors; - global.gag++; // suppress printing of error messages - int offset; - int baseOf = fdv->type->nextOf()->isBaseOf(type->nextOf(), &offset); - global.gag--; // suppress printing of error messages - if (errors != global.errors) - { - // any error in isBaseOf() is a forward reference error, so we bail out - global.errors = errors; - cd->sizeok = 2; // can't finish due to forward reference - Module::dprogress = dprogress_save; - return; - } - if (baseOf) - { - ti = fdv->type; - } - } - if (ti) - { - if (tintro && !tintro->equals(ti)) - { - error("incompatible covariant types %s and %s", tintro->toChars(), ti->toChars()); - } - tintro = ti; - } - goto L2; - } - } - } - - if (!doesoverride && isOverride()) - { - error("does not override any function"); - } - - L2: ; - - /* Go through all the interface bases. - * Disallow overriding any final functions in the interface(s). - */ - for (int i = 0; i < cd->interfaces_dim; i++) - { - BaseClass *b = cd->interfaces[i]; - if (b->base) - { - Dsymbol *s = search_function(b->base, ident); - if (s) - { - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - { - f = f->overloadExactMatch(type, getModule()); - if (f && f->isFinal() && f->prot() != PROTprivate) - error("cannot override final function %s.%s", b->base->toChars(), f->toPrettyChars()); - } - } - } - } - } - else if (isOverride() && !parent->isTemplateInstance()) - error("override only applies to class member functions"); - - /* Do not allow template instances to add virtual functions - * to a class. - */ - if (isVirtual()) - { - TemplateInstance *ti = parent->isTemplateInstance(); - if (ti) - { - // Take care of nested templates - while (1) - { - TemplateInstance *ti2 = ti->tempdecl->parent->isTemplateInstance(); - if (!ti2) - break; - ti = ti2; - } - - // If it's a member template - ClassDeclaration *cd = ti->tempdecl->isClassMember(); - if (cd) - { - error("cannot use template to add virtual function to class '%s'", cd->toChars()); - } - } - } - - if (isMain()) - { - // Check parameters to see if they are either () or (char[][] args) - switch (nparams) - { - case 0: - break; - - case 1: - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - if (arg0->type->ty != Tarray || - arg0->type->nextOf()->ty != Tarray || - arg0->type->nextOf()->nextOf()->ty != Tchar || - arg0->storageClass & (STCout | STCref | STClazy)) - goto Lmainerr; - break; - } - - default: - goto Lmainerr; - } - - if (!f->nextOf()) - error("must return int or void"); - else if (f->nextOf()->ty != Tint32 && f->nextOf()->ty != Tvoid) - error("must return int or void, not %s", f->nextOf()->toChars()); - if (f->varargs) - { - Lmainerr: - error("parameters must be main() or main(string[] args)"); - } - } - - if (ident == Id::assign && (sd || cd)) - { // Disallow identity assignment operator. - - // opAssign(...) - if (nparams == 0) - { if (f->varargs == 1) - goto Lassignerr; - } - else - { - Parameter *arg0 = Parameter::getNth(f->parameters, 0); - Type *t0 = arg0->type->toBasetype(); - Type *tb = sd ? sd->type : cd->type; - if (arg0->type->implicitConvTo(tb) || - (sd && t0->ty == Tpointer && t0->nextOf()->implicitConvTo(tb)) - ) - { - if (nparams == 1) - goto Lassignerr; - Parameter *arg1 = Parameter::getNth(f->parameters, 1); - if (arg1->defaultArg) - goto Lassignerr; - } - } - } - - if (isVirtual() && semanticRun != PASSsemanticdone) - { - Parameters *arguments = ((TypeFunction*)type)->parameters; - fdrequireParams = new Expressions(); - - /* Rewrite contracts as nested functions, then call them. - * Doing it as nested functions means that overriding functions - * can call them. - */ - if (frequire) - { /* in { ... } - * becomes: - * void __require() { ... } - * __require(); - */ - Loc loc = frequire->loc; - TypeFunction *tf = new TypeFunction(arguments->copy(), Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::require, STCundefined, tf); - fd->fbody = frequire; - Statement *s1 = new ExpStatement(loc, fd); - Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), fdrequireParams); - Statement *s2 = new ExpStatement(loc, e); - frequire = new CompoundStatement(loc, s1, s2); - fdrequire = fd; - } - - if (!outId && f->nextOf() && f->nextOf()->toBasetype()->ty != Tvoid) - outId = Id::result; // provide a default - - fdensureParams = new Expressions(); - Expression *eresult = NULL; - if (outId) { - eresult = new IdentifierExp(loc, outId); - fdensureParams->push(eresult); - } - - if (fensure) - { /* out (result) { ... } - * becomes: - * tret __ensure(ref tret result) { ... } - * __ensure(result); - */ - Loc loc = fensure->loc; - Parameter *a = NULL; - arguments = arguments->copy(); - if (outId) - { a = new Parameter(STCref | STCconst, f->nextOf(), outId, NULL); - arguments->insert(0, a); - } - TypeFunction *tf = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - FuncDeclaration *fd = new FuncDeclaration(loc, loc, - Id::ensure, STCundefined, tf); - fd->fbody = fensure; - Statement *s1 = new ExpStatement(loc, fd); - Expression *e = new CallExp(loc, new VarExp(loc, fd, 0), fdensureParams); - Statement *s2 = new ExpStatement(loc, e); - fensure = new CompoundStatement(loc, s1, s2); - fdensure = fd; - } - } - -Ldone: - Module::dprogress++; - //LDC relies on semanticRun variable not being reset here - if(semanticRun < PASSsemanticdone) - semanticRun = PASSsemanticdone; - - /* Save scope for possible later use (if we need the - * function internals) - */ - scope = new Scope(*sc); - scope->setNoFree(); - return; - -Lassignerr: - if (sd) - { - sd->hasIdentityAssign = 1; // don't need to generate it - goto Ldone; - } - error("identity assignment operator overload is illegal"); -} - -void FuncDeclaration::semantic2(Scope *sc) -{ -} - -// Do the semantic analysis on the internals of the function. - -void FuncDeclaration::semantic3(Scope *sc) -{ TypeFunction *f; - VarDeclaration *argptr = NULL; - VarDeclaration *_arguments = NULL; - int nerrors = global.errors; - - if (!parent) - { - if (global.errors) - return; - //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", kind(), toChars(), sc); - assert(0); - } - //printf("FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); - //printf("storage class = x%x %x\n", sc->stc, storage_class); - //{ static int x; if (++x == 2) *(char*)0=0; } - //printf("\tlinkage = %d\n", sc->linkage); - - //printf(" sc->incontract = %d\n", sc->incontract); - if (semanticRun >= PASSsemantic3) - return; - semanticRun = PASSsemantic3; - semantic3Errors = 0; - - // LDC - if (!global.params.useAvailableExternally) - availableExternally = false; - - if (!type || type->ty != Tfunction) - return; - f = (TypeFunction *)(type); - size_t nparams = Parameter::dim(f->parameters); - -#if 0 - // Check the 'throws' clause - if (fthrows) - { - for (int i = 0; i < fthrows->dim; i++) - { - Type *t = fthrows->tdata()[i]; - - t = t->semantic(loc, sc); - if (!t->isClassHandle()) - error("can only throw classes, not %s", t->toChars()); - } - } -#endif - - if (frequire) - { - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides.tdata()[i]; - - if (fdv->fbody && !fdv->frequire) - { - error("cannot have an in contract when overriden function %s does not have an in contract", fdv->toPrettyChars()); - break; - } - } - } - - frequire = mergeFrequire(frequire); - fensure = mergeFensure(fensure); - - if (fbody || frequire || fensure) - { - /* Symbol table into which we place parameters and nested functions, - * solely to diagnose name collisions. - */ - localsymtab = new DsymbolTable(); - - // Establish function scope - ScopeDsymbol *ss = new ScopeDsymbol(); - ss->parent = sc->scopesym; - Scope *sc2 = sc->push(ss); - sc2->func = this; - sc2->parent = this; - sc2->callSuper = 0; - sc2->sbreak = NULL; - sc2->scontinue = NULL; - sc2->sw = NULL; - sc2->fes = fes; - sc2->linkage = LINKd; - sc2->stc &= ~(STCauto | STCscope | STCstatic | STCabstract | - STCdeprecated | STCoverride | - STC_TYPECTOR | STCfinal | STCtls | STCgshared | STCref | - STCproperty | STCsafe | STCtrusted | STCsystem); - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - sc2->structalign = 8; - sc2->incontract = 0; -#if !IN_LLVM - sc2->tf = NULL; -#else - sc2->enclosingFinally = NULL; - sc2->enclosingScopeExit = NULL; -#endif - sc2->noctor = 0; - - // Declare 'this' - AggregateDeclaration *ad = isThis(); - if (ad) - { - if (isFuncLiteralDeclaration() && isNested() && !sc->intypeof) - { - error("function literals cannot be class members"); - return; - } - else - assert(!isNested() || sc->intypeof); // can't be both member and nested - } - vthis = declareThis(sc2, ad); - - // Declare hidden variable _arguments[] and _argptr - if (f->varargs == 1) - { -#if TARGET_NET - varArgs(sc2, f, argptr, _arguments); -#else - Type *t; - -#if !IN_LLVM - if (global.params.is64bit) - { // Declare save area for varargs registers - Type *t = new TypeIdentifier(loc, Id::va_argsave_t); - t = t->semantic(loc, sc); - if (t == Type::terror) - { - error("must import core.vararg to use variadic functions"); - return; - } - else - { - v_argsave = new VarDeclaration(loc, t, Id::va_argsave, NULL); - v_argsave->semantic(sc2); - sc2->insert(v_argsave); - v_argsave->parent = this; - } - } -#endif - - if (f->linkage == LINKd) - { // Declare _arguments[] -#if BREAKABI - v_arguments = new VarDeclaration(0, Type::typeinfotypelist->type, Id::_arguments_typeinfo, NULL); - v_arguments->storage_class = STCparameter; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; - - //t = Type::typeinfo->type->constOf()->arrayOf(); - t = Type::typeinfo->type->arrayOf(); - _arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - _arguments->semantic(sc2); - sc2->insert(_arguments); - _arguments->parent = this; -#else - t = Type::typeinfo->type->arrayOf(); - v_arguments = new VarDeclaration(0, t, Id::_arguments, NULL); - v_arguments->storage_class = STCparameter | STCin; - v_arguments->semantic(sc2); - sc2->insert(v_arguments); - v_arguments->parent = this; -#endif - } - if (f->linkage == LINKd || (f->parameters && Parameter::dim(f->parameters))) - { // Declare _argptr -#if IN_GCC - t = d_gcc_builtin_va_list_d_type; -#else - t = Type::tvoid->pointerTo(); -#endif - argptr = new VarDeclaration(0, t, Id::_argptr, NULL); - argptr->semantic(sc2); - sc2->insert(argptr); - argptr->parent = this; - } -#endif - } - -#if IN_LLVM - // LDC make sure argument type is semanticed. - // Turns TypeTuple!(int, int) into two int parameters, for instance. - if (f->parameters) - { - for (size_t i = 0; i < Parameter::dim(f->parameters); i++) - { Parameter *arg = (Parameter *)Parameter::getNth(f->parameters, i); - Type* nw = arg->type->semantic(0, sc); - if (arg->type != nw) { - arg->type = nw; - // Examine this index again. - // This is important if it turned into a tuple. - // In particular, the empty tuple should be handled or the - // next parameter will be skipped. - // FIXME: Maybe we only need to do this for tuples, - // and can add tuple.length after decrement? - i--; - } - } - // update nparams to include expanded tuples - nparams = Parameter::dim(f->parameters); - } -#endif - -#if 0 - // Propagate storage class from tuple parameters to their element-parameters. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; - - //printf("[%d] arg->type->ty = %d %s\n", i, arg->type->ty, arg->type->toChars()); - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Parameter::dim(t->arguments); - for (size_t j = 0; j < dim; j++) - { Parameter *narg = Parameter::getNth(t->arguments, j); - narg->storageClass = arg->storageClass; - } - } - } - } -#endif - - /* Declare all the function parameters as variables - * and install them in parameters[] - */ - size_t nparams = Parameter::dim(f->parameters); - if (nparams) - { /* parameters[] has all the tuples removed, as the back end - * doesn't know about tuples - */ - parameters = new VarDeclarations(); - parameters->reserve(nparams); - for (size_t i = 0; i < nparams; i++) - { - Parameter *arg = Parameter::getNth(f->parameters, i); - Identifier *id = arg->ident; - if (!id) - { - /* Generate identifier for un-named parameter, - * because we need it later on. - */ - arg->ident = id = Identifier::generateId("_param_", i); - } - Type *vtype = arg->type; - //if (isPure()) - //vtype = vtype->addMod(MODconst); - VarDeclaration *v = new VarDeclaration(loc, vtype, id, NULL); - //printf("declaring parameter %s of type %s\n", v->toChars(), v->type->toChars()); - v->storage_class |= STCparameter; - if (f->varargs == 2 && i + 1 == nparams) - v->storage_class |= STCvariadic; - v->storage_class |= arg->storageClass & (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - v->semantic(sc2); - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - parameters->push(v); - localsymtab->insert(v); - v->parent = this; - if (fdrequireParams) - fdrequireParams->push(new VarExp(loc, v)); - if (fdensureParams) - fdensureParams->push(new VarExp(loc, v)); - } - } - - // Declare the tuple symbols and put them in the symbol table, - // but not in parameters[]. - if (f->parameters) - { - for (size_t i = 0; i < f->parameters->dim; i++) - { Parameter *arg = f->parameters->tdata()[i]; - - if (!arg->ident) - continue; // never used, so ignore - if (arg->type->ty == Ttuple) - { TypeTuple *t = (TypeTuple *)arg->type; - size_t dim = Parameter::dim(t->arguments); - Objects *exps = new Objects(); - exps->setDim(dim); - for (size_t j = 0; j < dim; j++) - { Parameter *narg = Parameter::getNth(t->arguments, j); - assert(narg->ident); - VarDeclaration *v = sc2->search(0, narg->ident, NULL)->isVarDeclaration(); - assert(v); - Expression *e = new VarExp(v->loc, v); - exps->tdata()[j] = e; - } - assert(arg->ident); - TupleDeclaration *v = new TupleDeclaration(loc, arg->ident, exps); - //printf("declaring tuple %s\n", v->toChars()); - v->isexp = 1; - if (!sc2->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - localsymtab->insert(v); - v->parent = this; - } - } - } - - /* Do the semantic analysis on the [in] preconditions and - * [out] postconditions. - */ - sc2->incontract++; - - if (frequire) - { /* frequire is composed of the [in] contracts - */ - // BUG: need to error if accessing out parameters - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - // BUG: verify that all in and ref parameters are read - frequire = frequire->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (fensure || addPostInvariant()) - { /* fensure is composed of the [out] contracts - */ - if (!type->nextOf()) // if return type is inferred - { /* This case: - * auto fp = function() out { } body { }; - * Can fix by doing semantic() onf fbody first. - */ - error("post conditions are not supported if the return type is inferred"); - return; - } - - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc2->scopesym; - sc2 = sc2->push(sym); - - assert(type->nextOf()); - if (type->nextOf()->ty == Tvoid) - { - if (outId) - error("void functions have no result"); - } - else - { - if (!outId) - outId = Id::result; // provide a default - } - - if (outId) - { // Declare result variable - Loc loc = this->loc; - - if (fensure) - loc = fensure->loc; - - VarDeclaration *v = new VarDeclaration(loc, type->nextOf(), outId, NULL); - v->noscope = 1; - v->storage_class |= STCresult; -#if DMDV2 - if (!isVirtual()) - v->storage_class |= STCconst; - if (f->isref) - { - v->storage_class |= STCref | STCforeach; - } -#endif - sc2->incontract--; - v->semantic(sc2); - sc2->incontract++; - if (!sc2->insert(v)) - error("out result %s is already defined", v->toChars()); - v->parent = this; - vresult = v; - - // vresult gets initialized with the function return value - // in ReturnStatement::semantic() - } - - // BUG: need to treat parameters as const - // BUG: need to disallow returns and throws - if (fensure) - { fensure = fensure->semantic(sc2); - labtab = NULL; // so body can't refer to labels - } - - if (!global.params.useOut) - { fensure = NULL; // discard - vresult = NULL; - } - - // Postcondition invariant - if (addPostInvariant()) - { - Expression *e = NULL; - if (isCtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp *tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression* v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - e = new AssertExp(0, v); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - if (fensure) - fensure = new CompoundStatement(0, s, fensure); - else - fensure = s; - } - } - - if (fensure) - { returnLabel = new LabelDsymbol(Id::returnLabel); - LabelStatement *ls = new LabelStatement(0, Id::returnLabel, fensure); - returnLabel->statement = ls; - } - sc2 = sc2->pop(); - } - - sc2->incontract--; - - if (fbody) - { AggregateDeclaration *ad = isAggregateMember(); - - /* If this is a class constructor - */ - if (ad && isCtorDeclaration()) - { - for (size_t i = 0; i < ad->fields.dim; i++) - { VarDeclaration *v = ad->fields[i]; - - v->ctorinit = 0; - } - } - - if (inferRetType || f->retStyle() != RETstack) - nrvo_can = 0; - - fbody = fbody->semantic(sc2); - if (!fbody) - fbody = new CompoundStatement(0, new Statements()); - - if (inferRetType) - { // If no return type inferred yet, then infer a void - if (!type->nextOf()) - { - ((TypeFunction *)type)->next = Type::tvoid; - //type = type->semantic(loc, sc); // Removed with 6902 - } - f = (TypeFunction *)type; - } - - if (isStaticCtorDeclaration()) - { /* It's a static constructor. Ensure that all - * ctor consts were initialized. - */ - - Dsymbol *p = toParent(); - ScopeDsymbol *pd = p->isScopeDsymbol(); - if (!pd) - { - error("static constructor can only be member of struct/class/module, not %s %s", p->kind(), p->toChars()); - } - else - { - for (size_t i = 0; i < pd->members->dim; i++) - { Dsymbol *s = pd->members->tdata()[i]; - - s->checkCtorConstInit(); - } - } - } - - if (isCtorDeclaration() && ad) - { - //printf("callSuper = x%x\n", sc2->callSuper); - - ClassDeclaration *cd = ad->isClassDeclaration(); - - // Verify that all the ctorinit fields got initialized - if (!(sc2->callSuper & CSXthis_ctor)) - { - for (size_t i = 0; i < ad->fields.dim; i++) - { VarDeclaration *v = ad->fields[i]; - - if (v->ctorinit == 0) - { - /* Current bugs in the flow analysis: - * 1. union members should not produce error messages even if - * not assigned to - * 2. structs should recognize delegating opAssign calls as well - * as delegating calls to other constructors - */ - if (v->isCtorinit() && !v->type->isMutable() && cd) - error("missing initializer for final field %s", v->toChars()); - else if (v->storage_class & STCnodefaultctor) - error("field %s must be initialized in constructor", v->toChars()); - } - } - } - - if (cd && - !(sc2->callSuper & CSXany_ctor) && - cd->baseClass && cd->baseClass->ctor) - { - sc2->callSuper = 0; - - // Insert implicit super() at start of fbody - Expression *e1 = new SuperExp(0); - Expression *e = new CallExp(0, e1); - - e = e->trySemantic(sc2); - if (!e) - error("no match for implicit super() call in constructor"); - else - { - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, s, fbody); - } - } - } - else if (fes) - { // For foreach(){} body, append a return 0; - Expression *e = new IntegerExp(0); - Statement *s = new ReturnStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - assert(!returnLabel); - } - else if (!hasReturnExp && type->nextOf()->ty != Tvoid) - error("has no return statement, but is expected to return a value of type %s", type->nextOf()->toChars()); - else if (hasReturnExp & 8) // if inline asm - { - flags &= ~FUNCFLAGnothrowInprocess; - } - else - { -#if DMDV2 - // Check for errors related to 'nothrow'. - int nothrowErrors = global.errors; - int blockexit = fbody ? fbody->blockExit(f->isnothrow) : BEfallthru; - if (f->isnothrow && (global.errors != nothrowErrors) ) - error("'%s' is nothrow yet may throw", toChars()); - if (flags & FUNCFLAGnothrowInprocess) - { - flags &= ~FUNCFLAGnothrowInprocess; - if (!(blockexit & BEthrow)) - f->isnothrow = TRUE; - } - - int offend = blockexit & BEfallthru; -#endif - if (type->nextOf()->ty == Tvoid) - { - if (offend && isMain()) - { // Add a return 0; statement - Statement *s = new ReturnStatement(0, new IntegerExp(0)); - fbody = new CompoundStatement(0, fbody, s); - } - } - else - { - if (offend) - { Expression *e; -#if DMDV1 - warning(loc, "no return exp; or assert(0); at end of function"); -#else - error("no return exp; or assert(0); at end of function"); -#endif - if (global.params.useAssert && - !global.params.useInline) - { /* Add an assert(0, msg); where the missing return - * should be. - */ - e = new AssertExp( - endloc, - new IntegerExp(0), - new StringExp(loc, (char *)"missing return expression") - ); - } - else - e = new HaltExp(endloc); - e = new CommaExp(0, e, type->nextOf()->defaultInit()); - e = e->semantic(sc2); - Statement *s = new ExpStatement(0, e); - fbody = new CompoundStatement(0, fbody, s); - } - } - } - } - - { - Statements *a = new Statements(); - - // Merge in initialization of 'out' parameters - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = parameters->tdata()[i]; - if (v->storage_class & STCout) - { - assert(v->init); - ExpInitializer *ie = v->init->isExpInitializer(); - assert(ie); - if (ie->exp->op == TOKconstruct) - ie->exp->op = TOKassign; // construction occured in parameter processing - a->push(new ExpStatement(0, ie->exp)); - } - } - } - -// we'll handle variadics ourselves -#if !IN_LLVM - if (argptr) - { // Initialize _argptr -#if IN_GCC - // Handled in FuncDeclaration::toObjFile - v_argptr = argptr; - v_argptr->init = new VoidInitializer(loc); -#else - Type *t = argptr->type; - if (global.params.is64bit) - { // Initialize _argptr to point to v_argsave - Expression *e1 = new VarExp(0, argptr); - Expression *e = new SymOffExp(0, v_argsave, 6*8 + 8*16); - e->type = argptr->type; - e = new AssignExp(0, e1, e); - e = e->semantic(sc); - a->push(new ExpStatement(0, e)); - } - else - { // Initialize _argptr to point past non-variadic arg - VarDeclaration *p; - unsigned offset = 0; - - Expression *e1 = new VarExp(0, argptr); - // Find the last non-ref parameter - if (parameters && parameters->dim) - { - int lastNonref = parameters->dim -1; - p = parameters->tdata()[lastNonref]; - /* The trouble with out and ref parameters is that taking - * the address of it doesn't work, because later processing - * adds in an extra level of indirection. So we skip over them. - */ - while (p->storage_class & (STCout | STCref)) - { - --lastNonref; - offset += PTRSIZE; - if (lastNonref < 0) - { - p = v_arguments; - break; - } - p = parameters->tdata()[lastNonref]; - } - } - else - p = v_arguments; // last parameter is _arguments[] - if (p->storage_class & STClazy) - // If the last parameter is lazy, it's the size of a delegate - offset += PTRSIZE * 2; - else - offset += p->type->size(); - offset = (offset + PTRSIZE - 1) & ~(PTRSIZE - 1); // assume stack aligns on pointer size - Expression *e = new SymOffExp(0, p, offset); - e->type = Type::tvoidptr; - //e = e->semantic(sc); - e = new AssignExp(0, e1, e); - e->type = t; - a->push(new ExpStatement(0, e)); - p->isargptr = TRUE; - } -#endif - } - - if (_arguments) - { - /* Advance to elements[] member of TypeInfo_Tuple with: - * _arguments = v_arguments.elements; - */ - Expression *e = new VarExp(0, v_arguments); - e = new DotIdExp(0, e, Id::elements); - Expression *e1 = new VarExp(0, _arguments); - e = new ConstructExp(0, e1, e); - e = e->semantic(sc2); - a->push(new ExpStatement(0, e)); - } - -#endif // !IN_LLVM - - // Merge contracts together with body into one compound statement - - if (frequire && global.params.useIn) - { frequire->incontract = 1; - a->push(frequire); - } - - // Precondition invariant - if (addPreInvariant()) - { - Expression *e = NULL; - Expression *ee = NULL; - if (isDtorDeclaration()) - { - // Call invariant directly only if it exists - InvariantDeclaration *inv = ad->inv; - ClassDeclaration *cd = ad->isClassDeclaration(); - - while (!inv && cd) - { - cd = cd->baseClass; - if (!cd) - break; - inv = cd->inv; - } - if (inv) - { - e = new DsymbolExp(0, inv); - e = new CallExp(0, e); - e = e->semantic(sc2); - } - } - else - { // Call invariant virtually - ThisExp* tv = new ThisExp(0); - tv->type = vthis->type; - tv->var = vthis; - Expression *v = tv; - -#if STRUCTTHISREF - if (ad->isStructDeclaration()) - v = v->addressOf(sc); -#endif - Expression *se = new StringExp(0, (char *)"null this"); - se = se->semantic(sc); -#if !IN_LLVM - se->type = Type::tchar->arrayOf(); -#endif - e = new AssertExp(loc, v, se); - } - if (ee) - { - ExpStatement *s = new ExpStatement(0, ee); - a->push(s); - } - if (e) - { - ExpStatement *s = new ExpStatement(0, e); - a->push(s); - } - } - - if (fbody) - a->push(fbody); - - if (fensure) - { - a->push(returnLabel->statement); - - if (type->nextOf()->ty != Tvoid) - { -#if IN_LLVM - Expression *e = 0; - if (isCtorDeclaration()) { - ThisExp *te = new ThisExp(0); - te->type = vthis->type; - te->var = vthis; - e = te; - } else { - e = new VarExp(0, vresult); - } -#else - // Create: return vresult; - assert(vresult); - Expression *e = new VarExp(0, vresult); -#endif - if (tintro) - { e = e->implicitCastTo(sc, tintro->nextOf()); - e = e->semantic(sc); - } - ReturnStatement *s = new ReturnStatement(0, e); - a->push(s); - } - } - - fbody = new CompoundStatement(0, a); - -#if 0 // This seems to have been added in with dmd 2.032, see below - // wrap body of synchronized functions in a synchronized statement - if (isSynchronized()) - { - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd) - error("synchronized function %s must be a member of a class", toChars()); - - Expression *sync; - if (isStatic()) - { - // static member functions synchronize on classinfo - sync = cd->type->dotExp(sc2, new TypeExp(loc, cd->type), Id::classinfo); - } - else - { - // non-static member functions synchronize on this - sync = new VarExp(loc, vthis); - } - - // we do not want to rerun semantics on the whole function, so we - // manually adjust all labels in the function that currently don't - // have an enclosingScopeExit to use the new SynchronizedStatement - SynchronizedStatement* s = new SynchronizedStatement(loc, sync, NULL); - s->semantic(sc2); - s->body = fbody; - - // LDC - LabelMap::iterator it, end = labmap.end(); - for (it = labmap.begin(); it != end; ++it) - if (it->second->enclosingScopeExit == NULL) - it->second->enclosingScopeExit = s; - - a = new Statements; - a->push(s); - fbody = new CompoundStatement(0, a); - } -#endif -#if DMDV2 - /* Append destructor calls for parameters as finally blocks. - */ - if (parameters) - { for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = parameters->tdata()[i]; - - if (v->storage_class & (STCref | STCout)) - continue; - - /* Don't do this for static arrays, since static - * arrays are called by reference. Remove this - * when we change them to call by value. - */ - if (v->type->toBasetype()->ty == Tsarray) - continue; - - if (v->noscope) - continue; - - Expression *e = v->edtor; - if (e) - { Statement *s = new ExpStatement(0, e); - s = s->semantic(sc2); - if (fbody->blockExit(f->isnothrow) == BEfallthru) - fbody = new CompoundStatement(0, fbody, s); - else - fbody = new TryFinallyStatement(0, fbody, s); - } - } - } -#endif - -#if 1 - if (isSynchronized()) - { /* Wrap the entire function body in a synchronized statement - */ - AggregateDeclaration *ad = isThis(); - ClassDeclaration *cd = ad ? ad->isClassDeclaration() : parent->isClassDeclaration(); - - if (cd) - { -#if TARGET_WINDOS - if (/*config.flags2 & CFG2seh &&*/ // always on for WINDOS - !isStatic() && !fbody->usesEH()) - { - /* The back end uses the "jmonitor" hack for syncing; - * no need to do the sync at this level. - */ - } - else -#endif - { - Expression *vsync; - if (isStatic()) - { // The monitor is in the ClassInfo - vsync = new DotIdExp(loc, new DsymbolExp(loc, cd), Id::classinfo); - } - else - { // 'this' is the monitor - vsync = new VarExp(loc, vthis); - } - fbody = new PeelStatement(fbody); // don't redo semantic() - fbody = new SynchronizedStatement(loc, vsync, fbody); - fbody = fbody->semantic(sc2); - } - } - else - { - error("synchronized function %s must be a member of a class", toChars()); - } - } -#endif - } - - sc2->callSuper = 0; - sc2->pop(); - } - - /* If function survived being marked as impure, then it is pure - */ - if (flags & FUNCFLAGpurityInprocess) - { - flags &= ~FUNCFLAGpurityInprocess; - f->purity = PUREfwdref; - } - - if (flags & FUNCFLAGsafetyInprocess) - { - flags &= ~FUNCFLAGsafetyInprocess; - f->trust = TRUSTsafe; - } - - // Do semantic type AFTER pure/nothrow inference. - if (inferRetType) - { - type = type->semantic(loc, sc); - } - - if (global.gag && global.errors != nerrors) - semanticRun = PASSsemanticdone; // Ensure errors get reported again - else - { - semanticRun = PASSsemantic3done; - semantic3Errors = global.errors - nerrors; - } - //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent->toChars(), toChars(), sc, loc.toChars()); - //fflush(stdout); -} - -void FuncDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("FuncDeclaration::toCBuffer() '%s'\n", toChars()); - - StorageClassDeclaration::stcToCBuffer(buf, storage_class); - type->toCBuffer(buf, ident, hgs); - bodyToCBuffer(buf, hgs); -} - -VarDeclaration *FuncDeclaration::declareThis(Scope *sc, AggregateDeclaration *ad) -{ - if (ad) - { VarDeclaration *v; - - { - assert(ad->handle); - Type *thandle = ad->handle; -#if STRUCTTHISREF - thandle = thandle->addMod(type->mod); - thandle = thandle->addStorageClass(storage_class); - //if (isPure()) - //thandle = thandle->addMod(MODconst); -#else - if (storage_class & STCconst || type->isConst()) - { - assert(0); // BUG: shared not handled - if (thandle->ty == Tclass) - thandle = thandle->constOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->constOf()->pointerTo(); - } - } - else if (storage_class & STCimmutable || type->isImmutable()) - { - if (thandle->ty == Tclass) - thandle = thandle->invariantOf(); - else - { assert(thandle->ty == Tpointer); - thandle = thandle->nextOf()->invariantOf()->pointerTo(); - } - } - else if (storage_class & STCshared || type->isShared()) - { - assert(0); // not implemented - } -#endif - v = new ThisDeclaration(loc, thandle); - //v = new ThisDeclaration(loc, isCtorDeclaration() ? ad->handle : thandle); - v->storage_class |= STCparameter; -#if STRUCTTHISREF - if (thandle->ty == Tstruct) - v->storage_class |= STCref; -#endif - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = this; - return v; - } - } - else if (isNested()) - { - /* The 'this' for a nested function is the link to the - * enclosing function's stack frame. - * Note that nested functions and member functions are disjoint. - */ - VarDeclaration *v = new ThisDeclaration(loc, Type::tvoid->pointerTo()); - v->storage_class |= STCparameter; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = this; - return v; - } - - return NULL; -} - -int FuncDeclaration::equals(Object *o) -{ - if (this == o) - return TRUE; - - Dsymbol *s = isDsymbol(o); - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - return toParent()->equals(fd->toParent()) && - ident->equals(fd->ident) && type->equals(fd->type); - } - } - return FALSE; -} - -void FuncDeclaration::bodyToCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (fbody && - (!hgs->hdrgen || hgs->tpltMember || canInline(1,1,1)) - ) - { buf->writenl(); - - // in{} - if (frequire) - { buf->writestring("in"); - buf->writenl(); - frequire->toCBuffer(buf, hgs); - } - - // out{} - if (fensure) - { buf->writestring("out"); - if (outId) - { buf->writebyte('('); - buf->writestring(outId->toChars()); - buf->writebyte(')'); - } - buf->writenl(); - fensure->toCBuffer(buf, hgs); - } - - if (frequire || fensure) - { buf->writestring("body"); - buf->writenl(); - } - - buf->writebyte('{'); - buf->writenl(); - fbody->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { buf->writeByte(';'); - buf->writenl(); - } -} - -/**************************************************** - * Merge into this function the 'in' contracts of all it overrides. - * 'in's are OR'd together, i.e. only one of them needs to pass. - */ - -Statement *FuncDeclaration::mergeFrequire(Statement *sf, Expressions *params) -{ - if (!params) - params = fdrequireParams; - - /* If a base function and its override both have an IN contract, then - * only one of them needs to succeed. This is done by generating: - * - * void derived.in() { - * try { - * base.in(); - * } - * catch () { - * ... body of derived.in() ... - * } - * } - * - * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid. - * If base.in() throws, then derived.in()'s body is executed. - */ - - /* Implementing this is done by having the overriding function call - * nested functions (the fdrequire functions) nested inside the overridden - * function. This requires that the stack layout of the calling function's - * parameters and 'this' pointer be in the same place (as the nested - * function refers to them). - * This is easy for the parameters, as they are all on the stack in the same - * place by definition, since it's an overriding function. The problem is - * getting the 'this' pointer in the same place, since it is a local variable. - * We did some hacks in the code generator to make this happen: - * 1. always generate exception handler frame, or at least leave space for it - * in the frame (Windows 32 SEH only) - * 2. always generate an EBP style frame - * 3. since 'this' is passed in a register that is subsequently copied into - * a stack local, allocate that local immediately following the exception - * handler block, so it is always at the same offset from EBP. - */ - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides.tdata()[i]; - - /* The semantic pass on the contracts of the overridden functions must - * be completed before code generation occurs (bug 3602). - */ - if (fdv->fdrequire && fdv->fdrequire->semanticRun != PASSsemantic3done) - { - assert(fdv->scope); - Scope *sc = fdv->scope->push(); - sc->stc &= ~STCoverride; - fdv->semantic3(sc); - sc->pop(); - } - - sf = fdv->mergeFrequire(sf, params); - if (sf && fdv->fdrequire) - { - //printf("fdv->frequire: %s\n", fdv->frequire->toChars()); - /* Make the call: - * try { __require(); } - * catch { frequire; } - */ - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdrequire, 0), params); - Statement *s2 = new ExpStatement(loc, e); - - Catch *c = new Catch(loc, NULL, NULL, sf); - c->internalCatch = true; - Catches *catches = new Catches(); - catches->push(c); - sf = new TryCatchStatement(loc, s2, catches); - } - else - return NULL; - } - return sf; -} - -/**************************************************** - * Merge into this function the 'out' contracts of all it overrides. - * 'out's are AND'd together, i.e. all of them need to pass. - */ - -Statement *FuncDeclaration::mergeFensure(Statement *sf, Expressions *params) -{ - if (!params) - params = fdensureParams; - - /* Same comments as for mergeFrequire(), except that we take care - * of generating a consistent reference to the 'result' local by - * explicitly passing 'result' to the nested function as a reference - * argument. - * This won't work for the 'this' parameter as it would require changing - * the semantic code for the nested function so that it looks on the parameter - * list for the 'this' pointer, something that would need an unknown amount - * of tweaking of various parts of the compiler that I'd rather leave alone. - */ - for (int i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides.tdata()[i]; - - /* The semantic pass on the contracts of the overridden functions must - * be completed before code generation occurs (bug 3602 and 5230). - */ - if (fdv->fdensure && fdv->fdensure->semanticRun != PASSsemantic3done) - { - assert(fdv->scope); - Scope *sc = fdv->scope->push(); - sc->stc &= ~STCoverride; - fdv->semantic3(sc); - sc->pop(); - } - - sf = fdv->mergeFensure(sf, params); - if (fdv->fdensure) - { - //printf("fdv->fensure: %s\n", fdv->fensure->toChars()); - // Make the call: __ensure(result) - Expression *e = new CallExp(loc, new VarExp(loc, fdv->fdensure, 0), params); - Statement *s2 = new ExpStatement(loc, e); - - if (sf) - { - sf = new CompoundStatement(fensure->loc, s2, sf); - } - else - sf = s2; - } - } - return sf; -} - -/**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - -int FuncDeclaration::overrides(FuncDeclaration *fd) -{ int result = 0; - - if (fd->ident == ident) - { - int cov = type->covariant(fd->type); - if (cov) - { ClassDeclaration *cd1 = toParent()->isClassDeclaration(); - ClassDeclaration *cd2 = fd->toParent()->isClassDeclaration(); - - if (cd1 && cd2 && cd2->isBaseOf(cd1, NULL)) - result = 1; - } - } - return result; -} - -/************************************************* - * Find index of function in vtbl[0..dim] that - * this function overrides. - * Prefer an exact match to a covariant one. - * Returns: - * -1 didn't find one - * -2 can't determine because of forward references - */ - -int FuncDeclaration::findVtblIndex(Dsymbols *vtbl, int dim) -{ - FuncDeclaration *mismatch = NULL; - int bestvi = -1; - for (int vi = 0; vi < dim; vi++) - { - FuncDeclaration *fdv = vtbl->tdata()[vi]->isFuncDeclaration(); - if (fdv && fdv->ident == ident) - { - if (type->equals(fdv->type)) // if exact match - return vi; // no need to look further - - int cov = type->covariant(fdv->type); - //printf("\tbaseclass cov = %d\n", cov); - switch (cov) - { - case 0: // types are distinct - break; - - case 1: - bestvi = vi; // covariant, but not identical - break; // keep looking for an exact match - - case 2: - mismatch = fdv; // overrides, but is not covariant - break; // keep looking for an exact match - - case 3: - return -2; // forward references - - default: - assert(0); - } - } - } - if (bestvi == -1 && mismatch) - { - //type->print(); - //mismatch->type->print(); - //printf("%s %s\n", type->deco, mismatch->type->deco); - error("of type %s overrides but is not covariant with %s of type %s", - type->toChars(), mismatch->toPrettyChars(), mismatch->type->toChars()); - } - return bestvi; -} - -/**************************************************** - * Overload this FuncDeclaration with the new one f. - * Return !=0 if successful; i.e. no conflict. - */ - -int FuncDeclaration::overloadInsert(Dsymbol *s) -{ - FuncDeclaration *f; - AliasDeclaration *a; - - //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s->toChars(), toChars()); - a = s->isAliasDeclaration(); - if (a) - { - if (overnext) - return overnext->overloadInsert(a); - if (!a->aliassym && a->type->ty != Tident && a->type->ty != Tinstance) - { - //printf("\ta = '%s'\n", a->type->toChars()); - return FALSE; - } - overnext = a; - //printf("\ttrue: no conflict\n"); - return TRUE; - } - f = s->isFuncDeclaration(); - if (!f) - return FALSE; - -#if 0 - /* Disable this check because: - * const void foo(); - * semantic() isn't run yet on foo(), so the const hasn't been - * applied yet. - */ - if (type) - { printf("type = %s\n", type->toChars()); - printf("f->type = %s\n", f->type->toChars()); - } - if (type && f->type && // can be NULL for overloaded constructors - f->type->covariant(type) && - f->type->mod == type->mod && - !isFuncAliasDeclaration()) - { - //printf("\tfalse: conflict %s\n", kind()); - return FALSE; - } -#endif - - if (overnext) - return overnext->overloadInsert(f); - overnext = f; - //printf("\ttrue: no conflict\n"); - return TRUE; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -/*************************************************** - * Visit each overloaded function in turn, and call - * (*fp)(param, f) on it. - * Exit when no more, or (*fp)(param, f) returns 1. - * Returns: - * 0 continue - * 1 done - */ - -int overloadApply(FuncDeclaration *fstart, - int (*fp)(void *, FuncDeclaration *), - void *param) -{ - FuncDeclaration *f; - Declaration *d; - Declaration *next; - - for (d = fstart; d; d = next) - { FuncAliasDeclaration *fa = d->isFuncAliasDeclaration(); - - if (fa) - { - if (overloadApply(fa->funcalias, fp, param)) - return 1; - next = fa->overnext; - } - else - { - AliasDeclaration *a = d->isAliasDeclaration(); - - if (a) - { - Dsymbol *s = a->toAlias(); - next = s->isDeclaration(); - if (next == a) - break; - if (next == fstart) - break; - } - else - { - f = d->isFuncDeclaration(); - if (!f) - { d->error("is aliased to a function"); - break; // BUG: should print error message? - } - if ((*fp)(param, f)) - return 1; - - next = f->overnext; - } - } - } - return 0; -} - -/******************************************** - * If there are no overloads of function f, return that function, - * otherwise return NULL. - */ - -static int fpunique(void *param, FuncDeclaration *f) -{ FuncDeclaration **pf = (FuncDeclaration **)param; - - if (*pf) - { *pf = NULL; - return 1; // ambiguous, done - } - else - { *pf = f; - return 0; - } -} - -FuncDeclaration *FuncDeclaration::isUnique() -{ FuncDeclaration *result = NULL; - - overloadApply(this, &fpunique, &result); - return result; -} - -/******************************************** - * Find function in overload list that exactly matches t. - */ - -struct Param1 -{ - Type *t; // type to match - FuncDeclaration *f; // return value -}; - -int fp1(void *param, FuncDeclaration *f) -{ Param1 *p = (Param1 *)param; - Type *t = p->t; - - if (t->equals(f->type)) - { p->f = f; - return 1; - } - -#if DMDV2 - /* Allow covariant matches, as long as the return type - * is just a const conversion. - * This allows things like pure functions to match with an impure function type. - */ - if (t->ty == Tfunction) - { TypeFunction *tf = (TypeFunction *)f->type; - if (tf->covariant(t) == 1 && - tf->nextOf()->implicitConvTo(t->nextOf()) >= MATCHconst) - { - p->f = f; - return 1; - } - } -#endif - return 0; -} - -FuncDeclaration *FuncDeclaration::overloadExactMatch(Type *t, Module* from) -{ - Param1 p; - p.t = t; - p.f = NULL; - overloadApply(this, &fp1, &p); - return p.f; -} - - -/******************************************** - * Decide which function matches the arguments best. - */ - -struct Param2 -{ - Match *m; -#if DMDV2 - Expression *ethis; - int property; // 0: unintialized - // 1: seen @property - // 2: not @property -#endif - Expressions *arguments; -}; - -int fp2(void *param, FuncDeclaration *f) -{ Param2 *p = (Param2 *)param; - Match *m = p->m; - Expressions *arguments = p->arguments; - MATCH match; - - if (f != m->lastf) // skip duplicates - { - m->anyf = f; - TypeFunction *tf = (TypeFunction *)f->type; - - int property = (tf->isproperty) ? 1 : 2; - if (p->property == 0) - p->property = property; - else if (p->property != property) - error(f->loc, "cannot overload both property and non-property functions"); - - /* For constructors, don't worry about the right type of ethis. It's a problem - * anyway, because the constructor attribute may not match the ethis attribute, - * but we don't care because the attribute on the ethis doesn't matter until - * after it's constructed. - */ - match = (MATCH) tf->callMatch(f->needThis() && !f->isCtorDeclaration() ? p->ethis : NULL, arguments); - //printf("test1: match = %d\n", match); - if (match != MATCHnomatch) - { - if (match > m->last) - goto LfIsBetter; - - if (match < m->last) - goto LlastIsBetter; - - /* See if one of the matches overrides the other. - */ - if (m->lastf->overrides(f)) - goto LlastIsBetter; - else if (f->overrides(m->lastf)) - goto LfIsBetter; - -#if DMDV2 - /* Try to disambiguate using template-style partial ordering rules. - * In essence, if f() and g() are ambiguous, if f() can call g(), - * but g() cannot call f(), then pick f(). - * This is because f() is "more specialized." - */ - { - MATCH c1 = f->leastAsSpecialized(m->lastf); - MATCH c2 = m->lastf->leastAsSpecialized(f); - //printf("c1 = %d, c2 = %d\n", c1, c2); - if (c1 > c2) - goto LfIsBetter; - if (c1 < c2) - goto LlastIsBetter; - } -#endif - Lambiguous: - m->nextf = f; - m->count++; - return 0; - - LfIsBetter: - m->last = match; - m->lastf = f; - m->count = 1; - return 0; - - LlastIsBetter: - return 0; - } - } - return 0; -} - - -void overloadResolveX(Match *m, FuncDeclaration *fstart, - Expression *ethis, Expressions *arguments, Module* from) -{ - Param2 p; - p.m = m; - p.ethis = ethis; - p.property = 0; - p.arguments = arguments; - overloadApply(fstart, &fp2, &p); -} - - -FuncDeclaration *FuncDeclaration::overloadResolve(Loc loc, Expression *ethis, Expressions *arguments, int flags, Module* from) -{ - TypeFunction *tf; - Match m; - -#if 0 -printf("FuncDeclaration::overloadResolve('%s')\n", toChars()); -if (arguments) -{ int i; - - for (i = 0; i < arguments->dim; i++) - { Expression *arg; - - arg = arguments->tdata()[i]; - assert(arg->type); - printf("\t%s: ", arg->toChars()); - arg->type->print(); - } -} -#endif - - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - overloadResolveX(&m, this, ethis, arguments, from); - - if (m.count == 1) // exactly one match - { - return m.lastf; - } - else - { - OutBuffer buf; - - buf.writeByte('('); - if (arguments) - { - HdrGenState hgs; - - argExpTypesToCBuffer(&buf, arguments, &hgs); - buf.writeByte(')'); - if (ethis) - ethis->type->modToBuffer(&buf); - } - else - buf.writeByte(')'); - - if (m.last == MATCHnomatch) - { - if (flags & 1) // if do not print error messages - return NULL; // no match - - tf = (TypeFunction *)type; - - OutBuffer buf2; - tf->modToBuffer(&buf2); - - //printf("tf = %s, args = %s\n", tf->deco, arguments->tdata()[0]->type->deco); - error(loc, "%s%s is not callable using argument types %s", - Parameter::argsTypesToChars(tf->parameters, tf->varargs), - buf2.toChars(), - buf.toChars()); - return m.anyf; // as long as it's not a FuncAliasDeclaration - } - else - { -#if 1 - TypeFunction *t1 = (TypeFunction *)m.lastf->type; - TypeFunction *t2 = (TypeFunction *)m.nextf->type; - - error(loc, "called with argument types:\n\t(%s)\nmatches both:\n\t%s%s\nand:\n\t%s%s", - buf.toChars(), - m.lastf->toPrettyChars(), Parameter::argsTypesToChars(t1->parameters, t1->varargs), - m.nextf->toPrettyChars(), Parameter::argsTypesToChars(t2->parameters, t2->varargs)); -#else - error(loc, "overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); -#endif - return m.lastf; - } - } -} - -/************************************* - * Determine partial specialization order of 'this' vs g. - * This is very similar to TemplateDeclaration::leastAsSpecialized(). - * Returns: - * match 'this' is at least as specialized as g - * 0 g is more specialized than 'this' - */ - -#if DMDV2 -MATCH FuncDeclaration::leastAsSpecialized(FuncDeclaration *g) -{ -#define LOG_LEASTAS 0 - -#if LOG_LEASTAS - printf("%s.leastAsSpecialized(%s)\n", toChars(), g->toChars()); - printf("%s, %s\n", type->toChars(), g->type->toChars()); -#endif - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction *tf = (TypeFunction *)type; - TypeFunction *tg = (TypeFunction *)g->type; - size_t nfparams = Parameter::dim(tf->parameters); - size_t ngparams = Parameter::dim(tg->parameters); - MATCH match = MATCHexact; - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (needThis() && g->needThis()) - { - if (tf->mod != tg->mod) - { - if (MODimplicitConv(tf->mod, tg->mod)) - match = MATCHconst; - else - return MATCHnomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - args.setDim(nfparams); - for (int u = 0; u < nfparams; u++) - { - Parameter *p = Parameter::getNth(tf->parameters, u); - Expression *e; - if (p->storageClass & (STCref | STCout)) - { - e = new IdentifierExp(0, p->ident); - e->type = p->type; - } - else - e = p->type->defaultInit(); - args.tdata()[u] = e; - } - - MATCH m = (MATCH) tg->callMatch(NULL, &args, 1); - if (m) - { - /* A variadic parameter list is less specialized than a - * non-variadic one. - */ - if (tf->varargs && !tg->varargs) - goto L1; // less specialized - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - -/******************************************* - * Given a symbol that could be either a FuncDeclaration or - * a function template, resolve it to a function symbol. - * sc instantiation scope - * loc instantiation location - * targsi initial list of template arguments - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *resolveFuncCall(Scope *sc, Loc loc, Dsymbol *s, - Objects *tiargs, - Expression *ethis, - Expressions *arguments, - int flags) -{ - if (!s) - return NULL; // no match - FuncDeclaration *f = s->isFuncDeclaration(); - if (f) - f = f->overloadResolve(loc, ethis, arguments); - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - assert(td); - f = td->deduceFunctionTemplate(sc, loc, tiargs, NULL, arguments, flags); - } - return f; -} -#endif - -/******************************** - * Labels are in a separate scope, one per function. - */ - -LabelDsymbol *FuncDeclaration::searchLabel(Identifier *ident) -{ Dsymbol *s; - - if (!labtab) - labtab = new DsymbolTable(); // guess we need one - - s = labtab->lookup(ident); - if (!s) - { - s = new LabelDsymbol(ident); - labtab->insert(s); - } - return (LabelDsymbol *)s; -} - -/**************************************** - * If non-static member function that has a 'this' pointer, - * return the aggregate it is a member of. - * Otherwise, return NULL. - */ - -AggregateDeclaration *FuncDeclaration::isThis() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isThis() '%s'\n", toChars()); - ad = NULL; - if ((storage_class & STCstatic) == 0) - { - ad = isMember2(); - } - //printf("-FuncDeclaration::isThis() %p\n", ad); - return ad; -} - -AggregateDeclaration *FuncDeclaration::isMember2() -{ AggregateDeclaration *ad; - - //printf("+FuncDeclaration::isMember2() '%s'\n", toChars()); - ad = NULL; - for (Dsymbol *s = this; s; s = s->parent) - { -//printf("\ts = '%s', parent = '%s', kind = %s\n", s->toChars(), s->parent->toChars(), s->parent->kind()); - ad = s->isMember(); - if (ad) -{ - break; -} - if (!s->parent || - (!s->parent->isTemplateInstance())) -{ - break; -} - } - //printf("-FuncDeclaration::isMember2() %p\n", ad); - return ad; -} - -/***************************************** - * Determine lexical level difference from 'this' to nested function 'fd'. - * Error if this cannot call fd. - * Returns: - * 0 same level - * -1 increase nesting by 1 (fd is nested within 'this') - * >0 decrease nesting by number - */ - -int FuncDeclaration::getLevel(Loc loc, Scope *sc, FuncDeclaration *fd) -{ int level; - Dsymbol *s; - Dsymbol *fdparent; - - //printf("FuncDeclaration::getLevel(fd = '%s')\n", fd->toChars()); - fdparent = fd->toParent2(); - if (fdparent == this) - return -1; - s = this; - level = 0; - while (fd != s && fdparent != s->toParent2()) - { - //printf("\ts = %s, '%s'\n", s->kind(), s->toChars()); - FuncDeclaration *thisfd = s->isFuncDeclaration(); - if (thisfd) - { if (!thisfd->isNested() && !thisfd->vthis) - goto Lerr; - } - else - { - AggregateDeclaration *thiscd = s->isAggregateDeclaration(); - if (thiscd) - { if (!thiscd->isNested()) - goto Lerr; - } - else - goto Lerr; - } - - s = s->toParent2(); - assert(s); - level++; - } - return level; - -Lerr: - // Don't give error if in template constraint - if (!((sc->flags & SCOPEstaticif) && parent->isTemplateDeclaration())) - error(loc, "cannot access frame of function %s", fd->toPrettyChars()); - return 1; -} - -void FuncDeclaration::appendExp(Expression *e) -{ Statement *s; - - s = new ExpStatement(0, e); - appendState(s); -} - -void FuncDeclaration::appendState(Statement *s) -{ - if (!fbody) - fbody = s; - else - { - CompoundStatement *cs = fbody->isCompoundStatement(); - if (cs) - { - if (!cs->statements) - fbody = s; - else - cs->statements->push(s); - } - else - fbody = new CompoundStatement(0, fbody, s); - } -} - -const char *FuncDeclaration::toPrettyChars() -{ - if (isMain()) - return "D main"; - else - return Dsymbol::toPrettyChars(); -} - -int FuncDeclaration::isMain() -{ - return ident == Id::main && - linkage != LINKc && !isMember() && !isNested(); -} - -int FuncDeclaration::isWinMain() -{ - //printf("FuncDeclaration::isWinMain() %s\n", toChars()); -#if 0 - int x = ident == Id::WinMain && - linkage != LINKc && !isMember(); - printf("%s\n", x ? "yes" : "no"); - return x; -#else - return ident == Id::WinMain && - linkage != LINKc && !isMember(); -#endif -} - -int FuncDeclaration::isDllMain() -{ - return ident == Id::DllMain && - linkage != LINKc && !isMember(); -} - -int FuncDeclaration::isExport() -{ - return protection == PROTexport; -} - -int FuncDeclaration::isImportedSymbol() -{ - //printf("isImportedSymbol()\n"); - //printf("protection = %d\n", protection); - return (protection == PROTexport) && !fbody; -} - -// Determine if function goes into virtual function pointer table - -int FuncDeclaration::isVirtual() -{ - Dsymbol *p = toParent(); -#if 0 - printf("FuncDeclaration::isVirtual(%s)\n", toChars()); - printf("isMember:%p isStatic:%d private:%d ctor:%d !Dlinkage:%d\n", isMember(), isStatic(), protection == PROTprivate, isCtorDeclaration(), linkage != LINKd); - printf("result is %d\n", - isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - p->isClassDeclaration() && - !(p->isInterfaceDeclaration() && isFinal())); -#endif - return isMember() && - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - p->isClassDeclaration() && - !(p->isInterfaceDeclaration() && isFinal()); -} - -// Determine if a function is pedantically virtual - -int FuncDeclaration::isVirtualMethod() -{ - //printf("FuncDeclaration::isVirtualMethod() %s\n", toChars()); - if (!isVirtual()) - return 0; - // If it's a final method, and does not override anything, then it is not virtual - if (isFinal() && foverrides.dim == 0) - { - return 0; - } - return 1; -} - -int FuncDeclaration::isFinal() -{ - ClassDeclaration *cd; -#if 0 - printf("FuncDeclaration::isFinal(%s), %x\n", toChars(), Declaration::isFinal()); - printf("%p %d %d %d\n", isMember(), isStatic(), Declaration::isFinal(), ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); - printf("result is %d\n", - isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal))); - if (cd) - printf("\tmember of %s\n", cd->toChars()); -#if 0 - !(isStatic() || protection == PROTprivate || protection == PROTpackage) && - (cd = toParent()->isClassDeclaration()) != NULL && - cd->storage_class & STCfinal); -#endif -#endif - return isMember() && - (Declaration::isFinal() || - ((cd = toParent()->isClassDeclaration()) != NULL && cd->storage_class & STCfinal)); -} - -int FuncDeclaration::isAbstract() -{ - return storage_class & STCabstract; -} - -int FuncDeclaration::isCodeseg() -{ - return TRUE; // functions are always in the code segment -} - -int FuncDeclaration::isOverloadable() -{ - return 1; // functions can be overloaded -} - -enum PURE FuncDeclaration::isPure() -{ - //printf("FuncDeclaration::isPure() '%s'\n", toChars()); - assert(type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)type; - if (flags & FUNCFLAGpurityInprocess) - setImpure(); - if (tf->purity == PUREfwdref) - tf->purityLevel(); - enum PURE purity = tf->purity; - if (purity > PUREweak && needThis()) - { // The attribute of the 'this' reference affects purity strength - if (type->mod & (MODimmutable | MODwild)) - ; - else if (type->mod & MODconst && purity >= PUREconst) - purity = PUREconst; - else - purity = PUREweak; - } - tf->purity = purity; - // ^ This rely on the current situation that every FuncDeclaration has a - // unique TypeFunction. - return purity; -} - -enum PURE FuncDeclaration::isPureBypassingInference() -{ - if (flags & FUNCFLAGpurityInprocess) - return PUREfwdref; - else - return isPure(); -} - -/************************************** - * The function is doing something impure, - * so mark it as impure. - * If there's a purity error, return TRUE. - */ -bool FuncDeclaration::setImpure() -{ - if (flags & FUNCFLAGpurityInprocess) - { - flags &= ~FUNCFLAGpurityInprocess; - } - else if (isPure()) - return TRUE; - return FALSE; -} - -int FuncDeclaration::isSafe() -{ - assert(type->ty == Tfunction); - if (flags & FUNCFLAGsafetyInprocess) - setUnsafe(); - return ((TypeFunction *)type)->trust == TRUSTsafe; -} - -int FuncDeclaration::isTrusted() -{ - assert(type->ty == Tfunction); - if (flags & FUNCFLAGsafetyInprocess) - setUnsafe(); - return ((TypeFunction *)type)->trust == TRUSTtrusted; -} - -/************************************** - * The function is doing something unsave, - * so mark it as unsafe. - * If there's a safe error, return TRUE. - */ -bool FuncDeclaration::setUnsafe() -{ - if (flags & FUNCFLAGsafetyInprocess) - { - flags &= ~FUNCFLAGsafetyInprocess; - ((TypeFunction *)type)->trust = TRUSTsystem; - } - else if (isSafe()) - return TRUE; - return FALSE; -} - -// Determine if function needs -// a static frame pointer to its lexically enclosing function - -int FuncDeclaration::isNested() -{ - //if (!toParent()) - //printf("FuncDeclaration::isNested('%s') parent=%p\n", toChars(), parent); - //printf("\ttoParent2() = '%s'\n", toParent2()->toChars()); - return ((storage_class & STCstatic) == 0) && toParent2() && - (toParent2()->isFuncDeclaration() != NULL); -} - -int FuncDeclaration::needThis() -{ - //printf("FuncDeclaration::needThis() '%s'\n", toChars()); - int i = isThis() != NULL; - //printf("\t%d\n", i); - if (!i && isFuncAliasDeclaration()) - i = ((FuncAliasDeclaration *)this)->funcalias->needThis(); - return i; -} - -int FuncDeclaration::addPreInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -int FuncDeclaration::addPostInvariant() -{ - AggregateDeclaration *ad = isThis(); - return (ad && - ad->inv && - //ad->isClassDeclaration() && - global.params.useInvariants && - (protection == PROTprotected || protection == PROTpublic || protection == PROTexport) && - !naked && - ident != Id::cpctor); -} - -/********************************** - * Generate a FuncDeclaration for a runtime library function. - */ - -// -// LDC: Adjusted to give argument info to the runtime function decl. -// - -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, const char *name) -{ - return genCfunc(args, treturn, Lexer::idPool(name)); -} - -FuncDeclaration *FuncDeclaration::genCfunc(Parameters *args, Type *treturn, Identifier *id) -{ - FuncDeclaration *fd; - TypeFunction *tf; - Dsymbol *s; - static DsymbolTable *st = NULL; - - //printf("genCfunc(name = '%s')\n", id->toChars()); - //printf("treturn\n\t"); treturn->print(); - - // See if already in table - if (!st) - st = new DsymbolTable(); - s = st->lookup(id); - if (s) - { - fd = s->isFuncDeclaration(); - assert(fd); - assert(fd->type->nextOf()->equals(treturn)); - } - else - { - tf = new TypeFunction(args, treturn, 0, LINKc); - fd = new FuncDeclaration(0, 0, id, STCstatic, tf); - fd->protection = PROTpublic; - fd->linkage = LINKc; - - st->insert(fd); - } - return fd; -} - -const char *FuncDeclaration::kind() -{ - return "function"; -} - -void FuncDeclaration::checkNestedReference(Scope *sc, Loc loc) -{ - //printf("FuncDeclaration::checkNestedReference() %s\n", toChars()); - if (parent && parent != sc->parent && this->isNested() && - this->ident != Id::require && this->ident != Id::ensure) - { - // The function that this function is in - FuncDeclaration *fdv = toParent()->isFuncDeclaration(); - // The current function - FuncDeclaration *fdthis = sc->parent->isFuncDeclaration(); - - //printf("this = %s in [%s]\n", this->toChars(), this->loc.toChars()); - //printf("fdv = %s in [%s]\n", fdv->toChars(), fdv->loc.toChars()); - //printf("fdthis = %s in [%s]\n", fdthis->toChars(), fdthis->loc.toChars()); - - if (fdv && fdthis && fdv != fdthis) - { - int lv = fdthis->getLevel(loc, sc, fdv); - if (lv == -1) - return; // OK - if (lv == 0) - return; // OK - - // BUG: may need to walk up outer scopes like Declaration::checkNestedReference() does - - // function literal has reference to enclosing scope is delegate - if (FuncLiteralDeclaration *fld = fdthis->isFuncLiteralDeclaration()) - fld->tok = TOKdelegate; - } - } -} - -/******************************* - * Look at all the variables in this function that are referenced - * by nested functions, and determine if a closure needs to be - * created for them. - */ - -#if DMDV2 -int FuncDeclaration::needsClosure() -{ - /* Need a closure for all the closureVars[] if any of the - * closureVars[] are accessed by a - * function that escapes the scope of this function. - * We take the conservative approach and decide that any function that: - * 1) is a virtual function - * 2) has its address taken - * 3) has a parent that escapes - * -or- - * 4) this function returns a local struct/class - * - * Note that since a non-virtual function can be called by - * a virtual one, if that non-virtual function accesses a closure - * var, the closure still has to be taken. Hence, we check for isThis() - * instead of isVirtual(). (thanks to David Friedman) - */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); - for (int i = 0; i < closureVars.dim; i++) - { VarDeclaration *v = closureVars.tdata()[i]; - assert(v->isVarDeclaration()); - //printf("\tv = %s\n", v->toChars()); - - for (int j = 0; j < v->nestedrefs.dim; j++) - { FuncDeclaration *f = v->nestedrefs.tdata()[j]; - assert(f != this); - - //printf("\t\tf = %s, %d, %p, %d\n", f->toChars(), f->isVirtual(), f->isThis(), f->tookAddressOf); - if (f->isThis() || f->tookAddressOf) - goto Lyes; // assume f escapes this function's scope - - // Look to see if any parents of f that are below this escape - for (Dsymbol *s = f->parent; s && s != this; s = s->parent) - { - f = s->isFuncDeclaration(); - if (f && (f->isThis() || f->tookAddressOf)) - goto Lyes; - } - } - } - - /* Look for case (4) - */ - if (closureVars.dim) - { - assert(type->ty == Tfunction); - Type *tret = ((TypeFunction *)type)->next; - assert(tret); - tret = tret->toBasetype(); - if (tret->ty == Tclass || tret->ty == Tstruct) - { Dsymbol *st = tret->toDsymbol(NULL); - for (Dsymbol *s = st->parent; s; s = s->parent) - { - if (s == this) - goto Lyes; - } - } - } - - return 0; - -Lyes: - //printf("\tneeds closure\n"); - return 1; -} -#endif - -/*********************************************** - * Determine if function's variables are referenced by a function - * nested within it. - */ - -int FuncDeclaration::hasNestedFrameRefs() -{ -#if DMDV2 - if (closureVars.dim) -#else - if (nestedFrameRef) -#endif - return 1; - - /* If a virtual method has contracts, assume its variables are referenced - * by those contracts, even if they aren't. Because they might be referenced - * by the overridden or overriding function's contracts. - * This can happen because frequire and fensure are implemented as nested functions, - * and they can be called directly by an overriding function and the overriding function's - * context had better match, or Bugzilla 7337 will bite. - */ - if ((fdrequire || fdensure) && isVirtualMethod()) - return 1; - - if (foverrides.dim && isVirtualMethod()) - { - for (size_t i = 0; i < foverrides.dim; i++) - { - FuncDeclaration *fdv = foverrides.tdata()[i]; - if (fdv->hasNestedFrameRefs()) - return 1; - } - } - - return 0; -} - -/********************************************* - * Return the function's parameter list, and whether - * it is variadic or not. - */ - -Parameters *FuncDeclaration::getParameters(int *pvarargs) -{ Parameters *fparameters; - int fvarargs; - - if (type) - { - assert(type->ty == Tfunction); - TypeFunction *fdtype = (TypeFunction *)type; - fparameters = fdtype->parameters; - fvarargs = fdtype->varargs; - } - if (pvarargs) - *pvarargs = fvarargs; - return fparameters; -} - - -/****************************** FuncAliasDeclaration ************************/ - -// Used as a way to import a set of functions from another scope into this one. - -FuncAliasDeclaration::FuncAliasDeclaration(FuncDeclaration *funcalias) - : FuncDeclaration(funcalias->loc, funcalias->endloc, funcalias->ident, - funcalias->storage_class, funcalias->type) -{ - assert(funcalias != this); - this->funcalias = funcalias; -#if IN_LLVM - importprot = PROTundefined; -#endif -} - -const char *FuncAliasDeclaration::kind() -{ - return "function alias"; -} - - -/****************************** FuncLiteralDeclaration ************************/ - -FuncLiteralDeclaration::FuncLiteralDeclaration(Loc loc, Loc endloc, Type *type, - enum TOK tok, ForeachStatement *fes) - : FuncDeclaration(loc, endloc, NULL, STCundefined, type) -{ - const char *id; - - if (fes) - id = "__foreachbody"; - else if (tok == TOKreserved) - id = "__lambda"; - else if (tok == TOKdelegate) - id = "__dgliteral"; - else - id = "__funcliteral"; - this->ident = Lexer::uniqueId(id); - this->tok = tok; - this->fes = fes; - //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this->ident->toChars(), type->toChars()); -} - -Dsymbol *FuncLiteralDeclaration::syntaxCopy(Dsymbol *s) -{ - FuncLiteralDeclaration *f; - - //printf("FuncLiteralDeclaration::syntaxCopy('%s')\n", toChars()); - if (s) - f = (FuncLiteralDeclaration *)s; - else - { f = new FuncLiteralDeclaration(loc, endloc, type->syntaxCopy(), tok, fes); - f->ident = ident; // keep old identifier - } - FuncDeclaration::syntaxCopy(f); - return f; -} - -int FuncLiteralDeclaration::isNested() -{ - //printf("FuncLiteralDeclaration::isNested() '%s'\n", toChars()); - return (tok != TOKfunction); -} - -int FuncLiteralDeclaration::isVirtual() -{ - return FALSE; -} - -const char *FuncLiteralDeclaration::kind() -{ - // GCC requires the (char*) casts - return (tok != TOKfunction) ? (char*)"delegate" : (char*)"function"; -} - -void FuncLiteralDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte(' '); - type->toCBuffer(buf, NULL, hgs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* CtorDeclaration ****************************/ - -CtorDeclaration::CtorDeclaration(Loc loc, Loc endloc, StorageClass stc, Type *type) - : FuncDeclaration(loc, endloc, Id::ctor, stc, type) -{ - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); -} - -Dsymbol *CtorDeclaration::syntaxCopy(Dsymbol *s) -{ - CtorDeclaration *f = new CtorDeclaration(loc, endloc, storage_class, type->syntaxCopy()); - - f->outId = outId; - f->frequire = frequire ? frequire->syntaxCopy() : NULL; - f->fensure = fensure ? fensure->syntaxCopy() : NULL; - f->fbody = fbody ? fbody->syntaxCopy() : NULL; - assert(!fthrows); // deprecated - - return f; -} - - -void CtorDeclaration::semantic(Scope *sc) -{ - //printf("CtorDeclaration::semantic() %s\n", toChars()); - TypeFunction *tf = (TypeFunction *)type; - assert(tf && tf->ty == Tfunction); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static constructor - sc->flags |= SCOPEctor; - - parent = sc->parent; - Dsymbol *parent = toParent2(); - Type *tret; - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad || parent->isUnionDeclaration()) - { - error("constructors are only for class or struct definitions"); - fatal(); - tret = Type::tvoid; - } - else - { tret = ad->handle; - assert(tret); - tret = tret->addStorageClass(storage_class | sc->stc); - tret = tret->addMod(type->mod); - } - tf->next = tret; - type = type->semantic(loc, sc); - -#if STRUCTTHISREF - if (ad && ad->isStructDeclaration()) - { if (!originalType) - originalType = type->syntaxCopy(); - ((TypeFunction *)type)->isref = 1; - } -#endif - if (!originalType) - originalType = type; - - // Append: - // return this; - // to the function body - if (fbody && semanticRun < PASSsemantic) - { - ThisExp *e = new ThisExp(loc); - if (parent->isClassDeclaration()) - e->type = tret; - Statement *s = new ReturnStatement(loc, e); - fbody = new CompoundStatement(loc, fbody, s); - } - - FuncDeclaration::semantic(sc); - - sc->pop(); - - // See if it's the default constructor - if (ad && tf->varargs == 0 && Parameter::dim(tf->parameters) == 0) - { - StructDeclaration *sd = ad->isStructDeclaration(); - if (sd) - { - if (fbody || !(storage_class & STCdisable)) - { error("default constructor for structs only allowed with @disable and no body"); - storage_class |= STCdisable; - fbody = NULL; - } - sd->noDefaultCtor = TRUE; - } - else - ad->defaultCtor = this; - } -} - -const char *CtorDeclaration::kind() -{ - return "constructor"; -} - -char *CtorDeclaration::toChars() -{ - return (char *)"this"; -} - -int CtorDeclaration::isVirtual() -{ - return FALSE; -} - -int CtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int CtorDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - - -/********************************* PostBlitDeclaration ****************************/ - -#if DMDV2 -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, StorageClass stc) - : FuncDeclaration(loc, endloc, Id::_postblit, stc, NULL) -{ -} - -PostBlitDeclaration::PostBlitDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *PostBlitDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - PostBlitDeclaration *dd = new PostBlitDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void PostBlitDeclaration::semantic(Scope *sc) -{ - //printf("PostBlitDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - //printf("stc = x%llx\n", sc->stc); - parent = sc->parent; - Dsymbol *parent = toParent(); - StructDeclaration *ad = parent->isStructDeclaration(); - if (!ad) - { - error("post blits are only for struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - } - else if (ident == Id::_postblit && semanticRun < PASSsemantic) - ad->postblits.push(this); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd, storage_class); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not static - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int PostBlitDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload postblits -} - -int PostBlitDeclaration::addPreInvariant() -{ - return FALSE; -} - -int PostBlitDeclaration::addPostInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int PostBlitDeclaration::isVirtual() -{ - return FALSE; -} - -void PostBlitDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("this(this)"); - bodyToCBuffer(buf, hgs); -} -#endif - -/********************************* DtorDeclaration ****************************/ - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::dtor, STCundefined, NULL) -{ -} - -DtorDeclaration::DtorDeclaration(Loc loc, Loc endloc, Identifier *id) - : FuncDeclaration(loc, endloc, id, STCundefined, NULL) -{ -} - -Dsymbol *DtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DtorDeclaration *dd = new DtorDeclaration(loc, endloc, ident); - return FuncDeclaration::syntaxCopy(dd); -} - - -void DtorDeclaration::semantic(Scope *sc) -{ - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident->toChars(), Id::dtor->toChars(), ident, Id::dtor); - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("destructors are only for class/struct/union definitions, not %s %s", parent->kind(), parent->toChars()); - fatal(); - } - else if (ident == Id::dtor && semanticRun < PASSsemantic) - ad->dtors.push(this); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static destructor - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int DtorDeclaration::overloadInsert(Dsymbol *s) -{ - return FALSE; // cannot overload destructors -} - -int DtorDeclaration::addPreInvariant() -{ - return (isThis() && vthis && global.params.useInvariants); -} - -int DtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -const char *DtorDeclaration::kind() -{ - return "destructor"; -} - -char *DtorDeclaration::toChars() -{ - return (char *)"~this"; -} - -int DtorDeclaration::isVirtual() -{ - /* This should be FALSE so that dtor's don't get put into the vtbl[], - * but doing so will require recompiling everything. - */ -#if BREAKABI - return FALSE; -#else - return FuncDeclaration::isVirtual(); -#endif -} - -void DtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* StaticCtorDeclaration ****************************/ - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticCtor"), STCstatic, NULL) -{ -} - -StaticCtorDeclaration::StaticCtorDeclaration(Loc loc, Loc endloc, const char *name) - : FuncDeclaration(loc, endloc, - Identifier::generateId(name), STCstatic, NULL) -{ -} - -Dsymbol *StaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - StaticCtorDeclaration *scd = new StaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - - -void StaticCtorDeclaration::semantic(Scope *sc) -{ - //printf("StaticCtorDeclaration::semantic()\n"); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance() && semanticRun < PASSsemantic) - { - /* Add this prefix to the function: - * static int gate; - * if (++gate != 1) return; - * Note that this is not thread safe; should not have threads - * during static construction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = isSharedStaticCtorDeclaration() ? STCstatic : STCtls; - Statements *sa = new Statements(); - Statement *s = new ExpStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp(1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(1)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; - //printf("module1 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticCtorDeclaration::isThis() -{ - return NULL; -} - -int StaticCtorDeclaration::isVirtual() -{ - return FALSE; -} - -bool StaticCtorDeclaration::hasStaticCtorOrDtor() -{ - return TRUE; -} - -int StaticCtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticCtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - { buf->writestring("static this();"); - buf->writenl(); - return; - } - buf->writestring("static this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* SharedStaticCtorDeclaration ****************************/ - -SharedStaticCtorDeclaration::SharedStaticCtorDeclaration(Loc loc, Loc endloc) - : StaticCtorDeclaration(loc, endloc, "_sharedStaticCtor") -{ -} - -Dsymbol *SharedStaticCtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - SharedStaticCtorDeclaration *scd = new SharedStaticCtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(scd); -} - -void SharedStaticCtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("shared "); - StaticCtorDeclaration::toCBuffer(buf, hgs); -} - -/********************************* StaticDtorDeclaration ****************************/ - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, - Identifier::generateId("_staticDtor"), STCstatic, NULL) -{ - vgate = NULL; -} - -StaticDtorDeclaration::StaticDtorDeclaration(Loc loc, Loc endloc, const char *name) - : FuncDeclaration(loc, endloc, - Identifier::generateId(name), STCstatic, NULL) -{ - vgate = NULL; -} - -Dsymbol *StaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - StaticDtorDeclaration *sdd = new StaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - - -void StaticDtorDeclaration::semantic(Scope *sc) -{ - ClassDeclaration *cd = sc->scopesym->isClassDeclaration(); - - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - /* If the static ctor appears within a template instantiation, - * it could get called multiple times by the module constructors - * for different modules. Thus, protect it with a gate. - */ - if (inTemplateInstance() && semanticRun < PASSsemantic) - { - /* Add this prefix to the function: - * static int gate; - * if (--gate != 0) return; - * Increment gate during constructor execution. - * Note that this is not thread safe; should not have threads - * during static destruction. - */ - Identifier *id = Lexer::idPool("__gate"); - VarDeclaration *v = new VarDeclaration(0, Type::tint32, id, NULL); - v->storage_class = isSharedStaticDtorDeclaration() ? STCstatic : STCtls; - Statements *sa = new Statements(); - Statement *s = new ExpStatement(0, v); - sa->push(s); - Expression *e = new IdentifierExp(0, id); - e = new AddAssignExp(0, e, new IntegerExp((uint64_t)-1)); - e = new EqualExp(TOKnotequal, 0, e, new IntegerExp(0)); - s = new IfStatement(0, NULL, e, new ReturnStatement(0, NULL), NULL); - sa->push(s); - if (fbody) - sa->push(fbody); - fbody = new CompoundStatement(0, sa); - vgate = v; - } - - FuncDeclaration::semantic(sc); - - // We're going to need ModuleInfo - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { m->needmoduleinfo = 1; - //printf("module2 %s needs moduleinfo\n", m->toChars()); -#ifdef IN_GCC - m->strictlyneedmoduleinfo = 1; -#endif - } -} - -AggregateDeclaration *StaticDtorDeclaration::isThis() -{ - return NULL; -} - -int StaticDtorDeclaration::isVirtual() -{ - return FALSE; -} - -bool StaticDtorDeclaration::hasStaticCtorOrDtor() -{ - return TRUE; -} - -int StaticDtorDeclaration::addPreInvariant() -{ - return FALSE; -} - -int StaticDtorDeclaration::addPostInvariant() -{ - return FALSE; -} - -void StaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("static ~this()"); - bodyToCBuffer(buf, hgs); -} - -/********************************* SharedStaticDtorDeclaration ****************************/ - -SharedStaticDtorDeclaration::SharedStaticDtorDeclaration(Loc loc, Loc endloc) - : StaticDtorDeclaration(loc, endloc, "_sharedStaticDtor") -{ -} - -Dsymbol *SharedStaticDtorDeclaration::syntaxCopy(Dsymbol *s) -{ - assert(!s); - SharedStaticDtorDeclaration *sdd = new SharedStaticDtorDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(sdd); -} - -void SharedStaticDtorDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (!hgs->hdrgen) - { - buf->writestring("shared "); - StaticDtorDeclaration::toCBuffer(buf, hgs); - } -} - - -/********************************* InvariantDeclaration ****************************/ - -InvariantDeclaration::InvariantDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, Id::classInvariant, STCundefined, NULL) -{ -} - -Dsymbol *InvariantDeclaration::syntaxCopy(Dsymbol *s) -{ - InvariantDeclaration *id; - - assert(!s); - id = new InvariantDeclaration(loc, endloc); - FuncDeclaration::syntaxCopy(id); - return id; -} - - -void InvariantDeclaration::semantic(Scope *sc) -{ - parent = sc->parent; - Dsymbol *parent = toParent(); - AggregateDeclaration *ad = parent->isAggregateDeclaration(); - if (!ad) - { - error("invariants are only for struct/union/class definitions"); - return; - } - else if (ad->inv && ad->inv != this && semanticRun < PASSsemantic) - { - error("more than one invariant for %s", ad->toChars()); - } - ad->inv = this; - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - - sc = sc->push(); - sc->stc &= ~STCstatic; // not a static invariant - sc->stc |= STCconst; // invariant() is always const - sc->incontract++; - sc->linkage = LINKd; - - FuncDeclaration::semantic(sc); - - sc->pop(); -} - -int InvariantDeclaration::isVirtual() -{ - return FALSE; -} - -int InvariantDeclaration::addPreInvariant() -{ - return FALSE; -} - -int InvariantDeclaration::addPostInvariant() -{ - return FALSE; -} - -void InvariantDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("invariant"); - bodyToCBuffer(buf, hgs); -} - - -/********************************* UnitTestDeclaration ****************************/ - -/******************************* - * Generate unique unittest function Id so we can have multiple - * instances per module. - */ - -static Identifier *unitTestId() -{ - return Lexer::uniqueId("__unittest"); -} - -UnitTestDeclaration::UnitTestDeclaration(Loc loc, Loc endloc) - : FuncDeclaration(loc, endloc, unitTestId(), STCundefined, NULL) -{ -} - -Dsymbol *UnitTestDeclaration::syntaxCopy(Dsymbol *s) -{ - UnitTestDeclaration *utd; - - assert(!s); - utd = new UnitTestDeclaration(loc, endloc); - return FuncDeclaration::syntaxCopy(utd); -} - - -void UnitTestDeclaration::semantic(Scope *sc) -{ -#if IN_LLVM - if (global.params.useUnitTests && sc->module->isRoot) -#else - if (global.params.useUnitTests) -#endif - { - if (!type) - type = new TypeFunction(NULL, Type::tvoid, FALSE, LINKd); - Scope *sc2 = sc->push(); - // It makes no sense for unit tests to be pure or nothrow. - sc2->stc &= ~(STCnothrow | STCpure); - sc2->linkage = LINKd; - FuncDeclaration::semantic(sc2); - sc2->pop(); - } - -#if 0 - // We're going to need ModuleInfo even if the unit tests are not - // compiled in, because other modules may import this module and refer - // to this ModuleInfo. - // (This doesn't make sense to me?) - Module *m = getModule(); - if (!m) - m = sc->module; - if (m) - { - //printf("module3 %s needs moduleinfo\n", m->toChars()); - m->needmoduleinfo = 1; - } -#endif -} - -AggregateDeclaration *UnitTestDeclaration::isThis() -{ - return NULL; -} - -int UnitTestDeclaration::isVirtual() -{ - return FALSE; -} - -int UnitTestDeclaration::addPreInvariant() -{ - return FALSE; -} - -int UnitTestDeclaration::addPostInvariant() -{ - return FALSE; -} - -void UnitTestDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen) - return; - buf->writestring("unittest"); - bodyToCBuffer(buf, hgs); -} - -/********************************* NewDeclaration ****************************/ - -NewDeclaration::NewDeclaration(Loc loc, Loc endloc, Parameters *arguments, int varargs) - : FuncDeclaration(loc, endloc, Id::classNew, STCstatic, NULL) -{ - this->arguments = arguments; - this->varargs = varargs; -} - -Dsymbol *NewDeclaration::syntaxCopy(Dsymbol *s) -{ - NewDeclaration *f; - - f = new NewDeclaration(loc, endloc, NULL, varargs); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; -} - - -void NewDeclaration::semantic(Scope *sc) -{ - //printf("NewDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - Type *tret = Type::tvoid->pointerTo(); - if (!type) - type = new TypeFunction(arguments, tret, varargs, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is at least one argument of type size_t - TypeFunction *tf = (TypeFunction *)type; - if (Parameter::dim(tf->parameters) < 1) - { - error("at least one argument of type size_t expected"); - } - else - { - Parameter *a = Parameter::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tsize_t)) - error("first argument must be type size_t, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *NewDeclaration::kind() -{ - return "allocator"; -} - -int NewDeclaration::isVirtual() -{ - return FALSE; -} - -int NewDeclaration::addPreInvariant() -{ - return FALSE; -} - -int NewDeclaration::addPostInvariant() -{ - return FALSE; -} - -void NewDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("new"); - Parameter::argsToCBuffer(buf, hgs, arguments, varargs); - bodyToCBuffer(buf, hgs); -} - - -/********************************* DeleteDeclaration ****************************/ - -DeleteDeclaration::DeleteDeclaration(Loc loc, Loc endloc, Parameters *arguments) - : FuncDeclaration(loc, endloc, Id::classDelete, STCstatic, NULL) -{ - this->arguments = arguments; -} - -Dsymbol *DeleteDeclaration::syntaxCopy(Dsymbol *s) -{ - DeleteDeclaration *f; - - f = new DeleteDeclaration(loc, endloc, NULL); - - FuncDeclaration::syntaxCopy(f); - - f->arguments = Parameter::arraySyntaxCopy(arguments); - - return f; -} - - -void DeleteDeclaration::semantic(Scope *sc) -{ - //printf("DeleteDeclaration::semantic()\n"); - - parent = sc->parent; - Dsymbol *parent = toParent(); - ClassDeclaration *cd = parent->isClassDeclaration(); - if (!cd && !parent->isStructDeclaration()) - { - error("new allocators only are for class or struct definitions"); - } - if (!type) - type = new TypeFunction(arguments, Type::tvoid, 0, LINKd); - - type = type->semantic(loc, sc); - assert(type->ty == Tfunction); - - // Check that there is only one argument of type void* - TypeFunction *tf = (TypeFunction *)type; - if (Parameter::dim(tf->parameters) != 1) - { - error("one argument of type void* expected"); - } - else - { - Parameter *a = Parameter::getNth(tf->parameters, 0); - if (!a->type->equals(Type::tvoid->pointerTo())) - error("one argument of type void* expected, not %s", a->type->toChars()); - } - - FuncDeclaration::semantic(sc); -} - -const char *DeleteDeclaration::kind() -{ - return "deallocator"; -} - -int DeleteDeclaration::isDelete() -{ - return TRUE; -} - -int DeleteDeclaration::isVirtual() -{ - return FALSE; -} - -int DeleteDeclaration::addPreInvariant() -{ - return FALSE; -} - -int DeleteDeclaration::addPostInvariant() -{ - return FALSE; -} - -void DeleteDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("delete"); - Parameter::argsToCBuffer(buf, hgs, arguments, 0); - bodyToCBuffer(buf, hgs); -} - - - - diff --git a/dmd2/gpl.txt b/dmd2/gpl.txt deleted file mode 100644 index cc468912..00000000 --- a/dmd2/gpl.txt +++ /dev/null @@ -1,248 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 1, February 1989 - - Copyright (C) 1989 Free Software Foundation, Inc. - 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The license agreements of most software companies try to keep users -at the mercy of those companies. By contrast, our General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. The -General Public License applies to the Free Software Foundation's -software and to any other program whose authors commit to using it. -You can use it for your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Specifically, the General Public License is designed to make -sure that you have the freedom to give away or sell copies of free -software, that you receive source code or can get it if you want it, -that you can change the software or use pieces of it in new free -programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of a such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must tell them their rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any program or other work which -contains a notice placed by the copyright holder saying it may be -distributed under the terms of this General Public License. The -"Program", below, refers to any such program or work, and a "work based -on the Program" means either the Program or any work containing the -Program or a portion of it, either verbatim or with modifications. Each -licensee is addressed as "you". - - 1. You may copy and distribute verbatim copies of the Program's source -code as you receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice and -disclaimer of warranty; keep intact all the notices that refer to this -General Public License and to the absence of any warranty; and give any -other recipients of the Program a copy of this General Public License -along with the Program. You may charge a fee for the physical act of -transferring a copy. - - 2. You may modify your copy or copies of the Program or any portion of -it, and copy and distribute such modifications under the terms of Paragraph -1 above, provided that you also do the following: - - a) cause the modified files to carry prominent notices stating that - you changed the files and the date of any change; and - - b) cause the whole of any work that you distribute or publish, that - in whole or in part contains the Program or any part thereof, either - with or without modifications, to be licensed at no charge to all - third parties under the terms of this General Public License (except - that you may choose to grant warranty protection to some or all - third parties, at your option). - - c) If the modified program normally reads commands interactively when - run, you must cause it, when started running for such interactive use - in the simplest and most usual way, to print or display an - announcement including an appropriate copyright notice and a notice - that there is no warranty (or else, saying that you provide a - warranty) and that users may redistribute the program under these - conditions, and telling the user how to view a copy of this General - Public License. - - d) You may charge a fee for the physical act of transferring a - copy, and you may at your option offer warranty protection in - exchange for a fee. - -Mere aggregation of another independent work with the Program (or its -derivative) on a volume of a storage or distribution medium does not bring -the other work under the scope of these terms. - - 3. You may copy and distribute the Program (or a portion or derivative of -it, under Paragraph 2) in object code or executable form under the terms of -Paragraphs 1 and 2 above provided that you also do one of the following: - - a) accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of - Paragraphs 1 and 2 above; or, - - b) accompany it with a written offer, valid for at least three - years, to give any third party free (except for a nominal charge - for the cost of distribution) a complete machine-readable copy of the - corresponding source code, to be distributed under the terms of - Paragraphs 1 and 2 above; or, - - c) accompany it with the information you received as to where the - corresponding source code may be obtained. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form alone.) - -Source code for a work means the preferred form of the work for making -modifications to it. For an executable file, complete source code means -all the source code for all modules it contains; but, as a special -exception, it need not include source code for modules which are standard -libraries that accompany the operating system on which the executable -file runs, or for standard header files or definitions files that -accompany that operating system. - - 4. You may not copy, modify, sublicense, distribute or transfer the -Program except as expressly provided under this General Public License. -Any attempt otherwise to copy, modify, sublicense, distribute or transfer -the Program is void, and will automatically terminate your rights to use -the Program under this License. However, parties who have received -copies, or rights to use copies, from you under this General Public -License will not have their licenses terminated so long as such parties -remain in full compliance. - - 5. By copying, distributing or modifying the Program (or any work based -on the Program) you indicate your acceptance of this license to do so, -and all its terms and conditions. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the original -licensor to copy, distribute or modify the Program subject to these -terms and conditions. You may not impose any further restrictions on the -recipients' exercise of the rights granted herein. - - 7. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of the license which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -the license, you may choose any version ever published by the Free Software -Foundation. - - 8. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - Appendix: How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to humanity, the best way to achieve this is to make it -free software which everyone can redistribute and change under these -terms. - - To do so, attach the following notices to the program. It is safest to -attach them to the start of each source file to most effectively convey -the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) 19yy - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 1, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) 19xx name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the -appropriate parts of the General Public License. Of course, the -commands you use may be called something other than `show w' and `show -c'; they could even be mouse-clicks or menu items--whatever suits your -program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - program `Gnomovision' (a program to direct compilers to make passes - at assemblers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/dmd2/hdrgen.c b/dmd2/hdrgen.c deleted file mode 100644 index 78dd4001..00000000 --- a/dmd2/hdrgen.c +++ /dev/null @@ -1,100 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// Initial header generation implementation by Dave Fladebo -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Routines to emit header files - -#define PRETTY_PRINT -#define TEST_EMIT_ALL 0 // For Testing - -#define LOG 0 - -#include -#include -#include -#if __DMC__ -#include -#endif - -#include "rmem.h" - -#include "id.h" -#include "init.h" - -#include "attrib.h" -#include "cond.h" -#include "enum.h" -#include "import.h" -#include "module.h" -#include "mtype.h" -#include "scope.h" -#include "staticassert.h" -#include "template.h" -#include "utf.h" -#include "version.h" - -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "hdrgen.h" - -void argsToCBuffer(OutBuffer *buf, Expressions *arguments, HdrGenState *hgs); - -void Module::genhdrfile() -{ - OutBuffer hdrbufr; - - hdrbufr.printf("// D import file generated from '%s'", srcfile->toChars()); - hdrbufr.writenl(); - - HdrGenState hgs; - memset(&hgs, 0, sizeof(hgs)); - hgs.hdrgen = 1; - - toCBuffer(&hdrbufr, &hgs); - - // Transfer image to file - hdrfile->setbuffer(hdrbufr.data, hdrbufr.offset); - hdrbufr.data = NULL; - - char *pt = FileName::path(hdrfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - hdrfile->writev(); -} - - -void Module::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (md) - { - buf->writestring("module "); - buf->writestring(md->toChars()); - buf->writebyte(';'); - buf->writenl(); - } - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - - s->toHBuffer(buf, hgs); - } -} - - -void Dsymbol::toHBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - toCBuffer(buf, hgs); -} - - -/*************************************/ diff --git a/dmd2/hdrgen.h b/dmd2/hdrgen.h deleted file mode 100644 index 79cfb732..00000000 --- a/dmd2/hdrgen.h +++ /dev/null @@ -1,34 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// initial header generation implementation by Dave Fladebo -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -struct HdrGenState -{ - int hdrgen; // 1 if generating header file - int ddoc; // 1 if generating Ddoc file - int console; // 1 if writing to console - int tpltMember; - int inCallExp; - int inPtrExp; - int inSlcExp; - int inDotExp; - int inBinExp; - int inArrExp; - int emitInst; - struct - { - int init; - int decl; - } FLinit; - - HdrGenState() { memset(this, 0, sizeof(HdrGenState)); } -}; - - diff --git a/dmd2/html.c b/dmd2/html.c deleted file mode 100644 index f7ea2adb..00000000 --- a/dmd2/html.c +++ /dev/null @@ -1,772 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gpl.txt. -// See the included readme.txt for details. - - -/* HTML parser - */ - -#include -#include -#include -#include -#include -#include - -#define MARS 1 -#include "html.h" - -#if MARS -#include -#include "root.h" -//#include "../mars/mars.h" -#else -#include "outbuf.h" -#include "msgs2.h" - -extern void html_err(const char *, unsigned, unsigned, ...); - -static char __file__[] = __FILE__; /* for tassert.h */ -#include "tassert.h" -#endif - -#if __GNUC__ -int memicmp(const char *s1, const char *s2, int n); -#if 0 -{ - int result = 0; - - for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - } - return result; -} -#endif -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -static int isLineSeparator(const unsigned char* p); - -/********************************** - * Determine if beginning of tag identifier - * or a continuation of a tag identifier. - */ - -inline int istagstart(int c) -{ - return (isalpha(c) || c == '_'); -} - -inline int istag(int c) -{ - return (isalnum(c) || c == '_'); -} - -/********************************************** - */ - -Html::Html(const char *sourcename, unsigned char *base, unsigned length) -{ - //printf("Html::Html()\n"); - this->sourcename = sourcename; - this->base = base; - p = base; - end = base + length; - linnum = 1; - dbuf = NULL; - inCode = 0; -} - -/********************************************** - * Print error & quit. - */ - -void Html::error(const char *format, ...) -{ - printf("%s(%d) : HTML Error: ", sourcename, linnum); - - va_list ap; - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - - printf("\n"); - fflush(stdout); - -//#if MARS -// global.errors++; -//#else - exit(EXIT_FAILURE); -//#endif -} - -/********************************************** - * Extract all the code from an HTML file, - * concatenate it all together, and store in buf. - */ - -#if MARS -void Html::extractCode(OutBuffer *buf) -#else -void Html::extractCode(Outbuffer *buf) -#endif -{ - //printf("Html::extractCode()\n"); - dbuf = buf; // save for other routines - buf->reserve(end - p); - inCode = 0; - while (1) - { - //printf("p = %p, *p = x%x\n", p, *p); - switch (*p) - { -#if 0 // strings are not recognized outside of tags - case '"': - case '\'': - skipString(); - continue; -#endif - case '<': - if (p[1] == '!' && isCommentStart()) - { // Comments start with - * Netscape: comments nest - * w3c: whitespace can appear between -- and > of comment close - */ - -void Html::scanComment() -{ - // Most of the complexity is dealing with the case that - // an arbitrary amount of whitespace can appear between - // the -- and the > of a comment close. - int scangt = 0; - - //printf("scanComment()\n"); - if (*p == '\n') - { linnum++; - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - } - while (1) - { - //scangt = 1; // IE 5.0 compatibility - p++; - switch (*p) - { - case '-': - if (p[1] == '-') - { - if (p[2] == '>') // optimize for most common case - { - p += 3; - break; - } - p++; - scangt = 1; - } - else - scangt = 0; - continue; - - case '>': - if (scangt) - { // found --> - p++; - break; - } - continue; - - case ' ': - case '\t': - case '\f': - case '\v': - // skip white space - continue; - - case '\r': - if (p[1] == '\n') - goto Ldefault; - case '\n': - linnum++; // remember to count lines - // Always extract new lines, so that D lexer counts the - // lines right. - dbuf->writeByte(*p); - continue; - - case 0: - case 0x1a: - error("end of file before closing --> of comment"); - break; - - default: - Ldefault: - scangt = 0; // it's not --> - continue; - } - break; - } - //printf("*p = '%c'\n", *p); -} - -/******************************************** - * Determine if we are at the start of a comment. - * Input: - * p is on the opening '<' - * Returns: - * 0 if not start of a comment - * 1 if start of a comment, p is adjusted to point past -- - */ - -int Html::isCommentStart() -#ifdef __DMC__ - __out(result) - { - if (result == 0) - ; - else if (result == 1) - { - assert(p[-2] == '-' && p[-1] == '-'); - } - else - assert(0); - } - __body -#endif /* __DMC__ */ - { unsigned char *s; - - if (p[0] == '<' && p[1] == '!') - { - for (s = p + 2; 1; s++) - { - switch (*s) - { - case ' ': - case '\t': - case '\r': - case '\f': - case '\v': - // skip white space, even though spec says no - // white space is allowed - continue; - - case '-': - if (s[1] == '-') - { - p = s + 2; - return 1; - } - goto No; - - default: - goto No; - } - } - } - No: - return 0; - } - -int Html::isCDATAStart() -{ - const char * CDATA_START_MARKER = "0) - { - /* Always extract new lines, so that D lexer counts the lines - * right. - */ - linnum++; - dbuf->writeByte('\n'); - p += lineSepLength; - continue; - } - else if (p[0] == ']' && p[1] == ']' && p[2] == '>') - { - /* end of CDATA section */ - p += 3; - return; - } - else if (inCode) - { - /* this CDATA section contains D code */ - dbuf->writeByte(*p); - } - - p++; - } -} - - -/******************************************** - * Convert an HTML character entity into a character. - * Forms are: - * &name; named entity - * &#ddd; decimal - * &#xhhhh; hex - * Input: - * p is on the & - */ - -int Html::charEntity() -{ int c = 0; - int v; - int hex; - unsigned char *pstart = p; - - //printf("Html::charEntity('%c')\n", *p); - if (p[1] == '#') - { - p++; - if (p[1] == 'x' || p[1] == 'X') - { p++; - hex = 1; - } - else - hex = 0; - if (p[1] == ';') - goto Linvalid; - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - goto Lignore; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - break; - - case ';': - // Termination is explicit - p++; - break; - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - v = *p - '0'; - goto Lvalue; - - case 'a': case 'b': case 'c': - case 'd': case 'e': case 'f': - if (!hex) - goto Linvalid; - v = (*p - 'a') + 10; - goto Lvalue; - - case 'A': case 'B': case 'C': - case 'D': case 'E': case 'F': - if (!hex) - goto Linvalid; - v = (*p - 'A') + 10; - goto Lvalue; - - Lvalue: - if (hex) - c = (c << 4) + v; - else - c = (c * 10) + v; - if (c > 0x10FFFF) - { - error("character entity out of range"); - goto Lignore; - } - continue; - - default: - Linvalid: - error("invalid numeric character reference"); - goto Lignore; - } - break; - } - } - else - { - // It's a named entity; gather all characters until ; - unsigned char *idstart = p + 1; - - while (1) - { - p++; - switch (*p) - { - case 0: - case 0x1a: - error("end of file before end of character entity"); - break; - - case '\n': - case '\r': - case '<': // tag start - // Termination is assumed - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - break; - - case ';': - // Termination is explicit - c = HtmlNamedEntity(idstart, p - idstart); - if (c == -1) - goto Lignore; - p++; - break; - - default: - continue; - } - break; - } - } - - // Kludge to convert non-breaking space to ascii space - if (c == 160) - c = ' '; - - return c; - -Lignore: - //printf("Lignore\n"); - p = pstart + 1; - return '&'; -} - -/** - * identify DOS, Linux, Mac, Next and Unicode line endings - * 0 if this is no line separator - * >0 the length of the separator - * Note: input has to be UTF-8 - */ -static int isLineSeparator(const unsigned char* p) -{ - // Linux - if( p[0]=='\n') - return 1; - - // Mac & Dos - if( p[0]=='\r') - return (p[1]=='\n') ? 2 : 1; - - // Unicode (line || paragraph sep.) - if( p[0]==0xE2 && p[1]==0x80 && (p[2]==0xA8 || p[2]==0xA9)) - return 3; - - // Next - if( p[0]==0xC2 && p[1]==0x85) - return 2; - - return 0; -} - - diff --git a/dmd2/html.h b/dmd2/html.h deleted file mode 100644 index 9b5a548f..00000000 --- a/dmd2/html.h +++ /dev/null @@ -1,50 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gpl.txt. -// See the included readme.txt for details. - - -#if MARS -struct OutBuffer; -#else -struct Outbuffer; -#endif - -struct Html -{ - const char *sourcename; - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - unsigned linnum; // current line number -#if MARS - OutBuffer *dbuf; // code source buffer -#else - Outbuffer *dbuf; // code source buffer -#endif - int inCode; // !=0 if in code - - - Html(const char *sourcename, unsigned char *base, unsigned length); - - void error(const char *format, ...); -#if MARS - void extractCode(OutBuffer *buf); -#else - void extractCode(Outbuffer *buf); -#endif - void skipTag(); - void skipString(); - unsigned char *skipWhite(unsigned char *q); - void scanComment(); - int isCommentStart(); - void scanCDATA(); - int isCDATAStart(); - int charEntity(); - static int namedEntity(unsigned char *p, int length); -}; diff --git a/dmd2/identifier.c b/dmd2/identifier.c deleted file mode 100644 index 178ae12b..00000000 --- a/dmd2/identifier.c +++ /dev/null @@ -1,102 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "identifier.h" -#include "mars.h" -#include "lexer.h" -#include "id.h" - -Identifier::Identifier(const char *string, int value) -{ - //printf("Identifier('%s', %d)\n", string, value); - this->string = string; - this->value = value; - this->len = strlen(string); -} - -hash_t Identifier::hashCode() -{ - return String::calcHash(string); -} - -int Identifier::equals(Object *o) -{ - return this == o || memcmp(string,o->toChars(),len+1) == 0; -} - -int Identifier::compare(Object *o) -{ - return memcmp(string, o->toChars(), len + 1); -} - -char *Identifier::toChars() -{ - return (char *)string; -} - -const char *Identifier::toHChars2() -{ - const char *p = NULL; - - if (this == Id::ctor) p = "this"; - else if (this == Id::dtor) p = "~this"; - else if (this == Id::classInvariant) p = "invariant"; - else if (this == Id::unitTest) p = "unittest"; - else if (this == Id::dollar) p = "$"; - else if (this == Id::withSym) p = "with"; - else if (this == Id::result) p = "result"; - else if (this == Id::returnLabel) p = "return"; - else - { p = toChars(); - if (*p == '_') - { - if (memcmp(p, "_staticCtor", 11) == 0) - p = "static this"; - else if (memcmp(p, "_staticDtor", 11) == 0) - p = "static ~this"; - } - } - - return p; -} - -void Identifier::print() -{ - fprintf(stdmsg, "%s",string); -} - -int Identifier::dyncast() -{ - return DYNCAST_IDENTIFIER; -} - -// BUG: these are redundant with Lexer::uniqueId() - -Identifier *Identifier::generateId(const char *prefix) -{ - static size_t i; - - return generateId(prefix, ++i); -} - -Identifier *Identifier::generateId(const char *prefix, size_t i) -{ OutBuffer buf; - - buf.writestring(prefix); - buf.printf("%zu", i); - - char *id = buf.toChars(); - buf.data = NULL; - return Lexer::idPool(id); -} diff --git a/dmd2/identifier.h b/dmd2/identifier.h deleted file mode 100644 index d8796000..00000000 --- a/dmd2/identifier.h +++ /dev/null @@ -1,47 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_IDENTIFIER_H -#define DMD_IDENTIFIER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" - -#if IN_LLVM -namespace llvm -{ - class Value; -} -#endif - -struct Identifier : Object -{ - int value; - const char *string; - unsigned len; - - Identifier(const char *string, int value); - int equals(Object *o); - hash_t hashCode(); - int compare(Object *o); - void print(); - char *toChars(); - char *toHChars(); - const char *toHChars2(); - int dyncast(); - - static Identifier *generateId(const char *prefix); - static Identifier *generateId(const char *prefix, size_t i); -}; - -#endif /* DMD_IDENTIFIER_H */ diff --git a/dmd2/idgen.c b/dmd2/idgen.c deleted file mode 100644 index da3dc4f3..00000000 --- a/dmd2/idgen.c +++ /dev/null @@ -1,435 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/idgen.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Program to generate string files in d data structures. -// Saves much tedious typing, and eliminates typo problems. -// Generates: -// id.h -// id.c - -#include -#include -#include -#include - -struct Msgtable -{ - const char *ident; // name to use in DMD source - const char *name; // name in D executable -}; - -Msgtable msgtable[] = -{ - { "IUnknown" }, - { "Object" }, - { "object" }, - { "max" }, - { "min" }, - { "This", "this" }, - { "super" }, - { "ctor", "__ctor" }, - { "dtor", "__dtor" }, - { "cpctor", "__cpctor" }, - { "_postblit", "__postblit" }, - { "classInvariant", "__invariant" }, - { "unitTest", "__unitTest" }, - { "require", "__require" }, - { "ensure", "__ensure" }, - { "init" }, - { "size" }, - { "__sizeof", "sizeof" }, - { "__xalignof", "alignof" }, - { "mangleof" }, - { "stringof" }, - { "tupleof" }, - { "length" }, - { "remove" }, - { "ptr" }, - { "array" }, - { "funcptr" }, - { "dollar", "__dollar" }, - { "ctfe", "__ctfe" }, - { "offset" }, - { "offsetof" }, - { "ModuleInfo" }, - { "ClassInfo" }, - { "classinfo" }, - { "typeinfo" }, - { "outer" }, - { "Exception" }, - { "AssociativeArray" }, - { "Throwable" }, - { "Error" }, - { "withSym", "__withSym" }, - { "result", "__result" }, - { "returnLabel", "__returnLabel" }, - { "delegate" }, - { "line" }, - { "empty", "" }, - { "p" }, - { "q" }, - { "coverage", "__coverage" }, - { "__vptr" }, - { "__monitor" }, - - { "TypeInfo" }, - { "TypeInfo_Class" }, - { "TypeInfo_Interface" }, - { "TypeInfo_Struct" }, - { "TypeInfo_Enum" }, - { "TypeInfo_Typedef" }, - { "TypeInfo_Pointer" }, - { "TypeInfo_Vector" }, - { "TypeInfo_Array" }, - { "TypeInfo_StaticArray" }, - { "TypeInfo_AssociativeArray" }, - { "TypeInfo_Function" }, - { "TypeInfo_Delegate" }, - { "TypeInfo_Tuple" }, - { "TypeInfo_Const" }, - { "TypeInfo_Invariant" }, - { "TypeInfo_Shared" }, - { "TypeInfo_Wild", "TypeInfo_Inout" }, - { "elements" }, - { "_arguments_typeinfo" }, - { "_arguments" }, - { "_argptr" }, - { "_match" }, - { "destroy" }, - { "postblit" }, - - { "LINE", "__LINE__" }, - { "FILE", "__FILE__" }, - { "DATE", "__DATE__" }, - { "TIME", "__TIME__" }, - { "TIMESTAMP", "__TIMESTAMP__" }, - { "VENDOR", "__VENDOR__" }, - { "VERSIONX", "__VERSION__" }, - { "EOFX", "__EOF__" }, - - { "nan" }, - { "infinity" }, - { "dig" }, - { "epsilon" }, - { "mant_dig" }, - { "max_10_exp" }, - { "max_exp" }, - { "min_10_exp" }, - { "min_exp" }, - { "min_normal" }, - { "re" }, - { "im" }, - - { "C" }, - { "D" }, - { "Windows" }, - { "Pascal" }, - { "System" }, - - { "exit" }, - { "success" }, - { "failure" }, - - { "keys" }, - { "values" }, - { "rehash" }, - - { "sort" }, - { "reverse" }, - { "dup" }, - { "idup" }, - - { "property" }, - { "safe" }, - { "trusted" }, - { "system" }, - { "disable" }, - - // For inline assembler - { "___out", "out" }, - { "___in", "in" }, - { "__int", "int" }, - { "__dollar", "$" }, - { "__LOCAL_SIZE" }, - - // For operator overloads - { "uadd", "opPos" }, - { "neg", "opNeg" }, - { "com", "opCom" }, - { "add", "opAdd" }, - { "add_r", "opAdd_r" }, - { "sub", "opSub" }, - { "sub_r", "opSub_r" }, - { "mul", "opMul" }, - { "mul_r", "opMul_r" }, - { "div", "opDiv" }, - { "div_r", "opDiv_r" }, - { "mod", "opMod" }, - { "mod_r", "opMod_r" }, - { "eq", "opEquals" }, - { "cmp", "opCmp" }, - { "iand", "opAnd" }, - { "iand_r", "opAnd_r" }, - { "ior", "opOr" }, - { "ior_r", "opOr_r" }, - { "ixor", "opXor" }, - { "ixor_r", "opXor_r" }, - { "shl", "opShl" }, - { "shl_r", "opShl_r" }, - { "shr", "opShr" }, - { "shr_r", "opShr_r" }, - { "ushr", "opUShr" }, - { "ushr_r", "opUShr_r" }, - { "cat", "opCat" }, - { "cat_r", "opCat_r" }, - { "assign", "opAssign" }, - { "addass", "opAddAssign" }, - { "subass", "opSubAssign" }, - { "mulass", "opMulAssign" }, - { "divass", "opDivAssign" }, - { "modass", "opModAssign" }, - { "andass", "opAndAssign" }, - { "orass", "opOrAssign" }, - { "xorass", "opXorAssign" }, - { "shlass", "opShlAssign" }, - { "shrass", "opShrAssign" }, - { "ushrass", "opUShrAssign" }, - { "catass", "opCatAssign" }, - { "postinc", "opPostInc" }, - { "postdec", "opPostDec" }, - { "index", "opIndex" }, - { "indexass", "opIndexAssign" }, - { "slice", "opSlice" }, - { "sliceass", "opSliceAssign" }, - { "call", "opCall" }, - { "cast", "opCast" }, - { "match", "opMatch" }, - { "next", "opNext" }, - { "opIn" }, - { "opIn_r" }, - { "opStar" }, - { "opDot" }, - { "opDispatch" }, - { "opDollar" }, - { "opUnary" }, - { "opIndexUnary" }, - { "opSliceUnary" }, - { "opBinary" }, - { "opBinaryRight" }, - { "opOpAssign" }, - { "opIndexOpAssign" }, - { "opSliceOpAssign" }, - { "pow", "opPow" }, - { "pow_r", "opPow_r" }, - { "powass", "opPowAssign" }, - - { "classNew", "new" }, - { "classDelete", "delete" }, - - // For foreach - { "apply", "opApply" }, - { "applyReverse", "opApplyReverse" }, - - // Ranges - { "Fempty", "empty" }, - { "Ffront", "front" }, - { "Fback", "back" }, - { "FpopFront", "popFront" }, - { "FpopBack", "popBack" }, - - { "adDup", "_adDupT" }, - { "adReverse", "_adReverse" }, - - // For internal functions - { "aaLen", "_aaLen" }, - { "aaKeys", "_aaKeys" }, - { "aaValues", "_aaValues" }, - { "aaRehash", "_aaRehash" }, - { "monitorenter", "_d_monitorenter" }, - { "monitorexit", "_d_monitorexit" }, - { "criticalenter", "_d_criticalenter" }, - { "criticalexit", "_d_criticalexit" }, - { "_ArrayEq" }, - - // For pragma's - { "GNU_asm" }, - { "lib" }, - { "msg" }, - { "startaddress" }, - -#if IN_LLVM - // LDC pragma's - { "intrinsic" }, - { "va_intrinsic" }, - { "no_typeinfo" }, - { "no_moduleinfo" }, - { "Alloca", "alloca" }, - { "vastart", "va_start" }, - { "vacopy", "va_copy" }, - { "vaend", "va_end" }, - { "vaarg", "va_arg" }, - { "ldc" }, - { "allow_inline" }, - { "llvm_inline_asm" }, - { "fence" }, - { "atomic_load" }, - { "atomic_store" }, - { "atomic_cmp_xchg" }, - { "atomic_rmw" }, -#endif - - // For special functions - { "tohash", "toHash" }, - { "tostring", "toString" }, - { "getmembers", "getMembers" }, - - // Special functions -#if IN_DMD - { "alloca" }, -#endif - { "main" }, - { "WinMain" }, - { "DllMain" }, - { "tls_get_addr", "___tls_get_addr" }, - - // varargs implementation - { "va_argsave_t", "__va_argsave_t" }, - { "va_argsave", "__va_argsave" }, - - // Builtin functions - { "std" }, - { "core" }, - { "math" }, - { "sin" }, - { "cos" }, - { "tan" }, - { "_sqrt", "sqrt" }, - { "_pow", "pow" }, - { "atan2" }, - { "rndtol" }, - { "expm1" }, - { "exp2" }, - { "yl2x" }, - { "yl2xp1" }, - { "fabs" }, - { "bitop" }, - { "bsf" }, - { "bsr" }, - { "bswap" }, - - // Traits - { "isAbstractClass" }, - { "isArithmetic" }, - { "isAssociativeArray" }, - { "isFinalClass" }, - { "isFloating" }, - { "isIntegral" }, - { "isScalar" }, - { "isStaticArray" }, - { "isUnsigned" }, - { "isVirtualFunction" }, - { "isVirtualMethod" }, - { "isAbstractFunction" }, - { "isFinalFunction" }, - { "isStaticFunction" }, - { "isRef" }, - { "isOut" }, - { "isLazy" }, - { "hasMember" }, - { "identifier" }, - { "parent" }, - { "getMember" }, - { "getOverloads" }, - { "getVirtualFunctions" }, - { "getVirtualMethods" }, - { "classInstanceSize" }, - { "allMembers" }, - { "derivedMembers" }, - { "isSame" }, - { "compiles" }, -}; - - -int main() -{ - FILE *fp; - unsigned i; - - { - fp = fopen("id.h","w"); - if (!fp) - { printf("can't open id.h\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); -#if __DMC__ - fprintf(fp, "#pragma once\n"); -#endif - fprintf(fp, "#ifndef DMD_ID_H\n"); - fprintf(fp, "#define DMD_ID_H 1\n"); - fprintf(fp, "struct Identifier;\n"); - fprintf(fp, "struct Id\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - - fprintf(fp," static Identifier *%s;\n", id); - } - - fprintf(fp, " static void initialize();\n"); - fprintf(fp, "};\n"); - fprintf(fp, "#endif\n"); - - fclose(fp); - } - - { - fp = fopen("id.c","w"); - if (!fp) - { printf("can't open id.c\n"); - exit(EXIT_FAILURE); - } - - fprintf(fp, "// File generated by idgen.c\n"); - fprintf(fp, "#include \"id.h\"\n"); - fprintf(fp, "#include \"identifier.h\"\n"); - fprintf(fp, "#include \"lexer.h\"\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp,"Identifier *Id::%s;\n", id); - } - - fprintf(fp, "void Id::initialize()\n"); - fprintf(fp, "{\n"); - - for (i = 0; i < sizeof(msgtable) / sizeof(msgtable[0]); i++) - { const char *id = msgtable[i].ident; - const char *p = msgtable[i].name; - - if (!p) - p = id; - fprintf(fp," %s = Lexer::idPool(\"%s\");\n", id, p); - } - - fprintf(fp, "}\n"); - - fclose(fp); - } - - return EXIT_SUCCESS; -} diff --git a/dmd2/impcnvgen.c b/dmd2/impcnvgen.c deleted file mode 100644 index 8f182364..00000000 --- a/dmd2/impcnvgen.c +++ /dev/null @@ -1,427 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mtype.h" - -TY impcnvResult[TMAX][TMAX]; -TY impcnvType1[TMAX][TMAX]; -TY impcnvType2[TMAX][TMAX]; -int impcnvWarn[TMAX][TMAX]; - -int integral_promotion(int t) -{ - switch (t) - { - case Tchar: - case Twchar: - case Tbool: - case Tint8: - case Tuns8: - case Tint16: - case Tuns16: return Tint32; - case Tdchar: return Tuns32; - default: return t; - } -} - -void init() -{ int i, j; - - // Set conversion tables - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { impcnvResult[i][j] = Terror; - impcnvType1[i][j] = Terror; - impcnvType2[i][j] = Terror; - impcnvWarn[i][j] = 0; - } - -#define X(t1,t2, nt1,nt2, rt) \ - impcnvResult[t1][t2] = rt; \ - impcnvType1[t1][t2] = nt1; \ - impcnvType2[t1][t2] = nt2; - - - /* ======================= */ - - X(Tbool,Tbool, Tbool,Tbool, Tbool) - X(Tbool,Tint8, Tint32,Tint32, Tint32) - X(Tbool,Tuns8, Tint32,Tint32, Tint32) - X(Tbool,Tint16, Tint32,Tint32, Tint32) - X(Tbool,Tuns16, Tint32,Tint32, Tint32) - X(Tbool,Tint32, Tint32,Tint32, Tint32) - X(Tbool,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tbool,Tint64, Tint64,Tint64, Tint64) - X(Tbool,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tbool,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tbool,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tbool,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tbool,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tbool,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tbool,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tbool,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tbool,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tbool,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint8,Tint8, Tint32,Tint32, Tint32) - X(Tint8,Tuns8, Tint32,Tint32, Tint32) - X(Tint8,Tint16, Tint32,Tint32, Tint32) - X(Tint8,Tuns16, Tint32,Tint32, Tint32) - X(Tint8,Tint32, Tint32,Tint32, Tint32) - X(Tint8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint8,Tint64, Tint64,Tint64, Tint64) - X(Tint8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns8,Tuns8, Tint32,Tint32, Tint32) - X(Tuns8,Tint16, Tint32,Tint32, Tint32) - X(Tuns8,Tuns16, Tint32,Tint32, Tint32) - X(Tuns8,Tint32, Tint32,Tint32, Tint32) - X(Tuns8,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns8,Tint64, Tint64,Tint64, Tint64) - X(Tuns8,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns8,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns8,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns8,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns8,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns8,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns8,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns8,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns8,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns8,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint16,Tint16, Tint32,Tint32, Tint32) - X(Tint16,Tuns16, Tint32,Tint32, Tint32) - X(Tint16,Tint32, Tint32,Tint32, Tint32) - X(Tint16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint16,Tint64, Tint64,Tint64, Tint64) - X(Tint16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns16,Tuns16, Tint32,Tint32, Tint32) - X(Tuns16,Tint32, Tint32,Tint32, Tint32) - X(Tuns16,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns16,Tint64, Tint64,Tint64, Tint64) - X(Tuns16,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns16,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns16,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns16,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns16,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns16,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns16,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns16,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns16,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns16,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint32,Tint32, Tint32,Tint32, Tint32) - X(Tint32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tint32,Tint64, Tint64,Tint64, Tint64) - X(Tint32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns32,Tuns32, Tuns32,Tuns32, Tuns32) - X(Tuns32,Tint64, Tint64,Tint64, Tint64) - X(Tuns32,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tint64,Tint64, Tint64,Tint64, Tint64) - X(Tint64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tint64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tint64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tint64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tint64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tint64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tint64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tint64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tint64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tint64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tuns64,Tuns64, Tuns64,Tuns64, Tuns64) - - X(Tuns64,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tuns64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tuns64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - X(Tuns64,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tuns64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tuns64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - X(Tuns64,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tuns64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tuns64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat32,Tfloat32, Tfloat32,Tfloat32, Tfloat32) - X(Tfloat32,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat32,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat32,Timaginary32, Tfloat32,Timaginary32, Tfloat32) - X(Tfloat32,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat32,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat32,Tcomplex32, Tfloat32,Tcomplex32, Tcomplex32) - X(Tfloat32,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat32,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat64,Tfloat64, Tfloat64,Tfloat64, Tfloat64) - X(Tfloat64,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat64,Timaginary32, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary64, Tfloat64,Timaginary64, Tfloat64) - X(Tfloat64,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat64,Tcomplex32, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex64, Tfloat64,Tcomplex64, Tcomplex64) - X(Tfloat64,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tfloat80,Tfloat80, Tfloat80,Tfloat80, Tfloat80) - - X(Tfloat80,Timaginary32, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary64, Tfloat80,Timaginary80, Tfloat80) - X(Tfloat80,Timaginary80, Tfloat80,Timaginary80, Tfloat80) - - X(Tfloat80,Tcomplex32, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex64, Tfloat80,Tcomplex80, Tcomplex80) - X(Tfloat80,Tcomplex80, Tfloat80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary32,Timaginary32, Timaginary32,Timaginary32, Timaginary32) - X(Timaginary32,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary32,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary32,Tcomplex32, Timaginary32,Tcomplex32, Tcomplex32) - X(Timaginary32,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary32,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary64,Timaginary64, Timaginary64,Timaginary64, Timaginary64) - X(Timaginary64,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary64,Tcomplex32, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex64, Timaginary64,Tcomplex64, Tcomplex64) - X(Timaginary64,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Timaginary80,Timaginary80, Timaginary80,Timaginary80, Timaginary80) - - X(Timaginary80,Tcomplex32, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex64, Timaginary80,Tcomplex80, Tcomplex80) - X(Timaginary80,Tcomplex80, Timaginary80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex32,Tcomplex32, Tcomplex32,Tcomplex32, Tcomplex32) - X(Tcomplex32,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex32,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex64,Tcomplex64, Tcomplex64,Tcomplex64, Tcomplex64) - X(Tcomplex64,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - - /* ======================= */ - - X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80) - -#undef X - -#define Y(t1,t2) impcnvWarn[t1][t2] = 1; - - Y(Tuns8, Tint8) - Y(Tint16, Tint8) - Y(Tuns16, Tint8) - Y(Tint32, Tint8) - Y(Tuns32, Tint8) - Y(Tint64, Tint8) - Y(Tuns64, Tint8) - - Y(Tint8, Tuns8) - Y(Tint16, Tuns8) - Y(Tuns16, Tuns8) - Y(Tint32, Tuns8) - Y(Tuns32, Tuns8) - Y(Tint64, Tuns8) - Y(Tuns64, Tuns8) - - Y(Tint8, Tchar) - Y(Tint16, Tchar) - Y(Tuns16, Tchar) - Y(Tint32, Tchar) - Y(Tuns32, Tchar) - Y(Tint64, Tchar) - Y(Tuns64, Tchar) - - Y(Tuns16, Tint16) - Y(Tint32, Tint16) - Y(Tuns32, Tint16) - Y(Tint64, Tint16) - Y(Tuns64, Tint16) - - Y(Tint16, Tuns16) - Y(Tint32, Tuns16) - Y(Tuns32, Tuns16) - Y(Tint64, Tuns16) - Y(Tuns64, Tuns16) - - Y(Tint16, Twchar) - Y(Tint32, Twchar) - Y(Tuns32, Twchar) - Y(Tint64, Twchar) - Y(Tuns64, Twchar) - -// Y(Tuns32, Tint32) - Y(Tint64, Tint32) - Y(Tuns64, Tint32) - -// Y(Tint32, Tuns32) - Y(Tint64, Tuns32) - Y(Tuns64, Tuns32) - - Y(Tint64, Tdchar) - Y(Tuns64, Tdchar) - -// Y(Tint64, Tuns64) -// Y(Tuns64, Tint64) - - for (i = 0; i < TMAX; i++) - for (j = 0; j < TMAX; j++) - { - if (impcnvResult[i][j] == Terror) - { - impcnvResult[i][j] = impcnvResult[j][i]; - impcnvType1[i][j] = impcnvType2[j][i]; - impcnvType2[i][j] = impcnvType1[j][i]; - } - } -} - -int main() -{ FILE *fp; - int i; - int j; - - init(); - - fp = fopen("impcnvtab.c","w"); - - fprintf(fp,"// This file is generated by impcnvgen.c\n"); - fprintf(fp,"#include \"mtype.h\"\n"); - - fprintf(fp,"unsigned char Type::impcnvResult[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvResult[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType1[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType1[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvType2[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvType2[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fprintf(fp,"unsigned char Type::impcnvWarn[TMAX][TMAX] =\n{\n"); - for (i = 0; i < TMAX; i++) - { - for (j = 0; j < TMAX; j++) - { - fprintf(fp, "%d,",impcnvWarn[i][j]); - } - fprintf(fp, "\n"); - } - fprintf(fp,"};\n"); - - fclose(fp); - return EXIT_SUCCESS; -} diff --git a/dmd2/imphint.c b/dmd2/imphint.c deleted file mode 100644 index 09b057d8..00000000 --- a/dmd2/imphint.c +++ /dev/null @@ -1,88 +0,0 @@ - - -// Compiler implementation of the D programming language -// Copyright (c) 2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include - -#include "mars.h" - -/****************************************** - * Looks for undefined identifier s to see - * if it might be undefined because an import - * was not specified. - * Not meant to be a comprehensive list of names in each module, - * just the most common ones. - */ - -const char *importHint(const char *s) -{ -#if DMDV1 - static const char *modules[] = - { "std.c.stdio", - "std.stdio", - "std.math", - "std.c.stdarg", - }; - static const char *names[] = - { - "printf", NULL, - "writefln", NULL, - "sin", "cos", "sqrt", "fabs", NULL, - "__va_argsave_t", NULL, - }; -#else - static const char *modules[] = - { "core.stdc.stdio", - "std.stdio", - "std.math", - "core.vararg", - }; - static const char *names[] = - { - "printf", NULL, - "writeln", NULL, - "sin", "cos", "sqrt", "fabs", NULL, - "__va_argsave_t", NULL, - }; -#endif - int m = 0; - for (int n = 0; n < sizeof(names)/sizeof(names[0]); n++) - { - const char *p = names[n]; - if (p == NULL) - { m++; - continue; - } - assert(m < sizeof(modules)/sizeof(modules[0])); - if (strcmp(s, p) == 0) - return modules[m]; - } - return NULL; // didn't find it -} - -#if UNITTEST - -void unittest_importHint() -{ - const char *p; - - p = importHint("printf"); - assert(p); - p = importHint("fabs"); - assert(p); - p = importHint("xxxxx"); - assert(!p); -} - -#endif diff --git a/dmd2/import.c b/dmd2/import.c deleted file mode 100644 index bd43af90..00000000 --- a/dmd2/import.c +++ /dev/null @@ -1,397 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "dsymbol.h" -#include "import.h" -#include "identifier.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "mtype.h" -#include "declaration.h" -#include "id.h" -#include "attrib.h" - -/********************************* Import ****************************/ - -Import::Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, - int isstatic) - : Dsymbol(NULL) -{ - assert(id); - this->loc = loc; - this->packages = packages; - this->id = id; - this->aliasId = aliasId; - this->isstatic = isstatic; - this->protection = PROTprivate; // default to private - this->pkg = NULL; - this->mod = NULL; - - // Set symbol name (bracketed) - // import [cstdio] = std.stdio; - if (aliasId) - this->ident = aliasId; - // import [std].stdio; - else if (packages && packages->dim) - this->ident = packages->tdata()[0]; - // import [foo]; - else - this->ident = id; -} - -void Import::addAlias(Identifier *name, Identifier *alias) -{ - if (isstatic) - error("cannot have an import bind list"); - - if (!aliasId) - this->ident = NULL; // make it an anonymous import - - names.push(name); - aliases.push(alias); -} - -const char *Import::kind() -{ - return isstatic ? (char *)"static import" : (char *)"import"; -} - -enum PROT Import::prot() -{ - return protection; -} - -Dsymbol *Import::syntaxCopy(Dsymbol *s) -{ - assert(!s); - - Import *si; - - si = new Import(loc, packages, id, aliasId, isstatic); - - for (size_t i = 0; i < names.dim; i++) - { - si->addAlias(names.tdata()[i], aliases.tdata()[i]); - } - - return si; -} - -void Import::load(Scope *sc) -{ - //printf("Import::load('%s')\n", toChars()); - - // See if existing module - DsymbolTable *dst = Package::resolve(packages, NULL, &pkg); - - Dsymbol *s = dst->lookup(id); - if (s) - { -#if TARGET_NET - mod = (Module *)s; -#else - if (s->isModule()) - mod = (Module *)s; - else - error("package and module have the same name"); -#endif - } - - if (!mod) - { - // Load module - mod = Module::load(loc, packages, id); - dst->insert(id, mod); // id may be different from mod->ident, - // if so then insert alias - if (!mod->importedFrom) - mod->importedFrom = sc ? sc->module->importedFrom : Module::rootModule; - } - if (!pkg) - pkg = mod; - - //printf("-Import::load('%s'), pkg = %p\n", toChars(), pkg); -} - -void escapePath(OutBuffer *buf, const char *fname) -{ - while (1) - { - switch (*fname) - { - case 0: - return; - case '(': - case ')': - case '\\': - buf->writebyte('\\'); - default: - buf->writebyte(*fname); - break; - } - fname++; - } -} - -void Import::importAll(Scope *sc) -{ - if (!mod) - { - load(sc); - mod->importAll(0); - - if (!isstatic && !aliasId && !names.dim) - { - if (sc->explicitProtection) - protection = sc->protection; - sc->scopesym->importScope(mod, protection); - } - } -} - -void Import::semantic(Scope *sc) -{ - //printf("Import::semantic('%s')\n", toChars()); - - // Load if not already done so - if (!mod) - { load(sc); - mod->importAll(0); - } - - if (mod) - { -#if 0 - if (mod->loc.linnum != 0) - { /* If the line number is not 0, then this is not - * a 'root' module, i.e. it was not specified on the command line. - */ - mod->importedFrom = sc->module->importedFrom; - assert(mod->importedFrom); - } -#endif - - // Modules need a list of each imported module - //printf("%s imports %s\n", sc->module->toChars(), mod->toChars()); - sc->module->aimports.push(mod); - - if (!isstatic && !aliasId && !names.dim) - { - if (sc->explicitProtection) - protection = sc->protection; - for (Scope *scd = sc; scd; scd = scd->enclosing) - { - if (scd->scopesym) - { - scd->scopesym->importScope(mod, protection); - break; - } - } - } - - mod->semantic(); - - if (mod->needmoduleinfo) - { //printf("module4 %s because of %s\n", sc->module->toChars(), mod->toChars()); - sc->module->needmoduleinfo = 1; - } - - sc = sc->push(mod); - /* BUG: Protection checks can't be enabled yet. The issue is - * that Dsymbol::search errors before overload resolution. - */ -#if 0 - sc->protection = protection; -#else - sc->protection = PROTpublic; -#endif - for (size_t i = 0; i < aliasdecls.dim; i++) - { Dsymbol *s = aliasdecls.tdata()[i]; - - //printf("\tImport alias semantic('%s')\n", s->toChars()); - if (!mod->search(loc, names.tdata()[i], 0)) - error("%s not found", (names.tdata()[i])->toChars()); - - s->semantic(sc); - } - sc = sc->pop(); - } - - if (global.params.moduleDeps != NULL) - { - /* The grammar of the file is: - * ImportDeclaration - * ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> " - * ModuleAliasIdentifier ] "\n" - * - * BasicImportDeclaration - * ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection - * " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")" - * - * FilePath - * - any string with '(', ')' and '\' escaped with the '\' character - */ - - OutBuffer *ob = global.params.moduleDeps; - - ob->writestring(sc->module->toPrettyChars()); - ob->writestring(" ("); - escapePath(ob, sc->module->srcfile->toChars()); - ob->writestring(") : "); - - ProtDeclaration::protectionToCBuffer(ob, sc->protection); - if (isstatic) - StorageClassDeclaration::stcToCBuffer(ob, STCstatic); - ob->writestring(": "); - - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { - Identifier *pid = packages->tdata()[i]; - ob->printf("%s.", pid->toChars()); - } - } - - ob->writestring(id->toChars()); - ob->writestring(" ("); - if (mod) - escapePath(ob, mod->srcfile->toChars()); - else - ob->writestring("???"); - ob->writebyte(')'); - - for (size_t i = 0; i < names.dim; i++) - { - if (i == 0) - ob->writebyte(':'); - else - ob->writebyte(','); - - Identifier *name = names.tdata()[i]; - Identifier *alias = aliases.tdata()[i]; - - if (!alias) - { - ob->printf("%s", name->toChars()); - alias = name; - } - else - ob->printf("%s=%s", alias->toChars(), name->toChars()); - } - - if (aliasId) - ob->printf(" -> %s", aliasId->toChars()); - - ob->writenl(); - } - - //printf("-Import::semantic('%s'), pkg = %p\n", toChars(), pkg); -} - -void Import::semantic2(Scope *sc) -{ - //printf("Import::semantic2('%s')\n", toChars()); - mod->semantic2(); - if (mod->needmoduleinfo) - { //printf("module5 %s because of %s\n", sc->module->toChars(), mod->toChars()); - sc->module->needmoduleinfo = 1; - } -} - -Dsymbol *Import::toAlias() -{ - if (aliasId) - return mod; - return this; -} - -/***************************** - * Add import to sd's symbol table. - */ - -int Import::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - int result = 0; - - if (names.dim == 0) - return Dsymbol::addMember(sc, sd, memnum); - - if (aliasId) - result = Dsymbol::addMember(sc, sd, memnum); - - /* Instead of adding the import to sd's symbol table, - * add each of the alias=name pairs - */ - for (size_t i = 0; i < names.dim; i++) - { - Identifier *name = names.tdata()[i]; - Identifier *alias = aliases.tdata()[i]; - - if (!alias) - alias = name; - - TypeIdentifier *tname = new TypeIdentifier(loc, name); - AliasDeclaration *ad = new AliasDeclaration(loc, alias, tname); - result |= ad->addMember(sc, sd, memnum); - - aliasdecls.push(ad); - } - - return result; -} - -Dsymbol *Import::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.Import::search(ident = '%s', flags = x%x)\n", toChars(), ident->toChars(), flags); - - if (!pkg) - { load(NULL); - mod->semantic(); - } - - // Forward it to the package/module - return pkg->search(loc, ident, flags); -} - -int Import::overloadInsert(Dsymbol *s) -{ - // Allow multiple imports of the same name - return s->isImport() != NULL; -} - -void Import::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (hgs->hdrgen && id == Id::object) - return; // object is imported by default - - if (isstatic) - buf->writestring("static "); - buf->writestring("import "); - if (aliasId) - { - buf->printf("%s = ", aliasId->toChars()); - } - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; - - buf->printf("%s.", pid->toChars()); - } - } - buf->printf("%s;", id->toChars()); - buf->writenl(); -} - diff --git a/dmd2/import.h b/dmd2/import.h deleted file mode 100644 index a3ef1a55..00000000 --- a/dmd2/import.h +++ /dev/null @@ -1,66 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_IMPORT_H -#define DMD_IMPORT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - - -struct Identifier; -struct Scope; -struct OutBuffer; -struct Module; -struct Package; -struct AliasDeclaration; -struct HdrGenState; - -struct Import : Dsymbol -{ - Identifiers *packages; // array of Identifier's representing packages - Identifier *id; // module Identifier - Identifier *aliasId; - int isstatic; // !=0 if static import - enum PROT protection; - - // Pairs of alias=name to bind into current namespace - Identifiers names; - Identifiers aliases; - - AliasDeclarations aliasdecls; // AliasDeclarations for names/aliases - - Module *mod; - Package *pkg; // leftmost package/module - - Import(Loc loc, Identifiers *packages, Identifier *id, Identifier *aliasId, - int isstatic); - void addAlias(Identifier *name, Identifier *alias); - - const char *kind(); - enum PROT prot(); - Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees - void load(Scope *sc); - void importAll(Scope *sc); - void semantic(Scope *sc); - void semantic2(Scope *sc); - Dsymbol *toAlias(); - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Import *isImport() { return this; } -}; - -#endif /* DMD_IMPORT_H */ diff --git a/dmd2/inifile.c b/dmd2/inifile.c deleted file mode 100644 index 1bed9fe7..00000000 --- a/dmd2/inifile.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Some portions copyright (c) 1994-1995 by Symantec - * Copyright (c) 1999-2011 by Digital Mars - * All Rights Reserved - * http://www.digitalmars.com - * Written by Walter Bright - * - * This source file is made available for personal use - * only. The license is in /dmd/src/dmd/backendlicense.txt - * For any other uses, please contact Digital Mars. - */ - -#include -#include -#include -#include - -#if _WIN32 -#include -#endif - -#if __APPLE__ -#include -#endif -#if __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 -// for PATH_MAX -#include -#endif - -#if __sun&&__SVR4 -#include -#endif - -#include "root.h" -#include "rmem.h" - -#define LOG 0 - -char *skipspace(const char *p); - -#if __GNUC__ -char *strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} -#endif /* unix */ - -/***************************** - * Read and analyze .ini file. - * Input: - * argv0 program name (argv[0]) - * inifile .ini file name - * Returns: - * file name of ini file - * Note: this is a memory leak - */ - -const char *inifile(const char *argv0x, const char *inifilex) -{ - char *argv0 = (char *)argv0x; - char *inifile = (char *)inifilex; // do const-correct later - char *path; // need path for @P macro - char *filename; - OutBuffer buf; - int envsection = 0; - -#if LOG - printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile); -#endif - if (FileName::absolute(inifile)) - { - filename = inifile; - } - else - { - /* Look for inifile in the following sequence of places: - * o current directory - * o home directory - * o directory off of argv0 - * o /etc/ - */ - if (FileName::exists(inifile)) - { - filename = inifile; - } - else - { - filename = FileName::combine(getenv("HOME"), inifile); - if (!FileName::exists(filename)) - { -#if _WIN32 // This fix by Tim Matthews - char resolved_name[MAX_PATH + 1]; - if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name)) - { - filename = (char *)FileName::replaceName(resolved_name, inifile); - if(FileName::exists(filename)) - goto Ldone; - } -#endif - filename = (char *)FileName::replaceName(argv0, inifile); - if (!FileName::exists(filename)) - { -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 -#if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 // This fix by Thomas Kuehne - /* argv0 might be a symbolic link, - * so try again looking past it to the real path - */ -#if __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - char resolved_name[PATH_MAX + 1]; - char* real_argv0 = realpath(argv0, resolved_name); -#else - char* real_argv0 = realpath(argv0, NULL); -#endif - //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0); - if (real_argv0) - { - filename = (char *)FileName::replaceName(real_argv0, inifile); -#if !(__APPLE__ || __FreeBSD__ || __sun&&__SVR4) - free(real_argv0); -#endif - if (FileName::exists(filename)) - goto Ldone; - } -#else -#error use of glibc non-standard extension realpath(char*, NULL) -#endif - if (1){ - // Search PATH for argv0 - const char *p = getenv("PATH"); - Strings *paths = FileName::splitPath(p); - filename = FileName::searchPath(paths, argv0, 0); - if (!filename) - goto Letc; // argv0 not found on path - filename = (char *)FileName::replaceName(filename, inifile); - if (FileName::exists(filename)) - goto Ldone; - } - // Search /etc/ for inifile - Letc: -#endif - filename = FileName::combine((char *)"/etc/", inifile); - - Ldone: - ; - } - } - } - } - path = FileName::path(filename); -#if LOG - printf("\tpath = '%s', filename = '%s'\n", path, filename); -#endif - - File file(filename); - - if (file.read()) - return filename; // error reading file - - // Parse into lines - int eof = 0; - for (size_t i = 0; i < file.len && !eof; i++) - { - size_t linestart = i; - - for (; i < file.len; i++) - { - switch (file.buffer[i]) - { - case '\r': - break; - - case '\n': - // Skip if it was preceded by '\r' - if (i && file.buffer[i - 1] == '\r') - goto Lskip; - break; - - case 0: - case 0x1A: - eof = 1; - break; - - default: - continue; - } - break; - } - - // The line is file.buffer[linestart..i] - char *line; - size_t len; - char *p; - char *pn; - - line = (char *)&file.buffer[linestart]; - len = i - linestart; - - buf.reset(); - - // First, expand the macros. - // Macros are bracketed by % characters. - - for (size_t k = 0; k < len; k++) - { - if (line[k] == '%') - { - for (size_t j = k + 1; j < len; j++) - { - if (line[j] == '%') - { - if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0) - { - // %@P% is special meaning the path to the .ini file - p = path; - if (!*p) - p = (char *)"."; - } - else - { size_t len2 = j - k; - char tmp[10]; // big enough most of the time - - if (len2 <= sizeof(tmp)) - p = tmp; - else - p = (char *)alloca(len2); - len2--; - memcpy(p, &line[k + 1], len2); - p[len2] = 0; - strupr(p); - p = getenv(p); - if (!p) - p = (char *)""; - } - buf.writestring(p); - k = j; - goto L1; - } - } - } - buf.writeByte(line[k]); - L1: - ; - } - - // Remove trailing spaces - while (buf.offset && isspace(buf.data[buf.offset - 1])) - buf.offset--; - - p = buf.toChars(); - - // The expanded line is in p. - // Now parse it for meaning. - - p = skipspace(p); - switch (*p) - { - case ';': // comment - case 0: // blank - break; - - case '[': // look for [Environment] - p = skipspace(p + 1); - for (pn = p; isalnum((unsigned char)*pn); pn++) - ; - if (pn - p == 11 && - memicmp(p, "Environment", 11) == 0 && - *skipspace(pn) == ']' - ) - envsection = 1; - else - envsection = 0; - break; - - default: - if (envsection) - { - pn = p; - - // Convert name to upper case; - // remove spaces bracketing = - for (p = pn; *p; p++) - { if (islower((unsigned char)*p)) - *p &= ~0x20; - else if (isspace((unsigned char)*p)) - memmove(p, p + 1, strlen(p)); - else if (*p == '=') - { - p++; - while (isspace((unsigned char)*p)) - memmove(p, p + 1, strlen(p)); - break; - } - } - - putenv(strdup(pn)); -#if LOG - printf("\tputenv('%s')\n", pn); - //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST")); -#endif - } - break; - } - - Lskip: - ; - } - return filename; -} - -/******************** - * Skip spaces. - */ - -char *skipspace(const char *p) -{ - while (isspace((unsigned char)*p)) - p++; - return (char *)p; -} - diff --git a/dmd2/init.c b/dmd2/init.c deleted file mode 100644 index 4d9806c6..00000000 --- a/dmd2/init.c +++ /dev/null @@ -1,911 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "statement.h" -#include "identifier.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "hdrgen.h" - -/********************************** Initializer *******************************/ - -Initializer::Initializer(Loc loc) -{ - this->loc = loc; -} - -Initializer *Initializer::syntaxCopy() -{ - return this; -} - -Initializer *Initializer::semantic(Scope *sc, Type *t, int needInterpret) -{ - 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 (size_t i = 0; i < a->dim; i++) - { Initializer *e = ai->tdata()[i]; - - e = e->syntaxCopy(); - a->tdata()[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, int needInterpret) -{ - //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; -#if IN_LLVM - ltype = NULL; -#endif -} - -Initializer *StructInitializer::syntaxCopy() -{ - StructInitializer *ai = new StructInitializer(loc); - - assert(field.dim == value.dim); - ai->field.setDim(field.dim); - ai->value.setDim(value.dim); - for (size_t i = 0; i < field.dim; i++) - { - ai->field.tdata()[i] = field.tdata()[i]; - - Initializer *init = value.tdata()[i]; - init = init->syntaxCopy(); - ai->value.tdata()[i] = init; - } - return ai; -} - -void StructInitializer::addInit(Identifier *field, Initializer *value) -{ - //printf("StructInitializer::addInit(field = %p, value = %p)\n", field, value); - this->field.push(field); - this->value.push(value); -} - -Initializer *StructInitializer::semantic(Scope *sc, Type *t, int needInterpret) -{ - int errors = 0; - - //printf("StructInitializer::semantic(t = %s) %s\n", t->toChars(), toChars()); - vars.setDim(field.dim); - t = t->toBasetype(); - if (t->ty == Tstruct) - { - unsigned fieldi = 0; - - TypeStruct *ts = (TypeStruct *)t; - ad = ts->sym; - if (ad->ctor) - error(loc, "%s %s has constructors, cannot use { initializers }, use %s( initializers ) instead", - ad->kind(), ad->toChars(), ad->toChars()); - size_t nfields = ad->fields.dim; - if (((StructDeclaration *)ad)->isnested) nfields--; - for (size_t i = 0; i < field.dim; i++) - { - Identifier *id = field.tdata()[i]; - Initializer *val = value.tdata()[i]; - Dsymbol *s; - VarDeclaration *v; - - if (id == NULL) - { - if (fieldi >= nfields) - { error(loc, "too many initializers for %s", ad->toChars()); - errors = 1; - field.remove(i); - i--; - continue; - } - else - { - s = ad->fields.tdata()[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()); - errors = 1; - continue; - } - s = s->toAlias(); - - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - error(loc, "%s.%s is not a per-instance initializable field", - t->toChars(), s->toChars()); - errors = 1; - break; - } - if (s == ad->fields.tdata()[fieldi]) - break; - } - } - if (s && (v = s->isVarDeclaration()) != NULL) - { - val = val->semantic(sc, v->type, needInterpret); - value.tdata()[i] = val; - vars.tdata()[i] = v; - } - else - { error(loc, "%s is not a field of %s", id ? id->toChars() : s->toChars(), ad->toChars()); - errors = 1; - } - fieldi++; - } - } - else if (t->ty == Tdelegate && value.dim == 0) - { /* Rewrite as empty delegate literal { } - */ - Parameters *arguments = new Parameters; - Type *tf = new TypeFunction(arguments, NULL, 0, LINKd); - FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, TOKdelegate, NULL); - fd->fbody = new CompoundStatement(loc, new Statements()); - fd->endloc = loc; - Expression *e = new FuncExp(loc, fd); - ExpInitializer *ie = new ExpInitializer(loc, e); - return ie->semantic(sc, t, needInterpret); - } - 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; - size_t offset; - - //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(); - size_t nfields = ad->fields.dim; -#if DMDV2 - if (sd->isnested) - nfields--; -#endif - elements->setDim(nfields); - for (size_t i = 0; i < elements->dim; i++) - { - elements->tdata()[i] = NULL; - } - unsigned fieldi = 0; - for (size_t i = 0; i < value.dim; i++) - { - Identifier *id = field.tdata()[i]; - if (id) - { - Dsymbol * s = ad->search(loc, id, 0); - if (!s) - { - error(loc, "'%s' is not a member of '%s'", id->toChars(), sd->toChars()); - goto Lno; - } - s = s->toAlias(); - - // Find out which field index it is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - s->error("is not a per-instance initializable field"); - goto Lno; - } - if (s == ad->fields.tdata()[fieldi]) - break; - } - } - else if (fieldi >= nfields) - { error(loc, "too many initializers for '%s'", ad->toChars()); - goto Lno; - } - Initializer *iz = value.tdata()[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - goto Lno; - if (elements->tdata()[fieldi]) - { error(loc, "duplicate initializer for field '%s'", - ad->fields.tdata()[fieldi]->toChars()); - goto Lno; - } - elements->tdata()[fieldi] = ex; - ++fieldi; - } - // Now, fill in any missing elements with default initializers. - // We also need to validate any anonymous unions - offset = 0; - for (size_t i = 0; i < elements->dim; ) - { - VarDeclaration * vd = ad->fields.tdata()[i]->isVarDeclaration(); - - //printf("test2 [%d] : %s %d %d\n", i, vd->toChars(), (int)offset, (int)vd->offset); - if (vd->offset < offset) - { - // Only the first field of a union can have an initializer - if (elements->tdata()[i]) - goto Lno; - } - else - { - if (!elements->tdata()[i]) - // Default initialize - elements->tdata()[i] = vd->type->defaultInit(); - } - offset = vd->offset + vd->type->size(); - i++; -#if 0 - int unionSize = ad->numFieldsInUnion(i); - if (unionSize == 1) - { // Not a union -- default initialize if missing - if (!elements->tdata()[i]) - elements->tdata()[i] = vd->type->defaultInit(); - } - else - { // anonymous union -- check for errors - int found = -1; // index of the first field with an initializer - for (int j = i; j < i + unionSize; ++j) - { - if (!elements->tdata()[j]) - continue; - if (found >= 0) - { - VarDeclaration * v1 = ((Dsymbol *)ad->fields.data[found])->isVarDeclaration(); - VarDeclaration * v = ((Dsymbol *)ad->fields.data[j])->isVarDeclaration(); - error(loc, "%s cannot have initializers for fields %s and %s in same union", - ad->toChars(), - v1->toChars(), v->toChars()); - goto Lno; - } - found = j; - } - if (found == -1) - { - error(loc, "no initializer for union that contains field %s", - vd->toChars()); - goto Lno; - } - } - i += unionSize; -#endif - } - e = new StructLiteralExp(loc, sd, elements); - e->type = sd->type; - return e; - -Lno: - delete elements; - return NULL; -} - - -void StructInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - //printf("StructInitializer::toCBuffer()\n"); - buf->writebyte('{'); - for (size_t i = 0; i < field.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Identifier *id = field.tdata()[i]; - if (id) - { - buf->writestring(id->toChars()); - buf->writebyte(':'); - } - Initializer *iz = value.tdata()[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 (size_t i = 0; i < ai->value.dim; i++) - { Expression *e = index.tdata()[i]; - if (e) - e = e->syntaxCopy(); - ai->index.tdata()[i] = e; - - Initializer *init = value.tdata()[i]; - init = init->syntaxCopy(); - ai->value.tdata()[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, int needInterpret) -{ unsigned i; - unsigned length; - const unsigned amax = 0x80000000; - - //printf("ArrayInitializer::semantic(%s)\n", t->toChars()); - if (sem) // if semantic() already run - return this; - sem = 1; - type = t; - t = t->toBasetype(); - switch (t->ty) - { - case Tpointer: - case Tsarray: - case Tarray: - break; - - default: - error(loc, "cannot use array to initialize %s", type->toChars()); - goto Lerr; - } - - length = 0; - for (i = 0; i < index.dim; i++) - { - Expression *idx = index.tdata()[i]; - if (idx) - { idx = idx->semantic(sc); - idx = idx->optimize(WANTvalue | WANTinterpret); - index.tdata()[i] = idx; - length = idx->toInteger(); - } - - Initializer *val = value.tdata()[i]; - val = val->semantic(sc, t->nextOf(), needInterpret); - value.tdata()[i] = val; - length++; - if (length == 0) - { error(loc, "array dimension overflow"); - goto Lerr; - } - if (length > dim) - dim = length; - } - if (t->ty == Tsarray) - { - dinteger_t edim = ((TypeSArray *)t)->dim->toInteger(); - if (dim > edim) - { - error(loc, "array initializer has %u elements, but array length is %jd", dim, edim); - goto Lerr; - } - } - - if ((unsigned long) dim * t->nextOf()->size() >= amax) - { error(loc, "array dimension %u exceeds max of %u", dim, amax / t->nextOf()->size()); - goto Lerr; - } - return this; - -Lerr: - return new ExpInitializer(loc, new ErrorExp()); -} - -/******************************** - * If possible, convert array initializer to array literal. - * Otherwise return NULL. - */ - -Expression *ArrayInitializer::toExpression() -{ Expressions *elements; - - //printf("ArrayInitializer::toExpression(), dim = %d\n", dim); - //static int i; if (++i == 2) halt(); - - size_t edim; - Type *t = NULL; - if (type) - { - if (type == Type::terror) - return new ErrorExp(); - - t = type->toBasetype(); - switch (t->ty) - { - case Tsarray: - edim = ((TypeSArray *)t)->dim->toInteger(); - break; - - case Tpointer: - case Tarray: - edim = dim; - break; - - default: - assert(0); - } - } - else - { - edim = value.dim; - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index.tdata()[i]) - j = index.tdata()[i]->toInteger(); - if (j >= edim) - edim = j + 1; - } - } - - elements = new Expressions(); - elements->setDim(edim); - elements->zero(); - for (size_t i = 0, j = 0; i < value.dim; i++, j++) - { - if (index.tdata()[i]) - j = (index.tdata()[i])->toInteger(); - assert(j < edim); - Initializer *iz = value.tdata()[i]; - if (!iz) - goto Lno; - Expression *ex = iz->toExpression(); - if (!ex) - { - goto Lno; - } - elements->tdata()[j] = ex; - } - - /* Fill in any missing elements with the default initializer - */ - { - Expression *init = NULL; - for (size_t i = 0; i < edim; i++) - { - if (!elements->tdata()[i]) - { - if (!type) - goto Lno; - if (!init) - init = ((TypeNext *)t)->next->defaultInit(); - elements->tdata()[i] = init; - } - } - - Expression *e = new ArrayLiteralExp(loc, elements); - e->type = type; - return e; - } - -Lno: - return NULL; -} - - -/******************************** - * If possible, convert array initializer to associative array initializer. - */ - -Expression *ArrayInitializer::toAssocArrayLiteral() -{ - Expression *e; - - //printf("ArrayInitializer::toAssocArrayInitializer()\n"); - //static int i; if (++i == 2) halt(); - Expressions *keys = new Expressions(); - keys->setDim(value.dim); - Expressions *values = new Expressions(); - values->setDim(value.dim); - - for (size_t i = 0; i < value.dim; i++) - { - e = index.tdata()[i]; - if (!e) - goto Lno; - keys->tdata()[i] = e; - - Initializer *iz = value.tdata()[i]; - if (!iz) - goto Lno; - e = iz->toExpression(); - if (!e) - goto Lno; - values->tdata()[i] = e; - } - e = new AssocArrayLiteralExp(loc, keys, values); - return e; - -Lno: - delete keys; - delete values; - error(loc, "not an associative array initializer"); - return new ErrorExp(); -} - -int ArrayInitializer::isAssociativeArray() -{ - for (size_t i = 0; i < value.dim; i++) - { - if (index.tdata()[i]) - return 1; - } - return 0; -} - -Type *ArrayInitializer::inferType(Scope *sc) -{ - //printf("ArrayInitializer::inferType() %s\n", toChars()); - assert(0); - return NULL; -#if 0 - type = Type::terror; - for (size_t i = 0; i < value.dim; i++) - { - if (index.data[i]) - goto Laa; - } - for (size_t i = 0; i < value.dim; i++) - { - Initializer *iz = (Initializer *)value.data[i]; - if (iz) - { Type *t = iz->inferType(sc); - if (i == 0) - { /* BUG: This gets the type from the first element. - * Fix to use all the elements to figure out the type. - */ - t = new TypeSArray(t, new IntegerExp(value.dim)); - t = t->semantic(loc, sc); - type = t; - } - } - } - return type; - -Laa: - /* It's possibly an associative array initializer. - * BUG: inferring type from first member. - */ - Initializer *iz = (Initializer *)value.data[0]; - Expression *indexinit = (Expression *)index.data[0]; - if (iz && indexinit) - { Type *t = iz->inferType(sc); - indexinit = indexinit->semantic(sc); - Type *indext = indexinit->type; - t = new TypeAArray(t, indext); - type = t->semantic(loc, sc); - } - else - error(loc, "cannot infer type from this array initializer"); - return type; -#endif -} - - -void ArrayInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writebyte('['); - for (size_t i = 0; i < index.dim; i++) - { - if (i > 0) - buf->writebyte(','); - Expression *ex = index.tdata()[i]; - if (ex) - { - ex->toCBuffer(buf, hgs); - buf->writebyte(':'); - } - Initializer *iz = value.tdata()[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()); -} - -bool arrayHasNonConstPointers(Expressions *elems); - -bool hasNonConstPointers(Expression *e) -{ - if (e->op == TOKnull) - return false; - if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - return arrayHasNonConstPointers(se->elements); - } - if (e->op == TOKarrayliteral) - { - if (!e->type->nextOf()->hasPointers()) - return false; - ArrayLiteralExp *ae = (ArrayLiteralExp *)e; - return arrayHasNonConstPointers(ae->elements); - } - if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)e; - if (ae->type->nextOf()->hasPointers() && - arrayHasNonConstPointers(ae->values)) - return true; - if (((TypeAArray *)ae->type)->index->hasPointers()) - return arrayHasNonConstPointers(ae->keys); - return false; - } - if (e->type->ty== Tpointer && e->type->nextOf()->ty != Tfunction) - { -#if IN_LLVM - // address of a global is OK - if (e->op == TOKaddress || e->op == TOKcast) - return false; - if (e->op == TOKadd || e->op == TOKmin) { - BinExp *be = (BinExp*)e; - if (be->e1->type->ty == Tpointer || be->e2->type->ty == Tpointer) - return false; - } -#else - if (e->op == TOKsymoff) // address of a global is OK - return false; -#endif - if (e->op == TOKint64) // cast(void *)int is OK - return false; - if (e->op == TOKstring) // "abc".ptr is OK - return false; - return true; - } - return false; -} - -bool arrayHasNonConstPointers(Expressions *elems) -{ - for (size_t i = 0; i < elems->dim; i++) - { - if (!elems->tdata()[i]) - continue; - if (hasNonConstPointers(elems->tdata()[i])) - return true; - } - return false; -} - - - -Initializer *ExpInitializer::semantic(Scope *sc, Type *t, int needInterpret) -{ - //printf("ExpInitializer::semantic(%s), type = %s\n", exp->toChars(), t->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - int wantOptimize = needInterpret ? WANTinterpret|WANTvalue : WANTvalue; - - int olderrors = global.errors; - exp = exp->optimize(wantOptimize); - if (!global.gag && olderrors != global.errors) - return this; // Failed, suppress duplicate error messages - - if (exp->op == TOKtype) - error("initializer must be an expression, not '%s'", exp->toChars()); - - // Make sure all pointers are constants - if (needInterpret && hasNonConstPointers(exp)) - { - exp->error("cannot use non-constant CTFE pointer in an initializer '%s'", exp->toChars()); - return this; - } - - Type *tb = t->toBasetype(); - - /* Look for case of initializing a static array with a too-short - * string literal, such as: - * char[5] foo = "abc"; - * Allow this by doing an explicit cast, which will lengthen the string - * literal. - */ - if (exp->op == TOKstring && tb->ty == Tsarray && exp->type->ty == Tsarray) - { StringExp *se = (StringExp *)exp; - - if (!se->committed && se->type->ty == Tsarray && - ((TypeSArray *)se->type)->dim->toInteger() < - ((TypeSArray *)t)->dim->toInteger()) - { - exp = se->castTo(sc, t); - goto L1; - } - } - - // Look for the case of statically initializing an array - // with a single member. - if (tb->ty == Tsarray && - !tb->nextOf()->equals(exp->type->toBasetype()->nextOf()) && - exp->implicitConvTo(tb->nextOf()) - ) - { - t = tb->nextOf(); - } - - exp = exp->implicitCastTo(sc, t); -L1: - exp = exp->optimize(wantOptimize); - //printf("-ExpInitializer::semantic(): "); exp->print(); - return this; -} - -Type *ExpInitializer::inferType(Scope *sc) -{ - //printf("ExpInitializer::inferType() %s\n", toChars()); - if (exp->op == TOKfunction && ((FuncExp *)exp)->td) - { - exp->error("cannot infer type from ambiguous function literal %s", exp->toChars()); - return Type::terror; - } - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - - // Give error for overloaded function addresses - if (exp->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)exp; - if (se->hasOverloads && !se->var->isFuncDeclaration()->isUnique()) - exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); - } - - // Give error for overloaded function addresses - if (exp->op == TOKdelegate) - { DelegateExp *se = (DelegateExp *)exp; - if ( - se->func->isFuncDeclaration() && - !se->func->isFuncDeclaration()->isUnique()) - exp->error("cannot infer type from overloaded function symbol %s", exp->toChars()); - } - - Type *t = exp->type; - if (!t) - t = Initializer::inferType(sc); - return t; -} - -Expression *ExpInitializer::toExpression() -{ - return exp; -} - - -void ExpInitializer::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - exp->toCBuffer(buf, hgs); -} - - - diff --git a/dmd2/init.h b/dmd2/init.h deleted file mode 100644 index d038dd9e..00000000 --- a/dmd2/init.h +++ /dev/null @@ -1,149 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2007 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef INIT_H -#define INIT_H - -#include "root.h" - -#include "mars.h" -#include "arraytypes.h" - -struct Identifier; -struct Expression; -struct Scope; -struct Type; -struct dt_t; -struct AggregateDeclaration; -struct VoidInitializer; -struct StructInitializer; -struct ArrayInitializer; -struct ExpInitializer; -struct HdrGenState; - -#if IN_LLVM -namespace llvm { - class StructType; -} -#endif - - -struct Initializer : Object -{ - Loc loc; - - Initializer(Loc loc); - virtual Initializer *syntaxCopy(); - // needInterpret is WANTinterpret if must be a manifest constant, 0 if not. - virtual Initializer *semantic(Scope *sc, Type *t, int needInterpret); - virtual Type *inferType(Scope *sc); - virtual Expression *toExpression() = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - char *toChars(); - - static Initializers *arraySyntaxCopy(Initializers *ai); - -#if IN_DMD - virtual dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return NULL; } - virtual StructInitializer *isStructInitializer() { return NULL; } - virtual ArrayInitializer *isArrayInitializer() { return NULL; } - virtual ExpInitializer *isExpInitializer() { return NULL; } -}; - -struct VoidInitializer : Initializer -{ - Type *type; // type that this will initialize to - - VoidInitializer(Loc loc); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual VoidInitializer *isVoidInitializer() { return this; } -}; - -struct StructInitializer : Initializer -{ - Identifiers field; // of Identifier *'s - Initializers value; // parallel array of Initializer *'s - - VarDeclarations vars; // parallel array of VarDeclaration *'s - AggregateDeclaration *ad; // which aggregate this is for - - StructInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Identifier *field, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - StructInitializer *isStructInitializer() { return this; } -#if IN_LLVM - llvm::StructType *ltype; -#endif -}; - -struct ArrayInitializer : Initializer -{ - Expressions index; // indices - Initializers value; // of Initializer *'s - unsigned dim; // length of array being initialized - Type *type; // type that array will be used to initialize - int sem; // !=0 if semantic() is run - - ArrayInitializer(Loc loc); - Initializer *syntaxCopy(); - void addInit(Expression *index, Initializer *value); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); - int isAssociativeArray(); - Type *inferType(Scope *sc); - Expression *toExpression(); - Expression *toAssocArrayLiteral(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); - dt_t *toDtBit(); // for bit arrays -#endif - - ArrayInitializer *isArrayInitializer() { return this; } -}; - -struct ExpInitializer : Initializer -{ - Expression *exp; - - ExpInitializer(Loc loc, Expression *exp); - Initializer *syntaxCopy(); - Initializer *semantic(Scope *sc, Type *t, int needInterpret); - Type *inferType(Scope *sc); - Expression *toExpression(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - dt_t *toDt(); -#endif - - virtual ExpInitializer *isExpInitializer() { return this; } -}; - -#endif diff --git a/dmd2/inline.c b/dmd2/inline.c deleted file mode 100644 index 052dc343..00000000 --- a/dmd2/inline.c +++ /dev/null @@ -1,1831 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Routines to perform function inlining - -#define LOG 0 - -#include -#include -#include - -#include "id.h" -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "expression.h" -#include "statement.h" -#include "mtype.h" -#include "scope.h" - -/* ========== Compute cost of inlining =============== */ - -/* Walk trees to determine if inlining can be done, and if so, - * if it is too complex to be worth inlining or not. - */ - -struct InlineCostState -{ - int nested; - int hasthis; - int hdrscan; // !=0 if inline scan for 'header' content - FuncDeclaration *fd; -}; - -const int COST_MAX = 250; -const int STATEMENT_COST = 0x1000; -const int STATEMENT_COST_MAX = 250 * 0x1000; - -// STATEMENT_COST be power of 2 and greater than COST_MAX -//static assert((STATEMENT_COST & (STATEMENT_COST - 1)) == 0); -//static assert(STATEMENT_COST > COST_MAX); - -bool tooCostly(int cost) { return ((cost & (STATEMENT_COST - 1)) >= COST_MAX); } - -int expressionInlineCost(Expression *e, InlineCostState *ics); - -int Statement::inlineCost(InlineCostState *ics) -{ - //printf("Statement::inlineCost = %d\n", COST_MAX); - //printf("%p\n", isScopeStatement()); - //printf("%s\n", toChars()); - return COST_MAX; // default is we can't inline it -} - -int ExpStatement::inlineCost(InlineCostState *ics) -{ - return expressionInlineCost(exp, ics); - //return exp ? exp->inlineCost(ics) : 0; -} - -int CompoundStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - cost += s->inlineCost(ics); - if (tooCostly(cost)) - break; - } - } - //printf("CompoundStatement::inlineCost = %d\n", cost); - return cost; -} - -int UnrolledLoopStatement::inlineCost(InlineCostState *ics) -{ int cost = 0; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - cost += s->inlineCost(ics); - if (tooCostly(cost)) - break; - } - } - return cost; -} - -int ScopeStatement::inlineCost(InlineCostState *ics) -{ - return statement ? 1 + statement->inlineCost(ics) : 1; -} - -int IfStatement::inlineCost(InlineCostState *ics) -{ - int cost; - -#if !IN_LLVM - /* Can't declare variables inside ?: expressions, so - * we cannot inline if a variable is declared. - */ - if (arg) - return COST_MAX; -#endif - - cost = expressionInlineCost(condition, ics); - -#if !IN_LLVM - /* Specifically allow: - * if (condition) - * return exp1; - * else - * return exp2; - * Otherwise, we can't handle return statements nested in if's. - */ - - if (elsebody && ifbody && - ifbody->isReturnStatement() && - elsebody->isReturnStatement()) - { - cost += ifbody->inlineCost(ics); - cost += elsebody->inlineCost(ics); - //printf("cost = %d\n", cost); - } - else -#endif - { - ics->nested += 1; - if (ifbody) - cost += ifbody->inlineCost(ics); - if (elsebody) - cost += elsebody->inlineCost(ics); - ics->nested -= 1; - } - //printf("IfStatement::inlineCost = %d\n", cost); - return cost; -} - -int ReturnStatement::inlineCost(InlineCostState *ics) -{ -#if !IN_LLVM - // Can't handle return statements nested in if's - if (ics->nested) - return COST_MAX; -#endif - return expressionInlineCost(exp, ics); -} - -#if DMDV2 -int ImportStatement::inlineCost(InlineCostState *ics) -{ - return 0; -} -#endif - -int ForStatement::inlineCost(InlineCostState *ics) -{ - //return COST_MAX; - int cost = STATEMENT_COST; - if (init) - cost += init->inlineCost(ics); - if (condition) - cost += expressionInlineCost(condition, ics); - if (increment) - cost += expressionInlineCost(increment, ics); - if (body) - cost += body->inlineCost(ics); - //printf("ForStatement: inlineCost = %d\n", cost); - return cost; -} - - -/* -------------------------- */ - -struct ICS2 -{ - int cost; - InlineCostState *ics; -}; - -int lambdaInlineCost(Expression *e, void *param) -{ - ICS2 *ics2 = (ICS2 *)param; - ics2->cost += e->inlineCost3(ics2->ics); - return (ics2->cost >= COST_MAX); -} - -int expressionInlineCost(Expression *e, InlineCostState *ics) -{ - //printf("expressionInlineCost()\n"); - //e->dump(0); - ICS2 ics2; - ics2.cost = 0; - ics2.ics = ics; - if (e) - e->apply(&lambdaInlineCost, &ics2); - return ics2.cost; -} - -int Expression::inlineCost3(InlineCostState *ics) -{ - return 1; -} - -int VarExp::inlineCost3(InlineCostState *ics) -{ - //printf("VarExp::inlineCost3() %s\n", toChars()); - Type *tb = type->toBasetype(); - if (tb->ty == Tstruct) - { - StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->isnested) - /* An inner struct will be nested inside another function hierarchy than where - * we're inlining into, so don't inline it. - * At least not until we figure out how to 'move' the struct to be nested - * locally. Example: - * struct S(alias pred) { void unused_func(); } - * void abc() { int w; S!(w) m; } - * void bar() { abc(); } - */ - return COST_MAX; - } - FuncDeclaration *fd = var->isFuncDeclaration(); - if (fd && fd->isNested()) // see Bugzilla 7199 for test case - return COST_MAX; - return 1; -} - -int ThisExp::inlineCost3(InlineCostState *ics) -{ -#if !IN_LLVM - //printf("ThisExp::inlineCost3() %s\n", toChars()); - FuncDeclaration *fd = ics->fd; - if (!fd) - return COST_MAX; - if (!ics->hdrscan) - if (fd->isNested() || !ics->hasthis) - return COST_MAX; -#endif - return 1; -} - -int StructLiteralExp::inlineCost3(InlineCostState *ics) -{ - //printf("StructLiteralExp::inlineCost3() %s\n", toChars()); -#if DMDV2 - if (sd->isnested) - return COST_MAX; -#endif - return 1; -} - -int FuncExp::inlineCost3(InlineCostState *ics) -{ - //printf("FuncExp::inlineCost3()\n"); - - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - // Right now, this makes the function be output to the .obj file twice. - return COST_MAX; -} - -int DelegateExp::inlineCost3(InlineCostState *ics) -{ - // This breaks on LDC too, since nested functions have internal linkage - // and thus can't be referenced from other objects. - //printf("DelegateExp::inlineCost3()\n"); - return COST_MAX; -} - -int DeclarationExp::inlineCost3(InlineCostState *ics) -{ int cost = 0; - VarDeclaration *vd; - - //printf("DeclarationExp::inlineCost3()\n"); - vd = declaration->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { -#if 1 - return COST_MAX; // finish DeclarationExp::doInline -#else - for (size_t i = 0; i < td->objects->dim; i++) - { Object *o = (*td->objects)[i]; - if (o->dyncast() != DYNCAST_EXPRESSION) - return COST_MAX; - Expression *eo = (Expression *)o; - if (eo->op != TOKdsymbol) - return COST_MAX; - } - return td->objects->dim; -#endif - } - // This breaks on LDC too, since nested static variables have internal - // linkage and thus can't be referenced from other objects. - if (!ics->hdrscan && vd->isDataseg()) - return COST_MAX; - cost += 1; - -#if DMDV2 - if (vd->edtor) // if destructor required - return COST_MAX; // needs work to make this work -#endif - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { - cost += expressionInlineCost(ie->exp, ics); - } - } - } - - // These can contain functions, which when copied, get output twice. - // These break on LDC too, since nested static variables and functions have - // internal linkage and thus can't be referenced from other objects. - if (declaration->isStructDeclaration() || - declaration->isClassDeclaration() || - declaration->isFuncDeclaration() || - declaration->isTypedefDeclaration() || -#if DMDV2 - declaration->isAttribDeclaration() || -#endif - declaration->isTemplateMixin()) - return COST_MAX; - - //printf("DeclarationExp::inlineCost3('%s')\n", toChars()); - return cost; -} - -int CallExp::inlineCost3(InlineCostState *ics) -{ - //printf("CallExp::inlineCost3() %s\n", toChars()); - // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner - // can't handle that at present. - if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper) - return COST_MAX; - - return 1; -} - - -/* ======================== Perform the inlining ============================== */ - -/* Inlining is done by: - * o Converting to an Expression - * o Copying the trees of the function to be inlined - * o Renaming the variables - */ - -struct InlineDoState -{ - VarDeclaration *vthis; - Dsymbols from; // old Dsymbols - Dsymbols to; // parallel array of new Dsymbols - Dsymbol *parent; // new parent - FuncDeclaration *fd; // function being inlined (old parent) -}; - -/* -------------------------------------------------------------------- */ - -Statement *Statement::doInlineStatement(InlineDoState *ids) -{ - assert(0); - return NULL; // default is we can't inline it -} - -Statement *ExpStatement::doInlineStatement(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInlineStatement() '%s'\n", exp->toChars()); -#endif - return new ExpStatement(loc, exp ? exp->doInline(ids) : NULL); -} - -Statement *CompoundStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("CompoundStatement::doInlineStatement() %d\n", statements->dim); - Statements *as = new Statements(); - as->reserve(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - as->push(s->doInlineStatement(ids)); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - } - else - as->push(NULL); - } - return new CompoundStatement(loc, as); -} - -Statement *UnrolledLoopStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("UnrolledLoopStatement::doInlineStatement() %d\n", statements->dim); - Statements *as = new Statements(); - as->reserve(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - as->push(s->doInlineStatement(ids)); - if (s->isReturnStatement()) - break; - } - else - as->push(NULL); - } - return new UnrolledLoopStatement(loc, as); -} - -Statement *ScopeStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ScopeStatement::doInlineStatement() %d\n", statements->dim); - return statement ? new ScopeStatement(loc, statement->doInlineStatement(ids)) : this; -} - -Statement *IfStatement::doInlineStatement(InlineDoState *ids) -{ - assert(!arg); - - Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; - Statement *ifbody = this->ifbody ? this->ifbody->doInlineStatement(ids) : NULL; - Statement *elsebody = this->elsebody ? this->elsebody->doInlineStatement(ids) : NULL; - - return new IfStatement(loc, arg, condition, ifbody, elsebody); -} - -Statement *ReturnStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ReturnStatement::doInlineStatement() '%s'\n", exp ? exp->toChars() : ""); - return new ReturnStatement(loc, exp ? exp->doInline(ids) : NULL); -} - -#if DMDV2 -Statement *ImportStatement::doInlineStatement(InlineDoState *ids) -{ - return NULL; -} -#endif - -Statement *ForStatement::doInlineStatement(InlineDoState *ids) -{ - //printf("ForStatement::doInlineStatement()\n"); - Statement *init = this->init ? this->init->doInlineStatement(ids) : NULL; - Expression *condition = this->condition ? this->condition->doInline(ids) : NULL; - Expression *increment = this->increment ? this->increment->doInline(ids) : NULL; - Statement *body = this->body ? this->body->doInlineStatement(ids) : NULL; - return new ForStatement(loc, init, condition, increment, body); -} - -/* -------------------------------------------------------------------- */ - -Expression *Statement::doInline(InlineDoState *ids) -{ - printf("Statement::doInline()\n%s\n", toChars()); - fflush(stdout); - assert(0); - return NULL; // default is we can't inline it -} - -Expression *ExpStatement::doInline(InlineDoState *ids) -{ -#if LOG - if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); -#endif - return exp ? exp->doInline(ids) : NULL; -} - -Expression *CompoundStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("CompoundStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - - /* Check for: - * if (condition) - * return exp1; - * else - * return exp2; - */ - IfStatement *ifs = s->isIfStatement(); - if (ifs && ifs->elsebody && ifs->ifbody && - ifs->ifbody->isReturnStatement() && - ifs->elsebody->isReturnStatement() - ) - break; - - } - } - return e; -} - -Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) -{ - Expression *e = NULL; - - //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - Expression *e2 = s->doInline(ids); - e = Expression::combine(e, e2); - if (s->isReturnStatement()) - break; - } - } - return e; -} - -Expression *ScopeStatement::doInline(InlineDoState *ids) -{ - return statement ? statement->doInline(ids) : NULL; -} - -Expression *IfStatement::doInline(InlineDoState *ids) -{ - Expression *econd; - Expression *e1; - Expression *e2; - Expression *e; - - assert(!arg); - econd = condition->doInline(ids); - assert(econd); - if (ifbody) - e1 = ifbody->doInline(ids); - else - e1 = NULL; - if (elsebody) - e2 = elsebody->doInline(ids); - else - e2 = NULL; - if (e1 && e2) - { - e = new CondExp(econd->loc, econd, e1, e2); - e->type = e1->type; - } - else if (e1) - { - e = new AndAndExp(econd->loc, econd, e1); - e->type = Type::tvoid; - } - else if (e2) - { - e = new OrOrExp(econd->loc, econd, e2); - e->type = Type::tvoid; - } - else - { - e = econd; - } - return e; -} - -Expression *ReturnStatement::doInline(InlineDoState *ids) -{ - //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); - return exp ? exp->doInline(ids) : 0; -} - -#if DMDV2 -Expression *ImportStatement::doInline(InlineDoState *ids) -{ - return NULL; -} -#endif - -/* --------------------------------------------------------------- */ - -/****************************** - * Perform doInline() on an array of Expressions. - */ - -Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) -{ Expressions *newa = NULL; - - if (a) - { - newa = new Expressions(); - newa->setDim(a->dim); - - for (size_t i = 0; i < a->dim; i++) - { Expression *e = a->tdata()[i]; - - if (e) - e = e->doInline(ids); - newa->tdata()[i] = e; - } - } - return newa; -} - -Expression *Expression::doInline(InlineDoState *ids) -{ - //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); - return copy(); -} - -Expression *SymOffExp::doInline(InlineDoState *ids) -{ - //printf("SymOffExp::doInline(%s)\n", toChars()); - for (size_t i = 0; i < ids->from.dim; i++) - { - if (var == ids->from.tdata()[i]) - { - SymOffExp *se = (SymOffExp *)copy(); - - se->var = (Declaration *)ids->to.tdata()[i]; - return se; - } - } - return this; -} - -Expression *VarExp::doInline(InlineDoState *ids) -{ - //printf("VarExp::doInline(%s)\n", toChars()); - for (size_t i = 0; i < ids->from.dim; i++) - { - if (var == ids->from.tdata()[i]) - { - VarExp *ve = (VarExp *)copy(); - - ve->var = (Declaration *)ids->to.tdata()[i]; - return ve; - } - } - if (ids->fd && var == ids->fd->vthis) - { VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; - } - - return this; -} - -Expression *ThisExp::doInline(InlineDoState *ids) -{ - //if (!ids->vthis) - //error("no 'this' when inlining %s", ids->parent->toChars()); - if (!ids->vthis) - { - return this; - } - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *SuperExp::doInline(InlineDoState *ids) -{ - assert(ids->vthis); - - VarExp *ve = new VarExp(loc, ids->vthis); - ve->type = type; - return ve; -} - -Expression *DeclarationExp::doInline(InlineDoState *ids) -{ DeclarationExp *de = (DeclarationExp *)copy(); - VarDeclaration *vd; - - //printf("DeclarationExp::doInline(%s)\n", toChars()); - vd = declaration->isVarDeclaration(); - if (vd) - { -#if 0 - // Need to figure this out before inlining can work for tuples - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = td->objects->tdata()[i]; - assert(se->op == TOKdsymbol); - se->s; - } - return st->objects->dim; - } -#endif - if (vd->isStatic()) - ; - else - { - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init) - { - if (vd->init->isVoidInitializer()) - { - vto->init = new VoidInitializer(vd->init->loc); - } - else - { - Expression *e = vd->init->toExpression(); - assert(e); - vto->init = new ExpInitializer(e->loc, e->doInline(ids)); - } - } - de->declaration = (Dsymbol *) (void *)vto; - } - } - /* This needs work, like DeclarationExp::toElem(), if we are - * to handle TemplateMixin's. For now, we just don't inline them. - */ - return de; -} - -Expression *NewExp::doInline(InlineDoState *ids) -{ - //printf("NewExp::doInline(): %s\n", toChars()); - NewExp *ne = (NewExp *)copy(); - - if (thisexp) - ne->thisexp = thisexp->doInline(ids); - ne->newargs = arrayExpressiondoInline(ne->newargs, ids); - ne->arguments = arrayExpressiondoInline(ne->arguments, ids); - return ne; -} - -Expression *UnaExp::doInline(InlineDoState *ids) -{ - UnaExp *ue = (UnaExp *)copy(); - - ue->e1 = e1->doInline(ids); - return ue; -} - -Expression *AssertExp::doInline(InlineDoState *ids) -{ - AssertExp *ae = (AssertExp *)copy(); - - ae->e1 = e1->doInline(ids); - if (msg) - ae->msg = msg->doInline(ids); - return ae; -} - -Expression *BinExp::doInline(InlineDoState *ids) -{ - BinExp *be = (BinExp *)copy(); - - be->e1 = e1->doInline(ids); - be->e2 = e2->doInline(ids); - return be; -} - -Expression *CallExp::doInline(InlineDoState *ids) -{ - CallExp *ce; - - ce = (CallExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *IndexExp::doInline(InlineDoState *ids) -{ - IndexExp *are = (IndexExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init && !vd->init->isVoidInitializer()) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - are->e2 = e2->doInline(ids); - return are; -} - - -Expression *SliceExp::doInline(InlineDoState *ids) -{ - SliceExp *are = (SliceExp *)copy(); - - are->e1 = e1->doInline(ids); - - if (lengthVar) - { //printf("lengthVar\n"); - VarDeclaration *vd = lengthVar; - ExpInitializer *ie; - ExpInitializer *ieto; - VarDeclaration *vto; - - vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); - *vto = *vd; - vto->parent = ids->parent; -#if IN_DMD - vto->csym = NULL; - vto->isym = NULL; -#endif - - ids->from.push(vd); - ids->to.push(vto); - - if (vd->init && !vd->init->isVoidInitializer()) - { - ie = vd->init->isExpInitializer(); - assert(ie); - ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); - vto->init = ieto; - } - - are->lengthVar = (VarDeclaration *) (void *)vto; - } - if (lwr) - are->lwr = lwr->doInline(ids); - if (upr) - are->upr = upr->doInline(ids); - return are; -} - - -Expression *TupleExp::doInline(InlineDoState *ids) -{ - TupleExp *ce; - - ce = (TupleExp *)copy(); - ce->exps = arrayExpressiondoInline(exps, ids); - return ce; -} - - -Expression *ArrayLiteralExp::doInline(InlineDoState *ids) -{ - ArrayLiteralExp *ce; - - ce = (ArrayLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) -{ - AssocArrayLiteralExp *ce; - - ce = (AssocArrayLiteralExp *)copy(); - ce->keys = arrayExpressiondoInline(keys, ids); - ce->values = arrayExpressiondoInline(values, ids); - return ce; -} - - -Expression *StructLiteralExp::doInline(InlineDoState *ids) -{ - StructLiteralExp *ce; - - ce = (StructLiteralExp *)copy(); - ce->elements = arrayExpressiondoInline(elements, ids); - return ce; -} - - -Expression *ArrayExp::doInline(InlineDoState *ids) -{ - ArrayExp *ce; - - ce = (ArrayExp *)copy(); - ce->e1 = e1->doInline(ids); - ce->arguments = arrayExpressiondoInline(arguments, ids); - return ce; -} - - -Expression *CondExp::doInline(InlineDoState *ids) -{ - CondExp *ce = (CondExp *)copy(); - - ce->econd = econd->doInline(ids); - ce->e1 = e1->doInline(ids); - ce->e2 = e2->doInline(ids); - return ce; -} - - -/* ========== Walk the parse trees, and inline expand functions ============= */ - -/* Walk the trees, looking for functions to inline. - * Inline any that can be. - */ - -struct InlineScanState -{ - FuncDeclaration *fd; // function being scanned -}; - -Statement *Statement::inlineScan(InlineScanState *iss) -{ - return this; -} - -Statement *ExpStatement::inlineScan(InlineScanState *iss) -{ -#if LOG - printf("ExpStatement::inlineScan(%s)\n", toChars()); -#endif - if (exp) - { - exp = exp->inlineScan(iss); - - /* See if we can inline as a statement rather than as - * an Expression. - */ - if (exp && exp->op == TOKcall) - { - CallExp *ce = (CallExp *)exp; - if (ce->e1->op == TOKvar) - { - VarExp *ve = (VarExp *)ce->e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0, 0, 1)) - { - Statement *s; - fd->expandInline(iss, NULL, ce->arguments, &s); - return s; - } - } - } - } - return this; -} - -Statement *CompoundStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - (*statements)[i] = s->inlineScan(iss); - } - return this; -} - -Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - (*statements)[i] = s->inlineScan(iss); - } - return this; -} - -Statement *ScopeStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -Statement *WhileStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - return this; -} - - -Statement *DoStatement::inlineScan(InlineScanState *iss) -{ - body = body ? body->inlineScan(iss) : NULL; - condition = condition->inlineScan(iss); - return this; -} - - -Statement *ForStatement::inlineScan(InlineScanState *iss) -{ - if (init) - init = init->inlineScan(iss); - if (condition) - condition = condition->inlineScan(iss); - if (increment) - increment = increment->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *ForeachStatement::inlineScan(InlineScanState *iss) -{ - aggr = aggr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -#if DMDV2 -Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) -{ - lwr = lwr->inlineScan(iss); - upr = upr->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} -#endif - - -Statement *IfStatement::inlineScan(InlineScanState *iss) -{ - condition = condition->inlineScan(iss); - if (ifbody) - ifbody = ifbody->inlineScan(iss); - if (elsebody) - elsebody = elsebody->inlineScan(iss); - return this; -} - - -Statement *SwitchStatement::inlineScan(InlineScanState *iss) -{ - //printf("SwitchStatement::inlineScan()\n"); - condition = condition->inlineScan(iss); - body = body ? body->inlineScan(iss) : NULL; - if (sdefault) - sdefault = (DefaultStatement *)sdefault->inlineScan(iss); - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { CaseStatement *s; - - s = cases->tdata()[i]; - cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss); - } - } - return this; -} - - -Statement *CaseStatement::inlineScan(InlineScanState *iss) -{ - //printf("CaseStatement::inlineScan()\n"); - exp = exp->inlineScan(iss); - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *DefaultStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *ReturnStatement::inlineScan(InlineScanState *iss) -{ - //printf("ReturnStatement::inlineScan()\n"); - if (exp) - { - exp = exp->inlineScan(iss); - } - return this; -} - - -Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *WithStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - if (body) - body = body->inlineScan(iss); - return this; -} - - -Statement *TryCatchStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (catches) - { - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = catches->tdata()[i]; - - if (c->handler) - c->handler = c->handler->inlineScan(iss); - } - } - return this; -} - - -Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) -{ - if (body) - body = body->inlineScan(iss); - if (finalbody) - finalbody = finalbody->inlineScan(iss); - return this; -} - - -Statement *ThrowStatement::inlineScan(InlineScanState *iss) -{ - if (exp) - exp = exp->inlineScan(iss); - return this; -} - - -Statement *VolatileStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - - -Statement *LabelStatement::inlineScan(InlineScanState *iss) -{ - if (statement) - statement = statement->inlineScan(iss); - return this; -} - -/* -------------------------- */ - -void arrayInlineScan(InlineScanState *iss, Expressions *arguments) -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - if (e) - { - e = e->inlineScan(iss); - arguments->tdata()[i] = e; - } - } - } -} - -Expression *Expression::inlineScan(InlineScanState *iss) -{ - return this; -} - -void scanVar(Dsymbol *s, InlineScanState *iss) -{ - VarDeclaration *vd = s->isVarDeclaration(); - if (vd) - { - TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); - if (td) - { - for (size_t i = 0; i < td->objects->dim; i++) - { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i]; - assert(se->op == TOKdsymbol); - scanVar(se->s, iss); - } - } - else - { - // Scan initializer (vd->init) - if (vd->init) - { - ExpInitializer *ie = vd->init->isExpInitializer(); - - if (ie) - { -#if DMDV2 - if (vd->type) - { Type *tb = vd->type->toBasetype(); - if (tb->ty == Tstruct) - { StructDeclaration *sd = ((TypeStruct *)tb)->sym; - if (sd->cpctor) - { /* The problem here is that if the initializer is a - * function call that returns a struct S with a cpctor: - * S s = foo(); - * the postblit is done by the return statement in foo() - * in s2ir.c, the intermediate code generator. - * But, if foo() is inlined and now the code looks like: - * S s = x; - * the postblit is not there, because such assignments - * are rewritten as s.cpctor(&x) by the front end. - * So, the inlining won't get the postblit called. - * Work around by not inlining these cases. - * A proper fix would be to move all the postblit - * additions to the front end. - */ - return; - } - } - } -#endif - ie->exp = ie->exp->inlineScan(iss); - } - } - } - } -} - -Expression *DeclarationExp::inlineScan(InlineScanState *iss) -{ - //printf("DeclarationExp::inlineScan()\n"); - scanVar(declaration, iss); - return this; -} - -Expression *UnaExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - return this; -} - -Expression *AssertExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (msg) - msg = msg->inlineScan(iss); - return this; -} - -Expression *BinExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -Expression *CallExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("CallExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - FuncDeclaration *fd = ve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(0, 0, 0)) - { - e = fd->expandInline(iss, NULL, arguments, NULL); - } - } - else if (e1->op == TOKdotvar) - { - DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - - if (fd && fd != iss->fd && fd->canInline(1, 0, 0)) - { - if (dve->e1->op == TOKcall && - dve->e1->type->toBasetype()->ty == Tstruct) - { - /* To create ethis, we'll need to take the address - * of dve->e1, but this won't work if dve->e1 is - * a function call. - */ - ; - } - else - e = fd->expandInline(iss, dve->e1, arguments, NULL); - } - } - - return e; -} - - -Expression *SliceExp::inlineScan(InlineScanState *iss) -{ - e1 = e1->inlineScan(iss); - if (lwr) - lwr = lwr->inlineScan(iss); - if (upr) - upr = upr->inlineScan(iss); - return this; -} - - -Expression *TupleExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("TupleExp::inlineScan()\n"); - arrayInlineScan(iss, exps); - - return e; -} - - -Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("AssocArrayLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, keys); - arrayInlineScan(iss, values); - - return e; -} - - -Expression *StructLiteralExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("StructLiteralExp::inlineScan()\n"); - arrayInlineScan(iss, elements); - - return e; -} - - -Expression *ArrayExp::inlineScan(InlineScanState *iss) -{ Expression *e = this; - - //printf("ArrayExp::inlineScan()\n"); - e1 = e1->inlineScan(iss); - arrayInlineScan(iss, arguments); - - return e; -} - - -Expression *CondExp::inlineScan(InlineScanState *iss) -{ - econd = econd->inlineScan(iss); - e1 = e1->inlineScan(iss); - e2 = e2->inlineScan(iss); - return this; -} - - -/* ========== =============== */ - -void FuncDeclaration::inlineScan() -{ - InlineScanState iss; - -#if LOG - printf("FuncDeclaration::inlineScan('%s')\n", toChars()); -#endif - memset(&iss, 0, sizeof(iss)); - iss.fd = this; - if (fbody && !naked) - { - inlineNest++; - fbody = fbody->inlineScan(&iss); - inlineNest--; - } -} - -int FuncDeclaration::canInline(int hasthis, int hdrscan, int statementsToo) -{ - InlineCostState ics; - int cost; - -#define CANINLINE_LOG 0 - -#if CANINLINE_LOG - printf("FuncDeclaration::canInline(hasthis = %d, statementsToo = %d, '%s')\n", hasthis, statementsToo, toChars()); -#endif - - if (needThis() && !hasthis) - return 0; - - if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan)) - { -#if CANINLINE_LOG - printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); -#endif - return 0; - } - -#if 1 - switch (statementsToo ? inlineStatusStmt : inlineStatusExp) - { - case ILSyes: -#if CANINLINE_LOG - printf("\t1: yes %s\n", toChars()); -#endif - return 1; - - case ILSno: -#if CANINLINE_LOG - printf("\t1: no %s\n", toChars()); -#endif - return 0; - - case ILSuninitialized: - break; - - default: - assert(0); - } -#endif - - if (type) - { assert(type->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)(type); -#if IN_LLVM - // LDC: Only extern(C) varargs count. - if (tf->linkage != LINKd) -#endif - if (tf->varargs == 1) // no variadic parameter lists - goto Lno; - - /* Don't inline a function that returns non-void, but has - * no return expression. - * No statement inlining for non-voids. - */ - if (tf->next && tf->next->ty != Tvoid && - (!(hasReturnExp & 1) || statementsToo) && - !hdrscan) - goto Lno; - } -#if !IN_LLVM - // LDC: Only extern(C) varargs count, and ctors use extern(D). -#endif - - if ( - !fbody || - ident == Id::ensure || // ensure() has magic properties the inliner loses - !hdrscan && - ( -#if 0 - isCtorDeclaration() || // cannot because need to convert: - // return; - // to: - // return this; -#endif - isSynchronized() || - isImportedSymbol() || -//#if !IN_LLVM - hasNestedFrameRefs() || // no nested references to this frame -//#endif // !IN_LLVM - (isVirtual() && !isFinal()) - )) - { - goto Lno; - } - -#if 0 - /* If any parameters are Tsarray's (which are passed by reference) - * or out parameters (also passed by reference), don't do inlining. - */ - if (parameters) - { - for (size_t i = 0; i < parameters->dim; i++) - { - VarDeclaration *v = parameters->tdata()[i]; - if (v->type->toBasetype()->ty == Tsarray) - goto Lno; - } - } -#endif - - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); -#if CANINLINE_LOG - printf("cost = %d for %s\n", cost, toChars()); -#endif - if (tooCostly(cost)) - goto Lno; - if (!statementsToo && cost > COST_MAX) - goto Lno; - - if (!hdrscan) - { - // Don't modify inlineStatus for header content scan - if (statementsToo) - inlineStatusStmt = ILSyes; - else - inlineStatusExp = ILSyes; - -#if !IN_LLVM // TODO: why was it added in the first place? - inlineScan(); // Don't scan recursively for header content scan -#endif - - if (inlineStatusExp == ILSuninitialized) - { - // Need to redo cost computation, as some statements or expressions have been inlined - memset(&ics, 0, sizeof(ics)); - ics.hasthis = hasthis; - ics.fd = this; - ics.hdrscan = hdrscan; - cost = fbody->inlineCost(&ics); - #if CANINLINE_LOG - printf("recomputed cost = %d for %s\n", cost, toChars()); - #endif - if (tooCostly(cost)) - goto Lno; - if (!statementsToo && cost > COST_MAX) - goto Lno; - - if (statementsToo) - inlineStatusStmt = ILSyes; - else - inlineStatusExp = ILSyes; - } - } -#if CANINLINE_LOG - printf("\t2: yes %s\n", toChars()); -#endif - return 1; - -Lno: - if (!hdrscan) // Don't modify inlineStatus for header content scan - { if (statementsToo) - inlineStatusStmt = ILSno; - else - inlineStatusExp = ILSno; - } -#if CANINLINE_LOG - printf("\t2: no %s\n", toChars()); -#endif - return 0; -} - -Expression *FuncDeclaration::expandInline(InlineScanState *iss, Expression *ethis, Expressions *arguments, Statement **ps) -{ - InlineDoState ids; - DeclarationExp *de; - Expression *e = NULL; - Statements *as = NULL; - -#if LOG || CANINLINE_LOG - printf("FuncDeclaration::expandInline('%s')\n", toChars()); -#endif - - memset(&ids, 0, sizeof(ids)); - ids.parent = iss->fd; - ids.fd = this; - - if (ps) - as = new Statements(); - - // Set up vthis - if (ethis) - { - VarDeclaration *vthis; - ExpInitializer *ei; - VarExp *ve; - -#if STRUCTTHISREF - if (ethis->type->ty == Tpointer) - { Type *t = ethis->type->nextOf(); - ethis = new PtrExp(ethis->loc, ethis); - ethis->type = t; - } - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - if (ethis->type->ty != Tclass) - vthis->storage_class = STCref; - else - vthis->storage_class = STCin; -#else - if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) - { - ethis = ethis->addressOf(NULL); - } - - ei = new ExpInitializer(ethis->loc, ethis); - - vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); - vthis->storage_class = STCin; -#endif - vthis->linkage = LINKd; - vthis->parent = iss->fd; - - ve = new VarExp(vthis->loc, vthis); - ve->type = vthis->type; - - ei->exp = new AssignExp(vthis->loc, ve, ethis); - ei->exp->type = ve->type; -#if STRUCTTHISREF - if (ethis->type->ty != Tclass) - { /* This is a reference initialization, not a simple assignment. - */ - ei->exp->op = TOKconstruct; - } -#endif - - ids.vthis = vthis; - } - - // Set up parameters - if (ethis) - { - e = new DeclarationExp(0, ids.vthis); - e->type = Type::tvoid; - if (as) - as->push(new ExpStatement(e->loc, e)); - } - - if (arguments && arguments->dim) - { - assert(parameters->dim == arguments->dim); - - for (size_t i = 0; i < arguments->dim; i++) - { - VarDeclaration *vfrom = parameters->tdata()[i]; - VarDeclaration *vto; - Expression *arg = arguments->tdata()[i]; - ExpInitializer *ei; - VarExp *ve; - - ei = new ExpInitializer(arg->loc, arg); - - vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); - vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); - vto->linkage = vfrom->linkage; - vto->parent = iss->fd; - //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); - //printf("vto->parent = '%s'\n", iss->fd->toChars()); - - ve = new VarExp(vto->loc, vto); - //ve->type = vto->type; - ve->type = arg->type; - - ei->exp = new ConstructExp(vto->loc, ve, arg); - ei->exp->type = ve->type; -//ve->type->print(); -//arg->type->print(); -//ei->exp->print(); - - ids.from.push(vfrom); - ids.to.push(vto); - - de = new DeclarationExp(0, vto); - de->type = Type::tvoid; - - if (as) - as->push(new ExpStatement(0, de)); - else - e = Expression::combine(e, de); - } - } - - if (ps) - { - inlineNest++; - Statement *s = fbody->doInlineStatement(&ids); - as->push(s); - *ps = new ScopeStatement(0, new CompoundStatement(0, as)); - inlineNest--; - } - else - { - inlineNest++; - Expression *eb = fbody->doInline(&ids); - e = Expression::combine(e, eb); - inlineNest--; - //eb->type->print(); - //eb->print(); - //eb->dump(0); - } - - /* There's a problem if what the function returns is used subsequently as an - * lvalue, as in a struct return that is then used as a 'this'. - * If we take the address of the return value, we will be taking the address - * of the original, not the copy. Fix this by assigning the return value to - * a temporary, then returning the temporary. If the temporary is used as an - * lvalue, it will work. - * This only happens with struct returns. - * See Bugzilla 2127 for an example. - */ - TypeFunction *tf = (TypeFunction*)type; - if (!ps && tf->next->ty == Tstruct) - { - /* Generate a new variable to hold the result and initialize it with the - * inlined body of the function: - * tret __inlineretval = e; - */ - ExpInitializer* ei = new ExpInitializer(loc, e); - - Identifier* tmp = Identifier::generateId("__inlineretval"); - VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei); - vd->storage_class = tf->isref ? STCref : 0; - vd->linkage = tf->linkage; - vd->parent = iss->fd; - - VarExp *ve = new VarExp(loc, vd); - ve->type = tf->next; - - ei->exp = new ConstructExp(loc, ve, e); - ei->exp->type = ve->type; - - DeclarationExp* de = new DeclarationExp(0, vd); - de->type = Type::tvoid; - - // Chain the two together: - // ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval - e = Expression::combine(de, ve); - - //fprintf(stderr, "CallExp::inlineScan: e = "); e->print(); - } - - // Need to reevaluate whether parent can now be inlined - // in expressions, as we might have inlined statements - iss->fd->inlineStatusExp = ILSuninitialized; - return e; -} - - -/**************************************************** - * Perform the "inline copying" of a default argument for a function parameter. - */ - -Expression *Expression::inlineCopy(Scope *sc) -{ -#if 0 - /* See Bugzilla 2935 for explanation of why just a copy() is broken - */ - return copy(); -#else - InlineCostState ics; - - memset(&ics, 0, sizeof(ics)); - ics.hdrscan = 1; // so DeclarationExp:: will work on 'statics' which are not - int cost = expressionInlineCost(this, &ics); - if (cost >= COST_MAX) - { error("cannot inline default argument %s", toChars()); - return new ErrorExp(); - } - InlineDoState ids; - memset(&ids, 0, sizeof(ids)); - ids.parent = sc->parent; - Expression *e = doInline(&ids); - return e; -#endif -} diff --git a/dmd2/interpret.c b/dmd2/interpret.c deleted file mode 100644 index 3d82d385..00000000 --- a/dmd2/interpret.c +++ /dev/null @@ -1,6586 +0,0 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "utf.h" -#include "attrib.h" // for AttribDeclaration - -#include "template.h" -TemplateInstance *isSpeculativeFunction(FuncDeclaration *fd); - - -#define LOG 0 -#define LOGASSIGN 0 -#define SHOWPERFORMANCE 0 - -// Maximum allowable recursive function calls in CTFE -#define CTFE_RECURSION_LIMIT 1000 - -// The values of all CTFE variables. -struct CtfeStack -{ -private: - /* The stack. Every declaration we encounter is pushed here, - together with the VarDeclaration, and the previous - stack address of that variable, so that we can restore it - when we leave the stack frame. - Ctfe Stack addresses are just 0-based integers, but we save - them as 'void *' because ArrayBase can only do pointers. - */ - Expressions values; // values on the stack - VarDeclarations vars; // corresponding variables - ArrayBase savedId; // id of the previous state of that var - - /* Global constants get saved here after evaluation, so we never - * have to redo them. This saves a lot of time and memory. - */ - Expressions globalValues; // values of global constants - size_t framepointer; // current frame pointer - size_t maxStackPointer; // most stack we've ever used -public: - CtfeStack() : framepointer(0) - { - } - size_t stackPointer() - { - return values.dim; - } - // Largest number of stack positions we've used - size_t maxStackUsage() - { - return maxStackPointer; - } - // return the previous frame - size_t startFrame() - { - size_t oldframe = framepointer; - framepointer = stackPointer(); - return oldframe; - } - void endFrame(size_t oldframe) - { - popAll(framepointer); - framepointer = oldframe; - } - Expression *getValue(VarDeclaration *v) - { - if (v->isDataseg() && !v->isCTFE()) - { - assert(v->ctfeAdrOnStack >= 0 && - v->ctfeAdrOnStack < globalValues.dim); - return globalValues.tdata()[v->ctfeAdrOnStack]; - } - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - return values.tdata()[v->ctfeAdrOnStack]; - } - void setValue(VarDeclaration *v, Expression *e) - { - assert(!v->isDataseg() || v->isCTFE()); - assert(v->ctfeAdrOnStack >= 0 && v->ctfeAdrOnStack < stackPointer()); - values.tdata()[v->ctfeAdrOnStack] = e; - } - void push(VarDeclaration *v) - { - assert(!v->isDataseg() || v->isCTFE()); - if (v->ctfeAdrOnStack!= (size_t)-1 - && v->ctfeAdrOnStack >= framepointer) - { // Already exists in this frame, reuse it. - values.tdata()[v->ctfeAdrOnStack] = NULL; - return; - } - savedId.push((void *)(v->ctfeAdrOnStack)); - v->ctfeAdrOnStack = values.dim; - vars.push(v); - values.push(NULL); - } - void pop(VarDeclaration *v) - { - assert(!v->isDataseg() || v->isCTFE()); - assert(!(v->storage_class & (STCref | STCout))); - int oldid = v->ctfeAdrOnStack; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[oldid]); - if (v->ctfeAdrOnStack == values.dim - 1) - { - values.pop(); - vars.pop(); - savedId.pop(); - } - } - void popAll(size_t stackpointer) - { - if (stackPointer() > maxStackPointer) - maxStackPointer = stackPointer(); - assert(values.dim >= stackpointer && stackpointer >= 0); - for (size_t i = stackpointer; i < values.dim; ++i) - { - VarDeclaration *v = vars.tdata()[i]; - v->ctfeAdrOnStack = (size_t)(savedId.tdata()[i]); - } - values.setDim(stackpointer); - vars.setDim(stackpointer); - savedId.setDim(stackpointer); - } - void saveGlobalConstant(VarDeclaration *v, Expression *e) - { - assert(v->isDataseg() && !v->isCTFE()); - v->ctfeAdrOnStack = globalValues.dim; - globalValues.push(e); - } -}; - -CtfeStack ctfeStack; - - -struct InterState -{ - InterState *caller; // calling function's InterState - FuncDeclaration *fd; // function being interpreted - size_t framepointer; // frame pointer of previous frame - Statement *start; // if !=NULL, start execution at this statement - Statement *gotoTarget; /* target of EXP_GOTO_INTERPRET result; also - * target of labelled EXP_BREAK_INTERPRET or - * EXP_CONTINUE_INTERPRET. (NULL if no label). - */ - Expression *localThis; // value of 'this', or NULL if none - bool awaitingLvalueReturn; // Support for ref return values: - // Any return to this function should return an lvalue. - InterState(); -}; - -InterState::InterState() -{ - memset(this, 0, sizeof(InterState)); -} - -// Global status of the CTFE engine -struct CtfeStatus -{ - static int callDepth; // current number of recursive calls - static int stackTraceCallsToSuppress; /* When printing a stack trace, - * suppress this number of calls - */ - static int maxCallDepth; // highest number of recursive calls - static int numArrayAllocs; // Number of allocated arrays - static int numAssignments; // total number of assignments executed -}; - -int CtfeStatus::callDepth = 0; -int CtfeStatus::stackTraceCallsToSuppress = 0; -int CtfeStatus::maxCallDepth = 0; -int CtfeStatus::numArrayAllocs = 0; -int CtfeStatus::numAssignments = 0; - -// CTFE diagnostic information -void printCtfePerformanceStats() -{ -#if SHOWPERFORMANCE - printf(" ---- CTFE Performance ----\n"); - printf("max call depth = %d\tmax stack = %d\n", CtfeStatus::maxCallDepth, ctfeStack.maxStackUsage()); - printf("array allocs = %d\tassignments = %d\n\n", CtfeStatus::numArrayAllocs, CtfeStatus::numAssignments); -#endif -} - - -Expression * resolveReferences(Expression *e, Expression *thisval); -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal); -VarDeclaration *findParentVar(Expression *e, Expression *thisval); -bool needToCopyLiteral(Expression *expr); -Expression *copyLiteral(Expression *e); -Expression *paintTypeOntoLiteral(Type *type, Expression *lit); -Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2); -Expression *evaluateIfBuiltin(InterState *istate, Loc loc, - FuncDeclaration *fd, Expressions *arguments, Expression *pthis); -Expression *scrubReturnValue(Loc loc, Expression *e); -bool isAssocArray(Type *t); -bool isPointer(Type *t); - -// CTFE only expressions -#define TOKclassreference ((TOK)(TOKMAX+1)) -#define TOKthrownexception ((TOK)(TOKMAX+2)) - -// Reference to a class, or an interface. We need this when we -// point to a base class (we must record what the type is). -struct ClassReferenceExp : Expression -{ - StructLiteralExp *value; - ClassReferenceExp(Loc loc, StructLiteralExp *lit, Type *type) : Expression(loc, TOKclassreference, sizeof(ClassReferenceExp)) - { - assert(lit && lit->sd && lit->sd->isClassDeclaration()); - this->value = lit; - this->type = type; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - //printf("ClassReferenceExp::interpret() %s\n", value->toChars()); - return this; - } - char *toChars() - { - return value->toChars(); - } - ClassDeclaration *originalClass() - { - return value->sd->isClassDeclaration(); - } - // Return index of the field, or -1 if not found - int getFieldIndex(Type *fieldtype, size_t fieldoffset) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - for (size_t j = 0; j < value->elements->dim; j++) - { while (j - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; - VarDeclaration *v2 = s->isVarDeclaration(); - if (fieldoffset == v2->offset && - fieldtype->size() == v2->type->size()) - { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); - } - } - return -1; - } - // Return index of the field, or -1 if not found - // Same as getFieldIndex, but checks for a direct match with the VarDeclaration - int findFieldIndexByName(VarDeclaration *v) - { - ClassDeclaration *cd = originalClass(); - size_t fieldsSoFar = 0; - for (size_t j = 0; j < value->elements->dim; j++) - { while (j - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - } - Dsymbol *s = cd->fields.tdata()[j - fieldsSoFar]; - VarDeclaration *v2 = s->isVarDeclaration(); - if (v == v2) - { return value->elements->dim - fieldsSoFar - cd->fields.dim + (j-fieldsSoFar); - } - } - return -1; - } -}; - -// Return index of the field, or -1 if not found -// Same as getFieldIndex, but checks for a direct match with the VarDeclaration -int findFieldIndexByName(StructDeclaration *sd, VarDeclaration *v) -{ - for (int i = 0; i < sd->fields.dim; ++i) - { - if (sd->fields.tdata()[i] == v) - return i; - } - return -1; -} - -// Fake class which holds the thrown exception. Used for implementing exception handling. -struct ThrownExceptionExp : Expression -{ - ClassReferenceExp *thrown; // the thing being tossed - ThrownExceptionExp(Loc loc, ClassReferenceExp *victim) : Expression(loc, TOKthrownexception, sizeof(ThrownExceptionExp)) - { - this->thrown = victim; - this->type = type; - } - Expression *interpret(InterState *istate, CtfeGoal goal = ctfeNeedRvalue) - { - assert(0); // This should never be interpreted - return this; - } - char *toChars() - { - return (char *)"CTFE ThrownException"; - } - // Generate an error message when this exception is not caught - void generateUncaughtError() - { - thrown->error("Uncaught CTFE exception %s(%s)", thrown->type->toChars(), - thrown->value->elements->tdata()[0]->toChars()); - /* Also give the line where the throw statement was. We won't have it - * in the case where the ThrowStatement is generated internally - * (eg, in ScopeStatement) - */ - if (loc.filename && !loc.equals(thrown->loc)) - errorSupplemental(loc, "thrown from here"); - } -}; - -// True if 'e' is EXP_CANT_INTERPRET, or an exception -bool exceptionOrCantInterpret(Expression *e) -{ - if (e == EXP_CANT_INTERPRET) return true; - if (!e || e == EXP_GOTO_INTERPRET || e == EXP_VOID_INTERPRET - || e == EXP_BREAK_INTERPRET || e == EXP_CONTINUE_INTERPRET) - return false; - return e->op == TOKthrownexception; -} - - -// Used for debugging only -void showCtfeExpr(Expression *e, int level = 0) -{ - for (int i = level; i>0; --i) printf(" "); - Expressions *elements = NULL; - // We need the struct definition to detect block assignment - StructDeclaration *sd = NULL; - ClassDeclaration *cd = NULL; - if (e->op == TOKstructliteral) - { elements = ((StructLiteralExp *)e)->elements; - sd = ((StructLiteralExp *)e)->sd; - printf("STRUCT type = %s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKclassreference) - { elements = ((ClassReferenceExp *)e)->value->elements; - cd = ((ClassReferenceExp *)e)->originalClass(); - printf("CLASS type = %s %p:\n", e->type->toChars(), - ((ClassReferenceExp *)e)->value); - } - else if (e->op == TOKarrayliteral) - { - elements = ((ArrayLiteralExp *)e)->elements; - printf("ARRAY LITERAL type=%s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKassocarrayliteral) - { - printf("AA LITERAL type=%s %p:\n", e->type->toChars(), - e); - } - else if (e->op == TOKstring) - { - printf("STRING %s %p\n", e->toChars(), - ((StringExp *)e)->string); - } - else if (e->op == TOKslice) - { - printf("SLICE %p: %s\n", e, e->toChars()); - showCtfeExpr(((SliceExp *)e)->e1, level + 1); - } - else if (e->op == TOKvar) - { - printf("VAR %p %s\n", e, e->toChars()); - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - if (v && v->getValue()) - showCtfeExpr(v->getValue(), level + 1); - } - else if (isPointer(e->type)) - { - // This is potentially recursive. We mustn't try to print the thing we're pointing to. - if (e->op == TOKindex) - printf("POINTER %p into %p [%s]\n", e, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2->toChars()); - else if (e->op == TOKdotvar) - printf("POINTER %p to %p .%s\n", e, ((DotVarExp *)e)->e1, ((DotVarExp *)e)->var->toChars()); - else - printf("POINTER %p: %s\n", e, e->toChars()); - } - else - printf("VALUE %p: %s\n", e, e->toChars()); - - if (elements) - { - size_t fieldsSoFar = 0; - for (size_t i = 0; i < elements->dim; i++) - { Expression *z = NULL; - Dsymbol *s = NULL; - if (i > 15) { - printf("...(total %d elements)\n", elements->dim); - return; - } - if (sd) - { s = sd->fields.tdata()[i]; - z = elements->tdata()[i]; - } - else if (cd) - { while (i - fieldsSoFar >= cd->fields.dim) - { fieldsSoFar += cd->fields.dim; - cd = cd->baseClass; - for (int j = level; j>0; --j) printf(" "); - printf(" BASE CLASS: %s\n", cd->toChars()); - } - s = cd->fields.tdata()[i - fieldsSoFar]; - size_t indx = (elements->dim - fieldsSoFar)- cd->fields.dim + i; - assert(indx >= 0); - assert(indx < elements->dim); - z = elements->tdata()[indx]; - } - if (!z) { - for (int j = level; j>0; --j) printf(" "); - printf(" void\n"); - continue; - } - - if (s) - { - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - // If it is a void assignment, use the default initializer - if ((v->type->ty != z->type->ty) && v->type->ty == Tsarray) - { - for (int j = level; --j;) printf(" "); - printf(" field: block initalized static array\n"); - continue; - } - } - showCtfeExpr(z, level + 1); - } - } -} - -/************************************* - * Attempt to interpret a function given the arguments. - * Input: - * istate state for calling function (NULL if none) - * arguments function arguments - * thisarg 'this', if a needThis() function, NULL if not. - * - * Return result expression if successful, EXP_CANT_INTERPRET if not. - */ - -Expression *FuncDeclaration::interpret(InterState *istate, Expressions *arguments, Expression *thisarg) -{ -#if LOG - printf("\n********\nFuncDeclaration::interpret(istate = %p) %s\n", istate, toChars()); -#endif - if (semanticRun == PASSsemantic3) - return EXP_CANT_INTERPRET; - - if (semanticRun < PASSsemantic3 && scope) - { - /* Forward reference - we need to run semantic3 on this function. - * If errors are gagged, and it's not part of a speculative - * template instance, we need to temporarily ungag errors. - */ - int olderrors = global.errors; - int oldgag = global.gag; - TemplateInstance *spec = isSpeculativeFunction(this); - if (global.gag && !spec) - global.gag = 0; - ++scope->ignoreTemplates; - semantic3(scope); - --scope->ignoreTemplates; - global.gag = oldgag; // regag errors - - // If it is a speculatively-instantiated template, and errors occur, - // we need to mark the template as having errors. - if (spec && global.errors != olderrors) - spec->errors = global.errors - olderrors; - if (olderrors != global.errors) // if errors compiling this function - return EXP_CANT_INTERPRET; - } - if (semanticRun < PASSsemantic3done) - return EXP_CANT_INTERPRET; - - Type *tb = type->toBasetype(); - assert(tb->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)tb; - Type *tret = tf->next->toBasetype(); - if (tf->varargs && arguments && - ((parameters && arguments->dim != parameters->dim) || (!parameters && arguments->dim))) - { - error("C-style variadic functions are not yet implemented in CTFE"); - return EXP_CANT_INTERPRET; - } - - // Nested functions always inherit the 'this' pointer from the parent, - // except for delegates. (Note that the 'this' pointer may be null). - // Func literals report isNested() even if they are in global scope, - // so we need to check that the parent is a function. - if (isNested() && toParent2()->isFuncDeclaration() && !thisarg && istate) - thisarg = istate->localThis; - - InterState istatex; - istatex.caller = istate; - istatex.fd = this; - istatex.localThis = thisarg; - istatex.framepointer = ctfeStack.startFrame(); - - Expressions vsave; // place to save previous parameter values - size_t dim = 0; - if (needThis() && !thisarg) - { // error, no this. Prevent segfault. - error("need 'this' to access member %s", toChars()); - return EXP_CANT_INTERPRET; - } - if (thisarg && !istate) - { // Check that 'this' aleady has a value - if (thisarg->interpret(istate) == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - } - static int evaluatingArgs = 0; - if (arguments) - { - dim = arguments->dim; - assert(!dim || (parameters && (parameters->dim == dim))); - vsave.setDim(dim); - - /* Evaluate all the arguments to the function, - * store the results in eargs[] - */ - Expressions eargs; - eargs.setDim(dim); - for (size_t i = 0; i < dim; i++) - { Expression *earg = arguments->tdata()[i]; - Parameter *arg = Parameter::getNth(tf->parameters, i); - - if (arg->storageClass & (STCout | STCref)) - { - if (!istate && (arg->storageClass & STCout)) - { // initializing an out parameter involves writing to it. - earg->error("global %s cannot be passed as an 'out' parameter at compile time", earg->toChars()); - return EXP_CANT_INTERPRET; - } - // Convert all reference arguments into lvalue references - ++evaluatingArgs; - earg = earg->interpret(istate, ctfeNeedLvalueRef); - --evaluatingArgs; - if (earg == EXP_CANT_INTERPRET) - return earg; - } - else if (arg->storageClass & STClazy) - { - } - else - { /* Value parameters - */ - Type *ta = arg->type->toBasetype(); - if (ta->ty == Tsarray && earg->op == TOKaddress) - { - /* Static arrays are passed by a simple pointer. - * Skip past this to get at the actual arg. - */ - earg = ((AddrExp *)earg)->e1; - } - ++evaluatingArgs; - earg = earg->interpret(istate); - --evaluatingArgs; - if (earg == EXP_CANT_INTERPRET) - return earg; - } - if (earg->op == TOKthrownexception) - { - if (istate) - return earg; - ((ThrownExceptionExp *)earg)->generateUncaughtError(); - return EXP_CANT_INTERPRET; - } - eargs.tdata()[i] = earg; - } - - for (size_t i = 0; i < dim; i++) - { Expression *earg = eargs.tdata()[i]; - Parameter *arg = Parameter::getNth(tf->parameters, i); - VarDeclaration *v = parameters->tdata()[i]; -#if LOG - printf("arg[%d] = %s\n", i, earg->toChars()); -#endif - if (arg->storageClass & (STCout | STCref) && earg->op == TOKvar) - { - VarExp *ve = (VarExp *)earg; - VarDeclaration *v2 = ve->var->isVarDeclaration(); - if (!v2) - { - error("cannot interpret %s as a ref parameter", ve->toChars()); - return EXP_CANT_INTERPRET; - } - /* The push() isn't a variable we'll use, it's just a place - * to save the old value of v. - * Note that v might be v2! So we need to save v2's index - * before pushing. - */ - size_t oldadr = v2->ctfeAdrOnStack; - ctfeStack.push(v); - v->ctfeAdrOnStack = oldadr; - assert(v2->hasValue()); - } - else - { // Value parameters and non-trivial references - ctfeStack.push(v); - v->setValueWithoutChecking(earg); - } -#if LOG || LOGASSIGN - printf("interpreted arg[%d] = %s\n", i, earg->toChars()); - showCtfeExpr(earg); -#endif - } - } - - if (vresult) - ctfeStack.push(vresult); - - // Enter the function - ++CtfeStatus::callDepth; - if (CtfeStatus::callDepth > CtfeStatus::maxCallDepth) - CtfeStatus::maxCallDepth = CtfeStatus::callDepth; - - Expression *e = NULL; - while (1) - { - if (CtfeStatus::callDepth > CTFE_RECURSION_LIMIT) - { // This is a compiler error. It must not be suppressed. - global.gag = 0; - error("CTFE recursion limit exceeded"); - e = EXP_CANT_INTERPRET; - break; - } - e = fbody->interpret(&istatex); - if (e == EXP_CANT_INTERPRET) - { -#if LOG - printf("function body failed to interpret\n"); -#endif - } - - /* This is how we deal with a recursive statement AST - * that has arbitrary goto statements in it. - * Bubble up a 'result' which is the target of the goto - * statement, then go recursively down the AST looking - * for that statement, then execute starting there. - */ - if (e == EXP_GOTO_INTERPRET) - { - istatex.start = istatex.gotoTarget; // set starting statement - istatex.gotoTarget = NULL; - } - else - break; - } - assert(e != EXP_CONTINUE_INTERPRET && e != EXP_BREAK_INTERPRET); - - // Leave the function - --CtfeStatus::callDepth; - - ctfeStack.endFrame(istatex.framepointer); - - // If fell off the end of a void function, return void - if (!e && type->toBasetype()->nextOf()->ty == Tvoid) - return EXP_VOID_INTERPRET; - // If it generated an exception, return it - if (exceptionOrCantInterpret(e)) - { - if (istate || e == EXP_CANT_INTERPRET) - return e; - ((ThrownExceptionExp *)e)->generateUncaughtError(); - return EXP_CANT_INTERPRET; - } - if (!istate && !evaluatingArgs) - { - e = scrubReturnValue(loc, e); - } - return e; -} - -/******************************** Statement ***************************/ - -#define START() \ - if (istate->start) \ - { if (istate->start != this) \ - return NULL; \ - istate->start = NULL; \ - } - -/*********************************** - * Interpret the statement. - * Returns: - * NULL continue to next statement - * EXP_CANT_INTERPRET cannot interpret statement at compile time - * !NULL expression from return statement, or thrown exception - */ - -Expression *Statement::interpret(InterState *istate) -{ -#if LOG - printf("Statement::interpret()\n"); -#endif - START() - error("Statement %s cannot be interpreted at compile time", this->toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *ExpStatement::interpret(InterState *istate) -{ -#if LOG - printf("ExpStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (exp) - { - Expression *e = exp->interpret(istate, ctfeNeedNothing); - if (e == EXP_CANT_INTERPRET) - { - //printf("-ExpStatement::interpret(): %p\n", e); - return EXP_CANT_INTERPRET; - } - if (e && e!= EXP_VOID_INTERPRET && e->op == TOKthrownexception) - return e; - } - return NULL; -} - -Expression *CompoundStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("CompoundStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; - - if (s) - { - e = s->interpret(istate); - if (e) - break; - } - } - } -#if LOG - printf("-CompoundStatement::interpret() %p\n", e); -#endif - return e; -} - -Expression *UnrolledLoopStatement::interpret(InterState *istate) -{ Expression *e = NULL; - -#if LOG - printf("UnrolledLoopStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statements) - { - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = statements->tdata()[i]; - - e = s->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_CONTINUE_INTERPRET) - { - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at higher level - istate->gotoTarget = NULL; - e = NULL; - continue; - } - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e) - break; - } - } - return e; -} - -// For CTFE only. Returns true if 'e' is TRUE or a non-null pointer. -int isTrueBool(Expression *e) -{ - return e->isBool(TRUE) || ((e->type->ty == Tpointer || e->type->ty == Tclass) - && e->op != TOKnull); -} - -Expression *IfStatement::interpret(InterState *istate) -{ -#if LOG - printf("IfStatement::interpret(%s)\n", condition->toChars()); -#endif - - if (istate->start == this) - istate->start = NULL; - if (istate->start) - { - Expression *e = NULL; - if (ifbody) - e = ifbody->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (istate->start && elsebody) - e = elsebody->interpret(istate); - return e; - } - - Expression *e = condition->interpret(istate); - assert(e); - //if (e == EXP_CANT_INTERPRET) printf("cannot interpret\n"); - if (e != EXP_CANT_INTERPRET && (e && e->op != TOKthrownexception)) - { - if (isTrueBool(e)) - e = ifbody ? ifbody->interpret(istate) : NULL; - else if (e->isBool(FALSE)) - e = elsebody ? elsebody->interpret(istate) : NULL; - else - { - e = EXP_CANT_INTERPRET; - } - } - return e; -} - -Expression *ScopeStatement::interpret(InterState *istate) -{ -#if LOG - printf("ScopeStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - -Expression *resolveSlice(Expression *e) -{ - if ( ((SliceExp *)e)->e1->op == TOKnull) - return ((SliceExp *)e)->e1; - return Slice(e->type, ((SliceExp *)e)->e1, - ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); -} - -/* Determine the array length, without interpreting it. - * e must be an array literal, or a slice - * It's very wasteful to resolve the slice when we only - * need the length. - */ -uinteger_t resolveArrayLength(Expression *e) -{ - if (e->op == TOKnull) - return 0; - if (e->op == TOKslice) - { uinteger_t ilo = ((SliceExp *)e)->lwr->toInteger(); - uinteger_t iup = ((SliceExp *)e)->upr->toInteger(); - return iup - ilo; - } - if (e->op == TOKstring) - { return ((StringExp *)e)->len; - } - if (e->op == TOKarrayliteral) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)e; - return ale->elements ? ale->elements->dim : 0; - } - if (e->op == TOKassocarrayliteral) - { AssocArrayLiteralExp *ale = (AssocArrayLiteralExp *)e; - return ale->keys->dim; - } - assert(0); - return 0; -} - -// As Equal, but resolves slices before comparing -Expression *ctfeEqual(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - return Equal(op, type, e1, e2); -} - -Expression *ctfeCat(Type *type, Expression *e1, Expression *e2) -{ - Loc loc = e1->loc; - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - Expression *e; - if (e2->op == TOKstring && e1->op == TOKarrayliteral && - t1->nextOf()->isintegral()) - { - // [chars] ~ string => string (only valid for CTFE) - StringExp *es1 = (StringExp *)e2; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e1; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy((char *)s + sz * es2->elements->dim, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + i * sz, &v, sz); - } - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - StringExp *es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 0; - es->type = type; - e = es; - return e; - } - else if (e1->op == TOKstring && e2->op == TOKarrayliteral && - t2->nextOf()->isintegral()) - { - // string ~ [chars] => string (only valid for CTFE) - // Concatenate the strings - StringExp *es1 = (StringExp *)e1; - ArrayLiteralExp *es2 = (ArrayLiteralExp *)e2; - size_t len = es1->len + es2->elements->dim; - int sz = es1->sz; - - void *s = mem.malloc((len + 1) * sz); - memcpy(s, es1->string, es1->len * sz); - for (size_t i = 0; i < es2->elements->dim; i++) - { Expression *es2e = es2->elements->tdata()[i]; - if (es2e->op != TOKint64) - return EXP_CANT_INTERPRET; - dinteger_t v = es2e->toInteger(); - memcpy((unsigned char *)s + (es1->len + i) * sz, &v, sz); - } - - // Add terminating 0 - memset((unsigned char *)s + len * sz, 0, sz); - - StringExp *es = new StringExp(loc, s, len); - es->sz = sz; - es->committed = 0; //es1->committed; - es->type = type; - e = es; - return e; - } - return Cat(type, e1, e2); -} - -void scrubArray(Loc loc, Expressions *elems); - -/* All results destined for use outside of CTFE need to have their CTFE-specific - * features removed. - * In particular, all slices must be resolved. - */ -Expression *scrubReturnValue(Loc loc, Expression *e) -{ - if (e->op == TOKclassreference) - { - error(loc, "%s class literals cannot be returned from CTFE", ((ClassReferenceExp*)e)->originalClass()->toChars()); - return EXP_CANT_INTERPRET; - } - if (e->op == TOKslice) - { - e = resolveSlice(e); - } - if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - se->ownedByCtfe = false; - scrubArray(loc, se->elements); - } - if (e->op == TOKstring) - { - ((StringExp *)e)->ownedByCtfe = false; - } - if (e->op == TOKarrayliteral) - { - ((ArrayLiteralExp *)e)->ownedByCtfe = false; - scrubArray(loc, ((ArrayLiteralExp *)e)->elements); - } - if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; - aae->ownedByCtfe = false; - scrubArray(loc, aae->keys); - scrubArray(loc, aae->values); - } - return e; -} - -// Scrub all members of an array -void scrubArray(Loc loc, Expressions *elems) -{ - for (size_t i = 0; i < elems->dim; i++) - { - Expression *m = elems->tdata()[i]; - if (!m) - continue; - m = scrubReturnValue(loc, m); - elems->tdata()[i] = m; - } -} - - -Expression *ReturnStatement::interpret(InterState *istate) -{ -#if LOG - printf("ReturnStatement::interpret(%s)\n", exp ? exp->toChars() : ""); -#endif - START() - if (!exp) - return EXP_VOID_INTERPRET; - assert(istate && istate->fd && istate->fd->type); -#if DMDV2 - /* If the function returns a ref AND it's been called from an assignment, - * we need to return an lvalue. Otherwise, just do an (rvalue) interpret. - */ - if (istate->fd->type && istate->fd->type->ty==Tfunction) - { - TypeFunction *tf = (TypeFunction *)istate->fd->type; - if (tf->isref && istate->caller && istate->caller->awaitingLvalueReturn) - { // We need to return an lvalue - Expression *e = exp->interpret(istate, ctfeNeedLvalue); - if (e == EXP_CANT_INTERPRET) - error("ref return %s is not yet supported in CTFE", exp->toChars()); - return e; - } - if (tf->next && (tf->next->ty == Tdelegate) && istate->fd->closureVars.dim > 0) - { - // To support this, we need to copy all the closure vars - // into the delegate literal. - error("closures are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - } -#endif - // We need to treat pointers specially, because TOKsymoff can be used to - // return a value OR a pointer - Expression *e; - if ( isPointer(exp->type) ) - e = exp->interpret(istate, ctfeNeedLvalue); - else - e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (needToCopyLiteral(e)) - e = copyLiteral(e); -#if LOGASSIGN - printf("RETURN %s\n", loc.toChars()); - showCtfeExpr(e); -#endif - return e; -} - -Expression *BreakStatement::interpret(InterState *istate) -{ -#if LOG - printf("BreakStatement::interpret()\n"); -#endif - START() - if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); - assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; - istate->gotoTarget = s; - return EXP_BREAK_INTERPRET; - } - else - { - istate->gotoTarget = NULL; - return EXP_BREAK_INTERPRET; - } -} - -Expression *ContinueStatement::interpret(InterState *istate) -{ -#if LOG - printf("ContinueStatement::interpret()\n"); -#endif - START() - if (ident) - { LabelDsymbol *label = istate->fd->searchLabel(ident); - assert(label && label->statement); - Statement *s = label->statement; - if (s->isLabelStatement()) - s = s->isLabelStatement()->statement; - if (s->isScopeStatement()) - s = s->isScopeStatement()->statement; - istate->gotoTarget = s; - return EXP_CONTINUE_INTERPRET; - } - else - return EXP_CONTINUE_INTERPRET; -} - -Expression *WhileStatement::interpret(InterState *istate) -{ -#if LOG - printf("WhileStatement::interpret()\n"); -#endif - assert(0); // rewritten to ForStatement - return NULL; -} - -Expression *DoStatement::interpret(InterState *istate) -{ -#if LOG - printf("DoStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - return e; - } - if (e == EXP_CONTINUE_INTERPRET) - if (!istate->gotoTarget || istate->gotoTarget == this) - { - goto Lcontinue; - } - else // else continue at a higher level - return e; - if (e) - return e; - } - - while (1) - { - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - - Lcontinue: - istate->gotoTarget = NULL; - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (isTrueBool(e)) - { - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForStatement::interpret(InterState *istate) -{ -#if LOG - printf("ForStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e; - - if (init) - { - e = init->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - assert(!e); - } - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - return NULL; - } // else break at a higher level - } - if (e == EXP_CONTINUE_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - goto Lcontinue; - } // else continue at a higher level - } - if (e) - return e; - } - - while (1) - { - if (!condition) - goto Lhead; - e = condition->interpret(istate); - if (exceptionOrCantInterpret(e)) - break; - if (!e->isConst()) - { e = EXP_CANT_INTERPRET; - break; - } - if (isTrueBool(e)) - { - Lhead: - e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - break; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - break; - } - if (e && e != EXP_CONTINUE_INTERPRET) - break; - if (istate->gotoTarget && istate->gotoTarget != this) - break; // continue at a higher level - Lcontinue: - istate->gotoTarget = NULL; - if (increment) - { - e = increment->interpret(istate); - if (e == EXP_CANT_INTERPRET) - break; - } - } - else if (e->isBool(FALSE)) - { e = NULL; - break; - } - else - assert(0); - } - return e; -} - -Expression *ForeachStatement::interpret(InterState *istate) -{ - assert(0); // rewritten to ForStatement - return NULL; -} - -#if DMDV2 -Expression *ForeachRangeStatement::interpret(InterState *istate) -{ - assert(0); // rewritten to ForStatement - return NULL; -} -#endif - -Expression *SwitchStatement::interpret(InterState *istate) -{ -#if LOG - printf("SwitchStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - Expression *e = NULL; - - if (istate->start) - { - e = body ? body->interpret(istate) : NULL; - if (istate->start) - return NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - return NULL; - } // else break at a higher level - } - return e; - } - - - Expression *econdition = condition->interpret(istate); - if (exceptionOrCantInterpret(econdition)) - return econdition; - if (econdition->op == TOKslice) - econdition = resolveSlice(econdition); - - Statement *s = NULL; - if (cases) - { - for (size_t i = 0; i < cases->dim; i++) - { - CaseStatement *cs = cases->tdata()[i]; - Expression * caseExp = cs->exp->interpret(istate); - if (exceptionOrCantInterpret(caseExp)) - return caseExp; - e = ctfeEqual(TOKequal, Type::tint32, econdition, caseExp); - if (exceptionOrCantInterpret(e)) - return e; - if (e->isBool(TRUE)) - { s = cs; - break; - } - } - } - if (!s) - { if (hasNoDefault) - error("no default or case for %s in switch statement", econdition->toChars()); - s = sdefault; - } - -#if IN_LLVM - if (!s) - return EXP_CANT_INTERPRET; -#endif - assert(s); - istate->start = s; - e = body ? body->interpret(istate) : NULL; - assert(!istate->start); - if (e == EXP_BREAK_INTERPRET) - { - if (!istate->gotoTarget || istate->gotoTarget == this) - { - istate->gotoTarget = NULL; - e = NULL; - } // else break at a higher level - } - return e; -} - -Expression *CaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("CaseStatement::interpret(%s) this = %p\n", exp->toChars(), this); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *DefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("DefaultStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - if (statement) - return statement->interpret(istate); - else - return NULL; -} - -Expression *GotoStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoStatement::interpret()\n"); -#endif - START() - assert(label && label->statement); - istate->gotoTarget = label->statement; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoCaseStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoCaseStatement::interpret()\n"); -#endif - START() - assert(cs); - istate->gotoTarget = cs; - return EXP_GOTO_INTERPRET; -} - -Expression *GotoDefaultStatement::interpret(InterState *istate) -{ -#if LOG - printf("GotoDefaultStatement::interpret()\n"); -#endif - START() - assert(sw && sw->sdefault); - istate->gotoTarget = sw->sdefault; - return EXP_GOTO_INTERPRET; -} - -Expression *LabelStatement::interpret(InterState *istate) -{ -#if LOG - printf("LabelStatement::interpret()\n"); -#endif - if (istate->start == this) - istate->start = NULL; - return statement ? statement->interpret(istate) : NULL; -} - - -Expression *TryCatchStatement::interpret(InterState *istate) -{ -#if LOG - printf("TryCatchStatement::interpret()\n"); -#endif - START() - Expression *e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - return e; - if (!exceptionOrCantInterpret(e)) - return e; - // An exception was thrown - ThrownExceptionExp *ex = (ThrownExceptionExp *)e; - Type *extype = ex->thrown->originalClass()->type; - // Search for an appropriate catch clause. - for (size_t i = 0; i < catches->dim; i++) - { -#if DMDV1 - Catch *ca = (Catch *)catches->data[i]; -#else - Catch *ca = catches->tdata()[i]; -#endif - Type *catype = ca->type; - - if (catype->equals(extype) || catype->isBaseOf(extype, NULL)) - { // Execute the handler - if (ca->var) - { - ctfeStack.push(ca->var); - ca->var->setValue(ex->thrown); - } - return ca->handler->interpret(istate); - } - } - return e; -} - -bool isAnErrorException(ClassDeclaration *cd) -{ - return cd == ClassDeclaration::errorException || ClassDeclaration::errorException->isBaseOf(cd, NULL); -} - -ThrownExceptionExp *chainExceptions(ThrownExceptionExp *oldest, ThrownExceptionExp *newest) -{ -#if LOG - printf("Collided exceptions %s %s\n", oldest->thrown->toChars(), newest->thrown->toChars()); -#endif -#if DMDV2 - // Little sanity check to make sure it's really a Throwable - ClassReferenceExp *boss = oldest->thrown; - assert(boss->value->elements->tdata()[4]->type->ty == Tclass); - ClassReferenceExp *collateral = newest->thrown; - if (isAnErrorException(collateral->originalClass()) - && !isAnErrorException(boss->originalClass())) - { // The new exception bypass the existing chain - assert(collateral->value->elements->tdata()[5]->type->ty == Tclass); - collateral->value->elements->tdata()[5] = boss; - return newest; - } - while (boss->value->elements->tdata()[4]->op == TOKclassreference) - { - boss = (ClassReferenceExp *)(boss->value->elements->tdata()[4]); - } - boss->value->elements->tdata()[4] = collateral; - return oldest; -#else - // for D1, the newest exception just clobbers the older one - return newest; -#endif -} - - -Expression *TryFinallyStatement::interpret(InterState *istate) -{ -#if LOG - printf("TryFinallyStatement::interpret()\n"); -#endif - START() - Expression *e = body ? body->interpret(istate) : NULL; - if (e == EXP_CANT_INTERPRET) - return e; - Expression *second = finalbody ? finalbody->interpret(istate) : NULL; - if (second == EXP_CANT_INTERPRET) - return second; - if (exceptionOrCantInterpret(second)) - { // Check for collided exceptions - if (exceptionOrCantInterpret(e)) - e = chainExceptions((ThrownExceptionExp *)e, (ThrownExceptionExp *)second); - else - e = second; - } - return e; -} - -Expression *ThrowStatement::interpret(InterState *istate) -{ -#if LOG - printf("ThrowStatement::interpret()\n"); -#endif - START() - Expression *e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - assert(e->op == TOKclassreference); - return new ThrownExceptionExp(loc, (ClassReferenceExp *)e); -} - -Expression *OnScopeStatement::interpret(InterState *istate) -{ - assert(0); - return EXP_CANT_INTERPRET; -} - -Expression *WithStatement::interpret(InterState *istate) -{ -#if LOG - printf("WithStatement::interpret()\n"); -#endif - START() - Expression *e = exp->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (wthis->type->ty == Tpointer && exp->type->ty != Tpointer) - { - e = new AddrExp(loc, e); - e->type = wthis->type; - } - ctfeStack.push(wthis); - wthis->setValue(e); - e = body ? body->interpret(istate) : EXP_VOID_INTERPRET; - ctfeStack.pop(wthis); - return e; -} - -Expression *AsmStatement::interpret(InterState *istate) -{ -#if LOG - printf("AsmStatement::interpret()\n"); -#endif - START() - error("asm statements cannot be interpreted at compile time"); - return EXP_CANT_INTERPRET; -} - -#if DMDV2 -Expression *ImportStatement::interpret(InterState *istate) -{ -#if LOG - printf("ImportStatement::interpret()\n"); -#endif - START(); - return NULL; -} -#endif - -/******************************** Expression ***************************/ - -Expression *Expression::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("Expression::interpret() %s\n", toChars()); - printf("type = %s\n", type->toChars()); - dump(0); -#endif - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *ThisExp::interpret(InterState *istate, CtfeGoal goal) -{ - while (istate && !istate->localThis) - istate = istate->caller; - if (istate && istate->localThis && istate->localThis->op == TOKstructliteral) - return istate->localThis; - if (istate && istate->localThis) - return istate->localThis->interpret(istate, goal); - error("value of 'this' is not known at compile time"); - return EXP_CANT_INTERPRET; -} - -Expression *NullExp::interpret(InterState *istate, CtfeGoal goal) -{ - return this; -} - -Expression *IntegerExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("IntegerExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *RealExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("RealExp::interpret() %s\n", toChars()); -#endif - return this; -} - -Expression *ComplexExp::interpret(InterState *istate, CtfeGoal goal) -{ - return this; -} - -Expression *StringExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("StringExp::interpret() %s\n", toChars()); -#endif - /* In both D1 and D2, attempts to modify string literals are prevented - * in BinExp::interpretAssignCommon. - * In D2, we also disallow casts of read-only literals to mutable, - * though it isn't strictly necessary. - */ -#if DMDV2 - // Fixed-length char arrays always get duped later anyway. - if (type->ty == Tsarray) - return this; - if (!(((TypeNext *)type)->next->mod & (MODconst | MODimmutable))) - { // It seems this happens only when there has been an explicit cast - error("cannot cast a read-only string literal to mutable in CTFE"); - return EXP_CANT_INTERPRET; - } -#endif - return this; -} - -Expression *FuncExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("FuncExp::interpret() %s\n", toChars()); -#endif - return this; -} - -/* Is it safe to convert from srcPointee* to destPointee* ? - * srcPointee is the genuine type (never void). - * destPointee may be void. - */ -bool isSafePointerCast(Type *srcPointee, Type *destPointee) -{ // It's OK if both are the same (modulo const) -#if DMDV2 - if (srcPointee->castMod(0) == destPointee->castMod(0)) - return true; -#else - if (srcPointee == destPointee) - return true; -#endif - // it's OK to cast to void* - if (destPointee->ty == Tvoid) - return true; - // It's OK if they are the same size integers, eg int* and uint* - return srcPointee->isintegral() && destPointee->isintegral() - && srcPointee->size() == destPointee->size(); -} - -Expression *SymOffExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("SymOffExp::interpret() %s\n", toChars()); -#endif - if (var->isFuncDeclaration() && offset == 0) - { - return this; - } - if (type->ty != Tpointer) - { // Probably impossible - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - Type *pointee = ((TypePointer *)type)->next; - Expression *val = getVarExp(loc, istate, var, goal); - if (val->type->ty == Tarray || val->type->ty == Tsarray) - { - // Check for unsupported type painting operations - Type *elemtype = ((TypeArray *)(val->type))->next; - - // It's OK to cast from fixed length to dynamic array, eg &int[3] to int[]* - if (val->type->ty == Tsarray && pointee->ty == Tarray - && elemtype->size() == pointee->nextOf()->size()) - { - Expression *e = new AddrExp(loc, val); - e->type = type; - return e; - } - if ( !isSafePointerCast(elemtype, pointee) ) - { // It's also OK to cast from &string to string*. - if ( offset == 0 && isSafePointerCast(var->type, pointee) ) - { - VarExp *ve = new VarExp(loc, var); - ve->type = type; - return ve; - } - error("reinterpreting cast from %s to %s is not supported in CTFE", - val->type->toChars(), type->toChars()); - return EXP_CANT_INTERPRET; - } - - TypeArray *tar = (TypeArray *)val->type; - dinteger_t sz = pointee->size(); - dinteger_t indx = offset/sz; - assert(sz * indx == offset); - Expression *aggregate = NULL; - if (val->op == TOKarrayliteral || val->op == TOKstring) - aggregate = val; - else if (val->op == TOKslice) - { - aggregate = ((SliceExp *)val)->e1; - Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate); - indx += lwr->toInteger(); - } - if (aggregate) - { - IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); - IndexExp *ie = new IndexExp(loc, aggregate, ofs); - ie->type = type; - return ie; - } - } - else if ( offset == 0 && isSafePointerCast(var->type, pointee) ) - { - VarExp *ve = new VarExp(loc, var); - ve->type = type; - return ve; - } - - error("Cannot convert &%s to %s at compile time", var->type->toChars(), type->toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *AddrExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("AddrExp::interpret() %s\n", toChars()); -#endif -#if IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (ve->var->isFuncDeclaration()) - return this; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - if (type->ty != Tpointer) - { // Probably impossible - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - Type *pointee = ((TypePointer *)type)->next; - if (isSafePointerCast(ve->var->type, pointee)) - { - ve = new VarExp(loc, ve->var); - ve->type = type; - return ve; - } - } - } - else if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)e1; - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) { - dinteger_t indx = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (/*ve->type->ty == Tarray || */ve->type->ty == Tsarray) - { - Expression *val = getVarExp(loc, istate, ve->var, goal); - - Expression *aggregate = NULL; - if (val->op == TOKarrayliteral || val->op == TOKstring) - aggregate = val; - else if (val->op == TOKslice) - { - aggregate = ((SliceExp *)val)->e1; - Expression *lwr = ((SliceExp *)val)->lwr->interpret(istate); - indx += lwr->toInteger(); - } - if (aggregate) - { - IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); - IndexExp *ie = new IndexExp(loc, aggregate, ofs); - ie->type = type; - return ie; - } - } - } - } -#endif - - // For reference types, we need to return an lvalue ref. - TY tb = e1->type->toBasetype()->ty; - bool needRef = (tb == Tarray || tb == Taarray || tb == Tclass); - Expression *e = e1->interpret(istate, needRef ? ctfeNeedLvalueRef : ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - // Return a simplified address expression - e = new AddrExp(loc, e); - e->type = type; - return e; -} - -Expression *DelegateExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("DelegateExp::interpret() %s\n", toChars()); -#endif - return this; -} - -// ------------------------------------------------------------- -// Remove out, ref, and this -// ------------------------------------------------------------- -// The variable used in a dotvar, index, or slice expression, -// after 'out', 'ref', and 'this' have been removed. -Expression * resolveReferences(Expression *e, Expression *thisval) -{ - for(;;) - { - if (e->op == TOKthis) - { - assert(thisval); - assert(e != thisval); - e = thisval; - continue; - } - if (e->op == TOKvar) - { - VarExp *ve = (VarExp *)e; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (v->type->ty == Tpointer) - break; - if (v->ctfeAdrOnStack == (size_t)-1) // If not on the stack, can't possibly be a ref. - break; - if (v && v->getValue() && (v->getValue()->op == TOKslice)) - { - SliceExp *se = (SliceExp *)v->getValue(); - if (se->e1->op == TOKarrayliteral || se->e1->op == TOKassocarrayliteral || se->e1->op == TOKstring) - break; - e = v->getValue(); - continue; - } - else if (v && v->getValue() && (v->getValue()->op==TOKindex || v->getValue()->op == TOKdotvar - || v->getValue()->op == TOKthis )) - { - e = v->getValue(); - continue; - } - } - break; - } - return e; -} - -Expression *getVarExp(Loc loc, InterState *istate, Declaration *d, CtfeGoal goal) -{ - Expression *e = EXP_CANT_INTERPRET; - VarDeclaration *v = d->isVarDeclaration(); -#if IN_LLVM - StaticStructInitDeclaration *s = d->isStaticStructInitDeclaration(); -#else - SymbolDeclaration *s = d->isSymbolDeclaration(); -#endif - if (v) - { -#if DMDV2 - /* Magic variable __ctfe always returns true when interpreting - */ - if (v->ident == Id::ctfe) - return new IntegerExp(loc, 1, Type::tbool); - if ((v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) && v->init && !v->hasValue()) -#else - if (v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (e && (e->op == TOKconstruct || e->op == TOKblit)) - { AssignExp *ae = (AssignExp *)e; - e = ae->e2; - v->inuse++; - e = e->interpret(istate, ctfeNeedAnyValue); - v->inuse--; - if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - errorSupplemental(loc, "while evaluating %s.init", v->toChars()); - if (exceptionOrCantInterpret(e)) - return e; - e->type = v->type; - } - else - { - if (e && !e->type) - e->type = v->type; - if (e) - e = e->interpret(istate, ctfeNeedAnyValue); - if (e == EXP_CANT_INTERPRET && !global.gag && !CtfeStatus::stackTraceCallsToSuppress) - errorSupplemental(loc, "while evaluating %s.init", v->toChars()); - } - if (e && e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - { - e = copyLiteral(e); - if (v->isDataseg()) - ctfeStack.saveGlobalConstant(v, e); - else - v->setValueWithoutChecking(e); - } - } - else if (v->isCTFE() && !v->hasValue()) - { - if (v->init && v->type->size() != 0) - { - if (v->init->isVoidInitializer()) - { - error(loc, "variable %s is used before initialization", v->toChars()); - return EXP_CANT_INTERPRET; - } - e = v->init->toExpression(); - e = e->interpret(istate); - } - else - e = v->type->defaultInitLiteral(loc); - } - else if (!v->isDataseg() && !v->isCTFE() && !istate) - { error(loc, "variable %s cannot be read at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - else - { e = v->hasValue() ? v->getValue() : NULL; - if (!e && !v->isCTFE() && v->isDataseg()) - { error(loc, "static variable %s cannot be read at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; - } - else if (!e) - error(loc, "variable %s is used before initialization", v->toChars()); - else if (exceptionOrCantInterpret(e)) - return e; - else if (goal == ctfeNeedLvalue && v->isRef() && e->op == TOKindex) - { // If it is a foreach ref, resolve the index into a constant - IndexExp *ie = (IndexExp *)e; - Expression *w = ie->e2->interpret(istate); - if (w != ie->e2) - { - e = new IndexExp(ie->loc, ie->e1, w); - e->type = ie->type; - } - return e; - } - else if ((goal == ctfeNeedLvalue) - || e->op == TOKstring || e->op == TOKstructliteral || e->op == TOKarrayliteral - || e->op == TOKassocarrayliteral || e->op == TOKslice - || e->type->toBasetype()->ty == Tpointer) - return e; // it's already an Lvalue - else - e = e->interpret(istate, goal); - } - if (!e) - e = EXP_CANT_INTERPRET; - } - else if (s) - { // Struct static initializers, for example -#if !IN_LLVM - if (s->dsym->toInitializer() == s->sym) -#endif - { e = s->dsym->type->defaultInitLiteral(); - e = e->semantic(NULL); - if (e->op == TOKerror) - e = EXP_CANT_INTERPRET; - } -#if !IN_LLVM - else - error(loc, "cannot interpret symbol %s at compile time", v->toChars()); -#endif - } - else - error(loc, "cannot interpret declaration %s at compile time", d->toChars()); - return e; -} - -Expression *VarExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("VarExp::interpret() %s\n", toChars()); -#endif - if (goal == ctfeNeedLvalueRef) - { - VarDeclaration *v = var->isVarDeclaration(); - if (v && !v->isDataseg() && !v->isCTFE() && !istate) - { error("variable %s cannot be referenced at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - else if (v && !v->hasValue() && !v->isCTFE() && v->isDataseg()) - { error("static variable %s cannot be referenced at compile time", v->toChars()); - return EXP_CANT_INTERPRET; - } - return this; - } - Expression *e = getVarExp(loc, istate, var, goal); - // A VarExp may include an implicit cast. It must be done explicitly. - if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - e = paintTypeOntoLiteral(type, e); - return e; -} - -Expression *DeclarationExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("DeclarationExp::interpret() %s\n", toChars()); -#endif - Expression *e; - VarDeclaration *v = declaration->isVarDeclaration(); - if (v) - { - if (v->toAlias()->isTupleDeclaration()) - { // Reserve stack space for all tuple members - TupleDeclaration *td =v->toAlias()->isTupleDeclaration(); - if (!td->objects) - return NULL; - for(int i= 0; i < td->objects->dim; ++i) - { - Object * o = td->objects->tdata()[i]; - Expression *ex = isExpression(o); - DsymbolExp *s = (ex && ex->op == TOKdsymbol) ? (DsymbolExp *)ex : NULL; - VarDeclaration *v2 = s ? s->s->isVarDeclaration() : NULL; - assert(v2); - if (!v2->isDataseg() || v2->isCTFE()) - ctfeStack.push(v2); - } - } - if (!v->isDataseg() || v->isCTFE()) - ctfeStack.push(v); - Dsymbol *s = v->toAlias(); - if (s == v && !v->isStatic() && v->init) - { - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie) - e = ie->exp->interpret(istate); - else if (v->init->isVoidInitializer()) - e = NULL; - else - { - error("Declaration %s is not yet implemented in CTFE", toChars()); - e = EXP_CANT_INTERPRET; - } - } - else if (s == v && !v->init && v->type->size()==0) - { // Zero-length arrays don't need an initializer - e = v->type->defaultInitLiteral(loc); - } -#if DMDV2 - else if (s == v && (v->isConst() || v->isImmutable()) && v->init) -#else - else if (s == v && v->isConst() && v->init) -#endif - { e = v->init->toExpression(); - if (!e) - e = EXP_CANT_INTERPRET; - else if (!e->type) - e->type = v->type; - } - else if (s->isTupleDeclaration() && !v->init) - e = NULL; - else if (v->isStatic() && !v->init) - e = NULL; // Just ignore static variables which aren't read or written yet - else - { - error("Static variable %s cannot be modified at compile time", v->toChars()); - e = EXP_CANT_INTERPRET; - } - } - else if (declaration->isAttribDeclaration() || - declaration->isTemplateMixin() || - declaration->isTupleDeclaration()) - { // Check for static struct declarations, which aren't executable - AttribDeclaration *ad = declaration->isAttribDeclaration(); - if (ad && ad->decl && ad->decl->dim == 1 - && ad->decl->tdata()[0]->isAggregateDeclaration()) - return NULL; // static struct declaration. Nothing to do. - - // These can be made to work, too lazy now - error("Declaration %s is not yet implemented in CTFE", toChars()); - e = EXP_CANT_INTERPRET; - } - else - { // Others should not contain executable code, so are trivial to evaluate - e = NULL; - } -#if LOG - printf("-DeclarationExp::interpret(%s): %p\n", toChars(), e); -#endif - return e; -} - -Expression *TupleExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("TupleExp::interpret() %s\n", toChars()); -#endif - Expressions *expsx = NULL; - - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; - Expression *ex; - - ex = e->interpret(istate); - if (exceptionOrCantInterpret(ex)) - { delete expsx; - return ex; - } - - // A tuple of assignments can contain void (Bug 5676). - if (goal == ctfeNeedNothing) - continue; - if (ex == EXP_VOID_INTERPRET) - { - error("ICE: void element %s in tuple", e->toChars()); - assert(0); - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(exps->dim); - for (size_t j = 0; j < i; j++) - { - expsx->tdata()[j] = exps->tdata()[j]; - } - } - expsx->tdata()[i] = ex; - } - } - if (expsx) - { TupleExp *te = new TupleExp(loc, expsx); - expandTuples(te->exps); - te->type = new TypeTuple(te->exps); - return te; - } - return this; -} - -Expression *ArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *expsx = NULL; - -#if LOG - printf("ArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (ownedByCtfe) // We've already interpreted all the elements - return copyLiteral(this); - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - Expression *ex; - - if (e->op == TOKindex) // segfault bug 6250 - assert( ((IndexExp*)e)->e1 != this); - ex = e->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerror; - if (ex->op == TOKthrownexception) - return ex; - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->tdata()[j] = elements->tdata()[j]; - } - } - expsx->tdata()[i] = ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - goto Lerror; - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, expsx); - ae->type = type; - return copyLiteral(ae); - } -#if DMDV2 - if (((TypeNext *)type)->next->mod & (MODconst | MODimmutable)) - { // If it's immutable, we don't need to dup it - return this; - } -#endif - return copyLiteral(this); - -Lerror: - if (expsx) - delete expsx; - error("cannot interpret array literal"); - return EXP_CANT_INTERPRET; -} - -Expression *AssocArrayLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *keysx = keys; - Expressions *valuesx = values; - -#if LOG - printf("AssocArrayLiteralExp::interpret() %s\n", toChars()); -#endif - if (ownedByCtfe) // We've already interpreted all the elements - return copyLiteral(this); - for (size_t i = 0; i < keys->dim; i++) - { Expression *ekey = keys->tdata()[i]; - Expression *evalue = values->tdata()[i]; - Expression *ex; - - ex = ekey->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) - return ex; - - - /* If any changes, do Copy On Write - */ - if (ex != ekey) - { - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - keysx->tdata()[i] = ex; - } - - ex = evalue->interpret(istate); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->op == TOKthrownexception) - return ex; - - /* If any changes, do Copy On Write - */ - if (ex != evalue) - { - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - valuesx->tdata()[i] = ex; - } - } - if (keysx != keys) - expandTuples(keysx); - if (valuesx != values) - expandTuples(valuesx); - if (keysx->dim != valuesx->dim) - goto Lerr; - - /* Remove duplicate keys - */ - for (size_t i = 1; i < keysx->dim; i++) - { Expression *ekey = keysx->tdata()[i - 1]; - if (ekey->op == TOKslice) - ekey = resolveSlice(ekey); - for (size_t j = i; j < keysx->dim; j++) - { Expression *ekey2 = keysx->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, ekey2); - if (ex == EXP_CANT_INTERPRET) - goto Lerr; - if (ex->isBool(TRUE)) // if a match - { - // Remove ekey - if (keysx == keys) - keysx = (Expressions *)keys->copy(); - if (valuesx == values) - valuesx = (Expressions *)values->copy(); - keysx->remove(i - 1); - valuesx->remove(i - 1); - i -= 1; // redo the i'th iteration - break; - } - } - } - - if (keysx != keys || valuesx != values) - { - AssocArrayLiteralExp *ae; - ae = new AssocArrayLiteralExp(loc, keysx, valuesx); - ae->type = type; - ae->ownedByCtfe = true; - return ae; - } - return this; - -Lerr: - if (keysx != keys) - delete keysx; - if (valuesx != values) - delete values; - return EXP_CANT_INTERPRET; -} - -Expression *StructLiteralExp::interpret(InterState *istate, CtfeGoal goal) -{ Expressions *expsx = NULL; - -#if LOG - printf("StructLiteralExp::interpret() %s\n", toChars()); -#endif - /* We don't know how to deal with overlapping fields - */ - if (sd->hasUnions) - { error("Unions with overlapping fields are not yet supported in CTFE"); - return EXP_CANT_INTERPRET; - } - if (ownedByCtfe) - return copyLiteral(this); - - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - if (!e) - continue; - - Expression *ex = e->interpret(istate); - if (exceptionOrCantInterpret(ex)) - { delete expsx; - return ex; - } - - /* If any changes, do Copy On Write - */ - if (ex != e) - { - if (!expsx) - { expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(elements->dim); - for (size_t j = 0; j < elements->dim; j++) - { - expsx->tdata()[j] = elements->tdata()[j]; - } - } - expsx->tdata()[i] = ex; - } - } - } - if (elements && expsx) - { - expandTuples(expsx); - if (expsx->dim != elements->dim) - { delete expsx; - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = new StructLiteralExp(loc, sd, expsx); - se->type = type; - se->ownedByCtfe = true; - return se; - } - return copyLiteral(this); -} - -/****************************** - * Helper for NewExp - * Create an array literal consisting of 'elem' duplicated 'dim' times. - */ -ArrayLiteralExp *createBlockDuplicatedArrayLiteral(Loc loc, Type *type, - Expression *elem, size_t dim) -{ - Expressions *elements = new Expressions(); - elements->setDim(dim); - bool mustCopy = needToCopyLiteral(elem); - for (size_t i = 0; i < dim; i++) - { if (mustCopy) - elem = copyLiteral(elem); - elements->tdata()[i] = elem; - } - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); - ae->type = type; - ae->ownedByCtfe = true; - return ae; -} - -/****************************** - * Helper for NewExp - * Create a string literal consisting of 'value' duplicated 'dim' times. - */ -StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type, - unsigned value, size_t dim, int sz) -{ - unsigned char *s; - s = (unsigned char *)mem.calloc(dim + 1, sz); - for (size_t elemi=0; elemitype = type; - se->sz = sz; - se->committed = true; - se->ownedByCtfe = true; - return se; -} - -// Create an array literal of type 'newtype' with dimensions given by -// 'arguments'[argnum..$] -Expression *recursivelyCreateArrayLiteral(Loc loc, Type *newtype, InterState *istate, - Expressions *arguments, int argnum) -{ - Expression *lenExpr = ((arguments->tdata()[argnum]))->interpret(istate); - if (exceptionOrCantInterpret(lenExpr)) - return lenExpr; - size_t len = (size_t)(lenExpr->toInteger()); - Type *elemType = ((TypeArray *)newtype)->next; - if (elemType->ty == Tarray && argnum < arguments->dim - 1) - { - Expression *elem = recursivelyCreateArrayLiteral(loc, elemType, istate, - arguments, argnum + 1); - if (exceptionOrCantInterpret(elem)) - return elem; - - Expressions *elements = new Expressions(); - elements->setDim(len); - for (size_t i = 0; i < len; i++) - elements->tdata()[i] = copyLiteral(elem); - ArrayLiteralExp *ae = new ArrayLiteralExp(loc, elements); - ae->type = newtype; - ae->ownedByCtfe = true; - return ae; - } - assert(argnum == arguments->dim - 1); - if (elemType->ty == Tchar || elemType->ty == Twchar - || elemType->ty == Tdchar) - return createBlockDuplicatedStringLiteral(loc, newtype, - (unsigned)(elemType->defaultInitLiteral()->toInteger()), - len, elemType->size()); - return createBlockDuplicatedArrayLiteral(loc, newtype, - elemType->defaultInitLiteral(), - len); -} - -Expression *NewExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("NewExp::interpret() %s\n", toChars()); -#endif - if (newtype->ty == Tarray && arguments) - return recursivelyCreateArrayLiteral(loc, newtype, istate, arguments, 0); - - if (newtype->toBasetype()->ty == Tstruct) - { - Expression *se = newtype->defaultInitLiteral(); -#if DMDV2 - if (member) - { - int olderrors = global.errors; - member->interpret(istate, arguments, se); - if (olderrors != global.errors) - { - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - } -#else // The above code would fail on D1 because it doesn't use STRUCTTHISREF, - // but that's OK because D1 doesn't have struct constructors anyway. - assert(!member); -#endif - Expression *e = new AddrExp(loc, copyLiteral(se)); - e->type = type; - return e; - } - if (newtype->toBasetype()->ty == Tclass) - { - ClassDeclaration *cd = ((TypeClass *)newtype->toBasetype())->sym; - size_t totalFieldCount = 0; - for (ClassDeclaration *c = cd; c; c = c->baseClass) - totalFieldCount += c->fields.dim; - Expressions *elems = new Expressions; - elems->setDim(totalFieldCount); - size_t fieldsSoFar = totalFieldCount; - for (ClassDeclaration *c = cd; c; c = c->baseClass) - { - fieldsSoFar -= c->fields.dim; - for (size_t i = 0; i < c->fields.dim; i++) - { - Dsymbol *s = c->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - Expression *m = v->init ? v->init->toExpression() : v->type->defaultInitLiteral(); - if (exceptionOrCantInterpret(m)) - return m; - elems->tdata()[fieldsSoFar+i] = copyLiteral(m); - } - } - // Hack: we store a ClassDeclaration instead of a StructDeclaration. - // We probably won't get away with this. - StructLiteralExp *se = new StructLiteralExp(loc, (StructDeclaration *)cd, elems, newtype); - se->ownedByCtfe = true; - Expression *e = new ClassReferenceExp(loc, se, type); - if (member) - { // Call constructor - if (!member->fbody) - { - Expression *ctorfail = evaluateIfBuiltin(istate, loc, member, arguments, e); - if (ctorfail && exceptionOrCantInterpret(ctorfail)) - return ctorfail; - if (ctorfail) - return e; - member->error("%s cannot be constructed at compile time, because the constructor has no available source code", newtype->toChars()); - return EXP_CANT_INTERPRET; - } - Expression * ctorfail = member->interpret(istate, arguments, e); - if (exceptionOrCantInterpret(ctorfail)) - return ctorfail; - } - return e; - } - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; -} - -Expression *UnaExp::interpretCommon(InterState *istate, CtfeGoal goal, Expression *(*fp)(Type *, Expression *)) -{ Expression *e; - Expression *e1; - -#if LOG - printf("UnaExp::interpretCommon() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e = (*fp)(type, e1); - return e; -} - -#define UNA_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon(istate, goal, &op); \ -} - -UNA_INTERPRET(Neg) -UNA_INTERPRET(Com) -UNA_INTERPRET(Not) -UNA_INTERPRET(Bool) - -Expression *getAggregateFromPointer(Expression *e, dinteger_t *ofs) -{ - *ofs = 0; - if (e->op == TOKaddress) - e = ((AddrExp *)e)->e1; - if (e->op == TOKdotvar) - { - Expression *ex = ((DotVarExp *)e)->e1; - VarDeclaration *v = ((DotVarExp *)e)->var->isVarDeclaration(); - assert(v); - StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; - // We can't use getField, because it makes a copy - int i = -1; - if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->getFieldIndex(e->type, v->offset); - else - i = se->getFieldIndex(e->type, v->offset); - assert(i != -1); - e = se->elements->tdata()[i]; - } - if (e->op == TOKindex) - { - IndexExp *ie = (IndexExp *)e; - // Note that each AA element is part of its own memory block - if ((ie->e1->type->ty == Tarray || ie->e1->type->ty == Tsarray - || ie->e1->op == TOKstring || ie->e1->op==TOKarrayliteral) && - ie->e2->op == TOKint64) - { - *ofs = ie->e2->toInteger(); - return ie->e1; - } - } - return e; -} - -// return e1 - e2 as an integer, or error if not possible -Expression *pointerDifference(Loc loc, Type *type, Expression *e1, Expression *e2) -{ - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - if (agg1 == agg2) - { - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); - } - else if (agg1->op == TOKstring && agg2->op == TOKstring) - { - if (((StringExp *)agg1)->string == ((StringExp *)agg2)->string) - { - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - return new IntegerExp(loc, (ofs1-ofs2)*sz, type); - } - } -#if LOGASSIGN - printf("FAILED POINTER DIFF\n"); - showCtfeExpr(agg1); - showCtfeExpr(agg2); -#endif - error(loc, "%s - %s cannot be interpreted at compile time: cannot subtract " - "pointers to two different memory blocks", - e1->toChars(), e2->toChars()); - return EXP_CANT_INTERPRET; -} - -// Return eptr op e2, where eptr is a pointer, e2 is an integer, -// and op is TOKadd or TOKmin -Expression *pointerArithmetic(Loc loc, enum TOK op, Type *type, - Expression *eptr, Expression *e2) -{ - if (eptr->type->nextOf()->ty == Tvoid) - { - error(loc, "cannot perform arithmetic on void* pointers at compile time"); - return EXP_CANT_INTERPRET; - } - dinteger_t ofs1, ofs2; - if (eptr->op == TOKaddress) - eptr = ((AddrExp *)eptr)->e1; - Expression *agg1 = getAggregateFromPointer(eptr, &ofs1); - if (agg1->op != TOKstring && agg1->op != TOKarrayliteral) - { - error(loc, "cannot perform pointer arithmetic on non-arrays at compile time"); - return EXP_CANT_INTERPRET; - } - ofs2 = e2->toInteger(); - Type *pointee = ((TypePointer *)agg1->type)->next; - dinteger_t sz = pointee->size(); - Expression *dollar = ArrayLength(Type::tsize_t, agg1); - assert(dollar != EXP_CANT_INTERPRET); - dinteger_t len = dollar->toInteger(); - - Expression *val = agg1; - TypeArray *tar = (TypeArray *)val->type; - dinteger_t indx = ofs1; -#if IN_LLVM // LDC: llvm uses typesafe pointer arithmetic - if (op == TOKadd || op == TOKaddass || op == TOKplusplus) - indx += ofs2; - else if (op == TOKmin || op == TOKminass || op == TOKminusminus) - indx -= ofs2; -#else - if (op == TOKadd || op == TOKaddass || op == TOKplusplus) - indx = indx + ofs2/sz; - else if (op == TOKmin || op == TOKminass || op == TOKminusminus) - indx -= ofs2/sz; -#endif - else - { - error(loc, "CTFE Internal compiler error: bad pointer operation"); - return EXP_CANT_INTERPRET; - } - if (val->op != TOKarrayliteral && val->op != TOKstring) - { - error(loc, "CTFE Internal compiler error: pointer arithmetic %s", val->toChars()); - return EXP_CANT_INTERPRET; - } - if (indx < 0 || indx > len) - { - error(loc, "cannot assign pointer to index %jd inside memory block [0..%jd]", indx, len); - return EXP_CANT_INTERPRET; - } - - IntegerExp *ofs = new IntegerExp(loc, indx, Type::tsize_t); - IndexExp *ie = new IndexExp(loc, val, ofs); - ie->type = type; - return ie; -} - -typedef Expression *(*fp_t)(Type *, Expression *, Expression *); - -Expression *BinExp::interpretCommon(InterState *istate, CtfeGoal goal, fp_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon() %s\n", toChars()); -#endif - if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer && op == TOKmin) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e2; - return pointerDifference(loc, type, e1, e2); - } - if (this->e1->type->ty == Tpointer && this->e2->type->isintegral()) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - return pointerArithmetic(loc, op, type, e1, e2); - } - if (this->e2->type->ty == Tpointer && this->e1->type->isintegral() && op==TOKadd) - { - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e1; - return pointerArithmetic(loc, op, type, e2, e1); - } - if (this->e1->type->ty == Tpointer || this->e2->type->ty == Tpointer) - { - error("pointer expression %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->isConst() != 1) - goto Lcant; - - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->isConst() != 1) - goto Lcant; - - e = (*fp)(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET(op) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon(istate, goal, &op); \ -} - -BIN_INTERPRET(Add) -BIN_INTERPRET(Min) -BIN_INTERPRET(Mul) -BIN_INTERPRET(Div) -BIN_INTERPRET(Mod) -BIN_INTERPRET(Shl) -BIN_INTERPRET(Shr) -BIN_INTERPRET(Ushr) -BIN_INTERPRET(And) -BIN_INTERPRET(Or) -BIN_INTERPRET(Xor) -#if DMDV2 -BIN_INTERPRET(Pow) -#endif - - -typedef Expression *(*fp2_t)(enum TOK, Type *, Expression *, Expression *); - -// Return EXP_CANT_INTERPRET if they point to independent memory blocks -Expression *comparePointers(Loc loc, enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - dinteger_t ofs1, ofs2; - Expression *agg1 = getAggregateFromPointer(e1, &ofs1); - Expression *agg2 = getAggregateFromPointer(e2, &ofs2); - // Note that type painting can occur with VarExp, so we - // must compare the variables being pointed to. - if (agg1 == agg2 || - (agg1->op == TOKvar && agg2->op == TOKvar && - ((VarExp *)agg1)->var == ((VarExp *)agg2)->var) - ) - { - dinteger_t cm = ofs1 - ofs2; - dinteger_t n; - dinteger_t zero = 0; - switch(op) - { - case TOKlt: n = (ofs1 < ofs2); break; - case TOKle: n = (ofs1 <= ofs2); break; - case TOKgt: n = (ofs1 > ofs2); break; - case TOKge: n = (ofs1 >= ofs2); break; - case TOKidentity: - case TOKequal: n = (ofs1 == ofs2); break; - case TOKnotidentity: - case TOKnotequal: n = (ofs1 != ofs2); break; - default: - assert(0); - } - return new IntegerExp(loc, n, type); - } - int cmp; - if (agg1->op == TOKnull) - { - cmp = (agg2->op == TOKnull); - } - else if (agg2->op == TOKnull) - { - cmp = 0; - } - else - { - switch(op) - { - case TOKidentity: - case TOKequal: - case TOKnotidentity: // 'cmp' gets inverted below - case TOKnotequal: - cmp = 0; - break; - default: - return EXP_CANT_INTERPRET; - } - } - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(loc, cmp, type); -} - -Expression *ctfeIdentity(enum TOK op, Type *type, Expression *e1, Expression *e2) -{ - if (e1->op == TOKclassreference || e2->op == TOKclassreference) - { - int cmp = 0; - if (e1->op == TOKclassreference && e2->op == TOKclassreference && - ((ClassReferenceExp *)e1)->value == ((ClassReferenceExp *)e2)->value) - cmp = 1; - if (op == TOKnotidentity || op == TOKnotequal) - cmp ^= 1; - return new IntegerExp(e1->loc, cmp, type); - } - return Identity(op, type, e1, e2); -} - - -Expression *BinExp::interpretCommon2(InterState *istate, CtfeGoal goal, fp2_t fp) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("BinExp::interpretCommon2() %s\n", toChars()); -#endif - if (this->e1->type->ty == Tpointer && this->e2->type->ty == Tpointer) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e2)) - return e2; - e = comparePointers(loc, op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - { - error("%s and %s point to independent memory blocks and " - "cannot be compared at compile time", this->e1->toChars(), - this->e2->toChars()); - } - return e; - } - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - - if (e1->isConst() != 1 && - e1->op != TOKnull && - e1->op != TOKstring && - e1->op != TOKarrayliteral && - e1->op != TOKstructliteral && - e1->op != TOKclassreference) - { - error("cannot compare %s at compile time", e1->toChars()); - goto Lcant; - } - - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - if (e2->isConst() != 1 && - e2->op != TOKnull && - e2->op != TOKstring && - e2->op != TOKarrayliteral && - e2->op != TOKstructliteral && - e2->op != TOKclassreference) - { - error("cannot compare %s at compile time", e2->toChars()); - goto Lcant; - } - e = (*fp)(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - return e; - -Lcant: - return EXP_CANT_INTERPRET; -} - -#define BIN_INTERPRET2(op, opfunc) \ -Expression *op##Exp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretCommon2(istate, goal, &opfunc); \ -} - -BIN_INTERPRET2(Equal, Equal) -BIN_INTERPRET2(Identity, ctfeIdentity) -BIN_INTERPRET2(Cmp, Cmp) - -/* Helper functions for BinExp::interpretAssignCommon - */ - -/*************************************** - * Duplicate the elements array, then set field 'indexToChange' = newelem. - */ -Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem) -{ - Expressions *expsx = new Expressions(); - ++CtfeStatus::numArrayAllocs; - expsx->setDim(oldelems->dim); - for (size_t j = 0; j < expsx->dim; j++) - { - if (j == indexToChange) - expsx->tdata()[j] = newelem; - else - expsx->tdata()[j] = oldelems->tdata()[j]; - } - return expsx; -} - -// Create a new struct literal, which is the same as se except that se.field[offset] = elem -Expression * modifyStructField(Type *type, StructLiteralExp *se, size_t offset, Expression *newval) -{ - int fieldi = se->getFieldIndex(newval->type, offset); - if (fieldi == -1) - return EXP_CANT_INTERPRET; - /* Create new struct literal reflecting updated fieldi - */ - Expressions *expsx = changeOneElement(se->elements, fieldi, newval); - StructLiteralExp * ee = new StructLiteralExp(se->loc, se->sd, expsx); - ee->type = se->type; - ee->ownedByCtfe = 1; - return ee; -} - -/******************************** - * Given an array literal arr (either arrayliteral, stringliteral, or assocArrayLiteral), - * set arr[index] = newval and return the new array. - * - */ -Expression *assignAssocArrayElement(Loc loc, AssocArrayLiteralExp *aae, Expression *index, Expression *newval) -{ - /* Create new associative array literal reflecting updated key/value - */ - Expressions *keysx = aae->keys; - Expressions *valuesx = aae->values; - int updated = 0; - for (size_t j = valuesx->dim; j; ) - { j--; - Expression *ekey = aae->keys->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->isBool(TRUE)) - { valuesx->tdata()[j] = newval; - updated = 1; - } - } - if (!updated) - { // Append index/newval to keysx[]/valuesx[] - valuesx->push(newval); - keysx->push(index); - } - return newval; -} - -// Return true if e is derived from UnaryExp. -// Consider moving this function into Expression. -UnaExp *isUnaExp(Expression *e) -{ - switch (e->op) - { - case TOKdotvar: - case TOKindex: - case TOKslice: - case TOKcall: - case TOKdot: - case TOKdotti: - case TOKdottype: - case TOKcast: - return (UnaExp *)e; - default: - break; - } - return NULL; -} - -// Returns the variable which is eventually modified, or NULL if an rvalue. -// thisval is the current value of 'this'. -VarDeclaration * findParentVar(Expression *e, Expression *thisval) -{ - for (;;) - { - e = resolveReferences(e, thisval); - if (e->op == TOKvar) - break; - if (e->op == TOKindex) - e = ((IndexExp*)e)->e1; - else if (e->op == TOKdotvar) - e = ((DotVarExp *)e)->e1; - else if (e->op == TOKdotti) - e = ((DotTemplateInstanceExp *)e)->e1; - else if (e->op == TOKslice) - e = ((SliceExp*)e)->e1; - else - return NULL; - } - VarDeclaration *v = ((VarExp *)e)->var->isVarDeclaration(); - assert(v); - return v; -} - -// Given expr, which evaluates to an array/AA/string literal, -// return true if it needs to be copied -bool needToCopyLiteral(Expression *expr) -{ - for (;;) - { - switch (expr->op) - { - case TOKarrayliteral: - return !((ArrayLiteralExp *)expr)->ownedByCtfe; - case TOKassocarrayliteral: - return !((AssocArrayLiteralExp *)expr)->ownedByCtfe; - case TOKstructliteral: - return !((StructLiteralExp *)expr)->ownedByCtfe; - case TOKstring: - case TOKthis: - case TOKvar: - return false; - case TOKassign: - return false; - case TOKindex: - case TOKdotvar: - case TOKslice: - case TOKcast: - expr = ((UnaExp *)expr)->e1; - continue; - case TOKcat: - return needToCopyLiteral(((BinExp *)expr)->e1) || - needToCopyLiteral(((BinExp *)expr)->e2); - case TOKcatass: - expr = ((BinExp *)expr)->e2; - continue; - default: - return false; - } - } -} - -Expressions *copyLiteralArray(Expressions *oldelems) -{ - if (!oldelems) - return oldelems; - CtfeStatus::numArrayAllocs++; - Expressions *newelems = new Expressions(); - newelems->setDim(oldelems->dim); - for (size_t i = 0; i < oldelems->dim; i++) - newelems->tdata()[i] = copyLiteral(oldelems->tdata()[i]); - return newelems; -} - - - -// Make a copy of the ArrayLiteral, AALiteral, String, or StructLiteral. -// This value will be used for in-place modification. -Expression *copyLiteral(Expression *e) -{ - if (e->op == TOKstring) // syntaxCopy doesn't make a copy for StringExp! - { - StringExp *se = (StringExp *)e; - unsigned char *s; - s = (unsigned char *)mem.calloc(se->len + 1, se->sz); - memcpy(s, se->string, se->len * se->sz); - StringExp *se2 = new StringExp(se->loc, s, se->len); - se2->committed = se->committed; - se2->postfix = se->postfix; - se2->type = se->type; - se2->sz = se->sz; - se2->ownedByCtfe = true; - return se2; - } - else if (e->op == TOKarrayliteral) - { - ArrayLiteralExp *ae = (ArrayLiteralExp *)e; - ArrayLiteralExp *r = new ArrayLiteralExp(e->loc, - copyLiteralArray(ae->elements)); - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - else if (e->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)e; - AssocArrayLiteralExp *r = new AssocArrayLiteralExp(e->loc, - copyLiteralArray(aae->keys), copyLiteralArray(aae->values)); - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - /* syntaxCopy doesn't work for struct literals, because of a nasty special - * case: block assignment is permitted inside struct literals, eg, - * an int[4] array can be initialized with a single int. - */ - else if (e->op == TOKstructliteral) - { - StructLiteralExp *se = (StructLiteralExp *)e; - Expressions *oldelems = se->elements; - Expressions * newelems = new Expressions(); - newelems->setDim(oldelems->dim); - for (size_t i = 0; i < newelems->dim; i++) - { - Expression *m = oldelems->tdata()[i]; - // We need the struct definition to detect block assignment - AggregateDeclaration *sd = se->sd; - Dsymbol *s = sd->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v); - // If it is a void assignment, use the default initializer - if (!m) - m = v->type->defaultInitLiteral(e->loc); - if (m->op == TOKslice) - m = resolveSlice(m); - if ((v->type->ty != m->type->ty) && v->type->ty == Tsarray) - { - // Block assignment from inside struct literals - TypeSArray *tsa = (TypeSArray *)v->type; - uinteger_t length = tsa->dim->toInteger(); - m = createBlockDuplicatedArrayLiteral(e->loc, v->type, m, (size_t)length); - } - else if (v->type->ty != Tarray && v->type->ty!=Taarray) // NOTE: do not copy array references - m = copyLiteral(m); - newelems->tdata()[i] = m; - } -#if DMDV2 - StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems, se->stype); -#else - StructLiteralExp *r = new StructLiteralExp(e->loc, se->sd, newelems); -#endif - r->type = e->type; - r->ownedByCtfe = true; - return r; - } - else if (e->op == TOKfunction || e->op == TOKdelegate - || e->op == TOKsymoff || e->op == TOKnull - || e->op == TOKvar - || e->op == TOKint64 || e->op == TOKfloat64 - || e->op == TOKchar || e->op == TOKcomplex80) - { // Simple value types - Expression *r = e->syntaxCopy(); - r->type = e->type; - return r; - } - else if ( isPointer(e->type) ) - { // For pointers, we only do a shallow copy. - Expression *r; - if (e->op == TOKaddress) - r = new AddrExp(e->loc, ((AddrExp *)e)->e1); - else if (e->op == TOKindex) - r = new IndexExp(e->loc, ((IndexExp *)e)->e1, ((IndexExp *)e)->e2); - else if (e->op == TOKdotvar) - r = new DotVarExp(e->loc, ((DotVarExp *)e)->e1, - ((DotVarExp *)e)->var -#if DMDV2 - , ((DotVarExp *)e)->hasOverloads -#endif - ); - else - assert(0); - r->type = e->type; - return r; - } - else if (e->op == TOKslice) - { // Array slices only do a shallow copy - Expression *r = new SliceExp(e->loc, ((SliceExp *)e)->e1, - ((SliceExp *)e)->lwr, ((SliceExp *)e)->upr); - r->type = e->type; - return r; - } - else if (e->op == TOKclassreference) - return new ClassReferenceExp(e->loc, ((ClassReferenceExp *)e)->value, e->type); - else - { - e->error("Internal Compiler Error: CTFE literal %s", e->toChars()); - assert(0); - return e; - } -} - -/* Deal with type painting. - * Type painting is a major nuisance: we can't just set - * e->type = type, because that would change the original literal. - * But, we can't simply copy the literal either, because that would change - * the values of any pointers. - */ -Expression *paintTypeOntoLiteral(Type *type, Expression *lit) -{ - if (lit->type == type) - return lit; - Expression *e; - if (lit->op == TOKslice) - { - SliceExp *se = (SliceExp *)lit; - e = new SliceExp(lit->loc, se->e1, se->lwr, se->upr); - } - else if (lit->op == TOKindex) - { - IndexExp *ie = (IndexExp *)lit; - e = new IndexExp(lit->loc, ie->e1, ie->e2); - } - else if (lit->op == TOKarrayliteral) - { - e = new SliceExp(lit->loc, lit, - new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); - } - else if (lit->op == TOKstring) - { - // For strings, we need to introduce another level of indirection - e = new SliceExp(lit->loc, lit, - new IntegerExp(0, 0, Type::tsize_t), ArrayLength(Type::tsize_t, lit)); - } - else if (lit->op == TOKassocarrayliteral) - { - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)lit; - // TODO: we should be creating a reference to this AAExp, not - // just a ref to the keys and values. - bool wasOwned = aae->ownedByCtfe; - aae = new AssocArrayLiteralExp(lit->loc, aae->keys, aae->values); - aae->ownedByCtfe = wasOwned; - e = aae; - } - else - { // Can't type paint from struct to struct*; this needs another - // level of indirection - if (lit->op == TOKstructliteral && isPointer(type) ) - lit->error("CTFE internal error painting %s", type->toChars()); - e = copyLiteral(lit); - } - e->type = type; - return e; -} - - -Expression *ctfeCast(Loc loc, Type *type, Type *to, Expression *e) -{ - if (e->op == TOKnull) - return paintTypeOntoLiteral(to, e); - if (e->op == TOKclassreference) - { // Disallow reinterpreting class casts. Do this by ensuring that - // the original class can implicitly convert to the target class - ClassDeclaration *originalClass = ((ClassReferenceExp *)e)->originalClass(); - if (originalClass->type->implicitConvTo(to)) - return paintTypeOntoLiteral(to, e); - else - return new NullExp(loc, to); - } - Expression *r = Cast(type, to, e); - if (r == EXP_CANT_INTERPRET) - error(loc, "cannot cast %s to %s at compile time", e->toChars(), to->toChars()); - if (e->op == TOKarrayliteral) - ((ArrayLiteralExp *)e)->ownedByCtfe = true; - if (e->op == TOKstring) - ((StringExp *)e)->ownedByCtfe = true; - return r; -} - -/* Set dest = src, where both dest and src are container value literals - * (ie, struct literals, or static arrays (can be an array literal or a string) - * Assignment is recursively in-place. - * Purpose: any reference to a member of 'dest' will remain valid after the - * assignment. - */ -void assignInPlace(Expression *dest, Expression *src) -{ - assert(dest->op == TOKstructliteral || dest->op == TOKarrayliteral || - dest->op == TOKstring); - Expressions *oldelems; - Expressions *newelems; - if (dest->op == TOKstructliteral) - { - assert(dest->op == src->op); - oldelems = ((StructLiteralExp *)dest)->elements; - newelems = ((StructLiteralExp *)src)->elements; - } - else if (dest->op == TOKarrayliteral && src->op==TOKarrayliteral) - { - oldelems = ((ArrayLiteralExp *)dest)->elements; - newelems = ((ArrayLiteralExp *)src)->elements; - } - else if (dest->op == TOKstring && src->op == TOKstring) - { - sliceAssignStringFromString((StringExp *)dest, (StringExp *)src, 0); - return; - } - else if (dest->op == TOKarrayliteral && src->op == TOKstring) - { - sliceAssignArrayLiteralFromString((ArrayLiteralExp *)dest, (StringExp *)src, 0); - return; - } - else if (src->op == TOKarrayliteral && dest->op == TOKstring) - { - sliceAssignStringFromArrayLiteral((StringExp *)dest, (ArrayLiteralExp *)src, 0); - return; - } - else assert(0); - - assert(oldelems->dim == newelems->dim); - - for (size_t i= 0; i < oldelems->dim; ++i) - { - Expression *e = newelems->tdata()[i]; - Expression *o = oldelems->tdata()[i]; - if (e->op == TOKstructliteral) - { - assert(o->op == e->op); - assignInPlace(o, e); - } - else if (e->type->ty == Tsarray && o->type->ty == Tsarray) - { - assignInPlace(o, e); - } - else - { - oldelems->tdata()[i] = newelems->tdata()[i]; - } - } -} - -void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef) -{ - assert( ae->type->ty == Tsarray || ae->type->ty == Tarray); -#if DMDV2 - Type *desttype = ((TypeArray *)ae->type)->next->castMod(0); - bool directblk = (val->type->toBasetype()->castMod(0)) == desttype; -#else - Type *desttype = ((TypeArray *)ae->type)->next; - bool directblk = (val->type->toBasetype()) == desttype; -#endif - - bool cow = !(val->op == TOKstructliteral || val->op == TOKarrayliteral - || val->op == TOKstring); - - for (size_t k = 0; k < ae->elements->dim; k++) - { - if (!directblk && ae->elements->tdata()[k]->op == TOKarrayliteral) - { - recursiveBlockAssign((ArrayLiteralExp *)ae->elements->tdata()[k], val, wantRef); - } - else - { - if (wantRef || cow) - ae->elements->tdata()[k] = val; - else - assignInPlace(ae->elements->tdata()[k], val); - } - } -} - - -Expression *BinExp::interpretAssignCommon(InterState *istate, CtfeGoal goal, fp_t fp, int post) -{ -#if LOG - printf("BinExp::interpretAssignCommon() %s\n", toChars()); -#endif - Expression *returnValue = EXP_CANT_INTERPRET; - Expression *e1 = this->e1; - if (!istate) - { - error("value of %s is not known at compile time", e1->toChars()); - return returnValue; - } - ++CtfeStatus::numAssignments; - /* Before we begin, we need to know if this is a reference assignment - * (dynamic array, AA, or class) or a value assignment. - * Determining this for slice assignments are tricky: we need to know - * if it is a block assignment (a[] = e) rather than a direct slice - * assignment (a[] = b[]). Note that initializers of multi-dimensional - * static arrays can have 2D block assignments (eg, int[7][7] x = 6;). - * So we need to recurse to determine if it is a block assignment. - */ - bool isBlockAssignment = false; - if (e1->op == TOKslice) - { - // a[] = e can have const e. So we compare the naked types. - Type *desttype = e1->type->toBasetype(); -#if DMDV2 - Type *srctype = e2->type->toBasetype()->castMod(0); -#else - Type *srctype = e2->type->toBasetype(); -#endif - while ( desttype->ty == Tsarray || desttype->ty == Tarray) - { - desttype = ((TypeArray *)desttype)->next; -#if DMDV2 - if (srctype == desttype->castMod(0)) -#else - if (srctype == desttype) -#endif - { - isBlockAssignment = true; - break; - } - } - } - bool wantRef = false; - if (!fp && this->e1->type->toBasetype() == this->e2->type->toBasetype() && - (e1->type->toBasetype()->ty == Tarray || isAssocArray(e1->type)) - // e = *x is never a reference, because *x is always a value - && this->e2->op != TOKstar - ) - { -#if DMDV2 - wantRef = true; -#else - /* D1 doesn't have const in the type system. But there is still a - * vestigal const in the form of static const variables. - * Problematic code like: - * const int [] x = [1,2,3]; - * int [] y = x; - * can be dealt with by making this a non-ref assign (y = x.dup). - * Otherwise it's a big mess. - */ - VarDeclaration * targetVar = findParentVar(e2, istate->localThis); - if (!(targetVar && targetVar->isConst())) - wantRef = true; - // slice assignment of static arrays is not reference assignment - if ((e1->op==TOKslice) && ((SliceExp *)e1)->e1->type->ty == Tsarray) - wantRef = false; -#endif - // If it is assignment from a ref parameter, it's not a ref assignment - if (this->e2->op == TOKvar) - { - VarDeclaration *v = ((VarExp *)this->e2)->var->isVarDeclaration(); - if (v && (v->storage_class & (STCref | STCout))) - wantRef = false; - } - } - if (isBlockAssignment && (e2->type->toBasetype()->ty == Tarray || e2->type->toBasetype()->ty == Tsarray)) - { - wantRef = true; - } - // If it is a construction of a ref variable, it is a ref assignment - if (op == TOKconstruct && this->e1->op==TOKvar - && ((VarExp*)this->e1)->var->storage_class & STCref) - { - wantRef = true; - } - - if (fp) - { - while (e1->op == TOKcast) - { CastExp *ce = (CastExp *)e1; - e1 = ce->e1; - } - } - if (exceptionOrCantInterpret(e1)) - return e1; - - // First, deal with this = e; and call() = e; - if (e1->op == TOKthis) - { - e1 = istate->localThis; - } - if (e1->op == TOKcall) - { - bool oldWaiting = istate->awaitingLvalueReturn; - istate->awaitingLvalueReturn = true; - e1 = e1->interpret(istate); - istate->awaitingLvalueReturn = oldWaiting; - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKarrayliteral || e1->op == TOKstring) - { - // f() = e2, when f returns an array, is always a slice assignment. - // Convert into arr[0..arr.length] = e2 - e1 = new SliceExp(loc, e1, - new IntegerExp(0, 0, Type::tsize_t), - ArrayLength(Type::tsize_t, e1)); - e1->type = type; - } - } - if (e1->op == TOKstar) - { - e1 = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (!(e1->op == TOKvar || e1->op == TOKdotvar || e1->op == TOKindex - || e1->op == TOKslice)) - { - error("cannot dereference invalid pointer %s", - this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - } - - if (!(e1->op == TOKarraylength || e1->op == TOKvar || e1->op == TOKdotvar - || e1->op == TOKindex || e1->op == TOKslice)) - { - error("CTFE internal error: unsupported assignment %s", toChars()); - return EXP_CANT_INTERPRET; - } - - Expression * newval = NULL; - - if (!wantRef) - { // We need to treat pointers specially, because TOKsymoff can be used to - // return a value OR a pointer - assert(e1); - assert(e1->type); - if ( isPointer(e1->type) && (e2->op == TOKsymoff || e2->op==TOKaddress || e2->op==TOKvar)) - newval = this->e2->interpret(istate, ctfeNeedLvalue); - else - newval = this->e2->interpret(istate); - if (exceptionOrCantInterpret(newval)) - return newval; - } - // ---------------------------------------------------- - // Deal with read-modify-write assignments. - // Set 'newval' to the final assignment value - // Also determine the return value (except for slice - // assignments, which are more complicated) - // ---------------------------------------------------- - - if (fp || e1->op == TOKarraylength) - { - // If it isn't a simple assignment, we need the existing value - Expression * oldval = e1->interpret(istate); - if (exceptionOrCantInterpret(oldval)) - return oldval; - while (oldval->op == TOKvar) - { - oldval = resolveReferences(oldval, istate->localThis); - oldval = oldval->interpret(istate); - if (exceptionOrCantInterpret(oldval)) - return oldval; - } - - if (fp) - { - // ~= can create new values (see bug 6052) - if (op == TOKcatass) - { - // We need to dup it. We can skip this if it's a dynamic array, - // because it gets copied later anyway - if (newval->type->ty != Tarray) - newval = copyLiteral(newval); - if (newval->op == TOKslice) - newval = resolveSlice(newval); - // It becomes a reference assignment - wantRef = true; - } - if (oldval->op == TOKslice) - oldval = resolveSlice(oldval); - if (this->e1->type->ty == Tpointer && this->e2->type->isintegral() - && (op==TOKaddass || op == TOKminass || - op == TOKplusplus || op == TOKminusminus)) - { - oldval = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(oldval)) - return oldval; - newval = this->e2->interpret(istate); - if (exceptionOrCantInterpret(newval)) - return newval; - newval = pointerArithmetic(loc, op, type, oldval, newval); - } - else if (this->e1->type->ty == Tpointer) - { - error("pointer expression %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - else - { - newval = (*fp)(type, oldval, newval); - } - if (newval == EXP_CANT_INTERPRET) - { - error("Cannot interpret %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(newval)) - return newval; - // Determine the return value - returnValue = ctfeCast(loc, type, type, post ? oldval : newval); - if (exceptionOrCantInterpret(returnValue)) - return returnValue; - } - else - returnValue = newval; - if (e1->op == TOKarraylength) - { - size_t oldlen = oldval->toInteger(); - size_t newlen = newval->toInteger(); - if (oldlen == newlen) // no change required -- we're done! - return returnValue; - // Now change the assignment from arr.length = n into arr = newval - e1 = ((ArrayLengthExp *)e1)->e1; - if (oldlen != 0) - { // Get the old array literal. - oldval = e1->interpret(istate); - while (oldval->op == TOKvar) - { oldval = resolveReferences(oldval, istate->localThis); - oldval = oldval->interpret(istate); - } - } - if (oldval->op == TOKslice) - oldval = resolveSlice(oldval); - Type *t = e1->type->toBasetype(); - if (t->ty == Tarray) - { - Type *elemType= NULL; - elemType = ((TypeArray *)t)->next; - assert(elemType); - Expression *defaultElem = elemType->defaultInitLiteral(); - - Expressions *elements = new Expressions(); - elements->setDim(newlen); - size_t copylen = oldlen < newlen ? oldlen : newlen; - if (oldval->op == TOKstring) - { - StringExp *oldse = (StringExp *)oldval; - unsigned char *s = (unsigned char *)mem.calloc(newlen + 1, oldse->sz); - memcpy(s, oldse->string, copylen * oldse->sz); - unsigned defaultValue = (unsigned)(defaultElem->toInteger()); - for (size_t elemi = copylen; elemi < newlen; ++elemi) - { - switch (oldse->sz) - { - case 1: s[elemi] = defaultValue; break; - case 2: ((unsigned short *)s)[elemi] = defaultValue; break; - case 4: ((unsigned *)s)[elemi] = defaultValue; break; - default: assert(0); - } - } - StringExp *se = new StringExp(loc, s, newlen); - se->type = t; - se->sz = oldse->sz; - se->committed = oldse->committed; - se->ownedByCtfe = true; - newval = se; - } - else - { - if (oldlen !=0) - assert(oldval->op == TOKarrayliteral); - ArrayLiteralExp *ae = (ArrayLiteralExp *)oldval; - for (size_t i = 0; i < copylen; i++) - elements->tdata()[i] = ae->elements->tdata()[i]; - if (elemType->ty == Tstruct || elemType->ty == Tsarray) - { /* If it is an aggregate literal representing a value type, - * we need to create a unique copy for each element - */ - for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = copyLiteral(defaultElem); - } - else - { - for (size_t i = copylen; i < newlen; i++) - elements->tdata()[i] = defaultElem; - } - ArrayLiteralExp *aae = new ArrayLiteralExp(0, elements); - aae->type = t; - newval = aae; - aae->ownedByCtfe = true; - } - // We have changed it into a reference assignment - // Note that returnValue is still the new length. - wantRef = true; - if (e1->op == TOKstar) - { // arr.length+=n becomes (t=&arr, *(t).length=*(t).length+n); - e1 = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - } - } - else - { - error("%s is not yet supported at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - - } - } - else if (!wantRef && e1->op != TOKslice) - { /* Look for special case of struct being initialized with 0. - */ - if (type->toBasetype()->ty == Tstruct && newval->op == TOKint64) - { - newval = type->defaultInitLiteral(loc); - if (newval->op != TOKstructliteral) - { - error("nested structs with constructors are not yet supported in CTFE (Bug 6419)"); - return EXP_CANT_INTERPRET; - } - } - newval = ctfeCast(loc, type, type, newval); - if (exceptionOrCantInterpret(newval)) - return newval; - returnValue = newval; - } - if (exceptionOrCantInterpret(newval)) - return newval; - - // ------------------------------------------------- - // Make sure destination can be modified - // ------------------------------------------------- - // Make sure we're not trying to modify a global or static variable - // We do this by locating the ultimate parent variable which gets modified. - VarDeclaration * ultimateVar = findParentVar(e1, istate->localThis); - if (ultimateVar && ultimateVar->isDataseg() && !ultimateVar->isCTFE()) - { // Can't modify global or static data - error("%s cannot be modified at compile time", ultimateVar->toChars()); - return EXP_CANT_INTERPRET; - } - - e1 = resolveReferences(e1, istate->localThis); - - // Unless we have a simple var assignment, we're - // only modifying part of the variable. So we need to make sure - // that the parent variable exists. - if (e1->op != TOKvar && ultimateVar && !ultimateVar->getValue()) - ultimateVar->setValue(copyLiteral(ultimateVar->type->defaultInitLiteral())); - - // --------------------------------------- - // Deal with reference assignment - // (We already have 'newval' for arraylength operations) - // --------------------------------------- - if (wantRef && !fp && this->e1->op != TOKarraylength) - { - newval = this->e2->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(newval)) - return newval; - // If it is an assignment from a array function parameter passed by - // reference, resolve the reference. (This should NOT happen for - // non-reference types). - if (newval->op == TOKvar && (newval->type->ty == Tarray || - newval->type->ty == Tclass)) - { - newval = newval->interpret(istate); - } - - if (newval->op == TOKassocarrayliteral || newval->op == TOKstring || - newval->op==TOKarrayliteral) - { - if (needToCopyLiteral(newval)) - newval = copyLiteral(newval); - } - returnValue = newval; - } - - // --------------------------------------- - // Deal with AA index assignment - // --------------------------------------- - /* This needs special treatment if the AA doesn't exist yet. - * There are two special cases: - * (1) If the AA is itself an index of another AA, we may need to create - * multiple nested AA literals before we can insert the new value. - * (2) If the ultimate AA is null, no insertion happens at all. Instead, we - * create nested AA literals, and change it into a assignment. - */ - if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - IndexExp *ie = (IndexExp *)e1; - int depth = 0; // how many nested AA indices are there? - while (ie->e1->op == TOKindex && ((IndexExp *)ie->e1)->e1->type->toBasetype()->ty == Taarray) - { - ie = (IndexExp *)ie->e1; - ++depth; - } - Expression *aggregate = resolveReferences(ie->e1, istate->localThis); - Expression *oldagg = aggregate; - // Get the AA to be modified. (We do an LvalueRef interpret, unless it - // is a simple ref parameter -- in which case, we just want the value) - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - if (aggregate->op == TOKassocarrayliteral) - { // Normal case, ultimate parent AA already exists - // We need to walk from the deepest index up, checking that an AA literal - // already exists on each level. - Expression *index = ((IndexExp *)e1)->e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (index->op == TOKslice) // only happens with AA assignment - index = resolveSlice(index); - AssocArrayLiteralExp *existingAA = (AssocArrayLiteralExp *)aggregate; - while (depth > 0) - { // Walk the syntax tree to find the indexExp at this depth - IndexExp *xe = (IndexExp *)e1; - for (int d= 0; d < depth; ++d) - xe = (IndexExp *)xe->e1; - - Expression *indx = xe->e2->interpret(istate); - if (exceptionOrCantInterpret(indx)) - return indx; - if (indx->op == TOKslice) // only happens with AA assignment - indx = resolveSlice(indx); - - // Look up this index in it up in the existing AA, to get the next level of AA. - AssocArrayLiteralExp *newAA = (AssocArrayLiteralExp *)findKeyInAA(existingAA, indx); - if (exceptionOrCantInterpret(newAA)) - return newAA; - if (!newAA) - { // Doesn't exist yet, create an empty AA... - Expressions *valuesx = new Expressions(); - Expressions *keysx = new Expressions(); - newAA = new AssocArrayLiteralExp(loc, keysx, valuesx); - newAA->type = xe->type; - newAA->ownedByCtfe = true; - //... and insert it into the existing AA. - existingAA->keys->push(indx); - existingAA->values->push(newAA); - } - existingAA = newAA; - --depth; - } - if (assignAssocArrayElement(loc, existingAA, index, newval) == EXP_CANT_INTERPRET) - return EXP_CANT_INTERPRET; - return returnValue; - } - else - { /* The AA is currently null. 'aggregate' is actually a reference to - * whatever contains it. It could be anything: var, dotvarexp, ... - * We rewrite the assignment from: aggregate[i][j] = newval; - * into: aggregate = [i:[j: newval]]; - */ - while (e1->op == TOKindex && ((IndexExp *)e1)->e1->type->toBasetype()->ty == Taarray) - { - Expression *index = ((IndexExp *)e1)->e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (index->op == TOKslice) // only happens with AA assignment - index = resolveSlice(index); - Expressions *valuesx = new Expressions(); - Expressions *keysx = new Expressions(); - valuesx->push(newval); - keysx->push(index); - AssocArrayLiteralExp *newaae = new AssocArrayLiteralExp(loc, keysx, valuesx); - newaae->ownedByCtfe = true; - newaae->type = e1->type; - newval = newaae; - e1 = ((IndexExp *)e1)->e1; - } - // We must return to the original aggregate, in case it was a reference - wantRef = true; - e1 = oldagg; - // fall through -- let the normal assignment logic take care of it - } - } - - // --------------------------------------- - // Deal with dotvar expressions - // --------------------------------------- - // Because structs are not reference types, dotvar expressions can be - // collapsed into a single assignment. - if (!wantRef && e1->op == TOKdotvar) - { - // Strip of all of the leading dotvars, unless we started with a call - // or a ref parameter - // (in which case, we already have the lvalue). - if (this->e1->op != TOKcall && !(this->e1->op==TOKvar - && ((VarExp*)this->e1)->var->storage_class & (STCref | STCout))) - e1 = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKstructliteral && newval->op == TOKstructliteral) - { - assignInPlace(e1, newval); - return returnValue; - } - } -#if LOGASSIGN - if (wantRef) - printf("REF ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); - else - printf("ASSIGN: %s=%s\n", e1->toChars(), newval->toChars()); - showCtfeExpr(newval); -#endif - - /* Assignment to variable of the form: - * v = newval - */ - if (e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - if (wantRef) - { - v->setValueNull(); - v->setValue(newval); - } - else if (e1->type->toBasetype()->ty == Tstruct) - { - // In-place modification - if (newval->op != TOKstructliteral) - { - error("CTFE internal error assigning struct"); - return EXP_CANT_INTERPRET; - } - newval = copyLiteral(newval); - if (v->getValue()) - assignInPlace(v->getValue(), newval); - else - v->setValue(newval); - } - else - { - TY tyE1 = e1->type->toBasetype()->ty; - if (tyE1 == Tarray || tyE1 == Taarray) - { // arr op= arr - v->setValue(newval); - } - else - { - v->setValue(newval); - } - } - } - else if (e1->op == TOKdotvar) - { - /* Assignment to member variable of the form: - * e.v = newval - */ - Expression *exx = ((DotVarExp *)e1)->e1; - if (wantRef && exx->op != TOKstructliteral) - { - exx = exx->interpret(istate); - if (exceptionOrCantInterpret(exx)) - return exx; - } - if (exx->op != TOKstructliteral && exx->op != TOKclassreference) - { - error("CTFE internal error: Dotvar assignment"); - return EXP_CANT_INTERPRET; - } - VarDeclaration *member = ((DotVarExp *)e1)->var->isVarDeclaration(); - if (!member) - { - error("CTFE internal error: Dotvar assignment"); - return EXP_CANT_INTERPRET; - } - StructLiteralExp *se = exx->op == TOKstructliteral - ? (StructLiteralExp *)exx - : ((ClassReferenceExp *)exx)->value; - int fieldi = exx->op == TOKstructliteral - ? se->getFieldIndex(member->type, member->offset) - : ((ClassReferenceExp *)exx)->getFieldIndex(member->type, member->offset); - if (fieldi == -1) - { - error("CTFE internal error: cannot find field %s in %s", member->toChars(), exx->toChars()); - return EXP_CANT_INTERPRET; - } - assert(fieldi>=0 && fieldi < se->elements->dim); - if (newval->op == TOKstructliteral) - assignInPlace(se->elements->tdata()[fieldi], newval); - else - se->elements->tdata()[fieldi] = newval; - return returnValue; - } - else if (e1->op == TOKindex) - { - /* Assignment to array element of the form: - * aggregate[i] = newval - * aggregate is not AA (AAs were dealt with already). - */ - IndexExp *ie = (IndexExp *)e1; - assert(ie->e1->type->toBasetype()->ty != Taarray); - uinteger_t destarraylen = 0; - - // Set the $ variable, and find the array literal to modify - if (ie->e1->type->toBasetype()->ty != Tpointer) - { - Expression *oldval = ie->e1->interpret(istate); - if (oldval->op == TOKnull) - { - error("cannot index null array %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice) - { - error("cannot determine length of %s at compile time", - ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - destarraylen = resolveArrayLength(oldval); - if (ie->lengthVar) - { - IntegerExp *dollarExp = new IntegerExp(loc, destarraylen, Type::tsize_t); - ctfeStack.push(ie->lengthVar); - ie->lengthVar->setValue(dollarExp); - } - } - Expression *index = ie->e2->interpret(istate); - if (ie->lengthVar) - ctfeStack.pop(ie->lengthVar); // $ is defined only inside [] - if (exceptionOrCantInterpret(index)) - return index; - - assert (index->op != TOKslice); // only happens with AA assignment - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - Expression *aggregate = resolveReferences(ie->e1, istate->localThis); - - // Set the index to modify, and check that it is in range - dinteger_t indexToModify = index->toInteger(); - if (ie->e1->type->toBasetype()->ty == Tpointer) - { - dinteger_t ofs; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - if (aggregate->op == TOKnull) - { - error("cannot index through null pointer %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (aggregate->op == TOKint64) - { - error("cannot index through invalid pointer %s of value %s", - ie->e1->toChars(), aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - aggregate = getAggregateFromPointer(aggregate, &ofs); - indexToModify += ofs; - destarraylen = resolveArrayLength(aggregate); - } - if (indexToModify >= destarraylen) - { - error("array index %lld is out of bounds [0..%lld]", indexToModify, - destarraylen); - return EXP_CANT_INTERPRET; - } - - /* The only possible indexable LValue aggregates are array literals, and - * slices of array literals. - */ - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || aggregate->op == TOKcall || - aggregate->op == TOKstar) - { - Expression *origagg = aggregate; - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)aggregate; - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - if (aggregate->op == TOKnull) - { - // This would be a runtime segfault - error("cannot index null array %s", v->toChars()); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKslice) - { - SliceExp *sexp = (SliceExp *)aggregate; - aggregate = sexp->e1; - Expression *lwr = sexp->lwr->interpret(istate); - indexToModify += lwr->toInteger(); - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - else - { - error("CTFE internal compiler error %s", aggregate->toChars()); - return EXP_CANT_INTERPRET; - } - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE index assign %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - if (existingAE) - { - if (newval->op == TOKstructliteral) - assignInPlace((Expression *)(existingAE->elements->tdata()[indexToModify]), newval); - else - existingAE->elements->tdata()[indexToModify] = newval; - return returnValue; - } - if (existingSE) - { - unsigned char *s = (unsigned char *)existingSE->string; - if (!existingSE->ownedByCtfe) - { - error("cannot modify read-only string literal %s", ie->e1->toChars()); - return EXP_CANT_INTERPRET; - } - unsigned value = newval->toInteger(); - switch (existingSE->sz) - { - case 1: s[indexToModify] = value; break; - case 2: ((unsigned short *)s)[indexToModify] = value; break; - case 4: ((unsigned *)s)[indexToModify] = value; break; - default: - assert(0); - break; - } - return returnValue; - } - else - { - error("Index assignment %s is not yet supported in CTFE ", toChars()); - return EXP_CANT_INTERPRET; - } - return returnValue; - } - else if (e1->op == TOKslice) - { - // ------------------------------ - // aggregate[] = newval - // aggregate[low..upp] = newval - // ------------------------------ - SliceExp * sexp = (SliceExp *)e1; - // Set the $ variable - Expression *oldval = sexp->e1; - bool assignmentToSlicedPointer = false; - if (isPointer(oldval->type)) - { // Slicing a pointer - oldval = oldval->interpret(istate, ctfeNeedLvalue); - dinteger_t ofs; - oldval = getAggregateFromPointer(oldval, &ofs); - assignmentToSlicedPointer = true; - } else - oldval = oldval->interpret(istate); - - if (oldval->op != TOKarrayliteral && oldval->op != TOKstring - && oldval->op != TOKslice && oldval->op != TOKnull) - { - error("CTFE ICE: cannot resolve array length"); - return EXP_CANT_INTERPRET; - } - uinteger_t dollar = resolveArrayLength(oldval); - if (sexp->lengthVar) - { - Expression *arraylen = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(sexp->lengthVar); - sexp->lengthVar->setValue(arraylen); - } - - Expression *upper = NULL; - Expression *lower = NULL; - if (sexp->upr) - upper = sexp->upr->interpret(istate); - if (exceptionOrCantInterpret(upper)) - { - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - return upper; - } - if (sexp->lwr) - lower = sexp->lwr->interpret(istate); - if (sexp->lengthVar) - ctfeStack.pop(sexp->lengthVar); // $ is defined only in [L..U] - if (exceptionOrCantInterpret(lower)) - return lower; - - size_t dim = dollar; - size_t upperbound = upper ? upper->toInteger() : dim; - int lowerbound = lower ? lower->toInteger() : 0; - - if (!assignmentToSlicedPointer && (((int)lowerbound < 0) || (upperbound > dim))) - { - error("Array bounds [0..%d] exceeded in slice [%d..%d]", - dim, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - if (upperbound == lowerbound) - return newval; - - Expression *aggregate = resolveReferences(((SliceExp *)e1)->e1, istate->localThis); - dinteger_t firstIndex = lowerbound; - - ArrayLiteralExp *existingAE = NULL; - StringExp *existingSE = NULL; - - /* The only possible slicable LValue aggregates are array literals, - * and slices of array literals. - */ - - if (aggregate->op == TOKindex || aggregate->op == TOKdotvar || - aggregate->op == TOKslice || - aggregate->op == TOKstar || aggregate->op == TOKcall) - { - aggregate = aggregate->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - // The array could be an index of an AA. Resolve it if so. - if (aggregate->op == TOKindex && - ((IndexExp *)aggregate)->e1->op == TOKassocarrayliteral) - { - IndexExp *ix = (IndexExp *)aggregate; - aggregate = findKeyInAA((AssocArrayLiteralExp *)ix->e1, ix->e2); - if (!aggregate) - { - error("key %s not found in associative array %s", - ix->e2->toChars(), ix->e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (exceptionOrCantInterpret(aggregate)) - return aggregate; - } - } - if (aggregate->op == TOKvar) - { - VarExp *ve = (VarExp *)(aggregate); - VarDeclaration *v = ve->var->isVarDeclaration(); - aggregate = v->getValue(); - } - if (aggregate->op == TOKslice) - { // Slice of a slice --> change the bounds - SliceExp *sexpold = (SliceExp *)aggregate; - dinteger_t hi = upperbound + sexpold->lwr->toInteger(); - firstIndex = lowerbound + sexpold->lwr->toInteger(); - if (hi > sexpold->upr->toInteger()) - { - error("slice [%d..%d] exceeds array bounds [0..%jd]", - lowerbound, upperbound, - sexpold->upr->toInteger() - sexpold->lwr->toInteger()); - return EXP_CANT_INTERPRET; - } - aggregate = sexpold->e1; - } - if ( isPointer(aggregate->type) ) - { // Slicing a pointer --> change the bounds - aggregate = sexp->e1->interpret(istate, ctfeNeedLvalue); - dinteger_t ofs; - aggregate = getAggregateFromPointer(aggregate, &ofs); - dinteger_t hi = upperbound + ofs; - firstIndex = lowerbound + ofs; - if (firstIndex < 0 || hi > dim) - { - error("slice [%d..%jd] exceeds memory block bounds [0..%jd]", - firstIndex, hi, dim); - return EXP_CANT_INTERPRET; - } - } - if (aggregate->op == TOKarrayliteral) - existingAE = (ArrayLiteralExp *)aggregate; - else if (aggregate->op == TOKstring) - existingSE = (StringExp *)aggregate; - if (existingSE && !existingSE->ownedByCtfe) - { error("cannot modify read-only string literal %s", sexp->e1->toChars()); - return EXP_CANT_INTERPRET; - } - - if (!wantRef && newval->op == TOKslice) - { - newval = resolveSlice(newval); - if (newval == EXP_CANT_INTERPRET) - { - error("Compiler error: CTFE slice %s", toChars()); - assert(0); - } - } - if (wantRef && newval->op == TOKindex - && ((IndexExp *)newval)->e1 == aggregate) - { // It's a circular reference, resolve it now - newval = newval->interpret(istate); - } - - // For slice assignment, we check that the lengths match. - size_t srclen = 0; - if (newval->op == TOKarrayliteral) - srclen = ((ArrayLiteralExp *)newval)->elements->dim; - else if (newval->op == TOKstring) - srclen = ((StringExp *)newval)->len; - if (!isBlockAssignment && srclen != (upperbound - lowerbound)) - { - error("Array length mismatch assigning [0..%d] to [%d..%d]", srclen, lowerbound, upperbound); - return EXP_CANT_INTERPRET; - } - - if (!isBlockAssignment && newval->op == TOKarrayliteral && existingAE) - { - Expressions *oldelems = existingAE->elements; - Expressions *newelems = ((ArrayLiteralExp *)newval)->elements; - for (size_t j = 0; j < newelems->dim; j++) - { - oldelems->tdata()[j + firstIndex] = newelems->tdata()[j]; - } - return newval; - } - else if (newval->op == TOKstring && existingSE) - { - sliceAssignStringFromString((StringExp *)existingSE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKstring && existingAE - && existingAE->type->isString()) - { /* Mixed slice: it was initialized as an array literal of chars. - * Now a slice of it is being set with a string. - */ - sliceAssignArrayLiteralFromString(existingAE, (StringExp *)newval, firstIndex); - return newval; - } - else if (newval->op == TOKarrayliteral && existingSE) - { /* Mixed slice: it was initialized as a string literal. - * Now a slice of it is being set with an array literal. - */ - sliceAssignStringFromArrayLiteral(existingSE, (ArrayLiteralExp *)newval, firstIndex); - return newval; - } - else if (existingSE) - { // String literal block slice assign - unsigned value = newval->toInteger(); - unsigned char *s = (unsigned char *)existingSE->string; - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - switch (existingSE->sz) - { - case 1: s[j+firstIndex] = value; break; - case 2: ((unsigned short *)s)[j+firstIndex] = value; break; - case 4: ((unsigned *)s)[j+firstIndex] = value; break; - default: - assert(0); - break; - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingSE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else if (existingAE) - { - /* Block assignment, initialization of static arrays - * x[] = e - * x may be a multidimensional static array. (Note that this - * only happens with array literals, never with strings). - */ - Expressions * w = existingAE->elements; - assert( existingAE->type->ty == Tsarray || - existingAE->type->ty == Tarray); -#if DMDV2 - Type *desttype = ((TypeArray *)existingAE->type)->next->castMod(0); - bool directblk = (e2->type->toBasetype()->castMod(0)) == desttype; -#else - Type *desttype = ((TypeArray *)existingAE->type)->next; - bool directblk = (e2->type->toBasetype()) == desttype; -#endif - bool cow = !(newval->op == TOKstructliteral || newval->op == TOKarrayliteral - || newval->op == TOKstring); - for (size_t j = 0; j < upperbound-lowerbound; j++) - { - if (!directblk) - // Multidimensional array block assign - recursiveBlockAssign((ArrayLiteralExp *)w->tdata()[j+firstIndex], newval, wantRef); - else - { - if (wantRef || cow) - existingAE->elements->tdata()[j+firstIndex] = newval; - else - assignInPlace(existingAE->elements->tdata()[j+firstIndex], newval); - } - } - if (goal == ctfeNeedNothing) - return NULL; // avoid creating an unused literal - SliceExp *retslice = new SliceExp(loc, existingAE, - new IntegerExp(loc, firstIndex, Type::tsize_t), - new IntegerExp(loc, firstIndex + upperbound-lowerbound, Type::tsize_t)); - retslice->type = this->type; - return retslice->interpret(istate); - } - else - error("Slice operation %s cannot be evaluated at compile time", toChars()); - } - else - { - error("%s cannot be evaluated at compile time", toChars()); -#ifdef DEBUG - dump(0); -#endif - } - return returnValue; -} - -Expression *AssignExp::interpret(InterState *istate, CtfeGoal goal) -{ - return interpretAssignCommon(istate, goal, NULL); -} - -#define BIN_ASSIGN_INTERPRET_CTFE(op, ctfeOp) \ -Expression *op##AssignExp::interpret(InterState *istate, CtfeGoal goal) \ -{ \ - return interpretAssignCommon(istate, goal, &ctfeOp); \ -} - -#define BIN_ASSIGN_INTERPRET(op) BIN_ASSIGN_INTERPRET_CTFE(op, op) - -BIN_ASSIGN_INTERPRET(Add) -BIN_ASSIGN_INTERPRET(Min) -BIN_ASSIGN_INTERPRET_CTFE(Cat, ctfeCat) -BIN_ASSIGN_INTERPRET(Mul) -BIN_ASSIGN_INTERPRET(Div) -BIN_ASSIGN_INTERPRET(Mod) -BIN_ASSIGN_INTERPRET(Shl) -BIN_ASSIGN_INTERPRET(Shr) -BIN_ASSIGN_INTERPRET(Ushr) -BIN_ASSIGN_INTERPRET(And) -BIN_ASSIGN_INTERPRET(Or) -BIN_ASSIGN_INTERPRET(Xor) -#if DMDV2 -BIN_ASSIGN_INTERPRET(Pow) -#endif - -Expression *PostExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("PostExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if (op == TOKplusplus) - e = interpretAssignCommon(istate, goal, &Add, 1); - else - e = interpretAssignCommon(istate, goal, &Min, 1); -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PostExp::interpret() CANT\n"); -#endif - return e; -} - -Expression *AndAndExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("AndAndExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - int result; - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - { - e = e2->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (e == EXP_VOID_INTERPRET) - { - assert(type->ty == Tvoid); - return NULL; - } - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s does not evaluate to a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - } - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) - e = new IntegerExp(loc, result, type); - return e; -} - -Expression *OrOrExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("OrOrExp::interpret() %s\n", toChars()); -#endif - Expression *e = e1->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - int result; - if (e != EXP_CANT_INTERPRET) - { - if (isTrueBool(e)) - result = 1; - else if (e->isBool(FALSE)) - { - e = e2->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - - if (e == EXP_VOID_INTERPRET) - { - assert(type->ty == Tvoid); - return NULL; - } - if (e != EXP_CANT_INTERPRET) - { - if (e->isBool(FALSE)) - result = 0; - else if (isTrueBool(e)) - result = 1; - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - } - else - { - error("%s cannot be interpreted as a boolean", e->toChars()); - e = EXP_CANT_INTERPRET; - } - } - if (e != EXP_CANT_INTERPRET && goal != ctfeNeedNothing) - e = new IntegerExp(loc, result, type); - return e; -} - -// Print a stack trace, starting from callingExp which called fd. -// To shorten the stack trace, try to detect recursion. -void showCtfeBackTrace(InterState *istate, CallExp * callingExp, FuncDeclaration *fd) -{ - if (CtfeStatus::stackTraceCallsToSuppress > 0) - { - --CtfeStatus::stackTraceCallsToSuppress; - return; - } - errorSupplemental(callingExp->loc, "called from here: %s", callingExp->toChars()); - // Quit if it's not worth trying to compress the stack trace - if (CtfeStatus::callDepth < 6 || global.params.verbose) - return; - // Recursion happens if the current function already exists in the call stack. - int numToSuppress = 0; - int recurseCount = 0; - int depthSoFar = 0; - InterState *lastRecurse = istate; - for (InterState * cur = istate; cur; cur = cur->caller) - { - if (cur->fd == fd) - { ++recurseCount; - numToSuppress = depthSoFar; - lastRecurse = cur; - } - ++depthSoFar; - } - // We need at least three calls to the same function, to make compression worthwhile - if (recurseCount < 2) - return; - // We found a useful recursion. Print all the calls involved in the recursion - errorSupplemental(fd->loc, "%d recursive calls to function %s", recurseCount, fd->toChars()); - for (InterState *cur = istate; cur->fd != fd; cur = cur->caller) - { - errorSupplemental(cur->fd->loc, "recursively called from function %s", cur->fd->toChars()); - } - // We probably didn't enter the recursion in this function. - // Go deeper to find the real beginning. - InterState * cur = istate; - while (lastRecurse->caller && cur->fd == lastRecurse->caller->fd) - { - cur = cur->caller; - lastRecurse = lastRecurse->caller; - ++numToSuppress; - } - CtfeStatus::stackTraceCallsToSuppress = numToSuppress; -} - -Expression *CallExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("CallExp::interpret() %s\n", toChars()); -#endif - - Expression * pthis = NULL; - FuncDeclaration *fd = NULL; - Expression *ecall = e1; - if (ecall->op == TOKcall) - { - ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - if (ecall->op == TOKstar) - { // Calling a function pointer - Expression * pe = ((PtrExp*)ecall)->e1; - if (pe->op == TOKvar) { - VarDeclaration *vd = ((VarExp *)((PtrExp*)ecall)->e1)->var->isVarDeclaration(); - if (vd && vd->getValue() && vd->getValue()->op == TOKsymoff) - fd = ((SymOffExp *)vd->getValue())->var->isFuncDeclaration(); - else - { - ecall = getVarExp(loc, istate, vd, goal); - if (exceptionOrCantInterpret(ecall)) - return ecall; - -#if IN_LLVM - if (ecall->op == TOKaddress) { - AddrExp *e = (AddrExp*)ecall; - if (e->e1->op == TOKvar) - fd = ((VarExp *)e->e1)->var->isFuncDeclaration(); - } -#else - if (ecall->op == TOKsymoff) - fd = ((SymOffExp *)ecall)->var->isFuncDeclaration(); -#endif - } - } - else if (pe->op == TOKsymoff) - fd = ((SymOffExp *)pe)->var->isFuncDeclaration(); - else - ecall = ((PtrExp*)ecall)->e1->interpret(istate); - - } - if (exceptionOrCantInterpret(ecall)) - return ecall; - - if (ecall->op == TOKindex) - { ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - - if (ecall->op == TOKdotvar && !((DotVarExp*)ecall)->var->isFuncDeclaration()) - { ecall = e1->interpret(istate); - if (exceptionOrCantInterpret(ecall)) - return ecall; - } - - if (ecall->op == TOKdotvar) - { // Calling a member function - pthis = ((DotVarExp*)e1)->e1; - fd = ((DotVarExp*)e1)->var->isFuncDeclaration(); - } - else if (ecall->op == TOKvar) - { - VarDeclaration *vd = ((VarExp *)ecall)->var->isVarDeclaration(); - if (vd && vd->getValue()) - ecall = vd->getValue(); - else // Calling a function - fd = ((VarExp *)e1)->var->isFuncDeclaration(); - } - if (ecall->op == TOKdelegate) - { // Calling a delegate - fd = ((DelegateExp *)ecall)->func; - pthis = ((DelegateExp *)ecall)->e1; - } - else if (ecall->op == TOKfunction) - { // Calling a delegate literal - fd = ((FuncExp*)ecall)->fd; - } - else if (ecall->op == TOKstar && ((PtrExp*)ecall)->e1->op==TOKfunction) - { // Calling a function literal - fd = ((FuncExp*)((PtrExp*)ecall)->e1)->fd; - } - - TypeFunction *tf = fd ? (TypeFunction *)(fd->type) : NULL; - if (!tf) - { // DAC: This should never happen, it's an internal compiler error. - //printf("ecall=%s %d %d\n", ecall->toChars(), ecall->op, TOKcall); - if (ecall->op == TOKidentifier) - error("cannot evaluate %s at compile time. Circular reference?", toChars()); - else - error("CTFE internal error: cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (!fd) - { - error("cannot evaluate %s at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (pthis) - { // Member function call - Expression *oldpthis; - if (pthis->op == TOKthis) - { - pthis = istate ? istate->localThis : NULL; - oldpthis = pthis; - } - else - { - if (pthis->op == TOKcomma) - pthis = pthis->interpret(istate); - if (exceptionOrCantInterpret(pthis)) - return pthis; - // Evaluate 'this' - oldpthis = pthis; - if (pthis->op != TOKvar) - pthis = pthis->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(pthis)) - return pthis; - } - if (fd->isVirtual()) - { // Make a virtual function call. - Expression *thisval = pthis; - if (pthis->op == TOKvar) - { assert(((VarExp*)thisval)->var->isVarDeclaration()); - thisval = ((VarExp*)thisval)->var->isVarDeclaration()->getValue(); - } - // Get the function from the vtable of the original class - ClassDeclaration *cd; - if (thisval && thisval->op == TOKnull) - { - error("function call through null class reference %s", pthis->toChars()); - return EXP_CANT_INTERPRET; - } - if (oldpthis->op == TOKsuper) - { assert(oldpthis->type->ty == Tclass); - cd = ((TypeClass *)oldpthis->type)->sym; - } - else - { - assert(thisval && thisval->op == TOKclassreference); - cd = ((ClassReferenceExp *)thisval)->originalClass(); - } - // We can't just use the vtable index to look it up, because - // vtables for interfaces don't get populated until the glue layer. - fd = cd->findFunc(fd->ident, (TypeFunction *)fd->type); - - assert(fd); - } - } - if (fd && fd->semanticRun >= PASSsemantic3done && fd->semantic3Errors) - { - error("CTFE failed because of previous errors in %s", fd->toChars()); - return EXP_CANT_INTERPRET; - } - // Check for built-in functions - Expression *eresult = evaluateIfBuiltin(istate, loc, fd, arguments, pthis); - if (eresult) - return eresult; - - // Inline .dup. Special case because it needs the return type. - if (!pthis && fd->ident == Id::adDup && arguments && arguments->dim == 2) - { - e = arguments->tdata()[1]; - e = e->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (e != EXP_CANT_INTERPRET) - { - if (e->op == TOKslice) - e= resolveSlice(e); - e = paintTypeOntoLiteral(type, copyLiteral(e)); - } - return e; - } - if (!fd->fbody) - { - error("%s cannot be interpreted at compile time," - " because it has no available source code", fd->toChars()); - return EXP_CANT_INTERPRET; - } - eresult = fd->interpret(istate, arguments, pthis); - if (eresult == EXP_CANT_INTERPRET) - { // Print a stack trace. - if (!global.gag) - showCtfeBackTrace(istate, this, fd); - } - return eresult; -} - -Expression *CommaExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("CommaExp::interpret() %s\n", toChars()); -#endif - - CommaExp * firstComma = this; - while (firstComma->e1->op == TOKcomma) - firstComma = (CommaExp *)firstComma->e1; - - // If it creates a variable, and there's no context for - // the variable to be created in, we need to create one now. - InterState istateComma; - if (!istate && firstComma->e1->op == TOKdeclaration) - { - assert(ctfeStack.stackPointer() == 0); - ctfeStack.startFrame(); - istate = &istateComma; - } - - Expression *e = EXP_CANT_INTERPRET; - - // If the comma returns a temporary variable, it needs to be an lvalue - // (this is particularly important for struct constructors) - if (e1->op == TOKdeclaration && e2->op == TOKvar - && ((DeclarationExp *)e1)->declaration == ((VarExp*)e2)->var - && ((VarExp*)e2)->var->storage_class & STCctfe) // same as Expression::isTemp - { - VarExp* ve = (VarExp *)e2; - VarDeclaration *v = ve->var->isVarDeclaration(); - ctfeStack.push(v); - if (!v->init && !v->getValue()) - { - v->setValue(copyLiteral(v->type->defaultInitLiteral())); - } - if (!v->getValue()) { - Expression *newval = v->init->toExpression(); - // Bug 4027. Copy constructors are a weird case where the - // initializer is a void function (the variable is modified - // through a reference parameter instead). - newval = newval->interpret(istate); - if (exceptionOrCantInterpret(newval)) - { - if (istate == &istateComma) - ctfeStack.endFrame(0); - return newval; - } - if (newval != EXP_VOID_INTERPRET) - { - // v isn't necessarily null. - v->setValueWithoutChecking(copyLiteral(newval)); - } - } - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - e = e2; - else - e = e2->interpret(istate, goal); - } - else - { - e = e1->interpret(istate, ctfeNeedNothing); - if (!exceptionOrCantInterpret(e)) - e = e2->interpret(istate, goal); - } - // If we created a temporary stack frame, end it now. - if (istate == &istateComma) - ctfeStack.endFrame(0); - return e; -} - -Expression *CondExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("CondExp::interpret() %s\n", toChars()); -#endif - Expression *e; - if ( isPointer(econd->type) ) - { - e = econd->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - if (e->op != TOKnull) - e = new IntegerExp(loc, 1, Type::tbool); - } - else - e = econd->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - if (isTrueBool(e)) - e = e1->interpret(istate, goal); - else if (e->isBool(FALSE)) - e = e2->interpret(istate, goal); - else - { - error("%s does not evaluate to boolean result at compile time", - econd->toChars()); - e = EXP_CANT_INTERPRET; - } - return e; -} - -Expression *ArrayLengthExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("ArrayLengthExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - assert(e1); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKslice - || e1->op == TOKassocarrayliteral || e1->op == TOKnull) - { - e = new IntegerExp(loc, resolveArrayLength(e1), type); - } - else - { - error("%s cannot be evaluated at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - return e; -} - -/* Given an AA literal 'ae', and a key 'e2': - * Return ae[e2] if present, or NULL if not found. - * Return EXP_CANT_INTERPRET on error. - */ -Expression *findKeyInAA(AssocArrayLiteralExp *ae, Expression *e2) -{ - /* Search the keys backwards, in case there are duplicate keys - */ - for (size_t i = ae->keys->dim; i;) - { - i--; - Expression *ekey = ae->keys->tdata()[i]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, e2); - if (ex == EXP_CANT_INTERPRET) - { - error("cannot evaluate %s==%s at compile time", - ekey->toChars(), e2->toChars()); - return ex; - } - if (ex->isBool(TRUE)) - { - return ae->values->tdata()[i]; - } - } - return NULL; -} - -/* Same as for constfold.Index, except that it only works for static arrays, - * dynamic arrays, and strings. We know that e1 is an - * interpreted CTFE expression, so it cannot have side-effects. - */ -Expression *ctfeIndex(Loc loc, Type *type, Expression *e1, uinteger_t indx) -{ //printf("ctfeIndex(e1 = %s)\n", e1->toChars()); - assert(e1->type); - if (e1->op == TOKstring) - { StringExp *es1 = (StringExp *)e1; - if (indx >= es1->len) - { - error(loc, "string index %ju is out of bounds [0 .. %zu]", indx, es1->len); - return EXP_CANT_INTERPRET; - } - else - return new IntegerExp(loc, es1->charAt(indx), type); - } - assert(e1->op == TOKarrayliteral); - ArrayLiteralExp *ale = (ArrayLiteralExp *)e1; - if (indx >= ale->elements->dim) - { - error(loc, "array index %ju is out of bounds %s[0 .. %u]", indx, e1->toChars(), ale->elements->dim); - return EXP_CANT_INTERPRET; - } - Expression *e = ale->elements->tdata()[indx]; - return paintTypeOntoLiteral(type, e); -} - -Expression *IndexExp::interpret(InterState *istate, CtfeGoal goal) -{ - Expression *e1 = NULL; - Expression *e2; - -#if LOG - printf("IndexExp::interpret() %s\n", toChars()); -#endif - if (this->e1->type->toBasetype()->ty == Tpointer) - { - // Indexing a pointer. Note that there is no $ in this case. - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - dinteger_t indx = e2->toInteger(); - dinteger_t ofs; - Expression *agg = getAggregateFromPointer(e1, &ofs); - if (agg->op == TOKnull) - { - error("cannot index null pointer %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - assert(agg->op == TOKarrayliteral || agg->op == TOKstring); - dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; - if ((indx + ofs) < 0 || (indx+ofs) > len) - { - error("pointer index [%jd] exceeds allocated memory block [0..%jd]", - indx+ofs, len); - return EXP_CANT_INTERPRET; - } - return ctfeIndex(loc, type, agg, indx+ofs); - } - e1 = this->e1; - if (!(e1->op == TOKarrayliteral && ((ArrayLiteralExp *)e1)->ownedByCtfe)) - e1 = e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - - if (e1->op == TOKnull) - { - if (goal == ctfeNeedLvalue && e1->type->ty == Taarray) - return paintTypeOntoLiteral(type, e1); - error("cannot index null array %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - /* Set the $ variable. - * Note that foreach uses indexing but doesn't need $ - */ - if (lengthVar && (e1->op == TOKstring || e1->op == TOKarrayliteral - || e1->op == TOKslice)) - { - uinteger_t dollar = resolveArrayLength(e1); - Expression *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(lengthVar); - lengthVar->setValue(dollarExp); - } - - e2 = this->e2->interpret(istate); - if (lengthVar) - ctfeStack.pop(lengthVar); // $ is defined only inside [] - if (exceptionOrCantInterpret(e2)) - return e2; - if (e1->op == TOKslice && e2->op == TOKint64) - { - // Simplify index of slice: agg[lwr..upr][indx] --> agg[indx'] - uinteger_t indx = e2->toInteger(); - uinteger_t ilo = ((SliceExp *)e1)->lwr->toInteger(); - uinteger_t iup = ((SliceExp *)e1)->upr->toInteger(); - - if (indx > iup - ilo) - { - error("index %ju exceeds array length %ju", indx, iup - ilo); - return EXP_CANT_INTERPRET; - } - indx += ilo; - e1 = ((SliceExp *)e1)->e1; - e2 = new IntegerExp(e2->loc, indx, e2->type); - } - Expression *e = NULL; - if ((goal == ctfeNeedLvalue && type->ty != Taarray && type->ty != Tarray - && type->ty != Tsarray && type->ty != Tstruct && type->ty != Tclass) - || (goal == ctfeNeedLvalueRef && type->ty != Tsarray && type->ty != Tstruct) - ) - { // Pointer or reference of a scalar type - e = new IndexExp(loc, e1, e2); - e->type = type; - return e; - } - if (e1->op == TOKassocarrayliteral) - { - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - e = findKeyInAA((AssocArrayLiteralExp *)e1, e2); - if (!e) - { - error("key %s not found in associative array %s", - e2->toChars(), this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - } - else - { - if (e2->op != TOKint64) - { - e1->error("CTFE internal error: non-integral index [%s]", this->e2->toChars()); - return EXP_CANT_INTERPRET; - } - e = ctfeIndex(loc, type, e1, e2->toInteger()); - } - if (exceptionOrCantInterpret(e)) - return e; - if (goal == ctfeNeedRvalue && (e->op == TOKslice || e->op == TOKdotvar)) - e = e->interpret(istate); - e = paintTypeOntoLiteral(type, e); - return e; -} - - -Expression *SliceExp::interpret(InterState *istate, CtfeGoal goal) -{ - Expression *e1; - Expression *lwr; - Expression *upr; - -#if LOG - printf("SliceExp::interpret() %s\n", toChars()); -#endif - - if (this->e1->type->toBasetype()->ty == Tpointer) - { - // Slicing a pointer. Note that there is no $ in this case. - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKint64) - { - error("cannot slice invalid pointer %s of value %s", - this->e1->toChars(), e1->toChars()); - return EXP_CANT_INTERPRET; - } - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (exceptionOrCantInterpret(lwr)) - return lwr; - upr = this->upr->interpret(istate); - if (exceptionOrCantInterpret(upr)) - return upr; - uinteger_t ilwr; - uinteger_t iupr; - ilwr = lwr->toInteger(); - iupr = upr->toInteger(); - Expression *e; - dinteger_t ofs; - Expression *agg = getAggregateFromPointer(e1, &ofs); - if (agg->op == TOKnull) - { - if (iupr == ilwr) - { - e = new NullExp(loc); - e->type = type; - return e; - } - error("cannot slice null pointer %s", this->e1->toChars()); - return EXP_CANT_INTERPRET; - } - assert(agg->op == TOKarrayliteral || agg->op == TOKstring); - dinteger_t len = ArrayLength(Type::tsize_t, agg)->toInteger(); - Type *pointee = ((TypePointer *)agg->type)->next; - if ((ilwr + ofs) < 0 || (iupr+ofs) > (len + 1) || iupr < ilwr) - { - error("pointer slice [%jd..%jd] exceeds allocated memory block [0..%jd]", - ilwr+ofs, iupr+ofs, len); - return EXP_CANT_INTERPRET; - } - e = new SliceExp(loc, agg, lwr, upr); - e->type = type; - return e; - } - if (goal == ctfeNeedRvalue && this->e1->op == TOKstring) - e1 = this->e1; // Will get duplicated anyway - else - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKvar) - e1 = e1->interpret(istate); - - if (!this->lwr) - { - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - return e1; - return paintTypeOntoLiteral(type, e1); - } - - /* Set the $ variable - */ - if (e1->op != TOKarrayliteral && e1->op != TOKstring && - e1->op != TOKnull && e1->op != TOKslice) - { - error("Cannot determine length of %s at compile time", e1->toChars()); - return EXP_CANT_INTERPRET; - } - uinteger_t dollar = resolveArrayLength(e1); - if (lengthVar) - { - IntegerExp *dollarExp = new IntegerExp(loc, dollar, Type::tsize_t); - ctfeStack.push(lengthVar); - lengthVar->setValue(dollarExp); - } - - /* Evaluate lower and upper bounds of slice - */ - lwr = this->lwr->interpret(istate); - if (exceptionOrCantInterpret(lwr)) - { - if (lengthVar) - ctfeStack.pop(lengthVar);; // $ is defined only inside [L..U] - return lwr; - } - upr = this->upr->interpret(istate); - if (lengthVar) - ctfeStack.pop(lengthVar); // $ is defined only inside [L..U] - if (exceptionOrCantInterpret(upr)) - return upr; - - Expression *e; - uinteger_t ilwr; - uinteger_t iupr; - ilwr = lwr->toInteger(); - iupr = upr->toInteger(); - if (e1->op == TOKnull) - { - if (ilwr== 0 && iupr == 0) - return e1; - e1->error("slice [%ju..%ju] is out of bounds", ilwr, iupr); - return EXP_CANT_INTERPRET; - } - if (e1->op == TOKslice) - { - SliceExp *se = (SliceExp *)e1; - // Simplify slice of slice: - // aggregate[lo1..up1][lwr..upr] ---> aggregate[lwr'..upr'] - uinteger_t lo1 = se->lwr->toInteger(); - uinteger_t up1 = se->upr->toInteger(); - if (ilwr > iupr || iupr > up1 - lo1) - { - error("slice[%ju..%ju] exceeds array bounds[%ju..%ju]", - ilwr, iupr, lo1, up1); - return EXP_CANT_INTERPRET; - } - ilwr += lo1; - iupr += lo1; - e = new SliceExp(loc, se->e1, - new IntegerExp(loc, ilwr, lwr->type), - new IntegerExp(loc, iupr, upr->type)); - e->type = type; - return e; - } - if (e1->op == TOKarrayliteral - || e1->op == TOKstring) - { - if (iupr < ilwr || ilwr < 0 || iupr > dollar) - { - error("slice [%jd..%jd] exceeds array bounds [0..%jd]", - ilwr, iupr, dollar); - return EXP_CANT_INTERPRET; - } - } - e = new SliceExp(loc, e1, lwr, upr); - e->type = type; - return e; -} - -Expression *InExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("InExp::interpret() %s\n", toChars()); -#endif - Expression *e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - Expression *e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKnull) - return new NullExp(loc, type); - if (e2->op != TOKassocarrayliteral) - { - error(" %s cannot be interpreted at compile time", toChars()); - return EXP_CANT_INTERPRET; - } - if (e1->op == TOKslice) - e1 = resolveSlice(e1); - e = findKeyInAA((AssocArrayLiteralExp *)e2, e1); - if (exceptionOrCantInterpret(e)) - return e; - if (!e) - return new NullExp(loc, type); - e = new IndexExp(loc, e2, e1); - e->type = type; - return e; -} - -Expression *CatExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - Expression *e2; - -#if LOG - printf("CatExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op == TOKslice) - { - e1 = resolveSlice(e1); - } - e2 = this->e2->interpret(istate); - if (exceptionOrCantInterpret(e2)) - return e2; - if (e2->op == TOKslice) - e2 = resolveSlice(e2); - e = ctfeCat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - error("%s cannot be interpreted at compile time", toChars()); - // We know we still own it, because we interpreted both e1 and e2 - if (e->op == TOKarrayliteral) - ((ArrayLiteralExp *)e)->ownedByCtfe = true; - if (e->op == TOKstring) - ((StringExp *)e)->ownedByCtfe = true; - return e; -} - - -// Return true if t is a pointer (not a function pointer) -bool isPointer(Type *t) -{ - Type * tb = t->toBasetype(); - return tb->ty == Tpointer && tb->nextOf()->ty != Tfunction; -} - -// Return true if t is an AA, or AssociativeArray!(key, value) -bool isAssocArray(Type *t) -{ - t = t->toBasetype(); - if (t->ty == Taarray) - return true; -#if DMDV2 - if (t->ty != Tstruct) - return false; - StructDeclaration *sym = ((TypeStruct *)t)->sym; - if (sym->ident == Id::AssociativeArray) - return true; -#endif - return false; -} - -// Given a template AA type, extract the corresponding built-in AA type -TypeAArray *toBuiltinAAType(Type *t) -{ - t = t->toBasetype(); - if (t->ty == Taarray) - return (TypeAArray *)t; -#if DMDV2 - assert(t->ty == Tstruct); - StructDeclaration *sym = ((TypeStruct *)t)->sym; - assert(sym->ident == Id::AssociativeArray); - TemplateInstance *tinst = sym->parent->isTemplateInstance(); - assert(tinst); - return new TypeAArray((Type *)(tinst->tiargs->tdata()[1]), (Type *)(tinst->tiargs->tdata()[0])); -#else - assert(0); - return NULL; -#endif -} - -Expression *CastExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("CastExp::interpret() %s\n", toChars()); -#endif - e1 = this->e1->interpret(istate, goal); - if (exceptionOrCantInterpret(e1)) - return e1; - // If the expression has been cast to void, do nothing. - if (to->ty == Tvoid && goal == ctfeNeedNothing) - return e1; - if (to->ty == Tpointer && e1->op != TOKnull) - { - Type *pointee = ((TypePointer *)type)->next; - // Implement special cases of normally-unsafe casts -#if DMDV2 - if (pointee->ty == Taarray && e1->op == TOKaddress - && isAssocArray(((AddrExp*)e1)->e1->type)) - { // cast from template AA pointer to true AA pointer is OK. - return paintTypeOntoLiteral(to, e1); - } -#endif - if (e1->op == TOKint64) - { // Happens with Windows HANDLEs, for example. - return paintTypeOntoLiteral(to, e1); - } - bool castBackFromVoid = false; - if (e1->type->ty == Tarray || e1->type->ty == Tsarray || e1->type->ty == Tpointer) - { - // Check for unsupported type painting operations - // For slices, we need the type being sliced, - // since it may have already been type painted - Type *elemtype = e1->type->nextOf(); - if (e1->op == TOKslice) - elemtype = ((SliceExp *)e1)->e1->type->nextOf(); - // Allow casts from X* to void *, and X** to void** for any X. - // But don't allow cast from X* to void**. - // So, we strip all matching * from source and target to find X. - // Allow casts to X* from void* only if the 'void' was originally an X; - // we check this later on. - Type *ultimatePointee = pointee; - Type *ultimateSrc = elemtype; - while (ultimatePointee->ty == Tpointer && ultimateSrc->ty == Tpointer) - { - ultimatePointee = ultimatePointee->nextOf(); - ultimateSrc = ultimateSrc->nextOf(); - } - if (ultimatePointee->ty != Tvoid && ultimateSrc->ty != Tvoid - && !isSafePointerCast(elemtype, pointee)) - { - error("reinterpreting cast from %s* to %s* is not supported in CTFE", - elemtype->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - if (ultimateSrc->ty == Tvoid) - castBackFromVoid = true; - } - - if (e1->op == TOKslice) - { - if ( ((SliceExp *)e1)->e1->op == TOKnull) - { - return paintTypeOntoLiteral(type, ((SliceExp *)e1)->e1); - } - e = new IndexExp(loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr); - e->type = type; - return e; - } - if (e1->op == TOKarrayliteral || e1->op == TOKstring) - { - e = new IndexExp(loc, e1, new IntegerExp(loc, 0, Type::tsize_t)); - e->type = type; - return e; - } - if (e1->op == TOKindex && ((IndexExp *)e1)->e1->type != e1->type) - { // type painting operation - IndexExp *ie = (IndexExp *)e1; - e = new IndexExp(e1->loc, ie->e1, ie->e2); - if (castBackFromVoid) - { - // get the original type. For strings, it's just the type... - Type *origType = ie->e1->type->nextOf(); - // ..but for arrays of type void*, it's the type of the element - Expression *xx = NULL; - if (ie->e1->op == TOKarrayliteral && ie->e2->op == TOKint64) - { ArrayLiteralExp *ale = (ArrayLiteralExp *)ie->e1; - uinteger_t indx = ie->e2->toInteger(); - if (indx < ale->elements->dim) - xx = ale->elements->tdata()[indx]; - } - if (xx && xx->op == TOKindex) - origType = ((IndexExp *)xx)->e1->type->nextOf(); - else if (xx && xx->op == TOKaddress) - origType= ((AddrExp *)xx)->e1->type; - else if (xx && xx->op == TOKvar) - origType = ((VarExp *)xx)->var->type; - if (!isSafePointerCast(origType, pointee)) - { - error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", - origType->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - } - e->type = type; - return e; - } - if (e1->op == TOKaddress) - { - Type *origType = ((AddrExp *)e1)->type; - if (isSafePointerCast(origType, pointee)) - { - e = new AddrExp(loc, ((AddrExp *)e1)->e1); - e->type = type; - return e; - } - } - if (e1->op == TOKvar) - { // type painting operation - Type *origType = ((VarExp *)e1)->var->type; - if (castBackFromVoid && !isSafePointerCast(origType, pointee)) - { - error("using void* to reinterpret cast from %s* to %s* is not supported in CTFE", - origType->toChars(), pointee->toChars()); - return EXP_CANT_INTERPRET; - } - e = new VarExp(loc, ((VarExp *)e1)->var); - e->type = type; - return e; - } - error("pointer cast from %s to %s is not supported at compile time", - e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - if (to->ty == Tarray && e1->op == TOKslice) - { - e1 = new SliceExp(e1->loc, ((SliceExp *)e1)->e1, ((SliceExp *)e1)->lwr, - ((SliceExp *)e1)->upr); - e1->type = to; - return e1; - } - // Disallow array type painting, except for conversions between built-in - // types of identical size. - if ((to->ty == Tsarray || to->ty == Tarray) && - (e1->type->ty == Tsarray || e1->type->ty == Tarray) && - !isSafePointerCast(e1->type->nextOf(), to->nextOf()) ) - { - error("array cast from %s to %s is not supported at compile time", e1->type->toChars(), to->toChars()); - return EXP_CANT_INTERPRET; - } - if (to->ty == Tsarray && e1->op == TOKslice) - e1 = resolveSlice(e1); - if (to->toBasetype()->ty == Tbool && e1->type->ty==Tpointer) - { - return new IntegerExp(loc, e1->op != TOKnull, to); - } - return ctfeCast(loc, type, to, e1); -} - -Expression *AssertExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e; - Expression *e1; - -#if LOG - printf("AssertExp::interpret() %s\n", toChars()); -#endif -#if DMDV2 - e1 = this->e1->interpret(istate); -#else - // Deal with pointers (including compiler-inserted assert(&this, "null this")) - if ( isPointer(this->e1->type) ) - { - e1 = this->e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e1)) - return e1; - if (e1->op != TOKnull) - return new IntegerExp(loc, 1, Type::tbool); - } - else - e1 = this->e1->interpret(istate); -#endif - if (exceptionOrCantInterpret(e1)) - return e1; - if (isTrueBool(e1)) - { - } - else if (e1->isBool(FALSE)) - { - if (msg) - { - e = msg->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - error("%s", e->toChars()); - } - else - error("%s failed", toChars()); - goto Lcant; - } - else - { - error("%s is not a compile-time boolean expression", e1->toChars()); - goto Lcant; - } - return e1; - -Lcant: - return EXP_CANT_INTERPRET; -} - -Expression *PtrExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("PtrExp::interpret() %s\n", toChars()); -#endif - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { AddExp *ae = (AddExp *)e1; - if (ae->e1->op == TOKaddress && ae->e2->op == TOKint64) - { AddrExp *ade = (AddrExp *)ae->e1; - Expression *ex = ade->e1; - ex = ex->interpret(istate); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->op == TOKstructliteral) - { StructLiteralExp *se = (StructLiteralExp *)ex; - dinteger_t offset = ae->e2->toInteger(); - e = se->getField(type, offset); - if (!e) - e = EXP_CANT_INTERPRET; - return e; - } - } - e = Ptr(type, e1); - } -#if DMDV2 -#else // this is required for D1, where structs return *this instead of 'this'. - else if (e1->op == TOKthis) - { - if(istate->localThis) - return istate->localThis->interpret(istate); - } -#endif - else - { // It's possible we have an array bounds error. We need to make sure it - // errors with this line number, not the one where the pointer was set. - e = e1->interpret(istate, ctfeNeedLvalue); - if (exceptionOrCantInterpret(e)) - return e; - if (!(e->op == TOKvar || e->op == TOKdotvar || e->op == TOKindex - || e->op == TOKslice || e->op == TOKaddress)) - { - error("dereference of invalid pointer '%s'", e->toChars()); - return EXP_CANT_INTERPRET; - } - if (goal != ctfeNeedLvalue) - { - if (e->op == TOKindex && e->type->ty == Tpointer) - { - IndexExp *ie = (IndexExp *)e; - // Is this a real index to an array of pointers, or just a CTFE pointer? - // If the index has the same levels of indirection, it's an index - int srcLevels = 0; - int destLevels = 0; - for(Type *xx = ie->e1->type; xx->ty == Tpointer; xx = xx->nextOf()) - ++srcLevels; - for(Type *xx = e->type->nextOf(); xx->ty == Tpointer; xx = xx->nextOf()) - ++destLevels; - bool isGenuineIndex = (srcLevels == destLevels); - - if ((ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) - && ie->e2->op == TOKint64) - { - Expression *dollar = ArrayLength(Type::tsize_t, ie->e1); - dinteger_t len = dollar->toInteger(); - dinteger_t indx = ie->e2->toInteger(); - assert(indx >=0 && indx <= len); // invalid pointer - if (indx == len) - { - error("dereference of pointer %s one past end of memory block limits [0..%jd]", - toChars(), len); - return EXP_CANT_INTERPRET; - } - e = ctfeIndex(loc, type, ie->e1, indx); - if (isGenuineIndex) - { - if (e->op == TOKindex) - e = e->interpret(istate, goal); - else if (e->op == TOKaddress) - e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); - } - return e; - } - if (ie->e1->op == TOKassocarrayliteral) - { - e = Index(type, ie->e1, ie->e2); - if (isGenuineIndex) - { - if (e->op == TOKindex) - e = e->interpret(istate, goal); - else if (e->op == TOKaddress) - e = paintTypeOntoLiteral(type, ((AddrExp *)e)->e1); - } - return e; - } - } - if (e->op == TOKstructliteral) - return e; - e = e1->interpret(istate, goal); - if (e->op == TOKaddress) - { - e = ((AddrExp*)e)->e1; - if (e->op == TOKdotvar || e->op == TOKindex) - e = e->interpret(istate, goal); - } - else if (e->op == TOKvar) - { - e = e->interpret(istate, goal); - } - if (exceptionOrCantInterpret(e)) - return e; - } - else if (e->op == TOKaddress) - e = ((AddrExp*)e)->e1; // *(&x) ==> x - if (e->op == TOKnull) - { - error("dereference of null pointer '%s'", e1->toChars()); - return EXP_CANT_INTERPRET; - } - e->type = type; - } - -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("PtrExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *DotVarExp::interpret(InterState *istate, CtfeGoal goal) -{ Expression *e = EXP_CANT_INTERPRET; - -#if LOG - printf("DotVarExp::interpret() %s\n", toChars()); -#endif - - Expression *ex = e1->interpret(istate); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex != EXP_CANT_INTERPRET) - { - #if DMDV2 - // Special case for template AAs: AA.var returns the AA itself. - // ie AA.p ----> AA. This is a hack, to get around the - // corresponding hack in the AA druntime implementation. - if (isAssocArray(ex->type)) - return ex; - #endif - if (ex->op == TOKaddress) - ex = ((AddrExp *)ex)->e1; - VarDeclaration *v = var->isVarDeclaration(); - if (!v) - error("CTFE internal error: %s", toChars()); - if (ex->op == TOKnull && ex->type->toBasetype()->ty == Tclass) - { error("class '%s' is null and cannot be dereferenced", e1->toChars()); - return EXP_CANT_INTERPRET; - } - if (ex->op == TOKstructliteral || ex->op == TOKclassreference) - { - StructLiteralExp *se = ex->op == TOKclassreference ? ((ClassReferenceExp *)ex)->value : (StructLiteralExp *)ex; - // We can't use getField, because it makes a copy - int i = -1; - if (ex->op == TOKclassreference) - i = ((ClassReferenceExp *)ex)->findFieldIndexByName(v); - else - i = findFieldIndexByName(se->sd, v); - if (i == -1) - { - error("couldn't find field %s of type %s in %s", v->toChars(), type->toChars(), se->toChars()); - return EXP_CANT_INTERPRET; - } - e = se->elements->tdata()[i]; - if (goal == ctfeNeedLvalue || goal == ctfeNeedLvalueRef) - { - // If it is an lvalue literal, return it... - if (e->op == TOKstructliteral) - return e; - if ((type->ty == Tsarray || goal == ctfeNeedLvalue) && ( - e->op == TOKarrayliteral || - e->op == TOKassocarrayliteral || e->op == TOKstring || - e->op == TOKclassreference || e->op == TOKslice)) - return e; - /* Element is an allocated pointer, which was created in - * CastExp. - */ - if (goal == ctfeNeedLvalue && e->op == TOKindex && - e->type == type && - isPointer(type) ) - return e; - // ...Otherwise, just return the (simplified) dotvar expression - e = new DotVarExp(loc, ex, v); - e->type = type; - return e; - } - if (!e) - { - error("couldn't find field %s in %s", v->toChars(), type->toChars()); - e = EXP_CANT_INTERPRET; - } - // If it is an rvalue literal, return it... - if (e->op == TOKstructliteral || e->op == TOKarrayliteral || - e->op == TOKassocarrayliteral || e->op == TOKstring) - return e; - if ( isPointer(type) ) - { - return paintTypeOntoLiteral(type, e); - } - if (e->op == TOKvar) - { // Don't typepaint twice, since that might cause an erroneous copy - e = getVarExp(loc, istate, ((VarExp *)e)->var, goal); - if (e != EXP_CANT_INTERPRET && e->op != TOKthrownexception) - e = paintTypeOntoLiteral(type, e); - return e; - } - return e->interpret(istate, goal); - } - else - error("%s.%s is not yet implemented at compile time", e1->toChars(), var->toChars()); - } - -#if LOG - if (e == EXP_CANT_INTERPRET) - printf("DotVarExp::interpret() %s = EXP_CANT_INTERPRET\n", toChars()); -#endif - return e; -} - -Expression *RemoveExp::interpret(InterState *istate, CtfeGoal goal) -{ -#if LOG - printf("RemoveExp::interpret() %s\n", toChars()); -#endif - Expression *agg = e1->interpret(istate); - if (exceptionOrCantInterpret(agg)) - return agg; - Expression *index = e2->interpret(istate); - if (exceptionOrCantInterpret(index)) - return index; - if (agg->op == TOKnull) - return EXP_VOID_INTERPRET; - assert(agg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)agg; - Expressions *keysx = aae->keys; - Expressions *valuesx = aae->values; - size_t removed = 0; - for (size_t j = 0; j < valuesx->dim; ++j) - { Expression *ekey = keysx->tdata()[j]; - Expression *ex = ctfeEqual(TOKequal, Type::tbool, ekey, index); - if (exceptionOrCantInterpret(ex)) - return ex; - if (ex->isBool(TRUE)) - ++removed; - else if (removed != 0) - { keysx->tdata()[j - removed] = ekey; - valuesx->tdata()[j - removed] = valuesx->tdata()[j]; - } - } - valuesx->dim = valuesx->dim - removed; - keysx->dim = keysx->dim - removed; - return new IntegerExp(loc, removed?1:0, Type::tbool); -} - - -/******************************* Special Functions ***************************/ - -Expression *interpret_length(InterState *istate, Expression *earg) -{ - //printf("interpret_length()\n"); - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - dinteger_t len = 0; - if (earg->op == TOKassocarrayliteral) - len = ((AssocArrayLiteralExp *)earg)->keys->dim; - else assert(earg->op == TOKnull); - Expression *e = new IntegerExp(earg->loc, len, Type::tsize_t); - return e; -} - -Expression *interpret_keys(InterState *istate, Expression *earg, Type *elemType) -{ -#if LOG - printf("interpret_keys()\n"); -#endif - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - assert(earg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->keys); - ae->ownedByCtfe = aae->ownedByCtfe; - ae->type = new TypeSArray(elemType, new IntegerExp(aae->keys->dim)); - return copyLiteral(ae); -} - -Expression *interpret_values(InterState *istate, Expression *earg, Type *elemType) -{ -#if LOG - printf("interpret_values()\n"); -#endif - earg = earg->interpret(istate); - if (earg == EXP_CANT_INTERPRET) - return NULL; - if (exceptionOrCantInterpret(earg)) - return earg; - if (earg->op == TOKnull) - return new NullExp(earg->loc); - if (earg->op != TOKassocarrayliteral && earg->type->toBasetype()->ty != Taarray) - return NULL; - assert(earg->op == TOKassocarrayliteral); - AssocArrayLiteralExp *aae = (AssocArrayLiteralExp *)earg; - ArrayLiteralExp *ae = new ArrayLiteralExp(aae->loc, aae->values); - ae->ownedByCtfe = aae->ownedByCtfe; - ae->type = new TypeSArray(elemType, new IntegerExp(aae->values->dim)); - //printf("result is %s\n", e->toChars()); - return copyLiteral(ae); -} - -// signature is int delegate(ref Value) OR int delegate(ref Key, ref Value) -Expression *interpret_aaApply(InterState *istate, Expression *aa, Expression *deleg) -{ aa = aa->interpret(istate); - if (exceptionOrCantInterpret(aa)) - return aa; - if (aa->op != TOKassocarrayliteral) - return new IntegerExp(deleg->loc, 0, Type::tsize_t); - - FuncDeclaration *fd = NULL; - Expression *pthis = NULL; - if (deleg->op == TOKdelegate) - { - fd = ((DelegateExp *)deleg)->func; - pthis = ((DelegateExp *)deleg)->e1; - } - else if (deleg->op == TOKfunction) - fd = ((FuncExp*)deleg)->fd; - - assert(fd && fd->fbody); - assert(fd->parameters); - int numParams = fd->parameters->dim; - assert(numParams == 1 || numParams==2); - - Type *valueType = fd->parameters->tdata()[numParams-1]->type; - Type *keyType = numParams == 2 ? fd->parameters->tdata()[0]->type - : Type::tsize_t; - Expressions args; - args.setDim(numParams); - - AssocArrayLiteralExp *ae = (AssocArrayLiteralExp *)aa; - if (!ae->keys || ae->keys->dim == 0) - return new IntegerExp(deleg->loc, 0, Type::tsize_t); - Expression *eresult; - - for (size_t i = 0; i < ae->keys->dim; ++i) - { - Expression *ekey = ae->keys->tdata()[i]; - Expression *evalue = ae->values->tdata()[i]; - args.tdata()[numParams - 1] = evalue; - if (numParams == 2) args.tdata()[0] = ekey; - - eresult = fd->interpret(istate, &args, pthis); - if (exceptionOrCantInterpret(eresult)) - return eresult; - - assert(eresult->op == TOKint64); - if (((IntegerExp *)eresult)->value != 0) - return eresult; - } - return eresult; -} - -// Helper function: given a function of type A[] f(...), -// return A. -Type *returnedArrayElementType(FuncDeclaration *fd) -{ - assert(fd->type->ty == Tfunction); - assert(fd->type->nextOf()->ty == Tarray); - return ((TypeFunction *)fd->type)->nextOf()->nextOf(); -} - -/* Decoding UTF strings for foreach loops. Duplicates the functionality of - * the twelve _aApplyXXn functions in aApply.d in the runtime. - */ -Expression *foreachApplyUtf(InterState *istate, Expression *str, Expression *deleg, bool rvs) -{ -#if LOG - printf("foreachApplyUtf(%s, %s)\n", str->toChars(), deleg->toChars()); -#endif - FuncDeclaration *fd = NULL; - Expression *pthis = NULL; - if (deleg->op == TOKdelegate) - { - fd = ((DelegateExp *)deleg)->func; - pthis = ((DelegateExp *)deleg)->e1; - } - else if (deleg->op == TOKfunction) - fd = ((FuncExp*)deleg)->fd; - - assert(fd && fd->fbody); - assert(fd->parameters); - int numParams = fd->parameters->dim; - assert(numParams == 1 || numParams==2); - Type *charType = fd->parameters->tdata()[numParams-1]->type; - Type *indexType = numParams == 2 ? fd->parameters->tdata()[0]->type - : Type::tsize_t; - uinteger_t len = resolveArrayLength(str); - if (len == 0) - return new IntegerExp(deleg->loc, 0, indexType); - - if (str->op == TOKslice) - str = resolveSlice(str); - - StringExp *se = NULL; - ArrayLiteralExp *ale = NULL; - if (str->op == TOKstring) - se = (StringExp *) str; - else if (str->op == TOKarrayliteral) - ale = (ArrayLiteralExp *)str; - else - { error("CTFE internal error: cannot foreach %s", str->toChars()); - return EXP_CANT_INTERPRET; - } - Expressions args; - args.setDim(numParams); - - Expression *eresult; - - // Buffers for encoding; also used for decoding array literals - unsigned char utf8buf[4]; - unsigned short utf16buf[2]; - - size_t start = rvs ? len : 0; - size_t end = rvs ? 0: len; - for (size_t indx = start; indx != end;) - { - // Step 1: Decode the next dchar from the string. - - const char *errmsg = NULL; // Used for reporting decoding errors - dchar_t rawvalue; // Holds the decoded dchar - size_t currentIndex = indx; // The index of the decoded character - - if (ale) - { // If it is an array literal, copy the code points into the buffer - int buflen = 1; // #code points in the buffer - size_t n = 1; // #code points in this char - size_t sz = ale->type->nextOf()->size(); - - switch(sz) - { - case 1: - if (rvs) - { // find the start of the string - --indx; - buflen = 1; - while (indx > 0 && buflen < 4) - { Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - unsigned char x = (unsigned char)(((IntegerExp *)r)->value); - if ( (x & 0xC0) != 0x80) - break; - ++buflen; - } - } - else - buflen = (indx + 4 > len) ? len - indx : 4; - for (int i=0; i < buflen; ++i) - { - Expression * r = ale->elements->tdata()[indx + i]; - assert(r->op == TOKint64); - utf8buf[i] = (unsigned char)(((IntegerExp *)r)->value); - } - n = 0; - errmsg = utf_decodeChar(&utf8buf[0], buflen, &n, &rawvalue); - break; - case 2: - if (rvs) - { // find the start of the string - --indx; - buflen = 1; - Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - unsigned short x = (unsigned short)(((IntegerExp *)r)->value); - if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF) - { - --indx; - ++buflen; - } - } - else - buflen = (indx + 2 > len) ? len - indx : 2; - for (int i=0; i < buflen; ++i) - { - Expression * r = ale->elements->tdata()[indx + i]; - assert(r->op == TOKint64); - utf16buf[i] = (unsigned short)(((IntegerExp *)r)->value); - } - n = 0; - errmsg = utf_decodeWchar(&utf16buf[0], buflen, &n, &rawvalue); - break; - case 4: - { - if (rvs) - --indx; - - Expression * r = ale->elements->tdata()[indx]; - assert(r->op == TOKint64); - rawvalue = ((IntegerExp *)r)->value; - n = 1; - } - break; - default: - assert(0); - } - if (!rvs) - indx += n; - } - else - { // String literals - size_t saveindx; // used for reverse iteration - - switch (se->sz) - { - case 1: - if (rvs) - { // find the start of the string - unsigned char *s = (unsigned char *)se->string; - --indx; - while (indx > 0 && ((s[indx]&0xC0)==0x80)) - --indx; - saveindx = indx; - } - errmsg = utf_decodeChar((unsigned char *)se->string, se->len, &indx, &rawvalue); - if (rvs) - indx = saveindx; - break; - case 2: - if (rvs) - { // find the start - unsigned short *s = (unsigned short *)se->string; - --indx; - if (s[indx] >= 0xDC00 && s[indx]<= 0xDFFF) - --indx; - saveindx = indx; - } - errmsg = utf_decodeWchar((unsigned short *)se->string, se->len, &indx, &rawvalue); - if (rvs) - indx = saveindx; - break; - case 4: - if (rvs) - --indx; - rawvalue = ((unsigned *)(se->string))[indx]; - if (!rvs) - ++indx; - break; - default: - assert(0); - } - } - if (errmsg) - { deleg->error("%s", errmsg); - return EXP_CANT_INTERPRET; - } - - // Step 2: encode the dchar in the target encoding - - int charlen = 1; // How many codepoints are involved? - switch(charType->size()) - { - case 1: - charlen = utf_codeLengthChar(rawvalue); - utf_encodeChar(&utf8buf[0], rawvalue); - break; - case 2: - charlen = utf_codeLengthWchar(rawvalue); - utf_encodeWchar(&utf16buf[0], rawvalue); - break; - case 4: - break; - default: - assert(0); - } - if (rvs) - currentIndex = indx; - - // Step 3: call the delegate once for each code point - - // The index only needs to be set once - if (numParams == 2) - args.tdata()[0] = new IntegerExp(deleg->loc, currentIndex, indexType); - - Expression *val = NULL; - - for (int k= 0; k < charlen; ++k) - { - dchar_t codepoint; - switch(charType->size()) - { - case 1: - codepoint = utf8buf[k]; - break; - case 2: - codepoint = utf16buf[k]; - break; - case 4: - codepoint = rawvalue; - break; - default: - assert(0); - } - val = new IntegerExp(str->loc, codepoint, charType); - - args.tdata()[numParams - 1] = val; - - eresult = fd->interpret(istate, &args, pthis); - if (exceptionOrCantInterpret(eresult)) - return eresult; - assert(eresult->op == TOKint64); - if (((IntegerExp *)eresult)->value != 0) - return eresult; - } - } - return eresult; -} - -/* If this is a built-in function, return the interpreted result, - * Otherwise, return NULL. - */ -Expression *evaluateIfBuiltin(InterState *istate, Loc loc, - FuncDeclaration *fd, Expressions *arguments, Expression *pthis) -{ - Expression *e = NULL; - int nargs = arguments ? arguments->dim : 0; -#if DMDV2 - if (pthis && isAssocArray(pthis->type)) - { - if (fd->ident == Id::length && nargs==0) - return interpret_length(istate, pthis); - else if (fd->ident == Id::keys && nargs==0) - return interpret_keys(istate, pthis, returnedArrayElementType(fd)); - else if (fd->ident == Id::values && nargs==0) - return interpret_values(istate, pthis, returnedArrayElementType(fd)); - else if (fd->ident == Id::rehash && nargs==0) - return pthis->interpret(istate, ctfeNeedLvalue); // rehash is a no-op - } - if (!pthis) - { - enum BUILTIN b = fd->isBuiltin(); - if (b) - { Expressions args; - args.setDim(nargs); - for (size_t i = 0; i < args.dim; i++) - { - Expression *earg = arguments->tdata()[i]; - earg = earg->interpret(istate); - if (exceptionOrCantInterpret(earg)) - return earg; - args.tdata()[i] = earg; - } - e = eval_builtin(loc, b, &args); - if (!e) - e = EXP_CANT_INTERPRET; - } - } - /* Horrid hack to retrieve the builtin AA functions after they've been - * mashed by the inliner. - */ - if (!pthis) - { - Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; - // Check for the first parameter being a templatized AA. Hack: we assume that - // template AA.var is always the AA data itself. - Expression *firstdotvar = (firstarg && firstarg->op == TOKdotvar) - ? ((DotVarExp *)firstarg)->e1 : NULL; - if (nargs==3 && isAssocArray(firstarg->type) && !strcmp(fd->ident->string, "_aaApply")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - if (nargs==3 && isAssocArray(firstarg->type) &&!strcmp(fd->ident->string, "_aaApply2")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - if (firstdotvar && isAssocArray(firstdotvar->type)) - { if (fd->ident == Id::aaLen && nargs == 1) - return interpret_length(istate, firstdotvar->interpret(istate)); - else if (fd->ident == Id::aaKeys && nargs == 2) - { - Expression *trueAA = firstdotvar->interpret(istate); - return interpret_keys(istate, trueAA, toBuiltinAAType(trueAA->type)->index); - } - else if (fd->ident == Id::aaValues && nargs == 3) - { - Expression *trueAA = firstdotvar->interpret(istate); - return interpret_values(istate, trueAA, toBuiltinAAType(trueAA->type)->nextOf()); - } - else if (fd->ident == Id::aaRehash && nargs == 2) - { - return firstdotvar->interpret(istate, ctfeNeedLvalue); - } - } - } -#endif -#if DMDV1 - if (!pthis) - { - Expression *firstarg = nargs > 0 ? (Expression *)(arguments->data[0]) : NULL; - if (firstarg && firstarg->type->toBasetype()->ty == Taarray) - { - TypeAArray *firstAAtype = (TypeAArray *)firstarg->type; - if (fd->ident == Id::aaLen && nargs == 1) - return interpret_length(istate, firstarg); - else if (fd->ident == Id::aaKeys) - return interpret_keys(istate, firstarg, firstAAtype->index); - else if (fd->ident == Id::aaValues) - return interpret_values(istate, firstarg, firstAAtype->nextOf()); - else if (nargs==2 && fd->ident == Id::aaRehash) - return firstarg->interpret(istate, ctfeNeedLvalue); //no-op - else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - else if (nargs==3 && !strcmp(fd->ident->string, "_aaApply2")) - return interpret_aaApply(istate, firstarg, (Expression *)(arguments->data[2])); - } - } -#endif -#if DMDV2 - if (pthis && !fd->fbody && fd->isCtorDeclaration() && fd->parent && fd->parent->parent && fd->parent->parent->ident == Id::object) - { - if (pthis->op == TOKclassreference && fd->parent->ident == Id::Throwable) - { // At present, the constructors just copy their arguments into the struct. - // But we might need some magic if stack tracing gets added to druntime. - StructLiteralExp *se = ((ClassReferenceExp *)pthis)->value; - assert(arguments->dim <= se->elements->dim); - for (int i = 0; i < arguments->dim; ++i) - { - Expression *e = arguments->tdata()[i]->interpret(istate); - if (exceptionOrCantInterpret(e)) - return e; - se->elements->tdata()[i] = e; - } - return EXP_VOID_INTERPRET; - } - } -#endif - if (nargs == 1 && !pthis && - (fd->ident == Id::criticalenter || fd->ident == Id::criticalexit)) - { // Support synchronized{} as a no-op - return EXP_VOID_INTERPRET; - } - if (!pthis) - { - size_t idlen = strlen(fd->ident->string); - if (nargs == 2 && (idlen == 10 || idlen == 11) - && !strncmp(fd->ident->string, "_aApply", 7)) - { // Functions from aApply.d and aApplyR.d in the runtime - bool rvs = (idlen == 11); // true if foreach_reverse - char c = fd->ident->string[idlen-3]; // char width: 'c', 'w', or 'd' - char s = fd->ident->string[idlen-2]; // string width: 'c', 'w', or 'd' - char n = fd->ident->string[idlen-1]; // numParams: 1 or 2. - // There are 12 combinations - if ( (n == '1' || n == '2') && - (c == 'c' || c == 'w' || c == 'd') && - (s == 'c' || s == 'w' || s == 'd') && c != s) - { Expression *str = arguments->tdata()[0]; - str = str->interpret(istate); - if (exceptionOrCantInterpret(str)) - return str; - return foreachApplyUtf(istate, str, arguments->tdata()[1], rvs); - } - } - } - return e; -} - -/*************************** CTFE Sanity Checks ***************************/ - -/* Setter functions for CTFE variable values. - * These functions exist to check for compiler CTFE bugs. - */ - -bool isCtfeValueValid(Expression *newval) -{ - if ( -#if DMDV2 - newval->type->ty == Tnull || -#endif - isPointer(newval->type) ) - { - if (newval->op == TOKaddress || newval->op == TOKnull || - newval->op == TOKstring) - return true; - if (newval->op == TOKindex) - { - Expression *g = ((IndexExp *)newval)->e1; - if (g->op == TOKarrayliteral || g->op == TOKstring || - g->op == TOKassocarrayliteral) - return true; - } - if (newval->op == TOKvar) - return true; - if (newval->type->nextOf()->ty == Tarray && newval->op == TOKslice) - return true; - if (newval->op == TOKint64) - return true; // Result of a cast, but cannot be dereferenced - // else it must be a reference - } - if (newval->op == TOKclassreference || (newval->op == TOKnull && newval->type->ty == Tclass)) - return true; - if (newval->op == TOKvar) - { - VarExp *ve = (VarExp *)newval; - VarDeclaration *vv = ve->var->isVarDeclaration(); - // Must not be a reference to a reference - if (!(vv && vv->getValue() && vv->getValue()->op == TOKvar)) - return true; - } - if (newval->op == TOKdotvar) - { - if (((DotVarExp *)newval)->e1->op == TOKstructliteral) - { - assert(((StructLiteralExp *)((DotVarExp *)newval)->e1)->ownedByCtfe); - return true; - } - } - if (newval->op == TOKindex) - { - IndexExp *ie = (IndexExp *)newval; - if (ie->e2->op == TOKint64) - { - if (ie->e1->op == TOKarrayliteral || ie->e1->op == TOKstring) - return true; - } - if (ie->e1->op == TOKassocarrayliteral) - return true; - // BUG: Happens ONLY in ref foreach. Should tighten this. - if (ie->e2->op == TOKvar) - return true; - } - if (newval->op == TOKfunction) return true; // function/delegate literal - if (newval->op == TOKdelegate) return true; - if (newval->op == TOKsymoff) // function pointer - { - if (((SymOffExp *)newval)->var->isFuncDeclaration()) - return true; - } -#if IN_LLVM - if (newval->op == TOKaddress) { // function pointer - AddrExp *ae = (AddrExp *)newval; - if (ae->e1->op == TOKvar) { - if (((VarExp *)ae->e1)->var->isFuncDeclaration()) - return true; - } - } -#endif - if (newval->op == TOKint64 || newval->op == TOKfloat64 || - newval->op == TOKchar || newval->op == TOKcomplex80) - return true; - - // References - - if (newval->op == TOKstructliteral) - assert(((StructLiteralExp *)newval)->ownedByCtfe); - if (newval->op == TOKarrayliteral) - assert(((ArrayLiteralExp *)newval)->ownedByCtfe); - if (newval->op == TOKassocarrayliteral) - assert(((AssocArrayLiteralExp *)newval)->ownedByCtfe); - - if ((newval->op ==TOKarrayliteral) || ( newval->op==TOKstructliteral) || - (newval->op==TOKstring) || (newval->op == TOKassocarrayliteral) || - (newval->op == TOKnull)) - { return true; - } - // Dynamic arrays passed by ref may be null. When this happens - // they may originate from an index or dotvar expression. - if (newval->type->ty == Tarray || newval->type->ty == Taarray) - if (newval->op == TOKdotvar || newval->op == TOKindex) - return true; // actually must be null - - if (newval->op == TOKslice) - { - SliceExp *se = (SliceExp *)newval; - assert(se->lwr && se->lwr != EXP_CANT_INTERPRET && se->lwr->op == TOKint64); - assert(se->upr && se->upr != EXP_CANT_INTERPRET && se->upr->op == TOKint64); - assert(se->e1->op == TOKarrayliteral || se->e1->op == TOKstring); - if (se->e1->op == TOKarrayliteral) - assert(((ArrayLiteralExp *)se->e1)->ownedByCtfe); - return true; - } - newval->error("CTFE internal error: illegal value %s\n", newval->toChars()); - return false; -} - -bool VarDeclaration::hasValue() -{ - if (ctfeAdrOnStack == (size_t)-1) - return false; - return NULL != getValue(); -} - -Expression *VarDeclaration::getValue() -{ - return ctfeStack.getValue(this); -} - -void VarDeclaration::setValueNull() -{ - ctfeStack.setValue(this, NULL); -} - -// Don't check for validity -void VarDeclaration::setValueWithoutChecking(Expression *newval) -{ - ctfeStack.setValue(this, newval); -} - -void VarDeclaration::setValue(Expression *newval) -{ - assert(isCtfeValueValid(newval)); - ctfeStack.setValue(this, newval); -} diff --git a/dmd2/intrange.c b/dmd2/intrange.c deleted file mode 100644 index baf099c0..00000000 --- a/dmd2/intrange.c +++ /dev/null @@ -1,1105 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by KennyTM -// 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 "intrange.h" -#include "mars.h" -#include "mtype.h" -#include "expression.h" - -#ifndef PERFORM_UNITTEST -#define PERFORM_UNITTEST 0 -#endif - -// Copy the sign to the value *x*. Equivalent to `sign ? -x : x`. -static uinteger_t copySign(uinteger_t x, bool sign) -{ - // return sign ? -x : x; - return (x - (uinteger_t)sign) ^ -(uinteger_t)sign; -} - -#ifndef UINT64_MAX -#define UINT64_MAX 0xFFFFFFFFFFFFFFFFULL -#endif - -//==================== SignExtendedNumber ====================================== - -SignExtendedNumber SignExtendedNumber::fromInteger(uinteger_t value_) -{ - return SignExtendedNumber(value_, value_ >> 63); -} - -bool SignExtendedNumber::operator==(const SignExtendedNumber& a) const -{ - return value == a.value && negative == a.negative; -} - -bool SignExtendedNumber::operator<(const SignExtendedNumber& a) const -{ - return (negative && !a.negative) - || (negative == a.negative && value < a.value); -} - -SignExtendedNumber SignExtendedNumber::extreme(bool minimum) -{ - return SignExtendedNumber(minimum-1, minimum); -} - -SignExtendedNumber SignExtendedNumber::max() -{ - return SignExtendedNumber(UINT64_MAX, false); -} - -SignExtendedNumber SignExtendedNumber::operator-() const -{ - if (value == 0) - return SignExtendedNumber(-negative); - else - return SignExtendedNumber(-value, !negative); -} - -SignExtendedNumber SignExtendedNumber::operator+(const SignExtendedNumber& a) const -{ - uinteger_t sum = value + a.value; - bool carry = sum < value && sum < a.value; - if (negative != a.negative) - return SignExtendedNumber(sum, !carry); - else if (negative) - return SignExtendedNumber(carry ? sum : 0, true); - else - return SignExtendedNumber(carry ? UINT64_MAX : sum, false); -} - -SignExtendedNumber SignExtendedNumber::operator-(const SignExtendedNumber& a) const -{ - if (a.isMinimum()) - return negative ? SignExtendedNumber(value, false) : max(); - else - return *this + (-a); -} - - -SignExtendedNumber SignExtendedNumber::operator*(const SignExtendedNumber& a) const -{ - // perform *saturated* multiplication, otherwise we may get bogus ranges - // like 0x10 * 0x10 == 0x100 == 0. - - /* Special handling for zeros: - INT65_MIN * 0 = 0 - INT65_MIN * + = INT65_MIN - INT65_MIN * - = INT65_MAX - 0 * anything = 0 - */ - if (value == 0) - { - if (!negative) - return *this; - else if (a.negative) - return max(); - else - return a.value == 0 ? a : *this; - } - else if (a.value == 0) - return a * *this; // don't duplicate the symmetric case. - - SignExtendedNumber rv; - // these are != 0 now surely. - uinteger_t tAbs = copySign(value, negative); - uinteger_t aAbs = copySign(a.value, a.negative); - rv.negative = negative != a.negative; - if (UINT64_MAX / tAbs < aAbs) - rv.value = rv.negative-1; - else - rv.value = copySign(tAbs * aAbs, rv.negative); - return rv; -} - -SignExtendedNumber SignExtendedNumber::operator/(const SignExtendedNumber& a) const -{ - /* special handling for zeros: - INT65_MIN / INT65_MIN = 1 - anything / INT65_MIN = 0 - + / 0 = INT65_MAX (eh?) - - / 0 = INT65_MIN (eh?) - */ - if (a.value == 0) - { - if (a.negative) - return SignExtendedNumber(value == 0 && negative); - else - return extreme(negative); - } - - uinteger_t aAbs = copySign(a.value, a.negative); - uinteger_t rvVal; - - if (!isMinimum()) - rvVal = copySign(value, negative) / aAbs; - // Special handling for INT65_MIN - // if the denominator is not a power of 2, it is same as UINT64_MAX / x. - else if (aAbs & (aAbs-1)) - rvVal = UINT64_MAX / aAbs; - // otherwise, it's the same as reversing the bits of x. - else - { - if (aAbs == 1) - return extreme(!a.negative); - rvVal = 1ULL << 63; - aAbs >>= 1; - if (aAbs & 0xAAAAAAAAAAAAAAAAULL) rvVal >>= 1; - if (aAbs & 0xCCCCCCCCCCCCCCCCULL) rvVal >>= 2; - if (aAbs & 0xF0F0F0F0F0F0F0F0ULL) rvVal >>= 4; - if (aAbs & 0xFF00FF00FF00FF00ULL) rvVal >>= 8; - if (aAbs & 0xFFFF0000FFFF0000ULL) rvVal >>= 16; - if (aAbs & 0xFFFFFFFF00000000ULL) rvVal >>= 32; - } - bool rvNeg = negative != a.negative; - rvVal = copySign(rvVal, rvNeg); - - return SignExtendedNumber(rvVal, rvVal != 0 && rvNeg); -} - -SignExtendedNumber SignExtendedNumber::operator%(const SignExtendedNumber& a) const -{ - if (a.value == 0) - return !a.negative ? a : isMinimum() ? SignExtendedNumber(0) : *this; - - uinteger_t aAbs = copySign(a.value, a.negative); - uinteger_t rvVal; - - // a % b == sgn(a) * abs(a) % abs(b). - if (!isMinimum()) - rvVal = copySign(value, negative) % aAbs; - // Special handling for INT65_MIN - // if the denominator is not a power of 2, it is same as UINT64_MAX%x + 1. - else if (aAbs & (aAbs - 1)) - rvVal = UINT64_MAX % aAbs + 1; - // otherwise, the modulus is trivially zero. - else - rvVal = 0; - - rvVal = copySign(rvVal, negative); - return SignExtendedNumber(rvVal, rvVal != 0 && negative); -} - -SignExtendedNumber& SignExtendedNumber::operator++() -{ - if (value != UINT64_MAX) - ++ value; - else if (negative) - { - value = 0; - negative = false; - } - return *this; -} - -SignExtendedNumber SignExtendedNumber::operator<<(const SignExtendedNumber& a) const -{ - // assume left-shift the shift-amount is always unsigned. Thus negative - // shifts will give huge result. - if (value == 0) - return *this; - else if (a.negative) - return extreme(negative); - - uinteger_t v = copySign(value, negative); - - // compute base-2 log of 'v' to determine the maximum allowed bits to shift. - // Ref: http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog - - size_t r, s; - - r = (v > 0xFFFFFFFFULL) << 5; v >>= r; - s = (v > 0xFFFFULL ) << 4; v >>= s; r |= s; - s = (v > 0xFFULL ) << 3; v >>= s; r |= s; - s = (v > 0xFULL ) << 2; v >>= s; r |= s; - s = (v > 0x3ULL ) << 1; v >>= s; r |= s; - r |= (v >> 1); - - uinteger_t allowableShift = 63 - r; - if (a.value > allowableShift) - return extreme(negative); - else - return SignExtendedNumber(value << a.value, negative); -} - -SignExtendedNumber SignExtendedNumber::operator>>(const SignExtendedNumber& a) const -{ - if (a.negative || a.value > 64) - return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0); - else if (isMinimum()) - return a.value == 0 ? *this : SignExtendedNumber(-1ULL << (64-a.value), true); - - uinteger_t x = value ^ -negative; - x >>= a.value; - return SignExtendedNumber(x ^ -negative, negative); -} - - -//==================== IntRange ================================================ - -IntRange IntRange::widest() -{ - return IntRange(SignExtendedNumber::min(), SignExtendedNumber::max()); -} - -#if !PERFORM_UNITTEST -IntRange IntRange::fromType(Type *type) -{ - return fromType(type, type->isunsigned()); -} - -IntRange IntRange::fromType(Type *type, bool isUnsigned) -{ - if (!type->isintegral()) - return widest(); - - uinteger_t mask = type->sizemask(); - SignExtendedNumber lower(0), upper(mask); - if (type->toBasetype()->ty == Tdchar) - upper.value = 0x10FFFFULL; - else if (!isUnsigned) - { - lower.value = ~(mask >> 1); - lower.negative = true; - upper.value = (mask >> 1); - } - return IntRange(lower, upper); -} -#endif - -IntRange IntRange::fromNumbers2(const SignExtendedNumber numbers[2]) -{ - if (numbers[0] < numbers[1]) - return IntRange(numbers[0], numbers[1]); - else - return IntRange(numbers[1], numbers[0]); -} -IntRange IntRange::fromNumbers4(const SignExtendedNumber numbers[4]) -{ - IntRange ab = fromNumbers2(numbers); - IntRange cd = fromNumbers2(numbers + 2); - if (cd.imin < ab.imin) - ab.imin = cd.imin; - if (cd.imax > ab.imax) - ab.imax = cd.imax; - return ab; -} - -bool IntRange::contains(const IntRange& a) const -{ - return imin <= a.imin && imax >= a.imax; -} - -bool IntRange::containsZero() const -{ - return (imin.negative && !imax.negative) - || (!imin.negative && imin.value == 0); -} - -IntRange& IntRange::castUnsigned(uinteger_t mask) -{ - // .... 0x1eff ] [0x1f00 .. 0x1fff] [0 .. 0xff] [0x100 .. 0x1ff] [0x200 .... - // - // regular unsigned type. We just need to see if ir steps across the - // boundary of validRange. If yes, ir will represent the whole validRange, - // otherwise, we just take the modulus. - // e.g. [0x105, 0x107] & 0xff == [5, 7] - // [0x105, 0x207] & 0xff == [0, 0xff] - uinteger_t minChunk = imin.value & ~mask; - uinteger_t maxChunk = imax.value & ~mask; - if (minChunk == maxChunk && imin.negative == imax.negative) - { - imin.value &= mask; - imax.value &= mask; - } - else - { - imin.value = 0; - imax.value = mask; - } - imin.negative = imax.negative = false; - return *this; -} - -IntRange& IntRange::castSigned(uinteger_t mask) -{ - // .... 0x1e7f ] [0x1e80 .. 0x1f7f] [0x1f80 .. 0x7f] [0x80 .. 0x17f] [0x180 .... - // - // regular signed type. We use a technique similar to the unsigned version, - // but the chunk has to be offset by 1/2 of the range. - uinteger_t halfChunkMask = mask >> 1; - uinteger_t minHalfChunk = imin.value & ~halfChunkMask; - uinteger_t maxHalfChunk = imax.value & ~halfChunkMask; - int minHalfChunkNegativity = imin.negative; // 1 = neg, 0 = nonneg, -1 = chunk containing ::max - int maxHalfChunkNegativity = imax.negative; - if (minHalfChunk & mask) - { - minHalfChunk += halfChunkMask+1; - if (minHalfChunk == 0) - -- minHalfChunkNegativity; - } - if (maxHalfChunk & mask) - { - maxHalfChunk += halfChunkMask+1; - if (maxHalfChunk == 0) - -- maxHalfChunkNegativity; - } - if (minHalfChunk == maxHalfChunk && minHalfChunkNegativity == maxHalfChunkNegativity) - { - imin.value &= mask; - imax.value &= mask; - // sign extend if necessary. - imin.negative = imin.value & ~halfChunkMask; - imax.negative = imax.value & ~halfChunkMask; - halfChunkMask += 1; - imin.value = (imin.value ^ halfChunkMask) - halfChunkMask; - imax.value = (imax.value ^ halfChunkMask) - halfChunkMask; - } - else - { - imin = SignExtendedNumber(~halfChunkMask, true); - imax = SignExtendedNumber(halfChunkMask, false); - } - return *this; -} - -IntRange& IntRange::castDchar() -{ - // special case for dchar. Casting to dchar means "I'll ignore all - // invalid characters." - castUnsigned(0xFFFFFFFFULL); - if (imin.value > 0x10FFFFULL) // ?? - imin.value = 0x10FFFFULL; // ?? - if (imax.value > 0x10FFFFULL) - imax.value = 0x10FFFFULL; - return *this; -} - -#if !PERFORM_UNITTEST -IntRange& IntRange::cast(Type *type) -{ - if (!type->isintegral()) - return *this; - else if (!type->isunsigned()) - return castSigned(type->sizemask()); - else if (type->toBasetype()->ty == Tdchar) - return castDchar(); - else - return castUnsigned(type->sizemask()); -} - -IntRange& IntRange::castUnsigned(Type *type) -{ - if (!type->isintegral()) - return castUnsigned(UINT64_MAX); - else if (type->toBasetype()->ty == Tdchar) - return castDchar(); - else - return castUnsigned(type->sizemask()); -} -#endif - -IntRange IntRange::absNeg() const -{ - if (imax.negative) - return *this; - else if (!imin.negative) - return IntRange(-imax, -imin); - else - { - SignExtendedNumber imaxAbsNeg = -imax; - return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin, - SignExtendedNumber(0)); - } -} - -IntRange IntRange::unionWith(const IntRange& other) const -{ - return IntRange(imin < other.imin ? imin : other.imin, - imax > other.imax ? imax : other.imax); -} - -void IntRange::unionOrAssign(const IntRange& other, bool& union_) -{ - if (!union_ || imin > other.imin) - imin = other.imin; - if (!union_ || imax < other.imax) - imax = other.imax; - union_ = true; -} - -void IntRange::splitBySign(IntRange& negRange, bool& hasNegRange, - IntRange& nonNegRange, bool& hasNonNegRange) const -{ - hasNegRange = imin.negative; - if (hasNegRange) - { - negRange.imin = imin; - negRange.imax = imax.negative ? imax : SignExtendedNumber(-1, true); - } - hasNonNegRange = !imax.negative; - if (hasNonNegRange) - { - nonNegRange.imin = imin.negative ? SignExtendedNumber(0) : imin; - nonNegRange.imax = imax; - } -} - - -#if !PERFORM_UNITTEST -const IntRange& IntRange::dump(const char* funcName, Expression *e) const -{ - printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n", - imin.negative?'-':'+', (unsigned long long)imin.value, - imax.negative?'-':'+', (unsigned long long)imax.value, - funcName, e->toChars()); - return *this; -} -#endif - -//------------------------------------------------------------------------------ - -#if PERFORM_UNITTEST -#include -#include - -class AssertionError : public std::exception { -public: - AssertionError() : std::exception() {} -}; - -void _assertPred(uinteger_t x, uinteger_t y, int line) { - if (x != y) { - printf("Line %d: %#018llx != %#018llx\n", line, x, y); - throw AssertionError(); - } -} -void _assertPred(const SignExtendedNumber& x, const SignExtendedNumber& y, int line) { - if (x != y) { - printf("Line %d: (%c)%#018llx != (%c)%#018llx\n", line, - x.negative?'-':'+', x.value, - y.negative?'-':'+', y.value); - throw AssertionError(); - } -} -void _assertPred(bool x, bool y, int line) { - if (x != y) { - static const char* const names[] = {"false", "true"}; - printf("Line %d: %s != %s\n", line, names[x], names[y]); - throw AssertionError(); - } -} -#define assertPred(x, y) _assertPred(x, y, __LINE__) -#define RUN(testName) \ - try { \ - testName(); \ - } catch (const AssertionError&) { \ - printf("********" #testName " failed\n"); \ - } - -void testAssertSanity() { - int saneCount = 0; - - printf("Testing 'assert' sanity. You should see 3 assertion failures below\n"); - - assertPred(true, true); - try { - assertPred(true, false); - } catch (const AssertionError&) { - ++ saneCount; - } - - assertPred(4ULL, 4ULL); - try { - assertPred(3ULL, -3ULL); - } catch (const AssertionError&) { - ++ saneCount; - } - - assertPred(SignExtendedNumber(5, false), SignExtendedNumber(5, false)); - try { - assertPred(SignExtendedNumber(4, false), SignExtendedNumber(4, true)); - } catch (const AssertionError&) { - ++ saneCount; - } - - printf("--------------\n"); - - if (saneCount != 3) throw AssertionError(); -} - -void testNegation() { - SignExtendedNumber s (4); - SignExtendedNumber t = -s; - assertPred(t.value, -4ULL); - assertPred(t.negative, true); - - s = SignExtendedNumber::max(); - t = -s; - assertPred(t.value, 1); - assertPred(t.negative, true); - - s = SignExtendedNumber::fromInteger(-4); - assertPred(s.value, -4ULL); - assertPred(s.negative, true); - - t = -s; - assertPred(t.value, 4); - assertPred(t.negative, false); - - s = SignExtendedNumber::min(); - t = -s; - assertPred(t.value, UINT64_MAX); - assertPred(t.negative, false); - - s = SignExtendedNumber(0); - t = -s; - assertPred(t.value, 0); - assertPred(t.negative, false); -} - -void testCompare() { - SignExtendedNumber a = SignExtendedNumber::min(); - SignExtendedNumber b = SignExtendedNumber(-5, true); - SignExtendedNumber c = SignExtendedNumber(0, false); - SignExtendedNumber d = SignExtendedNumber(5, false); - SignExtendedNumber e = SignExtendedNumber::max(); - - assertPred(a == a, true); - assertPred(a != a, false); - assertPred(a < b, true); - assertPred(b < c, true); - assertPred(c < d, true); - assertPred(d < e, true); - assertPred(a < c, true); - assertPred(c < e, true); - assertPred(b < d, true); - assertPred(b < a, false); - assertPred(c < b, false); - assertPred(d < c, false); - assertPred(e < d, false); - assertPred(e < c, false); - assertPred(d < b, false); - assertPred(c < a, false); - - assertPred(a, a); - assertPred(SignExtendedNumber::extreme(false), SignExtendedNumber::max()); - assertPred(SignExtendedNumber::extreme(true), SignExtendedNumber::min()); -} - -void testAddition() { - assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(8, false), - SignExtendedNumber(12, false)); - assertPred(SignExtendedNumber(4, false) + SignExtendedNumber(-9, true), - SignExtendedNumber(-5, true)); - assertPred(SignExtendedNumber(-9, true) + SignExtendedNumber(4, false), - SignExtendedNumber(-5, true)); - assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(9, false), - SignExtendedNumber(5, false)); - assertPred(SignExtendedNumber(9, false) + SignExtendedNumber(-4, true), - SignExtendedNumber(5, false)); - assertPred(SignExtendedNumber(9, true) + SignExtendedNumber(-4, false), - SignExtendedNumber(5, false)); - assertPred(SignExtendedNumber(-4, true) + SignExtendedNumber(-6, true), - SignExtendedNumber(-10, true)); - assertPred(SignExtendedNumber::max() + SignExtendedNumber(1, false), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(UINT64_MAX/2+1, false) + SignExtendedNumber(UINT64_MAX/2+1, false), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::max() + SignExtendedNumber::min(), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber::min() + SignExtendedNumber(-1, true), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::max() + SignExtendedNumber::max(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::min() + SignExtendedNumber::min(), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(1, true) + SignExtendedNumber(1, true), - SignExtendedNumber::min()); - - SignExtendedNumber x(0); - assertPred(++x, SignExtendedNumber(1)); - x = SignExtendedNumber(-1, true); - assertPred(++x, SignExtendedNumber(0)); - x = SignExtendedNumber::min(); - assertPred(++x, SignExtendedNumber(1, true)); - x = SignExtendedNumber::max(); - assertPred(++x, SignExtendedNumber::max()); -} - -void testSubtraction() { - assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(8, false), - SignExtendedNumber(-4, true)); - assertPred(SignExtendedNumber(4, false) - SignExtendedNumber(-9, true), - SignExtendedNumber(13, false)); - assertPred(SignExtendedNumber(-9, true) - SignExtendedNumber(4, false), - SignExtendedNumber(-13, true)); - assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(9, false), - SignExtendedNumber(-13, true)); - assertPred(SignExtendedNumber(9, false) - SignExtendedNumber(-4, true), - SignExtendedNumber(13, false)); - assertPred(SignExtendedNumber(9, true) - SignExtendedNumber(-4, false), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(-4, true) - SignExtendedNumber(-6, true), - SignExtendedNumber(2, false)); - assertPred(SignExtendedNumber::max() - SignExtendedNumber(-1, true), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::max() - SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() - SignExtendedNumber::min(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::min() - SignExtendedNumber(1, false), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(1, false) - SignExtendedNumber::min(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::min() - SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(1, true) - SignExtendedNumber::min(), - SignExtendedNumber(1, false)); -} - -void testMultiplication() { - assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(8, false), - SignExtendedNumber(32, false)); - assertPred(SignExtendedNumber(4, false) * SignExtendedNumber(-9, true), - SignExtendedNumber(-36, true)); - assertPred(SignExtendedNumber(-9, true) * SignExtendedNumber(4, false), - SignExtendedNumber(-36, true)); - assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(9, false), - SignExtendedNumber(-36, true)); - assertPred(SignExtendedNumber(9, false) * SignExtendedNumber(-4, true), - SignExtendedNumber(-36, true)); - assertPred(SignExtendedNumber(9, true) * SignExtendedNumber(-4, false), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(-4, true) * SignExtendedNumber(-6, true), - SignExtendedNumber(24, false)); - assertPred(SignExtendedNumber::max() * SignExtendedNumber::max(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::max() * SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() * SignExtendedNumber::min(), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(0) * SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) * SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) * SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() * SignExtendedNumber::max(), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::min() * SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() * SignExtendedNumber::min(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(2, false), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(-6, false) * SignExtendedNumber(-2, true), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::max() * SignExtendedNumber(-1, true), - SignExtendedNumber(1, true)); - assertPred(SignExtendedNumber::max() * SignExtendedNumber(-2, true), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::max() * SignExtendedNumber(2, false), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::min() * SignExtendedNumber(2, false), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::min() * SignExtendedNumber(-1, true), - SignExtendedNumber::max()); -} - -void testDivision() { - assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(8, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(8, false) / SignExtendedNumber(4, false), - SignExtendedNumber(2, false)); - assertPred(SignExtendedNumber(4, false) / SignExtendedNumber(-9, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(-9, true) / SignExtendedNumber(4, false), - SignExtendedNumber(-2, true)); - assertPred(SignExtendedNumber(-4, true) / SignExtendedNumber(9, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(9, false) / SignExtendedNumber(-4, true), - SignExtendedNumber(-2, true)); - assertPred(SignExtendedNumber(4, true) / SignExtendedNumber(-9, false), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(-6, true) / SignExtendedNumber(-4, true), - SignExtendedNumber(1, false)); - assertPred(SignExtendedNumber::max() / SignExtendedNumber::max(), - SignExtendedNumber(1)); - assertPred(SignExtendedNumber::max() / SignExtendedNumber(0), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::max() / SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) / SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) / SignExtendedNumber(0), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(0) / SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() / SignExtendedNumber::max(), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber::min() / SignExtendedNumber(0), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::min() / SignExtendedNumber::min(), - SignExtendedNumber(1)); - assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(2, false), - SignExtendedNumber((~5ULL)>>1)); - assertPred(SignExtendedNumber(-6, false) / SignExtendedNumber(-2, true), - SignExtendedNumber(3 | 1ULL<<63, true)); - assertPred(SignExtendedNumber::max() / SignExtendedNumber(-1, true), - SignExtendedNumber(1, true)); - assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1, true), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::max() / SignExtendedNumber(1, false), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber::min() / SignExtendedNumber(1, false), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber::min() / SignExtendedNumber(2, false), - SignExtendedNumber(-(1ULL << 63), true)); - assertPred(SignExtendedNumber::min() / SignExtendedNumber(-1024, true), - SignExtendedNumber(1ULL << 54)); -} - -void testModulus() { - assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(8, false), - SignExtendedNumber(4, false)); - assertPred(SignExtendedNumber(8, false) % SignExtendedNumber(4, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(4, false) % SignExtendedNumber(-9, true), - SignExtendedNumber(4, false)); - assertPred(SignExtendedNumber(-9, true) % SignExtendedNumber(4, false), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(-4, true) % SignExtendedNumber(9, false), - SignExtendedNumber(-4, true)); - assertPred(SignExtendedNumber(9, false) % SignExtendedNumber(-4, true), - SignExtendedNumber(1, false)); - assertPred(SignExtendedNumber(4, true) % SignExtendedNumber(-9, false), - SignExtendedNumber(-5, true)); - assertPred(SignExtendedNumber(-6, true) % SignExtendedNumber(-4, true), - SignExtendedNumber(-2, true)); - assertPred(SignExtendedNumber::max() % SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() % SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() % SignExtendedNumber::min(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(0) % SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) % SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) % SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber::max(), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber(0), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(2, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(-6, false) % SignExtendedNumber(-2, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() % SignExtendedNumber(-1, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber(-1, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::max() % SignExtendedNumber(1, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber(1, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber(2, false), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber::min() % SignExtendedNumber(999, false), - SignExtendedNumber(-160, true)); -} - -void testShift() { - assertPred(SignExtendedNumber(0) << SignExtendedNumber(4), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) << SignExtendedNumber(74), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) << SignExtendedNumber(-5, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) << SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) << SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(1) << SignExtendedNumber(4), - SignExtendedNumber(16)); - assertPred(SignExtendedNumber(1) << SignExtendedNumber(74), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(1) << SignExtendedNumber(-5, true), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(1) << SignExtendedNumber::max(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(1) << SignExtendedNumber::min(), - SignExtendedNumber::max()); - assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(4), - SignExtendedNumber(-16, true)); - assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(74), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber(-5, true), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::max(), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(-1, true) << SignExtendedNumber::min(), - SignExtendedNumber::min()); - assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(12, false), - SignExtendedNumber(0xabcdef000ULL)); - assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(40, false), - SignExtendedNumber(0xabcdef0000000000ULL)); - assertPred(SignExtendedNumber(0xabcdef) << SignExtendedNumber(41, false), - SignExtendedNumber::max()); - - - assertPred(SignExtendedNumber(0) >> SignExtendedNumber(4), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) >> SignExtendedNumber(74), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) >> SignExtendedNumber(-5, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) >> SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(0) >> SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(16) >> SignExtendedNumber(4), - SignExtendedNumber(1)); - assertPred(SignExtendedNumber(16) >> SignExtendedNumber(74), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(16) >> SignExtendedNumber(-5, true), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(16) >> SignExtendedNumber::max(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(16) >> SignExtendedNumber::min(), - SignExtendedNumber(0)); - assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(4), - SignExtendedNumber(-2, true)); - assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(74), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber(-5, true), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::max(), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(-32, true) >> SignExtendedNumber::min(), - SignExtendedNumber(-1, true)); - assertPred(SignExtendedNumber(0xabcdef, false) >> SignExtendedNumber(12, false), - SignExtendedNumber(0xabcULL)); - assertPred(SignExtendedNumber(0xabcdef, true) >> SignExtendedNumber(12, false), - SignExtendedNumber(0xFFF0000000000ABCULL, true)); - assertPred(SignExtendedNumber::min() >> SignExtendedNumber(1, false), - SignExtendedNumber(0x8000000000000000ULL, true)); - assertPred(SignExtendedNumber::min() >> SignExtendedNumber(63, false), - SignExtendedNumber(-2, true)); - assertPred(SignExtendedNumber::min() >> SignExtendedNumber(65, false), - SignExtendedNumber(-1, true)); -} - -void testFromNumbers() { - SignExtendedNumber a[] = { - SignExtendedNumber(12, false), - SignExtendedNumber(-35, true), - SignExtendedNumber(40, false), - SignExtendedNumber(-21, true), - SignExtendedNumber::min() - }; - - IntRange ir1 = IntRange::fromNumbers2(a); - assertPred(ir1.imin, SignExtendedNumber(-35, true)); - assertPred(ir1.imax, SignExtendedNumber(12, false)); - - IntRange ir2 = IntRange::fromNumbers2(a+1); - assertPred(ir2.imin, SignExtendedNumber(-35, true)); - assertPred(ir2.imax, SignExtendedNumber(40, false)); - - IntRange ir3 = IntRange::fromNumbers4(a); - assertPred(ir3.imin, SignExtendedNumber(-35, true)); - assertPred(ir3.imax, SignExtendedNumber(40, false)); - - IntRange ir4 = IntRange::fromNumbers4(a+1); - assertPred(ir4.imin, SignExtendedNumber::min()); - assertPred(ir4.imax, SignExtendedNumber(40, false)); - - assertPred(ir4.contains(ir3), true); - assertPred(ir1.contains(ir2), false); - - IntRange ir5 = IntRange::widest(); - assertPred(ir5.imin, SignExtendedNumber::min()); - assertPred(ir5.imax, SignExtendedNumber::max()); - assertPred(ir5.contains(ir4), true); -} - -void testContainsZero() { - IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(4)); - assertPred(ir1.containsZero(), true); - - IntRange ir2 (SignExtendedNumber(-4, true), SignExtendedNumber(0)); - assertPred(ir2.containsZero(), true); - - IntRange ir3 (SignExtendedNumber(-5, true), SignExtendedNumber(5)); - assertPred(ir3.containsZero(), true); - - assertPred(IntRange::widest().containsZero(), true); - - IntRange ir4 (SignExtendedNumber(8), SignExtendedNumber(9)); - assertPred(ir4.containsZero(), false); - - IntRange ir5 (SignExtendedNumber(-5, true), SignExtendedNumber(-2, true)); - assertPred(ir5.containsZero(), false); - - IntRange ir6 (SignExtendedNumber(0), SignExtendedNumber(0)); - assertPred(ir6.containsZero(), true); -} - -void testCast() { - { - IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF)); - ir1.castUnsigned(0xFF); - assertPred(ir1.imin, SignExtendedNumber(0)); - assertPred(ir1.imax, SignExtendedNumber(0xFF)); - - IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105)); - ir2.castUnsigned(0xFF); - assertPred(ir2.imin, SignExtendedNumber(1)); - assertPred(ir2.imax, SignExtendedNumber(5)); - - IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false)); - ir3.castUnsigned(0xFF); - assertPred(ir3.imin, SignExtendedNumber(0)); - assertPred(ir3.imax, SignExtendedNumber(0xFF)); - - IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999)); - ir4.castUnsigned(0xFF); - assertPred(ir4.imin, SignExtendedNumber(0x7F)); - assertPred(ir4.imax, SignExtendedNumber(0x99)); - - IntRange ir5 (SignExtendedNumber(-1, true), SignExtendedNumber(1, false)); - ir5.castUnsigned(UINT64_MAX); - assertPred(ir5.imin, SignExtendedNumber(0)); - assertPred(ir5.imax, SignExtendedNumber::max()); - - IntRange ir6 (SignExtendedNumber::min(), SignExtendedNumber(0)); - ir6.castUnsigned(UINT64_MAX); - assertPred(ir6.imin, SignExtendedNumber(0)); - assertPred(ir6.imax, SignExtendedNumber::max()); - - IntRange ir7 (SignExtendedNumber::min(), SignExtendedNumber(-0x80, true)); - ir7.castUnsigned(UINT64_MAX); - assertPred(ir7.imin, SignExtendedNumber(0)); - assertPred(ir7.imax, SignExtendedNumber(-0x80, false)); - - IntRange ir8 = IntRange::widest(); - ir8.castUnsigned(0xFF); - assertPred(ir8.imin, SignExtendedNumber(0)); - assertPred(ir8.imax, SignExtendedNumber(0xFF)); - } - - { - IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0xFFFF)); - ir1.castSigned(0xFF); - assertPred(ir1.imin, SignExtendedNumber(-0x80, true)); - assertPred(ir1.imax, SignExtendedNumber(0x7F, false)); - - IntRange ir2 (SignExtendedNumber(0x101), SignExtendedNumber(0x105)); - ir2.castSigned(0xFF); - assertPred(ir2.imin, SignExtendedNumber(1)); - assertPred(ir2.imax, SignExtendedNumber(5)); - - IntRange ir3 (SignExtendedNumber(-7, true), SignExtendedNumber(7, false)); - ir3.castSigned(0xFF); - assertPred(ir3.imin, SignExtendedNumber(-7, true)); - assertPred(ir3.imax, SignExtendedNumber(7, false)); - - IntRange ir4 (SignExtendedNumber(0x997F), SignExtendedNumber(0x9999)); - ir4.castSigned(0xFF); - assertPred(ir4.imin, SignExtendedNumber(-0x80, true)); - assertPred(ir4.imax, SignExtendedNumber(0x7F, false)); - - IntRange ir5 (SignExtendedNumber(-0xFF, true), SignExtendedNumber(-0x80, true)); - ir5.castSigned(0xFF); - assertPred(ir5.imin, SignExtendedNumber(-0x80, true)); - assertPred(ir5.imax, SignExtendedNumber(0x7F, false)); - - IntRange ir6 (SignExtendedNumber(-0x80, true), SignExtendedNumber(-0x80, true)); - ir6.castSigned(0xFF); - assertPred(ir6.imin, SignExtendedNumber(-0x80, true)); - assertPred(ir6.imax, SignExtendedNumber(-0x80, true)); - - IntRange ir7 = IntRange::widest(); - ir7.castSigned(0xFFFFFFFFULL); - assertPred(ir7.imin, SignExtendedNumber(-0x80000000ULL, true)); - assertPred(ir7.imax, SignExtendedNumber( 0x7FFFFFFFULL, false)); - } - - { - IntRange ir1 (SignExtendedNumber(0), SignExtendedNumber(0x9999)); - ir1.castDchar(); - assertPred(ir1.imin, SignExtendedNumber(0)); - assertPred(ir1.imax, SignExtendedNumber(0x9999)); - - IntRange ir2 (SignExtendedNumber(0xFFFF), SignExtendedNumber(0x7FFFFFFF)); - ir2.castDchar(); - assertPred(ir2.imin, SignExtendedNumber(0xFFFF)); - assertPred(ir2.imax, SignExtendedNumber(0x10FFFF)); - - IntRange ir3 = IntRange::widest(); - ir3.castDchar(); - assertPred(ir3.imin, SignExtendedNumber(0)); - assertPred(ir3.imax, SignExtendedNumber(0x10FFFF)); - } -} - -void testAbsNeg() { - IntRange ir1 = IntRange(SignExtendedNumber(5), SignExtendedNumber(104)).absNeg(); - assertPred(ir1.imin, SignExtendedNumber(-104, true)); - assertPred(ir1.imax, SignExtendedNumber(-5, true)); - - IntRange ir2 = IntRange(SignExtendedNumber(-46, true), SignExtendedNumber(-3, true)).absNeg(); - assertPred(ir2.imin, SignExtendedNumber(-46, true)); - assertPred(ir2.imax, SignExtendedNumber(-3, true)); - - IntRange ir3 = IntRange(SignExtendedNumber(-7, true), SignExtendedNumber(9)).absNeg(); - assertPred(ir3.imin, SignExtendedNumber(-9, true)); - assertPred(ir3.imax, SignExtendedNumber(0)); - - IntRange ir4 = IntRange(SignExtendedNumber(-12, true), SignExtendedNumber(2)).absNeg(); - assertPred(ir4.imin, SignExtendedNumber(-12, true)); - assertPred(ir4.imax, SignExtendedNumber(0)); - - IntRange ir5 = IntRange::widest().absNeg(); - assertPred(ir5.imin, SignExtendedNumber::min()); - assertPred(ir5.imax, SignExtendedNumber(0)); - - IntRange ir6 = IntRange(SignExtendedNumber(0), SignExtendedNumber::max()).absNeg(); - assertPred(ir6.imin, SignExtendedNumber(1, true)); - assertPred(ir6.imax, SignExtendedNumber(0)); -} - -int main() { - RUN(testAssertSanity); - RUN(testNegation); - RUN(testCompare); - RUN(testAddition); - RUN(testSubtraction); - RUN(testMultiplication); - RUN(testDivision); - RUN(testModulus); - RUN(testShift); - RUN(testFromNumbers); - RUN(testContainsZero); - RUN(testCast); - RUN(testAbsNeg); - printf("Finished all tests.\n"); -} - - -#endif - - diff --git a/dmd2/intrange.h b/dmd2/intrange.h deleted file mode 100644 index 77685b02..00000000 --- a/dmd2/intrange.h +++ /dev/null @@ -1,149 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by KennyTM -// 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_SXNUM_H -#define DMD_SXNUM_H - -#include "mars.h" // for uinteger_t -struct Type; -struct Expression; - -/** -This class represents a "sign-extended number", i.e. a 65-bit number, which can -represent all built-in integer types in D. This class is mainly used for -performing value-range propagation only, therefore all arithmetic are done with -saturation, not wrapping as usual. -*/ -struct SignExtendedNumber -{ - /// The lower 64-bit of the number. - uinteger_t value; - /// The sign (i.e. the most significant bit) of the number. - bool negative; - - /// Create an uninitialized sign-extended number. - SignExtendedNumber() {} - - /// Create a sign-extended number from an unsigned 64-bit number. - SignExtendedNumber(uinteger_t value_) - : value(value_), negative(false) {} - /// Create a sign-extended number from the lower 64-bit and the sign bit. - SignExtendedNumber(uinteger_t value_, bool negative_) - : value(value_), negative(negative_) {} - - /// Create a sign-extended number from a signed 64-bit number. - static SignExtendedNumber fromInteger(uinteger_t value_); - - /// Get the minimum or maximum value of a sign-extended number. - static SignExtendedNumber extreme(bool minimum); - static SignExtendedNumber max(); - static SignExtendedNumber min() { return SignExtendedNumber(0, true); } - - /// Check if the sign-extended number is minimum or zero. - bool isMinimum() const { return negative && value == 0; } - - /// Compare two sign-extended number. - bool operator==(const SignExtendedNumber&) const; - bool operator!=(const SignExtendedNumber& a) const { return !(*this == a); } - bool operator<(const SignExtendedNumber&) const; - bool operator>(const SignExtendedNumber& a) const { return a < *this; } - bool operator<=(const SignExtendedNumber& a) const { return !(a < *this); } - bool operator>=(const SignExtendedNumber& a) const { return !(*this < a); } - - /// Compute the saturated negation of a sign-extended number. - SignExtendedNumber operator-() const; - - /// Compute the saturated sum of two sign-extended number. - SignExtendedNumber operator+(const SignExtendedNumber&) const; - /// Compute the saturated difference of two sign-extended number. - SignExtendedNumber operator-(const SignExtendedNumber& a) const; - /// Compute the saturated product of two sign-extended number. - SignExtendedNumber operator*(const SignExtendedNumber&) const; - /// Compute the saturated quotient of two sign-extended number. - SignExtendedNumber operator/(const SignExtendedNumber&) const; - /// Compute the saturated modulus of two sign-extended number. - SignExtendedNumber operator%(const SignExtendedNumber&) const; - - /// Increase the sign-extended number by 1 (saturated). - SignExtendedNumber& operator++(); - - /// Compute the saturated shifts of two sign-extended number. - SignExtendedNumber operator<<(const SignExtendedNumber&) const; - SignExtendedNumber operator>>(const SignExtendedNumber&) const; -}; - -/** -This class represents a range of integers, denoted by its lower and upper bounds -(inclusive). -*/ -struct IntRange -{ - SignExtendedNumber imin, imax; - - /// Create an uninitialized range. - IntRange() {} - - /// Create a range consisting of a single number. - IntRange(const SignExtendedNumber& a) - : imin(a), imax(a) {} - /// Create a range with the lower and upper bounds. - IntRange(const SignExtendedNumber& lower, const SignExtendedNumber& upper) - : imin(lower), imax(upper) {} - - /// Create the tightest range containing all valid integers in the specified - /// type. - static IntRange fromType(Type *type); - /// Create the tightest range containing all valid integers in the type with - /// a forced signedness. - static IntRange fromType(Type *type, bool isUnsigned); - - - /// Create the tightest range containing all specified numbers. - static IntRange fromNumbers2(const SignExtendedNumber numbers[2]); - static IntRange fromNumbers4(const SignExtendedNumber numbers[4]); - - /// Create the widest range possible. - static IntRange widest(); - - /// Cast the integer range to a signed type with the given size mask. - IntRange& castSigned(uinteger_t mask); - /// Cast the integer range to an unsigned type with the given size mask. - IntRange& castUnsigned(uinteger_t mask); - /// Cast the integer range to the dchar type. - IntRange& castDchar(); - - /// Cast the integer range to a specific type. - IntRange& cast(Type *type); - /// Cast the integer range to a specific type, forcing it to be unsigned. - IntRange& castUnsigned(Type *type); - - /// Check if this range contains another range. - bool contains(const IntRange& a) const; - - /// Check if this range contains 0. - bool containsZero() const; - - /// Compute the range of the negated absolute values of the original range. - IntRange absNeg() const; - - /// Compute the union of two ranges. - IntRange unionWith(const IntRange& other) const; - void unionOrAssign(const IntRange& other, bool& union_); - - /// Dump the content of the integer range to the console. - const IntRange& dump(const char* funcName, Expression *e) const; - - /// Split the range into two nonnegative- and negative-only subintervals. - void splitBySign(IntRange& negRange, bool& hasNegRange, - IntRange& nonNegRange, bool& hasNonNegRange) const; -}; - -#endif diff --git a/dmd2/irstate.c b/dmd2/irstate.c deleted file mode 100644 index 4fc35ece..00000000 --- a/dmd2/irstate.c +++ /dev/null @@ -1,195 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#include - -#include "mars.h" -#include "mtype.h" -#include "declaration.h" -#include "irstate.h" - -IRState::IRState(IRState *irs, Statement *s) -{ - prev = irs; - statement = s; - symbol = NULL; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - startaddress = NULL; - if (irs) - { - m = irs->m; - shidden = irs->shidden; - sclosure = irs->sclosure; - sthis = irs->sthis; - blx = irs->blx; - deferToObj = irs->deferToObj; -#if DMDV2 - varsInScope = irs->varsInScope; -#endif - } - else - { - m = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; -#if DMDV2 - varsInScope = NULL; -#endif - } -} - -IRState::IRState(IRState *irs, Dsymbol *s) -{ - prev = irs; - statement = NULL; - symbol = s; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - startaddress = NULL; - if (irs) - { - m = irs->m; - shidden = irs->shidden; - sclosure = irs->sclosure; - sthis = irs->sthis; - blx = irs->blx; - deferToObj = irs->deferToObj; - varsInScope = irs->varsInScope; - } - else - { - m = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; - varsInScope = NULL; - } -} - -IRState::IRState(Module *m, Dsymbol *s) -{ - prev = NULL; - statement = NULL; - this->m = m; - symbol = s; - breakBlock = NULL; - contBlock = NULL; - switchBlock = NULL; - defaultBlock = NULL; - ident = NULL; - ehidden = NULL; - shidden = NULL; - sclosure = NULL; - sthis = NULL; - blx = NULL; - deferToObj = NULL; - startaddress = NULL; - varsInScope = NULL; -} - -block *IRState::getBreakBlock(Identifier *ident) -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (ident) - { - if (bc->prev && bc->prev->ident == ident) - return bc->breakBlock; - } - else if (bc->breakBlock) - return bc->breakBlock; - } - return NULL; -} - -block *IRState::getContBlock(Identifier *ident) -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (ident) - { - if (bc->prev && bc->prev->ident == ident) - return bc->contBlock; - } - else if (bc->contBlock) - return bc->contBlock; - } - return NULL; -} - -block *IRState::getSwitchBlock() -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (bc->switchBlock) - return bc->switchBlock; - } - return NULL; -} - -block *IRState::getDefaultBlock() -{ - IRState *bc; - - for (bc = this; bc; bc = bc->prev) - { - if (bc->defaultBlock) - return bc->defaultBlock; - } - return NULL; -} - -FuncDeclaration *IRState::getFunc() -{ - IRState *bc; - - for (bc = this; bc->prev; bc = bc->prev) - { - } - return (FuncDeclaration *)(bc->symbol); -} - - -/********************** - * Return !=0 if do array bounds checking - */ -int IRState::arrayBoundsCheck() -{ - int result = global.params.useArrayBounds; - - if (result == 1) - { // For safe functions only - result = 0; - FuncDeclaration *fd = getFunc(); - if (fd) - { Type *t = fd->type; - if (t->ty == Tfunction && ((TypeFunction *)t)->trust == TRUSTsafe) - result = 1; - } - } - return result; -} diff --git a/dmd2/irstate.h b/dmd2/irstate.h deleted file mode 100644 index 75194b6f..00000000 --- a/dmd2/irstate.h +++ /dev/null @@ -1,59 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#ifndef DMD_CONTEXT_H -#define DMD_CONTEXT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -struct Module; -struct Statement; -struct block; -struct Dsymbol; -struct Identifier; -struct Symbol; -struct FuncDeclaration; -struct Blockx; -struct elem; -#include "arraytypes.h" - -struct IRState -{ - IRState *prev; - Statement *statement; - Module *m; // module - Dsymbol *symbol; - Identifier *ident; - Symbol *shidden; // hidden parameter to function - Symbol *sthis; // 'this' parameter to function (member and nested) - Symbol *sclosure; // pointer to closure instance - Blockx *blx; - Dsymbols *deferToObj; // array of Dsymbol's to run toObjFile(int multiobj) on later - elem *ehidden; // transmit hidden pointer to CallExp::toElem() - Symbol *startaddress; - VarDeclarations *varsInScope; // variables that are in scope that will need destruction later - - block *breakBlock; - block *contBlock; - block *switchBlock; - block *defaultBlock; - - IRState(IRState *irs, Statement *s); - IRState(IRState *irs, Dsymbol *s); - IRState(Module *m, Dsymbol *s); - - block *getBreakBlock(Identifier *ident); - block *getContBlock(Identifier *ident); - block *getSwitchBlock(); - block *getDefaultBlock(); - FuncDeclaration *getFunc(); - int arrayBoundsCheck(); -}; - -#endif /* DMD_CONTEXT_H */ diff --git a/dmd2/json.c b/dmd2/json.c deleted file mode 100644 index d3efacf5..00000000 --- a/dmd2/json.c +++ /dev/null @@ -1,462 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This implements the JSON capability. - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "mars.h" -#include "dsymbol.h" -#include "macro.h" -#include "template.h" -#include "lexer.h" -#include "aggregate.h" -#include "declaration.h" -#include "enum.h" -#include "id.h" -#include "module.h" -#include "scope.h" -#include "hdrgen.h" -#include "json.h" -#include "mtype.h" -#include "attrib.h" -#include "cond.h" - -const char Pname[] = "name"; -const char Pkind[] = "kind"; -const char Pfile[] = "file"; -const char Pline[] = "line"; -const char Ptype[] = "type"; -const char Pcomment[] = "comment"; -const char Pmembers[] = "members"; -const char Pprotection[] = "protection"; -const char* Pprotectionnames[] = {NULL, "none", "private", "package", "protected", "public", "export"}; - -void JsonRemoveComma(OutBuffer *buf); - -void json_generate(Modules *modules) -{ OutBuffer buf; - - buf.writestring("[\n"); - for (size_t i = 0; i < modules->dim; i++) - { Module *m = modules->tdata()[i]; - if (global.params.verbose) - printf("json gen %s\n", m->toChars()); - m->toJsonBuffer(&buf); - buf.writestring(",\n"); - } - JsonRemoveComma(&buf); - buf.writestring("]\n"); - - // Write buf to file - char *arg = global.params.xfilename; - if (!arg || !*arg) - { // Generate lib file name from first obj name - char *n = global.params.objfiles->tdata()[0]; - - n = FileName::name(n); - FileName *fn = FileName::forceExt(n, global.json_ext); - arg = fn->toChars(); - } - else if (arg[0] == '-' && arg[1] == 0) - { // Write to stdout; assume it succeeds - int n = fwrite(buf.data, 1, buf.offset, stdout); - assert(n == buf.offset); // keep gcc happy about return values - return; - } -// if (!FileName::absolute(arg)) -// arg = FileName::combine(dir, arg); - FileName *jsonfilename = FileName::defaultExt(arg, global.json_ext); - File *jsonfile = new File(jsonfilename); - assert(jsonfile); - jsonfile->setbuffer(buf.data, buf.offset); - jsonfile->ref = 1; - char *pt = FileName::path(jsonfile->toChars()); - if (*pt) - FileName::ensurePathExists(pt); - mem.free(pt); - jsonfile->writev(); -} - - -/********************************* - * Encode string into buf, and wrap it in double quotes. - */ -void JsonString(OutBuffer *buf, const char *s) -{ - buf->writeByte('\"'); - for (; *s; s++) - { - unsigned char c = (unsigned char) *s; - switch (c) - { - case '\n': - buf->writestring("\\n"); - break; - - case '\r': - buf->writestring("\\r"); - break; - - case '\t': - buf->writestring("\\t"); - break; - - case '\"': - buf->writestring("\\\""); - break; - - case '\\': - buf->writestring("\\\\"); - break; - - case '/': - buf->writestring("\\/"); - break; - - case '\b': - buf->writestring("\\b"); - break; - - case '\f': - buf->writestring("\\f"); - break; - - default: - if (c < 0x20) - buf->printf("\\u%04x", c); - else - // Note that UTF-8 chars pass through here just fine - buf->writeByte(c); - break; - } - } - buf->writeByte('\"'); -} - -void JsonProperty(OutBuffer *buf, const char *name, const char *value) -{ - JsonString(buf, name); - buf->writestring(" : "); - JsonString(buf, value); - buf->writestring(",\n"); -} - -void JsonProperty(OutBuffer *buf, const char *name, int value) -{ - JsonString(buf, name); - buf->writestring(" : "); - buf->printf("%d", value); - buf->writestring(",\n"); -} - -void JsonRemoveComma(OutBuffer *buf) -{ - if (buf->offset >= 2 && - buf->data[buf->offset - 2] == ',' && - buf->data[buf->offset - 1] == '\n') - buf->offset -= 2; -} - -void Dsymbol::toJsonBuffer(OutBuffer *buf) -{ -} - -void Module::toJsonBuffer(OutBuffer *buf) -{ - buf->writestring("{\n"); - - if (md) - JsonProperty(buf, Pname, md->toChars()); - - JsonProperty(buf, Pkind, kind()); - - JsonProperty(buf, Pfile, srcfile->toChars()); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - - JsonRemoveComma(buf); - buf->writestring("]\n"); - - buf->writestring("}\n"); -} - -void AttribDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("AttribDeclaration::toJsonBuffer()\n"); - - Dsymbols *d = include(NULL, NULL); - - if (d) - { - size_t offset = buf->offset; - for (unsigned i = 0; i < d->dim; i++) - { Dsymbol *s = d->tdata()[i]; - //printf("AttribDeclaration::toJsonBuffer %s\n", s->toChars()); - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - } -} - - -void ConditionalDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("ConditionalDeclaration::toJsonBuffer()\n"); - if (condition->inc) - { - AttribDeclaration::toJsonBuffer(buf); - } -} - - -void InvariantDeclaration::toJsonBuffer(OutBuffer *buf) { } -void DtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticCtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void StaticDtorDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ClassInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void ModuleInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void TypeInfoDeclaration::toJsonBuffer(OutBuffer *buf) { } -void UnitTestDeclaration::toJsonBuffer(OutBuffer *buf) { } -#if DMDV2 -void PostBlitDeclaration::toJsonBuffer(OutBuffer *buf) { } -#endif - -void Declaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("Declaration::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (type) - JsonProperty(buf, Ptype, type->toChars()); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - TypedefDeclaration *td = isTypedefDeclaration(); - if (td) - { - JsonProperty(buf, "base", td->basetype->toChars()); - } - - JsonRemoveComma(buf); - buf->writestring("}\n"); -} - -void AggregateDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("AggregateDeclaration::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - ClassDeclaration *cd = isClassDeclaration(); - if (cd) - { - if (cd->baseClass) - { - JsonProperty(buf, "base", cd->baseClass->toChars()); - } - if (cd->interfaces_dim) - { - JsonString(buf, "interfaces"); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < cd->interfaces_dim; i++) - { BaseClass *b = cd->interfaces[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - JsonString(buf, b->base->toChars()); - } - JsonRemoveComma(buf); - buf->writestring("],\n"); - } - } - - if (members) - { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - } - JsonRemoveComma(buf); - - buf->writestring("}\n"); -} - -void TemplateDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("TemplateDeclaration::toJsonBuffer()\n"); - - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - - buf->writestring("}\n"); -} - -void EnumDeclaration::toJsonBuffer(OutBuffer *buf) -{ - //printf("EnumDeclaration::toJsonBuffer()\n"); - if (isAnonymous()) - { - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toJsonBuffer(buf); - buf->writestring(",\n"); - } - JsonRemoveComma(buf); - } - return; - } - - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - if (memtype) - JsonProperty(buf, "base", memtype->toChars()); - - if (members) - { - JsonString(buf, Pmembers); - buf->writestring(" : [\n"); - size_t offset = buf->offset; - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - if (offset != buf->offset) - { buf->writestring(",\n"); - offset = buf->offset; - } - s->toJsonBuffer(buf); - } - JsonRemoveComma(buf); - buf->writestring("]\n"); - } - JsonRemoveComma(buf); - - buf->writestring("}\n"); -} - -void EnumMember::toJsonBuffer(OutBuffer *buf) -{ - //printf("EnumMember::toJsonBuffer()\n"); - buf->writestring("{\n"); - - JsonProperty(buf, Pname, toChars()); - JsonProperty(buf, Pkind, kind()); - - if (prot()) - JsonProperty(buf, Pprotection, Pprotectionnames[prot()]); - - if (comment) - JsonProperty(buf, Pcomment, (const char *)comment); - - if (loc.linnum) - JsonProperty(buf, Pline, loc.linnum); - - JsonRemoveComma(buf); - buf->writestring("}\n"); -} - - diff --git a/dmd2/json.h b/dmd2/json.h deleted file mode 100644 index 2c7e2e60..00000000 --- a/dmd2/json.h +++ /dev/null @@ -1,24 +0,0 @@ - - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_JSON_H -#define DMD_JSON_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" - -void json_generate(Modules *); - -#endif /* DMD_JSON_H */ - diff --git a/dmd2/lexer.c b/dmd2/lexer.c deleted file mode 100644 index 7b53f212..00000000 --- a/dmd2/lexer.c +++ /dev/null @@ -1,3216 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#if IN_LLVM -#include -#endif - -#include - -/* Lexical Analyzer */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include // for time() and ctime() - -#include "rmem.h" - -#include "stringtable.h" - -#include "lexer.h" -#include "utf.h" -#include "identifier.h" -#include "id.h" -#include "module.h" - -#if _WIN32 && __DMC__ -// from \dm\src\include\setlocal.h -extern "C" char * __cdecl __locale_decpoint; -#endif - -extern int HtmlNamedEntity(unsigned char *p, int length); - -#define LS 0x2028 // UTF line separator -#define PS 0x2029 // UTF paragraph separator - -void unittest_lexer(); - -/******************************************** - * Do our own char maps - */ - -static unsigned char cmtable[256]; - -const int CMoctal = 0x1; -const int CMhex = 0x2; -const int CMidchar = 0x4; - -inline unsigned char isoctal (unsigned char c) { return cmtable[c] & CMoctal; } -inline unsigned char ishex (unsigned char c) { return cmtable[c] & CMhex; } -inline unsigned char isidchar(unsigned char c) { return cmtable[c] & CMidchar; } - -static void cmtable_init() -{ - for (unsigned c = 0; c < sizeof(cmtable) / sizeof(cmtable[0]); c++) - { - if ('0' <= c && c <= '7') - cmtable[c] |= CMoctal; - if (isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F')) - cmtable[c] |= CMhex; - if (isalnum(c) || c == '_') - cmtable[c] |= CMidchar; - } -} - - -/************************* Token **********************************************/ - -const char *Token::tochars[TOKMAX]; - -void *Token::operator new(size_t size) -{ Token *t; - - if (Lexer::freelist) - { - t = Lexer::freelist; - Lexer::freelist = t->next; - return t; - } - - return ::operator new(size); -} - -#ifdef DEBUG -void Token::print() -{ - fprintf(stdmsg, "%s\n", toChars()); -} -#endif - -const char *Token::toChars() -{ const char *p; - static char buffer[3 + 3 * sizeof(float80value) + 1]; - - p = buffer; - switch (value) - { - case TOKint32v: - sprintf(buffer,"%d",(d_int32)int64value); - break; - - case TOKuns32v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - sprintf(buffer,"%uU",(d_uns32)uns64value); - break; - - case TOKint64v: - sprintf(buffer,"%jdL",(intmax_t)int64value); - break; - - case TOKuns64v: - sprintf(buffer,"%juUL",(uintmax_t)uns64value); - break; - -#if IN_GCC - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - float80value.format(buffer, sizeof(buffer)); - break; - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - float80value.format(buffer, sizeof(buffer)); - // %% buffer - strcat(buffer, "i"); - break; -#else - case TOKfloat32v: - sprintf(buffer,"%Lgf", float80value); - break; - - case TOKfloat64v: - sprintf(buffer,"%Lg", float80value); - break; - - case TOKfloat80v: - sprintf(buffer,"%LgL", float80value); - break; - - case TOKimaginary32v: - sprintf(buffer,"%Lgfi", float80value); - break; - - case TOKimaginary64v: - sprintf(buffer,"%Lgi", float80value); - break; - - case TOKimaginary80v: - sprintf(buffer,"%LgLi", float80value); - break; -#endif - - case TOKstring: -#if CSTRINGS - p = string; -#else - { OutBuffer buf; - - buf.writeByte('"'); - for (size_t i = 0; i < len; ) - { unsigned c; - - utf_decodeChar((unsigned char *)ustring, len, &i, &c); - switch (c) - { - case 0: - break; - - case '"': - case '\\': - buf.writeByte('\\'); - default: - if (isprint(c)) - buf.writeByte(c); - else if (c <= 0x7F) - buf.printf("\\x%02x", c); - else if (c <= 0xFFFF) - buf.printf("\\u%04x", c); - else - buf.printf("\\U%08x", c); - continue; - } - break; - } - buf.writeByte('"'); - if (postfix) - buf.writeByte('"'); - buf.writeByte(0); - p = (char *)buf.extractData(); - } -#endif - break; - - case TOKidentifier: - case TOKenum: - case TOKstruct: - case TOKimport: - case BASIC_TYPES: - p = ident->toChars(); - break; - - default: - p = toChars(value); - break; - } - return p; -} - -const char *Token::toChars(enum TOK value) -{ const char *p; - static char buffer[3 + 3 * sizeof(value) + 1]; - - p = tochars[value]; - if (!p) - { sprintf(buffer,"TOK%d",value); - p = buffer; - } - return p; -} - -/*************************** Lexer ********************************************/ - -Token *Lexer::freelist = NULL; -StringTable Lexer::stringtable; -OutBuffer Lexer::stringbuffer; - -Lexer::Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken) - : loc(mod, 1) -{ - //printf("Lexer::Lexer(%p,%d)\n",base,length); - //printf("lexer.mod = %p, %p\n", mod, this->loc.mod); - memset(&token,0,sizeof(token)); - this->base = base; - this->end = base + endoffset; - p = base + begoffset; - this->mod = mod; - this->doDocComment = doDocComment; - this->anyToken = 0; - this->commentToken = commentToken; - //initKeywords(); - - /* If first line starts with '#!', ignore the line - */ - - if (p[0] == '#' && p[1] =='!') - { - p += 2; - while (1) - { unsigned char c = *p; - switch (c) - { - case '\n': - p++; - break; - - case '\r': - p++; - if (*p == '\n') - p++; - break; - - case 0: - case 0x1A: - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - p++; - continue; - } - break; - } - loc.linnum = 2; - } -} - - -void Lexer::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Lexer::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end(ap); -} - -void Lexer::verror(Loc loc, const char *format, va_list ap) -{ - if (mod && !global.gag) - { - char *p = loc.toChars(); - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - vfprintf(stdmsg, format, ap); - - fprintf(stdmsg, "\n"); - fflush(stdmsg); - - if (global.errors >= 20) // moderate blizzard of cascading messages - fatal(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - -TOK Lexer::nextToken() -{ Token *t; - - if (token.next) - { - t = token.next; - memcpy(&token,t,sizeof(Token)); - t->next = freelist; - freelist = t; - } - else - { - scan(&token); - } - //token.print(); - return token.value; -} - -Token *Lexer::peek(Token *ct) -{ Token *t; - - if (ct->next) - t = ct->next; - else - { - t = new Token(); - scan(t); - t->next = NULL; - ct->next = t; - } - return t; -} - -/*********************** - * Look ahead at next token's value. - */ - -TOK Lexer::peekNext() -{ - return peek(&token)->value; -} - -/*********************** - * Look 2 tokens ahead at value. - */ - -TOK Lexer::peekNext2() -{ - Token *t = peek(&token); - return peek(t)->value; -} - -/********************************* - * tk is on the opening (. - * Look ahead and return token that is past the closing ). - */ - -Token *Lexer::peekPastParen(Token *tk) -{ - //printf("peekPastParen()\n"); - int parens = 1; - int curlynest = 0; - while (1) - { - tk = peek(tk); - //tk->print(); - switch (tk->value) - { - case TOKlparen: - parens++; - continue; - - case TOKrparen: - --parens; - if (parens) - continue; - tk = peek(tk); - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - break; - - case TOKeof: - break; - - default: - continue; - } - return tk; - } -} - -/********************************** - * Determine if string is a valid Identifier. - * Placed here because of commonality with Lexer functionality. - * Returns: - * 0 invalid - */ - -int Lexer::isValidIdentifier(char *p) -{ - size_t len; - size_t idx; - - if (!p || !*p) - goto Linvalid; - - if (*p >= '0' && *p <= '9') // beware of isdigit() on signed chars - goto Linvalid; - - len = strlen(p); - idx = 0; - while (p[idx]) - { dchar_t dc; - - const char *q = utf_decodeChar((unsigned char *)p, len, &idx, &dc); - if (q) - goto Linvalid; - - if (!((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_')) - goto Linvalid; - } - return 1; - -Linvalid: - return 0; -} - -/**************************** - * Turn next token in buffer into a token. - */ - -void Lexer::scan(Token *t) -{ - unsigned lastLine = loc.linnum; - unsigned linnum; - - t->blockComment = NULL; - t->lineComment = NULL; - while (1) - { - t->ptr = p; - //printf("p = %p, *p = '%c'\n",p,*p); - switch (*p) - { - case 0: - case 0x1A: - t->value = TOKeof; // end of file - return; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '\r': - p++; - if (*p != '\n') // if CR stands by itself - loc.linnum++; - continue; // skip white space - - case '\n': - p++; - loc.linnum++; - continue; // skip white space - - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - t->value = number(t); - return; - -#if CSTRINGS - case '\'': - t->value = charConstant(t, 0); - return; - - case '"': - t->value = stringConstant(t,0); - return; - - case 'l': - case 'L': - if (p[1] == '\'') - { - p++; - t->value = charConstant(t, 1); - return; - } - else if (p[1] == '"') - { - p++; - t->value = stringConstant(t, 1); - return; - } -#else - case '\'': - t->value = charConstant(t,0); - return; - - case 'r': - if (p[1] != '"') - goto case_ident; - p++; - case '`': - t->value = wysiwygStringConstant(t, *p); - return; - - case 'x': - if (p[1] != '"') - goto case_ident; - p++; - t->value = hexStringConstant(t); - return; - -#if DMDV2 - case 'q': - if (p[1] == '"') - { - p++; - t->value = delimitedStringConstant(t); - return; - } - else if (p[1] == '{') - { - p++; - t->value = tokenStringConstant(t); - return; - } - else - goto case_ident; -#endif - - case '"': - t->value = escapeStringConstant(t,0); - return; - -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': // escaped string literal - { unsigned c; - unsigned char *pstart = p; - - stringbuffer.reset(); - do - { - p++; - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - break; - - default: - c = escapeSequence(); - stringbuffer.writeByte(c); - break; - } - } while (*p == '\\'); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - t->postfix = 0; - t->value = TOKstring; -#if DMDV2 - if (!global.params.useDeprecated) - error("Escape String literal %.*s is deprecated, use double quoted string literal \"%.*s\" instead", (int)(p - pstart), pstart, (int)(p - pstart), pstart); -#endif - return; - } -#endif - - case 'l': - case 'L': -#endif - case 'a': case 'b': case 'c': case 'd': case 'e': - case 'f': case 'g': case 'h': case 'i': case 'j': - case 'k': case 'm': case 'n': case 'o': -#if DMDV2 - case 'p': /*case 'q': case 'r':*/ case 's': case 't': -#else - case 'p': case 'q': /*case 'r':*/ case 's': case 't': -#endif - case 'u': case 'v': case 'w': /*case 'x':*/ case 'y': - case 'z': - case 'A': case 'B': case 'C': case 'D': case 'E': - case 'F': case 'G': case 'H': case 'I': case 'J': - case 'K': case 'M': case 'N': case 'O': - case 'P': case 'Q': case 'R': case 'S': case 'T': - case 'U': case 'V': case 'W': case 'X': case 'Y': - case 'Z': - case '_': - case_ident: - { unsigned char c; - - while (1) - { - c = *++p; - if (isidchar(c)) - continue; - else if (c & 0x80) - { unsigned char *s = p; - unsigned u = decodeUTF(); - if (isUniAlpha(u)) - continue; - error("char 0x%04x not allowed in identifier", u); - p = s; - } - break; - } - - StringValue *sv = stringtable.update((char *)t->ptr, p - t->ptr); - Identifier *id = (Identifier *) sv->ptrvalue; - if (!id) - { id = new Identifier(sv->lstring.string,TOKidentifier); - sv->ptrvalue = id; - } - t->ident = id; - t->value = (enum TOK) id->value; - anyToken = 1; - if (*t->ptr == '_') // if special identifier token - { - static char date[11+1]; - static char time[8+1]; - static char timestamp[24+1]; - - if (!date[0]) // lazy evaluation - { time_t t; - char *p; - - ::time(&t); - p = ctime(&t); - assert(p); - sprintf(date, "%.6s %.4s", p + 4, p + 20); - sprintf(time, "%.8s", p + 11); - sprintf(timestamp, "%.24s", p); - } - -#if DMDV1 - if (mod && id == Id::FILE) - { - t->ustring = (unsigned char *)(loc.filename ? loc.filename : mod->ident->toChars()); - goto Lstr; - } - else if (mod && id == Id::LINE) - { - t->value = TOKint64v; - t->uns64value = loc.linnum; - } - else -#endif - if (id == Id::DATE) - { - t->ustring = (unsigned char *)date; - goto Lstr; - } - else if (id == Id::TIME) - { - t->ustring = (unsigned char *)time; - goto Lstr; - } - else if (id == Id::VENDOR) - { - t->ustring = (unsigned char *)"LDC"; - goto Lstr; - } - else if (id == Id::TIMESTAMP) - { - t->ustring = (unsigned char *)timestamp; - Lstr: - t->value = TOKstring; - t->postfix = 0; - t->len = strlen((char *)t->ustring); - } - else if (id == Id::VERSIONX) - { unsigned major = 0; - unsigned minor = 0; - - for (const char *p = global.version + 1; 1; p++) - { - char c = *p; - if (isdigit((unsigned char)c)) - minor = minor * 10 + c - '0'; - else if (c == '.') - { major = minor; - minor = 0; - } - else - break; - } - t->value = TOKint64v; - t->uns64value = major * 1000 + minor; - } -#if DMDV2 - else if (id == Id::EOFX) - { - t->value = TOKeof; - // Advance scanner to end of file - while (!(*p == 0 || *p == 0x1A)) - p++; - } -#endif - } - //printf("t->value = %d\n",t->value); - return; - } - - case '/': - p++; - switch (*p) - { - case '=': - p++; - t->value = TOKdivass; - return; - - case '*': - p++; - linnum = loc.linnum; - while (1) - { - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - break; - - case '\n': - loc.linnum++; - p++; - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated /* */ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - p++; - if (p[-2] == '*' && p - 3 != t->ptr) - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - else if (doDocComment && t->ptr[2] == '*' && p - 4 != t->ptr) - { // if /** but not /**/ - getDocComment(t, lastLine == linnum); - } - continue; - - case '/': // do // style comments - linnum = loc.linnum; - while (1) - { unsigned char c = *++p; - switch (c) - { - case '\n': - break; - - case '\r': - if (p[1] == '\n') - p++; - break; - - case 0: - case 0x1A: - if (commentToken) - { - p = end; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - break; - } - continue; - } - break; - } - - if (commentToken) - { - p++; - loc.linnum++; - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '/') - getDocComment(t, lastLine == linnum); - - p++; - loc.linnum++; - continue; - - case '+': - { int nest; - - linnum = loc.linnum; - p++; - nest = 1; - while (1) - { unsigned char c = *p; - switch (c) - { - case '/': - p++; - if (*p == '+') - { - p++; - nest++; - } - continue; - - case '+': - p++; - if (*p == '/') - { - p++; - if (--nest == 0) - break; - } - continue; - - case '\r': - p++; - if (*p != '\n') - loc.linnum++; - continue; - - case '\n': - loc.linnum++; - p++; - continue; - - case 0: - case 0x1A: - error("unterminated /+ +/ comment"); - p = end; - t->value = TOKeof; - return; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - loc.linnum++; - } - p++; - continue; - } - break; - } - if (commentToken) - { - t->value = TOKcomment; - return; - } - if (doDocComment && t->ptr[2] == '+' && p - 4 != t->ptr) - { // if /++ but not /++/ - getDocComment(t, lastLine == linnum); - } - continue; - } - } - t->value = TOKdiv; - return; - - case '.': - p++; - if (isdigit(*p)) - { /* Note that we don't allow ._1 and ._ as being - * valid floating point numbers. - */ - p--; - t->value = inreal(t); - } - else if (p[0] == '.') - { - if (p[1] == '.') - { p += 2; - t->value = TOKdotdotdot; - } - else - { p++; - t->value = TOKslice; - } - } - else - t->value = TOKdot; - return; - - case '&': - p++; - if (*p == '=') - { p++; - t->value = TOKandass; - } - else if (*p == '&') - { p++; - t->value = TOKandand; - } - else - t->value = TOKand; - return; - - case '|': - p++; - if (*p == '=') - { p++; - t->value = TOKorass; - } - else if (*p == '|') - { p++; - t->value = TOKoror; - } - else - t->value = TOKor; - return; - - case '-': - p++; - if (*p == '=') - { p++; - t->value = TOKminass; - } -#if 0 - else if (*p == '>') - { p++; - t->value = TOKarrow; - } -#endif - else if (*p == '-') - { p++; - t->value = TOKminusminus; - } - else - t->value = TOKmin; - return; - - case '+': - p++; - if (*p == '=') - { p++; - t->value = TOKaddass; - } - else if (*p == '+') - { p++; - t->value = TOKplusplus; - } - else - t->value = TOKadd; - return; - - case '<': - p++; - if (*p == '=') - { p++; - t->value = TOKle; // <= - } - else if (*p == '<') - { p++; - if (*p == '=') - { p++; - t->value = TOKshlass; // <<= - } - else - t->value = TOKshl; // << - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKleg; // <>= - } - else - t->value = TOKlg; // <> - } - else - t->value = TOKlt; // < - return; - - case '>': - p++; - if (*p == '=') - { p++; - t->value = TOKge; // >= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKshrass; // >>= - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKushrass; // >>>= - } - else - t->value = TOKushr; // >>> - } - else - t->value = TOKshr; // >> - } - else - t->value = TOKgt; // > - return; - - case '!': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKnotidentity; // !== - } - else - t->value = TOKnotequal; // != - } - else if (*p == '<') - { p++; - if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKunord; // !<>= - } - else - t->value = TOKue; // !<> - } - else if (*p == '=') - { p++; - t->value = TOKug; // !<= - } - else - t->value = TOKuge; // !< - } - else if (*p == '>') - { p++; - if (*p == '=') - { p++; - t->value = TOKul; // !>= - } - else - t->value = TOKule; // !> - } - else - t->value = TOKnot; // ! - return; - - case '=': - p++; - if (*p == '=') - { p++; - if (*p == '=' && global.params.Dversion == 1) - { p++; - t->value = TOKidentity; // === - } - else - t->value = TOKequal; // == - } -#if DMDV2 - else if (*p == '>') - { p++; - t->value = TOKgoesto; // => - } -#endif - else - t->value = TOKassign; // = - return; - - case '~': - p++; - if (*p == '=') - { p++; - t->value = TOKcatass; // ~= - } - else - t->value = TOKtilde; // ~ - return; - -#if DMDV2 - case '^': - p++; - if (*p == '^') - { p++; - if (*p == '=') - { p++; - t->value = TOKpowass; // ^^= - } - else - t->value = TOKpow; // ^^ - } - else if (*p == '=') - { p++; - t->value = TOKxorass; // ^= - } - else - t->value = TOKxor; // ^ - return; -#endif - -#define SINGLE(c,tok) case c: p++; t->value = tok; return; - - SINGLE('(', TOKlparen) - SINGLE(')', TOKrparen) - SINGLE('[', TOKlbracket) - SINGLE(']', TOKrbracket) - SINGLE('{', TOKlcurly) - SINGLE('}', TOKrcurly) - SINGLE('?', TOKquestion) - SINGLE(',', TOKcomma) - SINGLE(';', TOKsemicolon) - SINGLE(':', TOKcolon) - SINGLE('$', TOKdollar) -#if DMDV2 - SINGLE('@', TOKat) -#endif -#undef SINGLE - -#define DOUBLE(c1,tok1,c2,tok2) \ - case c1: \ - p++; \ - if (*p == c2) \ - { p++; \ - t->value = tok2; \ - } \ - else \ - t->value = tok1; \ - return; - - DOUBLE('*', TOKmul, '=', TOKmulass) - DOUBLE('%', TOKmod, '=', TOKmodass) -#if DMDV1 - DOUBLE('^', TOKxor, '=', TOKxorass) -#endif -#undef DOUBLE - - case '#': - p++; - pragma(); - continue; - - default: - { unsigned c = *p; - - if (c & 0x80) - { c = decodeUTF(); - - // Check for start of unicode identifier - if (isUniAlpha(c)) - goto case_ident; - - if (c == PS || c == LS) - { - loc.linnum++; - p++; - continue; - } - } - if (c < 0x80 && isprint(c)) - error("unsupported char '%c'", c); - else - error("unsupported char 0x%02x", c); - p++; - continue; - } - } - } -} - -/******************************************* - * Parse escape sequence. - */ - -unsigned Lexer::escapeSequence() -{ unsigned c = *p; - -#ifdef TEXTUAL_ASSEMBLY_OUT - return c; -#endif - int n; - int ndigits; - - switch (c) - { - case '\'': - case '"': - case '?': - case '\\': - Lconsume: - p++; - break; - - case 'a': c = 7; goto Lconsume; - case 'b': c = 8; goto Lconsume; - case 'f': c = 12; goto Lconsume; - case 'n': c = 10; goto Lconsume; - case 'r': c = 13; goto Lconsume; - case 't': c = 9; goto Lconsume; - case 'v': c = 11; goto Lconsume; - - case 'u': - ndigits = 4; - goto Lhex; - case 'U': - ndigits = 8; - goto Lhex; - case 'x': - ndigits = 2; - Lhex: - p++; - c = *p; - if (ishex(c)) - { unsigned v; - - n = 0; - v = 0; - while (1) - { - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - v = v * 16 + c; - c = *++p; - if (++n == ndigits) - break; - if (!ishex(c)) - { error("escape hex sequence has %d hex digits instead of %d", n, ndigits); - break; - } - } - if (ndigits != 2 && !utf_isValidDchar(v)) - { error("invalid UTF character \\U%08x", v); - v = '?'; // recover with valid UTF character - } - c = v; - } - else - error("undefined escape hex sequence \\%c\n",c); - break; - - case '&': // named character entity - for (unsigned char *idstart = ++p; 1; p++) - { - switch (*p) - { - case ';': - c = HtmlNamedEntity(idstart, p - idstart); - if (c == ~0) - { error("unnamed character entity &%.*s;", (int)(p - idstart), idstart); - c = ' '; - } - p++; - break; - - default: - if (isalpha(*p) || - (p != idstart + 1 && isdigit(*p))) - continue; - error("unterminated named entity"); - break; - } - break; - } - break; - - case 0: - case 0x1A: // end of file - c = '\\'; - break; - - default: - if (isoctal(c)) - { unsigned v; - - n = 0; - v = 0; - do - { - v = v * 8 + (c - '0'); - c = *++p; - } while (++n < 3 && isoctal(c)); - c = v; - if (c > 0xFF) - error("0%03o is larger than a byte", c); - } - else - error("undefined escape sequence \\%c\n",c); - break; - } - return c; -} - -/************************************** - */ - -TOK Lexer::wysiwygStringConstant(Token *t, int tc) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - case '`': - if (c == tc) - { - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - } - break; - - default: - if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - stringbuffer.writeUTF8(u); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - -TOK Lexer::hexStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned n = 0; - unsigned v; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - - case '\r': - if (*p == '\n') - continue; // ignore - // Treat isolated '\r' as if it were a '\n' - case '\n': - loc.linnum++; - continue; - - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - case '"': - if (n & 1) - { error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - default: - if (c >= '0' && c <= '9') - c -= '0'; - else if (c >= 'a' && c <= 'f') - c -= 'a' - 10; - else if (c >= 'A' && c <= 'F') - c -= 'A' - 10; - else if (c & 0x80) - { p--; - unsigned u = decodeUTF(); - p++; - if (u == PS || u == LS) - loc.linnum++; - else - error("non-hex character \\u%04x", u); - } - else - error("non-hex character '%c'", c); - if (n & 1) - { v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } -} - - -#if DMDV2 -/************************************** - * Lex delimited strings: - * q"(foo(xxx))" // "foo(xxx)" - * q"[foo(]" // "foo(" - * q"/foo]/" // "foo]" - * q"HERE - * foo - * HERE" // "foo\n" - * Input: - * p is on the " - */ - -TOK Lexer::delimitedStringConstant(Token *t) -{ unsigned c; - Loc start = loc; - unsigned delimleft = 0; - unsigned delimright = 0; - unsigned nest = 1; - unsigned nestcount; - Identifier *hereid = NULL; - unsigned blankrol = 0; - unsigned startline = 0; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - //printf("c = '%c'\n", c); - switch (c) - { - case '\n': - Lnextline: - loc.linnum++; - startline = 1; - if (blankrol) - { blankrol = 0; - continue; - } - if (hereid) - { - stringbuffer.writeUTF8(c); - continue; - } - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - goto Lnextline; - - case 0: - case 0x1A: - goto Lerror; - - default: - if (c & 0x80) - { p--; - c = decodeUTF(); - p++; - if (c == PS || c == LS) - goto Lnextline; - } - break; - } - if (delimleft == 0) - { delimleft = c; - nest = 1; - nestcount = 1; - if (c == '(') - delimright = ')'; - else if (c == '{') - delimright = '}'; - else if (c == '[') - delimright = ']'; - else if (c == '<') - delimright = '>'; - else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) - { // Start of identifier; must be a heredoc - Token t; - p--; - scan(&t); // read in heredoc identifier - if (t.value != TOKidentifier) - { error("identifier expected for heredoc, not %s", t.toChars()); - delimright = c; - } - else - { hereid = t.ident; - //printf("hereid = '%s'\n", hereid->toChars()); - blankrol = 1; - } - nest = 0; - } - else - { delimright = c; - nest = 0; -#if DMDV2 - if (isspace(c)) - error("delimiter cannot be whitespace"); -#endif - } - } - else - { - if (blankrol) - { error("heredoc rest of line should be blank"); - blankrol = 0; - continue; - } - if (nest == 1) - { - if (c == delimleft) - nestcount++; - else if (c == delimright) - { nestcount--; - if (nestcount == 0) - goto Ldone; - } - } - else if (c == delimright) - goto Ldone; - if (startline && isalpha(c) -#if DMDV2 - && hereid -#endif - ) - { Token t; - unsigned char *psave = p; - p--; - scan(&t); // read in possible heredoc identifier - //printf("endid = '%s'\n", t.ident->toChars()); - if (t.value == TOKidentifier && t.ident->equals(hereid)) - { /* should check that rest of line is blank - */ - goto Ldone; - } - p = psave; - } - stringbuffer.writeUTF8(c); - startline = 0; - } - } - -Ldone: - if (*p == '"') - p++; - else - error("delimited string must end in %c\"", delimright); - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -/************************************** - * Lex delimited strings: - * q{ foo(xxx) } // " foo(xxx) " - * q{foo(} // "foo(" - * q{{foo}"}"} // "{foo}"}"" - * Input: - * p is on the q - */ - -TOK Lexer::tokenStringConstant(Token *t) -{ - unsigned nest = 1; - Loc start = loc; - unsigned char *pstart = ++p; - - while (1) - { Token tok; - - scan(&tok); - switch (tok.value) - { - case TOKlcurly: - nest++; - continue; - - case TOKrcurly: - if (--nest == 0) - goto Ldone; - continue; - - case TOKeof: - goto Lerror; - - default: - continue; - } - } - -Ldone: - t->len = p - 1 - pstart; - t->ustring = (unsigned char *)mem.malloc(t->len + 1); - memcpy(t->ustring, pstart, t->len); - t->ustring[t->len] = 0; - stringPostfix(t); - return TOKstring; - -Lerror: - error("unterminated token string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; -} - -#endif - - -/************************************** - */ - -TOK Lexer::escapeStringConstant(Token *t, int wide) -{ unsigned c; - Loc start = loc; - - p++; - stringbuffer.reset(); - while (1) - { - c = *p++; - switch (c) - { -#if !( TEXTUAL_ASSEMBLY_OUT ) - case '\\': - switch (*p) - { - case 'u': - case 'U': - case '&': - c = escapeSequence(); - stringbuffer.writeUTF8(c); - continue; - - default: - c = escapeSequence(); - break; - } - break; -#endif - case '\n': - loc.linnum++; - break; - - case '\r': - if (*p == '\n') - continue; // ignore - c = '\n'; // treat EndOfLine as \n character - loc.linnum++; - break; - - case '"': - t->len = stringbuffer.offset; - stringbuffer.writeByte(0); - t->ustring = (unsigned char *)mem.malloc(stringbuffer.offset); - memcpy(t->ustring, stringbuffer.data, stringbuffer.offset); - stringPostfix(t); - return TOKstring; - - case 0: - case 0x1A: - p--; - error("unterminated string constant starting at %s", start.toChars()); - t->ustring = (unsigned char *)""; - t->len = 0; - t->postfix = 0; - return TOKstring; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - if (c == LS || c == PS) - { c = '\n'; - loc.linnum++; - } - p++; - stringbuffer.writeUTF8(c); - continue; - } - break; - } - stringbuffer.writeByte(c); - } -} - -/************************************** - */ - -TOK Lexer::charConstant(Token *t, int wide) -{ - unsigned c; - TOK tk = TOKcharv; - - //printf("Lexer::charConstant\n"); - p++; - c = *p++; - switch (c) - { -#if ! TEXTUAL_ASSEMBLY_OUT - case '\\': - switch (*p) - { - case 'u': - t->uns64value = escapeSequence(); - tk = TOKwcharv; - break; - - case 'U': - case '&': - t->uns64value = escapeSequence(); - tk = TOKdcharv; - break; - - default: - t->uns64value = escapeSequence(); - break; - } - break; -#endif - case '\n': - L1: - loc.linnum++; - case '\r': - case 0: - case 0x1A: - case '\'': - error("unterminated character constant"); - return tk; - - default: - if (c & 0x80) - { - p--; - c = decodeUTF(); - p++; - if (c == LS || c == PS) - goto L1; - if (c < 0xD800 || (c >= 0xE000 && c < 0xFFFE)) - tk = TOKwcharv; - else - tk = TOKdcharv; - } - t->uns64value = c; - break; - } - - if (*p != '\'') - { error("unterminated character constant"); - return tk; - } - p++; - return tk; -} - -/*************************************** - * Get postfix of string literal. - */ - -void Lexer::stringPostfix(Token *t) -{ - switch (*p) - { - case 'c': - case 'w': - case 'd': - t->postfix = *p; - p++; - break; - - default: - t->postfix = 0; - break; - } -} - -/*************************************** - * Read \u or \U unicode sequence - * Input: - * u 'u' or 'U' - */ - -#if 0 -unsigned Lexer::wchar(unsigned u) -{ - unsigned value; - unsigned n; - unsigned char c; - unsigned nchars; - - nchars = (u == 'U') ? 8 : 4; - value = 0; - for (n = 0; 1; n++) - { - ++p; - if (n == nchars) - break; - c = *p; - if (!ishex(c)) - { error("\\%c sequence must be followed by %d hex characters", u, nchars); - break; - } - if (isdigit(c)) - c -= '0'; - else if (islower(c)) - c -= 'a' - 10; - else - c -= 'A' - 10; - value <<= 4; - value |= c; - } - return value; -} -#endif - -/************************************** - * Read in a number. - * If it's an integer, store it in tok.TKutok.Vlong. - * integers can be decimal, octal or hex - * Handle the suffixes U, UL, LU, L, etc. - * If it's double, store it in tok.TKutok.Vdouble. - * Returns: - * TKnum - * TKdouble,... - */ - -TOK Lexer::number(Token *t) -{ - // We use a state machine to collect numbers - enum STATE { STATE_initial, STATE_0, STATE_decimal, STATE_octal, STATE_octale, - STATE_hex, STATE_binary, STATE_hex0, STATE_binary0, - STATE_hexh, STATE_error }; - enum STATE state; - - enum FLAGS - { FLAGS_decimal = 1, // decimal - FLAGS_unsigned = 2, // u or U suffix - FLAGS_long = 4, // l or L suffix - }; - enum FLAGS flags = FLAGS_decimal; - - int base; - unsigned c; - unsigned char *start; - TOK result; - - //printf("Lexer::number()\n"); - state = STATE_initial; - base = 0; - stringbuffer.reset(); - start = p; - while (1) - { - c = *p; - switch (state) - { - case STATE_initial: // opening state - if (c == '0') - state = STATE_0; - else - state = STATE_decimal; - break; - - case STATE_0: - flags = (FLAGS) (flags & ~FLAGS_decimal); - switch (c) - { -#if ZEROH - case 'H': // 0h - case 'h': - goto hexh; -#endif - case 'X': - case 'x': - state = STATE_hex0; - break; - - case '.': - if (p[1] == '.') // .. is a separate token - goto done; - case 'i': - case 'f': - case 'F': - goto real; -#if ZEROH - case 'E': - case 'e': - goto case_hex; -#endif - case 'B': - case 'b': - state = STATE_binary0; - break; - - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - state = STATE_octal; - break; - -#if ZEROH - case '8': case '9': case 'A': - case 'C': case 'D': case 'F': - case 'a': case 'c': case 'd': case 'f': - case_hex: - state = STATE_hexh; - break; -#endif - case '_': - state = STATE_octal; - p++; - continue; - - case 'L': - if (p[1] == 'i') - goto real; - goto done; - - default: - goto done; - } - break; - - case STATE_decimal: // reading decimal number - if (!isdigit(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - { -#if DMDV2 - if (isalpha(p[1]) || p[1] == '_') - goto done; -#endif - goto real; - } - else if (c == 'i' || c == 'f' || c == 'F' || - c == 'e' || c == 'E') - { - real: // It's a real number. Back up and rescan as a real - p = start; - return inreal(t); - } - else if (c == 'L' && p[1] == 'i') - goto real; - goto done; - } - break; - - case STATE_hex0: // reading hex number - case STATE_hex: - if (!ishex(c)) - { - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'P' || c == 'p' || c == 'i') - goto real; - if (state == STATE_hex0) - error("Hex digit expected, not '%c'", c); - goto done; - } - state = STATE_hex; - break; - -#if ZEROH - hexh: - state = STATE_hexh; - case STATE_hexh: // parse numbers like 0FFh - if (!ishex(c)) - { - if (c == 'H' || c == 'h') - { - p++; - base = 16; - goto done; - } - else - { - // Check for something like 1E3 or 0E24 - if (memchr((char *)stringbuffer.data, 'E', stringbuffer.offset) || - memchr((char *)stringbuffer.data, 'e', stringbuffer.offset)) - goto real; - error("Hex digit expected, not '%c'", c); - goto done; - } - } - break; -#endif - - case STATE_octal: // reading octal number - case STATE_octale: // reading octal number with non-octal digits - if (!isoctal(c)) - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (c == '.' && p[1] != '.') - goto real; - if (c == 'i') - goto real; - if (isdigit(c)) - { - state = STATE_octale; - } - else - goto done; - } - break; - - case STATE_binary0: // starting binary number - case STATE_binary: // reading binary number - if (c != '0' && c != '1') - { -#if ZEROH - if (ishex(c) - || c == 'H' || c == 'h' - ) - goto hexh; -#endif - if (c == '_') // ignore embedded _ - { p++; - continue; - } - if (state == STATE_binary0) - { error("binary digit expected"); - state = STATE_error; - break; - } - else - goto done; - } - state = STATE_binary; - break; - - case STATE_error: // for error recovery - if (!isdigit(c)) // scan until non-digit - goto done; - break; - - default: - assert(0); - } - stringbuffer.writeByte(c); - p++; - } -done: - stringbuffer.writeByte(0); // terminate string - if (state == STATE_octale) - error("Octal digit expected"); - - uinteger_t n; // unsigned >=64 bit integer type - - if (stringbuffer.offset == 2 && (state == STATE_decimal || state == STATE_0)) - n = stringbuffer.data[0] - '0'; - else - { - // Convert string to integer -#if __DMC__ - errno = 0; - n = strtoull((char *)stringbuffer.data,NULL,base); - if (errno == ERANGE) - error("integer overflow"); -#else - // Not everybody implements strtoull() - char *p = (char *)stringbuffer.data; - int r = 10, d; - - if (*p == '0') - { - if (p[1] == 'x' || p[1] == 'X') - p += 2, r = 16; - else if (p[1] == 'b' || p[1] == 'B') - p += 2, r = 2; - else if (isdigit((unsigned char)p[1])) - p += 1, r = 8; - } - - n = 0; - while (1) - { - if (*p >= '0' && *p <= '9') - d = *p - '0'; - else if (*p >= 'a' && *p <= 'z') - d = *p - 'a' + 10; - else if (*p >= 'A' && *p <= 'Z') - d = *p - 'A' + 10; - else - break; - if (d >= r) - break; - uinteger_t n2 = n * r; - //printf("n2 / r = %llx, n = %llx\n", n2/r, n); - if (n2 / r != n || n2 + d < n) - { - error ("integer overflow"); - break; - } - - n = n2 + d; - p++; - } -#endif - if (sizeof(n) > 8 && - n > 0xFFFFFFFFFFFFFFFFULL) // if n needs more than 64 bits - error("integer overflow"); - } - - // Parse trailing 'u', 'U', 'l' or 'L' in any combination - const unsigned char *psuffix = p; - while (1) - { unsigned char f; - - switch (*p) - { case 'U': - case 'u': - f = FLAGS_unsigned; - goto L1; - - case 'l': - if (1 || !global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - f = FLAGS_long; - L1: - p++; - if (flags & f) - error("unrecognized token"); - flags = (FLAGS) (flags | f); - continue; - default: - break; - } - break; - } - -#if DMDV2 - if (state == STATE_octal && n >= 8 && !global.params.useDeprecated) - error("octal literals 0%llo%.*s are deprecated, use std.conv.octal!%llo%.*s instead", - n, p - psuffix, psuffix, n, p - psuffix, psuffix); -#endif - - switch (flags) - { - case 0: - /* Octal or Hexadecimal constant. - * First that fits: int, uint, long, ulong - */ - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else if (n & 0xFFFFFFFF00000000LL) - result = TOKint64v; - else if (n & 0x80000000) - result = TOKuns32v; - else - result = TOKint32v; - break; - - case FLAGS_decimal: - /* First that fits: int, long, long long - */ - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else if (n & 0xFFFFFFFF80000000LL) - result = TOKint64v; - else - result = TOKint32v; - break; - - case FLAGS_unsigned: - case FLAGS_decimal | FLAGS_unsigned: - /* First that fits: uint, ulong - */ - if (n & 0xFFFFFFFF00000000LL) - result = TOKuns64v; - else - result = TOKuns32v; - break; - - case FLAGS_decimal | FLAGS_long: - if (n & 0x8000000000000000LL) - { error("signed integer overflow"); - result = TOKuns64v; - } - else - result = TOKint64v; - break; - - case FLAGS_long: - if (n & 0x8000000000000000LL) - result = TOKuns64v; - else - result = TOKint64v; - break; - - case FLAGS_unsigned | FLAGS_long: - case FLAGS_decimal | FLAGS_unsigned | FLAGS_long: - result = TOKuns64v; - break; - - default: - #ifdef DEBUG - printf("%x\n",flags); - #endif - assert(0); - } - t->uns64value = n; - return result; -} - -/************************************** - * Read in characters, converting them to real. - * Bugs: - * Exponent overflow not detected. - * Too much requested precision is not detected. - */ - -TOK Lexer::inreal(Token *t) -#ifdef __DMC__ -__in -{ - assert(*p == '.' || isdigit(*p)); -} -__out (result) -{ - switch (result) - { - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - break; - - default: - assert(0); - } -} -__body -#endif /* __DMC__ */ -{ int dblstate; - unsigned c; - char hex; // is this a hexadecimal-floating-constant? - TOK result; - - //printf("Lexer::inreal()\n"); - stringbuffer.reset(); - dblstate = 0; - hex = 0; -Lnext: - while (1) - { - // Get next char from input - c = *p++; - //printf("dblstate = %d, c = '%c'\n", dblstate, c); - while (1) - { - switch (dblstate) - { - case 0: // opening state - if (c == '0') - dblstate = 9; - else if (c == '.') - dblstate = 3; - else - dblstate = 1; - break; - - case 9: - dblstate = 1; - if (c == 'X' || c == 'x') - { hex++; - break; - } - case 1: // digits to left of . - case 3: // digits to right of . - case 7: // continuing exponent digits - if (!isdigit(c) && !(hex && isxdigit(c))) - { - if (c == '_') - goto Lnext; // ignore embedded '_' - dblstate++; - continue; - } - break; - - case 2: // no more digits to left of . - if (c == '.') - { dblstate++; - break; - } - case 4: // no more digits to right of . - if ((c == 'E' || c == 'e') || - hex && (c == 'P' || c == 'p')) - { dblstate = 5; - hex = 0; // exponent is always decimal - break; - } - if (hex) - error("binary-exponent-part required"); - goto done; - - case 5: // looking immediately to right of E - dblstate++; - if (c == '-' || c == '+') - break; - case 6: // 1st exponent digit expected - if (!isdigit(c)) - error("exponent expected"); - dblstate++; - break; - - case 8: // past end of exponent digits - goto done; - } - break; - } - stringbuffer.writeByte(c); - } -done: - p--; - - stringbuffer.writeByte(0); - -#if _WIN32 && __DMC__ - char *save = __locale_decpoint; - __locale_decpoint = "."; -#endif -#ifdef IN_GCC - t->float80value = real_t::parse((char *)stringbuffer.data, real_t::LongDouble); -#else - t->float80value = strtold((char *)stringbuffer.data, NULL); -#endif - errno = 0; - float strtofres; - double strtodres; - switch (*p) - { - case 'F': - case 'f': -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Float); -#else - strtofres = strtof((char *)stringbuffer.data, NULL); -#ifdef IN_LLVM -#ifdef _MSC_VER -#define HUGE_VALF HUGE_VAL -#endif - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtofres != 0 && strtofres != HUGE_VALF && strtofres != -HUGE_VALF) - errno = 0; -#endif -#endif - result = TOKfloat32v; - p++; - break; - - default: -#ifdef IN_GCC - real_t::parse((char *)stringbuffer.data, real_t::Double); -#else - strtodres = strtod((char *)stringbuffer.data, NULL); -#ifdef IN_LLVM - // LDC change: don't error on gradual underflow - if (errno == ERANGE && - strtodres != 0 && strtodres != HUGE_VAL && strtodres != -HUGE_VAL) - errno = 0; -#endif -#endif - result = TOKfloat64v; - break; - - case 'l': - if (!global.params.useDeprecated) - error("'l' suffix is deprecated, use 'L' instead"); - case 'L': - result = TOKfloat80v; - p++; - break; - } - if (*p == 'i' || *p == 'I') - { - if (!global.params.useDeprecated && *p == 'I') - error("'I' suffix is deprecated, use 'i' instead"); - p++; - switch (result) - { - case TOKfloat32v: - result = TOKimaginary32v; - break; - case TOKfloat64v: - result = TOKimaginary64v; - break; - case TOKfloat80v: - result = TOKimaginary80v; - break; - } - } -#if _WIN32 && __DMC__ - __locale_decpoint = save; -#endif - if (errno == ERANGE) - error("number is not representable"); - return result; -} - -/********************************************* - * Do pragma. - * Currently, the only pragma supported is: - * #line linnum [filespec] - */ - -void Lexer::pragma() -{ - Token tok; - int linnum; - char *filespec = NULL; - Loc loc = this->loc; - - scan(&tok); - if (tok.value != TOKidentifier || tok.ident != Id::line) - goto Lerr; - - scan(&tok); - if (tok.value == TOKint32v || tok.value == TOKint64v) - { linnum = tok.uns64value - 1; - if (linnum != tok.uns64value - 1) - error("line number out of range"); - } - else - goto Lerr; - - while (1) - { - switch (*p) - { - case 0: - case 0x1A: - case '\n': - Lnewline: - this->loc.linnum = linnum; - if (filespec) - this->loc.filename = filespec; - return; - - case '\r': - p++; - if (*p != '\n') - { p--; - goto Lnewline; - } - continue; - - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - - case '_': - if (mod && memcmp(p, "__FILE__", 8) == 0) - { - p += 8; - filespec = mem.strdup(loc.filename ? loc.filename : mod->ident->toChars()); - } - continue; - - case '"': - if (filespec) - goto Lerr; - stringbuffer.reset(); - p++; - while (1) - { unsigned c; - - c = *p; - switch (c) - { - case '\n': - case '\r': - case 0: - case 0x1A: - goto Lerr; - - case '"': - stringbuffer.writeByte(0); - filespec = mem.strdup((char *)stringbuffer.data); - p++; - break; - - default: - if (c & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lerr; - } - stringbuffer.writeByte(c); - p++; - continue; - } - break; - } - continue; - - default: - if (*p & 0x80) - { unsigned u = decodeUTF(); - if (u == PS || u == LS) - goto Lnewline; - } - goto Lerr; - } - } - -Lerr: - error(loc, "#line integer [\"filespec\"]\\n expected"); -} - - -/******************************************** - * Decode UTF character. - * Issue error messages for invalid sequences. - * Return decoded character, advance p to last character in UTF sequence. - */ - -unsigned Lexer::decodeUTF() -{ - dchar_t u; - unsigned char c; - unsigned char *s = p; - size_t len; - size_t idx; - const char *msg; - - c = *s; - assert(c & 0x80); - - // Check length of remaining string up to 6 UTF-8 characters - for (len = 1; len < 6 && s[len]; len++) - ; - - idx = 0; - msg = utf_decodeChar(s, len, &idx, &u); - p += idx - 1; - if (msg) - { - error("%s", msg); - } - return u; -} - - -/*************************************************** - * Parse doc comment embedded between t->ptr and p. - * Remove trailing blanks and tabs from lines. - * Replace all newlines with \n. - * Remove leading comment character from each line. - * Decide if it's a lineComment or a blockComment. - * Append to previous one for this token. - */ - -void Lexer::getDocComment(Token *t, unsigned lineComment) -{ - /* ct tells us which kind of comment it is: '/', '*', or '+' - */ - unsigned char ct = t->ptr[2]; - - /* Start of comment text skips over / * *, / + +, or / / / - */ - unsigned char *q = t->ptr + 3; // start of comment text - - unsigned char *qend = p; - if (ct == '*' || ct == '+') - qend -= 2; - - /* Scan over initial row of ****'s or ++++'s or ////'s - */ - for (; q < qend; q++) - { - if (*q != ct) - break; - } - - /* Remove trailing row of ****'s or ++++'s - */ - if (ct != '/') - { - for (; q < qend; qend--) - { - if (qend[-1] != ct) - break; - } - } - - /* Comment is now [q .. qend]. - * Canonicalize it into buf[]. - */ - OutBuffer buf; - int linestart = 0; - - for (; q < qend; q++) - { - unsigned char c = *q; - - switch (c) - { - case '*': - case '+': - if (linestart && c == ct) - { linestart = 0; - /* Trim preceding whitespace up to preceding \n - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - continue; - } - break; - - case ' ': - case '\t': - break; - - case '\r': - if (q[1] == '\n') - continue; // skip the \r - goto Lnewline; - - default: - if (c == 226) - { - // If LS or PS - if (q[1] == 128 && - (q[2] == 168 || q[2] == 169)) - { - q += 2; - goto Lnewline; - } - } - linestart = 0; - break; - - Lnewline: - c = '\n'; // replace all newlines with \n - case '\n': - linestart = 1; - - /* Trim trailing whitespace - */ - while (buf.offset && (buf.data[buf.offset - 1] == ' ' || buf.data[buf.offset - 1] == '\t')) - buf.offset--; - - break; - } - buf.writeByte(c); - } - - // Always end with a newline - if (!buf.offset || buf.data[buf.offset - 1] != '\n') - buf.writeByte('\n'); - - buf.writeByte(0); - - // It's a line comment if the start of the doc comment comes - // after other non-whitespace on the same line. - unsigned char** dc = (lineComment && anyToken) - ? &t->lineComment - : &t->blockComment; - - // Combine with previous doc comment, if any - if (*dc) - *dc = combineComments(*dc, (unsigned char *)buf.data); - else - *dc = (unsigned char *)buf.extractData(); -} - -/******************************************** - * Combine two document comments into one, - * separated by a newline. - */ - -unsigned char *Lexer::combineComments(unsigned char *c1, unsigned char *c2) -{ - //printf("Lexer::combineComments('%s', '%s')\n", c1, c2); - - unsigned char *c = c2; - - if (c1) - { c = c1; - if (c2) - { size_t len1 = strlen((char *)c1); - size_t len2 = strlen((char *)c2); - - c = (unsigned char *)mem.malloc(len1 + 1 + len2 + 1); - memcpy(c, c1, len1); - if (len1 && c1[len1 - 1] != '\n') - { c[len1] = '\n'; - len1++; - } - memcpy(c + len1, c2, len2); - c[len1 + len2] = 0; - } - } - return c; -} - -/******************************************** - * Create an identifier in the string table. - */ - -Identifier *Lexer::idPool(const char *s) -{ - size_t len = strlen(s); - StringValue *sv = stringtable.update(s, len); - Identifier *id = (Identifier *) sv->ptrvalue; - if (!id) - { - id = new Identifier(sv->lstring.string, TOKidentifier); - sv->ptrvalue = id; - } - return id; -} - -/********************************************* - * Create a unique identifier using the prefix s. - */ - -Identifier *Lexer::uniqueId(const char *s, int num) -{ char buffer[32]; - size_t slen = strlen(s); - - assert(slen + sizeof(num) * 3 + 1 <= sizeof(buffer)); - sprintf(buffer, "%s%d", s, num); - return idPool(buffer); -} - -Identifier *Lexer::uniqueId(const char *s) -{ - static int num; - return uniqueId(s, ++num); -} - -/**************************************** - */ - -struct Keyword -{ const char *name; - enum TOK value; -}; - -static Keyword keywords[] = -{ -// { "", TOK }, - - { "this", TOKthis }, - { "super", TOKsuper }, - { "assert", TOKassert }, - { "null", TOKnull }, - { "true", TOKtrue }, - { "false", TOKfalse }, - { "cast", TOKcast }, - { "new", TOKnew }, - { "delete", TOKdelete }, - { "throw", TOKthrow }, - { "module", TOKmodule }, - { "pragma", TOKpragma }, - { "typeof", TOKtypeof }, - { "typeid", TOKtypeid }, - - { "template", TOKtemplate }, - - { "void", TOKvoid }, - { "byte", TOKint8 }, - { "ubyte", TOKuns8 }, - { "short", TOKint16 }, - { "ushort", TOKuns16 }, - { "int", TOKint32 }, - { "uint", TOKuns32 }, - { "long", TOKint64 }, - { "ulong", TOKuns64 }, - { "cent", TOKcent, }, - { "ucent", TOKucent, }, - { "float", TOKfloat32 }, - { "double", TOKfloat64 }, - { "real", TOKfloat80 }, - - { "bool", TOKbool }, - { "char", TOKchar }, - { "wchar", TOKwchar }, - { "dchar", TOKdchar }, - - { "ifloat", TOKimaginary32 }, - { "idouble", TOKimaginary64 }, - { "ireal", TOKimaginary80 }, - - { "cfloat", TOKcomplex32 }, - { "cdouble", TOKcomplex64 }, - { "creal", TOKcomplex80 }, - - { "delegate", TOKdelegate }, - { "function", TOKfunction }, - - { "is", TOKis }, - { "if", TOKif }, - { "else", TOKelse }, - { "while", TOKwhile }, - { "for", TOKfor }, - { "do", TOKdo }, - { "switch", TOKswitch }, - { "case", TOKcase }, - { "default", TOKdefault }, - { "break", TOKbreak }, - { "continue", TOKcontinue }, - { "synchronized", TOKsynchronized }, - { "return", TOKreturn }, - { "goto", TOKgoto }, - { "try", TOKtry }, - { "catch", TOKcatch }, - { "finally", TOKfinally }, - { "with", TOKwith }, - { "asm", TOKasm }, - { "foreach", TOKforeach }, - { "foreach_reverse", TOKforeach_reverse }, - { "scope", TOKscope }, - - { "struct", TOKstruct }, - { "class", TOKclass }, - { "interface", TOKinterface }, - { "union", TOKunion }, - { "enum", TOKenum }, - { "import", TOKimport }, - { "mixin", TOKmixin }, - { "static", TOKstatic }, - { "final", TOKfinal }, - { "const", TOKconst }, - { "typedef", TOKtypedef }, - { "alias", TOKalias }, - { "override", TOKoverride }, - { "abstract", TOKabstract }, - { "volatile", TOKvolatile }, - { "debug", TOKdebug }, - { "deprecated", TOKdeprecated }, - { "in", TOKin }, - { "out", TOKout }, - { "inout", TOKinout }, - { "lazy", TOKlazy }, - { "auto", TOKauto }, - - { "align", TOKalign }, - { "extern", TOKextern }, - { "private", TOKprivate }, - { "package", TOKpackage }, - { "protected", TOKprotected }, - { "public", TOKpublic }, - { "export", TOKexport }, - - { "body", TOKbody }, - { "invariant", TOKinvariant }, - { "unittest", TOKunittest }, - { "version", TOKversion }, - //{ "manifest", TOKmanifest }, - - // Added after 1.0 - { "__argTypes", TOKargTypes }, - { "ref", TOKref }, - { "macro", TOKmacro }, -#if DMDV2 - { "pure", TOKpure }, - { "nothrow", TOKnothrow }, - { "__thread", TOKtls }, - { "__gshared", TOKgshared }, - { "__traits", TOKtraits }, - { "__vector", TOKvector }, - { "__overloadset", TOKoverloadset }, - { "__FILE__", TOKfile }, - { "__LINE__", TOKline }, - { "shared", TOKshared }, - { "immutable", TOKimmutable }, -#endif -}; - -int Token::isKeyword() -{ - for (unsigned u = 0; u < sizeof(keywords) / sizeof(keywords[0]); u++) - { - if (keywords[u].value == value) - return 1; - } - return 0; -} - -void Lexer::initKeywords() -{ - unsigned nkeywords = sizeof(keywords) / sizeof(keywords[0]); - - stringtable.init(6151); - - if (global.params.Dversion == 1) - nkeywords -= 2; - - cmtable_init(); - - for (unsigned u = 0; u < nkeywords; u++) - { - //printf("keyword[%d] = '%s'\n",u, keywords[u].name); - const char *s = keywords[u].name; - enum TOK v = keywords[u].value; - StringValue *sv = stringtable.insert(s, strlen(s)); - sv->ptrvalue = (void *) new Identifier(sv->lstring.string,v); - - //printf("tochars[%d] = '%s'\n",v, s); - Token::tochars[v] = s; - } - - Token::tochars[TOKeof] = "EOF"; - Token::tochars[TOKlcurly] = "{"; - Token::tochars[TOKrcurly] = "}"; - Token::tochars[TOKlparen] = "("; - Token::tochars[TOKrparen] = ")"; - Token::tochars[TOKlbracket] = "["; - Token::tochars[TOKrbracket] = "]"; - Token::tochars[TOKsemicolon] = ";"; - Token::tochars[TOKcolon] = ":"; - Token::tochars[TOKcomma] = ","; - Token::tochars[TOKdot] = "."; - Token::tochars[TOKxor] = "^"; - Token::tochars[TOKxorass] = "^="; - Token::tochars[TOKassign] = "="; - Token::tochars[TOKconstruct] = "="; -#if DMDV2 - Token::tochars[TOKblit] = "="; -#endif - Token::tochars[TOKlt] = "<"; - Token::tochars[TOKgt] = ">"; - Token::tochars[TOKle] = "<="; - Token::tochars[TOKge] = ">="; - Token::tochars[TOKequal] = "=="; - Token::tochars[TOKnotequal] = "!="; - Token::tochars[TOKnotidentity] = "!is"; - Token::tochars[TOKtobool] = "!!"; - - Token::tochars[TOKunord] = "!<>="; - Token::tochars[TOKue] = "!<>"; - Token::tochars[TOKlg] = "<>"; - Token::tochars[TOKleg] = "<>="; - Token::tochars[TOKule] = "!>"; - Token::tochars[TOKul] = "!>="; - Token::tochars[TOKuge] = "!<"; - Token::tochars[TOKug] = "!<="; - - Token::tochars[TOKnot] = "!"; - Token::tochars[TOKtobool] = "!!"; - Token::tochars[TOKshl] = "<<"; - Token::tochars[TOKshr] = ">>"; - Token::tochars[TOKushr] = ">>>"; - Token::tochars[TOKadd] = "+"; - Token::tochars[TOKmin] = "-"; - Token::tochars[TOKmul] = "*"; - Token::tochars[TOKdiv] = "/"; - Token::tochars[TOKmod] = "%"; - Token::tochars[TOKslice] = ".."; - Token::tochars[TOKdotdotdot] = "..."; - Token::tochars[TOKand] = "&"; - Token::tochars[TOKandand] = "&&"; - Token::tochars[TOKor] = "|"; - Token::tochars[TOKoror] = "||"; - Token::tochars[TOKarray] = "[]"; - Token::tochars[TOKindex] = "[i]"; - Token::tochars[TOKaddress] = "&"; - Token::tochars[TOKstar] = "*"; - Token::tochars[TOKtilde] = "~"; - Token::tochars[TOKdollar] = "$"; - Token::tochars[TOKcast] = "cast"; - Token::tochars[TOKplusplus] = "++"; - Token::tochars[TOKminusminus] = "--"; - Token::tochars[TOKpreplusplus] = "++"; - Token::tochars[TOKpreminusminus] = "--"; - Token::tochars[TOKtype] = "type"; - Token::tochars[TOKquestion] = "?"; - Token::tochars[TOKneg] = "-"; - Token::tochars[TOKuadd] = "+"; - Token::tochars[TOKvar] = "var"; - Token::tochars[TOKaddass] = "+="; - Token::tochars[TOKminass] = "-="; - Token::tochars[TOKmulass] = "*="; - Token::tochars[TOKdivass] = "/="; - Token::tochars[TOKmodass] = "%="; - Token::tochars[TOKshlass] = "<<="; - Token::tochars[TOKshrass] = ">>="; - Token::tochars[TOKushrass] = ">>>="; - Token::tochars[TOKandass] = "&="; - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKcatass] = "~="; - Token::tochars[TOKcat] = "~"; - Token::tochars[TOKcall] = "call"; - Token::tochars[TOKidentity] = "is"; - Token::tochars[TOKnotidentity] = "!is"; - - Token::tochars[TOKorass] = "|="; - Token::tochars[TOKidentifier] = "identifier"; -#if DMDV2 - Token::tochars[TOKat] = "@"; - Token::tochars[TOKpow] = "^^"; - Token::tochars[TOKpowass] = "^^="; - Token::tochars[TOKgoesto] = "=>"; -#endif - - // For debugging - Token::tochars[TOKerror] = "error"; - Token::tochars[TOKdotexp] = "dotexp"; - Token::tochars[TOKdotti] = "dotti"; - Token::tochars[TOKdotvar] = "dotvar"; - Token::tochars[TOKdottype] = "dottype"; - Token::tochars[TOKsymoff] = "symoff"; - Token::tochars[TOKarraylength] = "arraylength"; - Token::tochars[TOKarrayliteral] = "arrayliteral"; - Token::tochars[TOKassocarrayliteral] = "assocarrayliteral"; - Token::tochars[TOKstructliteral] = "structliteral"; - Token::tochars[TOKstring] = "string"; - Token::tochars[TOKdsymbol] = "symbol"; - Token::tochars[TOKtuple] = "tuple"; - Token::tochars[TOKdeclaration] = "declaration"; - Token::tochars[TOKdottd] = "dottd"; - Token::tochars[TOKon_scope_exit] = "scope(exit)"; - Token::tochars[TOKon_scope_success] = "scope(success)"; - Token::tochars[TOKon_scope_failure] = "scope(failure)"; - -#if UNITTEST - unittest_lexer(); -#endif -} - -#if UNITTEST - -void unittest_lexer() -{ - //printf("unittest_lexer()\n"); - - /* Not much here, just trying things out. - */ - const unsigned char text[] = "int"; - Lexer lex1(NULL, (unsigned char *)text, 0, sizeof(text), 0, 0); - TOK tok; - tok = lex1.nextToken(); - //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOKint32); - assert(tok == TOKint32); - tok = lex1.nextToken(); - assert(tok == TOKeof); - tok = lex1.nextToken(); - assert(tok == TOKeof); -} - -#endif - diff --git a/dmd2/lexer.h b/dmd2/lexer.h deleted file mode 100644 index 692e2c7f..00000000 --- a/dmd2/lexer.h +++ /dev/null @@ -1,321 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_LEXER_H -#define DMD_LEXER_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "mars.h" - -struct StringTable; -struct Identifier; -struct Module; - -/* Tokens: - ( ) - [ ] - { } - < > <= >= == != === !== - << >> <<= >>= >>> >>>= - + - += -= - * / % *= /= %= - & | ^ &= |= ^= - = ! ~ @ - ^^ ^^= - ++ -- - . -> : , => - ? && || - */ - -enum TOK -{ - TOKreserved, - - // Other - TOKlparen, TOKrparen, - TOKlbracket, TOKrbracket, - TOKlcurly, TOKrcurly, - TOKcolon, TOKneg, - TOKsemicolon, TOKdotdotdot, - TOKeof, TOKcast, - TOKnull, TOKassert, - TOKtrue, TOKfalse, - TOKarray, TOKcall, - TOKaddress, - TOKtype, TOKthrow, - TOKnew, TOKdelete, - TOKstar, TOKsymoff, - TOKvar, TOKdotvar, - TOKdotti, TOKdotexp, - TOKdottype, TOKslice, - TOKarraylength, TOKversion, - TOKmodule, TOKdollar, - TOKtemplate, TOKdottd, - TOKdeclaration, TOKtypeof, - TOKpragma, TOKdsymbol, - TOKtypeid, TOKuadd, - TOKremove, - TOKnewanonclass, TOKcomment, - TOKarrayliteral, TOKassocarrayliteral, - TOKstructliteral, - - // Operators - TOKlt, TOKgt, - TOKle, TOKge, - TOKequal, TOKnotequal, - TOKidentity, TOKnotidentity, - TOKindex, TOKis, - TOKtobool, - -// 60 - // NCEG floating point compares - // !<>= <> <>= !> !>= !< !<= !<> - TOKunord,TOKlg,TOKleg,TOKule,TOKul,TOKuge,TOKug,TOKue, - - TOKshl, TOKshr, - TOKshlass, TOKshrass, - TOKushr, TOKushrass, - TOKcat, TOKcatass, // ~ ~= - TOKadd, TOKmin, TOKaddass, TOKminass, - TOKmul, TOKdiv, TOKmod, - TOKmulass, TOKdivass, TOKmodass, - TOKand, TOKor, TOKxor, - TOKandass, TOKorass, TOKxorass, - TOKassign, TOKnot, TOKtilde, - TOKplusplus, TOKminusminus, TOKconstruct, TOKblit, - TOKdot, TOKarrow, TOKcomma, - TOKquestion, TOKandand, TOKoror, - TOKpreplusplus, TOKpreminusminus, - -// 106 - // Numeric literals - TOKint32v, TOKuns32v, - TOKint64v, TOKuns64v, - TOKfloat32v, TOKfloat64v, TOKfloat80v, - TOKimaginary32v, TOKimaginary64v, TOKimaginary80v, - - // Char constants - TOKcharv, TOKwcharv, TOKdcharv, - - // Leaf operators - TOKidentifier, TOKstring, - TOKthis, TOKsuper, - TOKhalt, TOKtuple, - TOKerror, - - // Basic types - TOKvoid, - TOKint8, TOKuns8, - TOKint16, TOKuns16, - TOKint32, TOKuns32, - TOKint64, TOKuns64, - TOKfloat32, TOKfloat64, TOKfloat80, - TOKimaginary32, TOKimaginary64, TOKimaginary80, - TOKcomplex32, TOKcomplex64, TOKcomplex80, - TOKchar, TOKwchar, TOKdchar, TOKbit, TOKbool, - TOKcent, TOKucent, - -// 152 - // Aggregates - TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport, - TOKtypedef, TOKalias, TOKoverride, TOKdelegate, TOKfunction, - TOKmixin, - - TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport, - TOKstatic, /*TOKvirtual,*/ TOKfinal, TOKconst, TOKabstract, TOKvolatile, - TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy, - TOKauto, TOKpackage, TOKmanifest, TOKimmutable, - - // Statements - TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch, - TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith, - TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally, - TOKasm, TOKforeach, TOKforeach_reverse, - TOKscope, - TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success, - - // Contracts - TOKbody, TOKinvariant, - - // Testing - TOKunittest, - - // Added after 1.0 - TOKargTypes, - TOKref, - TOKmacro, -#if DMDV2 - TOKtraits, - TOKoverloadset, - TOKpure, - TOKnothrow, - TOKtls, - TOKgshared, - TOKline, - TOKfile, - TOKshared, - TOKat, - TOKpow, - TOKpowass, - TOKgoesto, - TOKvector, -#endif - -// LDC specific -#if IN_LLVM - TOKgep, -#endif - - TOKMAX -}; - -#define TOKwild TOKinout - -#define BASIC_TYPES \ - TOKwchar: case TOKdchar: \ - case TOKbit: case TOKbool: case TOKchar: \ - case TOKint8: case TOKuns8: \ - case TOKint16: case TOKuns16: \ - case TOKint32: case TOKuns32: \ - case TOKint64: case TOKuns64: \ - case TOKfloat32: case TOKfloat64: case TOKfloat80: \ - case TOKimaginary32: case TOKimaginary64: case TOKimaginary80: \ - case TOKcomplex32: case TOKcomplex64: case TOKcomplex80: \ - case TOKvoid - -#define BASIC_TYPES_X(t) \ - TOKvoid: t = Type::tvoid; goto LabelX; \ - case TOKint8: t = Type::tint8; goto LabelX; \ - case TOKuns8: t = Type::tuns8; goto LabelX; \ - case TOKint16: t = Type::tint16; goto LabelX; \ - case TOKuns16: t = Type::tuns16; goto LabelX; \ - case TOKint32: t = Type::tint32; goto LabelX; \ - case TOKuns32: t = Type::tuns32; goto LabelX; \ - case TOKint64: t = Type::tint64; goto LabelX; \ - case TOKuns64: t = Type::tuns64; goto LabelX; \ - case TOKfloat32: t = Type::tfloat32; goto LabelX; \ - case TOKfloat64: t = Type::tfloat64; goto LabelX; \ - case TOKfloat80: t = Type::tfloat80; goto LabelX; \ - case TOKimaginary32: t = Type::timaginary32; goto LabelX; \ - case TOKimaginary64: t = Type::timaginary64; goto LabelX; \ - case TOKimaginary80: t = Type::timaginary80; goto LabelX; \ - case TOKcomplex32: t = Type::tcomplex32; goto LabelX; \ - case TOKcomplex64: t = Type::tcomplex64; goto LabelX; \ - case TOKcomplex80: t = Type::tcomplex80; goto LabelX; \ - case TOKbool: t = Type::tbool; goto LabelX; \ - case TOKchar: t = Type::tchar; goto LabelX; \ - case TOKwchar: t = Type::twchar; goto LabelX; \ - case TOKdchar: t = Type::tdchar; goto LabelX; \ - LabelX - -struct Token -{ - Token *next; - unsigned char *ptr; // pointer to first character of this token within buffer - enum TOK value; - unsigned char *blockComment; // doc comment string prior to this token - unsigned char *lineComment; // doc comment for previous token - union - { - // Integers - d_int32 int32value; - d_uns32 uns32value; - d_int64 int64value; - d_uns64 uns64value; - - // Floats -#ifdef IN_GCC - // real_t float80value; // can't use this in a union! -#else - d_float80 float80value; -#endif - - struct - { unsigned char *ustring; // UTF8 string - unsigned len; - unsigned char postfix; // 'c', 'w', 'd' - }; - - Identifier *ident; - }; -#ifdef IN_GCC - real_t float80value; // can't use this in a union! -#endif - - static const char *tochars[TOKMAX]; - static void *operator new(size_t sz); - - int isKeyword(); - void print(); - const char *toChars(); - static const char *toChars(enum TOK); -}; - -struct Lexer -{ - static StringTable stringtable; - static OutBuffer stringbuffer; - static Token *freelist; - - Loc loc; // for error messages - - unsigned char *base; // pointer to start of buffer - unsigned char *end; // past end of buffer - unsigned char *p; // current character - Token token; - Module *mod; - int doDocComment; // collect doc comment information - int anyToken; // !=0 means seen at least one token - int commentToken; // !=0 means comments are TOKcomment's - - Lexer(Module *mod, - unsigned char *base, unsigned begoffset, unsigned endoffset, - int doDocComment, int commentToken); - - static void initKeywords(); - static Identifier *idPool(const char *s); - static Identifier *uniqueId(const char *s); - static Identifier *uniqueId(const char *s, int num); - - TOK nextToken(); - TOK peekNext(); - TOK peekNext2(); - void scan(Token *t); - Token *peek(Token *t); - Token *peekPastParen(Token *t); - unsigned escapeSequence(); - TOK wysiwygStringConstant(Token *t, int tc); - TOK hexStringConstant(Token *t); -#if DMDV2 - TOK delimitedStringConstant(Token *t); - TOK tokenStringConstant(Token *t); -#endif - TOK escapeStringConstant(Token *t, int wide); - TOK charConstant(Token *t, int wide); - void stringPostfix(Token *t); - unsigned wchar(unsigned u); - TOK number(Token *t); - TOK inreal(Token *t); - void error(const char *format, ...) IS_PRINTF(2); - void error(Loc loc, const char *format, ...) IS_PRINTF(3); - void verror(Loc loc, const char *format, va_list ap); - void pragma(); - unsigned decodeUTF(); - void getDocComment(Token *t, unsigned lineComment); - - static int isValidIdentifier(char *p); - static unsigned char *combineComments(unsigned char *c1, unsigned char *c2); -}; - -#endif /* DMD_LEXER_H */ diff --git a/dmd2/lib.h b/dmd2/lib.h deleted file mode 100644 index abd31cb2..00000000 --- a/dmd2/lib.h +++ /dev/null @@ -1,54 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_LIB_H -#define DMD_LIB_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -struct ObjModule; - -struct ObjSymbol -{ - char *name; - ObjModule *om; -}; - -#include "arraytypes.h" - -typedef ArrayBase ObjModules; -typedef ArrayBase ObjSymbols; - -struct Library -{ - File *libfile; - ObjModules objmodules; // ObjModule[] - ObjSymbols objsymbols; // ObjSymbol[] - - StringTable tab; - - Library(); - void setFilename(char *dir, char *filename); - void addObject(const char *module_name, void *buf, size_t buflen); - void addLibrary(void *buf, size_t buflen); - void write(); - - private: - void addSymbol(ObjModule *om, char *name, int pickAny = 0); - void scanObjModule(ObjModule *om); - unsigned short numDictPages(unsigned padding); - int FillDict(unsigned char *bucketsP, unsigned short uNumPages); - void WriteLibToBuffer(OutBuffer *libbuf); -}; - -#endif /* DMD_LIB_H */ - diff --git a/dmd2/macro.c b/dmd2/macro.c deleted file mode 100644 index 398ba77f..00000000 --- a/dmd2/macro.c +++ /dev/null @@ -1,449 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -/* Simple macro text processor. - */ - -#include -#include -#include -#include -#include - -#include "rmem.h" -#include "root.h" - -#include "macro.h" - -#define isidstart(c) (isalpha(c) || (c) == '_') -#define isidchar(c) (isalnum(c) || (c) == '_') - -unsigned char *memdup(unsigned char *p, size_t len) -{ - return (unsigned char *)memcpy(mem.malloc(len), p, len); -} - -Macro::Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - next = NULL; - -#if 1 - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#else - this->name = name; - this->namelen = namelen; - - this->text = text; - this->textlen = textlen; -#endif - inuse = 0; -} - - -Macro *Macro::search(unsigned char *name, size_t namelen) -{ Macro *table; - - //printf("Macro::search(%.*s)\n", namelen, name); - for (table = this; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - //printf("\tfound %d\n", table->textlen); - break; - } - } - return table; -} - -Macro *Macro::define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen) -{ - //printf("Macro::define('%.*s' = '%.*s')\n", namelen, name, textlen, text); - - Macro *table; - - //assert(ptable); - for (table = *ptable; table; table = table->next) - { - if (table->namelen == namelen && - memcmp(table->name, name, namelen) == 0) - { - table->text = text; - table->textlen = textlen; - return table; - } - } - table = new Macro(name, namelen, text, textlen); - table->next = *ptable; - *ptable = table; - return table; -} - -/********************************************************** - * Given buffer p[0..end], extract argument marg[0..marglen]. - * Params: - * n 0: get entire argument - * 1..9: get nth argument - * -1: get 2nd through end - */ - -unsigned extractArgN(unsigned char *p, unsigned end, unsigned char **pmarg, unsigned *pmarglen, int n) -{ - /* Scan forward for matching right parenthesis. - * Nest parentheses. - * Skip over $( and $) - * Skip over "..." and '...' strings inside HTML tags. - * Skip over comments. - * Skip over previous macro insertions - * Set marglen. - */ - unsigned parens = 1; - unsigned char instring = 0; - unsigned incomment = 0; - unsigned intag = 0; - unsigned inexp = 0; - unsigned argn = 0; - - unsigned v = 0; - - Largstart: -#if 1 - // Skip first space, if any, to find the start of the macro argument - if (v < end && isspace(p[v])) - v++; -#else - // Skip past spaces to find the start of the macro argument - for (; v < end && isspace(p[v]); v++) - ; -#endif - *pmarg = p + v; - - for (; v < end; v++) - { unsigned char c = p[v]; - - switch (c) - { - case ',': - if (!inexp && !instring && !incomment && parens == 1) - { - argn++; - if (argn == 1 && n == -1) - { v++; - goto Largstart; - } - if (argn == n) - break; - if (argn + 1 == n) - { v++; - goto Largstart; - } - } - continue; - - case '(': - if (!inexp && !instring && !incomment) - parens++; - continue; - - case ')': - if (!inexp && !instring && !incomment && --parens == 0) - { - break; - } - continue; - - case '"': - case '\'': - if (!inexp && !incomment && intag) - { - if (c == instring) - instring = 0; - else if (!instring) - instring = c; - } - continue; - - case '<': - if (!inexp && !instring && !incomment) - { - if (v + 6 < end && - p[v + 1] == '!' && - p[v + 2] == '-' && - p[v + 3] == '-') - { - incomment = 1; - v += 3; - } - else if (v + 2 < end && - isalpha(p[v + 1])) - intag = 1; - } - continue; - - case '>': - if (!inexp) - intag = 0; - continue; - - case '-': - if (!inexp && - !instring && - incomment && - v + 2 < end && - p[v + 1] == '-' && - p[v + 2] == '>') - { - incomment = 0; - v += 2; - } - continue; - - case 0xFF: - if (v + 1 < end) - { - if (p[v + 1] == '{') - inexp++; - else if (p[v + 1] == '}') - inexp--; - } - continue; - - default: - continue; - } - break; - } - if (argn == 0 && n == -1) - *pmarg = p + v; - *pmarglen = p + v - *pmarg; - //printf("extractArg%d('%.*s') = '%.*s'\n", n, end, p, *pmarglen, *pmarg); - return v; -} - - -/***************************************************** - * Expand macro in place in buf. - * Only look at the text in buf from start to end. - */ - -void Macro::expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen) -{ -#if 0 - printf("Macro::expand(buf[%d..%d], arg = '%.*s')\n", start, *pend, arglen, arg); - printf("Buf is: '%.*s'\n", *pend - start, buf->data + start); -#endif - - static int nest; - if (nest > 100) // limit recursive expansion - return; - nest++; - - unsigned end = *pend; - assert(start <= end); - assert(end <= buf->offset); - - /* First pass - replace $0 - */ - arg = memdup(arg, arglen); - for (unsigned u = start; u + 1 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* Look for $0, but not $$0, and replace it with arg. - */ - if (p[u] == '$' && (isdigit(p[u + 1]) || p[u + 1] == '+')) - { - if (u > start && p[u - 1] == '$') - { // Don't expand $$0, but replace it with $0 - buf->remove(u - 1, 1); - end--; - u += 1; // now u is one past the closing '1' - continue; - } - - unsigned char c = p[u + 1]; - int n = (c == '+') ? -1 : c - '0'; - - unsigned char *marg; - unsigned marglen; - extractArgN(arg, arglen, &marg, &marglen, n); - if (marglen == 0) - { // Just remove macro invocation - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - end -= 2; - } - else if (c == '+') - { - // Replace '$+' with 'arg' - //printf("Replacing '$%c' with '%.*s'\n", p[u + 1], marglen, marg); - buf->remove(u, 2); - buf->insert(u, marg, marglen); - end += marglen - 2; - - // Scan replaced text for further expansion - unsigned mend = u + marglen; - expand(buf, u, &mend, NULL, 0); - end += mend - (u + marglen); - u = mend; - } - else - { - // Replace '$1' with '\xFF{arg\xFF}' - //printf("Replacing '$%c' with '\xFF{%.*s\xFF}'\n", p[u + 1], marglen, marg); - buf->data[u] = 0xFF; - buf->data[u + 1] = '{'; - buf->insert(u + 2, marg, marglen); - buf->insert(u + 2 + marglen, "\xFF}", 2); - end += -2 + 2 + marglen + 2; - - // Scan replaced text for further expansion - unsigned mend = u + 2 + marglen; - expand(buf, u + 2, &mend, NULL, 0); - end += mend - (u + 2 + marglen); - u = mend; - } - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end, &buf->data[0]); - continue; - } - - u++; - } - - /* Second pass - replace other macros - */ - for (unsigned u = start; u + 4 < end; ) - { - unsigned char *p = buf->data; // buf->data is not loop invariant - - /* A valid start of macro expansion is $(c, where c is - * an id start character, and not $$(c. - */ - if (p[u] == '$' && p[u + 1] == '(' && isidstart(p[u + 2])) - { - //printf("\tfound macro start '%c'\n", p[u + 2]); - unsigned char *name = p + u + 2; - unsigned namelen = 0; - - unsigned char *marg; - unsigned marglen; - - unsigned v; - /* Scan forward to find end of macro name and - * beginning of macro argument (marg). - */ - for (v = u + 2; v < end; v++) - { unsigned char c = p[v]; - - if (!isidchar(c)) - { // We've gone past the end of the macro name. - namelen = v - (u + 2); - break; - } - } - - v += extractArgN(p + v, end - v, &marg, &marglen, 0); - assert(v <= end); - - if (v < end) - { // v is on the closing ')' - if (u > start && p[u - 1] == '$') - { // Don't expand $$(NAME), but replace it with $(NAME) - buf->remove(u - 1, 1); - end--; - u = v; // now u is one past the closing ')' - continue; - } - - Macro *m = search(name, namelen); - if (m) - { -#if 0 - if (m->textlen && m->text[0] == ' ') - { m->text++; - m->textlen--; - } -#endif - if (m->inuse && marglen == 0) - { // Remove macro invocation - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - } - else if (m->inuse && arglen == marglen && memcmp(arg, marg, arglen) == 0) - { // Recursive expansion; just leave in place - - } - else - { - //printf("\tmacro '%.*s'(%.*s) = '%.*s'\n", m->namelen, m->name, marglen, marg, m->textlen, m->text); -#if 1 - marg = memdup(marg, marglen); - // Insert replacement text - buf->spread(v + 1, 2 + m->textlen + 2); - buf->data[v + 1] = 0xFF; - buf->data[v + 2] = '{'; - memcpy(buf->data + v + 3, m->text, m->textlen); - buf->data[v + 3 + m->textlen] = 0xFF; - buf->data[v + 3 + m->textlen + 1] = '}'; - - end += 2 + m->textlen + 2; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + 2+m->textlen+2; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + 2+m->textlen+2); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#else - // Insert replacement text - buf->insert(v + 1, m->text, m->textlen); - end += m->textlen; - - // Scan replaced text for further expansion - m->inuse++; - unsigned mend = v + 1 + m->textlen; - expand(buf, v + 1, &mend, marg, marglen); - end += mend - (v + 1 + m->textlen); - m->inuse--; - - buf->remove(u, v + 1 - u); - end -= v + 1 - u; - u += mend - (v + 1); -#endif - mem.free(marg); - //printf("u = %d, end = %d\n", u, end); - //printf("#%.*s#\n", end - u, &buf->data[u]); - continue; - } - } - else - { - // Replace $(NAME) with nothing - buf->remove(u, v + 1 - u); - end -= (v + 1 - u); - continue; - } - } - } - u++; - } - mem.free(arg); - *pend = end; - nest--; -} diff --git a/dmd2/macro.h b/dmd2/macro.h deleted file mode 100644 index 7c939621..00000000 --- a/dmd2/macro.h +++ /dev/null @@ -1,45 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MACRO_H -#define DMD_MACRO_H 1 - -#include -#include -#include -#include - -#include "root.h" - - -struct Macro -{ - private: - Macro *next; // next in list - - unsigned char *name; // macro name - size_t namelen; // length of macro name - - unsigned char *text; // macro replacement text - size_t textlen; // length of replacement text - - int inuse; // macro is in use (don't expand) - - Macro(unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - Macro *search(unsigned char *name, size_t namelen); - - public: - static Macro *define(Macro **ptable, unsigned char *name, size_t namelen, unsigned char *text, size_t textlen); - - void expand(OutBuffer *buf, unsigned start, unsigned *pend, - unsigned char *arg, unsigned arglen); -}; - -#endif diff --git a/dmd2/mangle.c b/dmd2/mangle.c deleted file mode 100644 index 0c19040c..00000000 --- a/dmd2/mangle.c +++ /dev/null @@ -1,303 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#include "root.h" - -#include "init.h" -#include "declaration.h" -#include "aggregate.h" -#include "mtype.h" -#include "attrib.h" -#include "template.h" -#include "id.h" -#include "module.h" - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -char *cpp_mangle(Dsymbol *s); -#endif - -char *mangle(Declaration *sthis) -{ - OutBuffer buf; - char *id; - Dsymbol *s; - - //printf("::mangle(%s)\n", sthis->toChars()); - s = sthis; - do - { - //printf("mangle: s = %p, '%s', parent = %p\n", s, s->toChars(), s->parent); - if (s->ident) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (s != sthis && fd) - { - id = mangle(fd); - buf.prependstring(id); - goto L1; - } - else - { - id = s->ident->toChars(); - int len = strlen(id); - char tmp[sizeof(len) * 3 + 1]; - buf.prependstring(id); - sprintf(tmp, "%d", len); - buf.prependstring(tmp); - } - } - else - buf.prependstring("0"); - s = s->parent; - } while (s); - -// buf.prependstring("_D"); -L1: - //printf("deco = '%s'\n", sthis->type->deco ? sthis->type->deco : "null"); - //printf("sthis->type = %s\n", sthis->type->toChars()); - FuncDeclaration *fd = sthis->isFuncDeclaration(); - if (fd && (fd->needThis() || fd->isNested())) - buf.writeByte(Type::needThisPrefix()); - if (sthis->type->deco) - buf.writestring(sthis->type->deco); - else - { -#ifdef DEBUG - if (!fd->inferRetType) - printf("%s\n", fd->toChars()); -#endif - assert(fd && fd->inferRetType); - } - - id = buf.toChars(); - buf.data = NULL; - return id; -} - -char *Declaration::mangle() -#if __DMC__ - __out(result) - { - int len = strlen(result); - - assert(len > 0); - //printf("mangle: '%s' => '%s'\n", toChars(), result); - for (int i = 0; i < len; i++) - { - assert(result[i] == '_' || - result[i] == '@' || - isalnum(result[i]) || result[i] & 0x80); - } - } - __body -#endif - { - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d)\n", this, toChars(), parent ? parent->toChars() : "null", linkage); - if (!parent || parent->isModule() || linkage == LINKcpp) // if at global scope - { - // If it's not a D declaration, no mangling - switch (linkage) - { - case LINKd: - break; - -#if IN_LLVM - case LINKintrinsic: -#endif - case LINKc: - case LINKwindows: - case LINKpascal: - return ident->toChars(); - - case LINKcpp: -#if CPP_MANGLE - return cpp_mangle(this); -#else - // Windows C++ mangling is done by C++ back end - return ident->toChars(); -#endif - - case LINKdefault: - error("forward declaration"); - return ident->toChars(); - - default: - fprintf(stdmsg, "'%s', linkage = %d\n", toChars(), linkage); - assert(0); - } - } - char *p = ::mangle(this); - OutBuffer buf; - buf.writestring("_D"); - buf.writestring(p); - p = buf.toChars(); - buf.data = NULL; - //printf("Declaration::mangle(this = %p, '%s', parent = '%s', linkage = %d) = %s\n", this, toChars(), parent ? parent->toChars() : "null", linkage, p); - return p; - } - -char *FuncDeclaration::mangle() -#if __DMC__ - __out(result) - { - assert(strlen(result) > 0); - } - __body -#endif - { - if (isMain()) - return (char *)"_Dmain"; - - if (isWinMain() || isDllMain() || ident == Id::tls_get_addr) - return ident->toChars(); - - assert(this); - return Declaration::mangle(); - } - -char *StructDeclaration::mangle() -{ - //printf("StructDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *TypedefDeclaration::mangle() -{ - //printf("TypedefDeclaration::mangle() '%s'\n", toChars()); - return Dsymbol::mangle(); -} - - -char *ClassDeclaration::mangle() -{ - Dsymbol *parentsave = parent; - - //printf("ClassDeclaration::mangle() %s.%s\n", parent->toChars(), toChars()); - - /* These are reserved to the compiler, so keep simple - * names for them. - */ - if (ident == Id::Exception) - { if (parent->ident == Id::object) - parent = NULL; - } - else if (ident == Id::TypeInfo || -// ident == Id::Exception || - ident == Id::TypeInfo_Struct || - ident == Id::TypeInfo_Class || - ident == Id::TypeInfo_Typedef || - ident == Id::TypeInfo_Tuple || - this == object || - this == classinfo || -#if !MODULEINFO_IS_STRUCT - this == Module::moduleinfo || -#endif - memcmp(ident->toChars(), "TypeInfo_", 9) == 0 - ) - parent = NULL; - - char *id = Dsymbol::mangle(); - parent = parentsave; - return id; -} - - -char *TemplateInstance::mangle() -{ - OutBuffer buf; - -#if 0 - printf("TemplateInstance::mangle() %p %s", this, toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - char *id = ident ? ident->toChars() : toChars(); - if (!tempdecl) - error("is not defined"); - else - { - Dsymbol *par = isnested || isTemplateMixin() ? parent : tempdecl->parent; - if (par) - { - char *p = par->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateInstance::mangle() %s = %s\n", toChars(), id); - return id; -} - -#if IN_LLVM -char *TemplateMixin::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("TemplateMixin::mangle() %s", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("TemplateMixin::mangle() %s = %s\n", toChars(), id); - return id; -} -#endif - -char *Dsymbol::mangle() -{ - OutBuffer buf; - char *id; - -#if 0 - printf("Dsymbol::mangle() '%s'", toChars()); - if (parent) - printf(" parent = %s %s", parent->kind(), parent->toChars()); - printf("\n"); -#endif - id = ident ? ident->toChars() : toChars(); - if (parent) - { - char *p = parent->mangle(); - if (p[0] == '_' && p[1] == 'D') - p += 2; - buf.writestring(p); - } - buf.printf("%zu%s", strlen(id), id); - id = buf.toChars(); - buf.data = NULL; - //printf("Dsymbol::mangle() %s = %s\n", toChars(), id); - return id; -} - - diff --git a/dmd2/mars.c b/dmd2/mars.c deleted file mode 100644 index f80250e6..00000000 --- a/dmd2/mars.c +++ /dev/null @@ -1,1605 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// https://github.com/D-Programming-Language/dmd/blob/master/src/mars.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include -#include -#include - -#if POSIX -#include -#endif - -#include "rmem.h" -#include "root.h" -#if !IN_LLVM -#include "async.h" -#endif - -#include "mars.h" -#include "module.h" -#include "mtype.h" -#include "id.h" -#include "cond.h" -#include "expression.h" -#include "lexer.h" -#if !IN_LLVM -#include "lib.h" -#include "json.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - - -int response_expand(int *pargc, char ***pargv); -void browse(const char *url); -void getenv_setargv(const char *envvar, int *pargc, char** *pargv); - -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); -#endif - -void printCtfePerformanceStats(); - -Global global; - -Global::Global() -{ - mars_ext = "d"; - sym_ext = "d"; - hdr_ext = "di"; - doc_ext = "html"; - ddoc_ext = "ddoc"; - json_ext = "json"; - map_ext = "map"; - -#if IN_LLVM - ll_ext = "ll"; - bc_ext = "bc"; - s_ext = "s"; - obj_ext = "o"; -#if _WIN32 - obj_ext_alt = "obj"; -#endif -#else -#if TARGET_WINDOS - obj_ext = "obj"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - obj_ext = "o"; -#elif TARGET_NET -#else -#error "fix this" -#endif - -#if TARGET_WINDOS - lib_ext = "lib"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - lib_ext = "a"; -#elif TARGET_NET -#else -#error "fix this" -#endif -#endif - - copyright = "Copyright (c) 1999-2012 by Digital Mars"; - written = "written by Walter Bright" -#if TARGET_NET - "\nMSIL back-end (alpha release) by Cristian L. Vlasceanu and associates."; -#endif - ; - version = "v2.058"; -#if IN_LLVM - ldc_version = "LDC trunk"; - llvm_version = "LLVM 3.0"; -#endif - global.structalign = 8; - - // This should only be used as a global, so the other fields are - // automatically initialized to zero when the program is loaded. - // In particular, DO NOT zero-initialize .params here (like DMD - // does) because command-line options initialize some of those - // fields to non-zero defaults, and do so from constructors that - // may run before this one. -} - -unsigned Global::startGagging() -{ - ++gag; - return gaggedErrors; -} - -bool Global::endGagging(unsigned oldGagged) -{ - bool anyErrs = (gaggedErrors != oldGagged); - --gag; - // Restore the original state of gagged errors; set total errors - // to be original errors + new ungagged errors. - errors -= (gaggedErrors - oldGagged); - gaggedErrors = oldGagged; - return anyErrs; -} - - -char *Loc::toChars() -{ - OutBuffer buf; - - if (filename) - { - buf.printf("%s", filename); - } - - if (linnum) - buf.printf("(%d)", linnum); - buf.writeByte(0); - return (char *)buf.extractData(); -} - -Loc::Loc(Module *mod, unsigned linnum) -{ - this->linnum = linnum; - this->filename = mod ? mod->srcfile->toChars() : NULL; -} - -bool Loc::equals(const Loc& loc) -{ - return linnum == loc.linnum && FileName::equals(filename, loc.filename); -} - -/************************************** - * Print error message - */ - -void error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verror(loc, format, ap); - va_end( ap ); -} - -void warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vwarning(loc, format, ap); - va_end( ap ); -} - -/************************************** - * Print supplementary message about the last error - * Used for backtraces, etc - */ -void errorSupplemental(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - verrorSupplemental(loc, format, ap); - va_end( ap ); -} - -void verror(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Error: "); - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); -#if _MSC_VER - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - } - else - { - global.gaggedErrors++; - } - global.errors++; -} - -// Doesn't increase error count, doesn't print "Error:". -void verrorSupplemental(Loc loc, const char *format, va_list ap) -{ - if (!global.gag) - { - fprintf(stdmsg, "%s: ", loc.toChars()); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); - } -} - -void vwarning(Loc loc, const char *format, va_list ap) -{ - if (global.params.warnings && !global.gag) - { - char *p = loc.toChars(); - - if (*p) - fprintf(stdmsg, "%s: ", p); - mem.free(p); - - fprintf(stdmsg, "Warning: "); -#if _MSC_VER - // MS doesn't recognize %zu format - OutBuffer tmp; - tmp.vprintf(format, ap); - fprintf(stdmsg, "%s", tmp.toChars()); -#else - vfprintf(stdmsg, format, ap); -#endif - fprintf(stdmsg, "\n"); - fflush(stdmsg); -//halt(); - if (global.params.warnings == 1) - global.warnings++; // warnings don't count if gagged - } -} - -/*************************************** - * Call this after printing out fatal error messages to clean up and exit - * the compiler. - */ - -void fatal() -{ -#if 0 - halt(); -#endif - exit(EXIT_FAILURE); -} - -/************************************** - * Try to stop forgetting to remove the breakpoints from - * release builds. - */ -void halt() -{ -#ifdef DEBUG - *(volatile char*)0=0; -#endif -} - -#if !IN_LLVM - -extern void backend_init(); -extern void backend_term(); - -void usage() -{ -#if TARGET_LINUX - const char fpic[] ="\ - -fPIC generate position independent code\n\ -"; -#else - const char fpic[] = ""; -#endif - printf("DMD%s D Compiler %s\n%s %s\n", - sizeof(size_t) == 4 ? "32" : "64", - global.version, global.copyright, global.written); - printf("\ -Documentation: http://www.dlang.org/index.html\n\ -Usage:\n\ - dmd files.d ... { -switch }\n\ -\n\ - files.d D source files\n\ - @cmdfile read arguments from cmdfile\n\ - -c do not link\n\ - -cov do code coverage analysis\n\ - -D generate documentation\n\ - -Dddocdir write documentation file to docdir directory\n\ - -Dffilename write documentation file to filename\n\ - -d allow deprecated features\n\ - -debug compile in debug code\n\ - -debug=level compile in debug code <= level\n\ - -debug=ident compile in debug code identified by ident\n\ - -debuglib=name set symbolic debug library to name\n\ - -defaultlib=name set default library to name\n\ - -deps=filename write module dependencies to filename\n%s" -" -g add symbolic debug info\n\ - -gc add symbolic debug info, pretend to be C\n\ - -gs always emit stack frame\n\ - -H generate 'header' file\n\ - -Hddirectory write 'header' file to directory\n\ - -Hffilename write 'header' file to filename\n\ - --help print help\n\ - -Ipath where to look for imports\n\ - -ignore ignore unsupported pragmas\n\ - -inline do function inlining\n\ - -Jpath where to look for string imports\n\ - -Llinkerflag pass linkerflag to link\n\ - -lib generate library rather than object files\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -m32 generate 32 bit code\n\ - -m64 generate 64 bit code\n" -#endif -" -man open web browser on manual page\n\ - -map generate linker .map file\n\ - -noboundscheck turns off array bounds checking for all functions\n\ - -nofloat do not emit reference to floating point\n\ - -O optimize\n\ - -o- do not write object file\n\ - -odobjdir write object & library files to directory objdir\n\ - -offilename name output file to filename\n\ - -op do not strip paths from source file\n\ - -profile profile runtime performance of generated code\n\ - -property enforce property syntax\n\ - -quiet suppress unnecessary messages\n\ - -release compile release version\n\ - -run srcfile args... run resulting program, passing args\n" -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -" -shared generate shared library\n" -#endif -" -unittest compile in unit tests\n\ - -v verbose\n\ - -version=level compile in version code >= level\n\ - -version=ident compile in version code identified by ident\n\ - -vtls list all variables going into thread local storage\n\ - -w enable warnings\n\ - -wi enable informational warnings\n\ - -X generate JSON file\n\ - -Xffilename write JSON file to filename\n\ -", fpic); -} - -extern signed char tyalignsize[]; - -#if _WIN32 -extern "C" -{ - extern int _xi_a; - extern int _end; -} -#endif - -int main(int argc, char *argv[]) -{ - mem.init(); // initialize storage allocator - mem.setStackBottom(&argv); -#if _WIN32 - mem.addroots((char *)&_xi_a, (char *)&_end); -#endif - - Strings files; - Strings libmodules; - char *p; - Module *m; - int status = EXIT_SUCCESS; - int argcstart = argc; - int setdebuglib = 0; - char noboundscheck = 0; - const char *inifilename = NULL; - -#ifdef DEBUG - printf("DMD %s DEBUG\n", global.version); -#endif - - unittests(); - - // Check for malformed input - if (argc < 1 || !argv) - { - Largs: - error("missing or null command line arguments"); - fatal(); - } - for (size_t i = 0; i < argc; i++) - { - if (!argv[i]) - goto Largs; - } - - if (response_expand(&argc,&argv)) // expand response files - error("can't open response file"); - - files.reserve(argc - 1); - - // Set default values - global.params.argv0 = argv[0]; - global.params.link = 1; - global.params.useAssert = 1; - global.params.useInvariants = 1; - global.params.useIn = 1; - global.params.useOut = 1; - global.params.useArrayBounds = 2; // default to all functions - global.params.useSwitchError = 1; - global.params.useInline = 0; - global.params.obj = 1; - global.params.Dversion = 2; - global.params.quiet = 1; - - global.params.linkswitches = new Strings(); - global.params.libfiles = new Strings(); - global.params.objfiles = new Strings(); - global.params.ddocfiles = new Strings(); - - // Default to -m32 for 32 bit dmd, -m64 for 64 bit dmd - global.params.is64bit = (sizeof(size_t) == 8); - -#if TARGET_WINDOS - global.params.defaultlibname = "phobos"; -#elif TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - global.params.defaultlibname = "phobos2"; -#elif TARGET_NET -#else -#error "fix this" -#endif - - // Predefine version identifiers - VersionCondition::addPredefinedGlobalIdent("DigitalMars"); - -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Windows"); - global.params.isWindows = 1; -#if TARGET_NET - // TARGET_NET macro is NOT mutually-exclusive with TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("D_NET"); -#endif -#elif TARGET_LINUX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("linux"); - global.params.isLinux = 1; -#elif TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OSX"); - global.params.isOSX = 1; - - // For legacy compatibility - VersionCondition::addPredefinedGlobalIdent("darwin"); -#elif TARGET_FREEBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("FreeBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_OPENBSD - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("OpenBSD"); - global.params.isFreeBSD = 1; -#elif TARGET_SOLARIS - VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("Solaris"); - global.params.isSolaris = 1; -#else -#error "fix this" -#endif - - VersionCondition::addPredefinedGlobalIdent("LittleEndian"); - //VersionCondition::addPredefinedGlobalIdent("D_Bits"); -#if DMDV2 - VersionCondition::addPredefinedGlobalIdent("D_Version2"); -#endif - VersionCondition::addPredefinedGlobalIdent("all"); - -#if _WIN32 - inifilename = inifile(argv[0], "sc.ini"); -#elif linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - inifilename = inifile(argv[0], "dmd.conf"); -#else -#error "fix this" -#endif - getenv_setargv("DFLAGS", &argc, &argv); - -#if 0 - for (size_t i = 0; i < argc; i++) - { - printf("argv[%d] = '%s'\n", i, argv[i]); - } -#endif - - for (size_t i = 1; i < argc; i++) - { - p = argv[i]; - if (*p == '-') - { - if (strcmp(p + 1, "d") == 0) - global.params.useDeprecated = 1; - else if (strcmp(p + 1, "c") == 0) - global.params.link = 0; - else if (strcmp(p + 1, "cov") == 0) - global.params.cov = 1; -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - else if (strcmp(p + 1, "shared") == 0 -#if TARGET_OSX - // backwards compatibility with old switch - || strcmp(p + 1, "dylib") == 0 -#endif - ) - global.params.dll = 1; - else if (strcmp(p + 1, "fPIC") == 0) - global.params.pic = 1; -#endif - else if (strcmp(p + 1, "map") == 0) - global.params.map = 1; - else if (strcmp(p + 1, "multiobj") == 0) - global.params.multiobj = 1; - else if (strcmp(p + 1, "g") == 0) - global.params.symdebug = 1; - else if (strcmp(p + 1, "gc") == 0) - global.params.symdebug = 2; - else if (strcmp(p + 1, "gs") == 0) - global.params.alwaysframe = 1; - else if (strcmp(p + 1, "gt") == 0) - { error("use -profile instead of -gt\n"); - global.params.trace = 1; - } - else if (strcmp(p + 1, "m32") == 0) - global.params.is64bit = 0; - else if (strcmp(p + 1, "m64") == 0) - global.params.is64bit = 1; - else if (strcmp(p + 1, "profile") == 0) - global.params.trace = 1; - else if (strcmp(p + 1, "v") == 0) - global.params.verbose = 1; -#if DMDV2 - else if (strcmp(p + 1, "vtls") == 0) - global.params.vtls = 1; -#endif - else if (strcmp(p + 1, "v1") == 0) - { -#if DMDV1 - global.params.Dversion = 1; -#else - error("use DMD 1.0 series compilers for -v1 switch"); - break; -#endif - } - else if (strcmp(p + 1, "w") == 0) - global.params.warnings = 1; - else if (strcmp(p + 1, "wi") == 0) - global.params.warnings = 2; - else if (strcmp(p + 1, "O") == 0) - global.params.optimize = 1; - else if (p[1] == 'o') - { - switch (p[2]) - { - case '-': - global.params.obj = 0; - break; - - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.objdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.objname = p + 3; - break; - - case 'p': - if (p[3]) - goto Lerror; - global.params.preservePaths = 1; - break; - - case 0: - error("-o no longer supported, use -of or -od"); - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'D') - { global.params.doDocComments = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.docdir = p + 3; - break; - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.docname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'H') - { global.params.doHdrGeneration = 1; - switch (p[2]) - { - case 'd': - if (!p[3]) - goto Lnoarg; - global.params.hdrdir = p + 3; - break; - - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.hdrname = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (p[1] == 'X') - { global.params.doXGeneration = 1; - switch (p[2]) - { - case 'f': - if (!p[3]) - goto Lnoarg; - global.params.xfilename = p + 3; - break; - - case 0: - break; - - default: - goto Lerror; - } - } - else if (strcmp(p + 1, "ignore") == 0) - global.params.ignoreUnsupportedPragmas = 1; - else if (strcmp(p + 1, "property") == 0) - global.params.enforcePropertySyntax = 1; - else if (strcmp(p + 1, "inline") == 0) - global.params.useInline = 1; - else if (strcmp(p + 1, "lib") == 0) - global.params.lib = 1; - else if (strcmp(p + 1, "nofloat") == 0) - global.params.nofloat = 1; - else if (strcmp(p + 1, "quiet") == 0) - global.params.quiet = 1; - else if (strcmp(p + 1, "release") == 0) - global.params.release = 1; -#if DMDV2 - else if (strcmp(p + 1, "noboundscheck") == 0) - noboundscheck = 1; -#endif - else if (strcmp(p + 1, "unittest") == 0) - global.params.useUnitTests = 1; - else if (p[1] == 'I') - { - if (!global.params.imppath) - global.params.imppath = new Strings(); - global.params.imppath->push(p + 2); - } - else if (p[1] == 'J') - { - if (!global.params.fileImppath) - global.params.fileImppath = new Strings(); - global.params.fileImppath->push(p + 2); - } - else if (memcmp(p + 1, "debug", 5) == 0 && p[6] != 'l') - { - // Parse: - // -debug - // -debug=number - // -debug=identifier - if (p[6] == '=') - { - if (isdigit((unsigned char)p[7])) - { long level; - - errno = 0; - level = strtol(p + 7, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - DebugCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 7)) - DebugCondition::addGlobalIdent(p + 7); - else - goto Lerror; - } - else if (p[6]) - goto Lerror; - else - global.params.debuglevel = 1; - } - else if (memcmp(p + 1, "version", 5) == 0) - { - // Parse: - // -version=number - // -version=identifier - if (p[8] == '=') - { - if (isdigit((unsigned char)p[9])) - { long level; - - errno = 0; - level = strtol(p + 9, &p, 10); - if (*p || errno || level > INT_MAX) - goto Lerror; - VersionCondition::setGlobalLevel((int)level); - } - else if (Lexer::isValidIdentifier(p + 9)) - VersionCondition::addGlobalIdent(p + 9); - else - goto Lerror; - } - else - goto Lerror; - } - else if (strcmp(p + 1, "-b") == 0) - global.params.debugb = 1; - else if (strcmp(p + 1, "-c") == 0) - global.params.debugc = 1; - else if (strcmp(p + 1, "-f") == 0) - global.params.debugf = 1; - else if (strcmp(p + 1, "-help") == 0) - { usage(); - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "-r") == 0) - global.params.debugr = 1; - else if (strcmp(p + 1, "-x") == 0) - global.params.debugx = 1; - else if (strcmp(p + 1, "-y") == 0) - global.params.debugy = 1; - else if (p[1] == 'L') - { - global.params.linkswitches->push(p + 2); - } - else if (memcmp(p + 1, "defaultlib=", 11) == 0) - { - global.params.defaultlibname = p + 1 + 11; - } - else if (memcmp(p + 1, "debuglib=", 9) == 0) - { - setdebuglib = 1; - global.params.debuglibname = p + 1 + 9; - } - else if (memcmp(p + 1, "deps=", 5) == 0) - { - global.params.moduleDepsFile = p + 1 + 5; - if (!global.params.moduleDepsFile[0]) - goto Lnoarg; - global.params.moduleDeps = new OutBuffer; - } - else if (memcmp(p + 1, "man", 3) == 0) - { -#if _WIN32 -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-windows.html"); -#else - browse("http://www.dlang.org/dmd-windows.html"); -#endif -#endif -#if linux -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-linux.html"); -#else - browse("http://www.dlang.org/dmd-linux.html"); -#endif -#endif -#if __APPLE__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-osx.html"); -#else - browse("http://www.dlang.org/dmd-osx.html"); -#endif -#endif -#if __FreeBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-freebsd.html"); -#else - browse("http://www.dlang.org/dmd-freebsd.html"); -#endif -#endif -#if __OpenBSD__ -#if DMDV1 - browse("http://www.digitalmars.com/d/1.0/dmd-openbsd.html"); -#else - browse("http://www.dlang.org/dmd-openbsd.html"); -#endif -#endif - exit(EXIT_SUCCESS); - } - else if (strcmp(p + 1, "run") == 0) - { global.params.run = 1; - global.params.runargs_length = ((i >= argcstart) ? argc : argcstart) - i - 1; - if (global.params.runargs_length) - { - files.push(argv[i + 1]); - global.params.runargs = &argv[i + 2]; - i += global.params.runargs_length; - global.params.runargs_length--; - } - else - { global.params.run = 0; - goto Lnoarg; - } - } - else - { - Lerror: - error("unrecognized switch '%s'", argv[i]); - continue; - - Lnoarg: - error("argument expected for switch '%s'", argv[i]); - continue; - } - } - else - { -#if TARGET_WINDOS - char *ext = FileName::ext(p); - if (ext && FileName::compare(ext, "exe") == 0) - { - global.params.objname = p; - continue; - } -#endif - files.push(p); - } - } - if (global.errors) - { - fatal(); - } - if (files.dim == 0) - { usage(); - return EXIT_FAILURE; - } - - if (!setdebuglib) - global.params.debuglibname = global.params.defaultlibname; - -#if TARGET_OSX - global.params.pic = 1; -#endif - -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - if (global.params.lib && global.params.dll) - error("cannot mix -lib and -shared\n"); -#endif - - if (global.params.release) - { global.params.useInvariants = 0; - global.params.useIn = 0; - global.params.useOut = 0; - global.params.useAssert = 0; - global.params.useArrayBounds = 1; - global.params.useSwitchError = 0; - } - if (noboundscheck) - global.params.useArrayBounds = 0; - - if (global.params.run) - global.params.quiet = 1; - - if (global.params.useUnitTests) - global.params.useAssert = 1; - - if (!global.params.obj || global.params.lib) - global.params.link = 0; - - if (global.params.link) - { - global.params.exefile = global.params.objname; - global.params.oneobj = 1; - if (global.params.objname) - { - /* Use this to name the one object file with the same - * name as the exe file. - */ - global.params.objname = FileName::forceExt(global.params.objname, global.obj_ext)->toChars(); - - /* If output directory is given, use that path rather than - * the exe file path. - */ - if (global.params.objdir) - { char *name = FileName::name(global.params.objname); - global.params.objname = FileName::combine(global.params.objdir, name); - } - } - } - else if (global.params.lib) - { - global.params.libname = global.params.objname; - global.params.objname = NULL; - - // Haven't investigated handling these options with multiobj - if (!global.params.cov && !global.params.trace -#if 0 && TARGET_WINDOS - /* multiobj causes class/struct debug info to be attached to init-data, - * but this will not be linked into the executable, so this info is lost. - * Bugzilla 4014 - */ - && !global.params.symdebug -#endif - ) - global.params.multiobj = 1; - } - else if (global.params.run) - { - error("flags conflict with -run"); - fatal(); - } - else - { - if (global.params.objname && files.dim > 1) - { - global.params.oneobj = 1; - //error("multiple source files, but only one .obj name"); - //fatal(); - } - } - if (global.params.is64bit) - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86_64"); - VersionCondition::addPredefinedGlobalIdent("X86_64"); - VersionCondition::addPredefinedGlobalIdent("D_LP64"); - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win64"); -#endif - } - else - { - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm"); - VersionCondition::addPredefinedGlobalIdent("D_InlineAsm_X86"); - VersionCondition::addPredefinedGlobalIdent("X86"); -#if TARGET_OSX - VersionCondition::addPredefinedGlobalIdent("D_SIMD"); -#endif -#if TARGET_WINDOS - VersionCondition::addPredefinedGlobalIdent("Win32"); -#endif - } - if (global.params.doDocComments) - VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); - if (global.params.cov) - VersionCondition::addPredefinedGlobalIdent("D_Coverage"); - if (global.params.pic) - VersionCondition::addPredefinedGlobalIdent("D_PIC"); -#if DMDV2 - if (global.params.useUnitTests) - VersionCondition::addPredefinedGlobalIdent("unittest"); -#endif - - // Initialization - Type::init(); - Id::initialize(); - Module::init(); - initPrecedence(); - - if (global.params.verbose) - { printf("binary %s\n", argv[0]); - printf("version %s\n", global.version); - printf("config %s\n", inifilename ? inifilename : "(none)"); - } - - //printf("%d source files\n",files.dim); - - // Build import search path - if (global.params.imppath) - { - for (size_t i = 0; i < global.params.imppath->dim; i++) - { - char *path = (*global.params.imppath)[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.path) - global.path = new Strings(); - global.path->append(a); - } - } - } - - // Build string import search path - if (global.params.fileImppath) - { - for (size_t i = 0; i < global.params.fileImppath->dim; i++) - { - char *path = global.params.fileImppath->tdata()[i]; - Strings *a = FileName::splitPath(path); - - if (a) - { - if (!global.filePath) - global.filePath = new Strings(); - global.filePath->append(a); - } - } - } - - // Create Modules - Modules modules; - modules.reserve(files.dim); - int firstmodule = 1; - for (size_t i = 0; i < files.dim; i++) - { - char *ext; - char *name; - - p = files.tdata()[i]; - -#if _WIN32 - // Convert / to \ so linker will work - for (size_t i = 0; p[i]; i++) - { - if (p[i] == '/') - p[i] = '\\'; - } -#endif - - p = FileName::name(p); // strip path - ext = FileName::ext(p); - if (ext) - { /* Deduce what to do with a file based on its extension - */ - if (FileName::equals(ext, global.obj_ext)) - { - global.params.objfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.lib_ext)) - { - global.params.libfiles->push(files.tdata()[i]); - libmodules.push(files.tdata()[i]); - continue; - } - - if (strcmp(ext, global.ddoc_ext) == 0) - { - global.params.ddocfiles->push(files.tdata()[i]); - continue; - } - - if (FileName::equals(ext, global.json_ext)) - { - global.params.doXGeneration = 1; - global.params.xfilename = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, global.map_ext)) - { - global.params.mapfile = files.tdata()[i]; - continue; - } - -#if TARGET_WINDOS - if (FileName::equals(ext, "res")) - { - global.params.resfile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "def")) - { - global.params.deffile = files.tdata()[i]; - continue; - } - - if (FileName::equals(ext, "exe")) - { - assert(0); // should have already been handled - } -#endif - - /* Examine extension to see if it is a valid - * D source file extension - */ - if (FileName::equals(ext, global.mars_ext) || - FileName::equals(ext, global.hdr_ext) || - FileName::equals(ext, "dd") || - FileName::equals(ext, "htm") || - FileName::equals(ext, "html") || - FileName::equals(ext, "xhtml")) - { - ext--; // skip onto '.' - assert(*ext == '.'); - name = (char *)mem.malloc((ext - p) + 1); - memcpy(name, p, ext - p); - name[ext - p] = 0; // strip extension - - if (name[0] == 0 || - strcmp(name, "..") == 0 || - strcmp(name, ".") == 0) - { - Linvalid: - error("invalid file name '%s'", files.tdata()[i]); - fatal(); - } - } - else - { error("unrecognized file extension %s\n", ext); - fatal(); - } - } - else - { name = p; - if (!*name) - goto Linvalid; - } - - /* At this point, name is the D source file name stripped of - * its path and extension. - */ - - Identifier *id = Lexer::idPool(name); - m = new Module(files[i], id, global.params.doDocComments, global.params.doHdrGeneration); - modules.push(m); - - if (firstmodule) - { global.params.objfiles->push(m->objfile->name->str); - firstmodule = 0; - } - } - -#if WINDOWS_SEH - __try - { -#endif - // Read files -#define ASYNCREAD 1 -#if ASYNCREAD - // Multi threaded - AsyncRead *aw = AsyncRead::create(modules.dim); - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - aw->addFile(m->srcfile); - } - aw->start(); -#else - // Single threaded - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - m->read(0); - } -#endif - - // Parse files - bool anydocfiles = false; - size_t filecount = modules.dim; - for (size_t filei = 0, modi = 0; filei < filecount; filei++, modi++) - { - m = modules[modi]; - if (global.params.verbose) - printf("parse %s\n", m->toChars()); - if (!Module::rootModule) - Module::rootModule = m; - m->importedFrom = m; - if (!global.params.oneobj || modi == 0 || m->isDocFile) - m->deleteObjFile(); -#if ASYNCREAD - if (aw->read(filei)) - { - error("cannot read file %s", m->srcfile->name->toChars()); - } -#endif - m->parse(); - if (m->isDocFile) - { - anydocfiles = true; - m->gendocfile(); - - // Remove m from list of modules - modules.remove(modi); - modi--; - - // Remove m's object file from list of object files - for (size_t j = 0; j < global.params.objfiles->dim; j++) - { - if (m->objfile->name->str == global.params.objfiles->tdata()[j]) - { - global.params.objfiles->remove(j); - break; - } - } - - if (global.params.objfiles->dim == 0) - global.params.link = 0; - } - } -#if ASYNCREAD - AsyncRead::dispose(aw); -#endif - - if (anydocfiles && modules.dim && - (global.params.oneobj || global.params.objname)) - { - error("conflicting Ddoc and obj generation options"); - fatal(); - } - if (global.errors) - fatal(); - if (global.params.doHdrGeneration) - { - /* Generate 'header' import files. - * Since 'header' import files must be independent of command - * line switches and what else is imported, they are generated - * before any semantic analysis. - */ - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("import %s\n", m->toChars()); - m->genhdrfile(); - } - } - if (global.errors) - fatal(); - - // load all unconditional imports for better symbol resolving - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("importall %s\n", m->toChars()); - m->importAll(0); - } - if (global.errors) - fatal(); - - backend_init(); - - // Do semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic %s\n", m->toChars()); - m->semantic(); - } - if (global.errors) - fatal(); - - Module::dprogress = 1; - Module::runDeferredSemantic(); - - // Do pass 2 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic2 %s\n", m->toChars()); - m->semantic2(); - } - if (global.errors) - fatal(); - - // Do pass 3 semantic analysis - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - - if (global.params.moduleDeps != NULL) - { - assert(global.params.moduleDepsFile != NULL); - - File deps(global.params.moduleDepsFile); - OutBuffer* ob = global.params.moduleDeps; - deps.setbuffer((void*)ob->data, ob->offset); - deps.writev(); - } - - - // Scan for functions to inline - if (global.params.useInline) - { - /* The problem with useArrayBounds and useAssert is that the - * module being linked to may not have generated them, so if - * we inline functions from those modules, the symbols for them will - * not be found at link time. - */ - if (!global.params.useArrayBounds && !global.params.useAssert) - { - // Do pass 3 semantic analysis on all imported modules, - // since otherwise functions in them cannot be inlined - for (size_t i = 0; i < Module::amodules.dim; i++) - { - m = Module::amodules[i]; - if (global.params.verbose) - printf("semantic3 %s\n", m->toChars()); - m->semantic3(); - } - if (global.errors) - fatal(); - } - - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("inline scan %s\n", m->toChars()); - m->inlineScan(); - } - } - - // Do not attempt to generate output files if errors or warnings occurred - if (global.errors || global.warnings) - fatal(); - - printCtfePerformanceStats(); - - Library *library = NULL; - if (global.params.lib) - { - library = new Library(); - library->setFilename(global.params.objdir, global.params.libname); - - // Add input object and input library files to output library - for (size_t i = 0; i < libmodules.dim; i++) - { - char *p = libmodules[i]; - library->addObject(p, NULL, 0); - } - } - - // Generate output files - - if (global.params.doXGeneration) - json_generate(&modules); - - if (global.params.oneobj) - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (i == 0) - obj_start(m->srcfile->toChars()); - m->genobjfile(0); - if (!global.errors && global.params.doDocComments) - m->gendocfile(); - } - if (!global.errors && modules.dim) - { - obj_end(library, modules.tdata()[0]->objfile); - } - } - else - { - for (size_t i = 0; i < modules.dim; i++) - { - m = modules[i]; - if (global.params.verbose) - printf("code %s\n", m->toChars()); - if (global.params.obj) - { obj_start(m->srcfile->toChars()); - m->genobjfile(global.params.multiobj); - obj_end(library, m->objfile); - obj_write_deferred(library); - } - if (global.errors) - { - if (!global.params.lib) - m->deleteObjFile(); - } - else - { - if (global.params.doDocComments) - m->gendocfile(); - } - } - } - - if (global.params.lib && !global.errors) - library->write(); - -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - printf("Stack overflow\n"); - fatal(); - } -#endif - backend_term(); - if (global.errors) - fatal(); - - if (!global.params.objfiles->dim) - { - if (global.params.link) - error("no object files to link"); - } - else - { - if (global.params.link) - status = runLINK(); - - if (global.params.run) - { - if (!status) - { - status = runProgram(); - - /* Delete .obj files and .exe file - */ - for (size_t i = 0; i < modules.dim; i++) - { - Module *m = modules[i]; - m->deleteObjFile(); - if (global.params.oneobj) - break; - } - deleteExeFile(); - } - } - } - - return status; -} - -#endif // !IN_LLVM - -/*********************************** - * Parse and append contents of environment variable envvar - * to argc and argv[]. - * The string is separated into arguments, processing \ and ". - */ - -void getenv_setargv(const char *envvar, int *pargc, char** *pargv) -{ - char *p; - - int instring; - int slash; - char c; - - char *env = getenv(envvar); - if (!env) - return; - - env = mem.strdup(env); // create our own writable copy - - int argc = *pargc; - Strings *argv = new Strings(); - argv->setDim(argc); - - int argc_left = 0; - for (int i = 0; i < argc; i++) { - if (!strcmp((*pargv)[i], "-run") || !strcmp((*pargv)[i], "--run")) { - // HACK: set flag to indicate we saw '-run' here - global.params.run = true; - // Don't eat -run yet so the program arguments don't get changed - argc_left = argc - i; - argc = i; - *pargv = &(*pargv)[i]; - argv->setDim(i); - break; - } else { - } - } - // HACK to stop required values from command line being drawn from DFLAGS - argv->push((char*)""); - argc++; - - size_t j = 1; // leave argv[0] alone - while (1) - { - int wildcard = 1; // do wildcard expansion - switch (*env) - { - case ' ': - case '\t': - env++; - break; - - case 0: - goto Ldone; - - case '"': - wildcard = 0; - default: - argv->push(env); // append - //argv->insert(j, env); // insert at position j - j++; - argc++; - p = env; - slash = 0; - instring = 0; - c = 0; - - while (1) - { - c = *env++; - switch (c) - { - case '"': - p -= (slash >> 1); - if (slash & 1) - { p--; - goto Laddc; - } - instring ^= 1; - slash = 0; - continue; - - case ' ': - case '\t': - if (instring) - goto Laddc; - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - break; - - case '\\': - slash++; - *p++ = c; - continue; - - case 0: - *p = 0; - //if (wildcard) - //wildcardexpand(); // not implemented - goto Ldone; - - default: - Laddc: - slash = 0; - *p++ = c; - continue; - } - break; - } - } - } - -Ldone: - assert(argc == argv->dim); - argv->reserve(argc_left); - for (int i = 0; i < argc_left; i++) - argv->data[argc++] = (void *)(*pargv)[i]; - - *pargc = argc; - *pargv = argv->tdata(); -} diff --git a/dmd2/mars.h b/dmd2/mars.h deleted file mode 100644 index dc640308..00000000 --- a/dmd2/mars.h +++ /dev/null @@ -1,503 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MARS_H -#define DMD_MARS_H - -#ifdef __DMC__ -#pragma once -#endif - -/* -It is very important to use version control macros correctly - the -idea is that host and target are independent. If these are done -correctly, cross compilers can be built. -The host compiler and host operating system are also different, -and are predefined by the host compiler. The ones used in -dmd are: - -Macros defined by the compiler, not the code: - - Compiler: - __DMC__ Digital Mars compiler - _MSC_VER Microsoft compiler - __GNUC__ Gnu compiler - __clang__ Clang compiler - - Host operating system: - _WIN32 Microsoft NT, Windows 95, Windows 98, Win32s, - Windows 2000, Win XP, Vista - _WIN64 Windows for AMD64 - linux Linux - __APPLE__ Mac OSX - __FreeBSD__ FreeBSD - __OpenBSD__ OpenBSD - __sun&&__SVR4 Solaris, OpenSolaris (yes, both macros are necessary) - -For the target systems, there are the target operating system and -the target object file format: - - Target operating system: - TARGET_WINDOS Covers 32 bit windows and 64 bit windows - TARGET_LINUX Covers 32 and 64 bit linux - TARGET_OSX Covers 32 and 64 bit Mac OSX - TARGET_FREEBSD Covers 32 and 64 bit FreeBSD - TARGET_OPENBSD Covers 32 and 64 bit OpenBSD - TARGET_SOLARIS Covers 32 and 64 bit Solaris - TARGET_NET Covers .Net - - It is expected that the compiler for each platform will be able - to generate 32 and 64 bit code from the same compiler binary. - - Target object module format: - OMFOBJ Intel Object Module Format, used on Windows - ELFOBJ Elf Object Module Format, used on linux, FreeBSD, OpenBSD and Solaris - MACHOBJ Mach-O Object Module Format, used on Mac OSX - - There are currently no macros for byte endianness order. - */ - - -#include -#include -#include -#include -#include - -#ifdef __DMC__ -#ifdef DEBUG -#undef assert -#define assert(e) (static_cast((e) || (printf("assert %s(%d) %s\n", __FILE__, __LINE__, #e), halt()))) -#endif -#endif - -#ifdef DEBUG -#define UNITTEST 1 -#endif -void unittests(); - -#ifndef IS_PRINTF -# ifdef __GNUC__ -# define IS_PRINTF(FMTARG) __attribute((__format__ (__printf__, (FMTARG), (FMTARG)+1) )) -# else -# define IS_PRINTF(FMTARG) -# endif -#endif - -#ifdef IN_GCC -/* Changes for the GDC compiler by David Friedman */ -#endif - -#define DMDV1 0 -#define DMDV2 1 // Version 2.0 features -#define BREAKABI 1 // 0 if not ready to break the ABI just yet -#define STRUCTTHISREF DMDV2 // if 'this' for struct is a reference, not a pointer -#define SNAN_DEFAULT_INIT DMDV2 // if floats are default initialized to signalling NaN -#define SARRAYVALUE DMDV2 // static arrays are value types -#define MODULEINFO_IS_STRUCT DMDV2 // if ModuleInfo is a struct rather than a class - -// Set if C++ mangling is done by the front end -#define CPP_MANGLE (DMDV2 && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)) - -/* Other targets are TARGET_LINUX, TARGET_OSX, TARGET_FREEBSD, TARGET_OPENBSD and - * TARGET_SOLARIS, which are - * set on the command line via the compiler makefile. - */ - -#if _WIN32 -#ifndef TARGET_WINDOS -#define TARGET_WINDOS 1 // Windows dmd generates Windows targets -#endif -#ifndef OMFOBJ -#define OMFOBJ TARGET_WINDOS -#endif -#endif - -#if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -#ifndef ELFOBJ -#define ELFOBJ 1 -#endif -#endif - -#if TARGET_OSX -#ifndef MACHOBJ -#define MACHOBJ 1 -#endif -#endif - - -struct OutBuffer; - -// Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -typedef ArrayBase Identifiers; -typedef ArrayBase Strings; - -#if IN_LLVM -enum ARCH -{ - ARCHinvalid, - ARCHx86, - ARCHx86_64, - ARCHppc, - ARCHppc_64, - ARCHarm, - ARCHthumb -}; -enum OUTPUTFLAG -{ - OUTPUTFLAGno, - OUTPUTFLAGdefault, // for the .o default - OUTPUTFLAGset // for -output -}; - -enum OS -{ - OSinvalid, - OSLinux, - OSHaiku, - OSWindows, - OSMacOSX, - OSFreeBSD, - OSSolaris, -}; - -typedef unsigned char ubyte; -#endif - -// Put command line switches in here -struct Param -{ - bool obj; // write object file - bool link; // perform link - bool verbose; // verbose compile - bool vtls; // identify thread local variables - ubyte symdebug; // insert debug symbolic information -#if !IN_LLVM - // LDC uses a different mechanism - bool optimize; // run optimizer - char optimizeLevel; // optimization level -#endif - ARCH cpu; // target CPU - OS os; - bool alwaysframe; // always emit standard stack frame - char map; // generate linker .map file - bool isLE; // generate little endian code - bool is64bit; // generate 64 bit code - bool useDeprecated; // allow use of deprecated features - bool useAssert; // generate runtime code for assert()'s - bool useInvariants; // generate class invariant checks - bool useIn; // generate precondition checks - bool useOut; // generate postcondition checks - bool useArrayBounds; // generate array bounds checks - bool useSwitchError; // check for switches without a default - bool useUnitTests; // generate unittest code - bool useInline; // inline expand functions - ubyte warnings; // enable warnings - ubyte Dversion; // D version number - bool ignoreUnsupportedPragmas; // rather than error on them - bool enforcePropertySyntax; - - char *argv0; // program name - Strings *imppath; // array of char*'s of where to look for import modules - Strings *fileImppath; // array of char*'s of where to look for file import modules - char *objdir; // .obj file output directory - char *objname; // .obj file output name - - bool doDocComments; // process embedded documentation comments - char *docdir; // write documentation file to docdir directory - char *docname; // write documentation file to docname - Strings *ddocfiles; // macro include files for Ddoc - - bool doHdrGeneration; // process embedded documentation comments - char *hdrdir; // write 'header' file to docdir directory - char *hdrname; // write 'header' file to docname - - bool doXGeneration; // write JSON file - char *xfilename; // write JSON file to xfilename - - unsigned debuglevel; // debug level - Strings *debugids; // debug identifiers - - unsigned versionlevel; // version level - Strings *versionids; // version identifiers - - bool dump_source; - - Strings *defaultlibnames; // default libraries for non-debug builds - Strings *debuglibnames; // default libraries for debug builds - - char *moduleDepsFile; // filename for deps output - OutBuffer *moduleDeps; // contents to be written to deps file - - // Hidden debug switches - bool debuga; - bool debugb; - bool debugc; - bool debugf; - bool debugr; - bool debugw; - bool debugx; - bool debugy; - - bool run; // run resulting executable - - // Linker stuff - Strings *objfiles; - Strings *linkswitches; - Strings *libfiles; - char *deffile; - char *resfile; - char *exefile; - char *mapfile; -#if IN_LLVM - // LDC stuff - OUTPUTFLAG output_ll; - OUTPUTFLAG output_bc; - OUTPUTFLAG output_s; - OUTPUTFLAG output_o; - bool llvmAnnotate; - bool useInlineAsm; - bool verbose_cg; - bool useAvailableExternally; - - // target stuff - const char* llvmArch; - const char *targetTriple; - const char *dataLayout; -#endif -}; - -struct Global -{ - const char *mars_ext; - const char *sym_ext; - const char *obj_ext; -#if IN_LLVM -#if _WIN32 - char *obj_ext_alt; -#endif - char *ll_ext; - char *bc_ext; - char *s_ext; -#endif - const char *lib_ext; - const char *dll_ext; - const char *doc_ext; // for Ddoc generated files - const char *ddoc_ext; // for Ddoc macro include files - const char *hdr_ext; // for D 'header' import files - const char *json_ext; // for JSON files - const char *map_ext; // for .map files - const char *copyright; - const char *written; - Strings *path; // Array of char*'s which form the import lookup path - Strings *filePath; // Array of char*'s which form the file import lookup path - int structalign; - const char *version; -#if IN_LLVM - char *ldc_version; - char *llvm_version; -#endif - - Param params; - unsigned errors; // number of errors reported so far - unsigned warnings; // number of warnings reported so far - unsigned gag; // !=0 means gag reporting of errors & warnings - unsigned gaggedErrors; // number of errors reported while gagged - - // Start gagging. Return the current number of gagged errors - unsigned startGagging(); - - /* End gagging, restoring the old gagged state. - * Return true if errors occured while gagged. - */ - bool endGagging(unsigned oldGagged); - - Global(); -}; - -extern Global global; - -/* Set if Windows Structured Exception Handling C extensions are supported. - * Apparently, VC has dropped support for these? - */ -#define WINDOWS_SEH (_WIN32 && __DMC__) - - -#ifdef __DMC__ - typedef _Complex long double complex_t; -#else - #ifndef IN_GCC - #include "complex_t.h" - #endif - #ifdef __APPLE__ - //#include "complex.h"//This causes problems with include the c++ and not the C "complex.h" - #endif -#endif - -// Be careful not to care about sign when using dinteger_t -//typedef uint64_t integer_t; -typedef uint64_t dinteger_t; // use this instead of integer_t to - // avoid conflicts with system #include's - -// Signed and unsigned variants -typedef int64_t sinteger_t; -typedef uint64_t uinteger_t; - -typedef int8_t d_int8; -typedef uint8_t d_uns8; -typedef int16_t d_int16; -typedef uint16_t d_uns16; -typedef int32_t d_int32; -typedef uint32_t d_uns32; -typedef int64_t d_int64; -typedef uint64_t d_uns64; - -typedef float d_float32; -typedef double d_float64; -typedef long double d_float80; - -typedef d_uns8 d_char; -typedef d_uns16 d_wchar; -typedef d_uns32 d_dchar; - -#ifdef IN_GCC -#include "d-gcc-real.h" -#else -typedef long double real_t; -#endif - -// Modify OutBuffer::writewchar to write the correct size of wchar -#if _WIN32 -#define writewchar writeword -#else -// This needs a configuration test... -#define writewchar write4 -#endif - -#ifdef IN_GCC -#include "d-gcc-complex_t.h" -#endif - -struct Module; - -//typedef unsigned Loc; // file location -struct Loc -{ - const char *filename; - unsigned linnum; - - Loc() - { - linnum = 0; - filename = NULL; - } - - Loc(int x) - { - linnum = x; - filename = NULL; - } - - Loc(Module *mod, unsigned linnum); - - char *toChars(); - bool equals(const Loc& loc); -}; - -#ifndef GCC_SAFE_DMD -#define TRUE 1 -#define FALSE 0 -#endif - -#define INTERFACE_OFFSET 0 // if 1, put classinfo as first entry - // in interface vtbl[]'s -#define INTERFACE_VIRTUAL 0 // 1 means if an interface appears - // in the inheritance graph multiple - // times, only one is used - -enum LINK -{ - LINKdefault, - LINKd, - LINKc, - LINKcpp, - LINKwindows, - LINKpascal, - -#if IN_LLVM - LINKintrinsic, -#endif -}; - -enum DYNCAST -{ - DYNCAST_OBJECT, - DYNCAST_EXPRESSION, - DYNCAST_DSYMBOL, - DYNCAST_TYPE, - DYNCAST_IDENTIFIER, - DYNCAST_TUPLE, -}; - -enum MATCH -{ - MATCHnomatch, // no match - MATCHconvert, // match with conversions -#if DMDV2 - MATCHconst, // match with conversion to const -#endif - MATCHexact // exact match -}; - -typedef uint64_t StorageClass; - - -void warning(Loc loc, const char *format, ...) IS_PRINTF(2); -void error(Loc loc, const char *format, ...) IS_PRINTF(2); -void errorSupplemental(Loc loc, const char *format, ...); -void verror(Loc loc, const char *format, va_list); -void vwarning(Loc loc, const char *format, va_list); -void verrorSupplemental(Loc loc, const char *format, va_list); -void fatal(); -void err_nomem(); -#if IN_LLVM -void inifile(char *argv0, const char *inifile); -#else -int runLINK(); -void deleteExeFile(); -int runProgram(); -const char *inifile(const char *argv0, const char *inifile); -#endif -void halt(); -#if !IN_LLVM -void util_progress(); -#endif - -/*** Where to send error messages ***/ -#if IN_GCC || IN_LLVM -#define stdmsg stderr -#else -#define stdmsg stderr -#endif - -#if !IN_LLVM -struct Dsymbol; -struct Library; -struct File; -void obj_start(char *srcfile); -void obj_end(Library *library, File *objfile); -void obj_append(Dsymbol *s); -void obj_write_deferred(Library *library); -#endif - -const char *importHint(const char *s); - -#endif /* DMD_MARS_H */ diff --git a/dmd2/module.c b/dmd2/module.c deleted file mode 100644 index c486bfc6..00000000 --- a/dmd2/module.c +++ /dev/null @@ -1,1365 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if defined(_MSC_VER) || defined(__MINGW32__) -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#include "rmem.h" - -#include "mars.h" -#include "module.h" -#include "parse.h" -#include "scope.h" -#include "identifier.h" -#include "id.h" -#include "import.h" -#include "dsymbol.h" -#include "hdrgen.h" -#include "lexer.h" - -#define MARS 1 -#include "html.h" - -#ifdef IN_GCC -#include "d-dmd-gcc.h" -#endif - -#if IN_LLVM -#include "llvm/Type.h" -#include "llvm/LLVMContext.h" -#include "llvm/DerivedTypes.h" -#include "llvm/Support/CommandLine.h" -#include - -static llvm::cl::opt preservePaths("op", - llvm::cl::desc("Do not strip paths from source file"), - llvm::cl::ZeroOrMore); - -static llvm::cl::opt fqnNames("oq", - llvm::cl::desc("Write object files with fully qualified names"), - llvm::cl::ZeroOrMore); -#endif - -AggregateDeclaration *Module::moduleinfo; - -Module *Module::rootModule; -DsymbolTable *Module::modules; -Modules Module::amodules; - -Dsymbols Module::deferred; // deferred Dsymbol's needing semantic() run on them -unsigned Module::dprogress; - -void Module::init() -{ - modules = new DsymbolTable(); -} - -Module::Module(char *filename, Identifier *ident, int doDocComment, int doHdrGen) - : Package(ident) -{ - FileName *srcfilename; -#if IN_DMD - FileName *objfilename; - FileName *symfilename; -#endif - -// printf("Module::Module(filename = '%s', ident = '%s')\n", filename, ident->toChars()); - this->arg = filename; - md = NULL; - errors = 0; - numlines = 0; - members = NULL; - isHtml = 0; - isDocFile = 0; - needmoduleinfo = 0; -#ifdef IN_GCC - strictlyneedmoduleinfo = 0; -#endif - selfimports = 0; - insearch = 0; - searchCacheIdent = NULL; - searchCacheSymbol = NULL; - searchCacheFlags = 0; - semanticstarted = 0; - semanticRun = 0; - decldefs = NULL; - vmoduleinfo = NULL; -#if IN_DMD - massert = NULL; - munittest = NULL; - marray = NULL; - sictor = NULL; - sctor = NULL; - sdtor = NULL; - ssharedctor = NULL; - sshareddtor = NULL; - stest = NULL; - sfilename = NULL; -#endif - root = 0; - importedFrom = NULL; - srcfile = NULL; - objfile = NULL; - docfile = NULL; - hdrfile = NULL; - - debuglevel = 0; - debugids = NULL; - debugidsNot = NULL; - versionlevel = 0; - versionids = NULL; - versionidsNot = NULL; - - macrotable = NULL; - escapetable = NULL; - safe = FALSE; -#if IN-DMD - doppelganger = 0; - cov = NULL; - covb = NULL; -#endif - - nameoffset = 0; - namelen = 0; - - srcfilename = FileName::defaultExt(filename, global.mars_ext); - if (!srcfilename->equalsExt(global.mars_ext) && - !srcfilename->equalsExt(global.hdr_ext) && - !srcfilename->equalsExt("dd")) - { - if (srcfilename->equalsExt("html") || - srcfilename->equalsExt("htm") || - srcfilename->equalsExt("xhtml")) - { if (!global.params.useDeprecated) - error("html source files is deprecated %s", srcfilename->toChars()); - isHtml = 1; - } - else - { error("source file name '%s' must have .%s extension", srcfilename->toChars(), global.mars_ext); - fatal(); - } - } -#if !IN_LLVM - char *argobj; - if (global.params.objname) - argobj = global.params.objname; -#if 0 - else if (global.params.preservePaths) - argobj = filename; - else - argobj = FileName::name(filename); - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(global.params.objdir, argobj); - } -#else // Bugzilla 3547 - else - { - if (global.params.preservePaths) - argobj = filename; - else - argobj = FileName::name(filename); - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(global.params.objdir, argobj); - } - } -#endif - - if (global.params.objname) - objfilename = new FileName(argobj, 0); - else - objfilename = FileName::forceExt(argobj, global.obj_ext); - - symfilename = FileName::forceExt(filename, global.sym_ext); -#endif - - srcfile = new File(srcfilename); -#if IN_DMD - if (doDocComment) - { - setDocfile(); - } - - if (doHdrGen) - { - setHdrfile(); - } - - objfile = new File(objfilename); - symfile = new File(symfilename); -#endif -#if IN_LLVM - // LDC - llvmForceLogging = false; - moduleInfoVar = NULL; - moduleInfoType = llvm::StructType::create(llvm::getGlobalContext()); - this->doDocComment = doDocComment; - this->doHdrGen = doHdrGen; - this->isRoot = false; - this->arrayfuncs = 0; -#endif -} -#if IN_LLVM -File* Module::buildFilePath(const char* forcename, const char* path, const char* ext) -{ - const char *argobj; - if (forcename) - argobj = forcename; - else - { - if (preservePaths) - argobj = (char*)this->arg; - else - argobj = FileName::name((char*)this->arg); - - if (fqnNames) - { - if(md) - argobj = FileName::replaceName((char*)argobj, md->toChars()); - else - argobj = FileName::replaceName((char*)argobj, toChars()); - - // add ext, otherwise forceExt will make nested.module into nested.bc - size_t len = strlen(argobj); - size_t extlen = strlen(ext); - char* s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s, argobj, len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - s[len+1+extlen] = 0; - argobj = s; - } - } - - if (!FileName::absolute(argobj)) - { - argobj = FileName::combine(path, argobj); - } - - FileName::ensurePathExists(FileName::path(argobj)); - -// always append the extension! otherwise hard to make output switches consistent -// if (forcename) -// return new File(argobj); -// else - // allow for .o and .obj on windows -#if _WIN32 - if (ext == global.params.objdir && FileName::ext(argobj) - && stricmp(FileName::ext(argobj), global.obj_ext_alt) == 0) - return new File((char*)argobj); -#endif - return new File(FileName::forceExt(argobj, ext)); -} -#endif -#if IN_DMD -void Module::setDocfile() -{ - FileName *docfilename; - char *argdoc; - - if (global.params.docname) - argdoc = global.params.docname; - else if (global.params.preservePaths) - argdoc = (char *)arg; - else - argdoc = FileName::name((char *)arg); - if (!FileName::absolute(argdoc)) - { //FileName::ensurePathExists(global.params.docdir); - argdoc = FileName::combine(global.params.docdir, argdoc); - } - if (global.params.docname) - docfilename = new FileName(argdoc, 0); - else - docfilename = FileName::forceExt(argdoc, global.doc_ext); - - if (docfilename->equals(srcfile->name)) - { error("Source file and documentation file have same name '%s'", srcfile->name->str); - fatal(); - } - - docfile = new File(docfilename); -} - -void Module::setHdrfile() -{ - FileName *hdrfilename; - char *arghdr; - - if (global.params.hdrname) - arghdr = global.params.hdrname; - else if (global.params.preservePaths) - arghdr = (char *)arg; - else - arghdr = FileName::name((char *)arg); - if (!FileName::absolute(arghdr)) - { //FileName::ensurePathExists(global.params.hdrdir); - arghdr = FileName::combine(global.params.hdrdir, arghdr); - } - if (global.params.hdrname) - hdrfilename = new FileName(arghdr, 0); - else - hdrfilename = FileName::forceExt(arghdr, global.hdr_ext); - - if (hdrfilename->equals(srcfile->name)) - { error("Source file and 'header' file have same name '%s'", srcfile->name->str); - fatal(); - } - - hdrfile = new File(hdrfilename); -} -#endif - -#if IN_LLVM - -// LDC -static void check_and_add_output_file(Module* NewMod, const std::string& str) -{ - typedef std::map map_t; - static map_t files; - - map_t::iterator i = files.find(str); - if (i != files.end()) - { - Module* ThisMod = i->second; - error("Output file '%s' for module '%s' collides with previous module '%s'. See the -oq option", - str.c_str(), NewMod->toPrettyChars(), ThisMod->toPrettyChars()); - fatal(); - } - files.insert(std::make_pair(str, NewMod)); -} - -void Module::buildTargetFiles(bool singleObj) -{ - if(objfile && - (!doDocComment || docfile) && - (!doHdrGen || hdrfile)) - return; - - if(!objfile) - { - if (global.params.output_o) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.obj_ext); - else if (global.params.output_bc) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.bc_ext); - else if (global.params.output_ll) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.ll_ext); - else if (global.params.output_s) - objfile = Module::buildFilePath(global.params.objname, global.params.objdir, global.s_ext); - } - if(doDocComment && !docfile) - docfile = Module::buildFilePath(global.params.docname, global.params.docdir, global.doc_ext); - if(doHdrGen && !hdrfile) - hdrfile = Module::buildFilePath(global.params.hdrname, global.params.hdrdir, global.hdr_ext); - - // safety check: never allow obj, doc or hdr file to have the source file's name - if(stricmp(FileName::name(objfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output object files with the same name as the source file are forbidden"); - fatal(); - } - if(docfile && stricmp(FileName::name(docfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output doc files with the same name as the source file are forbidden"); - fatal(); - } - if(hdrfile && stricmp(FileName::name(hdrfile->name->str), FileName::name((char*)this->arg)) == 0) - { - error("Output header files with the same name as the source file are forbidden"); - fatal(); - } - - // LDC - // another safety check to make sure we don't overwrite previous output files - if (!singleObj) - check_and_add_output_file(this, objfile->name->str); - if (docfile) - check_and_add_output_file(this, docfile->name->str); - if (hdrfile) - check_and_add_output_file(this, hdrfile->name->str); -} - -#endif - -void Module::deleteObjFile() -{ - if (global.params.obj) - objfile->remove(); - //if (global.params.llvmBC) - //bcfile->remove(); - if (doDocComment && docfile) - docfile->remove(); -} - -Module::~Module() -{ -#if IN_LLVM - delete moduleInfoType; -#endif -} - -const char *Module::kind() -{ - return "module"; -} - -Module *Module::load(Loc loc, Identifiers *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; - - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[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 = (*global.path)[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 = packages->tdata()[i]; - printf("%s.", pid->toChars()); - } - } - printf("%s\t(%s)\n", ident->toChars(), m->srcfile->toChars()); - } - - m->read(loc); - m->parse(); - -#ifdef IN_GCC - d_gcc_magic_module(m); -#endif - - return m; -} - -void Module::read(Loc loc) -{ - //printf("Module::read('%s') file '%s'\n", toChars(), srcfile->toChars()); - if (srcfile->read()) - { error(loc, "is in file '%s' which cannot be read", srcfile->toChars()); - if (!global.gag) - { /* Print path - */ - if (global.path) - { - for (size_t i = 0; i < global.path->dim; i++) - { - char *p = global.path->tdata()[i]; - fprintf(stdmsg, "import path[%zd] = %s\n", i, p); - } - } - else - fprintf(stdmsg, "Specify path to file '%s' with -I switch\n", srcfile->toChars()); - } - fatal(); - } -} - -inline unsigned readwordLE(unsigned short *p) -{ -#if LITTLE_ENDIAN - 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 LITTLE_ENDIAN - 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_LLVM -void Module::parse(bool gen_docs) -#elif IN_GCC -void Module::parse(bool dump_source) -#else -void Module::parse() -#endif -{ char *srcname; - unsigned char *buf; - unsigned buflen; - unsigned le; - unsigned bom; - - //printf("Module::parse()\n"); - - srcname = srcfile->name->toChars(); - //printf("Module::parse(srcname = '%s')\n", srcname); - - buf = srcfile->buffer; - buflen = srcfile->len; - - if (buflen >= 2) - { - /* Convert all non-UTF-8 formats to UTF-8. - * BOM : http://www.unicode.org/faq/utf_bom.html - * 00 00 FE FF UTF-32BE, big-endian - * FF FE 00 00 UTF-32LE, little-endian - * FE FF UTF-16BE, big-endian - * FF FE UTF-16LE, little-endian - * EF BB BF UTF-8 - */ - - bom = 1; // assume there's a BOM - if (buf[0] == 0xFF && buf[1] == 0xFE) - { - if (buflen >= 4 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - - Lutf32: - OutBuffer dbuf; - unsigned *pu = (unsigned *)(buf); - unsigned *pumax = &pu[buflen / 4]; - - if (buflen & 3) - { error("odd length of UTF-32 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 4); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readlongLE(pu) : readlongBE(pu); - if (u & ~0x7F) - { - if (u > 0x10FFFF) - { error("UTF-32 value %08x greater than 0x10FFFF", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - else - { // UTF-16LE (X86) - // Convert it to UTF-8 - le = 1; - - Lutf16: - OutBuffer dbuf; - unsigned short *pu = (unsigned short *)(buf); - unsigned short *pumax = &pu[buflen / 2]; - - if (buflen & 1) - { error("odd length of UTF-16 char source %u", buflen); - fatal(); - } - - dbuf.reserve(buflen / 2); - for (pu += bom; pu < pumax; pu++) - { unsigned u; - - u = le ? readwordLE(pu) : readwordBE(pu); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (++pu > pumax) - { error("surrogate UTF-16 high value %04x at EOF", u); - fatal(); - } - u2 = le ? readwordLE(pu) : readwordBE(pu); - if (u2 < 0xDC00 || u2 > 0xDFFF) - { error("surrogate UTF-16 low value %04x out of range", u2); - fatal(); - } - u = (u - 0xD7C0) << 10; - u |= (u2 - 0xDC00); - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { error("unpaired surrogate UTF-16 value %04x", u); - fatal(); - } - else if (u == 0xFFFE || u == 0xFFFF) - { error("illegal UTF-16 value %04x", u); - fatal(); - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); // add 0 as sentinel for scanner - buflen = dbuf.offset - 1; // don't include sentinel in count - buf = (unsigned char *) dbuf.extractData(); - } - } - else if (buf[0] == 0xFE && buf[1] == 0xFF) - { // UTF-16BE - le = 0; - goto Lutf16; - } - else if (buflen >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) - { // UTF-32BE - le = 0; - goto Lutf32; - } - else if (buflen >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) - { // UTF-8 - - buf += 3; - buflen -= 3; - } - else - { - /* There is no BOM. Make use of Arcane Jill's insight that - * the first char of D source must be ASCII to - * figure out the encoding. - */ - - bom = 0; - if (buflen >= 4) - { if (buf[1] == 0 && buf[2] == 0 && buf[3] == 0) - { // UTF-32LE - le = 1; - goto Lutf32; - } - else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0) - { // UTF-32BE - le = 0; - goto Lutf32; - } - } - if (buflen >= 2) - { - if (buf[1] == 0) - { // UTF-16LE - le = 1; - goto Lutf16; - } - else if (buf[0] == 0) - { // UTF-16BE - le = 0; - goto Lutf16; - } - } - - // It's UTF-8 - if (buf[0] >= 0x80) - { error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); - fatal(); - } - } - } - -#ifdef IN_GCC - // dump utf-8 encoded source - if (dump_source) - { // %% srcname could contain a path ... - d_gcc_dump_source(srcname, "utf-8", buf, buflen); - } -#endif - - /* If it starts with the string "Ddoc", then it's a documentation - * source file. - */ - if (buflen >= 4 && memcmp(buf, "Ddoc", 4) == 0) - { - comment = buf + 4; - isDocFile = 1; -#if IN_DMD - if (!docfile) - setDocfile(); -#endif - return; - } - if (isHtml) - { - OutBuffer *dbuf = new OutBuffer(); - Html h(srcname, buf, buflen); - h.extractCode(dbuf); - buf = dbuf->data; - buflen = dbuf->offset; -#ifdef IN_GCC - // dump extracted source - if (dump_source) - d_gcc_dump_source(srcname, "d.utf-8", buf, buflen); -#endif - } -#if IN_LLVM - Parser p(this, buf, buflen, gen_docs); -#else - Parser p(this, buf, buflen, docfile != NULL); -#endif - p.nextToken(); - members = p.parseModule(); - - ::free(srcfile->buffer); - srcfile->buffer = NULL; - srcfile->len = 0; - - md = p.md; - numlines = p.loc.linnum; - - DsymbolTable *dst; - - if (md) - { this->ident = md->id; - this->safe = md->safe; - dst = Package::resolve(md->packages, &this->parent, NULL); - } - else - { - dst = modules; - - /* Check to see if module name is a valid identifier - */ - if (!Lexer::isValidIdentifier(this->ident->toChars())) - error("has non-identifier characters in filename, use module declaration instead"); - } - - // Update global list of modules - if (!dst->insert(this)) - { - Dsymbol *prev = dst->lookup(ident); - assert(prev); - Module *mprev = prev->isModule(); - if (mprev) - error(loc, "from file %s conflicts with another module %s from file %s", - srcname, mprev->toChars(), mprev->srcfile->toChars()); - else - { - Package *pkg = prev->isPackage(); - assert(pkg); - error(loc, "from file %s conflicts with package name %s", - srcname, pkg->toChars()); - } - } - else - { - amodules.push(this); - } -} - -void Module::importAll(Scope *prevsc) -{ - //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - - if (scope) - return; // already done - - if (isDocFile) - { - error("is a Ddoc file, cannot import it"); - return; - } - - /* Note that modules get their own scope, from scratch. - * This is so regardless of where in the syntax a module - * gets imported, it is unaffected by context. - * Ignore prevsc. - */ - Scope *sc = Scope::createGlobal(this); // create root scope - - // Add import of "object", even for the "object" module. - // If it isn't there, some compiler rewrites, like - // classinst == classinst -> .object.opEquals(classinst, classinst) - // would fail inside object.d. - if (members->dim == 0 || ((*members)[0])->ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } - - if (!symtab) - { - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->addMember(NULL, sc->scopesym, 1); - } - } - // anything else should be run after addMember, so version/debug symbols are defined - - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - setScope(sc); // remember module scope for semantic - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - s->setScope(sc); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->importAll(sc); - } - - sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 -} - -void Module::semantic(Scope* unused_sc) -{ - if (semanticstarted) - return; - - //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); - semanticstarted = 1; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - Scope *sc = scope; // see if already got one from importAll() - if (!sc) - { printf("test2\n"); - Scope::createGlobal(this); // create root scope - } - - //printf("Module = %p, linkage = %d\n", sc->scopesym, sc->linkage); - -#if 0 - // Add import of "object" if this module isn't "object" - if (ident != Id::object) - { - Import *im = new Import(0, NULL, Id::object, NULL, 0); - members->shift(im); - } - - // Add all symbols into module's symbol table - symtab = new DsymbolTable(); - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->addMember(NULL, sc->scopesym, 1); - } - - /* Set scope for the symbols so that if we forward reference - * a symbol, it can possibly be resolved on the spot. - * If this works out well, it can be extended to all modules - * before any semantic() on any of them. - */ - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (Dsymbol *)members->data[i]; - s->setScope(sc); - } -#endif - - // Do semantic() on members that don't depend on others - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - - //printf("\tModule('%s'): '%s'.semantic0()\n", toChars(), s->toChars()); - s->semantic0(sc); - } - - // Pass 1 semantic routines: do public side of the definition - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - - //printf("\tModule('%s'): '%s'.semantic()\n", toChars(), s->toChars()); - s->semantic(sc); - runDeferredSemantic(); - } - - if (!scope) - { sc = sc->pop(); - sc->pop(); // 2 pops because Scope::createGlobal() created 2 - } - semanticRun = semanticstarted; - //printf("-Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); -} - -void Module::semantic2(Scope* unused_sc) -{ - if (deferred.dim) - { - for (size_t i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = deferred.tdata()[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 (size_t i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = members->tdata()[i]; - s->semantic2(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; - //printf("-Module::semantic2('%s'): parent = %p\n", toChars(), parent); -} - -void Module::semantic3(Scope* unused_sc) -{ - //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 (size_t i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = members->tdata()[i]; - //printf("Module %s: %s.semantic3()\n", toChars(), s->toChars()); - s->semantic3(sc); - } - - sc = sc->pop(); - sc->pop(); - semanticRun = semanticstarted; -} - -void Module::inlineScan() -{ - if (semanticstarted >= 4) - return; - assert(semanticstarted == 3); - semanticstarted = 4; - - // Note that modules get their own scope, from scratch. - // This is so regardless of where in the syntax a module - // gets imported, it is unaffected by context. - //printf("Module = %p\n", sc.scopesym); - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - //if (global.params.verbose) - //printf("inline scan symbol %s\n", s->toChars()); - - s->inlineScan(); - } - semanticRun = semanticstarted; -} - -/**************************************************** - */ - -// is this used anywhere? -/* -void Module::gensymfile() -{ - OutBuffer buf; - HdrGenState hgs; - - //printf("Module::gensymfile()\n"); - - buf.printf("// Sym file generated from '%s'", srcfile->toChars()); - buf.writenl(); - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = members->tdata()[i]; - - s->toCBuffer(&buf, &hgs); - } - - // Transfer image to file - symfile->setbuffer(buf.data, buf.offset); - buf.data = NULL; - - symfile->writev(); -}*/ - -/********************************** - * Determine if we need to generate an instance of ModuleInfo - * for this Module. - */ - -int Module::needModuleInfo() -{ - //printf("needModuleInfo() %s, %d, %d\n", toChars(), needmoduleinfo, global.params.cov); - return needmoduleinfo; -} - -Dsymbol *Module::search(Loc loc, Identifier *ident, int flags) -{ - /* Since modules can be circularly referenced, - * need to stop infinite recursive searches. - * This is done with the cache. - */ - - //printf("%s Module::search('%s', flags = %d) insearch = %d\n", toChars(), ident->toChars(), flags, insearch); - Dsymbol *s; - if (insearch) - s = NULL; - else if (searchCacheIdent == ident && searchCacheFlags == flags) - { - s = searchCacheSymbol; - //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", toChars(), ident->toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol->toChars() : "null"); - } - else - { - insearch = 1; - s = ScopeDsymbol::search(loc, ident, flags); - insearch = 0; - - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; - } - return s; -} - -Dsymbol *Module::symtabInsert(Dsymbol *s) -{ - searchCacheIdent = 0; // symbol is inserted, so invalidate cache - return Package::symtabInsert(s); -} - -void Module::clearCache() -{ - for (size_t i = 0; i < amodules.dim; i++) - { Module *m = amodules.tdata()[i]; - m->searchCacheIdent = NULL; - } -} - -/******************************************* - * Can't run semantic on s now, try again later. - */ - -void Module::addDeferredSemantic(Dsymbol *s) -{ - // Don't add it if it is already there - for (size_t i = 0; i < deferred.dim; i++) - { - Dsymbol *sd = deferred.tdata()[i]; - - if (sd == s) - return; - } - - //printf("Module::addDeferredSemantic('%s')\n", s->toChars()); - deferred.push(s); -} - - -/****************************************** - * Run semantic() on deferred symbols. - */ - -void Module::runDeferredSemantic() -{ - if (dprogress == 0) - return; - - static int nested; - if (nested) - return; - //if (deferred.dim) printf("+Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); - nested++; - - size_t len; - do - { - dprogress = 0; - len = deferred.dim; - if (!len) - break; - - Dsymbol **todo; - Dsymbol *tmp; - if (len == 1) - { - todo = &tmp; - } - else - { - todo = (Dsymbol **)alloca(len * sizeof(Dsymbol *)); - assert(todo); - } - memcpy(todo, deferred.tdata(), len * sizeof(Dsymbol *)); - deferred.setDim(0); - - for (size_t i = 0; i < len; i++) - { - Dsymbol *s = todo[i]; - - s->semantic(NULL); - //printf("deferred: %s, parent = %s\n", s->toChars(), s->parent->toChars()); - } - //printf("\tdeferred.dim = %d, len = %d, dprogress = %d\n", deferred.dim, len, dprogress); - } while (deferred.dim < len || dprogress); // while making progress - nested--; - //printf("-Module::runDeferredSemantic('%s'), len = %d\n", toChars(), deferred.dim); -} - -/************************************ - * Recursively look at every module this module imports, - * return TRUE if it imports m. - * Can be used to detect circular imports. - */ - -int Module::imports(Module *m) -{ - //printf("%s Module::imports(%s)\n", toChars(), m->toChars()); - int aimports_dim = aimports.dim; -#if 0 - for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = (Module *)aimports.data[i]; - printf("\t[%d] %s\n", i, mi->toChars()); - } -#endif - for (size_t i = 0; i < aimports.dim; i++) - { Module *mi = aimports.tdata()[i]; - if (mi == m) - return TRUE; - if (!mi->insearch) - { - mi->insearch = 1; - int r = mi->imports(m); - if (r) - return r; - } - } - return FALSE; -} - -/************************************* - * Return !=0 if module imports itself. - */ - -int Module::selfImports() -{ - //printf("Module::selfImports() %s\n", toChars()); - if (!selfimports) - { - for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - - selfimports = imports(this) + 1; - - for (size_t i = 0; i < amodules.dim; i++) - { Module *mi = amodules.tdata()[i]; - //printf("\t[%d] %s\n", i, mi->toChars()); - mi->insearch = 0; - } - } - return selfimports - 1; -} - - -/* =========================== ModuleDeclaration ===================== */ - -ModuleDeclaration::ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe) -{ - this->packages = packages; - this->id = id; - this->safe = safe; -} - -char *ModuleDeclaration::toChars() -{ - OutBuffer buf; - - if (packages && packages->dim) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[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(Identifiers *packages, Dsymbol **pparent, Package **ppkg) -{ - DsymbolTable *dst = Module::modules; - Dsymbol *parent = NULL; - - //printf("Package::resolve()\n"); - if (ppkg) - *ppkg = NULL; - - if (packages) - { - for (size_t i = 0; i < packages->dim; i++) - { Identifier *pid = packages->tdata()[i]; - Dsymbol *p; - - p = dst->lookup(pid); - if (!p) - { - p = new Package(pid); - dst->insert(p); - p->parent = parent; - ((ScopeDsymbol *)p)->symtab = new DsymbolTable(); - } - else - { - assert(p->isPackage()); -#if TARGET_NET //dot net needs modules and packages with same name -#else - if (p->isModule()) - { p->error("module and package have the same name"); - fatal(); - break; - } -#endif - } - parent = p; - dst = ((Package *)p)->symtab; - if (ppkg && !*ppkg) - *ppkg = (Package *)p; - } - if (pparent) - { - *pparent = parent; - } - } - return dst; -} diff --git a/dmd2/module.h b/dmd2/module.h deleted file mode 100644 index 22c8de2e..00000000 --- a/dmd2/module.h +++ /dev/null @@ -1,232 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2008 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MODULE_H -#define DMD_MODULE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "dsymbol.h" - -struct ModuleInfoDeclaration; -struct ClassDeclaration; -struct ModuleDeclaration; -struct Macro; -struct Escape; -struct VarDeclaration; -struct Library; - -// Back end -#if IN_LLVM -class Ir; -struct DValue; -typedef DValue elem; -namespace llvm { - class LLVMContext; - class Module; - class GlobalVariable; - class StructType; -} -#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(Identifiers *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 Modules amodules; // array of all modules - static Dsymbols deferred; // deferred Dsymbol's needing semantic() run on them - static unsigned dprogress; // progress resolving the deferred list - static void init(); - - static AggregateDeclaration *moduleinfo; - - const char *arg; // original argument name - ModuleDeclaration *md; // if !NULL, the contents of the ModuleDeclaration declaration - File *srcfile; // input source file - File *objfile; // output .obj file - File *hdrfile; // 'header' file - File *symfile; // output symbol file - File *docfile; // output documentation file - - unsigned errors; // if any errors in file - unsigned numlines; // number of lines in source file - int isHtml; // if it is an HTML file - int isDocFile; // if it is a documentation input file, not D source - int needmoduleinfo; -#ifdef IN_GCC - int strictlyneedmoduleinfo; -#endif - - int selfimports; // 0: don't know, 1: does not, 2: does - int selfImports(); // returns !=0 if module imports itself - - int insearch; - Identifier *searchCacheIdent; - Dsymbol *searchCacheSymbol; // cached value of search - int searchCacheFlags; // cached flags - - int semanticstarted; // has semantic() been started? - int semanticRun; // has semantic() been done? - int root; // != 0 if this is a 'root' module, - // i.e. a module that will be taken all the - // way to an object file - Module *importedFrom; // module from command line we're imported from, - // i.e. a module that will be taken all the - // way to an object file - - Dsymbols *decldefs; // top level declarations for this Module - - Modules aimports; // all imported modules - - ModuleInfoDeclaration *vmoduleinfo; - - unsigned debuglevel; // debug level - Strings *debugids; // debug identifiers - Strings *debugidsNot; // forward referenced debug identifiers - - unsigned versionlevel; // version level - Strings *versionids; // version identifiers - Strings *versionidsNot; // forward referenced version identifiers - - Macro *macrotable; // document comment macros - Escape *escapetable; // document comment escapes - bool safe; // TRUE if module is marked as 'safe' - - size_t nameoffset; // offset of module name from start of ModuleInfo - size_t namelen; // length of module name in characters - - int doDocComment; // enable generating doc comments for this module - int doHdrGen; // enable generating header file for this module - - Module(char *arg, Identifier *ident, int doDocComment, int doHdrGen); - ~Module(); - - static Module *load(Loc loc, Identifiers *packages, Identifier *ident); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - void toJsonBuffer(OutBuffer *buf); - const char *kind(); -#if !IN_LLVM - void setDocfile(); // set docfile member -#endif - void read(Loc loc); // read file -#if IN_LLVM - void parse(bool gen_docs = false); // syntactic parse -#elif IN_GCC - void parse(bool dump_source = false); // syntactic parse -#else - void parse(); // syntactic parse -#endif - void importAll(Scope *sc); - void semantic(Scope* unused_sc = NULL); // semantic analysis - void semantic2(Scope* unused_sc = NULL); // pass 2 semantic analysis - void semantic3(Scope* unused_sc = NULL); // pass 3 semantic analysis - void inlineScan(); // scan for functions to inline -#if !IN_LLVM - void setHdrfile(); // set hdrfile member -#endif - void genhdrfile(); // generate D import file -// void gensymfile(); - void gendocfile(); - int needModuleInfo(); - Dsymbol *search(Loc loc, Identifier *ident, int flags); - Dsymbol *symtabInsert(Dsymbol *s); - void deleteObjFile(); - void addDeferredSemantic(Dsymbol *s); - static void runDeferredSemantic(); - static void clearCache(); - int imports(Module *m); - - // Back end -#if IN_DMD - int doppelganger; // sub-module - Symbol *cov; // private uint[] __coverage; - unsigned *covb; // bit array of valid code line numbers - - Symbol *sictor; // module order independent constructor - Symbol *sctor; // module constructor - Symbol *sdtor; // module destructor - Symbol *ssharedctor; // module shared constructor - Symbol *sshareddtor; // module shared destructor - Symbol *stest; // module unit test - - Symbol *sfilename; // symbol for filename - - Symbol *massert; // module assert function - Symbol *toModuleAssert(); // get module assert function - - Symbol *munittest; // module unittest failure function - Symbol *toModuleUnittest(); // get module unittest failure function - - Symbol *marray; // module array bounds function - Symbol *toModuleArray(); // get module array bounds function - - - static Symbol *gencritsec(); - elem *toEfilename(); - - Symbol *toSymbol(); -#endif - void genmoduleinfo(); - -#if IN_LLVM - // LDC - llvm::Module* genLLVMModule(llvm::LLVMContext& context, Ir* sir); - void buildTargetFiles(bool singleObj); - File* buildFilePath(const char* forcename, const char* path, const char* ext); - Module *isModule() { return this; } - llvm::GlobalVariable* moduleInfoSymbol(); - - bool llvmForceLogging; - llvm::GlobalVariable* moduleInfoVar; - llvm::StructType* moduleInfoType; - - // array ops emitted in this module already - AA *arrayfuncs; - - bool isRoot; -#endif -}; - - -struct ModuleDeclaration -{ - Identifier *id; - Identifiers *packages; // array of Identifier's representing packages - bool safe; - - ModuleDeclaration(Identifiers *packages, Identifier *id, bool safe); - - char *toChars(); -}; - -#endif /* DMD_MODULE_H */ diff --git a/dmd2/mtype.c b/dmd2/mtype.c deleted file mode 100644 index c08c650b..00000000 --- a/dmd2/mtype.c +++ /dev/null @@ -1,9323 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/mtype.c -// 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. - -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#define __USE_ISOC99 1 // so signbit() gets defined - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#ifdef __DMC__ -#include -#else -#include -#endif - -#include -#include -#include - -#if _MSC_VER -#include -#include -#include -#elif __DMC__ -#include -#elif __MINGW32__ -#include -#endif - -#include "rmem.h" -#include "port.h" - -#include "dsymbol.h" -#include "mtype.h" -#include "scope.h" -#include "init.h" -#include "expression.h" -#include "attrib.h" -#include "declaration.h" -#include "template.h" -#include "id.h" -#include "enum.h" -#include "import.h" -#include "aggregate.h" -#include "hdrgen.h" - -#if IN_LLVM -//#include "gen/tollvm.h" -Ir* Type::sir = NULL; -unsigned GetTypeAlignment(Ir* ir, Type* t); -#endif - -FuncDeclaration *hasThis(Scope *sc); -void ObjectNotFound(Identifier *id); - - -#define LOGDOTEXP 0 // log ::dotExp() -#define LOGDEFAULTINIT 0 // log ::defaultInit() - -// Allow implicit conversion of T[] to T* -#define IMPLICIT_ARRAY_TO_PTR global.params.useDeprecated - -/* These have default values for 32 bit code, they get - * adjusted for 64 bit code. - */ - -int PTRSIZE = 4; - -/* REALSIZE = size a real consumes in memory - * REALPAD = 'padding' added to the CPU real size to bring it up to REALSIZE - * REALALIGNSIZE = alignment for reals - */ -#if TARGET_OSX -int REALSIZE = 16; -int REALPAD = 6; -int REALALIGNSIZE = 16; -#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS -int REALSIZE = 12; -int REALPAD = 2; -int REALALIGNSIZE = 4; -#else -int REALSIZE = 10; -int REALPAD = 0; -int REALALIGNSIZE = 2; -#endif - -int Tsize_t = Tuns32; -int Tptrdiff_t = Tint32; - -#if _WIN32 && !(defined __MINGW32__ || defined _MSC_VER) -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1/zero; -#endif - -/***************************** Type *****************************/ - -ClassDeclaration *Type::typeinfo; -ClassDeclaration *Type::typeinfoclass; -ClassDeclaration *Type::typeinfointerface; -ClassDeclaration *Type::typeinfostruct; -ClassDeclaration *Type::typeinfotypedef; -ClassDeclaration *Type::typeinfopointer; -ClassDeclaration *Type::typeinfoarray; -ClassDeclaration *Type::typeinfostaticarray; -ClassDeclaration *Type::typeinfoassociativearray; -ClassDeclaration *Type::typeinfovector; -ClassDeclaration *Type::typeinfoenum; -ClassDeclaration *Type::typeinfofunction; -ClassDeclaration *Type::typeinfodelegate; -ClassDeclaration *Type::typeinfotypelist; -ClassDeclaration *Type::typeinfoconst; -ClassDeclaration *Type::typeinfoinvariant; -ClassDeclaration *Type::typeinfoshared; -ClassDeclaration *Type::typeinfowild; - -TemplateDeclaration *Type::associativearray; - -Type *Type::tvoidptr; -Type *Type::tstring; -Type *Type::basic[TMAX]; -unsigned char Type::mangleChar[TMAX]; -unsigned short Type::sizeTy[TMAX]; -StringTable Type::stringtable; - -#if IN_LLVM -StringTable Type::deco_stringtable; -#endif - - -Type::Type(TY ty/*, Type *next*/) -{ - this->ty = ty; - this->mod = 0; - //this->next = next; - this->deco = NULL; -#if DMDV2 - this->cto = NULL; - this->ito = NULL; - this->sto = NULL; - this->scto = NULL; - this->wto = NULL; - this->swto = NULL; -#endif - this->pto = NULL; - this->rto = NULL; - this->arrayof = NULL; - this->vtinfo = NULL; -#if IN_DMD - this->ctype = NULL; -#endif - -#if IN_LLVM - this->irtype = NULL; -#endif -} - -Type *Type::syntaxCopy() -{ - print(); - fprintf(stdmsg, "ty = %d\n", ty); - assert(0); - return this; -} - -int Type::equals(Object *o) -{ Type *t; - - t = (Type *)o; - //printf("Type::equals(%s, %s)\n", toChars(), t->toChars()); - if (this == o || - (t && deco == t->deco) && // deco strings are unique - deco != NULL) // and semantic() has been run - { - //printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 1; - } - //if (deco && t && t->deco) printf("deco = '%s', t->deco = '%s'\n", deco, t->deco); - return 0; -} - -char Type::needThisPrefix() -{ - return 'M'; // name mangling prefix for functions needing 'this' -} - -#if IN_LLVM -void Type::init(Ir* _sir) -#else -void Type::init() -#endif -{ - stringtable.init(1543); -#if IN_LLVM - deco_stringtable.init(); -#endif - Lexer::initKeywords(); - - for (size_t i = 0; i < TMAX; i++) - sizeTy[i] = sizeof(TypeBasic); - sizeTy[Tsarray] = sizeof(TypeSArray); - sizeTy[Tarray] = sizeof(TypeDArray); - sizeTy[Taarray] = sizeof(TypeAArray); - sizeTy[Tpointer] = sizeof(TypePointer); - sizeTy[Treference] = sizeof(TypeReference); - sizeTy[Tfunction] = sizeof(TypeFunction); - sizeTy[Tdelegate] = sizeof(TypeDelegate); - sizeTy[Tident] = sizeof(TypeIdentifier); - sizeTy[Tinstance] = sizeof(TypeInstance); - sizeTy[Ttypeof] = sizeof(TypeTypeof); - sizeTy[Tenum] = sizeof(TypeEnum); - sizeTy[Ttypedef] = sizeof(TypeTypedef); - sizeTy[Tstruct] = sizeof(TypeStruct); - sizeTy[Tclass] = sizeof(TypeClass); - sizeTy[Ttuple] = sizeof(TypeTuple); - sizeTy[Tslice] = sizeof(TypeSlice); - sizeTy[Treturn] = sizeof(TypeReturn); - sizeTy[Terror] = sizeof(TypeError); - sizeTy[Tnull] = sizeof(TypeNull); - - mangleChar[Tarray] = 'A'; - mangleChar[Tsarray] = 'G'; - mangleChar[Taarray] = 'H'; - mangleChar[Tpointer] = 'P'; - mangleChar[Treference] = 'R'; - mangleChar[Tfunction] = 'F'; - mangleChar[Tident] = 'I'; - mangleChar[Tclass] = 'C'; - mangleChar[Tstruct] = 'S'; - mangleChar[Tenum] = 'E'; - mangleChar[Ttypedef] = 'T'; - mangleChar[Tdelegate] = 'D'; - - mangleChar[Tnone] = 'n'; - mangleChar[Tvoid] = 'v'; - mangleChar[Tint8] = 'g'; - mangleChar[Tuns8] = 'h'; - mangleChar[Tint16] = 's'; - mangleChar[Tuns16] = 't'; - mangleChar[Tint32] = 'i'; - mangleChar[Tuns32] = 'k'; - mangleChar[Tint64] = 'l'; - mangleChar[Tuns64] = 'm'; - mangleChar[Tfloat32] = 'f'; - mangleChar[Tfloat64] = 'd'; - mangleChar[Tfloat80] = 'e'; - - mangleChar[Timaginary32] = 'o'; - mangleChar[Timaginary64] = 'p'; - mangleChar[Timaginary80] = 'j'; - mangleChar[Tcomplex32] = 'q'; - mangleChar[Tcomplex64] = 'r'; - mangleChar[Tcomplex80] = 'c'; - - mangleChar[Tbool] = 'b'; - mangleChar[Tascii] = 'a'; - mangleChar[Twchar] = 'u'; - mangleChar[Tdchar] = 'w'; - - // '@' shouldn't appear anywhere in the deco'd names - mangleChar[Tinstance] = '@'; - mangleChar[Terror] = '@'; - mangleChar[Ttypeof] = '@'; - mangleChar[Ttuple] = 'B'; - mangleChar[Tslice] = '@'; - mangleChar[Treturn] = '@'; - mangleChar[Tvector] = '@'; - - mangleChar[Tnull] = 'n'; // same as TypeNone - - for (size_t i = 0; i < TMAX; i++) - { if (!mangleChar[i]) - fprintf(stdmsg, "ty = %zd\n", i); - assert(mangleChar[i]); - } - - // Set basic types - static TY basetab[] = - { Tvoid, Tint8, Tuns8, Tint16, Tuns16, Tint32, Tuns32, Tint64, Tuns64, - Tfloat32, Tfloat64, Tfloat80, - Timaginary32, Timaginary64, Timaginary80, - Tcomplex32, Tcomplex64, Tcomplex80, - Tbool, - Tascii, Twchar, Tdchar }; - - for (size_t i = 0; i < sizeof(basetab) / sizeof(basetab[0]); i++) - { Type *t = new TypeBasic(basetab[i]); - t = t->merge(); - basic[basetab[i]] = t; - } - basic[Terror] = new TypeError(); - - tnull = new TypeNull(); - tnull->deco = tnull->merge()->deco; - - tvoidptr = tvoid->pointerTo(); - tstring = tchar->invariantOf()->arrayOf(); - - // LDC - sir = _sir; - - // set size_t / ptrdiff_t types and pointer size - if (global.params.is64bit) - { - Tsize_t = Tuns64; - Tptrdiff_t = Tint64; - PTRSIZE = 8; - } - else - { - PTRSIZE = 4; -#if TARGET_OSX - REALSIZE = 16; - REALPAD = 6; -#elif TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - REALSIZE = 12; - REALPAD = 2; -#else - REALSIZE = 10; - REALPAD = 0; -#endif - Tsize_t = Tuns32; - Tptrdiff_t = Tint32; - PTRSIZE = 4; - } - - // set real size and padding - if (global.params.cpu == ARCHx86) - { - REALSIZE = 12; - REALPAD = 2; - } - else if (global.params.cpu == ARCHx86_64) - { - REALSIZE = 16; - REALPAD = 6; - } - else - { - REALSIZE = 8; - REALPAD = 0; - } -} - -d_uns64 Type::size() -{ - return size(0); -} - -d_uns64 Type::size(Loc loc) -{ - error(loc, "no size for type %s", toChars()); - return 1; -} - -unsigned Type::alignsize() -{ - return size(0); -} - -Type *Type::semantic(Loc loc, Scope *sc) -{ - return merge(); -} - -Type *Type::trySemantic(Loc loc, Scope *sc) -{ - //printf("+trySemantic(%s) %d\n", toChars(), global.errors); - unsigned errors = global.startGagging(); - Type *t = semantic(loc, sc); - if (global.endGagging(errors)) // if any errors happened - { - t = NULL; - } - //printf("-trySemantic(%s) %d\n", toChars(), global.errors); - return t; -} - -/******************************** - * Convert to 'const'. - */ - -Type *Type::constOf() -{ - //printf("Type::constOf() %p %s\n", this, toChars()); - if (mod == MODconst) - return this; - if (cto) - { assert(cto->mod == MODconst); - return cto; - } - Type *t = makeConst(); - t = t->merge(); - t->fixTo(this); - //printf("-Type::constOf() %p %s\n", t, t->toChars()); - return t; -} - -/******************************** - * Convert to 'immutable'. - */ - -Type *Type::invariantOf() -{ - //printf("Type::invariantOf() %p %s\n", this, toChars()); - if (isImmutable()) - { - return this; - } - if (ito) - { - assert(ito->isImmutable()); - return ito; - } - Type *t = makeInvariant(); - t = t->merge(); - t->fixTo(this); - //printf("\t%p\n", t); - return t; -} - -/******************************** - * Make type mutable. - */ - -Type *Type::mutableOf() -{ - //printf("Type::mutableOf() %p, %s\n", this, toChars()); - Type *t = this; - if (isConst()) - { if (isShared()) - t = sto; // shared const => shared - else - t = cto; // const => naked - assert(!t || t->isMutable()); - } - else if (isImmutable()) - { t = ito; // immutable => naked - assert(!t || (t->isMutable() && !t->isShared())); - } - else if (isWild()) - { - if (isShared()) - t = sto; // shared wild => shared - else - t = wto; // wild => naked - assert(!t || t->isMutable()); - } - if (!t) - { - t = makeMutable(); - t = t->merge(); - t->fixTo(this); - } - assert(t->isMutable()); - return t; -} - -Type *Type::sharedOf() -{ - //printf("Type::sharedOf() %p, %s\n", this, toChars()); - if (mod == MODshared) - { - return this; - } - if (sto) - { - assert(sto->isShared()); - return sto; - } - Type *t = makeShared(); - t = t->merge(); - t->fixTo(this); - //printf("\t%p\n", t); - return t; -} - -Type *Type::sharedConstOf() -{ - //printf("Type::sharedConstOf() %p, %s\n", this, toChars()); - if (mod == (MODshared | MODconst)) - { - return this; - } - if (scto) - { - assert(scto->mod == (MODshared | MODconst)); - return scto; - } - Type *t = makeSharedConst(); - t = t->merge(); - t->fixTo(this); - //printf("\t%p\n", t); - return t; -} - - -/******************************** - * Make type unshared. - * 0 => 0 - * const => const - * immutable => immutable - * shared => 0 - * shared const => const - * wild => wild - * shared wild => wild - */ - -Type *Type::unSharedOf() -{ - //printf("Type::unSharedOf() %p, %s\n", this, toChars()); - Type *t = this; - - if (isShared()) - { - if (isConst()) - t = cto; // shared const => const - else if (isWild()) - t = wto; // shared wild => wild - else - t = sto; - assert(!t || !t->isShared()); - } - - if (!t) - { - unsigned sz = sizeTy[ty]; - t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = mod & ~MODshared; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; - t = t->merge(); - - t->fixTo(this); - } - assert(!t->isShared()); - return t; -} - -/******************************** - * Convert to 'wild'. - */ - -Type *Type::wildOf() -{ - //printf("Type::wildOf() %p %s\n", this, toChars()); - if (mod == MODwild) - { - return this; - } - if (wto) - { - assert(wto->isWild()); - return wto; - } - Type *t = makeWild(); - t = t->merge(); - t->fixTo(this); - //printf("\t%p %s\n", t, t->toChars()); - return t; -} - -Type *Type::sharedWildOf() -{ - //printf("Type::sharedWildOf() %p, %s\n", this, toChars()); - if (mod == (MODshared | MODwild)) - { - return this; - } - if (swto) - { - assert(swto->mod == (MODshared | MODwild)); - return swto; - } - Type *t = makeSharedWild(); - t = t->merge(); - t->fixTo(this); - //printf("\t%p\n", t); - return t; -} - -/********************************** - * For our new type 'this', which is type-constructed from t, - * fill in the cto, ito, sto, scto, wto shortcuts. - */ - -void Type::fixTo(Type *t) -{ - ito = t->ito; -#if 0 - /* Cannot do these because these are not fully transitive: - * there can be a shared ptr to immutable, for example. - * Immutable subtypes are always immutable, though. - */ - cto = t->cto; - sto = t->sto; - scto = t->scto; -#endif - - assert(mod != t->mod); -#define X(m, n) (((m) << 4) | (n)) - switch (X(mod, t->mod)) - { - case X(0, MODconst): - cto = t; - break; - - case X(0, MODimmutable): - ito = t; - break; - - case X(0, MODshared): - sto = t; - break; - - case X(0, MODshared | MODconst): - scto = t; - break; - - case X(0, MODwild): - wto = t; - break; - - case X(0, MODshared | MODwild): - swto = t; - break; - - - case X(MODconst, 0): - cto = NULL; - goto L2; - - case X(MODconst, MODimmutable): - ito = t; - goto L2; - - case X(MODconst, MODshared): - sto = t; - goto L2; - - case X(MODconst, MODshared | MODconst): - scto = t; - goto L2; - - case X(MODconst, MODwild): - wto = t; - goto L2; - - case X(MODconst, MODshared | MODwild): - swto = t; - L2: - t->cto = this; - break; - - - case X(MODimmutable, 0): - ito = NULL; - goto L3; - - case X(MODimmutable, MODconst): - cto = t; - goto L3; - - case X(MODimmutable, MODshared): - sto = t; - goto L3; - - case X(MODimmutable, MODshared | MODconst): - scto = t; - goto L3; - - case X(MODimmutable, MODwild): - wto = t; - goto L3; - - case X(MODimmutable, MODshared | MODwild): - swto = t; - L3: - t->ito = this; - if (t->cto) t->cto->ito = this; - if (t->sto) t->sto->ito = this; - if (t->scto) t->scto->ito = this; - if (t->wto) t->wto->ito = this; - if (t->swto) t->swto->ito = this; - break; - - - case X(MODshared, 0): - sto = NULL; - goto L4; - - case X(MODshared, MODconst): - cto = t; - goto L4; - - case X(MODshared, MODimmutable): - ito = t; - goto L4; - - case X(MODshared, MODshared | MODconst): - scto = t; - goto L4; - - case X(MODshared, MODwild): - wto = t; - goto L4; - - case X(MODshared, MODshared | MODwild): - swto = t; - L4: - t->sto = this; - break; - - - case X(MODshared | MODconst, 0): - scto = NULL; - goto L5; - - case X(MODshared | MODconst, MODconst): - cto = t; - goto L5; - - case X(MODshared | MODconst, MODimmutable): - ito = t; - goto L5; - - case X(MODshared | MODconst, MODwild): - wto = t; - goto L5; - - case X(MODshared | MODconst, MODshared): - sto = t; - goto L5; - - case X(MODshared | MODconst, MODshared | MODwild): - swto = t; - L5: - t->scto = this; - break; - - - case X(MODwild, 0): - wto = NULL; - goto L6; - - case X(MODwild, MODconst): - cto = t; - goto L6; - - case X(MODwild, MODimmutable): - ito = t; - goto L6; - - case X(MODwild, MODshared): - sto = t; - goto L6; - - case X(MODwild, MODshared | MODconst): - scto = t; - goto L6; - - case X(MODwild, MODshared | MODwild): - swto = t; - L6: - t->wto = this; - break; - - - case X(MODshared | MODwild, 0): - swto = NULL; - goto L7; - - case X(MODshared | MODwild, MODconst): - cto = t; - goto L7; - - case X(MODshared | MODwild, MODimmutable): - ito = t; - goto L7; - - case X(MODshared | MODwild, MODshared): - sto = t; - goto L7; - - case X(MODshared | MODwild, MODshared | MODconst): - scto = t; - goto L7; - - case X(MODshared | MODwild, MODwild): - wto = t; - L7: - t->swto = this; - break; - - - default: - assert(0); - } -#undef X - - check(); - t->check(); - //printf("fixTo: %s, %s\n", toChars(), t->toChars()); -} - -/*************************** - * Look for bugs in constructing types. - */ - -void Type::check() -{ - switch (mod) - { - case 0: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODconst: - if (cto) assert(cto->mod == 0); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODimmutable: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == 0); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODshared: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == 0); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODshared | MODconst: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == 0); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODwild: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == 0); - if (swto) assert(swto->mod == (MODshared | MODwild)); - break; - - case MODshared | MODwild: - if (cto) assert(cto->mod == MODconst); - if (ito) assert(ito->mod == MODimmutable); - if (sto) assert(sto->mod == MODshared); - if (scto) assert(scto->mod == (MODshared | MODconst)); - if (wto) assert(wto->mod == MODwild); - if (swto) assert(swto->mod == 0); - break; - - default: - assert(0); - } - - Type *tn = nextOf(); - if (tn && ty != Tfunction && tn->ty != Tfunction) - { // Verify transitivity - switch (mod) - { - case 0: - break; - - case MODconst: - assert(tn->mod & MODimmutable || tn->mod & MODconst); - break; - - case MODimmutable: - assert(tn->mod == MODimmutable); - break; - - case MODshared: - assert(tn->mod & MODimmutable || tn->mod & MODshared); - break; - - case MODshared | MODconst: - assert(tn->mod & MODimmutable || tn->mod & (MODshared | MODconst)); - break; - - case MODwild: - assert(tn->mod); - break; - - case MODshared | MODwild: - assert(tn->mod == MODimmutable || tn->mod == (MODshared | MODconst) || tn->mod == (MODshared | MODwild)); - break; - - default: - assert(0); - } - tn->check(); - } -} - -Type *Type::makeConst() -{ - //printf("Type::makeConst() %p, %s\n", this, toChars()); - if (cto) - return cto; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODconst; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - //printf("-Type::makeConst() %p, %s\n", t, toChars()); - return t; -} - -Type *Type::makeInvariant() -{ - if (ito) - return ito; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODimmutable; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -Type *Type::makeShared() -{ - if (sto) - return sto; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODshared; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -Type *Type::makeSharedConst() -{ - if (scto) - return scto; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODshared | MODconst; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -Type *Type::makeWild() -{ - if (wto) - return wto; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODwild; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -Type *Type::makeSharedWild() -{ - if (swto) - return swto; - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = MODshared | MODwild; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -Type *Type::makeMutable() -{ - unsigned sz = sizeTy[ty]; - Type *t = (Type *)mem.malloc(sz); - memcpy(t, this, sz); - t->mod = mod & MODshared; - t->deco = NULL; - t->arrayof = NULL; - t->pto = NULL; - t->rto = NULL; - t->cto = NULL; - t->ito = NULL; - t->sto = NULL; - t->scto = NULL; - t->wto = NULL; - t->swto = NULL; - t->vtinfo = NULL; -#if IN_DMD - t->ctype = NULL; -#endif - return t; -} - -/************************************* - * Apply STCxxxx bits to existing type. - * Use *before* semantic analysis is run. - */ - -Type *Type::addSTC(StorageClass stc) -{ Type *t = this; - - if (stc & STCconst) - { if (t->isShared()) - t = t->makeSharedConst(); - else - t = t->makeConst(); - } - if (stc & STCimmutable) - t = t->makeInvariant(); - if (stc & STCshared) - { if (t->isConst()) - t = t->makeSharedConst(); - else - t = t->makeShared(); - } - if (stc & STCwild) - { if (t->isShared()) - t = t->makeSharedWild(); - else - t = t->makeWild(); - } - return t; -} - -/************************************ - * Apply MODxxxx bits to existing type. - */ - -Type *Type::castMod(unsigned mod) -{ Type *t; - - switch (mod) - { - case 0: - t = unSharedOf()->mutableOf(); - break; - - case MODconst: - t = unSharedOf()->constOf(); - break; - - case MODimmutable: - t = invariantOf(); - break; - - case MODshared: - t = mutableOf()->sharedOf(); - break; - - case MODshared | MODconst: - t = sharedConstOf(); - break; - - case MODwild: - t = unSharedOf()->wildOf(); - break; - - case MODshared | MODwild: - t = sharedWildOf(); - break; - - default: - assert(0); - } - return t; -} - -/************************************ - * Add MODxxxx bits to existing type. - * We're adding, not replacing, so adding const to - * a shared type => "shared const" - */ - -Type *Type::addMod(unsigned mod) -{ Type *t = this; - - /* Add anything to immutable, and it remains immutable - */ - if (!t->isImmutable()) - { - //printf("addMod(%x) %s\n", mod, toChars()); - switch (mod) - { - case 0: - break; - - case MODconst: - if (isShared()) - t = sharedConstOf(); - else - t = constOf(); - break; - - case MODimmutable: - t = invariantOf(); - break; - - case MODshared: - if (isConst()) - t = sharedConstOf(); - else if (isWild()) - t = sharedWildOf(); - else - t = sharedOf(); - break; - - case MODshared | MODconst: - t = sharedConstOf(); - break; - - case MODwild: - if (isConst()) - ; - else if (isShared()) - t = sharedWildOf(); - else - t = wildOf(); - break; - - case MODshared | MODwild: - if (isConst()) - t = sharedConstOf(); - else - t = sharedWildOf(); - break; - - default: - assert(0); - } - } - return t; -} - -/************************************ - * Add storage class modifiers to type. - */ - -Type *Type::addStorageClass(StorageClass stc) -{ - /* Just translate to MOD bits and let addMod() do the work - */ - unsigned mod = 0; - - if (stc & STCimmutable) - mod = MODimmutable; - else - { if (stc & (STCconst | STCin)) - mod = MODconst; - else if (stc & STCwild) // const takes precedence over wild - mod |= MODwild; - if (stc & STCshared) - mod |= MODshared; - } - return addMod(mod); -} - -Type *Type::pointerTo() -{ - if (ty == Terror) - return this; - if (!pto) - { Type *t; - - t = new TypePointer(this); - pto = t->merge(); - } - return pto; -} - -Type *Type::referenceTo() -{ - if (ty == Terror) - return this; - if (!rto) - { Type *t; - - t = new TypeReference(this); - rto = t->merge(); - } - return rto; -} - -Type *Type::arrayOf() -{ - if (ty == Terror) - return this; - if (!arrayof) - { Type *t; - - t = new TypeDArray(this); - arrayof = t->merge(); - } - return arrayof; -} - -Type *Type::aliasthisOf() -{ - AggregateDeclaration *ad = NULL; - if (ty == Tclass) - { - ad = ((TypeClass *)this)->sym; - goto L1; - } - else if (ty == Tstruct) - { - ad = ((TypeStruct *)this)->sym; - L1: - if (!ad->aliasthis) - return NULL; - - Declaration *d = ad->aliasthis->isDeclaration(); - if (d) - { assert(d->type); - Type *t = d->type; - if (d->isVarDeclaration() && d->needThis()) - { - t = t->addMod(this->mod); - } - else if (d->isFuncDeclaration()) - { - FuncDeclaration *fd = (FuncDeclaration *)d; - Expression *ethis = this->defaultInit(0); - fd = fd->overloadResolve(0, ethis, NULL); - if (fd) - t = ((TypeFunction *)fd->type)->next; - } - return t; - } - EnumDeclaration *ed = ad->aliasthis->isEnumDeclaration(); - if (ed) - { - Type *t = ed->type; - return t; - } - //printf("%s\n", ad->aliasthis->kind()); - } - return NULL; -} - -Dsymbol *Type::toDsymbol(Scope *sc) -{ - return NULL; -} - -/******************************* - * If this is a shell around another type, - * get that other type. - */ - -Type *Type::toBasetype() -{ - return this; -} - -/*************************** - * Return !=0 if modfrom can be implicitly converted to modto - */ -int MODimplicitConv(unsigned char modfrom, unsigned char modto) -{ - if (modfrom == modto) - return 1; - - //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto); - #define X(m, n) (((m) << 4) | (n)) - switch (X(modfrom, modto)) - { - case X(0, MODconst): - case X(MODimmutable, MODconst): - case X(MODwild, MODconst): - case X(MODimmutable, MODconst | MODshared): - case X(MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - return 1; - - default: - return 0; - } - #undef X -} - -/*************************** - * Return !=0 if a method of type '() modfrom' can call a method of type '() modto'. - */ -int MODmethodConv(unsigned char modfrom, unsigned char modto) -{ - if (MODimplicitConv(modfrom, modto)) - return 1; - - #define X(m, n) (((m) << 4) | (n)) - switch (X(modfrom, modto)) - { - case X(0, MODwild): - case X(MODimmutable, MODwild): - case X(MODconst, MODwild): - case X(MODshared, MODshared|MODwild): - case X(MODshared|MODimmutable, MODshared|MODwild): - case X(MODshared|MODconst, MODshared|MODwild): - return 1; - - default: - return 0; - } - #undef X -} - -/*************************** - * Merge mod bits to form common mod. - */ -int MODmerge(unsigned char mod1, unsigned char mod2) -{ - if (mod1 == mod2) - return mod1; - - //printf("MODmerge(1 = %x, 2 = %x)\n", modfrom, modto); - #define X(m, n) (((m) << 4) | (n)) - // cases are commutative - #define Y(m, n) X(m, n): case X(n, m) - switch (X(mod1, mod2)) - { -#if 0 - case X(0, 0): - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODshared | MODconst, MODshared | MODconst): - case X(MODwild, MODwild): - case X(MODshared | MODwild, MODshared | MODwild): -#endif - - case Y(0, MODconst): - case Y(0, MODimmutable): - case Y(MODconst, MODimmutable): - case Y(MODconst, MODwild): - case Y(0, MODwild): - case Y(MODimmutable, MODwild): - return MODconst; - - case Y(0, MODshared): - return MODshared; - - case Y(0, MODshared | MODconst): - case Y(MODconst, MODshared): - case Y(MODconst, MODshared | MODconst): - case Y(MODimmutable, MODshared): - case Y(MODimmutable, MODshared | MODconst): - case Y(MODshared, MODshared | MODconst): - case Y(0, MODshared | MODwild): - case Y(MODconst, MODshared | MODwild): - case Y(MODimmutable, MODshared | MODwild): - case Y(MODshared, MODwild): - case Y(MODshared, MODshared | MODwild): - case Y(MODshared | MODconst, MODwild): - case Y(MODshared | MODconst, MODshared | MODwild): - return MODshared | MODconst; - - case Y(MODwild, MODshared | MODwild): - return MODshared | MODwild; - - default: - assert(0); - } - #undef Y - #undef X - assert(0); - return 0; -} - -/********************************* - * Mangling for mod. - */ -void MODtoDecoBuffer(OutBuffer *buf, unsigned char mod) -{ - switch (mod) - { case 0: - break; - case MODconst: - buf->writeByte('x'); - break; - case MODimmutable: - buf->writeByte('y'); - break; - case MODshared: - buf->writeByte('O'); - break; - case MODshared | MODconst: - buf->writestring("Ox"); - break; - case MODwild: - buf->writestring("Ng"); - break; - case MODshared | MODwild: - buf->writestring("ONg"); - break; - default: - assert(0); - } -} - -/********************************* - * Name for mod. - */ -void MODtoBuffer(OutBuffer *buf, unsigned char mod) -{ - switch (mod) - { case 0: - break; - - case MODimmutable: - buf->writestring(Token::tochars[TOKimmutable]); - break; - - case MODshared: - buf->writestring(Token::tochars[TOKshared]); - break; - - case MODshared | MODconst: - buf->writestring(Token::tochars[TOKshared]); - buf->writeByte(' '); - case MODconst: - buf->writestring(Token::tochars[TOKconst]); - break; - - case MODshared | MODwild: - buf->writestring(Token::tochars[TOKshared]); - buf->writeByte(' '); - case MODwild: - buf->writestring(Token::tochars[TOKwild]); - break; - default: - assert(0); - } -} - -/******************************** - * Name mangling. - * Input: - * flag 0x100 do not do const/invariant - */ - -void Type::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) // Possible conflict from merge -{ - if (flag != mod && flag != 0x100) - { - MODtoDecoBuffer(buf, mod); - } - buf->writeByte(mangleChar[ty]); -} - -/******************************** - * For pretty-printing a type. - */ - -char *Type::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, NULL, &hgs); - return buf->toChars(); -} - -void Type::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - toCBuffer2(buf, hgs, 0); - if (ident) - { buf->writeByte(' '); - buf->writestring(ident->toChars()); - } -} - -void Type::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(toChars()); -} - -void Type::toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { - if (!(mod & MODshared) && (this->mod & MODshared)) - { - MODtoBuffer(buf, this->mod & MODshared); - buf->writeByte('('); - } - int m1 = this->mod & ~MODshared; - int m2 = (mod ^ m1) & m1; - if (m2) - { - MODtoBuffer(buf, m2); - buf->writeByte('('); - toCBuffer2(buf, hgs, this->mod); - buf->writeByte(')'); - } - else - toCBuffer2(buf, hgs, this->mod); - if (!(mod & MODshared) && (this->mod & MODshared)) - { - buf->writeByte(')'); - } - } -} - -void Type::modToBuffer(OutBuffer *buf) -{ - if (mod) - { - buf->writeByte(' '); - MODtoBuffer(buf, mod); - } -} - -/************************************ - */ - -Type *Type::merge() -{ - if (ty == Terror) return this; - if (ty == Ttypeof) return this; - if (ty == Tident) return this; - if (ty == Tinstance) return this; - if (nextOf() && !nextOf()->merge()->deco) - return this; - - //printf("merge(%s)\n", toChars()); - Type *t = this; - assert(t); - if (!deco) - { - OutBuffer buf; - StringValue *sv; - - //if (next) - //next = next->merge(); - toDecoBuffer(&buf, 0, false); - sv = stringtable.update((char *)buf.data, buf.offset); - if (sv->ptrvalue) - { t = (Type *) sv->ptrvalue; -#ifdef DEBUG - if (!t->deco) - printf("t = %s\n", t->toChars()); -#endif - assert(t->deco); - //printf("old value, deco = '%s' %p\n", t->deco, t->deco); - } - else - { - sv->ptrvalue = this; - - // we still need deco strings to be unique - // or Type::equals fails, which breaks a bunch of stuff, - // like covariant member function overloads. - OutBuffer mangle; - toDecoBuffer(&mangle, 0, true); - StringValue* sv2 = deco_stringtable.update((char *)mangle.data, mangle.offset); - if (sv2->ptrvalue) - { Type* t2 = (Type *) sv2->ptrvalue; - assert(t2->deco); - deco = t2->deco; - } - else - { - sv2->ptrvalue = this; - deco = (char *)sv2->lstring.string; - } - //printf("new value, deco = '%s' %p\n", t->deco, t->deco); - } - } - return t; -} - -/************************************* - * This version does a merge even if the deco is already computed. - * Necessary for types that have a deco, but are not merged. - */ -Type *Type::merge2() -{ - //printf("merge2(%s)\n", toChars()); - Type *t = this; - assert(t); - if (!t->deco) - return t->merge(); - - StringValue *sv = deco_stringtable.lookup((char *)t->deco, strlen(t->deco)); - if (sv && sv->ptrvalue) - { t = (Type *) sv->ptrvalue; - assert(t->deco); - } - else - assert(0); - return t; -} - -int Type::isintegral() -{ - return FALSE; -} - -int Type::isfloating() -{ - return FALSE; -} - -int Type::isreal() -{ - return FALSE; -} - -int Type::isimaginary() -{ - return FALSE; -} - -int Type::iscomplex() -{ - return FALSE; -} - -int Type::isscalar() -{ - return FALSE; -} - -int Type::isunsigned() -{ - return FALSE; -} - -ClassDeclaration *Type::isClassHandle() -{ - return NULL; -} - -int Type::isscope() -{ - return FALSE; -} - -int Type::isString() -{ - return FALSE; -} - -/************************** - * Given: - * T a, b; - * Can we assign: - * a = b; - * ? - */ -int Type::isAssignable() -{ - return TRUE; -} - -int Type::checkBoolean() -{ - return isscalar(); -} - -/******************************** - * TRUE if when type goes out of scope, it needs a destructor applied. - * Only applies to value types, not ref types. - */ -int Type::needsDestruction() -{ - return FALSE; -} - -/********************************* - * Check type to see if it is based on a deprecated symbol. - */ - -void Type::checkDeprecated(Loc loc, Scope *sc) -{ - Dsymbol *s = toDsymbol(sc); - - if (s) - s->checkDeprecated(loc, sc); -} - - -Expression *Type::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("Type::defaultInit() '%s'\n", toChars()); -#endif - return NULL; -} - -/*************************************** - * Use when we prefer the default initializer to be a literal, - * rather than a global immutable variable. - */ -Expression *Type::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("Type::defaultInitLiteral() '%s'\n", toChars()); -#endif - return defaultInit(loc); -} - -int Type::isZeroInit(Loc loc) -{ - return 0; // assume not -} - -int Type::isBaseOf(Type *t, int *poffset) -{ - return 0; // assume not -} - -/******************************** - * Determine if 'this' can be implicitly converted - * to type 'to'. - * Returns: - * MATCHnomatch, MATCHconvert, MATCHconst, MATCHexact - */ - -MATCH Type::implicitConvTo(Type *to) -{ - //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to->toChars()); - if (this == to) - return MATCHexact; -#if IN_LLVM - if (deco == to->deco) - return MATCHexact; -#endif - return MATCHnomatch; -} - -/******************************* - * Determine if converting 'this' to 'to' is an identity operation, - * a conversion to const operation, or the types aren't the same. - * Returns: - * MATCHexact 'this' == 'to' - * MATCHconst 'to' is const - * MATCHnomatch conversion to mutable or invariant - */ - -MATCH Type::constConv(Type *to) -{ - //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to->toChars()); - if (equals(to)) - return MATCHexact; - if (ty == to->ty && MODimplicitConv(mod, to->mod)) - return MATCHconst; - return MATCHnomatch; -} - -/*************************************** - * Return MOD bits matching this type to wild parameter type (tprm). - */ - -unsigned Type::wildConvTo(Type *tprm) -{ - //printf("Type::wildConvTo this = '%s', tprm = '%s'\n", toChars(), tprm->toChars()); - - if (tprm->isWild() && implicitConvTo(tprm->substWildTo(MODconst))) - { - if (isWild()) - return MODwild; - else if (isConst()) - return MODconst; - else if (isImmutable()) - return MODimmutable; - else if (isMutable()) - return MODmutable; - else - assert(0); - } - return 0; -} - -Type *Type::substWildTo(unsigned mod) -{ - //printf("+Type::substWildTo this = %s, mod = x%x\n", toChars(), mod); - Type *t; - - if (nextOf()) - { - t = nextOf()->substWildTo(mod); - if (t == nextOf()) - t = this; - else - { - if (ty == Tpointer) - t = t->pointerTo(); - else if (ty == Tarray) - t = t->arrayOf(); - else if (ty == Tsarray) - t = new TypeSArray(t, ((TypeSArray *)this)->dim->syntaxCopy()); - else if (ty == Taarray) - { - t = new TypeAArray(t, ((TypeAArray *)this)->index->syntaxCopy()); - t = t->merge(); - } - else - assert(0); - - t = t->addMod(this->mod); - } - } - else - t = this; - - if (isWild()) - { - if (mod & MODconst) - t = isShared() ? t->sharedConstOf() : t->constOf(); - else if (mod & MODimmutable) - t = t->invariantOf(); - else if (mod & MODwild) - t = isShared() ? t->sharedWildOf() : t->wildOf(); - else - t = isShared() ? t->sharedOf() : t->mutableOf(); - } - - //printf("-Type::substWildTo t = %s\n", t->toChars()); - return t; -} - -/************************** - * Return type with the top level of it being mutable. - */ -Type *Type::toHeadMutable() -{ - if (!mod) - return this; - return mutableOf(); -} - -Expression *Type::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - -#if LOGDOTEXP - printf("Type::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars()); -#endif - if (ident == Id::__sizeof) - { - e = new IntegerExp(loc, size(loc), Type::tsize_t); - } - else if (ident == Id::size) - { - error(loc, ".size property should be replaced with .sizeof"); - e = new ErrorExp(); - } - else if (ident == Id::__xalignof) - { - e = new IntegerExp(loc, alignsize(), Type::tsize_t); - } - else if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(NULL); - } - else if (ident == Id::init) - { - if (ty == Tvoid) - error(loc, "void does not have an initializer"); - if (ty == Tfunction) - error(loc, "function does not have an initializer"); - e = defaultInitLiteral(loc); - } - else if (ident == Id::mangleof) - { const char *s; - if (!deco) - { s = toChars(); - error(loc, "forward reference of type %s.mangleof", s); - } - else - s = deco; - e = new StringExp(loc, (char *)s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else - { - Dsymbol *s = NULL; - if (ty == Tstruct || ty == Tclass || ty == Tenum || ty == Ttypedef) - s = toDsymbol(NULL); - if (s) - s = s->search_correct(ident); - if (this != Type::terror) - { - if (s) - error(loc, "no property '%s' for type '%s', did you mean '%s'?", ident->toChars(), toChars(), s->toChars()); - else - error(loc, "no property '%s' for type '%s'", ident->toChars(), toChars()); - } - e = new ErrorExp(); - } - return e; -} - -Expression *Type::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ VarDeclaration *v = NULL; - -#if LOGDOTEXP - printf("Type::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (e->op == TOKdotvar) - { - DotVarExp *dv = (DotVarExp *)e; - v = dv->var->isVarDeclaration(); - } - else if (e->op == TOKvar) - { - VarExp *ve = (VarExp *)e; - v = ve->var->isVarDeclaration(); - } - if (v) - { - if (ident == Id::offset) - { - if (!global.params.useDeprecated) - error(e->loc, ".offset deprecated, use .offsetof"); - goto Loffset; - } - else if (ident == Id::offsetof) - { - Loffset: - if (v->storage_class & STCfield) - { - e = new IntegerExp(e->loc, v->offset, Type::tsize_t); - return e; - } - } - else if (ident == Id::init) - { -#if 0 - if (v->init) - { - if (v->init->isVoidInitializer()) - error(e->loc, "%s.init is void", v->toChars()); - else - { Loc loc = e->loc; - e = v->init->toExpression(); - if (e->op == TOKassign || e->op == TOKconstruct || e->op == TOKblit) - { - e = ((AssignExp *)e)->e2; - - /* Take care of case where we used a 0 - * to initialize the struct. - */ - if (e->type == Type::tint32 && - e->isBool(0) && - v->type->toBasetype()->ty == Tstruct) - { - e = v->type->defaultInit(e->loc); - } - } - e = e->optimize(WANTvalue | WANTinterpret); -// if (!e->isConst()) -// error(loc, ".init cannot be evaluated at compile time"); - } - goto Lreturn; - } -#endif - e = defaultInitLiteral(e->loc); - goto Lreturn; - } - } - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - e = getTypeInfo(sc); - } - else if (ident == Id::stringof) - { /* Bugzilla 3796: this should demangle e->type->deco rather than - * pretty-printing the type. - */ - char *s = e->toChars(); - e = new StringExp(e->loc, s, strlen(s), 'c'); - } - else - e = getProperty(e->loc, ident); - -Lreturn: - e = e->semantic(sc); - return e; -} - -/*************************************** - * Figures out what to do with an undefined member reference - * for classes and structs. - */ -Expression *Type::noMember(Scope *sc, Expression *e, Identifier *ident) -{ - assert(ty == Tstruct || ty == Tclass); - AggregateDeclaration *sym = toDsymbol(sc)->isAggregateDeclaration(); - assert(sym); - - if (ident != Id::__sizeof && - ident != Id::__xalignof && - ident != Id::init && - ident != Id::mangleof && - ident != Id::stringof && - ident != Id::offsetof) - { - /* Look for overloaded opDot() to see if we should forward request - * to it. - */ - Dsymbol *fd = search_function(sym, Id::opDot); - if (fd) - { /* Rewrite e.ident as: - * e.opDot().ident - */ - e = build_overload(e->loc, sc, e, NULL, fd); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - - /* Look for overloaded opDispatch to see if we should forward request - * to it. - */ - fd = search_function(sym, Id::opDispatch); - if (fd) - { - /* Rewrite e.ident as: - * e.opDispatch!("ident") - */ - TemplateDeclaration *td = fd->isTemplateDeclaration(); - if (!td) - { - fd->error("must be a template opDispatch(string s), not a %s", fd->kind()); - return new ErrorExp(); - } - StringExp *se = new StringExp(e->loc, ident->toChars()); - Objects *tiargs = new Objects(); - tiargs->push(se); - e = new DotTemplateInstanceExp(e->loc, e, Id::opDispatch, tiargs); - ((DotTemplateInstanceExp *)e)->ti->tempdecl = td; - //return e; - e = e->semantic(sc); - return e; - } - - /* See if we should forward to the alias this. - */ - if (sym->aliasthis) - { /* Rewrite e.ident as: - * e.aliasthis.ident - */ - e = new DotIdExp(e->loc, e, sym->aliasthis->ident); - e = new DotIdExp(e->loc, e, ident); - return e->semantic(sc); - } - } - - return Type::dotExp(sc, e, ident); -} - -unsigned Type::memalign(unsigned salign) -{ - return salign; -} - -void Type::error(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Type::warning(Loc loc, const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); -} - -Identifier *Type::getTypeInfoIdent(int internal) -{ - // _init_10TypeInfo_%s - OutBuffer buf; - Identifier *id; - char *name; - int len; - - if (internal) - { buf.writeByte(mangleChar[ty]); - if (ty == Tarray) - buf.writeByte(mangleChar[((TypeArray *)this)->next->ty]); - } - else - toDecoBuffer(&buf, 0, true); - len = buf.offset; - name = (char *)alloca(19 + sizeof(len) * 3 + len + 1); - buf.writeByte(0); -#if TARGET_OSX - // The LINKc will prepend the _ - sprintf(name, "D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -#else - sprintf(name, "_D%dTypeInfo_%s6__initZ", 9 + len, buf.data); -#endif -// LDC -// it is not clear where the underscore that's stripped here is added back in -// if (global.params.isWindows) -// name++; // C mangling will add it back in - //printf("name = %s\n", name); - id = Lexer::idPool(name); - return id; -} - -TypeBasic *Type::isTypeBasic() -{ - return NULL; -} - - -void Type::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("Type::resolve() %s, %d\n", toChars(), ty); - Type *t = semantic(loc, sc); - *pt = t; - *pe = NULL; - *ps = NULL; -} - -/******************************* - * If one of the subtypes of this type is a TypeIdentifier, - * i.e. it's an unresolved type, return that type. - */ - -Type *Type::reliesOnTident() -{ - return NULL; -} - -/*************************************** - * Return !=0 if the type or any of its subtypes is wild. - */ - -int Type::hasWild() -{ - return mod & MODwild; -} - -/******************************** - * We've mistakenly parsed this as a type. - * Redo it as an Expression. - * NULL if cannot. - */ - -Expression *Type::toExpression() -{ - return NULL; -} - -/*************************************** - * Return !=0 if type has pointers that need to - * be scanned by the GC during a collection cycle. - */ - -int Type::hasPointers() -{ - //printf("Type::hasPointers() %s, %d\n", toChars(), ty); - return FALSE; -} - -/************************************* - * If this is a type of something, return that something. - */ - -Type *Type::nextOf() -{ - return NULL; -} - -/**************************************** - * Return the mask that an integral type will - * fit into. - */ -uinteger_t Type::sizemask() -{ uinteger_t m; - - switch (toBasetype()->ty) - { - case Tbool: m = 1; break; - case Tchar: - case Tint8: - case Tuns8: m = 0xFF; break; - case Twchar: - case Tint16: - case Tuns16: m = 0xFFFFUL; break; - case Tdchar: - case Tint32: - case Tuns32: m = 0xFFFFFFFFUL; break; - case Tint64: - case Tuns64: m = 0xFFFFFFFFFFFFFFFFULL; break; - default: - assert(0); - } - return m; -} - -/* ============================= TypeError =========================== */ - -TypeError::TypeError() - : Type(Terror) -{ -} - -Type *TypeError::syntaxCopy() -{ - // No semantic analysis done, no need to copy - return this; -} - -void TypeError::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->writestring("_error_"); -} - -d_uns64 TypeError::size(Loc loc) { return 1; } -Expression *TypeError::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); } -Expression *TypeError::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); } -Expression *TypeError::defaultInit(Loc loc) { return new ErrorExp(); } -Expression *TypeError::defaultInitLiteral(Loc loc) { return new ErrorExp(); } - -/* ============================= TypeNext =========================== */ - -TypeNext::TypeNext(TY ty, Type *next) - : Type(ty) -{ - this->next = next; -} - -void TypeNext::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - Type::toDecoBuffer(buf, flag, mangle); - assert(next != this); - //printf("this = %p, ty = %d, next = %p, ty = %d\n", this, this->ty, next, next->ty); - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod, mangle); -} - -void TypeNext::checkDeprecated(Loc loc, Scope *sc) -{ - Type::checkDeprecated(loc, sc); - if (next) // next can be NULL if TypeFunction and auto return type - next->checkDeprecated(loc, sc); -} - - -Type *TypeNext::reliesOnTident() -{ - return next->reliesOnTident(); -} - -int TypeNext::hasWild() -{ - return mod & MODwild || (next && next->hasWild()); -} - - -/******************************* - * For TypeFunction, nextOf() can return NULL if the function return - * type is meant to be inferred, and semantic() hasn't yet ben run - * on the function. After semantic(), it must no longer be NULL. - */ - -Type *TypeNext::nextOf() -{ - return next; -} - -Type *TypeNext::makeConst() -{ - //printf("TypeNext::makeConst() %p, %s\n", this, toChars()); - if (cto) - { assert(cto->mod == MODconst); - return cto; - } - TypeNext *t = (TypeNext *)Type::makeConst(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable() && !next->isConst()) - { if (next->isShared()) - t->next = next->sharedConstOf(); - else - t->next = next->constOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeConst() returns %p, %s\n", t, t->toChars()); - return t; -} - -Type *TypeNext::makeInvariant() -{ - //printf("TypeNext::makeInvariant() %s\n", toChars()); - if (ito) - { assert(ito->isImmutable()); - return ito; - } - TypeNext *t = (TypeNext *)Type::makeInvariant(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable()) - { t->next = next->invariantOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - return t; -} - -Type *TypeNext::makeShared() -{ - //printf("TypeNext::makeShared() %s\n", toChars()); - if (sto) - { assert(sto->mod == MODshared); - return sto; - } - TypeNext *t = (TypeNext *)Type::makeShared(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable() && !next->isShared()) - { - if (next->isConst()) - t->next = next->sharedConstOf(); - else if (next->isWild()) - t->next = next->sharedWildOf(); - else - t->next = next->sharedOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeShared() returns %p, %s\n", t, t->toChars()); - return t; -} - -Type *TypeNext::makeSharedConst() -{ - //printf("TypeNext::makeSharedConst() %s\n", toChars()); - if (scto) - { assert(scto->mod == (MODshared | MODconst)); - return scto; - } - TypeNext *t = (TypeNext *)Type::makeSharedConst(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable() && !next->isSharedConst()) - { - t->next = next->sharedConstOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeSharedConst() returns %p, %s\n", t, t->toChars()); - return t; -} - -Type *TypeNext::makeWild() -{ - //printf("TypeNext::makeWild() %s\n", toChars()); - if (wto) - { assert(wto->mod == MODwild); - return wto; - } - TypeNext *t = (TypeNext *)Type::makeWild(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable() && !next->isConst() && !next->isWild()) - { - if (next->isShared()) - t->next = next->sharedWildOf(); - else - t->next = next->wildOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeWild() returns %p, %s\n", t, t->toChars()); - return t; -} - -Type *TypeNext::makeSharedWild() -{ - //printf("TypeNext::makeSharedWild() %s\n", toChars()); - if (swto) - { assert(swto->isSharedWild()); - return swto; - } - TypeNext *t = (TypeNext *)Type::makeSharedWild(); - if (ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - !next->isImmutable() && !next->isSharedConst()) - { - if (next->isConst()) - t->next = next->sharedConstOf(); - else - t->next = next->sharedWildOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeSharedWild() returns %p, %s\n", t, t->toChars()); - return t; -} - -Type *TypeNext::makeMutable() -{ - //printf("TypeNext::makeMutable() %p, %s\n", this, toChars()); - TypeNext *t = (TypeNext *)Type::makeMutable(); - if ((ty != Tfunction && next->ty != Tfunction && - //(next->deco || next->ty == Tfunction) && - next->isWild()) || ty == Tsarray) - { - t->next = next->mutableOf(); - } - if (ty == Taarray) - { - ((TypeAArray *)t)->impl = NULL; // lazily recompute it - } - //printf("TypeNext::makeMutable() returns %p, %s\n", t, t->toChars()); - return t; -} - -MATCH TypeNext::constConv(Type *to) -{ - //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to->toChars()); - if (equals(to)) - return MATCHexact; - - if (!(ty == to->ty && MODimplicitConv(mod, to->mod))) - return MATCHnomatch; - - Type *tn = to->nextOf(); - if (!(tn && next->ty == tn->ty)) - return MATCHnomatch; - - MATCH m; - if (to->isConst()) // whole tail const conversion - { // Recursive shared level check - m = next->constConv(tn); - if (m == MATCHexact) - m = MATCHconst; - } - else - { //printf("\tnext => %s, to->next => %s\n", next->toChars(), tn->toChars()); - m = next->equals(tn) ? MATCHconst : MATCHnomatch; - } - return m; -} - -unsigned TypeNext::wildConvTo(Type *tprm) -{ - if (ty == Tfunction) - return 0; - - unsigned mod = 0; - Type *tn = tprm->nextOf(); - if (!tn) - return 0; - mod = next->wildConvTo(tn); - if (!mod) - mod = Type::wildConvTo(tprm); - - return mod; -} - - -void TypeNext::transitive() -{ - /* Invoke transitivity of type attributes - */ - next = next->addMod(mod); -} - -/* ============================= TypeBasic =========================== */ - -TypeBasic::TypeBasic(TY ty) - : Type(ty) -{ const char *d; - unsigned flags; - -#define TFLAGSintegral 1 -#define TFLAGSfloating 2 -#define TFLAGSunsigned 4 -#define TFLAGSreal 8 -#define TFLAGSimaginary 0x10 -#define TFLAGScomplex 0x20 -#define TFLAGSvector 0x40 // valid for a SIMD vector type - - flags = 0; - switch (ty) - { - case Tvoid: d = Token::toChars(TOKvoid); - flags |= TFLAGSvector; - break; - - case Tint8: d = Token::toChars(TOKint8); - flags |= TFLAGSintegral | TFLAGSvector; - break; - - case Tuns8: d = Token::toChars(TOKuns8); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; - break; - - case Tint16: d = Token::toChars(TOKint16); - flags |= TFLAGSintegral | TFLAGSvector; - break; - - case Tuns16: d = Token::toChars(TOKuns16); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; - break; - - case Tint32: d = Token::toChars(TOKint32); - flags |= TFLAGSintegral | TFLAGSvector; - break; - - case Tuns32: d = Token::toChars(TOKuns32); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; - break; - - case Tfloat32: d = Token::toChars(TOKfloat32); - flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; - break; - - case Tint64: d = Token::toChars(TOKint64); - flags |= TFLAGSintegral | TFLAGSvector; - break; - - case Tuns64: d = Token::toChars(TOKuns64); - flags |= TFLAGSintegral | TFLAGSunsigned | TFLAGSvector; - break; - - case Tfloat64: d = Token::toChars(TOKfloat64); - flags |= TFLAGSfloating | TFLAGSreal | TFLAGSvector; - break; - - case Tfloat80: d = Token::toChars(TOKfloat80); - flags |= TFLAGSfloating | TFLAGSreal; - break; - - case Timaginary32: d = Token::toChars(TOKimaginary32); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary64: d = Token::toChars(TOKimaginary64); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Timaginary80: d = Token::toChars(TOKimaginary80); - flags |= TFLAGSfloating | TFLAGSimaginary; - break; - - case Tcomplex32: d = Token::toChars(TOKcomplex32); - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex64: d = Token::toChars(TOKcomplex64); - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tcomplex80: d = Token::toChars(TOKcomplex80); - flags |= TFLAGSfloating | TFLAGScomplex; - break; - - case Tbool: d = "bool"; - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tascii: d = Token::toChars(TOKchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Twchar: d = Token::toChars(TOKwchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - case Tdchar: d = Token::toChars(TOKdchar); - flags |= TFLAGSintegral | TFLAGSunsigned; - break; - - default: assert(0); - } - this->dstring = d; - this->flags = flags; - merge(); -} - -Type *TypeBasic::syntaxCopy() -{ - // No semantic analysis done on basic types, no need to copy - return this; -} - - -char *TypeBasic::toChars() -{ - return Type::toChars(); -} - -void TypeBasic::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeBasic::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(dstring); -} - -d_uns64 TypeBasic::size(Loc loc) -{ unsigned size; - - //printf("TypeBasic::size()\n"); - switch (ty) - { - case Tint8: - case Tuns8: size = 1; break; - case Tint16: - case Tuns16: size = 2; break; - case Tint32: - case Tuns32: - case Tfloat32: - case Timaginary32: - size = 4; break; - case Tint64: - case Tuns64: - case Tfloat64: - case Timaginary64: - size = 8; break; - case Tfloat80: - case Timaginary80: - size = REALSIZE; break; - case Tcomplex32: - size = 8; break; - case Tcomplex64: - size = 16; break; - case Tcomplex80: - size = REALSIZE * 2; break; - - case Tvoid: - //size = Type::size(); // error message - size = 1; - break; - - case Tbool: size = 1; break; - case Tascii: size = 1; break; - case Twchar: size = 2; break; - case Tdchar: size = 4; break; - - default: - assert(0); - break; - } - //printf("TypeBasic::size() = %d\n", size); - return size; -} - -unsigned TypeBasic::alignsize() -{ - if (ty == Tvoid) - return 1; - return GetTypeAlignment(sir, this); -#if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS - case Tint64: - case Tuns64: - sz = global.params.is64bit ? 8 : 4; - break; - - case Tfloat64: - case Timaginary64: - sz = global.params.is64bit ? 8 : 4; - break; - - case Tcomplex32: - sz = 4; - break; - - case Tcomplex64: - sz = global.params.is64bit ? 8 : 4; - break; -#endif -#if IN_DMD - default: - sz = size(0); - break; - } - return sz; -#endif -} - -#if IN_LLVM -unsigned TypeBasic::memalign(unsigned salign) -{ - if (global.params.cpu == ARCHx86_64 && (ty == Tfloat80 || ty == Timaginary80)) - return 16; - return Type::memalign(salign); -} -#endif - -Expression *TypeBasic::getProperty(Loc loc, Identifier *ident) -{ - Expression *e; - d_int64 ivalue; -#ifdef IN_GCC - real_t fvalue; -#else - d_float80 fvalue; -#endif - - //printf("TypeBasic::getProperty('%s')\n", ident->toChars()); - if (ident == Id::max) - { - switch (ty) - { - case Tint8: ivalue = 0x7F; goto Livalue; - case Tuns8: ivalue = 0xFF; goto Livalue; - case Tint16: ivalue = 0x7FFFUL; goto Livalue; - case Tuns16: ivalue = 0xFFFFUL; goto Livalue; - case Tint32: ivalue = 0x7FFFFFFFUL; goto Livalue; - case Tuns32: ivalue = 0xFFFFFFFFUL; goto Livalue; - case Tint64: ivalue = 0x7FFFFFFFFFFFFFFFLL; goto Livalue; - case Tuns64: ivalue = 0xFFFFFFFFFFFFFFFFULL; goto Livalue; - case Tbool: ivalue = 1; goto Livalue; - case Tchar: ivalue = 0xFF; goto Livalue; - case Twchar: ivalue = 0xFFFFUL; goto Livalue; - case Tdchar: ivalue = 0x10FFFFUL; goto Livalue; - - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MAX; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MAX; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = Port::ldbl_max; goto Lfvalue; - } - } - else if (ident == Id::min) - { - switch (ty) - { - case Tint8: ivalue = -128; goto Livalue; - case Tuns8: ivalue = 0; goto Livalue; - case Tint16: ivalue = -32768; goto Livalue; - case Tuns16: ivalue = 0; goto Livalue; - case Tint32: ivalue = -2147483647L - 1; goto Livalue; - case Tuns32: ivalue = 0; goto Livalue; - case Tint64: ivalue = (-9223372036854775807LL-1LL); goto Livalue; - case Tuns64: ivalue = 0; goto Livalue; - case Tbool: ivalue = 0; goto Livalue; - case Tchar: ivalue = 0; goto Livalue; - case Twchar: ivalue = 0; goto Livalue; - case Tdchar: ivalue = 0; goto Livalue; - - case Tcomplex32: - case Timaginary32: - case Tfloat32: - case Tcomplex64: - case Timaginary64: - case Tfloat64: - case Tcomplex80: - case Timaginary80: - case Tfloat80: - // For backwards compatibility - eventually, deprecate - goto Lmin_normal; - } - } - else if (ident == Id::min_normal) - { - Lmin_normal: - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_MIN; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_MIN; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_MIN; goto Lfvalue; - } - } - else if (ident == Id::nan) - { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - { - fvalue = Port::nan; - goto Lfvalue; - } - } - } - else if (ident == Id::infinity) - { - switch (ty) - { - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - fvalue = Port::infinity; - goto Lfvalue; - } - } - else if (ident == Id::dig) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_DIG; goto Lint; - } - } - else if (ident == Id::epsilon) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: fvalue = FLT_EPSILON; goto Lfvalue; - case Tcomplex64: - case Timaginary64: - case Tfloat64: fvalue = DBL_EPSILON; goto Lfvalue; - case Tcomplex80: - case Timaginary80: - case Tfloat80: fvalue = LDBL_EPSILON; goto Lfvalue; - } - } - else if (ident == Id::mant_dig) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MANT_DIG; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MANT_DIG; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MANT_DIG; goto Lint; - } - } - else if (ident == Id::max_10_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_10_EXP; goto Lint; - } - } - else if (ident == Id::max_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MAX_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MAX_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MAX_EXP; goto Lint; - } - } - else if (ident == Id::min_10_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_10_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_10_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_10_EXP; goto Lint; - } - } - else if (ident == Id::min_exp) - { - switch (ty) - { - case Tcomplex32: - case Timaginary32: - case Tfloat32: ivalue = FLT_MIN_EXP; goto Lint; - case Tcomplex64: - case Timaginary64: - case Tfloat64: ivalue = DBL_MIN_EXP; goto Lint; - case Tcomplex80: - case Timaginary80: - case Tfloat80: ivalue = LDBL_MIN_EXP; goto Lint; - } - } - - return Type::getProperty(loc, ident); - -Livalue: - e = new IntegerExp(loc, ivalue, this); - return e; - -Lfvalue: - if (isreal() || isimaginary()) - e = new RealExp(loc, fvalue, this); - else - { - complex_t cvalue; - -#if __DMC__ - //((real_t *)&cvalue)[0] = fvalue; - //((real_t *)&cvalue)[1] = fvalue; - cvalue = fvalue + fvalue * I; -#else - cvalue.re = fvalue; - cvalue.im = fvalue; -#endif - //for (int i = 0; i < 20; i++) - // printf("%02x ", ((unsigned char *)&cvalue)[i]); - //printf("\n"); - e = new ComplexExp(loc, cvalue, this); - } - return e; - -Lint: - e = new IntegerExp(loc, ivalue, Type::tint32); - return e; -} - -Expression *TypeBasic::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeBasic::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - Type *t; - - if (ident == Id::re) - { - switch (ty) - { - case Tcomplex32: t = tfloat32; goto L1; - case Tcomplex64: t = tfloat64; goto L1; - case Tcomplex80: t = tfloat80; goto L1; - L1: - e = e->castTo(sc, t); - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - break; - - case Timaginary32: t = tfloat32; goto L2; - case Timaginary64: t = tfloat64; goto L2; - case Timaginary80: t = tfloat80; goto L2; - L2: - e = new RealExp(0, 0.0, t); - break; - - default: - e = Type::getProperty(e->loc, ident); - break; - } - } - else if (ident == Id::im) - { Type *t2; - - switch (ty) - { - case Tcomplex32: t = timaginary32; t2 = tfloat32; goto L3; - case Tcomplex64: t = timaginary64; t2 = tfloat64; goto L3; - case Tcomplex80: t = timaginary80; t2 = tfloat80; goto L3; - L3: - e = e->castTo(sc, t); - e->type = t2; - break; - - case Timaginary32: t = tfloat32; goto L4; - case Timaginary64: t = tfloat64; goto L4; - case Timaginary80: t = tfloat80; goto L4; - L4: - e = e->copy(); - e->type = t; - break; - - case Tfloat32: - case Tfloat64: - case Tfloat80: - e = new RealExp(0, 0.0, this); - break; - - default: - e = Type::getProperty(e->loc, ident); - break; - } - } - else - { - return Type::dotExp(sc, e, ident); - } - e = e->semantic(sc); - return e; -} - -Expression *TypeBasic::defaultInit(Loc loc) -{ dinteger_t value = 0; - -#if SNAN_DEFAULT_INIT - /* - * Use a payload which is different from the machine NaN, - * so that uninitialised variables can be - * detected even if exceptions are disabled. - */ - union - { unsigned short us[8]; - long double ld; - } snan = {{ 0, 0, 0, 0xA000, 0x7FFF }}; - /* - * Although long doubles are 10 bytes long, some - * C ABIs pad them out to 12 or even 16 bytes, so - * leave enough space in the snan array. - */ - assert(REALSIZE <= sizeof(snan)); - d_float80 fvalue = snan.ld; -#endif - -#if LOGDEFAULTINIT - printf("TypeBasic::defaultInit() '%s'\n", toChars()); -#endif - switch (ty) - { - case Tchar: - value = 0xFF; - break; - - case Twchar: - case Tdchar: - value = 0xFFFF; - break; - - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: -#if SNAN_DEFAULT_INIT - return new RealExp(loc, fvalue, this); -#else - return getProperty(loc, Id::nan); -#endif - - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: -#if SNAN_DEFAULT_INIT - { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). - complex_t cvalue; - ((real_t *)&cvalue)[0] = fvalue; - ((real_t *)&cvalue)[1] = fvalue; - return new ComplexExp(loc, cvalue, this); - } -#else - return getProperty(loc, Id::nan); -#endif - - case Tvoid: - error(loc, "void does not have a default initializer"); - return new ErrorExp(); - } - return new IntegerExp(loc, value, this); -} - -int TypeBasic::isZeroInit(Loc loc) -{ - switch (ty) - { - case Tchar: - case Twchar: - case Tdchar: - case Timaginary32: - case Timaginary64: - case Timaginary80: - case Tfloat32: - case Tfloat64: - case Tfloat80: - case Tcomplex32: - case Tcomplex64: - case Tcomplex80: - return 0; // no - } - return 1; // yes -} - -int TypeBasic::isintegral() -{ - //printf("TypeBasic::isintegral('%s') x%x\n", toChars(), flags); - return flags & TFLAGSintegral; -} - -int TypeBasic::isfloating() -{ - return flags & TFLAGSfloating; -} - -int TypeBasic::isreal() -{ - return flags & TFLAGSreal; -} - -int TypeBasic::isimaginary() -{ - return flags & TFLAGSimaginary; -} - -int TypeBasic::iscomplex() -{ - return flags & TFLAGScomplex; -} - -int TypeBasic::isunsigned() -{ - return flags & TFLAGSunsigned; -} - -int TypeBasic::isscalar() -{ - return flags & (TFLAGSintegral | TFLAGSfloating); -} - -MATCH TypeBasic::implicitConvTo(Type *to) -{ - //printf("TypeBasic::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); - if (this == to) - return MATCHexact; - -#if DMDV2 - if (ty == to->ty) - { - if (mod == to->mod) - return MATCHexact; - else if (MODimplicitConv(mod, to->mod)) - return MATCHconst; - else if (!((mod ^ to->mod) & MODshared)) // for wild matching - return MATCHconst; - else - return MATCHconvert; - } -#endif - - if (ty == Tvoid || to->ty == Tvoid) - return MATCHnomatch; - if (to->ty == Tbool) - return MATCHnomatch; - - TypeBasic *tob; - if (to->ty == Tvector) - { - TypeVector *tv = (TypeVector *)to; - tob = tv->elementType(); - } - else - tob = to->isTypeBasic(); - if (!tob) - return MATCHnomatch; - - if (flags & TFLAGSintegral) - { - // Disallow implicit conversion of integers to imaginary or complex - if (tob->flags & (TFLAGSimaginary | TFLAGScomplex)) - return MATCHnomatch; - -#if DMDV2 - // If converting from integral to integral - if (tob->flags & TFLAGSintegral) - { d_uns64 sz = size(0); - d_uns64 tosz = tob->size(0); - - /* Can't convert to smaller size - */ - if (sz > tosz) - return MATCHnomatch; - - /* Can't change sign if same size - */ - /*if (sz == tosz && (flags ^ tob->flags) & TFLAGSunsigned) - return MATCHnomatch;*/ - } -#endif - } - else if (flags & TFLAGSfloating) - { - // Disallow implicit conversion of floating point to integer - if (tob->flags & TFLAGSintegral) - return MATCHnomatch; - - assert(tob->flags & TFLAGSfloating); - - // Disallow implicit conversion from complex to non-complex - if (flags & TFLAGScomplex && !(tob->flags & TFLAGScomplex)) - return MATCHnomatch; - - // Disallow implicit conversion of real or imaginary to complex - if (flags & (TFLAGSreal | TFLAGSimaginary) && - tob->flags & TFLAGScomplex) - return MATCHnomatch; - - // Disallow implicit conversion to-from real and imaginary - if ((flags & (TFLAGSreal | TFLAGSimaginary)) != - (tob->flags & (TFLAGSreal | TFLAGSimaginary))) - return MATCHnomatch; - } - return MATCHconvert; -} - -TypeBasic *TypeBasic::isTypeBasic() -{ - return (TypeBasic *)this; -} - -/* ============================= TypeVector =========================== */ - -/* The basetype must be one of: - * byte[16],ubyte[16],short[8],ushort[8],int[4],uint[4],long[2],ulong[2],float[4],double[2] - */ -TypeVector::TypeVector(Loc loc, Type *basetype) - : Type(Tvector) -{ - this->basetype = basetype; -} - -Type *TypeVector::syntaxCopy() -{ - return new TypeVector(0, basetype->syntaxCopy()); -} - -Type *TypeVector::semantic(Loc loc, Scope *sc) -{ - int errors = global.errors; - basetype = basetype->semantic(loc, sc); - if (errors != global.errors) - return terror; - basetype = basetype->toBasetype()->mutableOf(); - if (basetype->ty != Tsarray || basetype->size() != 16) - { error(loc, "base type of __vector must be a 16 byte static array, not %s", basetype->toChars()); - return terror; - } - TypeSArray *t = (TypeSArray *)basetype; - TypeBasic *tb = t->nextOf()->isTypeBasic(); - if (!tb || !(tb->flags & TFLAGSvector)) - { error(loc, "base type of __vector must be a static array of an arithmetic type, not %s", t->toChars()); - return terror; - } - return merge(); -} - -TypeBasic *TypeVector::elementType() -{ - assert(basetype->ty == Tsarray); - TypeSArray *t = (TypeSArray *)basetype; - TypeBasic *tb = t->nextOf()->isTypeBasic(); - assert(tb); - return tb; -} - -int TypeVector::checkBoolean() -{ - return FALSE; -} - -char *TypeVector::toChars() -{ - return Type::toChars(); -} - -void TypeVector::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeVector::toCBuffer2(mod = %d, this->mod = %d)\n", mod, this->mod); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring("__vector("); - basetype->toCBuffer2(buf, hgs, this->mod); - buf->writestring(")"); -} - -void TypeVector::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - if (flag != mod && flag != 0x100) - { - MODtoDecoBuffer(buf, mod); - } - buf->writestring("Nh"); - basetype->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod, mangle); -} - -d_uns64 TypeVector::size(Loc loc) -{ - return 16; -} - -unsigned TypeVector::alignsize() -{ - return 16; -} - -Expression *TypeVector::getProperty(Loc loc, Identifier *ident) -{ - return basetype->getProperty(loc, ident); -} - -Expression *TypeVector::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::array) - { - e = e->castTo(sc, basetype); - return e; - } - return basetype->dotExp(sc, e->castTo(sc, basetype), ident); -} - -Expression *TypeVector::defaultInit(Loc loc) -{ - return basetype->defaultInit(loc); -} - -int TypeVector::isZeroInit(Loc loc) -{ - return basetype->isZeroInit(loc); -} - -int TypeVector::isintegral() -{ - //printf("TypeVector::isintegral('%s') x%x\n", toChars(), flags); - return basetype->nextOf()->isintegral(); -} - -int TypeVector::isfloating() -{ - return basetype->nextOf()->isfloating(); -} - -int TypeVector::isunsigned() -{ - return basetype->nextOf()->isunsigned(); -} - -int TypeVector::isscalar() -{ - return basetype->nextOf()->isscalar(); -} - -MATCH TypeVector::implicitConvTo(Type *to) -{ - //printf("TypeVector::implicitConvTo(%s) from %s\n", to->toChars(), toChars()); - if (this == to) - return MATCHexact; - if (ty == to->ty) - return MATCHconvert; - return MATCHnomatch; -} - -/***************************** TypeArray *****************************/ - -TypeArray::TypeArray(TY ty, Type *next) - : TypeNext(ty, next) -{ -} - -Expression *TypeArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - Type *n = this->next->toBasetype(); // uncover any typedef's - -#if LOGDOTEXP - printf("TypeArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - - if (!n->isMutable()) - if (ident == Id::sort || ident == Id::reverse) - error(e->loc, "can only %s a mutable array\n", ident->toChars()); - - if (ident == Id::reverse && (n->ty == Tchar || n->ty == Twchar)) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adReverseChar_fd = NULL; - if(!adReverseChar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::tchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adReverseChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseChar"); - } - static FuncDeclaration *adReverseWchar_fd = NULL; - if(!adReverseWchar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::twchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adReverseWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adReverseWchar"); - } - - if(n->ty == Twchar) - ec = new VarExp(0, adReverseWchar_fd); - else - ec = new VarExp(0, adReverseChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::sort && (n->ty == Tchar || n->ty == Twchar)) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adSortChar_fd = NULL; - if(!adSortChar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::tchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adSortChar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortChar"); - } - static FuncDeclaration *adSortWchar_fd = NULL; - if(!adSortWchar_fd) { - Parameters* args = new Parameters; - Type* arrty = Type::twchar->arrayOf(); - args->push(new Parameter(STCin, arrty, NULL, NULL)); - adSortWchar_fd = FuncDeclaration::genCfunc(args, arrty, "_adSortWchar"); - } - - if(n->ty == Twchar) - ec = new VarExp(0, adSortWchar_fd); - else - ec = new VarExp(0, adSortChar_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::reverse || ident == Id::dup || ident == Id::idup) - { - Expression *ec; - Expressions *arguments; - int size = next->size(e->loc); - int dup; - - Expression *olde = e; - assert(size); - dup = (ident == Id::dup || ident == Id::idup); - //LDC: Build arguments. - static FuncDeclaration *adDup_fd = NULL; - if(!adDup_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - adDup_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adDup); - } - static FuncDeclaration *adReverse_fd = NULL; - if(!adReverse_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - adReverse_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::adReverse); - } - - if(dup) - ec = new VarExp(0, adDup_fd); - else - ec = new VarExp(0, adReverse_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - if (dup) - arguments->push(getTypeInfo(sc)); - - // LDC repaint array type to void[] - if (n->ty != Tvoid) { - CastExp *exp = new CastExp(e->loc, e, e->type); - exp->type = Type::tvoid->arrayOf(); - exp->disableOptimization = true; - e = exp; - } - arguments->push(e); - - if (!dup) - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - if (ident == Id::idup) - { Type *einv = next->invariantOf(); - if (next->implicitConvTo(einv) < MATCHconst) - error(e->loc, "cannot implicitly convert element type %s to immutable in %s.idup", - next->toChars(), olde->toChars()); - e->type = einv->arrayOf(); - } - else if (ident == Id::dup) - { - Type *emut = next->mutableOf(); - if (next->implicitConvTo(emut) < MATCHconst) - error(e->loc, "cannot implicitly convert element type %s to mutable in %s.dup", - next->toChars(), olde->toChars()); - e->type = emut->arrayOf(); - } - else - e->type = next->mutableOf()->arrayOf(); - } - else if (ident == Id::sort) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *adSort_fd = NULL; - if(!adSort_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->arrayOf(), NULL, NULL)); - args->push(new Parameter(STCin, Type::typeinfo->type, NULL, NULL)); - adSort_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), "_adSort"); - } - - ec = new VarExp(0, adSort_fd); - e = e->castTo(sc, n->arrayOf()); // convert to dynamic array - arguments = new Expressions(); - - // LDC repaint array type to void[] - if (n->ty != Tvoid) { - CastExp *exp = new CastExp(e->loc, e, e->type); - exp->type = Type::tvoid->arrayOf(); - exp->disableOptimization = true; - e = exp; - } - arguments->push(e); - // LDC, we don't support the getInternalTypeInfo - // optimization arbitrarily, not yet at least... - arguments->push(n->getTypeInfo(sc)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else - { - e = Type::dotExp(sc, e, ident); - } - e = e->semantic(sc); - return e; -} - - -/***************************** TypeSArray *****************************/ - -TypeSArray::TypeSArray(Type *t, Expression *dim) - : TypeArray(Tsarray, t) -{ - //printf("TypeSArray(%s)\n", dim->toChars()); - this->dim = dim; -} - -Type *TypeSArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - Expression *e = dim->syntaxCopy(); - t = new TypeSArray(t, e); - t->mod = mod; - return t; -} - -d_uns64 TypeSArray::size(Loc loc) -{ dinteger_t sz; - - if (!dim) - return Type::size(loc); - sz = dim->toInteger(); - - { dinteger_t n, n2; - - n = next->size(); - n2 = n * sz; - if (n && (n2 / n) != sz) - goto Loverflow; - sz = n2; - } - return sz; - -Loverflow: - error(loc, "index %jd overflow for static array", sz); - return 1; -} - -unsigned TypeSArray::alignsize() -{ - return next->alignsize(); -} - -/************************** - * This evaluates exp while setting length to be the number - * of elements in the tuple t. - */ -Expression *semanticLength(Scope *sc, Type *t, Expression *exp) -{ - if (t->ty == Ttuple) - { ScopeDsymbol *sym = new ArrayScopeSymbol(sc, (TypeTuple *)t); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - exp = exp->semantic(sc); - - sc->pop(); - } - else - exp = exp->semantic(sc); - return exp; -} - -Expression *semanticLength(Scope *sc, TupleDeclaration *s, Expression *exp) -{ - ScopeDsymbol *sym = new ArrayScopeSymbol(sc, s); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - exp = exp->semantic(sc); - - sc->pop(); - return exp; -} - -void TypeSArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("TypeSArray::resolve() %s\n", toChars()); - next->resolve(loc, sc, pe, pt, ps); - //printf("s = %p, e = %p, t = %p\n", *ps, *pe, *pt); - if (*pe) - { // It's really an index expression - Expression *e = new IndexExp(loc, *pe, dim); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - dim = dim->semantic(sc); - dim = dim->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); - - sc = sc->pop(); - - if (d >= td->objects->dim) - { error(loc, "tuple index %ju exceeds length %u", d, td->objects->dim); - goto Ldefault; - } - Object *o = td->objects->tdata()[(size_t)d]; - if (o->dyncast() == DYNCAST_DSYMBOL) - { - *ps = (Dsymbol *)o; - return; - } - if (o->dyncast() == DYNCAST_EXPRESSION) - { - *ps = NULL; - *pe = (Expression *)o; - return; - } - if (o->dyncast() == DYNCAST_TYPE) - { - *ps = NULL; - *pt = (Type *)o; - return; - } - - /* Create a new TupleDeclaration which - * is a slice [d..d+1] out of the old one. - * Do it this way because TemplateInstance::semanticTiargs() - * can handle unresolved Objects this way. - */ - Objects *objects = new Objects; - objects->setDim(1); - objects->tdata()[0] = o; - - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; - } - else - { - Ldefault: - Type::resolve(loc, sc, pe, pt, ps); - } -} - -Type *TypeSArray::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSArray::semantic() %s\n", toChars()); - - Type *t; - Expression *e; - Dsymbol *s; - next->resolve(loc, sc, &e, &t, &s); - if (dim && s && s->isTupleDeclaration()) - { TupleDeclaration *sd = s->isTupleDeclaration(); - - dim = semanticLength(sc, sd, dim); - dim = dim->optimize(WANTvalue | WANTinterpret); - uinteger_t d = dim->toUInteger(); - - if (d >= sd->objects->dim) - { error(loc, "tuple index %ju exceeds %u", d, sd->objects->dim); - return Type::terror; - } - Object *o = sd->objects->tdata()[(size_t)d]; - if (o->dyncast() != DYNCAST_TYPE) - { error(loc, "%s is not a type", toChars()); - return Type::terror; - } - t = (Type *)o; - return t; - } - - Type *tn = next->semantic(loc,sc); - if (tn->ty == Terror) - return terror; - - Type *tbn = tn->toBasetype(); - - if (dim) - { dinteger_t n, n2; - - int errors = global.errors; - dim = semanticLength(sc, tbn, dim); - if (errors != global.errors) - goto Lerror; - - dim = dim->optimize(WANTvalue); - if (sc && sc->parameterSpecialization && dim->op == TOKvar && - ((VarExp *)dim)->var->storage_class & STCtemplateparameter) - { - /* It could be a template parameter N which has no value yet: - * template Foo(T : T[N], size_t N); - */ - return this; - } - dim = dim->optimize(WANTvalue | WANTinterpret); - dinteger_t d1 = dim->toInteger(); - dim = dim->implicitCastTo(sc, tsize_t); - dim = dim->optimize(WANTvalue); - dinteger_t d2 = dim->toInteger(); - - if (dim->op == TOKerror) - goto Lerror; - - if (d1 != d2) - goto Loverflow; - - if (tbn->isintegral() || - tbn->isfloating() || - tbn->ty == Tpointer || - tbn->ty == Tarray || - tbn->ty == Tsarray || - tbn->ty == Taarray || - tbn->ty == Tclass) - { - /* Only do this for types that don't need to have semantic() - * run on them for the size, since they may be forward referenced. - */ - n = tbn->size(loc); - n2 = n * d2; - if ((int)n2 < 0) - goto Loverflow; - if (n2 >= 0x1000000) // put a 'reasonable' limit on it - goto Loverflow; - if (n && n2 / n != d2) - { - Loverflow: - error(loc, "index %jd overflow for static array", d1); - goto Lerror; - } - } - } - switch (tbn->ty) - { - case Ttuple: - { // Index the tuple to get the type - assert(dim); - TypeTuple *tt = (TypeTuple *)tbn; - uinteger_t d = dim->toUInteger(); - - if (d >= tt->arguments->dim) - { error(loc, "tuple index %ju exceeds %u", d, tt->arguments->dim); - goto Lerror; - } - Parameter *arg = tt->arguments->tdata()[(size_t)d]; - return arg->type; - } - case Tstruct: - { TypeStruct *ts = (TypeStruct *)tbn; - if (0 && ts->sym->isnested) - { error(loc, "cannot have static array of inner struct %s", ts->toChars()); - goto Lerror; - } - break; - } - case Tfunction: - case Tnone: - error(loc, "can't have array of %s", tbn->toChars()); - goto Lerror; - } - if (tbn->isscope()) - { error(loc, "cannot have array of scope %s", tbn->toChars()); - goto Lerror; - } - - /* Ensure things like const(immutable(T)[3]) become immutable(T[3]) - * and const(T)[3] become const(T[3]) - */ - next = tn; - transitive(); - t = addMod(tn->mod); - - return t->merge(); - -Lerror: - return Type::terror; -} - -void TypeSArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - Type::toDecoBuffer(buf, flag, mangle); - if (dim) - buf->printf("%ju", dim->toInteger()); - if (next) - /* Note that static arrays are value types, so - * for a parameter, propagate the 0x100 to the next - * level, since for T[4][3], any const should apply to the T, - * not the [4]. - */ - next->toDecoBuffer(buf, (flag & 0x100) ? flag : mod, mangle); -} - -void TypeSArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->printf("[%s]", dim->toChars()); -} - -Expression *TypeSArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeSArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - e = dim; - } - else if (ident == Id::ptr) - { - e = e->castTo(sc, next->pointerTo()); - } - else - { - e = TypeArray::dotExp(sc, e, ident); - } - e = e->semantic(sc); - return e; -} - -int TypeSArray::isString() -{ - TY nty = next->toBasetype()->ty; - return nty == Tchar || nty == Twchar || nty == Tdchar; -} - -unsigned TypeSArray::memalign(unsigned salign) -{ - return next->memalign(salign); -} - -MATCH TypeSArray::constConv(Type *to) -{ - if (to->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)to; - if (!dim->equals(tsa->dim)) - return MATCHnomatch; - } - return TypeNext::constConv(to); -} - -MATCH TypeSArray::implicitConvTo(Type *to) -{ - //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); - - // Allow implicit conversion of static array to pointer or dynamic array - if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) - { - TypePointer *tp = (TypePointer *)to; - - if (!MODimplicitConv(next->mod, tp->next->mod)) - return MATCHnomatch; - - if (tp->next->ty == Tvoid || next->constConv(tp->next) != MATCHnomatch) - { - return MATCHconvert; - } - return MATCHnomatch; - } - if (to->ty == Tarray) - { - TypeDArray *ta = (TypeDArray *)to; - - if (!MODimplicitConv(next->mod, ta->next->mod)) - return MATCHnomatch; - - /* Allow conversion to void[] - */ - if (ta->next->ty == Tvoid) - { - return MATCHconvert; - } - - MATCH m = next->constConv(ta->next); - if (m != MATCHnomatch) - { - return MATCHconvert; - } - return MATCHnomatch; - } - - if (to->ty == Tsarray) - { - if (this == to) - return MATCHexact; - - TypeSArray *tsa = (TypeSArray *)to; - - if (dim->equals(tsa->dim)) - { - /* Since static arrays are value types, allow - * conversions from const elements to non-const - * ones, just like we allow conversion from const int - * to int. - */ - MATCH m = next->implicitConvTo(tsa->next); - if (m >= MATCHconst) - { - if (mod != to->mod) - m = MATCHconst; - return m; - } - } - } - return MATCHnomatch; -} - -Expression *TypeSArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeSArray::defaultInit() '%s'\n", toChars()); -#endif - return next->defaultInit(loc); -} - -int TypeSArray::isZeroInit(Loc loc) -{ - return next->isZeroInit(loc); -} - -int TypeSArray::needsDestruction() -{ - return next->needsDestruction(); -} - -Expression *TypeSArray::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeSArray::defaultInitLiteral() '%s'\n", toChars()); -#endif - size_t d = dim->toInteger(); - Expression *elementinit = next->defaultInitLiteral(loc); - Expressions *elements = new Expressions(); - elements->setDim(d); - for (size_t i = 0; i < d; i++) - elements->tdata()[i] = elementinit; - ArrayLiteralExp *ae = new ArrayLiteralExp(0, elements); - ae->type = this; - return ae; -} - -Expression *TypeSArray::toExpression() -{ - Expression *e = next->toExpression(); - if (e) - { Expressions *arguments = new Expressions(); - arguments->push(dim); - e = new ArrayExp(dim->loc, e, arguments); - } - return e; -} - -int TypeSArray::hasPointers() -{ - /* Don't want to do this, because: - * struct S { T* array[0]; } - * may be a variable length struct. - */ - //if (dim->toInteger() == 0) - //return FALSE; - - if (next->ty == Tvoid) - // Arrays of void contain arbitrary data, which may include pointers - return TRUE; - else - return next->hasPointers(); -} - -/***************************** TypeDArray *****************************/ - -TypeDArray::TypeDArray(Type *t) - : TypeArray(Tarray, t) -{ - //printf("TypeDArray(t = %p)\n", t); -} - -Type *TypeDArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - { t = new TypeDArray(t); - t->mod = mod; - } - return t; -} - -d_uns64 TypeDArray::size(Loc loc) -{ - //printf("TypeDArray::size()\n"); - return PTRSIZE * 2; -} - -unsigned TypeDArray::alignsize() -{ - // A DArray consists of two ptr-sized values, so align it on pointer size - // boundary - return PTRSIZE; -} - -Type *TypeDArray::semantic(Loc loc, Scope *sc) -{ Type *tn = next; - - tn = next->semantic(loc,sc); - Type *tbn = tn->toBasetype(); - switch (tbn->ty) - { - case Tfunction: - case Tnone: - case Ttuple: - error(loc, "can't have array of %s", tbn->toChars()); - case Terror: - return Type::terror; - - case Tstruct: - { TypeStruct *ts = (TypeStruct *)tbn; - if (0 && ts->sym->isnested) - error(loc, "cannot have dynamic array of inner struct %s", ts->toChars()); - break; - } - } - if (tn->isscope()) - error(loc, "cannot have array of scope %s", tn->toChars()); - - next = tn; - transitive(); - return merge(); -} - -void TypeDArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - Type::toDecoBuffer(buf, flag, mangle); - if (next) - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod, mangle); -} - -void TypeDArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - if (equals(tstring)) - buf->writestring("string"); - else - { next->toCBuffer2(buf, hgs, this->mod); - buf->writestring("[]"); - } -} - -Expression *TypeDArray::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - if (e->op == TOKstring) - { StringExp *se = (StringExp *)e; - - return new IntegerExp(se->loc, se->len, Type::tindex); - } - if (e->op == TOKnull) - return new IntegerExp(e->loc, 0, Type::tindex); - e = new ArrayLengthExp(e->loc, e); - e->type = Type::tsize_t; - return e; - } - else if (ident == Id::ptr) - { - e = e->castTo(sc, next->pointerTo()); - return e; - } - else - { - e = TypeArray::dotExp(sc, e, ident); - } - return e; -} - -int TypeDArray::isString() -{ - TY nty = next->toBasetype()->ty; - return nty == Tchar || nty == Twchar || nty == Tdchar; -} - -MATCH TypeDArray::implicitConvTo(Type *to) -{ - //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); - if (equals(to)) - return MATCHexact; - - // Allow implicit conversion of array to pointer - if (IMPLICIT_ARRAY_TO_PTR && to->ty == Tpointer) - { - TypePointer *tp = (TypePointer *)to; - - /* Allow conversion to void* - */ - if (tp->next->ty == Tvoid && - MODimplicitConv(next->mod, tp->next->mod)) - { - return MATCHconvert; - } - - return next->constConv(to); - } - - if (to->ty == Tarray) - { - TypeDArray *ta = (TypeDArray *)to; - - if (!MODimplicitConv(next->mod, ta->next->mod)) - return MATCHnomatch; // not const-compatible - - // Check head inout conversion: - // T [] -> inout(const(T)[]) - // const(T)[] -> inout(const(T)[]) - if (isMutable() && ta->isWild()) - if ((next->isMutable() || next->isConst()) && ta->next->isConst()) - return MATCHnomatch; - - /* Allow conversion to void[] - */ - if (next->ty != Tvoid && ta->next->ty == Tvoid) - { - return MATCHconvert; - } - - MATCH m = next->constConv(ta->next); - if (m != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - return m; - } - } - return Type::implicitConvTo(to); -} - -Expression *TypeDArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeDArray::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeDArray::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeDArray::checkBoolean() -{ - return TRUE; -} - -int TypeDArray::hasPointers() -{ - return TRUE; -} - - -/***************************** TypeAArray *****************************/ - -TypeAArray::TypeAArray(Type *t, Type *index) - : TypeArray(Taarray, t) -{ - this->index = index; - this->impl = NULL; - this->loc = 0; - this->sc = NULL; -} - -Type *TypeAArray::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - Type *ti = index->syntaxCopy(); - if (t == next && ti == index) - t = this; - else - { t = new TypeAArray(t, ti); - t->mod = mod; - } - return t; -} - -d_uns64 TypeAArray::size(Loc loc) -{ - return PTRSIZE /* * 2*/; -} - - -Type *TypeAArray::semantic(Loc loc, Scope *sc) -{ - //printf("TypeAArray::semantic() %s index->ty = %d\n", toChars(), index->ty); - if (deco) - return this; - - this->loc = loc; - this->sc = sc; - if (sc) - sc->setNoFree(); - - // Deal with the case where we thought the index was a type, but - // in reality it was an expression. - if (index->ty == Tident || index->ty == Tinstance || index->ty == Tsarray) - { - Expression *e; - Type *t; - Dsymbol *s; - - index->resolve(loc, sc, &e, &t, &s); - if (e) - { // It was an expression - - // Rewrite as a static array - TypeSArray *tsa; - - tsa = new TypeSArray(next, e); - return tsa->semantic(loc,sc); - } - else if (t) - index = t; - else - { index->error(loc, "index is not a type or an expression"); - return Type::terror; - } - } - else - index = index->semantic(loc,sc); - - if (index->nextOf() && !index->nextOf()->isImmutable()) - { - index = index->constOf()->mutableOf(); -#if 0 -printf("index is %p %s\n", index, index->toChars()); -index->check(); -printf("index->mod = x%x\n", index->mod); -printf("index->ito = x%x\n", index->ito); -if (index->ito) { -printf("index->ito->mod = x%x\n", index->ito->mod); -printf("index->ito->ito = x%x\n", index->ito->ito); -} -#endif - } - - switch (index->toBasetype()->ty) - { - case Tfunction: - case Tvoid: - case Tnone: - case Ttuple: - error(loc, "can't have associative array key of %s", index->toBasetype()->toChars()); - case Terror: - return Type::terror; - } - next = next->semantic(loc,sc); - transitive(); - - switch (next->toBasetype()->ty) - { - case Tfunction: - case Tvoid: - case Tnone: - error(loc, "can't have associative array of %s", next->toChars()); - case Terror: - return Type::terror; - } - if (next->isscope()) - { error(loc, "cannot have array of scope %s", next->toChars()); - return Type::terror; - } - return merge(); -} - -StructDeclaration *TypeAArray::getImpl() -{ - // Do it lazily - if (!impl) - { - Type *index = this->index; - Type *next = this->next; - if (index->reliesOnTident() || next->reliesOnTident()) - { - error(loc, "cannot create associative array %s", toChars()); - index = terror; - next = terror; - - // Head off future failures - StructDeclaration *s = new StructDeclaration(0, NULL); - s->type = terror; - impl = s; - return impl; - } - /* This is really a proxy for the template instance AssocArray!(index, next) - * But the instantiation can fail if it is a template specialization field - * which has Tident's instead of real types. - */ - Objects *tiargs = new Objects(); - tiargs->push(index); - tiargs->push(next); - - // Create AssociativeArray!(index, next) -#if 1 - if (! Type::associativearray) - { - ObjectNotFound(Id::AssociativeArray); - } - TemplateInstance *ti = new TemplateInstance(loc, Type::associativearray, tiargs); -#else - //Expression *e = new IdentifierExp(loc, Id::object); - Expression *e = new IdentifierExp(loc, Id::empty); - //e = new DotIdExp(loc, e, Id::object); - DotTemplateInstanceExp *dti = new DotTemplateInstanceExp(loc, - e, - Id::AssociativeArray, - tiargs); - dti->semantic(sc); - TemplateInstance *ti = dti->ti; -#endif - ti->semantic(sc); - ti->semantic2(sc); - ti->semantic3(sc); - impl = ti->toAlias()->isStructDeclaration(); -#ifdef DEBUG - if (!impl) - { Dsymbol *s = ti->toAlias(); - printf("%s %s\n", s->kind(), s->toChars()); - } -#endif - assert(impl); - } - return impl; -} - -void TypeAArray::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - //printf("TypeAArray::resolve() %s\n", toChars()); - - // 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 - printf("TypeAArray::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif -#if 0 - if (ident == Id::length) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaLen_fd = NULL; - if(!aaLen_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - aaLen_fd = FuncDeclaration::genCfunc(args, Type::tsize_t, Id::aaLen); - } - - ec = new VarExp(0, aaLen_fd); - arguments = new Expressions(); - arguments->push(e); - e = new CallExp(e->loc, ec, arguments); - e->type = aaLen_fd->type->nextOf(); - } - else - if (ident == Id::keys) - { - Expression *ec; - Expressions *arguments; - int size = index->size(e->loc); - - assert(size); - //LDC: Build arguments. - static FuncDeclaration *aaKeys_fd = NULL; - if(!aaKeys_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - aaKeys_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaKeys); - } - - ec = new VarExp(0, aaKeys_fd); - arguments = new Expressions(); - arguments->push(e); - arguments->push(new IntegerExp(0, size, Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = index->arrayOf(); - } - else if (ident == Id::values) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaValues_fd = NULL; - if(!aaValues_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - args->push(new Argument(STCin, Type::tsize_t, NULL, NULL)); - aaValues_fd = FuncDeclaration::genCfunc(args, Type::tvoid->arrayOf(), Id::aaValues); - } - - ec = new VarExp(0, aaValues_fd); - arguments = new Expressions(); - arguments->push(e); - size_t keysize = index->size(e->loc); - keysize = (keysize + PTRSIZE - 1) & ~(PTRSIZE - 1); - arguments->push(new IntegerExp(0, keysize, Type::tsize_t)); - arguments->push(new IntegerExp(0, next->size(e->loc), Type::tsize_t)); - e = new CallExp(e->loc, ec, arguments); - e->type = next->arrayOf(); - } - else if (ident == Id::rehash) - { - Expression *ec; - Expressions *arguments; - - //LDC: Build arguments. - static FuncDeclaration *aaRehash_fd = NULL; - if(!aaRehash_fd) { - Arguments* args = new Arguments; - args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Argument(STCin, Type::typeinfo->type, NULL, NULL)); - aaRehash_fd = FuncDeclaration::genCfunc(args, Type::tvoidptr, Id::aaRehash); - } - - ec = new VarExp(0, aaRehash_fd); - arguments = new Expressions(); - arguments->push(e->addressOf(sc)); - arguments->push(index->getInternalTypeInfo(sc)); // LDC doesn't support getInternalTypeInfo, see above - e = new CallExp(e->loc, ec, arguments); - e->type = this; - } - else -#endif - if (ident != Id::__sizeof && - ident != Id::__xalignof && - ident != Id::init && - ident != Id::mangleof && - ident != Id::stringof && - ident != Id::offsetof) - { - e->type = getImpl()->type; - e = e->type->dotExp(sc, e, ident); - } - else - e = Type::dotExp(sc, e, ident); - return e; -} - -void TypeAArray::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - Type::toDecoBuffer(buf, flag, mangle); - index->toDecoBuffer(buf, 0, mangle); - next->toDecoBuffer(buf, (flag & 0x100) ? 0 : mod, mangle); -} - -void TypeAArray::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->writeByte('['); - index->toCBuffer2(buf, hgs, 0); - buf->writeByte(']'); -} - -Expression *TypeAArray::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeAArray::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeAArray::isZeroInit(Loc loc) -{ - return TRUE; -} - -int TypeAArray::checkBoolean() -{ - return TRUE; -} - -int TypeAArray::hasPointers() -{ - return TRUE; -} - -MATCH TypeAArray::implicitConvTo(Type *to) -{ - //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); - if (equals(to)) - return MATCHexact; - - if (to->ty == Taarray) - { TypeAArray *ta = (TypeAArray *)to; - - if (!MODimplicitConv(next->mod, ta->next->mod)) - return MATCHnomatch; // not const-compatible - - if (!MODimplicitConv(index->mod, ta->index->mod)) - return MATCHnomatch; // not const-compatible - - // Check head inout conversion: - // V [K] -> inout(const(V)[K]) - // const(V)[K] -> inout(const(V)[K]) - if (isMutable() && ta->isWild()) - if ((next->isMutable() || next->isConst()) && ta->next->isConst()) - return MATCHnomatch; - - MATCH m = next->constConv(ta->next); - MATCH mi = index->constConv(ta->index); - if (m != MATCHnomatch && mi != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - if (mi < m) - m = mi; - return m; - } - } - else if (to->ty == Tstruct && ((TypeStruct *)to)->sym->ident == Id::AssociativeArray) - { - int errs = global.startGagging(); - Type *from = getImpl()->type; - if (global.endGagging(errs)) - { - return MATCHnomatch; - } - return from->implicitConvTo(to); - } - return Type::implicitConvTo(to); -} - -MATCH TypeAArray::constConv(Type *to) -{ - if (to->ty == Taarray) - { - TypeAArray *taa = (TypeAArray *)to; - MATCH mindex = index->constConv(taa->index); - MATCH mkey = next->constConv(taa->next); - // Pick the worst match - return mkey < mindex ? mkey : mindex; - } - return Type::constConv(to); -} - -/***************************** TypePointer *****************************/ - -TypePointer::TypePointer(Type *t) - : TypeNext(Tpointer, t) -{ -} - -Type *TypePointer::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - { t = new TypePointer(t); - t->mod = mod; - } - return t; -} - -Type *TypePointer::semantic(Loc loc, Scope *sc) -{ - //printf("TypePointer::semantic()\n"); - if (deco) - return this; - Type *n = next->semantic(loc, sc); - switch (n->toBasetype()->ty) - { - case Ttuple: - error(loc, "can't have pointer to %s", n->toChars()); - case Terror: - return Type::terror; - } - if (n != next) - { - deco = NULL; - } - next = n; - transitive(); - return merge(); -} - - -d_uns64 TypePointer::size(Loc loc) -{ - return PTRSIZE; -} - -void TypePointer::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypePointer::toCBuffer2() next = %d\n", next->ty); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - if (next->ty != Tfunction) - buf->writeByte('*'); -} - -MATCH TypePointer::implicitConvTo(Type *to) -{ - //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); - - if (equals(to)) - return MATCHexact; - if (next->ty == Tfunction) - { - if (to->ty == Tpointer) - { - TypePointer *tp = (TypePointer*)to; - if (tp->next->ty == Tfunction) - { - if (next->equals(tp->next)) - return MATCHconst; - - if (next->covariant(tp->next) == 1) - return MATCHconvert; - } - else if (tp->next->ty == Tvoid) - { - // Allow conversions to void* - return MATCHconvert; - } - } - return MATCHnomatch; - } - else if (to->ty == Tpointer) - { - TypePointer *tp = (TypePointer *)to; - assert(tp->next); - - if (!MODimplicitConv(next->mod, tp->next->mod)) - return MATCHnomatch; // not const-compatible - - // Check head inout conversion: - // T * -> inout(const(T)*) - // const(T)* -> inout(const(T)*) - if (isMutable() && tp->isWild()) - if ((next->isMutable() || next->isConst()) && tp->next->isConst()) - return MATCHnomatch; - - /* Alloc conversion to void* - */ - if (next->ty != Tvoid && tp->next->ty == Tvoid) - { - return MATCHconvert; - } - - MATCH m = next->constConv(tp->next); - if (m != MATCHnomatch) - { - if (m == MATCHexact && mod != to->mod) - m = MATCHconst; - return m; - } - } - return MATCHnomatch; -} - -MATCH TypePointer::constConv(Type *to) -{ - if (next->ty == Tfunction) - { - if (to->nextOf() && next->equals(((TypeNext*)to)->next)) - return Type::constConv(to); - else - return MATCHnomatch; - } - return TypeNext::constConv(to); -} - -int TypePointer::isscalar() -{ - return TRUE; -} - -Expression *TypePointer::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypePointer::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypePointer::isZeroInit(Loc loc) -{ - return 1; -} - -int TypePointer::hasPointers() -{ - return TRUE; -} - - -/***************************** TypeReference *****************************/ - -TypeReference::TypeReference(Type *t) - : TypeNext(Treference, t) -{ - // BUG: what about references to static arrays? -} - -Type *TypeReference::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - { t = new TypeReference(t); - t->mod = mod; - } - return t; -} - -Type *TypeReference::semantic(Loc loc, Scope *sc) -{ - //printf("TypeReference::semantic()\n"); - Type *n = next->semantic(loc, sc); - if (n != next) - deco = NULL; - next = n; - transitive(); - return merge(); -} - - -d_uns64 TypeReference::size(Loc loc) -{ - return PTRSIZE; -} - -void TypeReference::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - buf->writeByte('&'); -} - -Expression *TypeReference::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeReference::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - - // References just forward things along - return next->dotExp(sc, e, ident); -} - -Expression *TypeReference::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeReference::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeReference::isZeroInit(Loc loc) -{ - return 1; -} - - -/***************************** TypeFunction *****************************/ - -TypeFunction::TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc) - : TypeNext(Tfunction, treturn) -{ -//if (!treturn) *(char*)0=0; -// assert(treturn); - assert(0 <= varargs && varargs <= 2); - this->parameters = parameters; - this->varargs = varargs; - this->linkage = linkage; - this->inuse = 0; - this->isnothrow = false; - this->purity = PUREimpure; - this->isproperty = false; - this->isref = false; - this->fargs = NULL; - -#if IN_LLVM - this->funcdecl = NULL; -#endif - if (stc & STCpure) - this->purity = PUREfwdref; - if (stc & STCnothrow) - this->isnothrow = true; - if (stc & STCproperty) - this->isproperty = true; - - if (stc & STCref) - this->isref = true; - - this->trust = TRUSTdefault; - if (stc & STCsafe) - this->trust = TRUSTsafe; - if (stc & STCsystem) - this->trust = TRUSTsystem; - if (stc & STCtrusted) - this->trust = TRUSTtrusted; -} - -Type *TypeFunction::syntaxCopy() -{ - Type *treturn = next ? next->syntaxCopy() : NULL; - Parameters *params = Parameter::arraySyntaxCopy(parameters); - TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage); - t->mod = mod; - t->isnothrow = isnothrow; - t->purity = purity; - t->isproperty = isproperty; - t->isref = isref; - t->trust = trust; - t->fargs = fargs; - return t; -} - -/******************************* - * Covariant means that 'this' can substitute for 't', - * i.e. a pure function is a match for an impure type. - * Returns: - * 0 types are distinct - * 1 this is covariant with t - * 2 arguments match as far as overloading goes, - * but types are not covariant - * 3 cannot determine covariance because of forward references - */ - -int Type::covariant(Type *t) -{ -#if 0 - printf("Type::covariant(t = %s) %s\n", t->toChars(), toChars()); - printf("deco = %p, %p\n", deco, t->deco); -// printf("ty = %d\n", next->ty); - printf("mod = %x, %x\n", mod, t->mod); -#endif - - int inoutmismatch = 0; - - TypeFunction *t1; - TypeFunction *t2; - - if (equals(t)) - return 1; // covariant - - if (ty != Tfunction || t->ty != Tfunction) - goto Ldistinct; - - t1 = (TypeFunction *)this; - t2 = (TypeFunction *)t; - - if (t1->varargs != t2->varargs) - goto Ldistinct; - - if (t1->parameters && t2->parameters) - { - size_t dim = Parameter::dim(t1->parameters); - if (dim != Parameter::dim(t2->parameters)) - goto Ldistinct; - - for (size_t i = 0; i < dim; i++) - { Parameter *arg1 = Parameter::getNth(t1->parameters, i); - Parameter *arg2 = Parameter::getNth(t2->parameters, i); - - if (!arg1->type->equals(arg2->type)) - { -#if 0 // turn on this for contravariant argument types, see bugzilla 3075 - // BUG: cannot convert ref to const to ref to immutable - // We can add const, but not subtract it - if (arg2->type->implicitConvTo(arg1->type) < MATCHconst) -#endif - goto Ldistinct; - } - const StorageClass sc = STCref | STCin | STCout | STClazy; - if ((arg1->storageClass & sc) != (arg2->storageClass & sc)) - inoutmismatch = 1; - // We can add scope, but not subtract it - if (!(arg1->storageClass & STCscope) && (arg2->storageClass & STCscope)) - inoutmismatch = 1; - } - } - else if (t1->parameters != t2->parameters) - { - size_t dim1 = !t1->parameters ? 0 : t1->parameters->dim; - size_t dim2 = !t2->parameters ? 0 : t2->parameters->dim; - if (dim1 || dim2) - goto Ldistinct; - } - - // The argument lists match - if (inoutmismatch) - goto Lnotcovariant; - if (t1->linkage != t2->linkage) - goto Lnotcovariant; - - { - // Return types - Type *t1n = t1->next; - Type *t2n = t2->next; - - if (!t1n || !t2n) // happens with return type inference - goto Lnotcovariant; - - if (t1n->equals(t2n)) - goto Lcovariant; - if (t1n->ty == Tclass && t2n->ty == Tclass) - { - /* If same class type, but t2n is const, then it's - * covariant. Do this test first because it can work on - * forward references. - */ - if (((TypeClass *)t1n)->sym == ((TypeClass *)t2n)->sym && - MODimplicitConv(t1n->mod, t2n->mod)) - goto Lcovariant; - - // If t1n is forward referenced: - ClassDeclaration *cd = ((TypeClass *)t1n)->sym; -// if (cd->scope) -// cd->semantic(NULL); -#if 0 - if (!cd->baseClass && cd->baseclasses->dim && !cd->isInterfaceDeclaration()) -#else - if (!cd->isBaseInfoComplete()) -#endif - { - return 3; // forward references - } - } - if (t1n->ty == Tstruct && t2n->ty == Tstruct) - { - if (((TypeStruct *)t1n)->sym == ((TypeStruct *)t2n)->sym && - MODimplicitConv(t1n->mod, t2n->mod)) - goto Lcovariant; - } - else if (t1n->ty == t2n->ty && t1n->implicitConvTo(t2n)) - goto Lcovariant; - } - goto Lnotcovariant; - -Lcovariant: - /* Can convert mutable to const - */ - if (!MODimplicitConv(t2->mod, t1->mod)) - goto Lnotcovariant; -#if 0 - if (t1->mod != t2->mod) - { - if (!(t1->mod & MODconst) && (t2->mod & MODconst)) - goto Lnotcovariant; - if (!(t1->mod & MODshared) && (t2->mod & MODshared)) - goto Lnotcovariant; - } -#endif - - /* Can convert pure to impure, and nothrow to throw - */ - if (!t1->purity && t2->purity) - goto Lnotcovariant; - - if (!t1->isnothrow && t2->isnothrow) - goto Lnotcovariant; - - if (t1->isref != t2->isref) - goto Lnotcovariant; - - /* Can convert safe/trusted to system - */ - if (t1->trust <= TRUSTsystem && t2->trust >= TRUSTtrusted) - goto Lnotcovariant; - - //printf("\tcovaraint: 1\n"); - return 1; - -Ldistinct: - //printf("\tcovaraint: 0\n"); - return 0; - -Lnotcovariant: - //printf("\tcovaraint: 2\n"); - return 2; -} - -void TypeFunction::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ unsigned char mc; - - //printf("TypeFunction::toDecoBuffer() this = %p %s\n", this, toChars()); - //static int nest; if (++nest == 50) *(char*)0=0; - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - MODtoDecoBuffer(buf, mod); - switch (linkage) - { - case LINKd: mc = 'F'; break; - case LINKc: mc = 'U'; break; - case LINKwindows: mc = 'W'; break; - case LINKpascal: mc = 'V'; break; - case LINKcpp: mc = 'R'; break; - - // LDC - case LINKintrinsic: mc = 'Q'; break; - - default: - assert(0); - } - buf->writeByte(mc); - if (purity || isnothrow || isproperty || isref || trust) - { - if (purity) - buf->writestring("Na"); - if (isnothrow) - buf->writestring("Nb"); - if (isref) - buf->writestring("Nc"); - if (isproperty) - buf->writestring("Nd"); - switch (trust) - { - case TRUSTtrusted: - buf->writestring("Ne"); - break; - case TRUSTsafe: - buf->writestring("Nf"); - break; - } - } - - // LDC: if we're not producing a mangle string, add the this - // type to prevent merging different member function - if (!mangle && funcdecl) - { - if (funcdecl->needThis()) - { - AggregateDeclaration* ad = funcdecl->isMember2(); - buf->writeByte('M'); - ad->type->toDecoBuffer(buf, 0, false); - } - if (FuncLiteralDeclaration *literal = funcdecl->isFuncLiteralDeclaration()) { - // Never merge types of function literals of different kind - if (literal->tok == TOKreserved) - buf->writeByte('L'); - else if (literal->tok == TOKfunction) - buf->writeByte('F'); - else if (literal->tok == TOKdelegate) - buf->writeByte('D'); - } - /* BUG This causes problems with delegate types - On the other hand, the llvm type for nested functions *is* different - so not doing anything here may be lead to bugs! - A sane solution would be DtoType(Dsymbol)... - if (funcdecl->isNested()) - { - buf->writeByte('M'); - if (funcdecl->toParent2() && funcdecl->toParent2()->isFuncDeclaration()) - { - FuncDeclaration* fd = funcdecl->toParent2()->isFuncDeclaration(); - fd->type->toDecoBuffer(buf, 0, false); - } - }*/ - } - - // Write argument types - Parameter::argsToDecoBuffer(buf, parameters, mangle); - //if (buf->data[buf->offset - 1] == '@') halt(); - buf->writeByte('Z' - varargs); // mark end of arg list - assert(next); - next->toDecoBuffer(buf, 0, mangle); - inuse--; -} - -void TypeFunction::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - toCBufferWithAttributes(buf, ident, hgs, this, NULL); -} - -void TypeFunction::toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td) -{ - //printf("TypeFunction::toCBuffer() this = %p\n", this); - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - - /* Use 'storage class' style for attributes - */ - if (attrs->mod) - { - MODtoBuffer(buf, attrs->mod); - buf->writeByte(' '); - } - - if (attrs->purity) - buf->writestring("pure "); - if (attrs->isnothrow) - buf->writestring("nothrow "); - if (attrs->isproperty) - buf->writestring("@property "); - if (attrs->isref) - buf->writestring("ref "); - - switch (attrs->trust) - { - case TRUSTsystem: - buf->writestring("@system "); - break; - - case TRUSTtrusted: - buf->writestring("@trusted "); - break; - - case TRUSTsafe: - buf->writestring("@safe "); - break; - } - - if (hgs->ddoc != 1) - { - const char *p = NULL; - switch (attrs->linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - case LINKcpp: p = "C++"; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - - if (!ident || ident->toHChars2() == ident->toChars()) - { if (next) - next->toCBuffer2(buf, hgs, 0); - else if (hgs->ddoc) - buf->writestring("auto"); - } - - if (ident) - { - if (next || hgs->ddoc) - buf->writeByte(' '); - buf->writestring(ident->toHChars2()); - } - - if (td) - { buf->writeByte('('); - for (size_t i = 0; i < td->origParameters->dim; i++) - { - TemplateParameter *tp = td->origParameters->tdata()[i]; - if (i) - buf->writestring(", "); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); - } - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); - inuse--; -} - -void TypeFunction::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeFunction::toCBuffer2() this = %p, ref = %d\n", this, isref); - if (inuse) - { inuse = 2; // flag error to caller - return; - } - inuse++; - if (hgs->ddoc != 1) - { - const char *p = NULL; - switch (linkage) - { - case LINKd: p = NULL; break; - case LINKc: p = "C"; break; - case LINKwindows: p = "Windows"; break; - case LINKpascal: p = "Pascal"; break; - case LINKcpp: p = "C++"; break; - - // LDC - case LINKintrinsic: p = "Intrinsic"; break; - - default: - assert(0); - } - if (!hgs->hdrgen && p) - { - buf->writestring("extern ("); - buf->writestring(p); - buf->writestring(") "); - } - } - if (next) - { - next->toCBuffer2(buf, hgs, 0); - buf->writeByte(' '); - } - buf->writestring("function"); - Parameter::argsToCBuffer(buf, hgs, parameters, varargs); - attributesToCBuffer(buf, mod); - inuse--; -} - -void TypeFunction::attributesToCBuffer(OutBuffer *buf, int mod) -{ - /* Use postfix style for attributes - */ - if (mod != this->mod) - { - modToBuffer(buf); - } - if (purity) - buf->writestring(" pure"); - if (isnothrow) - buf->writestring(" nothrow"); - if (isproperty) - buf->writestring(" @property"); - if (isref) - buf->writestring(" ref"); - - switch (trust) - { - case TRUSTsystem: - buf->writestring(" @system"); - break; - - case TRUSTtrusted: - buf->writestring(" @trusted"); - break; - - case TRUSTsafe: - buf->writestring(" @safe"); - break; - } -} - -Type *TypeFunction::semantic(Loc loc, Scope *sc) -{ - if (deco) // if semantic() already run - { - //printf("already done\n"); - return this; - } - //printf("TypeFunction::semantic() this = %p\n", this); - //printf("TypeFunction::semantic() %s, sc->stc = %llx, fargs = %p\n", toChars(), sc->stc, fargs); - - /* Copy in order to not mess up original. - * This can produce redundant copies if inferring return type, - * as semantic() will get called again on this. - */ - TypeFunction *tf = (TypeFunction *)mem.malloc(sizeof(TypeFunction)); - memcpy(tf, this, sizeof(TypeFunction)); - if (parameters) - { tf->parameters = (Parameters *)parameters->copy(); - for (size_t i = 0; i < parameters->dim; i++) - { Parameter *arg = parameters->tdata()[i]; - Parameter *cpy = (Parameter *)mem.malloc(sizeof(Parameter)); - memcpy(cpy, arg, sizeof(Parameter)); - tf->parameters->tdata()[i] = cpy; - } - } - - if (sc->stc & STCpure) - tf->purity = PUREfwdref; - if (sc->stc & STCnothrow) - tf->isnothrow = TRUE; - if (sc->stc & STCref) - tf->isref = TRUE; - if (sc->stc & STCsafe) - tf->trust = TRUSTsafe; - if (sc->stc & STCtrusted) - tf->trust = TRUSTtrusted; - if (sc->stc & STCproperty) - tf->isproperty = TRUE; - - tf->linkage = sc->linkage; - - /* If the parent is @safe, then this function defaults to safe - * too. - */ - if (tf->trust == TRUSTdefault) - for (Dsymbol *p = sc->func; p; p = p->toParent2()) - { FuncDeclaration *fd = p->isFuncDeclaration(); - if (fd) - { - if (fd->isSafe()) - tf->trust = TRUSTsafe; // default to @safe - break; - } - } - - bool wildreturn = FALSE; - if (tf->next) - { - sc = sc->push(); - sc->stc &= ~(STC_TYPECTOR | STC_FUNCATTR); - tf->next = tf->next->semantic(loc,sc); - sc = sc->pop(); -#if !SARRAYVALUE - if (tf->next->toBasetype()->ty == Tsarray) - { error(loc, "functions cannot return static array %s", tf->next->toChars()); - tf->next = Type::terror; - } -#endif - if (tf->next->toBasetype()->ty == Tfunction) - { error(loc, "functions cannot return a function"); - tf->next = Type::terror; - } - if (tf->next->toBasetype()->ty == Ttuple) - { error(loc, "functions cannot return a tuple"); - tf->next = Type::terror; - } - if (tf->next->isscope() && !(sc->flags & SCOPEctor)) - error(loc, "functions cannot return scope %s", tf->next->toChars()); - if (tf->next->toBasetype()->ty == Tvoid) - tf->isref = FALSE; // rewrite "ref void" as just "void" - if (tf->next->hasWild() && - !(tf->next->ty == Tpointer && tf->next->nextOf()->ty == Tfunction || tf->next->ty == Tdelegate)) - wildreturn = TRUE; - } - - bool wildparams = FALSE; - bool wildsubparams = FALSE; - if (tf->parameters) - { - /* Create a scope for evaluating the default arguments for the parameters - */ - Scope *argsc = sc->push(); - argsc->stc = 0; // don't inherit storage class - argsc->protection = PROTpublic; - argsc->func = NULL; - - size_t dim = Parameter::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Parameter *fparam = Parameter::getNth(tf->parameters, i); - - tf->inuse++; - fparam->type = fparam->type->semantic(loc, argsc); - if (tf->inuse == 1) tf->inuse--; - - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - - if (fparam->storageClass & (STCauto | STCalias | STCstatic)) - { - if (!fparam->type) - continue; - } -// Possible merge conflict - Type *t = fparam->type->toBasetype(); - - if (fparam->storageClass & (STCout | STCref | STClazy)) - { - //if (t->ty == Tsarray) - //error(loc, "cannot have out or ref parameter of type %s", t->toChars()); - if (fparam->storageClass & STCout && fparam->type->mod & (STCconst | STCimmutable)) - error(loc, "cannot have const or immutable out parameter of type %s", t->toChars()); - } - if (!(fparam->storageClass & STClazy) && t->ty == Tvoid) - error(loc, "cannot have parameter of type %s", fparam->type->toChars()); - - if (t->hasWild() && - !(t->ty == Tpointer && t->nextOf()->ty == Tfunction || t->ty == Tdelegate)) - { - wildparams = TRUE; - if (tf->next && !wildreturn) - error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with 'ref')"); - } - else if (!wildsubparams && t->hasWild()) - wildsubparams = TRUE; - - if (fparam->defaultArg) - { - fparam->defaultArg = fparam->defaultArg->semantic(argsc); - fparam->defaultArg = resolveProperties(argsc, fparam->defaultArg); - fparam->defaultArg = fparam->defaultArg->implicitCastTo(argsc, fparam->type); - } - - /* If fparam after semantic() turns out to be a tuple, the number of parameters may - * change. - */ - if (t->ty == Ttuple) - { - TypeTuple *tt = (TypeTuple *)t; - if (fparam->storageClass && tt->arguments && tt->arguments->dim) - { - /* Propagate additional storage class from tuple parameters to their - * element-parameters. - * Make a copy, as original may be referenced elsewhere. - */ - size_t tdim = tt->arguments->dim; - Parameters *newparams = new Parameters(); - newparams->setDim(tdim); - for (size_t j = 0; j < tdim; j++) - { Parameter *narg = (*tt->arguments)[j]; - newparams->tdata()[j] = new Parameter(narg->storageClass | fparam->storageClass, - narg->type, narg->ident, narg->defaultArg); - } - fparam->type = new TypeTuple(newparams); - } - fparam->storageClass = 0; - - /* Reset number of parameters, and back up one to do this fparam again, - * now that it is a tuple - */ - dim = Parameter::dim(tf->parameters); - i--; - continue; - } - - /* Resolve "auto ref" storage class to be either ref or value, - * based on the argument matching the parameter - */ - if (fparam->storageClass & STCauto) - { - if (fargs && i < fargs->dim) - { Expression *farg = fargs->tdata()[i]; - if (farg->isLvalue()) - ; // ref parameter - else - fparam->storageClass &= ~STCref; // value parameter - } - else - error(loc, "auto can only be used for template function parameters"); - } - - // Remove redundant storage classes for type, they are already applied - fparam->storageClass &= ~(STC_TYPECTOR | STCin); - } - argsc->pop(); - } - if (tf->isWild()) - wildparams = TRUE; - - if (wildreturn && !wildparams) - error(loc, "inout on return means inout must be on a parameter as well for %s", toChars()); - if (wildsubparams && wildparams) - error(loc, "inout must be all or none on top level for %s", toChars()); - - if (tf->next) - tf->deco = tf->merge()->deco; - - if (tf->inuse) - { error(loc, "recursive type"); - tf->inuse = 0; - return terror; - } - - if (tf->isproperty && (tf->varargs || Parameter::dim(tf->parameters) > 1)) - error(loc, "properties can only have zero or one parameter"); - - if (tf->varargs == 1 && tf->linkage != LINKd && Parameter::dim(tf->parameters) == 0) - error(loc, "variadic functions with non-D linkage must have at least one parameter"); - - /* Don't return merge(), because arg identifiers and default args - * can be different - * even though the types match - */ - return tf; -} - - -/******************************************** - * Do this lazily, as the parameter types might be forward referenced. - */ -void TypeFunction::purityLevel() -{ - TypeFunction *tf = this; - if (tf->purity == PUREfwdref) - { /* Evaluate what kind of purity based on the modifiers for the parameters - */ - tf->purity = PUREstrong; // assume strong until something weakens it - if (tf->parameters) - { - size_t dim = Parameter::dim(tf->parameters); - for (size_t i = 0; i < dim; i++) - { Parameter *fparam = Parameter::getNth(tf->parameters, i); - if (fparam->storageClass & STClazy) - { - tf->purity = PUREweak; - break; - } - if (fparam->storageClass & STCout) - { - tf->purity = PUREweak; - break; - } - if (!fparam->type) - continue; - if (fparam->storageClass & STCref) - { - if (!(fparam->type->mod & (MODconst | MODimmutable | MODwild))) - { tf->purity = PUREweak; - break; - } - if (fparam->type->mod & MODconst) - { tf->purity = PUREconst; - continue; - } - } - Type *t = fparam->type->toBasetype(); - if (!t->hasPointers()) - continue; - if (t->mod & (MODimmutable | MODwild)) - continue; - /* The rest of this is too strict; fix later. - * For example, the only pointer members of a struct may be immutable, - * which would maintain strong purity. - */ - if (t->mod & MODconst) - { tf->purity = PUREconst; - continue; - } - Type *tn = t->nextOf(); - if (tn) - { tn = tn->toBasetype(); - if (tn->ty == Tpointer || tn->ty == Tarray) - { /* Accept immutable(T)* and immutable(T)[] as being strongly pure - */ - if (tn->mod & (MODimmutable | MODwild)) - continue; - if (tn->mod & MODconst) - { tf->purity = PUREconst; - continue; - } - } - } - /* Should catch delegates and function pointers, and fold in their purity - */ - tf->purity = PUREweak; // err on the side of too strict - break; - } - } - } -} - - -/******************************** - * 'args' are being matched to function 'this' - * Determine match level. - * Input: - * flag 1 performing a partial ordering match - * Returns: - * MATCHxxxx - */ - -int TypeFunction::callMatch(Expression *ethis, Expressions *args, int flag) -{ - //printf("TypeFunction::callMatch() %s\n", toChars()); - MATCH match = MATCHexact; // assume exact match - unsigned wildmatch = 0; - - if (ethis) - { Type *t = ethis->type; - if (t->toBasetype()->ty == Tpointer) - t = t->toBasetype()->nextOf(); // change struct* to struct - if (t->mod != mod) - { - if (MODimplicitConv(t->mod, mod)) - match = MATCHconst; - else if ((mod & MODwild) - && MODimplicitConv(t->mod, (mod & ~MODwild) | MODconst)) - { - match = MATCHconst; - } - else - return MATCHnomatch; - } - if (isWild()) - { - if (t->isWild()) - wildmatch |= MODwild; - else if (t->isConst()) - wildmatch |= MODconst; - else if (t->isImmutable()) - wildmatch |= MODimmutable; - else - wildmatch |= MODmutable; - } - } - - size_t nparams = Parameter::dim(parameters); - size_t nargs = args ? args->dim : 0; - if (nparams == nargs) - ; - else if (nargs > nparams) - { - if (varargs == 0) - goto Nomatch; // too many args; no match - match = MATCHconvert; // match ... with a "conversion" match level - } - - for (size_t u = 0; u < nargs; u++) - { - if (u >= nparams) - break; - Parameter *p = Parameter::getNth(parameters, u); - Expression *arg = args->tdata()[u]; - assert(arg); - - if (!(p->storageClass & STClazy && p->type->ty == Tvoid && arg->type->ty != Tvoid)) - { - unsigned mod = arg->type->wildConvTo(p->type); - if (mod) - { - wildmatch |= mod; - } - } - } - if (wildmatch) - { /* Calculate wild matching modifier - */ - if (wildmatch & MODconst || wildmatch & (wildmatch - 1)) - wildmatch = MODconst; - else if (wildmatch & MODimmutable) - wildmatch = MODimmutable; - else if (wildmatch & MODwild) - wildmatch = MODwild; - else - { assert(wildmatch & MODmutable); - wildmatch = MODmutable; - } - } - - for (size_t u = 0; u < nparams; u++) - { MATCH m; - - // BUG: what about out and ref? - - Parameter *p = Parameter::getNth(parameters, u); - assert(p); - if (u >= nargs) - { - if (p->defaultArg) - continue; - goto L1; // try typesafe variadics - } - { - Expression *arg = args->tdata()[u]; - assert(arg); - - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *pt = p->type; - arg = ((FuncExp *)arg)->inferType(NULL, pt); - if (!arg) - goto L1; // try typesafe variadics - } - - //printf("arg: %s, type: %s\n", arg->toChars(), arg->type->toChars()); - - Type *targ = arg->type; - Type *tprm = wildmatch ? p->type->substWildTo(wildmatch) : p->type; - - // Non-lvalues do not match ref or out parameters - if (p->storageClass & STCref) - { if (!arg->isLvalue()) - { if (arg->op == TOKstring && tprm->ty == Tsarray) - { if (targ->ty != Tsarray) - targ = new TypeSArray(targ->nextOf(), - new IntegerExp(0, ((StringExp *)arg)->len, - Type::tindex)); - } - else - goto Nomatch; - } - - /* Don't allow static arrays to be passed to mutable references - * to static arrays if the argument cannot be modified. - */ - Type *targb = targ->toBasetype(); - Type *tprmb = tprm->toBasetype(); - //printf("%s\n", targb->toChars()); - //printf("%s\n", tprmb->toChars()); - if (targb->nextOf() && tprmb->ty == Tsarray && - !MODimplicitConv(targb->nextOf()->mod, tprmb->nextOf()->mod)) - goto Nomatch; - - // ref variable behaves like head-const reference - if (!targb->constConv(tprmb)) - goto Nomatch; - } - else if (p->storageClass & STCout) - { if (!arg->isLvalue()) - goto Nomatch; - } - - if (p->storageClass & STClazy && tprm->ty == Tvoid && targ->ty != Tvoid) - m = MATCHconvert; - else - { - //printf("%s of type %s implicitConvTo %s\n", arg->toChars(), targ->toChars(), tprm->toChars()); - if (flag) - // for partial ordering, value is an irrelevant mockup, just look at the type - m = targ->implicitConvTo(tprm); - else - m = arg->implicitConvTo(tprm); - //printf("match %d\n", m); - } - } - - /* prefer matching the element type rather than the array - * type when more arguments are present with T[]... - */ - if (varargs == 2 && u + 1 == nparams && nargs > nparams) - goto L1; - - //printf("\tm = %d\n", m); - if (m == MATCHnomatch) // if no match - { - L1: - if (varargs == 2 && u + 1 == nparams) // if last varargs param - { Type *tb = p->type->toBasetype(); - TypeSArray *tsa; - dinteger_t sz; - - switch (tb->ty) - { - case Tsarray: - tsa = (TypeSArray *)tb; - sz = tsa->dim->toInteger(); - if (sz != nargs - u) - goto Nomatch; - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; u < nargs; u++) - { - Expression *arg = args->tdata()[u]; - assert(arg); -#if 1 - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *pt = tb->nextOf(); - arg = ((FuncExp *)arg)->inferType(NULL, pt); - if (!arg) - goto Nomatch; - } - - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = p->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - m = arg->implicitConvTo(ta->next); -#else - m = arg->implicitConvTo(ta->next); -#endif - if (m == MATCHnomatch) - goto Nomatch; - if (m < match) - match = m; - } - goto Ldone; - } - case Tclass: - // Should see if there's a constructor match? - // Or just leave it ambiguous? - goto Ldone; - - default: - goto Nomatch; - } - } - goto Nomatch; - } - if (m < match) - match = m; // pick worst match - } - -Ldone: - //printf("match = %d\n", match); - return match; - -Nomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -Type *TypeFunction::reliesOnTident() -{ - size_t dim = Parameter::dim(parameters); - for (size_t i = 0; i < dim; i++) - { Parameter *fparam = Parameter::getNth(parameters, i); - Type *t = fparam->type->reliesOnTident(); - if (t) - return t; - } - return next ? next->reliesOnTident() : NULL; -} - -/******************************************** - * Return TRUE if there are lazy parameters. - */ -bool TypeFunction::hasLazyParameters() -{ - size_t dim = Parameter::dim(parameters); - for (size_t i = 0; i < dim; i++) - { Parameter *fparam = Parameter::getNth(parameters, i); - if (fparam->storageClass & STClazy) - return TRUE; - } - return FALSE; -} - -/*************************** - * Examine function signature for parameter p and see if - * p can 'escape' the scope of the function. - */ - -bool TypeFunction::parameterEscapes(Parameter *p) -{ - - /* Scope parameters do not escape. - * Allow 'lazy' to imply 'scope' - - * lazy parameters can be passed along - * as lazy parameters to the next function, but that isn't - * escaping. - */ - if (p->storageClass & (STCscope | STClazy)) - return FALSE; - - if (purity) - { /* With pure functions, we need only be concerned if p escapes - * via any return statement. - */ - Type* tret = nextOf()->toBasetype(); - if (!isref && !tret->hasPointers()) - { /* The result has no references, so p could not be escaping - * that way. - */ - return FALSE; - } - } - - /* Assume it escapes in the absence of better information. - */ - return TRUE; -} - -Expression *TypeFunction::defaultInit(Loc loc) -{ - error(loc, "function does not have a default initializer"); - return new ErrorExp(); -} - -/***************************** TypeDelegate *****************************/ - -TypeDelegate::TypeDelegate(Type *t) - : TypeNext(Tfunction, t) -{ - ty = Tdelegate; -} - -Type *TypeDelegate::syntaxCopy() -{ - Type *t = next->syntaxCopy(); - if (t == next) - t = this; - else - { t = new TypeDelegate(t); - t->mod = mod; - } - return t; -} - -Type *TypeDelegate::semantic(Loc loc, Scope *sc) -{ - if (deco) // if semantic() already run - { - //printf("already done\n"); - return this; - } - next = next->semantic(loc,sc); - /* In order to deal with Bugzilla 4028, perhaps default arguments should - * be removed from next before the merge. - */ - - /* Don't return merge(), because arg identifiers and default args - * can be different - * even though the types match - */ - //deco = merge()->deco; - //return this; - return merge(); -} - -d_uns64 TypeDelegate::size(Loc loc) -{ - return PTRSIZE * 2; -} - -// LDC added, no reason to align to 2*PTRSIZE -unsigned TypeDelegate::alignsize() -{ - // A Delegate consists of two ptr values, so align it on pointer size - // boundary - return PTRSIZE; -} - -MATCH TypeDelegate::implicitConvTo(Type *to) -{ - //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to->toChars()); - if (this == to) - return MATCHexact; -#if 1 // not allowing covariant conversions because it interferes with overriding - if (to->ty == Tdelegate && this->nextOf()->covariant(to->nextOf()) == 1) - return MATCHconvert; -#endif - return MATCHnomatch; -} - -void TypeDelegate::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - TypeFunction *tf = (TypeFunction *)next; - - tf->next->toCBuffer2(buf, hgs, 0); - buf->writestring(" delegate"); - Parameter::argsToCBuffer(buf, hgs, tf->parameters, tf->varargs); - tf->attributesToCBuffer(buf, mod); -} - -Expression *TypeDelegate::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeDelegate::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeDelegate::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeDelegate::checkBoolean() -{ - return TRUE; -} - -Expression *TypeDelegate::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeDelegate::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (ident == Id::ptr) - { - e = new GEPExp(e->loc, e, ident, 0); - e->type = tvoidptr; - return e; - } - else if (ident == Id::funcptr) - { - e = new GEPExp(e->loc, e, ident, 1); - e->type = next->pointerTo(); - return e; - } - else - { - e = Type::dotExp(sc, e, ident); - } - return e; -} - -int TypeDelegate::hasPointers() -{ - return TRUE; -} - - - -/***************************** TypeQualified *****************************/ - -TypeQualified::TypeQualified(TY ty, Loc loc) - : Type(ty) -{ - this->loc = loc; -} - -void TypeQualified::syntaxCopyHelper(TypeQualified *t) -{ - //printf("TypeQualified::syntaxCopyHelper(%s) %s\n", t->toChars(), toChars()); - idents.setDim(t->idents.dim); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = t->idents.tdata()[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - idents.tdata()[i] = id; - } -} - - -void TypeQualified::addIdent(Identifier *ident) -{ - idents.push(ident); -} - -void TypeQualified::toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs) -{ - for (size_t i = 0; i < idents.dim; i++) - { Identifier *id = idents.tdata()[i]; - - buf->writeByte('.'); - - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - ti->toCBuffer(buf, hgs); - } - else - buf->writestring(id->toChars()); - } -} - -d_uns64 TypeQualified::size(Loc loc) -{ - error(this->loc, "size of type %s is not known", toChars()); - return 1; -} - -/************************************* - * Takes an array of Identifiers and figures out if - * it represents a Type or an Expression. - * Output: - * if expression, *pe is set - * if type, *pt is set - */ - -void TypeQualified::resolveHelper(Loc loc, Scope *sc, - Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps) -{ - VarDeclaration *v; - EnumMember *em; - Expression *e; - -#if 0 - printf("TypeQualified::resolveHelper(sc = %p, idents = '%s')\n", sc, toChars()); - if (scopesym) - printf("\tscopesym = '%s'\n", scopesym->toChars()); -#endif - *pe = NULL; - *pt = NULL; - *ps = NULL; - if (s) - { - //printf("\t1: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - s->checkDeprecated(loc, sc); // check for deprecated aliases - s = s->toAlias(); - //printf("\t2: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = idents.tdata()[i]; - Dsymbol *sm = s->searchX(loc, sc, id); - //printf("\t3: s = '%s' %p, kind = '%s'\n",s->toChars(), s, s->kind()); - //printf("\tgetType = '%s'\n", s->getType()->toChars()); - if (!sm) - { Type *t; - - v = s->isVarDeclaration(); - if (v && id == Id::length) - { - e = v->getConstInitializer(); - if (!e) - e = new VarExp(loc, v); - t = e->type; - if (!t) - goto Lerror; - goto L3; - } - else if (v && (id == Id::stringof || id == Id::offsetof)) - { - e = new DsymbolExp(loc, s, 0); - do - { - id = idents.tdata()[i]; - e = new DotIdExp(loc, e, id); - } while (++i < idents.dim); - e = e->semantic(sc); - *pe = e; - return; - } - - t = s->getType(); - if (!t && s->isDeclaration()) - { t = s->isDeclaration()->type; - if (!t && s->isTupleDeclaration()) - { - e = new TupleExp(loc, s->isTupleDeclaration()); - e = e->semantic(sc); - t = e->type; - } - } - if (t) - { - sm = t->toDsymbol(sc); - if (sm) - { sm = sm->search(loc, id, 0); - if (sm) - goto L2; - } - //e = t->getProperty(loc, id); - e = new TypeExp(loc, t); - e = t->dotExp(sc, e, id); - i++; - L3: - for (; i < idents.dim; i++) - { - id = idents.tdata()[i]; - //printf("e: '%s', id: '%s', type = %s\n", e->toChars(), id->toChars(), e->type->toChars()); - e = new DotIdExp(e->loc, e, id); - e = e->semantic(sc); - } - if (e->op == TOKtype) - *pt = e->type; - else - *pe = e; - } - else - { - Lerror: - error(loc, "identifier '%s' of '%s' is not defined", id->toChars(), toChars()); - *pe = new ErrorExp(); - } - return; - } - L2: - s = sm->toAlias(); - } - - v = s->isVarDeclaration(); - if (v) - { - *pe = new VarExp(loc, v); - return; - } -#if 0 - fd = s->isFuncDeclaration(); - if (fd) - { - *pe = new DsymbolExp(loc, fd, 1); - return; - } -#endif - em = s->isEnumMember(); - if (em) - { - // It's not a type, it's an expression - *pe = em->value->copy(); - return; - } - -L1: - Type *t = s->getType(); - if (!t) - { - // If the symbol is an import, try looking inside the import - Import *si; - - si = s->isImport(); - if (si) - { - s = si->search(loc, s->ident, 0); - if (s && s != si) - goto L1; - s = si; - } - *ps = s; - return; - } - if (t->ty == Tinstance && t != this && !t->deco) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - - if (t != this) - { - if (t->reliesOnTident()) - { - if (s->scope) - t = t->semantic(loc, s->scope); - else - { - /* Attempt to find correct scope in which to evaluate t. - * Not sure if this is right or not, or if we should just - * give forward reference error if s->scope is not set. - */ - for (Scope *scx = sc; 1; scx = scx->enclosing) - { - if (!scx) - { error(loc, "forward reference to '%s'", t->toChars()); - return; - } - if (scx->scopesym == scopesym) - { - t = t->semantic(loc, scx); - break; - } - } - } - } - } - if (t->ty == Ttuple) - *pt = t; - else - *pt = t->merge(); - } - if (!s) - { - const char *p = toChars(); - const char *n = importHint(p); - if (n) - error(loc, "'%s' is not defined, perhaps you need to import %s; ?", p, n); - else - { - Identifier *id = new Identifier(p, TOKidentifier); - s = sc->search_correct(id); - if (s) - error(loc, "undefined identifier %s, did you mean %s %s?", p, s->kind(), s->toChars()); - else - error(loc, "undefined identifier %s", p); - } - *pt = Type::terror; - } -} - -/***************************** TypeIdentifier *****************************/ - -TypeIdentifier::TypeIdentifier(Loc loc, Identifier *ident) - : TypeQualified(Tident, loc) -{ - this->ident = ident; -} - - -Type *TypeIdentifier::syntaxCopy() -{ - TypeIdentifier *t; - - t = new TypeIdentifier(loc, ident); - t->syntaxCopyHelper(this); - t->mod = mod; - return t; -} - -void TypeIdentifier::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ unsigned len; - char *name; - - Type::toDecoBuffer(buf, flag, mangle); - name = ident->toChars(); - len = strlen(name); - buf->printf("%d%s", len, name); -} - -void TypeIdentifier::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(this->ident->toChars()); - toCBuffer2Helper(buf, hgs); -} - -/************************************* - * Takes an array of Identifiers and figures out if - * it represents a Type or an Expression. - * Output: - * if expression, *pe is set - * if type, *pt is set - */ - -void TypeIdentifier::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - Dsymbol *scopesym; - - //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, toChars()); - - if ((ident->equals(Id::super) || ident->equals(Id::This)) && !hasThis(sc)) - { - AggregateDeclaration *ad = sc->getStructClassScope(); - if (ad) - { - ClassDeclaration *cd = ad->isClassDeclaration(); - if (cd) - { - if (ident->equals(Id::This)) - ident = cd->ident; - else if (cd->baseClass && ident->equals(Id::super)) - ident = cd->baseClass->ident; - } - else - { - StructDeclaration *sd = ad->isStructDeclaration(); - if (sd && ident->equals(Id::This)) - ident = sd->ident; - } - } - } - - Dsymbol *s = sc->search(loc, ident, &scopesym); - resolveHelper(loc, sc, s, scopesym, pe, pt, ps); - if (*pt) - (*pt) = (*pt)->addMod(mod); -} - -/***************************************** - * See if type resolves to a symbol, if so, - * return that symbol. - */ - -Dsymbol *TypeIdentifier::toDsymbol(Scope *sc) -{ - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); - if (!sc) - return NULL; - //printf("ident = '%s'\n", ident->toChars()); - - Dsymbol *scopesym; - Dsymbol *s = sc->search(loc, ident, &scopesym); - if (s) - { - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = idents.tdata()[i]; - s = s->searchX(loc, sc, id); - if (!s) // failed to find a symbol - { //printf("\tdidn't find a symbol\n"); - break; - } - } - } - return s; -} - -Type *TypeIdentifier::semantic(Loc loc, Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeIdentifier::semantic(%s)\n", toChars()); - resolve(loc, sc, &e, &t, &s); - if (t) - { - //printf("\tit's a type %d, %s, %s\n", t->ty, t->toChars(), t->deco); - - if (t->ty == Ttypedef) - { TypeTypedef *tt = (TypeTypedef *)t; - - if (tt->sym->sem == 1) - error(loc, "circular reference of typedef %s", tt->toChars()); - } - t = t->addMod(mod); - } - else - { -#ifdef DEBUG - if (!global.gag) - printf("1: "); -#endif - if (s) - { - s->error(loc, "is used as a type"); - //halt(); - } - else - error(loc, "%s is used as a type", toChars()); - t = terror; - } - //t->print(); - return t; -} - -Type *TypeIdentifier::reliesOnTident() -{ - return this; -} - -Expression *TypeIdentifier::toExpression() -{ - Expression *e = new IdentifierExp(loc, ident); - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id = idents.tdata()[i]; - e = new DotIdExp(loc, e, id); - } - - return e; -} - -/***************************** TypeInstance *****************************/ - -TypeInstance::TypeInstance(Loc loc, TemplateInstance *tempinst) - : TypeQualified(Tinstance, loc) -{ - this->tempinst = tempinst; -} - -Type *TypeInstance::syntaxCopy() -{ - //printf("TypeInstance::syntaxCopy() %s, %d\n", toChars(), idents.dim); - TypeInstance *t; - - t = new TypeInstance(loc, (TemplateInstance *)tempinst->syntaxCopy(NULL)); - t->syntaxCopyHelper(this); - t->mod = mod; - return t; -} - - -void TypeInstance::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - tempinst->toCBuffer(buf, hgs); - toCBuffer2Helper(buf, hgs); -} - -void TypeInstance::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - // Note close similarity to TypeIdentifier::resolve() - - Dsymbol *s; - - *pe = NULL; - *pt = NULL; - *ps = NULL; - -#if 0 - if (!idents.dim) - { - error(loc, "template instance '%s' has no identifier", toChars()); - return; - } -#endif - //id = (Identifier *)idents.data[0]; - //printf("TypeInstance::resolve(sc = %p, idents = '%s')\n", sc, id->toChars()); - s = tempinst; - if (s) - { //printf("s = %s\n", s->toChars()); - s->semantic(sc); - } - resolveHelper(loc, sc, s, NULL, pe, pt, ps); - if (*pt) - *pt = (*pt)->addMod(mod); - //printf("pt = '%s'\n", (*pt)->toChars()); -} - -Type *TypeInstance::semantic(Loc loc, Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeInstance::semantic(%s)\n", toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - { - return this; - } - } - else - resolve(loc, sc, &e, &t, &s); - - if (!t) - { - error(loc, "%s is used as a type", toChars()); - t = terror; - } - return t; -} - -Dsymbol *TypeInstance::toDsymbol(Scope *sc) -{ - Type *t; - Expression *e; - Dsymbol *s; - - //printf("TypeInstance::semantic(%s)\n", toChars()); - - if (sc->parameterSpecialization) - { - unsigned errors = global.startGagging(); - - resolve(loc, sc, &e, &t, &s); - - if (global.endGagging(errors)) - return NULL; - } - else - resolve(loc, sc, &e, &t, &s); - - return s; -} - - -/***************************** TypeTypeof *****************************/ - -TypeTypeof::TypeTypeof(Loc loc, Expression *exp) - : TypeQualified(Ttypeof, loc) -{ - this->exp = exp; - inuse = 0; -} - -Type *TypeTypeof::syntaxCopy() -{ - //printf("TypeTypeof::syntaxCopy() %s\n", toChars()); - TypeTypeof *t; - - t = new TypeTypeof(loc, exp->syntaxCopy()); - t->syntaxCopyHelper(this); - t->mod = mod; - return t; -} - -Dsymbol *TypeTypeof::toDsymbol(Scope *sc) -{ - Type *t; - - t = semantic(loc, sc); - if (t == this) - return NULL; - return t->toDsymbol(sc); -} - -void TypeTypeof::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring("typeof("); - exp->toCBuffer(buf, hgs); - buf->writeByte(')'); - toCBuffer2Helper(buf, hgs); -} - -Type *TypeTypeof::semantic(Loc loc, Scope *sc) -{ - Type *t; - - //printf("TypeTypeof::semantic() %s\n", toChars()); - - //static int nest; if (++nest == 50) *(char*)0=0; - if (inuse) - { - inuse = 2; - error(loc, "circular typeof definition"); - return Type::terror; - } - inuse++; - -#if 0 - /* Special case for typeof(this) and typeof(super) since both - * should work even if they are not inside a non-static member function - */ - if (exp->op == TOKthis || exp->op == TOKsuper) - { - // Find enclosing struct or class - for (Dsymbol *s = sc->parent; 1; s = s->parent) - { - ClassDeclaration *cd; - StructDeclaration *sd; - - if (!s) - { - error(loc, "%s is not in a struct or class scope", exp->toChars()); - goto Lerr; - } - cd = s->isClassDeclaration(); - if (cd) - { - if (exp->op == TOKsuper) - { - cd = cd->baseClass; - if (!cd) - { error(loc, "class %s has no 'super'", s->toChars()); - goto Lerr; - } - } - t = cd->type; - break; - } - sd = s->isStructDeclaration(); - if (sd) - { - if (exp->op == TOKsuper) - { - error(loc, "struct %s has no 'super'", sd->toChars()); - goto Lerr; - } - t = sd->type->pointerTo(); - break; - } - } - } - else -#endif - { - Scope *sc2 = sc->push(); - sc2->intypeof++; - sc2->ignoreTemplates++; - sc2->flags |= sc->flags & SCOPEstaticif; - exp = exp->semantic(sc2); -#if DMDV2 - if (exp->type && exp->type->ty == Tfunction && - ((TypeFunction *)exp->type)->isproperty) - exp = resolveProperties(sc2, exp); -#endif - sc2->pop(); - if (exp->op == TOKtype) - { - error(loc, "argument %s to typeof is not an expression", exp->toChars()); - goto Lerr; - } - t = exp->type; - if (!t) - { - error(loc, "expression (%s) has no type", exp->toChars()); - goto Lerr; - } - if (t->ty == Ttypeof) - { error(loc, "forward reference to %s", toChars()); - goto Lerr; - } - - t = t->addMod(mod); - - /* typeof should reflect the true type, - * not what 'auto' would have gotten us. - */ - //t = t->toHeadMutable(); - } - if (idents.dim) - { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = idents.tdata()[i]; - s = s->searchX(loc, sc, id); - } - - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } - } - inuse--; - return t; - -Lerr: - inuse--; - return terror; -} - -d_uns64 TypeTypeof::size(Loc loc) -{ - if (exp->type) - return exp->type->size(loc); - else - return TypeQualified::size(loc); -} - - - -/***************************** TypeReturn *****************************/ - -TypeReturn::TypeReturn(Loc loc) - : TypeQualified(Treturn, loc) -{ -} - -Type *TypeReturn::syntaxCopy() -{ - TypeReturn *t = new TypeReturn(loc); - t->syntaxCopyHelper(this); - t->mod = mod; - return t; -} - -Dsymbol *TypeReturn::toDsymbol(Scope *sc) -{ - Type *t = semantic(0, sc); - if (t == this) - return NULL; - return t->toDsymbol(sc); -} - -Type *TypeReturn::semantic(Loc loc, Scope *sc) -{ - Type *t; - if (!sc->func) - { error(loc, "typeof(return) must be inside function"); - goto Lerr; - } - t = sc->func->type->nextOf(); - if (!t) - { - error(loc, "cannot use typeof(return) inside function %s with inferred return type", sc->func->toChars()); - goto Lerr; - } - t = t->addMod(mod); - - if (idents.dim) - { - Dsymbol *s = t->toDsymbol(sc); - for (size_t i = 0; i < idents.dim; i++) - { - if (!s) - break; - Identifier *id = idents.tdata()[i]; - s = s->searchX(loc, sc, id); - } - if (s) - { - t = s->getType(); - if (!t) - { error(loc, "%s is not a type", s->toChars()); - goto Lerr; - } - } - else - { error(loc, "cannot resolve .property for %s", toChars()); - goto Lerr; - } - } - return t; - -Lerr: - return terror; -} - -void TypeReturn::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring("typeof(return)"); - toCBuffer2Helper(buf, hgs); -} - - -/***************************** TypeEnum *****************************/ - -TypeEnum::TypeEnum(EnumDeclaration *sym) - : Type(Tenum) -{ - this->sym = sym; -} - -char *TypeEnum::toChars() -{ - if (mod) - return Type::toChars(); - return sym->toChars(); -} - -Type *TypeEnum::syntaxCopy() -{ - return this; -} - -Type *TypeEnum::semantic(Loc loc, Scope *sc) -{ - //printf("TypeEnum::semantic() %s\n", toChars()); - //sym->semantic(sc); - return merge(); -} - -d_uns64 TypeEnum::size(Loc loc) -{ - if (!sym->memtype) - { - error(loc, "enum %s is forward referenced", sym->toChars()); - return 4; - } - return sym->memtype->size(loc); -} - -unsigned TypeEnum::alignsize() -{ - if (!sym->memtype) - { -#ifdef DEBUG - printf("1: "); -#endif - error(0, "enum %s is forward referenced", sym->toChars()); - return 4; - } - return sym->memtype->alignsize(); -} - -Dsymbol *TypeEnum::toDsymbol(Scope *sc) -{ - return sym; -} - -Type *TypeEnum::toBasetype() -{ - if (sym->scope) - { // Enum is forward referenced. We don't need to resolve the whole thing, - // just the base type - if (sym->memtype) - { sym->memtype = sym->memtype->semantic(sym->loc, sym->scope); - } - else - { if (!sym->isAnonymous()) - sym->memtype = Type::tint32; - } - } - if (!sym->memtype) - { -#ifdef DEBUG - printf("2: "); -#endif - error(sym->loc, "enum %s is forward referenced", sym->toChars()); - return tint32; - } - return sym->memtype->toBasetype(); -} - -void TypeEnum::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - const char *name = sym->mangle(); - Type::toDecoBuffer(buf, flag, mangle); - buf->printf("%s", name); -} - -void TypeEnum::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeEnum::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeEnum::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - Dsymbol *s = sym->search(e->loc, ident, 0); - if (!s) - { - if (ident == Id::max || - ident == Id::min || - ident == Id::init || - ident == Id::mangleof || - !sym->memtype - ) - { - return getProperty(e->loc, ident); - } - return sym->memtype->dotExp(sc, e, ident); - } - EnumMember *m = s->isEnumMember(); - Expression *em = m->value->copy(); - em->loc = e->loc; - return em; -} - -Expression *TypeEnum::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - - if (ident == Id::max) - { - if (!sym->maxval) - goto Lfwd; - e = sym->maxval; - } - else if (ident == Id::min) - { - if (!sym->minval) - goto Lfwd; - e = sym->minval; - } - else if (ident == Id::init) - { - e = defaultInitLiteral(loc); - } - else if (ident == Id::stringof) - { char *s = toChars(); - e = new StringExp(loc, s, strlen(s), 'c'); - Scope sc; - e = e->semantic(&sc); - } - else if (ident == Id::mangleof) - { - e = Type::getProperty(loc, ident); - } - else - { - e = toBasetype()->getProperty(loc, ident); - } - return e; - -Lfwd: - error(loc, "forward reference of %s.%s", toChars(), ident->toChars()); - return new ErrorExp(); -} - -int TypeEnum::isintegral() -{ - return sym->memtype->isintegral(); -} - -int TypeEnum::isfloating() -{ - return sym->memtype->isfloating(); -} - -int TypeEnum::isreal() -{ - return sym->memtype->isreal(); -} - -int TypeEnum::isimaginary() -{ - return sym->memtype->isimaginary(); -} - -int TypeEnum::iscomplex() -{ - return sym->memtype->iscomplex(); -} - -int TypeEnum::isunsigned() -{ - return sym->memtype->isunsigned(); -} - -int TypeEnum::isscalar() -{ - return sym->memtype->isscalar(); -} - -int TypeEnum::isAssignable() -{ - return sym->memtype->isAssignable(); -} - -int TypeEnum::checkBoolean() -{ - return sym->memtype->checkBoolean(); -} - -int TypeEnum::needsDestruction() -{ - return sym->memtype->needsDestruction(); -} - -MATCH TypeEnum::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeEnum::implicitConvTo()\n"); - if (ty == to->ty && sym == ((TypeEnum *)to)->sym) - m = (mod == to->mod) ? MATCHexact : MATCHconst; - else if (sym->memtype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else - m = MATCHnomatch; // no match - return m; -} - -MATCH TypeEnum::constConv(Type *to) -{ - if (equals(to)) - return MATCHexact; - if (ty == to->ty && sym == ((TypeEnum *)to)->sym && - MODimplicitConv(mod, to->mod)) - return MATCHconst; - return MATCHnomatch; -} - - -Expression *TypeEnum::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeEnum::defaultInit() '%s'\n", toChars()); -#endif - // Initialize to first member of enum - //printf("%s\n", sym->defaultval->type->toChars()); - if (!sym->defaultval) - { - error(loc, "forward reference of %s.init", toChars()); - return new ErrorExp(); - } - return sym->defaultval; -} - -int TypeEnum::isZeroInit(Loc loc) -{ - if (!sym->defaultval && sym->scope) - { // Enum is forward referenced. We need to resolve the whole thing. - sym->semantic(NULL); - } - if (!sym->defaultval) - { -#ifdef DEBUG - printf("3: "); -#endif - error(loc, "enum %s is forward referenced", sym->toChars()); - return 0; - } - return sym->defaultval->isBool(FALSE); -} - -int TypeEnum::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -/***************************** TypeTypedef *****************************/ - -TypeTypedef::TypeTypedef(TypedefDeclaration *sym) - : Type(Ttypedef) -{ - this->sym = sym; -} - -Type *TypeTypedef::syntaxCopy() -{ - return this; -} - -char *TypeTypedef::toChars() -{ - return Type::toChars(); -} - -Type *TypeTypedef::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTypedef::semantic(%s), sem = %d\n", toChars(), sym->sem); - int errors = global.errors; - sym->semantic(sc); - if (errors != global.errors) - return terror; - return merge(); -} - -d_uns64 TypeTypedef::size(Loc loc) -{ - return sym->basetype->size(loc); -} - -unsigned TypeTypedef::alignsize() -{ - return sym->basetype->alignsize(); -} - -Dsymbol *TypeTypedef::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeTypedef::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - Type::toDecoBuffer(buf, flag, mangle); - const char *name = sym->mangle(); - buf->printf("%s", name); -} - -void TypeTypedef::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - //printf("TypeTypedef::toCBuffer2() '%s'\n", sym->toChars()); - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeTypedef::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeTypedef::dotExp(e = '%s', ident = '%s') '%s'\n", e->toChars(), ident->toChars(), toChars()); -#endif - if (ident == Id::init) - { - return Type::dotExp(sc, e, ident); - } - return sym->basetype->dotExp(sc, e, ident); -} - -Expression *TypeTypedef::getProperty(Loc loc, Identifier *ident) -{ -#if LOGDOTEXP - printf("TypeTypedef::getProperty(ident = '%s') '%s'\n", ident->toChars(), toChars()); -#endif - if (ident == Id::init) - { - return Type::getProperty(loc, ident); - } - return sym->basetype->getProperty(loc, ident); -} - -int TypeTypedef::isintegral() -{ - //printf("TypeTypedef::isintegral()\n"); - //printf("sym = '%s'\n", sym->toChars()); - //printf("basetype = '%s'\n", sym->basetype->toChars()); - return sym->basetype->isintegral(); -} - -int TypeTypedef::isfloating() -{ - return sym->basetype->isfloating(); -} - -int TypeTypedef::isreal() -{ - return sym->basetype->isreal(); -} - -int TypeTypedef::isimaginary() -{ - return sym->basetype->isimaginary(); -} - -int TypeTypedef::iscomplex() -{ - return sym->basetype->iscomplex(); -} - -int TypeTypedef::isunsigned() -{ - return sym->basetype->isunsigned(); -} - -int TypeTypedef::isscalar() -{ - return sym->basetype->isscalar(); -} - -int TypeTypedef::isAssignable() -{ - return sym->basetype->isAssignable(); -} - -int TypeTypedef::checkBoolean() -{ - return sym->basetype->checkBoolean(); -} - -int TypeTypedef::needsDestruction() -{ - return sym->basetype->needsDestruction(); -} - -Type *TypeTypedef::toBasetype() -{ - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - return Type::terror; - } - sym->inuse = 1; - Type *t = sym->basetype->toBasetype(); - sym->inuse = 0; - t = t->addMod(mod); - return t; -} - -MATCH TypeTypedef::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeTypedef::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); - if (equals(to)) - m = MATCHexact; // exact match - else if (sym->basetype->implicitConvTo(to)) - m = MATCHconvert; // match with conversions - else if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) - { - m = constConv(to); - } - else - m = MATCHnomatch; // no match - return m; -} - -MATCH TypeTypedef::constConv(Type *to) -{ - if (equals(to)) - return MATCHexact; - if (ty == to->ty && sym == ((TypeTypedef *)to)->sym) - return sym->basetype->implicitConvTo(((TypeTypedef *)to)->sym->basetype); - return MATCHnomatch; -} - -Type *TypeTypedef::toHeadMutable() -{ - if (!mod) - return this; - - Type *tb = toBasetype(); - Type *t = tb->toHeadMutable(); - if (t->equals(tb)) - return this; - else - return mutableOf(); -} - -Expression *TypeTypedef::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInit() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); - } - Type *bt = sym->basetype; - Expression *e = bt->defaultInit(loc); - e->type = this; - while (bt->ty == Tsarray) - { TypeSArray *tsa = (TypeSArray *)bt; - e->type = tsa->next; - bt = tsa->next->toBasetype(); - } - return e; -} - -Expression *TypeTypedef::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeTypedef::defaultInitLiteral() '%s'\n", toChars()); -#endif - if (sym->init) - { - //sym->init->toExpression()->print(); - return sym->init->toExpression(); - } - Type *bt = sym->basetype; - Expression *e = bt->defaultInitLiteral(loc); - e->type = this; - return e; -} - -int TypeTypedef::isZeroInit(Loc loc) -{ - if (sym->init) - { - if (sym->init->isVoidInitializer()) - return 1; // initialize voids to 0 - Expression *e = sym->init->toExpression(); - if (e && e->isBool(FALSE)) - return 1; - return 0; // assume not - } - if (sym->inuse) - { - sym->error("circular definition"); - sym->basetype = Type::terror; - } - sym->inuse = 1; - int result = sym->basetype->isZeroInit(loc); - sym->inuse = 0; - return result; -} - -int TypeTypedef::hasPointers() -{ - return toBasetype()->hasPointers(); -} - -int TypeTypedef::hasWild() -{ - assert(toBasetype()); - return mod & MODwild || toBasetype()->hasWild(); -} - -/***************************** TypeStruct *****************************/ - -TypeStruct::TypeStruct(StructDeclaration *sym) - : Type(Tstruct) -{ - this->sym = sym; - - // LDC - this->unaligned = 0; -} - -char *TypeStruct::toChars() -{ - //printf("sym.parent: %s, deco = %s\n", sym->parent->toChars(), deco); - if (mod) - return Type::toChars(); - TemplateInstance *ti = sym->parent->isTemplateInstance(); - if (ti && ti->toAlias() == sym) - { - return ti->toChars(); - } - return sym->toChars(); -} - -Type *TypeStruct::syntaxCopy() -{ - return this; -} - -Type *TypeStruct::semantic(Loc loc, Scope *sc) -{ - //printf("TypeStruct::semantic('%s')\n", sym->toChars()); - - /* Cannot do semantic for sym because scope chain may not - * be right. - */ - //sym->semantic(sc); - - return merge(); -} - -d_uns64 TypeStruct::size(Loc loc) -{ - return sym->size(loc); -} - -unsigned TypeStruct::alignsize() -{ unsigned sz; - - sym->size(0); // give error for forward references - sz = sym->alignsize; - if (sz > sym->structalign) - sz = sym->structalign; - return sz; -} - -Dsymbol *TypeStruct::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeStruct::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - const char *name = sym->mangle(); - //printf("TypeStruct::toDecoBuffer('%s') = '%s'\n", toChars(), name); - Type::toDecoBuffer(buf, flag, mangle); - buf->printf("%s", name); -} - -void TypeStruct::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - TemplateInstance *ti = sym->parent->isTemplateInstance(); - if (ti && ti->toAlias() == sym) - buf->writestring(ti->toChars()); - else - buf->writestring(sym->toChars()); -} - -Expression *TypeStruct::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - VarDeclaration *v; - Dsymbol *s; - DotVarExp *de; - Declaration *d; - -#if LOGDOTEXP - printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e->toChars(), ident->toChars()); -#endif - if (!sym->members) - { - error(e->loc, "struct %s is forward referenced", sym->toChars()); - return new ErrorExp(); - } - - /* If e.tupleof - */ - if (ident == Id::tupleof) - { - /* Create a TupleExp out of the fields of the struct e: - * (e.field0, e.field1, e.field2, ...) - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - e->type->size(); // do semantic of type - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - - Expression *ev = e; - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; - Expression *fe; - if (i == 0 && sc->func && sym->fields.dim > 1 && - e->hasSideEffect()) - { - Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e->loc, e); - VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); - vd->storage_class |= STCctfe | STCref | STCforeach; - - ev = new VarExp(e->loc, vd); - fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev); - fe = new DotVarExp(e->loc, fe, v); - } - else - fe = new DotVarExp(ev->loc, ev, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e1->op == TOKimport) - { - assert(0); // cannot find a case where this happens; leave - // assert in until we do - ScopeExp *se = (ScopeExp *)de->e1; - - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - return noMember(sc, e, ident); - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - - v = s->isVarDeclaration(); - if (v && !v->isDataseg()) - { - Expression *ei = v->getConstInitializer(); - if (ei) - { e = ei->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } - } - - if (s->getType()) - { - //return new DotTypeExp(e->loc, e, s); - return new TypeExp(e->loc, s->getType()); - } - - EnumMember *em = s->isEnumMember(); - if (em) - { - assert(em->value); - return em->value->copy(); - } - - TemplateMixin *tm = s->isTemplateMixin(); - if (tm) - { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new DotTemplateExp(e->loc, e, td); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway - ti->semantic(sc); - } - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; - } - - if (s->isImport() || s->isModule() || s->isPackage()) - { - e = new DsymbolExp(e->loc, s, 0); - e = e->semantic(sc); - return e; - } - - OverloadSet *o = s->isOverloadSet(); - if (o) - { - OverExp *oe = new OverExp(o); - if (e->op == TOKtype) - return oe; - return new DotExp(e->loc, e, oe); - } - - d = s->isDeclaration(); -#ifdef DEBUG - if (!d) - printf("d = %s '%s'\n", s->kind(), s->toChars()); -#endif - assert(d); - - if (e->op == TOKtype) - { FuncDeclaration *fd = sc->func; - - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - else if (d->needThis() && fd && fd->vthis) - { - e = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = e->semantic(sc); - return e; - } - return new VarExp(e->loc, d, 1); - } - - if (d->isDataseg()) - { - // (e, d) - VarExp *ve; - - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e = e->semantic(sc); - return e; - } - - if (v) - { - if (v->toParent() != sym) - sym->error(e->loc, "'%s' is not a member", v->toChars()); - - // *(&e + offset) - accessCheck(e->loc, sc, e, d); -#if 0 - Expression *b = new AddrExp(e->loc, e); - b->type = e->type->pointerTo(); - b = new AddExp(e->loc, b, new IntegerExp(e->loc, v->offset, Type::tint32)); - b->type = v->type->pointerTo(); - b = new PtrExp(e->loc, b); - b->type = v->type->addMod(e->type->mod); - return b; -#endif - } - - de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -unsigned TypeStruct::memalign(unsigned salign) -{ - sym->size(0); // give error for forward references - return sym->structalign; -} - -Expression *TypeStruct::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeStruct::defaultInit() '%s'\n", toChars()); -#endif - Declaration *d = new StaticStructInitDeclaration(sym->loc, sym); - assert(d); - d->type = this; - return new VarExp(sym->loc, d); -} - -/*************************************** - * Use when we prefer the default initializer to be a literal, - * rather than a global immutable variable. - */ -Expression *TypeStruct::defaultInitLiteral(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeStruct::defaultInitLiteral() '%s'\n", toChars()); -#endif - if (sym->isNested()) - return defaultInit(loc); - Expressions *structelems = new Expressions(); - structelems->setDim(sym->fields.dim); - for (size_t j = 0; j < structelems->dim; j++) - { - VarDeclaration *vd = sym->fields.tdata()[j]; - Expression *e; - if (vd->init) - { if (vd->init->isVoidInitializer()) - e = NULL; - else - e = vd->init->toExpression(); - } - else - e = vd->type->defaultInitLiteral(); - structelems->tdata()[j] = e; - } - StructLiteralExp *structinit = new StructLiteralExp(loc, (StructDeclaration *)sym, structelems); - // Why doesn't the StructLiteralExp constructor do this, when - // sym->type != NULL ? - structinit->type = sym->type; - return structinit; -} - - -int TypeStruct::isZeroInit(Loc loc) -{ - return sym->zeroInit; -} - -int TypeStruct::checkBoolean() -{ - return FALSE; -} - -int TypeStruct::needsDestruction() -{ - return sym->dtor != NULL; -} - -int TypeStruct::isAssignable() -{ - int assignable = TRUE; - unsigned offset; - - /* If any of the fields are const or invariant, - * then one cannot assign this struct. - */ - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; - //printf("%s [%d] v = (%s) %s, v->offset = %d, v->parent = %s", sym->toChars(), i, v->kind(), v->toChars(), v->offset, v->parent->kind()); - if (i == 0) - ; - else if (v->offset == offset) - { - /* If any fields of anonymous union are assignable, - * then regard union as assignable. - * This is to support unsafe things like Rebindable templates. - */ - if (assignable) - continue; - } - else - { - if (!assignable) - return FALSE; - } - assignable = v->type->isMutable() && v->type->isAssignable(); - offset = v->offset; - //printf(" -> assignable = %d\n", assignable); - } - - return assignable; -} - -int TypeStruct::hasPointers() -{ - // Probably should cache this information in sym rather than recompute - StructDeclaration *s = sym; - - sym->size(0); // give error for forward references - for (size_t i = 0; i < s->fields.dim; i++) - { - Dsymbol *sm = s->fields.tdata()[i]; - Declaration *d = sm->isDeclaration(); - if (d->storage_class & STCref || d->hasPointers()) - return TRUE; - } - return FALSE; -} - -MATCH TypeStruct::implicitConvTo(Type *to) -{ MATCH m; - - //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to->toChars()); - if (to->ty == Taarray) - { - /* If there is an error instantiating AssociativeArray!(), it shouldn't - * be reported -- it just means implicit conversion is impossible. - */ - int errs = global.startGagging(); - to = ((TypeAArray*)to)->getImpl()->type; - if (global.endGagging(errs)) - { - return MATCHnomatch; - } - } - - if (ty == to->ty && sym == ((TypeStruct *)to)->sym) - { m = MATCHexact; // exact match - if (mod != to->mod) - { - if (MODimplicitConv(mod, to->mod)) - m = MATCHconst; - else - { /* Check all the fields. If they can all be converted, - * allow the conversion. - */ - for (size_t i = 0; i < sym->fields.dim; i++) - { Dsymbol *s = sym->fields.tdata()[i]; - VarDeclaration *v = s->isVarDeclaration(); - assert(v && v->storage_class & STCfield); - - // 'from' type - Type *tvf = v->type->addMod(mod); - - // 'to' type - Type *tv = v->type->castMod(to->mod); - - //printf("\t%s => %s, match = %d\n", v->type->toChars(), tv->toChars(), tvf->implicitConvTo(tv)); - if (tvf->implicitConvTo(tv) < MATCHconst) - return MATCHnomatch; - } - m = MATCHconst; - } - } - } - else if (sym->aliasthis) - m = aliasthisOf()->implicitConvTo(to); - else - m = MATCHnomatch; // no match - return m; -} - -MATCH TypeStruct::constConv(Type *to) -{ - if (equals(to)) - return MATCHexact; - if (ty == to->ty && sym == ((TypeStruct *)to)->sym && - MODimplicitConv(mod, to->mod)) - return MATCHconst; - return MATCHnomatch; -} - -unsigned TypeStruct::wildConvTo(Type *tprm) -{ - if (ty == tprm->ty && sym == ((TypeStruct *)tprm)->sym) - return Type::wildConvTo(tprm); - - if (sym->aliasthis) - { Type *t = aliasthisOf(); - assert(t); - return t->wildConvTo(tprm); - } - - return 0; -} - -Type *TypeStruct::toHeadMutable() -{ - return this; -} - - -/***************************** TypeClass *****************************/ - -TypeClass::TypeClass(ClassDeclaration *sym) - : Type(Tclass) -{ - this->sym = sym; -} - -char *TypeClass::toChars() -{ - if (mod) - return Type::toChars(); - return (char *)sym->toPrettyChars(); -} - -Type *TypeClass::syntaxCopy() -{ - return this; -} - -Type *TypeClass::semantic(Loc loc, Scope *sc) -{ - //printf("TypeClass::semantic(%s)\n", sym->toChars()); - if (deco) - return this; - //printf("\t%s\n", merge()->deco); - return merge(); -} - -d_uns64 TypeClass::size(Loc loc) -{ - return PTRSIZE; -} - -Dsymbol *TypeClass::toDsymbol(Scope *sc) -{ - return sym; -} - -void TypeClass::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - const char *name = sym->mangle(); - //printf("TypeClass::toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name); - Type::toDecoBuffer(buf, flag, mangle); - buf->printf("%s", name); -} - -void TypeClass::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - buf->writestring(sym->toChars()); -} - -Expression *TypeClass::dotExp(Scope *sc, Expression *e, Identifier *ident) -{ - VarDeclaration *v; - Dsymbol *s; - -#if LOGDOTEXP - printf("TypeClass::dotExp(e='%s', ident='%s')\n", e->toChars(), ident->toChars()); -#endif - - if (e->op == TOKdotexp) - { DotExp *de = (DotExp *)e; - - if (de->e1->op == TOKimport) - { - ScopeExp *se = (ScopeExp *)de->e1; - - s = se->sds->search(e->loc, ident, 0); - e = de->e1; - goto L1; - } - } - - if (ident == Id::tupleof) - { - /* Create a TupleExp - */ - e = e->semantic(sc); // do this before turning on noaccesscheck - - /* If this is called in the middle of a class declaration, - * class Inner { - * int x; - * alias typeof(Inner.tupleof) T; - * int y; - * } - * then Inner.y will be omitted from the tuple. - */ - // Detect that error, and at least try to run semantic() on it if we can - sym->size(e->loc); - - Expressions *exps = new Expressions; - exps->reserve(sym->fields.dim); - - Expression *ev = e; - for (size_t i = 0; i < sym->fields.dim; i++) - { VarDeclaration *v = sym->fields.tdata()[i]; - // Don't include hidden 'this' pointer - if (v->isThisDeclaration()) - continue; - Expression *fe; - if (i == 0 && sc->func && sym->fields.dim > 1 && - e->hasSideEffect()) - { - Identifier *id = Lexer::uniqueId("__tup"); - ExpInitializer *ei = new ExpInitializer(e->loc, e); - VarDeclaration *vd = new VarDeclaration(e->loc, NULL, id, ei); - vd->storage_class |= STCctfe | STCref | STCforeach; - - ev = new VarExp(e->loc, vd); - fe = new CommaExp(e->loc, new DeclarationExp(e->loc, vd), ev); - fe = new DotVarExp(e->loc, fe, v); - } - else - fe = new DotVarExp(e->loc, ev, v); - exps->push(fe); - } - e = new TupleExp(e->loc, exps); - sc = sc->push(); - sc->noaccesscheck = 1; - e = e->semantic(sc); - sc->pop(); - return e; - } - - s = sym->search(e->loc, ident, 0); -L1: - if (!s) - { - // See if it's a base class - if (Dsymbol *cbase = sym->searchBase(e->loc, ident)) - { - e = new DotTypeExp(0, e, cbase); - return e; - } - - if (ident == Id::classinfo) - { - assert(ClassDeclaration::classinfo); - Type *t = ClassDeclaration::classinfo->type; - if (e->op == TOKtype || e->op == TOKdottype) - { - /* For type.classinfo, we know the classinfo - * at compile time. - */ - if (!sym->vclassinfo) - sym->vclassinfo = new TypeInfoClassDeclaration(sym->type); - e = new VarExp(e->loc, sym->vclassinfo); - e = e->addressOf(sc); - e->type = t; // do this so we don't get redundant dereference - } - else - { - /* For class objects, the classinfo reference is the first - * entry in the vtbl[] - */ -#if IN_LLVM - - Type* ct; - if (sym->isInterfaceDeclaration()) { - ct = t->pointerTo()->pointerTo()->pointerTo(); - } - else { - ct = t->pointerTo()->pointerTo(); - } - - e = e->castTo(sc, ct); - e = new PtrExp(e->loc, e); - e->type = ct->nextOf(); - e = new PtrExp(e->loc, e); - e->type = ct->nextOf()->nextOf(); - - if (sym->isInterfaceDeclaration()) - { - if (sym->isCOMinterface()) - { /* COM interface vtbl[]s are different in that the - * first entry is always pointer to QueryInterface(). - * We can't get a .classinfo for it. - */ - error(e->loc, "no .classinfo for COM interface objects"); - } - /* For an interface, the first entry in the vtbl[] - * is actually a pointer to an instance of struct Interface. - * The first member of Interface is the .classinfo, - * so add an extra pointer indirection. - */ - e = new PtrExp(e->loc, e); - e->type = ct->nextOf()->nextOf()->nextOf(); - } - } - -#else - - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - if (sym->isInterfaceDeclaration()) - { - if (sym->isCPPinterface()) - { /* C++ interface vtbl[]s are different in that the - * first entry is always pointer to the first virtual - * function, not classinfo. - * We can't get a .classinfo for it. - */ - error(e->loc, "no .classinfo for C++ interface objects"); - } - /* For an interface, the first entry in the vtbl[] - * is actually a pointer to an instance of struct Interface. - * The first member of Interface is the .classinfo, - * so add an extra pointer indirection. - */ - e->type = e->type->pointerTo(); - e = new PtrExp(e->loc, e); - e->type = t->pointerTo(); - } - e = new PtrExp(e->loc, e, t); - } - -#endif // !LDC - - return e; - } - - if (ident == Id::__vptr) - { /* The pointer to the vtbl[] - * *cast(invariant(void*)**)e - */ - e = e->castTo(sc, tvoidptr->invariantOf()->pointerTo()->pointerTo()); - e = new PtrExp(e->loc, e); - e = e->semantic(sc); - return e; - } - - if (ident == Id::__monitor) - { /* The handle to the monitor (call it a void*) - * *(cast(void**)e + 1) - */ -#if IN_LLVM - e = e->castTo(sc, tint8->pointerTo()->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e->type = tint8->pointerTo(); - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new PtrExp(e->loc, e); -#else - e = e->castTo(sc, tvoidptr->pointerTo()); - e = new AddExp(e->loc, e, new IntegerExp(1)); - e = new PtrExp(e->loc, e); -#endif - e = e->semantic(sc); - return e; - } - - if (ident == Id::typeinfo) - { - if (!global.params.useDeprecated) - error(e->loc, ".typeinfo deprecated, use typeid(type)"); - return getTypeInfo(sc); - } - if (ident == Id::outer && sym->vthis) - { - s = sym->vthis; - } - else - { - return noMember(sc, e, ident); - } - } - if (!s->isFuncDeclaration()) // because of overloading - s->checkDeprecated(e->loc, sc); - s = s->toAlias(); - v = s->isVarDeclaration(); - if (v && !v->isDataseg()) - { Expression *ei = v->getConstInitializer(); - - if (ei) - { e = ei->copy(); // need to copy it if it's a StringExp - e = e->semantic(sc); - return e; - } - } - - if (s->getType()) - { -// if (e->op == TOKtype) - return new TypeExp(e->loc, s->getType()); -// return new DotTypeExp(e->loc, e, s); - } - - EnumMember *em = s->isEnumMember(); - if (em) - { - assert(em->value); - return em->value->copy(); - } - - TemplateMixin *tm = s->isTemplateMixin(); - if (tm) - { - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, tm)); - de->type = e->type; - return de; - } - - TemplateDeclaration *td = s->isTemplateDeclaration(); - if (td) - { - e = new DotTemplateExp(e->loc, e, td); - e = e->semantic(sc); - return e; - } - - TemplateInstance *ti = s->isTemplateInstance(); - if (ti) - { if (!ti->semanticRun) - { - if (global.errors) - return new ErrorExp(); // TemplateInstance::semantic() will fail anyway - ti->semantic(sc); - } - s = ti->inst->toAlias(); - if (!s->isTemplateInstance()) - goto L1; - Expression *de = new DotExp(e->loc, e, new ScopeExp(e->loc, ti)); - de->type = e->type; - return de; - } - -#if 0 // shouldn't this be here? - if (s->isImport() || s->isModule() || s->isPackage()) - { - e = new DsymbolExp(e->loc, s, 0); - e = e->semantic(sc); - return e; - } -#endif - - OverloadSet *o = s->isOverloadSet(); - if (o) - { - OverExp *oe = new OverExp(o); - if (e->op == TOKtype) - return oe; - return new DotExp(e->loc, e, oe); - } - - Declaration *d = s->isDeclaration(); - if (!d) - { - e->error("%s.%s is not a declaration", e->toChars(), ident->toChars()); - return new ErrorExp(); - } - - if (e->op == TOKtype) - { - /* It's: - * Class.d - */ - if (d->isTupleDeclaration()) - { - e = new TupleExp(e->loc, d->isTupleDeclaration()); - e = e->semantic(sc); - return e; - } - else if (d->needThis() && (hasThis(sc) || !(sc->intypeof || d->isFuncDeclaration()))) - { - if (sc->func) - { - ClassDeclaration *thiscd; - thiscd = sc->func->toParent()->isClassDeclaration(); - - if (thiscd) - { - ClassDeclaration *cd = e->type->isClassHandle(); - - if (cd == thiscd) - { - e = new ThisExp(e->loc); - e = new DotTypeExp(e->loc, e, cd); - DotVarExp *de = new DotVarExp(e->loc, e, d); - e = de->semantic(sc); - return e; - } - else if ((!cd || !cd->isBaseOf(thiscd, NULL)) && - !d->isFuncDeclaration()) - e->error("'this' is required, but %s is not a base class of %s", e->type->toChars(), thiscd->toChars()); - } - } - - /* Rewrite as: - * this.d - */ - DotVarExp *de = new DotVarExp(e->loc, new ThisExp(e->loc), d); - e = de->semantic(sc); - return e; - } - else - { - VarExp *ve = new VarExp(e->loc, d, 1); - return ve; - } - } - - if (d->isDataseg()) - { - // (e, d) - VarExp *ve; - - accessCheck(e->loc, sc, e, d); - ve = new VarExp(e->loc, d); - e = new CommaExp(e->loc, e, ve); - e = e->semantic(sc); - return e; - } - - if (d->parent && d->toParent()->isModule()) - { - // (e, d) - VarExp *ve = new VarExp(e->loc, d, 1); - e = new CommaExp(e->loc, e, ve); - e->type = d->type; - return e; - } - - DotVarExp *de = new DotVarExp(e->loc, e, d); - return de->semantic(sc); -} - -ClassDeclaration *TypeClass::isClassHandle() -{ - return sym; -} - -int TypeClass::isscope() -{ - return sym->isscope; -} - -int TypeClass::isBaseOf(Type *t, int *poffset) -{ - if (t->ty == Tclass) - { ClassDeclaration *cd; - - cd = ((TypeClass *)t)->sym; - if (sym->isBaseOf(cd, poffset)) - return 1; - } - return 0; -} - -MATCH TypeClass::implicitConvTo(Type *to) -{ - //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to->toChars(), toChars()); - MATCH m = constConv(to); - if (m != MATCHnomatch) - return m; - - ClassDeclaration *cdto = to->isClassHandle(); - if (cdto) - { - if (cdto->scope) - cdto->semantic(NULL); - if (cdto->isBaseOf(sym, NULL)) - { //printf("'to' is base\n"); - return MATCHconvert; - } - } - - if (global.params.Dversion == 1) - { - // Allow conversion to (void *) - if (to->ty == Tpointer && ((TypePointer *)to)->next->ty == Tvoid) - return MATCHconvert; - } - - m = MATCHnomatch; - if (sym->aliasthis) - m = aliasthisOf()->implicitConvTo(to); - - return m; -} - -MATCH TypeClass::constConv(Type *to) -{ - if (equals(to)) - return MATCHexact; - if (ty == to->ty && sym == ((TypeClass *)to)->sym && - MODimplicitConv(mod, to->mod)) - return MATCHconst; - - /* Conversion derived to const(base) - */ - int offset = 0; - if (to->isBaseOf(this, &offset) && offset == 0 && !to->isMutable()) - return MATCHconvert; - - return MATCHnomatch; -} - -unsigned TypeClass::wildConvTo(Type *tprm) -{ - Type *tcprm = tprm->substWildTo(MODconst); - - if (constConv(tcprm)) - return Type::wildConvTo(tprm); - - ClassDeclaration *cdprm = tcprm->isClassHandle(); - if (cdprm && cdprm->isBaseOf(sym, NULL)) - return Type::wildConvTo(tprm); - - if (sym->aliasthis) - return aliasthisOf()->wildConvTo(tprm); - - return 0; -} - -Type *TypeClass::toHeadMutable() -{ - return this; -} - -Expression *TypeClass::defaultInit(Loc loc) -{ -#if LOGDEFAULTINIT - printf("TypeClass::defaultInit() '%s'\n", toChars()); -#endif - return new NullExp(loc, this); -} - -int TypeClass::isZeroInit(Loc loc) -{ - return 1; -} - -int TypeClass::checkBoolean() -{ - return TRUE; -} - -int TypeClass::hasPointers() -{ - return TRUE; -} - -/***************************** TypeTuple *****************************/ - -TypeTuple::TypeTuple(Parameters *arguments) - : Type(Ttuple) -{ - //printf("TypeTuple(this = %p)\n", this); - this->arguments = arguments; - //printf("TypeTuple() %p, %s\n", this, toChars()); -#ifdef DEBUG - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *arg = arguments->tdata()[i]; - assert(arg && arg->type); - } - } -#endif -} - -/**************** - * Form TypeTuple from the types of the expressions. - * Assume exps[] is already tuple expanded. - */ - -TypeTuple::TypeTuple(Expressions *exps) - : Type(Ttuple) -{ - Parameters *arguments = new Parameters; - if (exps) - { - arguments->setDim(exps->dim); - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; - if (e->type->ty == Ttuple) - e->error("cannot form tuple of tuples"); - Parameter *arg = new Parameter(STCundefined, e->type, NULL, NULL); - arguments->tdata()[i] = arg; - } - } - this->arguments = arguments; - //printf("TypeTuple() %p, %s\n", this, toChars()); -} - -/******************************************* - * Type tuple with 0, 1 or 2 types in it. - */ -TypeTuple::TypeTuple() - : Type(Ttuple) -{ - arguments = new Parameters(); -} - -TypeTuple::TypeTuple(Type *t1) - : Type(Ttuple) -{ - arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); -} - -TypeTuple::TypeTuple(Type *t1, Type *t2) - : Type(Ttuple) -{ - arguments = new Parameters(); - arguments->push(new Parameter(0, t1, NULL, NULL)); - arguments->push(new Parameter(0, t2, NULL, NULL)); -} - -Type *TypeTuple::syntaxCopy() -{ - Parameters *args = Parameter::arraySyntaxCopy(arguments); - Type *t = new TypeTuple(args); - t->mod = mod; - return t; -} - -Type *TypeTuple::semantic(Loc loc, Scope *sc) -{ - //printf("TypeTuple::semantic(this = %p)\n", this); - //printf("TypeTuple::semantic() %p, %s\n", this, toChars()); - if (!deco) - deco = merge()->deco; - - /* Don't return merge(), because a tuple with one type has the - * same deco as that type. - */ - return this; -} - -int TypeTuple::equals(Object *o) -{ Type *t; - - t = (Type *)o; - //printf("TypeTuple::equals(%s, %s)\n", toChars(), t->toChars()); - if (this == t) - { - return 1; - } - if (t->ty == Ttuple) - { TypeTuple *tt = (TypeTuple *)t; - - if (arguments->dim == tt->arguments->dim) - { - for (size_t i = 0; i < tt->arguments->dim; i++) - { Parameter *arg1 = arguments->tdata()[i]; - Parameter *arg2 = tt->arguments->tdata()[i]; - - if (!arg1->type->equals(arg2->type)) - return 0; - } - return 1; - } - } - return 0; -} - -Type *TypeTuple::reliesOnTident() -{ - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *arg = arguments->tdata()[i]; - Type *t = arg->type->reliesOnTident(); - if (t) - return t; - } - } - return NULL; -} - -#if 0 -Type *TypeTuple::makeConst() -{ - //printf("TypeTuple::makeConst() %s\n", toChars()); - if (cto) - return cto; - TypeTuple *t = (TypeTuple *)Type::makeConst(); - t->arguments = new Parameters(); - t->arguments->setDim(arguments->dim); - for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = arguments->tdata()[i]; - Parameter *narg = new Parameter(arg->storageClass, arg->type->constOf(), arg->ident, arg->defaultArg); - t->arguments->tdata()[i] = (Parameter *)narg; - } - return t; -} -#endif - -void TypeTuple::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - Parameter::argsToCBuffer(buf, hgs, arguments, 0); -} - -void TypeTuple::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - //printf("TypeTuple::toDecoBuffer() this = %p, %s\n", this, toChars()); - Type::toDecoBuffer(buf, flag, mangle); - OutBuffer buf2; - Parameter::argsToDecoBuffer(&buf2, arguments, mangle); - unsigned len = buf2.offset; - buf->printf("%d%.*s", len, len, (char *)buf2.extractData()); -} - -Expression *TypeTuple::getProperty(Loc loc, Identifier *ident) -{ Expression *e; - -#if LOGDOTEXP - printf("TypeTuple::getProperty(type = '%s', ident = '%s')\n", toChars(), ident->toChars()); -#endif - if (ident == Id::length) - { - e = new IntegerExp(loc, arguments->dim, Type::tsize_t); - } - else - { - error(loc, "no property '%s' for tuple '%s'", ident->toChars(), toChars()); - e = new ErrorExp(); - } - return e; -} - -/***************************** TypeSlice *****************************/ - -/* This is so we can slice a TypeTuple */ - -TypeSlice::TypeSlice(Type *next, Expression *lwr, Expression *upr) - : TypeNext(Tslice, next) -{ - //printf("TypeSlice[%s .. %s]\n", lwr->toChars(), upr->toChars()); - this->lwr = lwr; - this->upr = upr; -} - -Type *TypeSlice::syntaxCopy() -{ - Type *t = new TypeSlice(next->syntaxCopy(), lwr->syntaxCopy(), upr->syntaxCopy()); - t->mod = mod; - return t; -} - -Type *TypeSlice::semantic(Loc loc, Scope *sc) -{ - //printf("TypeSlice::semantic() %s\n", toChars()); - next = next->semantic(loc, sc); - transitive(); - //printf("next: %s\n", next->toChars()); - - Type *tbn = next->toBasetype(); - if (tbn->ty != Ttuple) - { error(loc, "can only slice tuple types, not %s", tbn->toChars()); - return Type::terror; - } - TypeTuple *tt = (TypeTuple *)tbn; - - lwr = semanticLength(sc, tbn, lwr); - lwr = lwr->optimize(WANTvalue | WANTinterpret); - uinteger_t i1 = lwr->toUInteger(); - - upr = semanticLength(sc, tbn, upr); - upr = upr->optimize(WANTvalue | WANTinterpret); - uinteger_t i2 = upr->toUInteger(); - - if (!(i1 <= i2 && i2 <= tt->arguments->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, tt->arguments->dim); - return Type::terror; - } - - Parameters *args = new Parameters; - args->reserve(i2 - i1); - for (size_t i = i1; i < i2; i++) - { Parameter *arg = tt->arguments->tdata()[i]; - args->push(arg); - } - - Type *t = (new TypeTuple(args))->semantic(loc, sc); - return t; -} - -void TypeSlice::resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps) -{ - next->resolve(loc, sc, pe, pt, ps); - if (*pe) - { // It's really a slice expression - Expression *e; - e = new SliceExp(loc, *pe, lwr, upr); - *pe = e; - } - else if (*ps) - { Dsymbol *s = *ps; - TupleDeclaration *td = s->isTupleDeclaration(); - if (td) - { - /* It's a slice of a TupleDeclaration - */ - ScopeDsymbol *sym = new ArrayScopeSymbol(sc, td); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - lwr = lwr->semantic(sc); - lwr = lwr->optimize(WANTvalue | WANTinterpret); - uinteger_t i1 = lwr->toUInteger(); - - upr = upr->semantic(sc); - upr = upr->optimize(WANTvalue | WANTinterpret); - uinteger_t i2 = upr->toUInteger(); - - sc = sc->pop(); - - if (!(i1 <= i2 && i2 <= td->objects->dim)) - { error(loc, "slice [%ju..%ju] is out of range of [0..%u]", i1, i2, td->objects->dim); - goto Ldefault; - } - - if (i1 == 0 && i2 == td->objects->dim) - { - *ps = td; - return; - } - - /* Create a new TupleDeclaration which - * is a slice [i1..i2] out of the old one. - */ - Objects *objects = new Objects; - objects->setDim(i2 - i1); - for (size_t i = 0; i < objects->dim; i++) - { - objects->tdata()[i] = td->objects->tdata()[(size_t)i1 + i]; - } - - TupleDeclaration *tds = new TupleDeclaration(loc, td->ident, objects); - *ps = tds; - } - else - goto Ldefault; - } - else - { - Ldefault: - Type::resolve(loc, sc, pe, pt, ps); - } -} - -void TypeSlice::toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod) -{ - if (mod != this->mod) - { toCBuffer3(buf, hgs, mod); - return; - } - next->toCBuffer2(buf, hgs, this->mod); - - buf->printf("[%s .. ", lwr->toChars()); - buf->printf("%s]", upr->toChars()); -} - -/***************************** TypeNull *****************************/ - -TypeNull::TypeNull() - : Type(Tnull) -{ -} - -Type *TypeNull::syntaxCopy() -{ - // No semantic analysis done, no need to copy - return this; -} - -MATCH TypeNull::implicitConvTo(Type *to) -{ - //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to->toChars()); - MATCH m = Type::implicitConvTo(to); - if (m) - return m; - - // NULL implicitly converts to any pointer type or dynamic array - //if (type->ty == Tpointer && type->nextOf()->ty == Tvoid) - { - Type *tb= to->toBasetype(); - if (tb->ty == Tpointer || tb->ty == Tarray || - tb->ty == Taarray || tb->ty == Tclass || - tb->ty == Tdelegate) - return MATCHconst; - } - - return MATCHnomatch; -} - -void TypeNull::toDecoBuffer(OutBuffer *buf, int flag, bool mangle) -{ - //tvoidptr->toDecoBuffer(buf, flag); - Type::toDecoBuffer(buf, flag, mangle); -} - -void TypeNull::toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs) -{ - buf->writestring("typeof(null)"); -} - -d_uns64 TypeNull::size(Loc loc) { return tvoidptr->size(loc); } -//Expression *TypeNull::getProperty(Loc loc, Identifier *ident) { return new ErrorExp(); } -//Expression *TypeNull::dotExp(Scope *sc, Expression *e, Identifier *ident) { return new ErrorExp(); } -Expression *TypeNull::defaultInit(Loc loc) { return new NullExp(0, Type::tnull); } -//Expression *TypeNull::defaultInitLiteral(Loc loc) { return new ErrorExp(); } - -/***************************** Parameter *****************************/ - -Parameter::Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg) -{ - this->type = type; - this->ident = ident; - this->storageClass = storageClass; - this->defaultArg = defaultArg; -} - -Parameter *Parameter::syntaxCopy() -{ - Parameter *a = new Parameter(storageClass, - type ? type->syntaxCopy() : NULL, - ident, - defaultArg ? defaultArg->syntaxCopy() : NULL); - return a; -} - -Parameters *Parameter::arraySyntaxCopy(Parameters *args) -{ Parameters *a = NULL; - - if (args) - { - a = new Parameters(); - a->setDim(args->dim); - for (size_t i = 0; i < a->dim; i++) - { Parameter *arg = args->tdata()[i]; - - arg = arg->syntaxCopy(); - a->tdata()[i] = arg; - } - } - return a; -} - -char *Parameter::argsTypesToChars(Parameters *args, int varargs) -{ - OutBuffer *buf = new OutBuffer(); - -#if 1 - HdrGenState hgs; - argsToCBuffer(buf, &hgs, args, varargs); -#else - buf->writeByte('('); - if (args) - { OutBuffer argbuf; - HdrGenState hgs; - - for (size_t i = 0; i < args->dim; i++) - { if (i) - buf->writeByte(','); - Parameter *arg = args->tdata()[i]; - argbuf.reset(); - arg->type->toCBuffer2(&argbuf, &hgs, 0); - buf->write(&argbuf); - } - if (varargs) - { - if (i && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -#endif - return buf->toChars(); -} - -void Parameter::argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs) -{ - buf->writeByte('('); - if (arguments) - { - OutBuffer argbuf; - - size_t dim = Parameter::dim(arguments); - for (size_t i = 0; i < dim; i++) - { - if (i) - buf->writestring(", "); - Parameter *arg = Parameter::getNth(arguments, i); - - if (arg->storageClass & STCauto) - buf->writestring("auto "); - - if (arg->storageClass & STCout) - buf->writestring("out "); - else if (arg->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? "inout " : "ref "); - else if (arg->storageClass & STCin) - buf->writestring("in "); - else if (arg->storageClass & STClazy) - buf->writestring("lazy "); - else if (arg->storageClass & STCalias) - buf->writestring("alias "); - - StorageClass stc = arg->storageClass; - if (arg->type && arg->type->mod & MODshared) - stc &= ~STCshared; - - StorageClassDeclaration::stcToCBuffer(buf, - stc & (STCconst | STCimmutable | STCshared | STCscope)); - - argbuf.reset(); - if (arg->storageClass & STCalias) - { if (arg->ident) - argbuf.writestring(arg->ident->toChars()); - } - else - arg->type->toCBuffer(&argbuf, arg->ident, hgs); - if (arg->defaultArg) - { - argbuf.writestring(" = "); - arg->defaultArg->toCBuffer(&argbuf, hgs); - } - buf->write(&argbuf); - } - if (varargs) - { - if (arguments->dim && varargs == 1) - buf->writeByte(','); - buf->writestring("..."); - } - } - buf->writeByte(')'); -} - -static const int mangleFlag = 0x01; - -static int argsToDecoBufferDg(void *ctx, size_t n, Parameter *arg, int flags) -{ - arg->toDecoBuffer((OutBuffer *)ctx, flags & mangleFlag); - return 0; -} - -void Parameter::argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle) -{ - //printf("Parameter::argsToDecoBuffer()\n"); - // Write argument types - foreach(arguments, &argsToDecoBufferDg, buf, 0, mangle ? mangleFlag : 0); -} - -/**************************************** - * Determine if parameter list is really a template parameter list - * (i.e. it has auto or alias parameters) - */ - -static int isTPLDg(void *ctx, size_t n, Parameter *arg, int) -{ - if (arg->storageClass & (STCalias | STCauto | STCstatic)) - return 1; - return 0; -} - -int Parameter::isTPL(Parameters *arguments) -{ - //printf("Parameter::isTPL()\n"); - return foreach(arguments, &isTPLDg, NULL); -} - -/**************************************************** - * Determine if parameter is a lazy array of delegates. - * If so, return the return type of those delegates. - * If not, return NULL. - */ - -Type *Parameter::isLazyArray() -{ -// if (inout == Lazy) - { - Type *tb = type->toBasetype(); - if (tb->ty == Tsarray || tb->ty == Tarray) - { - Type *tel = ((TypeArray *)tb)->next->toBasetype(); - if (tel->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)tel; - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - return tf->next; // return type of delegate - } - } - } - } - return NULL; -} - -void Parameter::toDecoBuffer(OutBuffer *buf, bool mangle) -{ - if (storageClass & STCscope) - buf->writeByte('M'); - switch (storageClass & (STCin | STCout | STCref | STClazy)) - { case 0: - case STCin: - break; - case STCout: - buf->writeByte('J'); - break; - case STCref: - buf->writeByte('K'); - break; - case STClazy: - buf->writeByte('L'); - break; - default: -#ifdef DEBUG - printf("storageClass = x%llx\n", storageClass & (STCin | STCout | STCref | STClazy)); - halt(); -#endif - assert(0); - } -#if 0 - int mod = 0x100; - if (type->toBasetype()->ty == Tclass) - mod = 0; - type->toDecoBuffer(buf, mod); -#else - //type->toHeadMutable()->toDecoBuffer(buf, 0); - type->toDecoBuffer(buf, 0, mangle); -#endif -} - -/*************************************** - * Determine number of arguments, folding in tuples. - */ - -static int dimDg(void *ctx, size_t n, Parameter *, int) -{ - ++*(size_t *)ctx; - return 0; -} - -size_t Parameter::dim(Parameters *args) -{ - size_t n = 0; - foreach(args, &dimDg, &n); - return n; -} - -/*************************************** - * Get nth Parameter, folding in tuples. - * Returns: - * Parameter* nth Parameter - * NULL not found, *pn gets incremented by the number - * of Parameters - */ - -struct GetNthParamCtx -{ - size_t nth; - Parameter *arg; -}; - -static int getNthParamDg(void *ctx, size_t n, Parameter *arg, int) -{ - GetNthParamCtx *p = (GetNthParamCtx *)ctx; - if (n == p->nth) - { p->arg = arg; - return 1; - } - return 0; -} - -Parameter *Parameter::getNth(Parameters *args, size_t nth, size_t *pn) -{ - GetNthParamCtx ctx = { nth, NULL }; - int res = foreach(args, &getNthParamDg, &ctx); - return res ? ctx.arg : NULL; -} - -/*************************************** - * Expands tuples in args in depth first order. Calls - * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. - * If dg returns !=0, stops and returns that value else returns 0. - * Use this function to avoid the O(N + N^2/2) complexity of - * calculating dim and calling N times getNth. - */ - -int Parameter::foreach(Parameters *args, Parameter::ForeachDg dg, void *ctx, size_t *pn, int flags) -{ - assert(dg); - if (!args) - return 0; - - size_t n = pn ? *pn : 0; // take over index - int result = 0; - for (size_t i = 0; i < args->dim; i++) - { Parameter *arg = args->tdata()[i]; - Type *t = arg->type->toBasetype(); - - if (t->ty == Ttuple) - { TypeTuple *tu = (TypeTuple *)t; - result = foreach(tu->arguments, dg, ctx, &n, flags); - } - else - result = dg(ctx, n++, arg, flags); - - if (result) - break; - } - - if (pn) - *pn = n; // update index - return result; -} diff --git a/dmd2/mtype.h b/dmd2/mtype.h deleted file mode 100644 index 00536496..00000000 --- a/dmd2/mtype.h +++ /dev/null @@ -1,1067 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_MTYPE_H -#define DMD_MTYPE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "expression.h" - -#if IN_LLVM -#include "../ir/irfuncty.h" -namespace llvm { class Type; } -class Ir; -class IrType; -#endif - -struct Scope; -struct Identifier; -struct Expression; -struct StructDeclaration; -struct ClassDeclaration; -struct VarDeclaration; -struct EnumDeclaration; -struct TypedefDeclaration; -struct TypeInfoDeclaration; -struct Dsymbol; -struct TemplateInstance; -struct CppMangleState; -struct TemplateDeclaration; -enum LINK; - -struct TypeBasic; -struct HdrGenState; -struct Parameter; - -// Back end -#if IN_GCC -union tree_node; typedef union tree_node TYPE; -typedef TYPE type; -#endif - -#if IN_DMD -struct Symbol; -#endif - -struct TypeTuple; - -enum ENUMTY -{ - Tarray, // slice array, aka T[] - Tsarray, // static array, aka T[dimension] - Taarray, // associative array, aka T[type] - Tpointer, - Treference, - Tfunction, - Tident, - Tclass, - Tstruct, - Tenum, - - Ttypedef, - Tdelegate, - Tnone, - Tvoid, - Tint8, - Tuns8, - Tint16, - Tuns16, - Tint32, - Tuns32, - - Tint64, - Tuns64, - Tfloat32, - Tfloat64, - Tfloat80, - Timaginary32, - Timaginary64, - Timaginary80, - Tcomplex32, - Tcomplex64, - - Tcomplex80, - Tbool, - Tchar, - Twchar, - Tdchar, - Terror, - Tinstance, - Ttypeof, - Ttuple, - Tslice, - - Treturn, - Tnull, - Tvector, - TMAX -}; -typedef unsigned char TY; // ENUMTY - -#define Tascii Tchar - -extern int Tsize_t; -extern int Tptrdiff_t; - - -struct Type : Object -{ - TY ty; - unsigned char mod; // modifiers MODxxxx - /* pick this order of numbers so switch statements work better - */ - #define MODconst 1 // type is const - #define MODimmutable 4 // type is immutable - #define MODshared 2 // type is shared - #define MODwild 8 // type is wild - #define MODmutable 0x10 // type is mutable (only used in wildcard matching) - char *deco; - - /* These are cached values that are lazily evaluated by constOf(), invariantOf(), etc. - * They should not be referenced by anybody but mtype.c. - * They can be NULL if not lazily evaluated yet. - * Note that there is no "shared immutable", because that is just immutable - * Naked == no MOD bits - */ - - Type *cto; // MODconst ? naked version of this type : const version - Type *ito; // MODimmutable ? naked version of this type : immutable version - Type *sto; // MODshared ? naked version of this type : shared mutable version - Type *scto; // MODshared|MODconst ? naked version of this type : shared const version - Type *wto; // MODwild ? naked version of this type : wild version - Type *swto; // MODshared|MODwild ? naked version of this type : shared wild version - - Type *pto; // merged pointer to this type - Type *rto; // reference to this type - Type *arrayof; // array of this type - TypeInfoDeclaration *vtinfo; // TypeInfo object for this Type - -#if IN_DMD - type *ctype; // for back end -#endif - - #define tvoid basic[Tvoid] - #define tint8 basic[Tint8] - #define tuns8 basic[Tuns8] - #define tint16 basic[Tint16] - #define tuns16 basic[Tuns16] - #define tint32 basic[Tint32] - #define tuns32 basic[Tuns32] - #define tint64 basic[Tint64] - #define tuns64 basic[Tuns64] - #define tfloat32 basic[Tfloat32] - #define tfloat64 basic[Tfloat64] - #define tfloat80 basic[Tfloat80] - - #define timaginary32 basic[Timaginary32] - #define timaginary64 basic[Timaginary64] - #define timaginary80 basic[Timaginary80] - - #define tcomplex32 basic[Tcomplex32] - #define tcomplex64 basic[Tcomplex64] - #define tcomplex80 basic[Tcomplex80] - - #define tbool basic[Tbool] - #define tchar basic[Tchar] - #define twchar basic[Twchar] - #define tdchar basic[Tdchar] - - // Some special types - #define tshiftcnt tint32 // right side of shift expression -// #define tboolean tint32 // result of boolean expression - #define tboolean tbool // result of boolean expression - #define tindex tsize_t // array/ptr index - static Type *tvoidptr; // void* - static Type *tstring; // immutable(char)[] - #define terror basic[Terror] // for error recovery - - #define tnull basic[Tnull] // for null type - - #define tsize_t basic[Tsize_t] // matches size_t alias - #define tptrdiff_t basic[Tptrdiff_t] // matches ptrdiff_t alias - #define thash_t tsize_t // matches hash_t alias - - static ClassDeclaration *typeinfo; - static ClassDeclaration *typeinfoclass; - static ClassDeclaration *typeinfointerface; - static ClassDeclaration *typeinfostruct; - static ClassDeclaration *typeinfotypedef; - static ClassDeclaration *typeinfopointer; - static ClassDeclaration *typeinfoarray; - static ClassDeclaration *typeinfostaticarray; - static ClassDeclaration *typeinfoassociativearray; - static ClassDeclaration *typeinfovector; - static ClassDeclaration *typeinfoenum; - static ClassDeclaration *typeinfofunction; - static ClassDeclaration *typeinfodelegate; - static ClassDeclaration *typeinfotypelist; - static ClassDeclaration *typeinfoconst; - static ClassDeclaration *typeinfoinvariant; - static ClassDeclaration *typeinfoshared; - static ClassDeclaration *typeinfowild; - - static TemplateDeclaration *associativearray; - - static Type *basic[TMAX]; - static unsigned char mangleChar[TMAX]; - static unsigned short sizeTy[TMAX]; - static StringTable stringtable; -#if IN_LLVM - static StringTable deco_stringtable; -#endif - - // These tables are for implicit conversion of binary ops; - // the indices are the type of operand one, followed by operand two. - static unsigned char impcnvResult[TMAX][TMAX]; - static unsigned char impcnvType1[TMAX][TMAX]; - static unsigned char impcnvType2[TMAX][TMAX]; - - // If !=0, give warning on implicit conversion - static unsigned char impcnvWarn[TMAX][TMAX]; - - Type(TY ty); - virtual Type *syntaxCopy(); - int equals(Object *o); - int dyncast() { return DYNCAST_TYPE; } // kludge for template.isType() - int covariant(Type *t); - char *toChars(); - static char needThisPrefix(); -#if IN_LLVM - static void init(Ir*); -#else - static void init(); -#endif - d_uns64 size(); - virtual d_uns64 size(Loc loc); - virtual unsigned alignsize(); - virtual Type *semantic(Loc loc, Scope *sc); - Type *trySemantic(Loc loc, Scope *sc); - // append the mangleof or a string uniquely identifying this type to buf - virtual void toDecoBuffer(OutBuffer *buf, int flag = 0, bool mangle=false); - Type *merge(); - Type *merge2(); - virtual void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - virtual void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toCBuffer3(OutBuffer *buf, HdrGenState *hgs, int mod); - void modToBuffer(OutBuffer *buf); -#if CPP_MANGLE - virtual void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - virtual int isintegral(); - virtual int isfloating(); // real, imaginary, or complex - virtual int isreal(); - virtual int isimaginary(); - virtual int iscomplex(); - virtual int isscalar(); - virtual int isunsigned(); - virtual int isscope(); - virtual int isString(); - virtual int isAssignable(); - virtual int checkBoolean(); // if can be converted to boolean value - virtual void checkDeprecated(Loc loc, Scope *sc); - int isConst() { return mod & MODconst; } - int isImmutable() { return mod & MODimmutable; } - int isMutable() { return !(mod & (MODconst | MODimmutable | MODwild)); } - int isShared() { return mod & MODshared; } - int isSharedConst() { return mod == (MODshared | MODconst); } - int isWild() { return mod & MODwild; } - int isSharedWild() { return mod == (MODshared | MODwild); } - int isNaked() { return mod == 0; } - Type *constOf(); - Type *invariantOf(); - Type *mutableOf(); - Type *sharedOf(); - Type *sharedConstOf(); - Type *unSharedOf(); - Type *wildOf(); - Type *sharedWildOf(); - void fixTo(Type *t); - void check(); - Type *addSTC(StorageClass stc); - Type *castMod(unsigned mod); - Type *addMod(unsigned mod); - Type *addStorageClass(StorageClass stc); - Type *pointerTo(); - Type *referenceTo(); - Type *arrayOf(); - Type *aliasthisOf(); - virtual Type *makeConst(); - virtual Type *makeInvariant(); - virtual Type *makeShared(); - virtual Type *makeSharedConst(); - virtual Type *makeWild(); - virtual Type *makeSharedWild(); - virtual Type *makeMutable(); - virtual Dsymbol *toDsymbol(Scope *sc); - virtual Type *toBasetype(); - virtual int isBaseOf(Type *t, int *poffset); - virtual MATCH implicitConvTo(Type *to); - virtual MATCH constConv(Type *to); - virtual unsigned wildConvTo(Type *tprm); - Type *substWildTo(unsigned mod); - virtual Type *toHeadMutable(); - virtual ClassDeclaration *isClassHandle(); - virtual Expression *getProperty(Loc loc, Identifier *ident); - virtual Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *noMember(Scope *sc, Expression *e, Identifier *ident); - virtual unsigned memalign(unsigned salign); - virtual Expression *defaultInit(Loc loc = 0); - virtual Expression *defaultInitLiteral(Loc loc = 0); - virtual int isZeroInit(Loc loc = 0); // if initializer is 0 -#if IN_DMD - virtual dt_t **toDt(dt_t **pdt); -#endif - Identifier *getTypeInfoIdent(int internal); - virtual MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - virtual void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Expression *getInternalTypeInfo(Scope *sc); - Expression *getTypeInfo(Scope *sc); - virtual TypeInfoDeclaration *getTypeInfoDeclaration(); - virtual int builtinTypeInfo(); - virtual Type *reliesOnTident(); - virtual int hasWild(); - virtual Expression *toExpression(); - virtual int hasPointers(); - virtual TypeTuple *toArgTypes(); - virtual Type *nextOf(); - uinteger_t sizemask(); - virtual int needsDestruction(); - - - static void error(Loc loc, const char *format, ...) IS_PRINTF(2); - static void warning(Loc loc, const char *format, ...) IS_PRINTF(2); - -#if IN_DMD - // For backend - virtual unsigned totym(); - virtual type *toCtype(); - virtual type *toCParamtype(); - virtual Symbol *toSymbol(); -#endif - - // For eliminating dynamic_cast - virtual TypeBasic *isTypeBasic(); - -#if IN_LLVM - static Ir* sir; - IrType* irtype; -#endif -}; - -struct TypeError : Type -{ - TypeError(); - Type *syntaxCopy(); - - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - - d_uns64 size(Loc loc); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); -}; - -struct TypeNext : Type -{ - Type *next; - - TypeNext(TY ty, Type *next); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void checkDeprecated(Loc loc, Scope *sc); - Type *reliesOnTident(); - int hasWild(); - Type *nextOf(); - Type *makeConst(); - Type *makeInvariant(); - Type *makeShared(); - Type *makeSharedConst(); - Type *makeWild(); - Type *makeSharedWild(); - Type *makeMutable(); - MATCH constConv(Type *to); - unsigned wildConvTo(Type *tprm); - void transitive(); -}; - -struct TypeBasic : Type -{ - const char *dstring; - unsigned flags; - - TypeBasic(TY ty); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); -#if IN_LLVM - unsigned memalign(unsigned salign); -#endif - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - char *toChars(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int builtinTypeInfo(); - TypeTuple *toArgTypes(); - - // For eliminating dynamic_cast - TypeBasic *isTypeBasic(); -}; - -struct TypeVector : Type -{ - Type *basetype; - - TypeVector(Loc loc, Type *basetype); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - unsigned alignsize(); - Expression *getProperty(Loc loc, Identifier *ident); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - char *toChars(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - int isintegral(); - int isfloating(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - TypeBasic *elementType(); - int isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - TypeTuple *toArgTypes(); -}; - -struct TypeArray : TypeNext -{ - TypeArray(TY ty, Type *next); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); -}; - -// Static array, one with a fixed dimension -struct TypeSArray : TypeArray -{ - Expression *dim; - - TypeSArray(Type *t, Expression *dim); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - unsigned memalign(unsigned salign); - MATCH constConv(Type *to); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); - dt_t **toDtElem(dt_t **pdt, Expression *e); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *toExpression(); - int hasPointers(); - int needsDestruction(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -// Dynamic array, no dimension -struct TypeDArray : TypeArray -{ - TypeDArray(Type *t); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - Type *semantic(Loc loc, Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int isString(); - int isZeroInit(Loc loc); - int checkBoolean(); - MATCH implicitConvTo(Type *to); - Expression *defaultInit(Loc loc); - int builtinTypeInfo(); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeAArray : TypeArray -{ - Type *index; // key type - Loc loc; - Scope *sc; - - StructDeclaration *impl; // implementation - - TypeAArray(Type *t, Type *index); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - Type *semantic(Loc loc, Scope *sc); - StructDeclaration *getImpl(); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - // Back end - Symbol *aaGetSymbol(const char *func, int flags); - - type *toCtype(); -#endif -}; - -struct TypePointer : TypeNext -{ - TypePointer(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - int isscalar(); - // LDC: pointers are unsigned - int isunsigned() { return TRUE; }; - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeReference : TypeNext -{ - TypeReference(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif -}; - -enum RET -{ - RETregs = 1, // returned in registers - RETstack = 2, // returned on stack -}; - -enum TRUST -{ - TRUSTdefault = 0, - TRUSTsystem = 1, // @system (same as TRUSTdefault) - TRUSTtrusted = 2, // @trusted - TRUSTsafe = 3, // @safe -}; - -enum PURE -{ - PUREimpure = 0, // not pure at all - PUREweak = 1, // no mutable globals are read or written - PUREconst = 2, // parameters are values or const - PUREstrong = 3, // parameters are values or immutable - PUREfwdref = 4, // it's pure, but not known which level yet -}; - -struct TypeFunction : TypeNext -{ - // .next is the return type - - Parameters *parameters; // function parameters - int varargs; // 1: T t, ...) style for variable number of arguments - // 2: T t ...) style for variable number of arguments - bool isnothrow; // true: nothrow - bool isproperty; // can be called without parentheses - bool isref; // true: returns a reference - enum LINK linkage; // calling convention - enum TRUST trust; // level of trust - enum PURE purity; // PURExxxx - Expressions *fargs; // function arguments - - int inuse; - - TypeFunction(Parameters *parameters, Type *treturn, int varargs, enum LINK linkage, StorageClass stc = 0); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void purityLevel(); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - void toCBufferWithAttributes(OutBuffer *buf, Identifier *ident, HdrGenState* hgs, TypeFunction *attrs, TemplateDeclaration *td); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void attributesToCBuffer(OutBuffer *buf, int mod); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Type *reliesOnTident(); - bool hasLazyParameters(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - bool parameterEscapes(Parameter *p); - - int callMatch(Expression *ethis, Expressions *toargs, int flag = 0); -#if IN_DMD - type *toCtype(); -#endif - - enum RET retStyle(); - -#if IN_DMD - unsigned totym(); -#endif - - Expression *defaultInit(Loc loc); - -#if IN_LLVM - // LDC - IrFuncTy fty; - - FuncDeclaration* funcdecl; -#endif -}; - -struct TypeDelegate : TypeNext -{ - // .next is a TypeFunction - - TypeDelegate(Type *t); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); - unsigned alignsize(); - MATCH implicitConvTo(Type *to); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeQualified : Type -{ - Loc loc; - Identifiers idents; // array of Identifier's representing ident.ident.ident etc. - - TypeQualified(TY ty, Loc loc); - void syntaxCopyHelper(TypeQualified *t); - void addIdent(Identifier *ident); - void toCBuffer2Helper(OutBuffer *buf, HdrGenState *hgs); - d_uns64 size(Loc loc); - void resolveHelper(Loc loc, Scope *sc, Dsymbol *s, Dsymbol *scopesym, - Expression **pe, Type **pt, Dsymbol **ps); -}; - -struct TypeIdentifier : TypeQualified -{ - Identifier *ident; - - TypeIdentifier(Loc loc, Identifier *ident); - Type *syntaxCopy(); - //char *toChars(); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - Type *reliesOnTident(); - Expression *toExpression(); -}; - -/* Similar to TypeIdentifier, but with a TemplateInstance as the root - */ -struct TypeInstance : TypeQualified -{ - TemplateInstance *tempinst; - - TypeInstance(Loc loc, TemplateInstance *tempinst); - Type *syntaxCopy(); - //char *toChars(); - //void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); -}; - -struct TypeTypeof : TypeQualified -{ - Expression *exp; - int inuse; - - TypeTypeof(Loc loc, Expression *exp); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Type *semantic(Loc loc, Scope *sc); - d_uns64 size(Loc loc); -}; - -struct TypeReturn : TypeQualified -{ - TypeReturn(Loc loc); - Type *syntaxCopy(); - Dsymbol *toDsymbol(Scope *sc); - Type *semantic(Loc loc, Scope *sc); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -struct TypeStruct : Type -{ - StructDeclaration *sym; - - TypeStruct(StructDeclaration *sym); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - unsigned memalign(unsigned salign); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - int isZeroInit(Loc loc); - int isAssignable(); - int checkBoolean(); - int needsDestruction(); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - unsigned wildConvTo(Type *tprm); - Type *toHeadMutable(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#elif IN_LLVM - // LDC - // cache the hasUnalignedFields check - // 0 = not checked, 1 = aligned, 2 = unaligned - int unaligned; -#endif -}; - -struct TypeEnum : Type -{ - EnumDeclaration *sym; - - TypeEnum(EnumDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - int isAssignable(); - int needsDestruction(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Type *toBasetype(); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); -#endif -}; - -struct TypeTypedef : Type -{ - TypedefDeclaration *sym; - - TypeTypedef(TypedefDeclaration *sym); - Type *syntaxCopy(); - d_uns64 size(Loc loc); - unsigned alignsize(); - char *toChars(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *getProperty(Loc loc, Identifier *ident); - int isintegral(); - int isfloating(); - int isreal(); - int isimaginary(); - int iscomplex(); - int isscalar(); - int isunsigned(); - int checkBoolean(); - int isAssignable(); - int needsDestruction(); - Type *toBasetype(); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - Type *toHeadMutable(); - Expression *defaultInit(Loc loc); - Expression *defaultInitLiteral(Loc loc); - int isZeroInit(Loc loc); -#if IN_DMD - dt_t **toDt(dt_t **pdt); -#endif - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - int hasWild(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); - type *toCParamtype(); -#endif -}; - -struct TypeClass : Type -{ - ClassDeclaration *sym; - - TypeClass(ClassDeclaration *sym); - d_uns64 size(Loc loc); - char *toChars(); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - Dsymbol *toDsymbol(Scope *sc); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - ClassDeclaration *isClassHandle(); - int isBaseOf(Type *t, int *poffset); - MATCH implicitConvTo(Type *to); - MATCH constConv(Type *to); - unsigned wildConvTo(Type *tprm); - Type *toHeadMutable(); - Expression *defaultInit(Loc loc); - int isZeroInit(Loc loc); - MATCH deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch = NULL); - int isscope(); - int checkBoolean(); - TypeInfoDeclaration *getTypeInfoDeclaration(); - int hasPointers(); - TypeTuple *toArgTypes(); - int builtinTypeInfo(); -#if CPP_MANGLE - void toCppMangle(OutBuffer *buf, CppMangleState *cms); -#endif - -#if IN_DMD - type *toCtype(); - - Symbol *toSymbol(); -#endif -}; - -struct TypeTuple : Type -{ - Parameters *arguments; // types making up the tuple - - TypeTuple(Parameters *arguments); - TypeTuple(Expressions *exps); - TypeTuple(); - TypeTuple(Type *t1); - TypeTuple(Type *t1, Type *t2); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - int equals(Object *o); - Type *reliesOnTident(); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - Expression *getProperty(Loc loc, Identifier *ident); - TypeInfoDeclaration *getTypeInfoDeclaration(); -}; - -struct TypeSlice : TypeNext -{ - Expression *lwr; - Expression *upr; - - TypeSlice(Type *next, Expression *lwr, Expression *upr); - Type *syntaxCopy(); - Type *semantic(Loc loc, Scope *sc); - void resolve(Loc loc, Scope *sc, Expression **pe, Type **pt, Dsymbol **ps); - void toCBuffer2(OutBuffer *buf, HdrGenState *hgs, int mod); -}; - -struct TypeNull : Type -{ - TypeNull(); - - Type *syntaxCopy(); - void toDecoBuffer(OutBuffer *buf, int flag, bool mangle); - MATCH implicitConvTo(Type *to); - - void toCBuffer(OutBuffer *buf, Identifier *ident, HdrGenState *hgs); - - d_uns64 size(Loc loc); - //Expression *getProperty(Loc loc, Identifier *ident); - //Expression *dotExp(Scope *sc, Expression *e, Identifier *ident); - Expression *defaultInit(Loc loc); - //Expression *defaultInitLiteral(Loc loc); -}; - -/**************************************************************/ - -//enum InOut { None, In, Out, InOut, Lazy }; - -struct Parameter : Object -{ - //enum InOut inout; - StorageClass storageClass; - Type *type; - Identifier *ident; - Expression *defaultArg; - - Parameter(StorageClass storageClass, Type *type, Identifier *ident, Expression *defaultArg); - Parameter *syntaxCopy(); - Type *isLazyArray(); - void toDecoBuffer(OutBuffer *buf, bool mangle); - static Parameters *arraySyntaxCopy(Parameters *args); - static char *argsTypesToChars(Parameters *args, int varargs); - static void argsCppMangle(OutBuffer *buf, CppMangleState *cms, Parameters *arguments, int varargs); - static void argsToCBuffer(OutBuffer *buf, HdrGenState *hgs, Parameters *arguments, int varargs); - static void argsToDecoBuffer(OutBuffer *buf, Parameters *arguments, bool mangle); - static int isTPL(Parameters *arguments); - static size_t dim(Parameters *arguments); - static Parameter *getNth(Parameters *arguments, size_t nth, size_t *pn = NULL); - - typedef int (*ForeachDg)(void *ctx, size_t paramidx, Parameter *param, int flags); - static int foreach(Parameters *args, ForeachDg dg, void *ctx, size_t *pn=NULL, int flags = 0); -}; - -extern int PTRSIZE; -extern int REALSIZE; -extern int REALPAD; -extern int Tsize_t; -extern int Tptrdiff_t; - -int arrayTypeCompatible(Loc loc, Type *t1, Type *t2); -int arrayTypeCompatibleWithoutCasting(Loc loc, Type *t1, Type *t2); -void MODtoBuffer(OutBuffer *buf, unsigned char mod); -int MODimplicitConv(unsigned char modfrom, unsigned char modto); -int MODmethodConv(unsigned char modfrom, unsigned char modto); -int MODmerge(unsigned char mod1, unsigned char mod2); - -#endif /* DMD_MTYPE_H */ diff --git a/dmd2/opover.c b/dmd2/opover.c deleted file mode 100644 index 27e2c7d1..00000000 --- a/dmd2/opover.c +++ /dev/null @@ -1,1612 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#if _MSC_VER -#include -#else -#include -#endif - -#ifdef __APPLE__ -#define integer_t dmd_integer_t -#endif - -#include "rmem.h" - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "statement.h" -#include "scope.h" -#include "id.h" -#include "declaration.h" -#include "aggregate.h" -#include "template.h" -#include "scope.h" - -static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments); -static void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments); -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flags = 0); -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments); - -/******************************** Expression **************************/ - - -/*********************************** - * Determine if operands of binary op can be reversed - * to fit operator overload. - */ - -int Expression::isCommutative() -{ - return FALSE; // default is no reverse -} - -/*********************************** - * Get Identifier for operator overload. - */ - -Identifier *Expression::opId() -{ - assert(0); - return NULL; -} - -/*********************************** - * Get Identifier for reverse operator overload, - * NULL if not supported for this operator. - */ - -Identifier *Expression::opId_r() -{ - return NULL; -} - -/************************* Operators *****************************/ - -Identifier *UAddExp::opId() { return Id::uadd; } - -Identifier *NegExp::opId() { return Id::neg; } - -Identifier *ComExp::opId() { return Id::com; } - -Identifier *CastExp::opId() { return Id::cast; } - -Identifier *InExp::opId() { return Id::opIn; } -Identifier *InExp::opId_r() { return Id::opIn_r; } - -Identifier *PostExp::opId() { return (op == TOKplusplus) - ? Id::postinc - : Id::postdec; } - -int AddExp::isCommutative() { return TRUE; } -Identifier *AddExp::opId() { return Id::add; } -Identifier *AddExp::opId_r() { return Id::add_r; } - -Identifier *MinExp::opId() { return Id::sub; } -Identifier *MinExp::opId_r() { return Id::sub_r; } - -int MulExp::isCommutative() { return TRUE; } -Identifier *MulExp::opId() { return Id::mul; } -Identifier *MulExp::opId_r() { return Id::mul_r; } - -Identifier *DivExp::opId() { return Id::div; } -Identifier *DivExp::opId_r() { return Id::div_r; } - -Identifier *ModExp::opId() { return Id::mod; } -Identifier *ModExp::opId_r() { return Id::mod_r; } - -#if DMDV2 -Identifier *PowExp::opId() { return Id::pow; } -Identifier *PowExp::opId_r() { return Id::pow_r; } -#endif - -Identifier *ShlExp::opId() { return Id::shl; } -Identifier *ShlExp::opId_r() { return Id::shl_r; } - -Identifier *ShrExp::opId() { return Id::shr; } -Identifier *ShrExp::opId_r() { return Id::shr_r; } - -Identifier *UshrExp::opId() { return Id::ushr; } -Identifier *UshrExp::opId_r() { return Id::ushr_r; } - -int AndExp::isCommutative() { return TRUE; } -Identifier *AndExp::opId() { return Id::iand; } -Identifier *AndExp::opId_r() { return Id::iand_r; } - -int OrExp::isCommutative() { return TRUE; } -Identifier *OrExp::opId() { return Id::ior; } -Identifier *OrExp::opId_r() { return Id::ior_r; } - -int XorExp::isCommutative() { return TRUE; } -Identifier *XorExp::opId() { return Id::ixor; } -Identifier *XorExp::opId_r() { return Id::ixor_r; } - -Identifier *CatExp::opId() { return Id::cat; } -Identifier *CatExp::opId_r() { return Id::cat_r; } - -Identifier * AssignExp::opId() { return Id::assign; } -Identifier * AddAssignExp::opId() { return Id::addass; } -Identifier * MinAssignExp::opId() { return Id::subass; } -Identifier * MulAssignExp::opId() { return Id::mulass; } -Identifier * DivAssignExp::opId() { return Id::divass; } -Identifier * ModAssignExp::opId() { return Id::modass; } -Identifier * AndAssignExp::opId() { return Id::andass; } -Identifier * OrAssignExp::opId() { return Id::orass; } -Identifier * XorAssignExp::opId() { return Id::xorass; } -Identifier * ShlAssignExp::opId() { return Id::shlass; } -Identifier * ShrAssignExp::opId() { return Id::shrass; } -Identifier *UshrAssignExp::opId() { return Id::ushrass; } -Identifier * CatAssignExp::opId() { return Id::catass; } -Identifier * PowAssignExp::opId() { return Id::powass; } - -int EqualExp::isCommutative() { return TRUE; } -Identifier *EqualExp::opId() { return Id::eq; } - -int CmpExp::isCommutative() { return TRUE; } -Identifier *CmpExp::opId() { return Id::cmp; } - -Identifier *ArrayExp::opId() { return Id::index; } -Identifier *PtrExp::opId() { return Id::opStar; } - -/************************************ - * If type is a class or struct, return the symbol for it, - * else NULL - */ -AggregateDeclaration *isAggregate(Type *t) -{ - t = t->toBasetype(); - if (t->ty == Tclass) - { - return ((TypeClass *)t)->sym; - } - else if (t->ty == Tstruct) - { - return ((TypeStruct *)t)->sym; - } - return NULL; -} - -/******************************************* - * Helper function to turn operator into template argument list - */ -Objects *opToArg(Scope *sc, enum TOK op) -{ - /* Remove the = from op= - */ - switch (op) - { - case TOKaddass: op = TOKadd; break; - case TOKminass: op = TOKmin; break; - case TOKmulass: op = TOKmul; break; - case TOKdivass: op = TOKdiv; break; - case TOKmodass: op = TOKmod; break; - case TOKandass: op = TOKand; break; - case TOKorass: op = TOKor; break; - case TOKxorass: op = TOKxor; break; - case TOKshlass: op = TOKshl; break; - case TOKshrass: op = TOKshr; break; - case TOKushrass: op = TOKushr; break; - case TOKcatass: op = TOKcat; break; - case TOKpowass: op = TOKpow; break; - } - Expression *e = new StringExp(0, (char *)Token::toChars(op)); - e = e->semantic(sc); - Objects *targsi = new Objects(); - targsi->push(e); - return targsi; -} - -/************************************ - * Operator overload. - * Check for operator overload, if so, replace - * with function call. - * Return NULL if not an operator overload. - */ - -Expression *UnaExp::op_overload(Scope *sc) -{ - //printf("UnaExp::op_overload() (%s)\n", toChars()); - -#if DMDV2 - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - - AggregateDeclaration *ad = isAggregate(ae->e1->type); - if (ad) - { - /* Rewrite as: - * a.opIndexUnary!("+")(args); - */ - Dsymbol *fd = search_function(ad, Id::opIndexUnary); - if (fd) - { - Objects *targsi = opToArg(sc, op); - Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(a[arguments]) as: - * op(a.aliasthis[arguments]) - */ - Expression *e1 = ae->copy(); - ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - } - else if (e1->op == TOKslice) - { - SliceExp *se = (SliceExp *)e1; - se->e1 = se->e1->semantic(sc); - se->e1 = resolveProperties(sc, se->e1); - - AggregateDeclaration *ad = isAggregate(se->e1->type); - if (ad) - { - /* Rewrite as: - * a.opSliceUnary!("+")(lwr, upr); - */ - Dsymbol *fd = search_function(ad, Id::opSliceUnary); - if (fd) - { - Expressions *a = new Expressions(); - if (se->lwr) - { a->push(se->lwr); - a->push(se->upr); - } - - Objects *targsi = opToArg(sc, op); - Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(a[lwr..upr]) as: - * op(a.aliasthis[lwr..upr]) - */ - Expression *e1 = se->copy(); - ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - } -#endif - - e1 = e1->semantic(sc); - e1 = resolveProperties(sc, e1); - - AggregateDeclaration *ad = isAggregate(e1->type); - if (ad) - { - Dsymbol *fd = NULL; -#if 1 // Old way, kept for compatibility with D1 - if (op != TOKpreplusplus && op != TOKpreminusminus) - { fd = search_function(ad, opId()); - if (fd) - { - if (op == TOKarray) - { - /* Rewrite op e1[arguments] as: - * e1.fd(arguments) - */ - Expression *e = new DotIdExp(loc, e1, fd->ident); - ArrayExp *ae = (ArrayExp *)this; - e = new CallExp(loc, e, ae->arguments); - e = e->semantic(sc); - return e; - } - else - { - // Rewrite +e1 as e1.add() - return build_overload(loc, sc, e1, NULL, fd); - } - } - } -#endif - -#if DMDV2 - /* Rewrite as: - * e1.opUnary!("+")(); - */ - fd = search_function(ad, Id::opUnary); - if (fd) - { - Objects *targsi = opToArg(sc, op); - Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi); - e = new CallExp(loc, e); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } -#endif - } - return NULL; -} - -Expression *ArrayExp::op_overload(Scope *sc) -{ - //printf("ArrayExp::op_overload() (%s)\n", toChars()); - AggregateDeclaration *ad = isAggregate(e1->type); - if (ad) - { - Dsymbol *fd = search_function(ad, opId()); - if (fd) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *x = arguments->tdata()[i]; - // Create scope for '$' variable for this dimension - ArrayScopeSymbol *sym = new ArrayScopeSymbol(sc, this); - sym->loc = loc; - sym->parent = sc->scopesym; - sc = sc->push(sym); - lengthVar = NULL; // Create it only if required - currentDimension = i; // Dimension for $, if required - - x = x->semantic(sc); - x = resolveProperties(sc, x); - if (!x->type) - error("%s has no value", x->toChars()); - if (lengthVar) - { // If $ was used, declare it now - Expression *av = new DeclarationExp(loc, lengthVar); - x = new CommaExp(0, av, x); - x->semantic(sc); - } - arguments->tdata()[i] = x; - sc = sc->pop(); - } - - /* Rewrite op e1[arguments] as: - * e1.opIndex(arguments) - */ - Expression *e = new DotIdExp(loc, e1, fd->ident); - e = new CallExp(loc, e, arguments); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - return NULL; -} - -/*********************************************** - * This is mostly the same as UnaryExp::op_overload(), but has - * a different rewrite. - */ -Expression *CastExp::op_overload(Scope *sc) -{ - //printf("CastExp::op_overload() (%s)\n", toChars()); - AggregateDeclaration *ad = isAggregate(e1->type); - if (ad) - { - Dsymbol *fd = NULL; - /* Rewrite as: - * e1.opCast!(T)(); - */ - fd = search_function(ad, Id::cast); - if (fd) - { -#if 1 // Backwards compatibility with D1 if opCast is a function, not a template - if (fd->isFuncDeclaration()) - { // Rewrite as: e1.opCast() - return build_overload(loc, sc, e1, NULL, fd); - } -#endif - Objects *targsi = new Objects(); - targsi->push(to); - Expression *e = new DotTemplateInstanceExp(loc, e1, fd->ident, targsi); - e = new CallExp(loc, e); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - return NULL; -} - -Expression *BinExp::op_overload(Scope *sc) -{ - //printf("BinExp::op_overload() (%s)\n", toChars()); - - Identifier *id = opId(); - Identifier *id_r = opId_r(); - - Expressions args1; - Expressions args2; - int argsset = 0; - - AggregateDeclaration *ad1 = isAggregate(e1->type); - AggregateDeclaration *ad2 = isAggregate(e2->type); - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - -#if 1 // the old D1 scheme - if (ad1 && id) - { - s = search_function(ad1, id); - } - if (ad2 && id_r) - { - s_r = search_function(ad2, id_r); - } -#endif - - Objects *targsi = NULL; -#if DMDV2 - if (op == TOKplusplus || op == TOKminusminus) - { // Bug4099 fix - if (ad1 && search_function(ad1, Id::opUnary)) - return NULL; - } - if (!s && !s_r && op != TOKequal && op != TOKnotequal && op != TOKassign && - op != TOKplusplus && op != TOKminusminus) - { - /* Try the new D2 scheme, opBinary and opBinaryRight - */ - if (ad1) - s = search_function(ad1, Id::opBinary); - if (ad2) - s_r = search_function(ad2, Id::opBinaryRight); - - // Set targsi, the template argument list, which will be the operator string - if (s || s_r) - { - id = Id::opBinary; - id_r = Id::opBinaryRight; - targsi = opToArg(sc, op); - } - } -#endif - - if (s || s_r) - { - /* Try: - * a.opfunc(b) - * b.opfunc_r(a) - * and see which is better. - */ - - args1.setDim(1); - args1.tdata()[0] = e1; - args2.setDim(1); - args2.tdata()[0] = e2; - argsset = 1; - - Match m; - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, e1, &args2); - } - } - - FuncDeclaration *lastf = m.lastf; - - if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, e2, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - if (targsi) - goto L1; - } - - Expression *e; - if (op == TOKplusplus || op == TOKminusminus) - // Kludge because operator overloading regards e++ and e-- - // as unary, but it's implemented as a binary. - // Rewrite (e1 ++ e2) as e1.postinc() - // Rewrite (e1 -- e2) as e1.postdec() - e = build_overload(loc, sc, e1, NULL, m.lastf ? m.lastf : s); - else if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s); - else - // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r); - return e; - } - -L1: -#if 1 // Retained for D1 compatibility - if (isCommutative() && !targsi) - { - s = NULL; - s_r = NULL; - if (ad1 && id_r) - { - s_r = search_function(ad1, id_r); - } - if (ad2 && id) - { - s = search_function(ad2, id); - } - - if (s || s_r) - { - /* Try: - * a.opfunc_r(b) - * b.opfunc(a) - * and see which is better. - */ - - if (!argsset) - { args1.setDim(1); - args1.tdata()[0] = e1; - args2.setDim(1); - args2.tdata()[0] = e2; - } - - Match m; - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, e1, &args2); - } - } - FuncDeclaration *lastf = m.lastf; - - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, e2, &args1); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - Expression *e; - if (lastf && m.lastf == lastf || !s && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc_r(e2) - e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s_r); - else - // Rewrite (e1 op e2) as e2.opfunc(e1) - e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // These are symmetric - case TOKunord: - case TOKlg: - case TOKleg: - case TOKue: - break; - } - - return e; - } - } -#endif - -#if DMDV2 - // Try alias this on first operand - if (ad1 && ad1->aliasthis && - !(op == TOKassign && ad2 && ad1 == ad2)) // See Bugzilla 2943 - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - - // Try alias this on second operand - if (ad2 && ad2->aliasthis && - /* Bugzilla 2943: make sure that when we're copying the struct, we don't - * just copy the alias this member - */ - !(op == TOKassign && ad1 && ad1 == ad2)) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; - } -#endif - return NULL; -} - -/****************************************** - * Common code for overloading of EqualExp and CmpExp - */ -Expression *BinExp::compare_overload(Scope *sc, Identifier *id) -{ - //printf("BinExp::compare_overload(id = %s) %s\n", id->toChars(), toChars()); - - AggregateDeclaration *ad1 = isAggregate(e1->type); - AggregateDeclaration *ad2 = isAggregate(e2->type); - - Dsymbol *s = NULL; - Dsymbol *s_r = NULL; - - if (ad1) - { - s = search_function(ad1, id); - } - if (ad2) - { - s_r = search_function(ad2, id); - if (s == s_r) - s_r = NULL; - } - - Objects *targsi = NULL; - - if (s || s_r) - { - /* Try: - * a.opEquals(b) - * b.opEquals(a) - * and see which is better. - */ - - Expressions args1; - Expressions args2; - - args1.setDim(1); - args1.tdata()[0] = e1; - args2.setDim(1); - args2.tdata()[0] = e2; - - Match m; - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (0 && s && s_r) - { - printf("s : %s\n", s->toPrettyChars()); - printf("s_r: %s\n", s_r->toPrettyChars()); - } - - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, NULL, &args2); - } - } - - FuncDeclaration *lastf = m.lastf; - int count = m.count; - - if (s_r) - { - FuncDeclaration *fd = s_r->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args1, sc->module); - } - else - { TemplateDeclaration *td = s_r->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, NULL, &args1); - } - } - - if (m.count > 1) - { - /* The following if says "not ambiguous" if there's one match - * from s and one from s_r, in which case we pick s. - * This doesn't follow the spec, but is a workaround for the case - * where opEquals was generated from templates and we cannot figure - * out if both s and s_r came from the same declaration or not. - * The test case is: - * import std.typecons; - * void main() { - * assert(tuple("has a", 2u) == tuple("has a", 1)); - * } - */ - if (!(m.lastf == lastf && m.count == 2 && count == 1)) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - } - - Expression *e; - if (lastf && m.lastf == lastf || !s_r && m.last == MATCHnomatch) - // Rewrite (e1 op e2) as e1.opfunc(e2) - e = build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s); - else - { // Rewrite (e1 op e2) as e2.opfunc_r(e1) - e = build_overload(loc, sc, e2, e1, m.lastf ? m.lastf : s_r); - - // When reversing operands of comparison operators, - // need to reverse the sense of the op - switch (op) - { - case TOKlt: op = TOKgt; break; - case TOKgt: op = TOKlt; break; - case TOKle: op = TOKge; break; - case TOKge: op = TOKle; break; - - // Floating point compares - case TOKule: op = TOKuge; break; - case TOKul: op = TOKug; break; - case TOKuge: op = TOKule; break; - case TOKug: op = TOKul; break; - - // The rest are symmetric - default: - break; - } - } - - return e; - } - - // Try alias this on first operand - if (ad1 && ad1->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - - // Try alias this on second operand - if (ad2 && ad2->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; - } - - return NULL; -} - -Expression *EqualExp::op_overload(Scope *sc) -{ - //printf("EqualExp::op_overload() (%s)\n", toChars()); - - Type *t1 = e1->type->toBasetype(); - Type *t2 = e2->type->toBasetype(); - if (t1->ty == Tclass && t2->ty == Tclass) - { ClassDeclaration *cd1 = t1->isClassHandle(); - ClassDeclaration *cd2 = t2->isClassHandle(); - - if (!(cd1->isCPPinterface() || cd2->isCPPinterface())) - { - /* Rewrite as: - * .object.opEquals(cast(Object)e1, cast(Object)e2) - * The explicit cast is necessary for interfaces, - * see http://d.puremagic.com/issues/show_bug.cgi?id=4088 - */ - Expression *e1x = new CastExp(loc, e1, ClassDeclaration::object->getType()); - Expression *e2x = new CastExp(loc, e2, ClassDeclaration::object->getType()); - - Expression *e = new IdentifierExp(loc, Id::empty); - e = new DotIdExp(loc, e, Id::object); - e = new DotIdExp(loc, e, Id::eq); - e = new CallExp(loc, e, e1x, e2x); - e = e->semantic(sc); - return e; - } - } - - return compare_overload(sc, Id::eq); -} - -Expression *CmpExp::op_overload(Scope *sc) -{ - //printf("CmpExp::op_overload() (%s)\n", toChars()); - - return compare_overload(sc, Id::cmp); -} - -/********************************* - * Operator overloading for op= - */ -Expression *BinAssignExp::op_overload(Scope *sc) -{ - //printf("BinAssignExp::op_overload() (%s)\n", toChars()); - -#if DMDV2 - if (e1->op == TOKarray) - { - ArrayExp *ae = (ArrayExp *)e1; - ae->e1 = ae->e1->semantic(sc); - ae->e1 = resolveProperties(sc, ae->e1); - - AggregateDeclaration *ad = isAggregate(ae->e1->type); - if (ad) - { - /* Rewrite a[args]+=e2 as: - * a.opIndexOpAssign!("+")(e2, args); - */ - Dsymbol *fd = search_function(ad, Id::opIndexOpAssign); - if (fd) - { - Expressions *a = new Expressions(); - a->push(e2); - for (size_t i = 0; i < ae->arguments->dim; i++) - a->push(ae->arguments->tdata()[i]); - - Objects *targsi = opToArg(sc, op); - Expression *e = new DotTemplateInstanceExp(loc, ae->e1, fd->ident, targsi); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite a[arguments] op= e2 as: - * a.aliasthis[arguments] op= e2 - */ - Expression *e1 = ae->copy(); - ((ArrayExp *)e1)->e1 = new DotIdExp(loc, ae->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - } - else if (e1->op == TOKslice) - { - SliceExp *se = (SliceExp *)e1; - se->e1 = se->e1->semantic(sc); - se->e1 = resolveProperties(sc, se->e1); - - AggregateDeclaration *ad = isAggregate(se->e1->type); - if (ad) - { - /* Rewrite a[lwr..upr]+=e2 as: - * a.opSliceOpAssign!("+")(e2, lwr, upr); - */ - Dsymbol *fd = search_function(ad, Id::opSliceOpAssign); - if (fd) - { - Expressions *a = new Expressions(); - a->push(e2); - if (se->lwr) - { a->push(se->lwr); - a->push(se->upr); - } - - Objects *targsi = opToArg(sc, op); - Expression *e = new DotTemplateInstanceExp(loc, se->e1, fd->ident, targsi); - e = new CallExp(loc, e, a); - e = e->semantic(sc); - return e; - } - - // Didn't find it. Forward to aliasthis - if (ad->aliasthis) - { - /* Rewrite a[lwr..upr] op= e2 as: - * a.aliasthis[lwr..upr] op= e2 - */ - Expression *e1 = se->copy(); - ((SliceExp *)e1)->e1 = new DotIdExp(loc, se->e1, ad->aliasthis->ident); - Expression *e = copy(); - ((UnaExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - } - } -#endif - - BinExp::semantic(sc); - e1 = resolveProperties(sc, e1); - e2 = resolveProperties(sc, e2); - - Identifier *id = opId(); - - Expressions args2; - - AggregateDeclaration *ad1 = isAggregate(e1->type); - - Dsymbol *s = NULL; - -#if 1 // the old D1 scheme - if (ad1 && id) - { - s = search_function(ad1, id); - } -#endif - - Objects *targsi = NULL; -#if DMDV2 - if (!s) - { /* Try the new D2 scheme, opOpAssign - */ - if (ad1) - s = search_function(ad1, Id::opOpAssign); - - // Set targsi, the template argument list, which will be the operator string - if (s) - { - id = Id::opOpAssign; - targsi = opToArg(sc, op); - } - } -#endif - - if (s) - { - /* Try: - * a.opOpAssign(b) - */ - - args2.setDim(1); - args2.tdata()[0] = e2; - - Match m; - memset(&m, 0, sizeof(m)); - m.last = MATCHnomatch; - - if (s) - { - FuncDeclaration *fd = s->isFuncDeclaration(); - if (fd) - { - overloadResolveX(&m, fd, NULL, &args2, sc->module); - } - else - { TemplateDeclaration *td = s->isTemplateDeclaration(); - templateResolve(&m, td, sc, loc, targsi, e1, &args2); - } - } - - if (m.count > 1) - { - // Error, ambiguous - error("overloads %s and %s both match argument list for %s", - m.lastf->type->toChars(), - m.nextf->type->toChars(), - m.lastf->toChars()); - } - else if (m.last == MATCHnomatch) - { - m.lastf = m.anyf; - if (targsi) - goto L1; - } - - // Rewrite (e1 op e2) as e1.opOpAssign(e2) - return build_overload(loc, sc, e1, e2, m.lastf ? m.lastf : s); - } - -L1: - -#if DMDV2 - // Try alias this on first operand - if (ad1 && ad1->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1.aliasthis op e2) - */ - Expression *e1 = new DotIdExp(loc, this->e1, ad1->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e1 = e1; - e = e->trySemantic(sc); - return e; - } - - // Try alias this on second operand - AggregateDeclaration *ad2 = isAggregate(e2->type); - if (ad2 && ad2->aliasthis) - { - /* Rewrite (e1 op e2) as: - * (e1 op e2.aliasthis) - */ - Expression *e2 = new DotIdExp(loc, this->e2, ad2->aliasthis->ident); - Expression *e = copy(); - ((BinExp *)e)->e2 = e2; - e = e->trySemantic(sc); - return e; - } -#endif - return NULL; -} - -/*********************************** - * Utility to build a function call out of this reference and argument. - */ - -Expression *build_overload(Loc loc, Scope *sc, Expression *ethis, Expression *earg, - Dsymbol *d) -{ - assert(d); - Expression *e; - - //printf("build_overload(id = '%s')\n", id->toChars()); - //earg->print(); - //earg->type->print(); - Declaration *decl = d->isDeclaration(); - if (decl) - e = new DotVarExp(loc, ethis, decl, 0); - else - e = new DotIdExp(loc, ethis, d->ident); - e = new CallExp(loc, e, earg); - - e = e->semantic(sc); - return e; -} - -/*************************************** - * Search for function funcid in aggregate ad. - */ - -Dsymbol *search_function(ScopeDsymbol *ad, Identifier *funcid) -{ - Dsymbol *s; - FuncDeclaration *fd; - TemplateDeclaration *td; - - s = ad->search(0, funcid, 0); - if (s) - { Dsymbol *s2; - - //printf("search_function: s = '%s'\n", s->kind()); - s2 = s->toAlias(); - //printf("search_function: s2 = '%s'\n", s2->kind()); - fd = s2->isFuncDeclaration(); - if (fd && fd->type->ty == Tfunction) - return fd; - - td = s2->isTemplateDeclaration(); - if (td) - return td; - } - return NULL; -} - - -int ForeachStatement::inferAggregate(Scope *sc, Dsymbol *&sapply) -{ - Identifier *idapply = (op == TOKforeach) ? Id::apply : Id::applyReverse; -#if DMDV2 - Identifier *idhead = (op == TOKforeach) ? Id::Ffront : Id::Fback; - int sliced = 0; -#endif - Type *tab; - AggregateDeclaration *ad; - - while (1) - { - aggr = aggr->semantic(sc); - aggr = resolveProperties(sc, aggr); - aggr = aggr->optimize(WANTvalue); - if (!aggr->type) - goto Lerr; - - tab = aggr->type->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - case Taarray: - break; - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: -#if DMDV2 - if (!sliced) - { - sapply = search_function(ad, idapply); - if (sapply) - { // opApply aggregate - break; - } - - Dsymbol *s = search_function(ad, Id::slice); - if (s) - { Expression *rinit = new SliceExp(aggr->loc, aggr, NULL, NULL); - rinit = rinit->trySemantic(sc); - if (rinit) // if application of [] succeeded - { aggr = rinit; - sliced = 1; - continue; - } - } - } - - if (Dsymbol *shead = search_function(ad, idhead)) - { // range aggregate - break; - } - - if (ad->aliasthis) - { - aggr = new DotIdExp(aggr->loc, aggr, ad->aliasthis->ident); - continue; - } -#else - sapply = search_function(ad, idapply); - if (sapply) - { // opApply aggregate - break; - } -#endif - goto Lerr; - - case Tdelegate: - if (aggr->op == TOKdelegate) - { DelegateExp *de = (DelegateExp *)aggr; - sapply = de->func->isFuncDeclaration(); - } - break; - - case Terror: - break; - - default: - goto Lerr; - } - break; - } - return 1; - -Lerr: - return 0; -} - -/***************************************** - * Given array of arguments and an aggregate type, - * if any of the argument types are missing, attempt to infer - * them from the aggregate type. - */ - -int ForeachStatement::inferApplyArgTypes(Scope *sc, Dsymbol *&sapply) -{ - if (!arguments || !arguments->dim) - return 0; - - if (sapply) // prefer opApply - { - for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; - if (arg->type) - arg->type = arg->type->semantic(loc, sc); - } - - Expression *ethis; - Type *tab = aggr->type->toBasetype(); - if (tab->ty == Tclass || tab->ty == Tstruct) - ethis = aggr; - else - { assert(tab->ty == Tdelegate && aggr->op == TOKdelegate); - ethis = ((DelegateExp *)aggr)->e1; - } - - /* Look for like an - * int opApply(int delegate(ref Type [, ...]) dg); - * overload - */ - FuncDeclaration *fd = sapply->isFuncDeclaration(); - if (fd) - { sapply = inferApplyArgTypesX(ethis, fd, arguments); - } -#if 0 - TemplateDeclaration *td = sapply->isTemplateDeclaration(); - if (td) - { inferApplyArgTypesZ(td, arguments); - } -#endif - return sapply ? 1 : 0; - } - - /* Return if no arguments need types. - */ - for (size_t u = 0; u < arguments->dim; u++) - { Parameter *arg = arguments->tdata()[u]; - if (!arg->type) - break; - } - - AggregateDeclaration *ad; - - Parameter *arg = arguments->tdata()[0]; - Type *taggr = aggr->type; - assert(taggr); - Type *tab = taggr->toBasetype(); - switch (tab->ty) - { - case Tarray: - case Tsarray: - case Ttuple: - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = Type::tsize_t; // key type - arg = arguments->tdata()[1]; - } - if (!arg->type && tab->ty != Ttuple) - arg->type = tab->nextOf(); // value type - break; - - case Taarray: - { TypeAArray *taa = (TypeAArray *)tab; - - if (arguments->dim == 2) - { - if (!arg->type) - arg->type = taa->index; // key type - arg = arguments->tdata()[1]; - } - if (!arg->type) - arg->type = taa->next; // value type - break; - } - - case Tclass: - ad = ((TypeClass *)tab)->sym; - goto Laggr; - - case Tstruct: - ad = ((TypeStruct *)tab)->sym; - goto Laggr; - - Laggr: - if (arguments->dim == 1) - { - if (!arg->type) - { - /* Look for a head() or rear() overload - */ - Identifier *id = (op == TOKforeach) ? Id::Ffront : Id::Fback; - Dsymbol *s = search_function(ad, id); - FuncDeclaration *fd = s ? s->isFuncDeclaration() : NULL; - if (!fd) - { if (s && s->isTemplateDeclaration()) - break; - break; - } - // Resolve inout qualifier of front type - arg->type = fd->type->nextOf(); - if (arg->type) - arg->type = arg->type->substWildTo(tab->mod); - } - break; - } - break; - - case Tdelegate: - { - if (!inferApplyArgTypesY((TypeFunction *)tab->nextOf(), arguments)) - return 0; - break; - } - - default: - break; // ignore error, caught later - } - return 1; -} - -static Dsymbol *inferApplyArgTypesX(Expression *ethis, FuncDeclaration *fstart, Parameters *arguments) -{ - struct Param3 - { - Parameters *arguments; - int mod; - MATCH match; - FuncDeclaration *fd_best; - FuncDeclaration *fd_ambig; - - static int fp(void *param, FuncDeclaration *f) - { - Param3 *p = (Param3 *)param; - TypeFunction *tf = (TypeFunction *)f->type; - MATCH m = MATCHexact; - - if (f->isThis()) - { if (!MODimplicitConv(p->mod, tf->mod)) - m = MATCHnomatch; - else if (p->mod != tf->mod) - m = MATCHconst; - } - if (!inferApplyArgTypesY(tf, p->arguments, 1)) - m = MATCHnomatch; - - if (m > p->match) - { p->fd_best = f; - p->fd_ambig = NULL; - p->match = m; - } - else if (m == p->match) - p->fd_ambig = f; - return 0; - } - }; - - Param3 p; - p.arguments = arguments; - p.mod = ethis->type->mod; - p.match = MATCHnomatch; - p.fd_best = NULL; - p.fd_ambig = NULL; - overloadApply(fstart, &Param3::fp, &p); - if (p.fd_best) - { - inferApplyArgTypesY((TypeFunction *)p.fd_best->type, arguments); - if (p.fd_ambig) - { ::error(ethis->loc, "%s.%s matches more than one declaration:\n\t%s(%d):%s\nand:\n\t%s(%d):%s", - ethis->toChars(), fstart->ident->toChars(), - p.fd_best ->loc.filename, p.fd_best ->loc.linnum, p.fd_best ->type->toChars(), - p.fd_ambig->loc.filename, p.fd_ambig->loc.linnum, p.fd_ambig->type->toChars()); - p.fd_best = NULL; - } - } - return p.fd_best; -} - -/****************************** - * Infer arguments from type of function. - * Returns: - * 1 match for this function - * 0 no match for this function - */ - -static int inferApplyArgTypesY(TypeFunction *tf, Parameters *arguments, int flags) -{ size_t nparams; - Parameter *p; - - if (Parameter::dim(tf->parameters) != 1) - goto Lnomatch; - p = Parameter::getNth(tf->parameters, 0); - if (p->type->ty != Tdelegate) - goto Lnomatch; - tf = (TypeFunction *)p->type->nextOf(); - assert(tf->ty == Tfunction); - - /* We now have tf, the type of the delegate. Match it against - * the arguments, filling in missing argument types. - */ - nparams = Parameter::dim(tf->parameters); - if (nparams == 0 || tf->varargs) - goto Lnomatch; // not enough parameters - if (arguments->dim != nparams) - goto Lnomatch; // not enough parameters - - for (size_t u = 0; u < nparams; u++) - { - Parameter *arg = arguments->tdata()[u]; - Parameter *param = Parameter::getNth(tf->parameters, u); - if (arg->type) - { if (!arg->type->equals(param->type)) - goto Lnomatch; - } - else if (!flags) - arg->type = param->type; - } - Lmatch: - return 1; - - Lnomatch: - return 0; -} - -/******************************************* - * Infer foreach arg types from a template function opApply which looks like: - * int opApply(alias int func(ref uint))() { ... } - */ - -#if 0 -void inferApplyArgTypesZ(TemplateDeclaration *tstart, Parameters *arguments) -{ - for (TemplateDeclaration *td = tstart; td; td = td->overnext) - { - if (!td->scope) - { - error("forward reference to template %s", td->toChars()); - return; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - return; - } - if (!td->parameters || td->parameters->dim != 1) - continue; - TemplateParameter *tp = td->parameters->tdata()[0]; - TemplateAliasParameter *tap = tp->isTemplateAliasParameter(); - if (!tap || !tap->specType || tap->specType->ty != Tfunction) - continue; - TypeFunction *tf = (TypeFunction *)tap->specType; - if (inferApplyArgTypesY(tf, arguments) == 0) // found it - return; - } -} -#endif - -/************************************** - */ - -static void templateResolve(Match *m, TemplateDeclaration *td, Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *arguments) -{ - FuncDeclaration *fd; - - assert(td); - fd = td->deduceFunctionTemplate(sc, loc, targsi, ethis, arguments, 1); - if (!fd) - return; - m->anyf = fd; - if (m->last >= MATCHexact) - { - m->nextf = fd; - m->count++; - } - else - { - m->last = MATCHexact; - m->lastf = fd; - m->count = 1; - } -} - diff --git a/dmd2/optimize.c b/dmd2/optimize.c deleted file mode 100644 index 82bfe9c1..00000000 --- a/dmd2/optimize.c +++ /dev/null @@ -1,1219 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if __DMC__ -#include -#endif - -#include "lexer.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "aggregate.h" -#include "init.h" - - -#ifdef IN_GCC -#include "d-gcc-real.h" - -/* %% fix? */ -extern "C" bool real_isnan (const real_t *); -#endif - -static real_t zero; // work around DMC bug for now - - -/************************************* - * If variable has a const initializer, - * return that initializer. - */ - -Expression *expandVar(int result, VarDeclaration *v) -{ - //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null"); - - Expression *e = NULL; - if (!v) - return e; - if (!v->originalType && v->scope) // semantic() not yet run - v->semantic (v->scope); - - if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) - { - if (!v->type) - { - //error("ICE"); - return e; - } - Type *tb = v->type->toBasetype(); - if (result & WANTinterpret || - v->storage_class & STCmanifest || - v->type->toBasetype()->isscalar() || - ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)) - ) - { - if (v->init) - { - if (v->inuse) - { if (v->storage_class & STCmanifest) - v->error("recursive initialization of constant"); - goto L1; - } - Expression *ei = v->init->toExpression(); - if (!ei) - { if (v->storage_class & STCmanifest) - v->error("enum cannot be initialized with %s", v->init->toChars()); - goto L1; - } - if (ei->op == TOKconstruct || ei->op == TOKblit) - { AssignExp *ae = (AssignExp *)ei; - ei = ae->e2; - if (result & WANTinterpret) - { - v->inuse++; - ei = ei->optimize(result); - v->inuse--; - } - else if (ei->isConst() != 1 && ei->op != TOKstring) - goto L1; - - if (ei->type == v->type) - { // const variable initialized with const expression - } - else if (ei->implicitConvTo(v->type) >= MATCHconst) - { // const var initialized with non-const expression - ei = ei->implicitCastTo(0, v->type); - ei = ei->semantic(0); - } - else - goto L1; - } - if (v->scope) - { - v->inuse++; - e = ei->syntaxCopy(); - e = e->semantic(v->scope); - e = e->implicitCastTo(v->scope, v->type); - // enabling this line causes test22 in test suite to fail - //ei->type = e->type; - v->scope = NULL; - v->inuse--; - } - else if (!ei->type) - { - goto L1; - } - else - // Should remove the copy() operation by - // making all mods to expressions copy-on-write - e = ei->copy(); - } - else - { -#if 1 - goto L1; -#else - // BUG: what if const is initialized in constructor? - e = v->type->defaultInit(); - e->loc = e1->loc; -#endif - } - if (e->type != v->type) - { - e = e->castTo(NULL, v->type); - } - v->inuse++; - e = e->optimize(result); - v->inuse--; - } - } -L1: - //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars()); - return e; -} - - -Expression *fromConstInitializer(int result, Expression *e1) -{ - //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); - //static int xx; if (xx++ == 10) assert(0); - Expression *e = e1; - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - int fwdref = (v && !v->originalType && v->scope); - e = expandVar(result, v); - if (e) - { - // If it is a comma expression involving a declaration, we mustn't - // perform a copy -- we'd get two declarations of the same variable. - // See bugzilla 4465. - if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration) - e = e1; - else - - if (e->type != e1->type && e1->type && e1->type->ty != Tident) - { // Type 'paint' operation - e = e->copy(); - e->type = e1->type; - } - e->loc = e1->loc; - } - else - { - e = e1; - /* If we needed to interpret, generate an error. - * Don't give an error if it's a template parameter - */ - if (v && (result & WANTinterpret) && - !(v->storage_class & STCtemplateparameter)) - { - e1->error("variable %s cannot be read at compile time", v->toChars()); - } - } - } - return e; -} - - -Expression *Expression::optimize(int result) -{ - //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); - return this; -} - -Expression *VarExp::optimize(int result) -{ - return fromConstInitializer(result, this); -} - -Expression *TupleExp::optimize(int result) -{ - for (size_t i = 0; i < exps->dim; i++) - { Expression *e = exps->tdata()[i]; - - e = e->optimize(WANTvalue | (result & WANTinterpret)); - exps->tdata()[i] = e; - } - return this; -} - -Expression *ArrayLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; - } - } - return this; -} - -Expression *AssocArrayLiteralExp::optimize(int result) -{ - assert(keys->dim == values->dim); - for (size_t i = 0; i < keys->dim; i++) - { Expression *e = keys->tdata()[i]; - - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - keys->tdata()[i] = e; - - e = values->tdata()[i]; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - values->tdata()[i] = e; - } - return this; -} - -Expression *StructLiteralExp::optimize(int result) -{ - if (elements) - { - for (size_t i = 0; i < elements->dim; i++) - { Expression *e = elements->tdata()[i]; - if (!e) - continue; - e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); - elements->tdata()[i] = e; - } - } - return this; -} - -Expression *TypeExp::optimize(int result) -{ - return this; -} - -Expression *UnaExp::optimize(int result) -{ - //printf("UnaExp::optimize() %s\n", toChars()); - 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()); - // LDC never try to interpret: it could change the semantics by turning - // const p = &s; into an something like const p = &(Struct()); - - /* Rewrite &(a,b) as (a,&b) - */ - if (e1->op == TOKcomma) - { CommaExp *ce = (CommaExp *)e1; - AddrExp *ae = new AddrExp(loc, ce->e2); - ae->type = type; - e = new CommaExp(ce->loc, ce->e1, ae); - e->type = type; - return e->optimize(result & ~WANTinterpret); - } - -#if IN_LLVM - if (e1->op == TOKindex) - { - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - dinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); - return this; - } - } - } -#endif - - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (ve->var->storage_class & STCmanifest) - e1 = e1->optimize(result & ~WANTinterpret); - } - else - e1 = e1->optimize(result); - - // Convert &*ex to ex - if (e1->op == TOKstar) - { Expression *ex; - - ex = ((PtrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } -#if !IN_LLVM - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); - se->type = type; - return se; - } - } - if (e1->op == TOKindex) - { // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - dinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - dinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - error("array index %jd is out of bounds [0..%jd]", index, dim); - e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); - e->type = type; - return e; - } - } - } -#endif - return this; -} - -Expression *PtrExp::optimize(int result) -{ - //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - // Convert *&ex to ex - if (e1->op == TOKaddress) - { Expression *e; - Expression *ex; - - ex = ((AddrExp *)e1)->e1; - if (type->equals(ex->type)) - e = ex; - else - { - e = ex->copy(); - e->type = type; - } - return e; - } - // Constant fold *(&structliteral + offset) - if (e1->op == TOKadd) - { - Expression *e; - e = Ptr(type, e1); - if (e != EXP_CANT_INTERPRET) - return e; - } - - if (e1->op == TOKsymoff) - { SymOffExp *se = (SymOffExp *)e1; - VarDeclaration *v = se->var->isVarDeclaration(); - Expression *e = expandVar(result, v); - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - e = sle->getField(type, se->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - return this; -} - -Expression *DotVarExp::optimize(int result) -{ - //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); - e1 = e1->optimize(result); - - Expression *e = e1; - - if (e1->op == TOKvar) - { VarExp *ve = (VarExp *)e1; - VarDeclaration *v = ve->var->isVarDeclaration(); - e = expandVar(result, v); - } - - if (e && e->op == TOKstructliteral) - { StructLiteralExp *sle = (StructLiteralExp *)e; - VarDeclaration *vf = var->isVarDeclaration(); - if (vf) - { - Expression *e = sle->getField(type, vf->offset); - if (e && e != EXP_CANT_INTERPRET) - return e; - } - } - - return this; -} - -Expression *NewExp::optimize(int result) -{ - if (thisexp) - thisexp = thisexp->optimize(WANTvalue); - - // Optimize parameters - if (newargs) - { - for (size_t i = 0; i < newargs->dim; i++) - { Expression *e = newargs->tdata()[i]; - - e = e->optimize(WANTvalue); - newargs->tdata()[i] = e; - } - } - - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; - } - } - if (result & WANTinterpret) - { - error("cannot evaluate %s at compile time", toChars()); - } - return this; -} - -Expression *CallExp::optimize(int result) -{ - //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e = this; - - // Optimize parameters - if (arguments) - { - for (size_t i = 0; i < arguments->dim; i++) - { Expression *e = arguments->tdata()[i]; - - e = e->optimize(WANTvalue); - arguments->tdata()[i] = e; - } - } - - e1 = e1->optimize(result); -#if 1 - if (result & WANTinterpret) - { - Expression *eresult = interpret(NULL); - if (eresult == EXP_CANT_INTERPRET) - return e; - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } -#else - if (e1->op == TOKvar) - { - FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); - if (fd) - { - enum BUILTIN b = fd->isBuiltin(); - if (b) - { - e = eval_builtin(b, arguments); - if (!e) // failed - e = this; // evaluate at runtime - } - else if (result & WANTinterpret) - { - Expression *eresult = fd->interpret(NULL, arguments); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } - } - } - else if (e1->op == TOKdotvar && result & WANTinterpret) - { DotVarExp *dve = (DotVarExp *)e1; - FuncDeclaration *fd = dve->var->isFuncDeclaration(); - if (fd) - { - Expression *eresult = fd->interpret(NULL, arguments, dve->e1); - if (eresult && eresult != EXP_VOID_INTERPRET) - e = eresult; - else - error("cannot evaluate %s at compile time", toChars()); - } - } -#endif - return e; -} - - -Expression *CastExp::optimize(int result) -{ -#if IN_LLVM - if (disableOptimization) - return this; -#endif - //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); - //printf("from %s to %s\n", type->toChars(), to->toChars()); - //printf("from %s\n", type->toChars()); - //printf("e1->type %s\n", e1->type->toChars()); - //printf("type = %p\n", type); - assert(type); - enum TOK op1 = e1->op; -#define X 0 - -#if IN_LLVM - if (type->toBasetype()->ty == Tpointer && - e1->type->toBasetype()->ty == Tsarray) - { - return this; - } -#endif - Expression *e1old = e1; - e1 = e1->optimize(result); - e1 = fromConstInitializer(result, e1); - - if (e1 == e1old && - e1->op == TOKarrayliteral && - type->toBasetype()->ty == Tpointer && - e1->type->toBasetype()->ty != Tsarray) - { - // Casting this will result in the same expression, and - // infinite loop because of Expression::implicitCastTo() - return this; // no change - } - - if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && - (type->ty == Tpointer || type->ty == Tarray) && - e1->type->nextOf()->size() == type->nextOf()->size() - ) - { - Expression *e = e1->castTo(NULL, type); - if (X) printf(" returning1 %s\n", e->toChars()); - return e; - } - - if (e1->op == TOKstructliteral && - e1->type->implicitConvTo(type) >= MATCHconst) - { - e1->type = type; - if (X) printf(" returning2 %s\n", e1->toChars()); - return e1; - } - - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) - return e1->castTo(NULL, to); - if (e1->op == TOKnull && - (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray)) - { - e1->type = type; - if (X) printf(" returning3 %s\n", e1->toChars()); - return e1; - } - - if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom; - ClassDeclaration *cdto; - int offset; - - cdfrom = e1->type->isClassHandle(); - cdto = type->isClassHandle(); - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - e1->type = type; - if (X) printf(" returning4 %s\n", e1->toChars()); - return e1; - } - } - - // We can convert 'head const' to mutable - if (to->constOf()->equals(e1->type->constOf())) - { - e1->type = type; - if (X) printf(" returning5 %s\n", e1->toChars()); - return e1; - } - - Expression *e; - - if (e1->isConst()) - { - if (e1->op == TOKsymoff) - { - if (type->size() == e1->type->size() && - type->toBasetype()->ty != Tsarray) - { - e1->type = type; - return e1; - } - return this; - } - if (to->toBasetype()->ty == Tvoid) - e = this; - else - e = Cast(type, to, e1); - } - else - e = this; - if (X) printf(" returning6 %s\n", e->toChars()); - return e; -#undef X -} - -Expression *BinExp::optimize(int result) -{ - //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); - if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (op == TOKshlass || op == TOKshrass || op == TOKushrass) - { - if (e2->isConst() == 1) - { - dinteger_t i2 = e2->toInteger(); - d_uns64 sz = e1->type->size() * 8; - if (i2 < 0 || i2 >= sz) - { error("shift assign by %jd is outside the range 0..%zu", i2, sz - 1); - e2 = new IntegerExp(0); - } - } - } - return this; -} - -Expression *AddExp::optimize(int result) -{ Expression *e; - - //printf("AddExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e1->op == TOKsymoff && e2->op == TOKsymoff) - return this; - e = Add(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MinExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() && e2->isConst()) - { - if (e2->op == TOKsymoff) - return this; - e = Min(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *MulExp::optimize(int result) -{ Expression *e; - - //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mul(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *DivExp::optimize(int result) -{ Expression *e; - - //printf("DivExp::optimize(%s)\n", toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Div(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *ModExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Mod(type, e1, e2); - } - else - e = this; - return e; -} - -Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) -{ Expression *ex = e; - - e->e1 = e->e1->optimize(result); - e->e2 = e->e2->optimize(result); - if (e->e2->isConst() == 1) - { - dinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size() * 8; - if (i2 < 0 || i2 >= sz) - { e->error("shift by %jd is outside the range 0..%zu", i2, sz - 1); - 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 *PowExp::optimize(int result) -{ Expression *e; - - e1 = e1->optimize(result); - e2 = e2->optimize(result); - - // Replace 1 ^^ x or 1.0^^x by (x, 1) - if ((e1->op == TOKint64 && e1->toInteger() == 1) || - (e1->op == TOKfloat64 && e1->toReal() == 1.0)) - { - e = new CommaExp(loc, e2, e1); - } - // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral - else if (e2->type->isintegral() && e1->op == TOKint64 && (sinteger_t)e1->toInteger() == -1L) - { - Type* resultType = type; - e = new AndExp(loc, e2, new IntegerExp(loc, 1, e2->type)); - e = new CondExp(loc, e, new IntegerExp(loc, -1L, resultType), new IntegerExp(loc, 1L, resultType)); - } - // Replace x ^^ 0 or x^^0.0 by (x, 1) - else if ((e2->op == TOKint64 && e2->toInteger() == 0) || - (e2->op == TOKfloat64 && e2->toReal() == 0.0)) - { - if (e1->type->isintegral()) - e = new IntegerExp(loc, 1, e1->type); - else - e = new RealExp(loc, 1.0, e1->type); - - e = new CommaExp(loc, e1, e); - } - // Replace x ^^ 1 or x^^1.0 by (x) - else if ((e2->op == TOKint64 && e2->toInteger() == 1) || - (e2->op == TOKfloat64 && e2->toReal() == 1.0)) - { - e = e1; - } - // Replace x ^^ -1.0 by (1.0 / x) - else if ((e2->op == TOKfloat64 && e2->toReal() == -1.0)) - { - e = new DivExp(loc, new RealExp(loc, 1.0, e2->type), e1); - } - // All other negative integral powers are illegal - else if ((e1->type->isintegral()) && (e2->op == TOKint64) && (sinteger_t)e2->toInteger() < 0) - { - error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?", - e1->type->toBasetype()->toChars(), e1->toChars(), e2->toChars()); - e = new ErrorExp(); - } - else - { - // If e2 *could* have been an integer, make it one. - if (e2->op == TOKfloat64 && (e2->toReal() == (sinteger_t)(e2->toReal()))) - e2 = new IntegerExp(loc, e2->toInteger(), Type::tint64); - - if (e1->isConst() == 1 && e2->isConst() == 1) - { - e = Pow(type, e1, e2); - if (e != EXP_CANT_INTERPRET) - return e; - } - e = this; - } - return e; -} - -Expression *CommaExp::optimize(int result) -{ Expression *e; - - //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); - // Comma needs special treatment, because it may - // contain compiler-generated declarations. We can interpret them, but - // otherwise we must NOT attempt to constant-fold them. - // In particular, if the comma returns a temporary variable, it needs - // to be an lvalue (this is particularly important for struct constructors) - - if (result & WANTinterpret) - { // Interpreting comma needs special treatment, because it may - // contain compiler-generated declarations. - e = interpret(NULL); - return (e == EXP_CANT_INTERPRET) ? this : e; - } - - e1 = e1->optimize(result & WANTinterpret); - e2 = e2->optimize(result); - if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->hasSideEffect()) - { - 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 | WANTexpand | (result & WANTinterpret)); - e = this; - if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) - { - e = ArrayLength(type, e1); - } - return e; -} - -Expression *EqualExp::optimize(int result) -{ Expression *e; - - //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - e = this; - - Expression *e1 = fromConstInitializer(result, this->e1); - Expression *e2 = fromConstInitializer(result, this->e2); - - e = Equal(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *IdentityExp::optimize(int result) -{ - //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - Expression *e = this; - - if ((this->e1->isConst() && this->e2->isConst()) || - (this->e1->op == TOKnull && this->e2->op == TOKnull)) - { - e = Identity(op, type, this->e1, this->e2); - if (e == EXP_CANT_INTERPRET) - e = this; - } - return e; -} - -/* It is possible for constant folding to change an array expression of - * unknown length, into one where the length is known. - * If the expression 'arr' is a literal, set lengthVar to be its length. - */ -void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) -{ - if (!lengthVar) - return; - if (lengthVar->init && !lengthVar->init->isVoidInitializer()) - return; // we have previously calculated the length - size_t len; - if (arr->op == TOKstring) - len = ((StringExp *)arr)->len; - else if (arr->op == TOKarrayliteral) - len = ((ArrayLiteralExp *)arr)->elements->dim; - else - return; // we don't know the length yet - - Expression *dollar = new IntegerExp(0, len, Type::tsize_t); - lengthVar->init = new ExpInitializer(0, dollar); - lengthVar->storage_class |= STCstatic | STCconst; -} - - -Expression *IndexExp::optimize(int result) -{ Expression *e; - - //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); - Expression *e1 = this->e1->optimize( - WANTvalue | (result & (WANTinterpret| WANTexpand))); - e1 = fromConstInitializer(result, e1); - if (this->e1->op == TOKvar) - { VarExp *ve = (VarExp *)this->e1; - if (ve->var->storage_class & STCmanifest) - { /* We generally don't want to have more than one copy of an - * array literal, but if it's an enum we have to because the - * enum isn't stored elsewhere. See Bugzilla 2559 - */ - this->e1 = e1; - } - } - // We might know $ now - setLengthVarIfKnown(lengthVar, 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|WANTexpand))); - if (!lwr) - { if (e1->op == TOKstring) - { // Convert slice of string literal into dynamic array - Type *t = e1->type->toBasetype(); - if (t->nextOf()) - e = e1->castTo(NULL, t->nextOf()->arrayOf()); - } - return e; - } - e1 = fromConstInitializer(result, e1); - // We might know $ now - setLengthVarIfKnown(lengthVar, e1); - lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); - upr = upr->optimize(WANTvalue | (result & WANTinterpret)); - e = Slice(type, e1, lwr, upr); - if (e == EXP_CANT_INTERPRET) - e = this; - //printf("-SliceExp::optimize() %s\n", e->toChars()); - return e; -} - -Expression *AndAndExp::optimize(int result) -{ Expression *e; - - //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(WANTflags | (result & WANTinterpret)); - e = this; - if (e1->isBool(FALSE)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else - { 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)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else 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)) - { - if (type->toBasetype()->ty == Tvoid) - e = e2; - else - e = new BoolExp(loc, e2, type); - } - } - } - return e; -} - -Expression *CmpExp::optimize(int result) -{ Expression *e; - - //printf("CmpExp::optimize() %s\n", toChars()); - e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); - e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); - - Expression *e1 = fromConstInitializer(result, this->e1); - Expression *e2 = fromConstInitializer(result, this->e2); - - e = Cmp(op, type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - -Expression *CatExp::optimize(int result) -{ Expression *e; - - //printf("CatExp::optimize(%d) %s\n", result, toChars()); - e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = Cat(type, e1, e2); - if (e == EXP_CANT_INTERPRET) - e = this; - return e; -} - - -Expression *CondExp::optimize(int result) -{ Expression *e; - - econd = econd->optimize(WANTflags | (result & WANTinterpret)); - if (econd->isBool(TRUE)) - e = e1->optimize(result); - else if (econd->isBool(FALSE)) - e = e2->optimize(result); - else - { e1 = e1->optimize(result); - e2 = e2->optimize(result); - e = this; - } - return e; -} - - diff --git a/dmd2/parse.c b/dmd2/parse.c deleted file mode 100644 index 17ae1df5..00000000 --- a/dmd2/parse.c +++ /dev/null @@ -1,6709 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// This is the D parser - -#include -#include - -#include "rmem.h" -#include "lexer.h" -#include "parse.h" -#include "init.h" -#include "attrib.h" -#include "cond.h" -#include "mtype.h" -#include "template.h" -#include "staticassert.h" -#include "expression.h" -#include "statement.h" -#include "module.h" -#include "dsymbol.h" -#include "import.h" -#include "declaration.h" -#include "aggregate.h" -#include "enum.h" -#include "id.h" -#include "version.h" -#include "aliasthis.h" - -// How multiple declarations are parsed. -// If 1, treat as C. -// If 0, treat: -// int *p, i; -// as: -// int* p; -// int* i; -#define CDECLSYNTAX 0 - -// Support C cast syntax: -// (type)(expression) -#define CCASTSYNTAX 1 - -// Support postfix C array declarations, such as -// int a[3][4]; -#define CARRAYDECL 1 - -// Support D1 inout -#define D1INOUT 0 - -Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment) - : Lexer(module, base, 0, length, doDocComment, 0) -{ - //printf("Parser::Parser()\n"); - md = NULL; - linkage = LINKd; - endloc = 0; - inBrackets = 0; - lookingForElse = 0; - //nextToken(); // start up the scanner -} - -Dsymbols *Parser::parseModule() -{ - Dsymbols *decldefs; - - // ModuleDeclation leads off - if (token.value == TOKmodule) - { - unsigned char *comment = token.blockComment; - bool safe = FALSE; - - nextToken(); -#if 0 && DMDV2 - if (token.value == TOKlparen) - { - nextToken(); - if (token.value != TOKidentifier) - { error("module (system) identifier expected"); - goto Lerr; - } - Identifier *id = token.ident; - - if (id == Id::system) - safe = TRUE; - else - error("(safe) expected, not %s", id->toChars()); - nextToken(); - check(TOKrparen); - } -#endif - - if (token.value != TOKidentifier) - { error("Identifier expected following module"); - goto Lerr; - } - else - { - Identifiers *a = NULL; - Identifier *id; - - id = token.ident; - while (nextToken() == TOKdot) - { - if (!a) - a = new Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following package"); - goto Lerr; - } - id = token.ident; - } - - md = new ModuleDeclaration(a, id, safe); - - if (token.value != TOKsemicolon) - error("';' expected following module declaration instead of %s", token.toChars()); - nextToken(); - addComment(mod, comment); - } - } - - decldefs = parseDeclDefs(0); - if (token.value != TOKeof) - { error("unrecognized declaration"); - goto Lerr; - } - return decldefs; - -Lerr: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - return new Dsymbols(); -} - -Dsymbols *Parser::parseDeclDefs(int once) -{ Dsymbol *s; - Dsymbols *decldefs; - Dsymbols *a; - Dsymbols *aelse; - enum PROT prot; - StorageClass stc; - StorageClass storageClass; - Condition *condition; - unsigned char *comment; - - //printf("Parser::parseDeclDefs()\n"); - decldefs = new Dsymbols(); - do - { - comment = token.blockComment; - storageClass = STCundefined; - switch (token.value) - { - case TOKenum: - { /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - s = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - s = parseEnum(); - else - goto Ldeclaration; - } - break; - } - - case TOKstruct: - case TOKunion: - case TOKclass: - case TOKinterface: - s = parseAggregate(); - break; - - case TOKimport: - s = parseImport(decldefs, 0); - break; - - case TOKtemplate: - s = (Dsymbol *)parseTemplateDeclaration(0); - break; - - case TOKmixin: - { Loc loc = this->loc; - switch (peekNext()) - { - case TOKlparen: - { // mixin(string) - nextToken(); - check(TOKlparen, "mixin"); - Expression *e = parseAssignExp(); - check(TOKrparen); - check(TOKsemicolon); - s = new CompileDeclaration(loc, e); - break; - } - case TOKtemplate: - // mixin template - nextToken(); - s = (Dsymbol *)parseTemplateDeclaration(1); - break; - - default: - s = parseMixin(); - break; - } - break; - } - - case BASIC_TYPES: - case TOKalias: - case TOKtypedef: - case TOKidentifier: - case TOKsuper: - case TOKtypeof: - case TOKdot: - case TOKvector: - Ldeclaration: - a = parseDeclarations(STCundefined, NULL); - decldefs->append(a); - continue; - - case TOKthis: - if (peekNext() == TOKdot) - goto Ldeclaration; - else - s = parseCtor(); - break; - -#if 0 // dead end, use this(this){} instead - case TOKassign: - s = parsePostBlit(); - break; -#endif - case TOKtilde: - s = parseDtor(); - break; - - case TOKinvariant: - { Token *t; - t = peek(&token); - if (t->value == TOKlparen) - { - if (peek(t)->value == TOKrparen) - // invariant() forms start of class invariant - s = parseInvariant(); - else - // invariant(type) - goto Ldeclaration; - } - else - { - if (!global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - stc = STCimmutable; - goto Lstc; - } - break; - } - - case TOKunittest: - s = parseUnitTest(); - break; - - case TOKnew: - s = parseNew(); - break; - - case TOKdelete: - s = parseDelete(); - break; - - case TOKeof: - case TOKrcurly: - return decldefs; - - case TOKstatic: - nextToken(); - if (token.value == TOKthis) - s = parseStaticCtor(); - else if (token.value == TOKtilde) - s = parseStaticDtor(); - else if (token.value == TOKassert) - s = parseStaticAssert(); - else if (token.value == TOKif) - { condition = parseStaticIfCondition(); - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - a = parseBlock(); - lookingForElse = lookingForElseSave; - aelse = NULL; - if (token.value == TOKelse) - { - Loc elseloc = this->loc; - nextToken(); - aelse = parseBlock(); - checkDanglingElse(elseloc); - } - s = new StaticIfDeclaration(condition, a, aelse); - break; - } - else if (token.value == TOKimport) - { - s = parseImport(decldefs, 1); - } - else - { stc = STCstatic; - goto Lstc2; - } - break; - - case TOKconst: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCconst; - goto Lstc; - - case TOKimmutable: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCimmutable; - goto Lstc; - - case TOKshared: - { TOK next = peekNext(); - if (next == TOKlparen) - goto Ldeclaration; - if (next == TOKstatic) - { TOK next2 = peekNext2(); - if (next2 == TOKthis) - { s = parseSharedStaticCtor(); - break; - } - if (next2 == TOKtilde) - { s = parseSharedStaticDtor(); - break; - } - } - stc = STCshared; - goto Lstc; - } - - case TOKwild: - if (peekNext() == TOKlparen) - goto Ldeclaration; - stc = STCwild; - goto Lstc; - - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; - case TOKat: stc = parseAttribute(); goto Lstc; -#endif - - Lstc: - if (storageClass & stc) - error("redundant storage class %s", Token::toChars(token.value)); - composeStorageClass(storageClass | stc); - nextToken(); - Lstc2: - storageClass |= stc; - switch (token.value) - { - case TOKshared: - // Look for "shared static this" or "shared static ~this" - if (peekNext() == TOKstatic) - { TOK next2 = peekNext2(); - if (next2 == TOKthis || next2 == TOKtilde) - break; - } - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKwild: - // If followed by a (, it is not a storage class - if (peek(&token)->value == TOKlparen) - break; - if (token.value == TOKconst) - stc = STCconst; - else if (token.value == TOKshared) - stc = STCshared; - else if (token.value == TOKwild) - stc = STCwild; - else - { - if (token.value == TOKinvariant && !global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - stc = STCimmutable; - } - goto Lstc; - case TOKfinal: stc = STCfinal; goto Lstc; - case TOKauto: stc = STCauto; goto Lstc; - case TOKscope: stc = STCscope; goto Lstc; - case TOKoverride: stc = STCoverride; goto Lstc; - case TOKabstract: stc = STCabstract; goto Lstc; - case TOKsynchronized: stc = STCsynchronized; goto Lstc; - case TOKdeprecated: stc = STCdeprecated; goto Lstc; - case TOKnothrow: stc = STCnothrow; goto Lstc; - case TOKpure: stc = STCpure; goto Lstc; - case TOKref: stc = STCref; goto Lstc; - case TOKtls: stc = STCtls; goto Lstc; - case TOKgshared: stc = STCgshared; goto Lstc; - //case TOKmanifest: stc = STCmanifest; goto Lstc; - case TOKat: stc = parseAttribute(); goto Lstc; - default: - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - a = parseAutoDeclarations(storageClass, comment); - decldefs->append(a); - continue; - } - - /* Look for return type inference for template functions. - */ - Token *tk; - if (token.value == TOKidentifier && - (tk = peek(&token))->value == TOKlparen && - skipParens(tk, &tk) && - ((tk = peek(tk)), 1) && - skipAttributes(tk, &tk) && - (tk->value == TOKlparen || - tk->value == TOKlcurly) - ) - { - a = parseDeclarations(storageClass, comment); - decldefs->append(a); - continue; - } - a = parseBlock(); - s = new StorageClassDeclaration(storageClass, a); - break; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto Lstc; - } - { - enum LINK linksave = linkage; - linkage = parseLinkage(); - a = parseBlock(); - s = new LinkDeclaration(linkage, a); - linkage = linksave; - break; - } - case TOKprivate: prot = PROTprivate; goto Lprot; - case TOKpackage: prot = PROTpackage; goto Lprot; - case TOKprotected: prot = PROTprotected; goto Lprot; - case TOKpublic: prot = PROTpublic; goto Lprot; - case TOKexport: prot = PROTexport; goto Lprot; - - Lprot: - nextToken(); - switch (token.value) - { - case TOKprivate: - case TOKpackage: - case TOKprotected: - case TOKpublic: - case TOKexport: - error("redundant protection attribute"); - break; - } - a = parseBlock(); - s = new ProtDeclaration(prot, a); - break; - - case TOKalign: - { unsigned n; - - // LDC better align code locations - Loc alignloc = loc; - - s = NULL; - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - if (token.value == TOKint32v && token.uns64value > 0) - n = (unsigned)token.uns64value; - else - { error("positive integer expected, not %s", token.toChars()); - n = 1; - } - nextToken(); - check(TOKrparen); - } - else - n = global.structalign; // default - - a = parseBlock(); - s = new AlignDeclaration(alignloc, n, a); - break; - } - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...) - else - check(TOKrparen); // pragma(identifier) - - if (token.value == TOKsemicolon) - a = NULL; - else - a = parseBlock(); - s = new PragmaDeclaration(loc, ident, args, a); - break; - } - - case TOKdebug: - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value == TOKidentifier) - s = new DebugSymbol(loc, token.ident); - else if (token.value == TOKint32v || token.value == TOKint64v) - 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 || token.value == TOKint64v) - 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: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - a = parseBlock(); - lookingForElse = lookingForElseSave; - } - aelse = NULL; - if (token.value == TOKelse) - { - Loc elseloc = this->loc; - nextToken(); - aelse = parseBlock(); - checkDanglingElse(elseloc); - } - s = new ConditionalDeclaration(condition, a, aelse); - break; - - case TOKsemicolon: // empty declaration - //error("empty declaration"); - nextToken(); - continue; - - default: - error("Declaration expected, not '%s'",token.toChars()); - Lerror: - while (token.value != TOKsemicolon && token.value != TOKeof) - nextToken(); - nextToken(); - s = NULL; - continue; - } - if (s) - { decldefs->push(s); - addComment(s, comment); - } - } while (!once); - return decldefs; -} - -/********************************************* - * Give error on conflicting storage classes. - */ - -#if DMDV2 -void Parser::composeStorageClass(StorageClass stc) -{ - StorageClass u = stc; - u &= STCconst | STCimmutable | STCmanifest; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCgshared | STCshared | STCtls; - if (u & (u - 1)) - error("conflicting storage class %s", Token::toChars(token.value)); - u = stc; - u &= STCsafe | STCsystem | STCtrusted; - if (u & (u - 1)) - error("conflicting attribute @%s", token.toChars()); -} -#endif - -/*********************************************** - * Parse storage class, lexer is on '@' - */ - -#if DMDV2 -StorageClass Parser::parseAttribute() -{ - nextToken(); - StorageClass stc = 0; - if (token.value != TOKidentifier) - { - error("identifier expected after @, not %s", token.toChars()); - } - else if (token.ident == Id::property) - stc = STCproperty; - else if (token.ident == Id::safe) - stc = STCsafe; - else if (token.ident == Id::trusted) - stc = STCtrusted; - else if (token.ident == Id::system) - stc = STCsystem; - else if (token.ident == Id::disable) - stc = STCdisable; - else - error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars()); - return stc; -} -#endif - -/*********************************************** - * Parse const/immutable/shared/inout/nothrow/pure postfix - */ - -StorageClass Parser::parsePostfix() -{ - StorageClass stc = 0; - - while (1) - { - switch (token.value) - { - case TOKconst: stc |= STCconst; break; - case TOKinvariant: - if (!global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - case TOKimmutable: stc |= STCimmutable; break; - case TOKshared: stc |= STCshared; break; - case TOKwild: stc |= STCwild; break; - case TOKnothrow: stc |= STCnothrow; break; - case TOKpure: stc |= STCpure; break; - case TOKat: stc |= parseAttribute(); break; - - default: return stc; - } - composeStorageClass(stc); - nextToken(); - } -} - -/******************************************** - * Parse declarations after an align, protection, or extern decl. - */ - -Dsymbols *Parser::parseBlock() -{ - Dsymbols *a = NULL; - - //printf("parseBlock()\n"); - switch (token.value) - { - case TOKsemicolon: - error("declaration expected following attribute, not ';'"); - nextToken(); - break; - - case TOKeof: - error("declaration expected following attribute, not EOF"); - break; - - case TOKlcurly: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = 0; - - nextToken(); - a = parseDeclDefs(0); - if (token.value != TOKrcurly) - { /* { */ - error("matching '}' expected, not %s", token.toChars()); - } - else - nextToken(); - lookingForElse = lookingForElseSave; - 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 __vector(type). - * Current token is on the '__vector'. - */ - -#if DMDV2 -Type *Parser::parseVector() -{ - Loc loc = this->loc; - nextToken(); - check(TOKlparen); - Type *tb = parseType(); - check(TOKrparen); - return new TypeVector(loc, tb); -} -#endif - -/*********************************** - * Parse extern (linkage) - * The parser is on the 'extern' token. - */ - -enum LINK Parser::parseLinkage() -{ - enum LINK link = LINKdefault; - nextToken(); - assert(token.value == TOKlparen); - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (id == Id::Windows) - link = LINKwindows; - else if (id == Id::Pascal) - link = LINKpascal; - else if (id == Id::D) - link = LINKd; - else if (id == Id::C) - { - link = LINKc; - if (token.value == TOKplusplus) - { link = LINKcpp; - nextToken(); - } - } - else if (id == Id::System) - { - // LDC we configure target at runtime - if (global.params.os == OSWindows) - link = LINKwindows; - else - link = LINKc; - } - else - { - error("valid linkage identifiers are D, C, C++, Pascal, Windows, System"); - link = LINKd; - } - } - else - { - link = LINKd; // default - } - check(TOKrparen); - return link; -} - -/************************************** - * Parse a debug conditional - */ - -Condition *Parser::parseDebugCondition() -{ - Condition *c; - - if (token.value == TOKlparen) - { - nextToken(); - unsigned level = 1; - Identifier *id = NULL; - - if (token.value == TOKidentifier) - id = token.ident; - else if (token.value == TOKint32v || token.value == TOKint64v) - 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 || token.value == TOKint64v) - 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; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseAssignExp(); - check(TOKrparen); - } - else - { error("(expression) expected following static if"); - exp = NULL; - } - condition = new StaticIfCondition(loc, exp); - return condition; -} - - -/***************************************** - * Parse a constructor definition: - * this(parameters) { body } - * or postblit: - * this(this) { body } - * or constructor template: - * this(templateparameters)(parameters) { body } - * Current token is 'this'. - */ - -Dsymbol *Parser::parseCtor() -{ - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen && peek(&token)->value == TOKthis) - { // this(this) { ... } - nextToken(); - nextToken(); - check(TOKrparen); - StorageClass stc = parsePostfix(); - PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0, stc); - parseContracts(f); - return f; - } - - /* Look ahead to see if: - * this(...)(...) - * which is a constructor template - */ - TemplateParameters *tpl = NULL; - if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen) - { tpl = parseTemplateParameterList(); - - int varargs; - Parameters *parameters = parseParameters(&varargs); - StorageClass stc = parsePostfix(); - - Expression *constraint = tpl ? parseConstraint() : NULL; - - Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto - tf = tf->addSTC(stc); - - CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf); - parseContracts(f); - - // Wrap a template around it - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(f); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs, 0); - return tempdecl; - } - - /* Just a regular constructor - */ - int varargs; - Parameters *parameters = parseParameters(&varargs); - StorageClass stc = parsePostfix(); - Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto - tf = tf->addSTC(stc); - - CtorDeclaration *f = new CtorDeclaration(loc, 0, stc, tf); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a postblit definition: - * =this() { body } - * Current token is '='. - */ - -PostBlitDeclaration *Parser::parsePostBlit() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a destructor definition: - * ~this() { body } - * Current token is '~'. - */ - -DtorDeclaration *Parser::parseDtor() -{ - DtorDeclaration *f; - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - f = new DtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static constructor definition: - * static this() { body } - * Current token is 'this'. - */ - -StaticCtorDeclaration *Parser::parseStaticCtor() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKlparen); - check(TOKrparen); - - StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a shared static constructor definition: - * shared static this() { body } - * Current token is 'shared'. - */ - -SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKlparen); - check(TOKrparen); - - SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a static destructor definition: - * static ~this() { body } - * Current token is '~'. - */ - -StaticDtorDeclaration *Parser::parseStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a shared static destructor definition: - * shared static ~this() { body } - * Current token is 'shared'. - */ - -SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor() -{ - Loc loc = this->loc; - - nextToken(); - nextToken(); - nextToken(); - check(TOKthis); - check(TOKlparen); - check(TOKrparen); - - SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0); - parseContracts(f); - return f; -} - -/***************************************** - * Parse an invariant definition: - * invariant() { body } - * Current token is 'invariant'. - */ - -InvariantDeclaration *Parser::parseInvariant() -{ - InvariantDeclaration *f; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) // optional () - { - nextToken(); - check(TOKrparen); - } - - f = new InvariantDeclaration(loc, 0); - f->fbody = parseStatement(PScurly); - return f; -} - -/***************************************** - * Parse a unittest definition: - * unittest { body } - * Current token is 'unittest'. - */ - -UnitTestDeclaration *Parser::parseUnitTest() -{ - UnitTestDeclaration *f; - Statement *body; - Loc loc = this->loc; - - nextToken(); - - body = parseStatement(PScurly); - - f = new UnitTestDeclaration(loc, this->loc); - f->fbody = body; - return f; -} - -/***************************************** - * Parse a new definition: - * new(arguments) { body } - * Current token is 'new'. - */ - -NewDeclaration *Parser::parseNew() -{ - NewDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - f = new NewDeclaration(loc, 0, arguments, varargs); - parseContracts(f); - return f; -} - -/***************************************** - * Parse a delete definition: - * delete(arguments) { body } - * Current token is 'delete'. - */ - -DeleteDeclaration *Parser::parseDelete() -{ - DeleteDeclaration *f; - Parameters *arguments; - int varargs; - Loc loc = this->loc; - - nextToken(); - arguments = parseParameters(&varargs); - if (varargs) - error("... not allowed in delete function parameter list"); - f = new DeleteDeclaration(loc, 0, arguments); - parseContracts(f); - return f; -} - -/********************************************** - * Parse parameter list. - */ - -Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl) -{ - Parameters *arguments = new Parameters(); - int varargs = 0; - int hasdefault = 0; - - check(TOKlparen); - while (1) - { - Identifier *ai = NULL; - Type *at; - Parameter *a; - StorageClass storageClass = 0; - StorageClass stc; - Expression *ae; - - for (;1; nextToken()) - { - switch (token.value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - varargs = 1; - nextToken(); - break; - - case TOKconst: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCconst; - goto L2; - - case TOKinvariant: - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - if (token.value == TOKinvariant && !global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - stc = STCimmutable; - goto L2; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCshared; - goto L2; - - case TOKwild: - if (peek(&token)->value == TOKlparen) - goto Ldefault; - stc = STCwild; - goto L2; - - case TOKin: stc = STCin; goto L2; - case TOKout: stc = STCout; goto L2; -#if D1INOUT - case TOKinout: -#endif - case TOKref: stc = STCref; goto L2; - case TOKlazy: stc = STClazy; goto L2; - case TOKscope: stc = STCscope; goto L2; - case TOKfinal: stc = STCfinal; goto L2; - case TOKauto: stc = STCauto; goto L2; - L2: - if (storageClass & stc || - (storageClass & STCin && stc & (STCconst | STCscope)) || - (stc & STCin && storageClass & (STCconst | STCscope)) - ) - error("redundant storage class %s", Token::toChars(token.value)); - storageClass |= stc; - composeStorageClass(storageClass); - continue; - -#if 0 - case TOKstatic: stc = STCstatic; goto L2; - case TOKauto: storageClass = STCauto; goto L4; - case TOKalias: storageClass = STCalias; goto L4; - L4: - nextToken(); - if (token.value == TOKidentifier) - { ai = token.ident; - nextToken(); - } - else - ai = NULL; - at = NULL; // no type - ae = NULL; // no default argument - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for alias %s", - ai ? ai->toChars() : ""); - } - goto L3; -#endif - - default: - Ldefault: - { stc = storageClass & (STCin | STCout | STCref | STClazy); - if (stc & (stc - 1)) // if stc is not a power of 2 - error("incompatible parameter storage classes"); - if ((storageClass & (STCconst | STCout)) == (STCconst | STCout)) - error("out cannot be const"); - if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout)) - error("out cannot be immutable"); - if ((storageClass & STCscope) && (storageClass & (STCref | STCout))) - error("scope cannot be ref or out"); - - Token *t; - if (tpl && !stc && token.value == TOKidentifier && - (t = peek(&token), (t->value == TOKcomma || t->value == TOKrparen))) - { Identifier *id = Lexer::uniqueId("__T"); - at = new TypeIdentifier(loc, id); - if (!*tpl) - *tpl = new TemplateParameters(); - TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); - (*tpl)->push(tp); - - ai = token.ident; - nextToken(); - } - else - at = parseType(&ai); - - ae = NULL; - if (token.value == TOKassign) // = defaultArg - { nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { if (hasdefault) - error("default argument expected for %s", - ai ? ai->toChars() : at->toChars()); - } - if (token.value == TOKdotdotdot) - { /* This is: - * at ai ... - */ - - if (storageClass & (STCout | STCref)) - error("variadic argument cannot be out or ref"); - varargs = 2; - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - nextToken(); - break; - } - L3: - a = new Parameter(storageClass, at, ai, ae); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - goto L1; - } - break; - } - } - break; - } - break; - - L1: ; - } - check(TOKrparen); - *pvarargs = varargs; - return arguments; -} - - -/************************************* - */ - -EnumDeclaration *Parser::parseEnum() -{ EnumDeclaration *e; - Identifier *id; - Type *memtype; - Loc loc = this->loc; - - //printf("Parser::parseEnum()\n"); - nextToken(); - if (token.value == TOKidentifier) - { id = token.ident; - nextToken(); - } - else - id = NULL; - - if (token.value == TOKcolon) - { - nextToken(); - memtype = parseBasicType(); - memtype = parseDeclarator(memtype, NULL, NULL); - } - else - memtype = NULL; - - e = new EnumDeclaration(loc, id, memtype); - if (token.value == TOKsemicolon && id) - nextToken(); - else if (token.value == TOKlcurly) - { - //printf("enum definition\n"); - e->members = new Dsymbols(); - nextToken(); - unsigned char *comment = token.blockComment; - while (token.value != TOKrcurly) - { - /* Can take the following forms: - * 1. ident - * 2. ident = value - * 3. type ident = value - */ - - loc = this->loc; - - Type *type = NULL; - Identifier *ident; - Token *tp = peek(&token); - if (token.value == TOKidentifier && - (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly)) - { - ident = token.ident; - type = NULL; - nextToken(); - } - else - { - type = parseType(&ident, NULL); - if (id || memtype) - error("type only allowed if anonymous enum and no enum type"); - } - - Expression *value; - if (token.value == TOKassign) - { - nextToken(); - value = parseAssignExp(); - } - else - { value = NULL; - if (type) - error("if type, there must be an initializer"); - } - - EnumMember *em = new EnumMember(loc, ident, value, type); - e->members->push(em); - - if (token.value == TOKrcurly) - ; - else - { addComment(em, comment); - comment = NULL; - check(TOKcomma); - } - addComment(em, comment); - comment = token.blockComment; - - if (token.value == TOKeof) - { error("premature end of file"); - break; - } - } - nextToken(); - } - else - error("enum declaration is invalid"); - - //printf("-parseEnum() %s\n", e->toChars()); - return e; -} - -/******************************** - * Parse struct, union, interface, class. - */ - -Dsymbol *Parser::parseAggregate() -{ AggregateDeclaration *a = NULL; - int anon = 0; - enum TOK tok; - Identifier *id; - TemplateParameters *tpl = NULL; - Expression *constraint = NULL; - - //printf("Parser::parseAggregate()\n"); - tok = token.value; - nextToken(); - if (token.value != TOKidentifier) - { id = NULL; - } - else - { id = token.ident; - nextToken(); - - if (token.value == TOKlparen) - { // Class template declaration. - - // Gather template parameter list - tpl = parseTemplateParameterList(); - constraint = parseConstraint(); - } - } - - Loc loc = this->loc; - switch (tok) - { case TOKclass: - case TOKinterface: - { - if (!id) - error("anonymous classes not allowed"); - - // Collect base class(es) - BaseClasses *baseclasses = NULL; - if (token.value == TOKcolon) - { - nextToken(); - baseclasses = parseBaseClasses(); - - if (token.value != TOKlcurly) - error("members expected"); - } - - if (tok == TOKclass) - a = new ClassDeclaration(loc, id, baseclasses); - else - a = new InterfaceDeclaration(loc, id, baseclasses); - break; - } - - case TOKstruct: - if (id) - a = new StructDeclaration(loc, id); - else - anon = 1; - break; - - case TOKunion: - if (id) - a = new UnionDeclaration(loc, id); - else - anon = 2; - break; - - default: - assert(0); - break; - } - if (a && token.value == TOKsemicolon) - { nextToken(); - } - else if (token.value == TOKlcurly) - { - //printf("aggregate definition\n"); - nextToken(); - Dsymbols *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("} expected following member declarations in aggregate"); - nextToken(); - if (anon) - { - /* Anonymous structs/unions are more like attributes. - */ - return new AnonDeclaration(loc, anon - 1, decl); - } - else - a->members = decl; - } - else - { - error("{ } expected following aggregate declaration"); - a = new StructDeclaration(loc, NULL); - } - - if (tpl) - { // Wrap a template around the aggregate declaration - - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(a); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, id, tpl, constraint, decldefs, 0); - return tempdecl; - } - - return a; -} - -/******************************************* - */ - -BaseClasses *Parser::parseBaseClasses() -{ - BaseClasses *baseclasses = new BaseClasses(); - - for (; 1; nextToken()) - { - bool prot = false; - enum PROT protection = PROTpublic; - switch (token.value) - { - case TOKprivate: - prot = true; - protection = PROTprivate; - nextToken(); - break; - case TOKpackage: - prot = true; - protection = PROTpackage; - nextToken(); - break; - case TOKprotected: - prot = true; - protection = PROTprotected; - nextToken(); - break; - case TOKpublic: - prot = true; - protection = PROTpublic; - nextToken(); - break; - } - if (prot && !global.params.useDeprecated) - error("use of base class protection is deprecated"); - if (token.value == TOKidentifier) - { - BaseClass *b = new BaseClass(parseBasicType(), protection); - baseclasses->push(b); - if (token.value != TOKcomma) - break; - } - else - { - error("base classes expected instead of %s", token.toChars()); - return NULL; - } - } - return baseclasses; -} - -/************************************** - * Parse constraint. - * Constraint is of the form: - * if ( ConstraintExpression ) - */ - -#if DMDV2 -Expression *Parser::parseConstraint() -{ Expression *e = NULL; - - if (token.value == TOKif) - { - nextToken(); // skip over 'if' - check(TOKlparen); - e = parseExpression(); - check(TOKrparen); - } - return e; -} -#endif - -/************************************** - * Parse a TemplateDeclaration. - */ - -TemplateDeclaration *Parser::parseTemplateDeclaration(int ismixin) -{ - TemplateDeclaration *tempdecl; - Identifier *id; - TemplateParameters *tpl; - Dsymbols *decldefs; - Expression *constraint = NULL; - Loc loc = this->loc; - - nextToken(); - if (token.value != TOKidentifier) - { error("TemplateIdentifier expected following template"); - goto Lerr; - } - id = token.ident; - nextToken(); - tpl = parseTemplateParameterList(); - if (!tpl) - goto Lerr; - - constraint = parseConstraint(); - - if (token.value != TOKlcurly) - { error("members of template declaration expected"); - goto Lerr; - } - else - { - nextToken(); - decldefs = parseDeclDefs(0); - if (token.value != TOKrcurly) - { error("template member expected"); - goto Lerr; - } - nextToken(); - } - - tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin); - return tempdecl; - -Lerr: - return NULL; -} - -/****************************************** - * Parse template parameter list. - * Input: - * flag 0: parsing "( list )" - * 1: parsing non-empty "list )" - */ - -TemplateParameters *Parser::parseTemplateParameterList(int flag) -{ - TemplateParameters *tpl = new TemplateParameters(); - - if (!flag && token.value != TOKlparen) - { error("parenthesized TemplateParameterList expected following TemplateIdentifier"); - goto Lerr; - } - nextToken(); - - // Get array of TemplateParameters - if (flag || token.value != TOKrparen) - { int isvariadic = 0; - - while (token.value != TOKrparen) - { TemplateParameter *tp; - Identifier *tp_ident = NULL; - Type *tp_spectype = NULL; - Type *tp_valtype = NULL; - Type *tp_defaulttype = NULL; - Expression *tp_specvalue = NULL; - Expression *tp_defaultvalue = NULL; - Token *t; - - // Get TemplateParameter - - // First, look ahead to see if it is a TypeParameter or a ValueParameter - t = peek(&token); - if (token.value == TOKalias) - { // AliasParameter - nextToken(); - Type *spectype = NULL; - if (isDeclaration(&token, 2, TOKreserved, NULL)) - { - spectype = parseType(&tp_ident); - } - else - { - if (token.value != TOKidentifier) - { error("identifier expected for template alias parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - } - Object *spec = NULL; - if (token.value == TOKcolon) // : Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - spec = parseType(); - else - spec = parseCondExp(); - } - Object *def = NULL; - if (token.value == TOKassign) // = Type - { - nextToken(); - if (isDeclaration(&token, 0, TOKreserved, NULL)) - def = parseType(); - else - def = parseCondExp(); - } - tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def); - } - else if (t->value == TOKcolon || t->value == TOKassign || - t->value == TOKcomma || t->value == TOKrparen) - { // TypeParameter - if (token.value != TOKidentifier) - { error("identifier expected for template type parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } - else if (token.value == TOKidentifier && t->value == TOKdotdotdot) - { // ident... - if (isvariadic) - error("variadic template parameter must be last"); - isvariadic = 1; - tp_ident = token.ident; - nextToken(); - nextToken(); - tp = new TemplateTupleParameter(loc, tp_ident); - } -#if DMDV2 - else if (token.value == TOKthis) - { // ThisParameter - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected for template this parameter"); - goto Lerr; - } - tp_ident = token.ident; - nextToken(); - if (token.value == TOKcolon) // : Type - { - nextToken(); - tp_spectype = parseType(); - } - if (token.value == TOKassign) // = Type - { - nextToken(); - tp_defaulttype = parseType(); - } - tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype); - } -#endif - else - { // ValueParameter - tp_valtype = parseType(&tp_ident); - if (!tp_ident) - { - error("identifier expected for template value parameter"); - tp_ident = new Identifier("error", TOKidentifier); - } - if (token.value == TOKcolon) // : CondExpression - { - nextToken(); - tp_specvalue = parseCondExp(); - } - if (token.value == TOKassign) // = CondExpression - { - nextToken(); - tp_defaultvalue = parseDefaultInitExp(); - } - tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue); - } - tpl->push(tp); - if (token.value != TOKcomma) - break; - nextToken(); - } - } - check(TOKrparen); -Lerr: - return tpl; -} - -/****************************************** - * Parse template mixin. - * mixin Foo; - * mixin Foo!(args); - * mixin a.b.c!(args).Foo!(args); - * mixin Foo!(args) identifier; - * mixin typeof(expr).identifier!(args); - */ - -Dsymbol *Parser::parseMixin() -{ - TemplateMixin *tm; - Identifier *id; - Type *tqual; - Objects *tiargs; - Identifiers *idents; - - //printf("parseMixin()\n"); - nextToken(); - tqual = NULL; - if (token.value == TOKdot) - { - id = Id::empty; - } - else - { - if (token.value == TOKtypeof) - { - tqual = parseTypeof(); - check(TOKdot); - } - else if (token.value == TOKvector) - { - tqual = parseVector(); - check(TOKdot); - } - if (token.value != TOKidentifier) - { - error("identifier expected, not %s", token.toChars()); - id = Id::empty; - } - else - id = token.ident; - nextToken(); - } - - idents = new Identifiers(); - while (1) - { - tiargs = NULL; - if (token.value == TOKnot) - { - nextToken(); - if (token.value == TOKlparen) - tiargs = parseTemplateArgumentList(); - else - tiargs = parseTemplateArgument(); - } - - if (token.value != TOKdot) - break; - - if (tiargs) - { TemplateInstance *tempinst = new TemplateInstance(loc, id); - tempinst->tiargs = tiargs; - id = (Identifier *)tempinst; - tiargs = NULL; - } - idents->push(id); - - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - } - idents->push(id); - - if (token.value == TOKidentifier) - { - id = token.ident; - nextToken(); - } - else - id = NULL; - - tm = new TemplateMixin(loc, id, tqual, idents, tiargs); - if (token.value != TOKsemicolon) - error("';' expected after mixin"); - nextToken(); - - return tm; -} - -/****************************************** - * Parse template argument list. - * Input: - * current token is opening '(' - * Output: - * current token is one after closing ')' - */ - -Objects *Parser::parseTemplateArgumentList() -{ - //printf("Parser::parseTemplateArgumentList()\n"); - if (token.value != TOKlparen && token.value != TOKlcurly) - { error("!(TemplateArgumentList) expected following TemplateIdentifier"); - return new Objects(); - } - return parseTemplateArgumentList2(); -} - -Objects *Parser::parseTemplateArgumentList2() -{ - //printf("Parser::parseTemplateArgumentList2()\n"); - Objects *tiargs = new Objects(); - enum TOK endtok = TOKrparen; - nextToken(); - - // Get TemplateArgumentList - while (token.value != endtok) - { - // See if it is an Expression or a Type - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // Template argument is a type - Type *ta = parseType(); - tiargs->push(ta); - } - else - { // Template argument is an expression - Expression *ea = parseAssignExp(); - - if (ea->op == TOKfunction && ((FuncExp *)ea)->td) - tiargs->push(((FuncExp *)ea)->td); - else - tiargs->push(ea); - } - if (token.value != TOKcomma) - break; - nextToken(); - } - check(endtok, "template argument list"); - return tiargs; -} - -/***************************** - * Parse single template argument, to support the syntax: - * foo!arg - * Input: - * current token is the arg - */ - -Objects *Parser::parseTemplateArgument() -{ - //printf("parseTemplateArgument()\n"); - Objects *tiargs = new Objects(); - Type *ta; - switch (token.value) - { - case TOKidentifier: - ta = new TypeIdentifier(loc, token.ident); - goto LabelX; - - case TOKvector: - ta = parseVector(); - goto LabelX; - - case BASIC_TYPES_X(ta): - tiargs->push(ta); - nextToken(); - break; - - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKfile: - case TOKline: - case TOKthis: - { // Template argument is an expression - Expression *ea = parsePrimaryExp(); - tiargs->push(ea); - break; - } - - default: - error("template argument expected following !"); - break; - } - if (token.value == TOKnot) - error("multiple ! arguments are not allowed"); - return tiargs; -} - -Import *Parser::parseImport(Dsymbols *decldefs, int isstatic) -{ Import *s; - Identifier *id; - Identifier *aliasid = NULL; - Identifiers *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 Identifiers(); - a->push(id); - nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following package"); - break; - } - id = token.ident; - nextToken(); - } - - s = new Import(loc, a, id, aliasid, isstatic); - decldefs->push(s); - - /* Look for - * : alias=name, alias=name; - * syntax. - */ - if (token.value == TOKcolon) - { - do - { Identifier *name; - - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following :"); - break; - } - Identifier *alias = token.ident; - nextToken(); - if (token.value == TOKassign) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following %s=", alias->toChars()); - break; - } - name = token.ident; - nextToken(); - } - else - { name = alias; - alias = NULL; - } - s->addAlias(name, alias); - } while (token.value == TOKcomma); - break; // no comma-separated imports of this form - } - - aliasid = NULL; - } while (token.value == TOKcomma); - - if (token.value == TOKsemicolon) - nextToken(); - else - { - error("';' expected"); - nextToken(); - } - - return NULL; -} - -#if DMDV2 -Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl) -{ Type *t; - - /* Take care of the storage class prefixes that - * serve as type attributes: - * const shared, shared const, const, invariant, shared - */ - if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared const type - */ - t = parseType(pident, tpl); - t = t->makeSharedConst(); - return t; - } - else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen || - token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen) - { - nextToken(); - nextToken(); - /* shared wild type - */ - t = parseType(pident, tpl); - t = t->makeSharedWild(); - return t; - } - else if (token.value == TOKconst && peekNext() != TOKlparen) - { - nextToken(); - /* const type - */ - t = parseType(pident, tpl); - t = t->makeConst(); - return t; - } - else if ((token.value == TOKinvariant || token.value == TOKimmutable) && - peekNext() != TOKlparen) - { - nextToken(); - /* invariant type - */ - t = parseType(pident, tpl); - t = t->makeInvariant(); - return t; - } - else if (token.value == TOKshared && peekNext() != TOKlparen) - { - nextToken(); - /* shared type - */ - t = parseType(pident, tpl); - t = t->makeShared(); - return t; - } - else if (token.value == TOKwild && peekNext() != TOKlparen) - { - nextToken(); - /* wild type - */ - t = parseType(pident, tpl); - t = t->makeWild(); - return t; - } - else - t = parseBasicType(); - t = parseDeclarator(t, pident, tpl); - return t; -} -#endif - -Type *Parser::parseBasicType() -{ Type *t; - Identifier *id; - TypeQualified *tid; - - //printf("parseBasicType()\n"); - switch (token.value) - { - case BASIC_TYPES_X(t): - nextToken(); - break; - - case TOKthis: - case TOKsuper: - case TOKidentifier: - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { // ident!(template_arguments) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - tid = new TypeInstance(loc, tempinst); - goto Lident2; - } - Lident: - tid = new TypeIdentifier(loc, id); - Lident2: - while (token.value == TOKdot) - { nextToken(); - if (token.value != TOKidentifier) - { error("identifier expected following '.' instead of '%s'", token.toChars()); - break; - } - id = token.ident; - nextToken(); - if (token.value == TOKnot) - { - TemplateInstance *tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - tid->addIdent((Identifier *)tempinst); - } - else - tid->addIdent(id); - } - t = tid; - break; - - case TOKdot: - // Leading . as in .foo - id = Id::empty; - goto Lident; - - case TOKtypeof: - // typeof(expression) - tid = parseTypeof(); - goto Lident2; - - case TOKvector: - t = parseVector(); - break; - - case TOKconst: - // const(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - if (t->isImmutable()) - ; - else if (t->isShared()) - t = t->makeSharedConst(); - else - t = t->makeConst(); - break; - - case TOKinvariant: - if (!global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - case TOKimmutable: - // invariant(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - t = t->makeInvariant(); - break; - - case TOKshared: - // shared(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - if (t->isImmutable()) - ; - else if (t->isConst()) - t = t->makeSharedConst(); - else if (t->isWild()) - t = t->makeSharedWild(); - else - t = t->makeShared(); - break; - - case TOKwild: - // wild(type) - nextToken(); - check(TOKlparen); - t = parseType(); - check(TOKrparen); - if (t->isImmutable()/* || t->isConst()*/) - ; - else if (t->isShared()) - t = t->makeSharedWild(); - else - t = t->makeWild(); - break; - - default: - error("basic type expected, not %s", token.toChars()); - t = Type::tint32; - break; - } - return t; -} - -/****************************************** - * Parse things that follow the initial type t. - * t * - * t [] - * t [type] - * t [expression] - * t [expression .. expression] - * t function - * t delegate - */ - -Type *Parser::parseBasicType2(Type *t) -{ - //printf("parseBasicType2()\n"); - while (1) - { - switch (token.value) - { - case TOKmul: - t = new TypePointer(t); - nextToken(); - continue; - - case TOKlbracket: - // Handle []. Make sure things like - // int[3][1] a; - // is (array[1] of array[3] of int) - nextToken(); - if (token.value == TOKrbracket) - { - t = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array declaration - - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - t = new TypeAArray(t, index); - check(TOKrbracket); - } - else - { - //printf("it's type[expression]\n"); - inBrackets++; - Expression *e = parseAssignExp(); // [ expression ] - if (token.value == TOKslice) - { - nextToken(); - Expression *e2 = parseAssignExp(); // [ exp .. exp ] - t = new TypeSlice(t, e, e2); - } - else - t = new TypeSArray(t,e); - inBrackets--; - check(TOKrbracket); - } - continue; - - case TOKdelegate: - case TOKfunction: - { // Handle delegate declaration: - // t delegate(parameter list) nothrow pure - // t function(parameter list) nothrow pure - Parameters *arguments; - int varargs; - enum TOK save = token.value; - - nextToken(); - arguments = parseParameters(&varargs); - - StorageClass stc = parsePostfix(); - if (stc & (STCconst | STCimmutable | STCshared | STCwild)) - error("const/immutable/shared/inout attributes are only valid for non-static member functions"); - - TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc); - - if (save == TOKdelegate) - t = new TypeDelegate(tf); - else - t = new TypePointer(tf); // pointer to function - continue; - } - - default: - return t; - } - assert(0); - } - assert(0); - return NULL; -} - -Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl, StorageClass storage_class, int* pdisable) -{ Type *ts; - - //printf("parseDeclarator(tpl = %p)\n", tpl); - t = parseBasicType2(t); - - switch (token.value) - { - - case TOKidentifier: - if (pident) - *pident = token.ident; - else - error("unexpected identifer '%s' in declarator", token.ident->toChars()); - ts = t; - nextToken(); - break; - - case TOKlparen: - if (peekNext() == TOKmul || // like: T (*fp)(); - peekNext() == TOKlparen // like: T ((*fp))(); - /* || peekNext() == TOKlbracket*/) // like: T ([] a) - { - /* Parse things with parentheses around the identifier, like: - * int (*ident[3])[] - * although the D style would be: - * int[]*[3] ident - */ - if (!global.params.useDeprecated) - { - error("C-style function pointer and pointer to array syntax is deprecated. Use 'function' to declare function pointers"); - } - nextToken(); - ts = parseDeclarator(t, pident); - check(TOKrparen); - break; - } - ts = t; - { - Token *peekt = &token; - /* Completely disallow C-style things like: - * T (a); - * Improve error messages for the common bug of a missing return type - * by looking to see if (a) looks like a parameter list. - */ - if (isParameters(&peekt)) { - error("function declaration without return type. " - "(Note that constructors are always named 'this')"); - } - else - error("unexpected ( in declarator"); - } - break; - - default: - ts = t; - break; - } - - // parse DeclaratorSuffixes - while (1) - { - switch (token.value) - { -#if CARRAYDECL - /* Support C style array syntax: - * int ident[] - * as opposed to D-style: - * int[] ident - */ - case TOKlbracket: - { // This is the old C-style post [] syntax. - TypeNext *ta; - nextToken(); - if (token.value == TOKrbracket) - { // It's a dynamic array - ta = new TypeDArray(t); // [] - nextToken(); - } - else if (isDeclaration(&token, 0, TOKrbracket, NULL)) - { // It's an associative array - - //printf("it's an associative array\n"); - Type *index = parseType(); // [ type ] - check(TOKrbracket); - ta = new TypeAArray(t, index); - } - else - { - //printf("It's a static array\n"); - Expression *e = parseAssignExp(); // [ expression ] - ta = new TypeSArray(t, e); - check(TOKrbracket); - } - - /* Insert ta into - * ts -> ... -> t - * so that - * ts -> ... -> ta -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) - ; - *pt = ta; - continue; - } -#endif - case TOKlparen: - { - if (tpl) - { - /* Look ahead to see if this is (...)(...), - * i.e. a function template declaration - */ - if (peekPastParen(&token)->value == TOKlparen) - { - //printf("function template declaration\n"); - - // Gather template parameter list - *tpl = parseTemplateParameterList(); - } - } - - int varargs; - Parameters *arguments = parseParameters(&varargs); - - /* Parse const/immutable/shared/inout/nothrow/pure postfix - */ - StorageClass stc = parsePostfix(); - stc |= storage_class; // merge prefix storage classes - Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc); - tf = tf->addSTC(stc); - if (pdisable) - *pdisable = stc & STCdisable ? 1 : 0; - - /* Insert tf into - * ts -> ... -> t - * so that - * ts -> ... -> tf -> t - */ - Type **pt; - for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next) - ; - *pt = tf; - break; - } - } - break; - } - - return ts; -} - -/********************************** - * Parse Declarations. - * These can be: - * 1. declarations at global/class level - * 2. declarations at statement level - * Return array of Declaration *'s. - */ - -Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *comment) -{ - StorageClass stc; - int disable; - Type *ts; - Type *t; - Type *tfirst; - Identifier *ident; - Dsymbols *a; - enum TOK tok = TOKreserved; - enum LINK link = linkage; - - //printf("parseDeclarations() %s\n", token.toChars()); - if (!comment) - comment = token.blockComment; - - if (storage_class) - { ts = NULL; // infer type - goto L2; - } - - switch (token.value) - { - case TOKalias: - /* Look for: - * alias identifier this; - */ - tok = token.value; - nextToken(); - if (token.value == TOKidentifier && peek(&token)->value == TOKthis) - { - AliasThis *s = new AliasThis(this->loc, token.ident); - nextToken(); - check(TOKthis); - check(TOKsemicolon); - a = new Dsymbols(); - a->push(s); - addComment(s, comment); - return a; - } - break; - case TOKtypedef: - if (!global.params.useDeprecated) - error("use of typedef is deprecated; use alias instead"); - tok = token.value; - nextToken(); - break; - } - - storage_class = STCundefined; - while (1) - { - switch (token.value) - { - case TOKconst: - if (peek(&token)->value == TOKlparen) - break; // const as type constructor - stc = STCconst; // const as storage class - goto L1; - - case TOKinvariant: - case TOKimmutable: - if (peek(&token)->value == TOKlparen) - break; - if (token.value == TOKinvariant && !global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - stc = STCimmutable; - goto L1; - - case TOKshared: - if (peek(&token)->value == TOKlparen) - break; - stc = STCshared; - goto L1; - - case TOKwild: - if (peek(&token)->value == TOKlparen) - break; - stc = STCwild; - goto L1; - - case TOKstatic: stc = STCstatic; goto L1; - case TOKfinal: stc = STCfinal; goto L1; - case TOKauto: stc = STCauto; goto L1; - case TOKscope: stc = STCscope; goto L1; - case TOKoverride: stc = STCoverride; goto L1; - case TOKabstract: stc = STCabstract; goto L1; - case TOKsynchronized: stc = STCsynchronized; goto L1; - case TOKdeprecated: stc = STCdeprecated; goto L1; -#if DMDV2 - case TOKnothrow: stc = STCnothrow; goto L1; - case TOKpure: stc = STCpure; goto L1; - case TOKref: stc = STCref; goto L1; - case TOKtls: stc = STCtls; goto L1; - case TOKgshared: stc = STCgshared; goto L1; - case TOKenum: stc = STCmanifest; goto L1; - case TOKat: stc = parseAttribute(); goto L1; -#endif - L1: - if (storage_class & stc) - error("redundant storage class '%s'", token.toChars()); - storage_class = storage_class | stc; - composeStorageClass(storage_class); - nextToken(); - continue; - - case TOKextern: - if (peek(&token)->value != TOKlparen) - { stc = STCextern; - goto L1; - } - - link = parseLinkage(); - continue; - - default: - break; - } - break; - } - - /* Look for auto initializers: - * storage_class identifier = initializer; - */ - if (storage_class && - token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - return parseAutoDeclarations(storage_class, comment); - } - - if (token.value == TOKclass) - { - AggregateDeclaration *s = (AggregateDeclaration *)parseAggregate(); - s->storage_class |= storage_class; - Dsymbols *a = new Dsymbols(); - a->push(s); - addComment(s, comment); - return a; - } - - /* Look for return type inference for template functions. - */ - { - Token *tk; - if (storage_class && - token.value == TOKidentifier && - (tk = peek(&token))->value == TOKlparen && - skipParens(tk, &tk) && - ((tk = peek(tk)), 1) && - skipAttributes(tk, &tk) && - (tk->value == TOKlparen || - tk->value == TOKlcurly) - ) - { - ts = NULL; - } - else - { - ts = parseBasicType(); - ts = parseBasicType2(ts); - } - } - -L2: - tfirst = NULL; - a = new Dsymbols(); - - while (1) - { - Loc loc = this->loc; - TemplateParameters *tpl = NULL; - - ident = NULL; - t = parseDeclarator(ts, &ident, &tpl, storage_class, &disable); - assert(t); - if (!tfirst) - tfirst = t; - else if (t != tfirst) - error("multiple declarations must have the same type, not %s and %s", - tfirst->toChars(), t->toChars()); - if (!ident) - error("no identifier for declarator %s", t->toChars()); - - if (tok == TOKtypedef || tok == TOKalias) - { Declaration *v; - Initializer *init = NULL; - - /* Aliases can no longer have multiple declarators, storage classes, - * linkages, or auto declarations. - * These never made any sense, anyway. - * The code below needs to be fixed to reject them. - * The grammar has already been fixed to preclude them. - */ - - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - if (tok == TOKtypedef) - { v = new TypedefDeclaration(loc, ident, t, init); - if (!global.params.useDeprecated) - error("use of typedef is deprecated; use alias instead"); - } - else - { if (init) - error("alias cannot have initializer"); - v = new AliasDeclaration(loc, ident, t); - } - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected to close %s declaration", Token::toChars(tok)); - break; - } - } - else if (t->ty == Tfunction) - { - TypeFunction *tf = (TypeFunction *)t; - Expression *constraint = NULL; -#if 0 - if (Parameter::isTPL(tf->parameters)) - { - if (!tpl) - tpl = new TemplateParameters(); - } -#endif - - //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class); - - FuncDeclaration *f = - new FuncDeclaration(loc, 0, ident, storage_class | (disable ? STCdisable : 0), t); - addComment(f, comment); - if (tpl) - constraint = parseConstraint(); - parseContracts(f); - addComment(f, NULL); - Dsymbol *s; - if (link == linkage) - { - s = f; - } - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(f); - s = new LinkDeclaration(link, ax); - } - /* A template parameter list means it's a function template - */ - if (tpl) - { - // Wrap a template around the function declaration - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(s); - TemplateDeclaration *tempdecl = - new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs, 0); - s = tempdecl; - } - addComment(s, comment); - a->push(s); - } - else - { - Initializer *init = NULL; - if (token.value == TOKassign) - { - nextToken(); - init = parseInitializer(); - } - - VarDeclaration *v = new VarDeclaration(loc, t, ident, init); - v->storage_class = storage_class; - if (link == linkage) - a->push(v); - else - { - Dsymbols *ax = new Dsymbols(); - ax->push(v); - Dsymbol *s = new LinkDeclaration(link, ax); - a->push(s); - } - switch (token.value) - { case TOKsemicolon: - nextToken(); - addComment(v, comment); - break; - - case TOKcomma: - nextToken(); - addComment(v, comment); - continue; - - default: - error("semicolon expected, not '%s'", token.toChars()); - break; - } - } - break; - } - return a; -} - -/***************************************** - * Parse auto declarations of the form: - * storageClass ident = init, ident = init, ... ; - * and return the array of them. - * Starts with token on the first ident. - * Ends with scanner past closing ';' - */ - -#if DMDV2 -Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment) -{ - Dsymbols *a = new Dsymbols; - - while (1) - { - Identifier *ident = token.ident; - nextToken(); // skip over ident - assert(token.value == TOKassign); - nextToken(); // skip over '=' - Initializer *init = parseInitializer(); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = storageClass; - a->push(v); - if (token.value == TOKsemicolon) - { - nextToken(); - addComment(v, comment); - } - else if (token.value == TOKcomma) - { - nextToken(); - if (token.value == TOKidentifier && - peek(&token)->value == TOKassign) - { - addComment(v, comment); - continue; - } - else - error("Identifier expected following comma"); - } - else - error("semicolon expected following auto declaration, not '%s'", token.toChars()); - break; - } - return a; -} -#endif - -/***************************************** - * Parse contracts following function declaration. - */ - -void Parser::parseContracts(FuncDeclaration *f) -{ - enum LINK linksave = linkage; - - // The following is irrelevant, as it is overridden by sc->linkage in - // TypeFunction::semantic - linkage = LINKd; // nested functions have D linkage -L1: - switch (token.value) - { - case TOKlcurly: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - f->fbody = parseStatement(PSsemi); - f->endloc = endloc; - break; - - case TOKbody: - nextToken(); - f->fbody = parseStatement(PScurly); - f->endloc = endloc; - break; - - case TOKsemicolon: - if (f->frequire || f->fensure) - error("missing body { ... } after in or out"); - nextToken(); - break; - -#if 0 // Do we want this for function declarations, so we can do: - // int x, y, foo(), z; - case TOKcomma: - nextToken(); - continue; -#endif - -#if 0 // Dumped feature - case TOKthrow: - if (!f->fthrows) - f->fthrows = new Types(); - nextToken(); - check(TOKlparen); - while (1) - { - Type *tb = parseBasicType(); - f->fthrows->push(tb); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKrparen); - goto L1; -#endif - - case TOKin: - nextToken(); - if (f->frequire) - error("redundant 'in' statement"); - f->frequire = parseStatement(PScurly | PSscope); - goto L1; - - case TOKout: - // parse: out (identifier) { statement } - nextToken(); - if (token.value != TOKlcurly) - { - check(TOKlparen); - if (token.value != TOKidentifier) - error("(identifier) following 'out' expected, not %s", token.toChars()); - f->outId = token.ident; - nextToken(); - check(TOKrparen); - } - if (f->fensure) - error("redundant 'out' statement"); - f->fensure = parseStatement(PScurly | PSscope); - goto L1; - - default: - if (!f->frequire && !f->fensure) // allow these even with no body - error("semicolon expected following function declaration"); - break; - } - linkage = linksave; -} - -/***************************************** - * Parse initializer for variable declaration. - */ - -Initializer *Parser::parseInitializer() -{ - StructInitializer *is; - ArrayInitializer *ia; - ExpInitializer *ie; - Expression *e; - Identifier *id; - Initializer *value; - int comma; - Loc loc = this->loc; - Token *t; - int braces; - int brackets; - - switch (token.value) - { - case TOKlcurly: - /* Scan ahead to see if it is a struct initializer or - * a function literal. - * If it contains a ';', it is a function literal. - * Treat { } as a struct initializer. - */ - braces = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKsemicolon: - case TOKreturn: - goto Lexpression; - - case TOKlcurly: - braces++; - continue; - - case TOKrcurly: - if (--braces == 0) - break; - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - is = new StructInitializer(loc); - nextToken(); - comma = 2; - 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: - if (comma == 2) - error("expression expected, not ','"); - nextToken(); - comma = 2; - continue; - - case TOKrcurly: // allow trailing comma's - nextToken(); - break; - - case TOKeof: - error("found EOF instead of initializer"); - break; - - default: - if (comma == 1) - error("comma expected separating field initializers"); - value = parseInitializer(); - is->addInit(NULL, value); - comma = 1; - continue; - //error("found '%s' instead of field initializer", token.toChars()); - //break; - } - break; - } - return is; - - case TOKlbracket: - /* Scan ahead to see if it is an array initializer or - * an expression. - * If it ends with a ';' ',' or '}', it is an array initializer. - */ - brackets = 1; - for (t = peek(&token); 1; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brackets++; - continue; - - case TOKrbracket: - if (--brackets == 0) - { t = peek(t); - if (t->value != TOKsemicolon && - t->value != TOKcomma && - t->value != TOKrbracket && - t->value != TOKrcurly) - goto Lexpression; - break; - } - continue; - - case TOKeof: - break; - - default: - continue; - } - break; - } - - ia = new ArrayInitializer(loc); - nextToken(); - comma = 2; - 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: - if (comma == 2) - error("expression expected, not ','"); - 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 - -/***************************************** - */ - -void Parser::checkDanglingElse(Loc elseloc) -{ - if (token.value != TOKelse && - token.value != TOKcatch && - token.value != TOKfinally && - lookingForElse.linnum != 0) - { - warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); - } -} - -/***************************************** - * Input: - * flags PSxxxx - */ - -Statement *Parser::parseStatement(int flags) -{ Statement *s; - Token *t; - Condition *condition; - Statement *ifbody; - Statement *elsebody; - bool isfinal; - Loc loc = this->loc; - - //printf("parseStatement()\n"); - - if (flags & PScurly && token.value != TOKlcurly) - error("statement expected to be { }, not %s", token.toChars()); - - switch (token.value) - { - case TOKidentifier: - /* A leading identifier can be a declaration, label, or expression. - * The easiest case to check first is label: - */ - t = peek(&token); - if (t->value == TOKcolon) - { // It's a label - - Identifier *ident = token.ident; - nextToken(); - nextToken(); - s = parseStatement(PSsemi_ok); - s = new LabelStatement(loc, ident, s); - break; - } - // fallthrough to TOKdot - case TOKdot: - case TOKtypeof: - case TOKvector: - if (isDeclaration(&token, 2, TOKreserved, NULL)) - goto Ldeclaration; - else - goto Lexp; - break; - - case TOKassert: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKstring: - case TOKlparen: - case TOKcast: - case TOKmul: - case TOKmin: - case TOKadd: - case TOKtilde: - case TOKnot: - case TOKplusplus: - case TOKminusminus: - case TOKnew: - case TOKdelete: - case TOKdelegate: - case TOKfunction: - case TOKtypeid: - case TOKis: - case TOKlbracket: -#if DMDV2 - case TOKtraits: - case TOKfile: - case TOKline: -#endif - Lexp: - { - Expression *exp = parseExpression(); - check(TOKsemicolon, "statement"); - s = new ExpStatement(loc, exp); - break; - } - - case TOKstatic: - { // Look ahead to see if it's static assert() or static if() - - Token *t = peek(&token); - if (t->value == TOKassert) - { - nextToken(); - s = new StaticAssertStatement(parseStaticAssert()); - break; - } - if (t->value == TOKif) - { - nextToken(); - condition = parseStaticIfCondition(); - goto Lcondition; - } - if (t->value == TOKstruct || t->value == TOKunion || t->value == TOKclass) - { - nextToken(); - Dsymbols *a = parseBlock(); - Dsymbol *d = new StorageClassDeclaration(STCstatic, a); - s = new ExpStatement(loc, d); - if (flags & PSscope) - s = new ScopeStatement(loc, s); - break; - } - if (t->value == TOKimport) - { nextToken(); - Dsymbols *imports = new Dsymbols(); - parseImport(imports, 1); // static import ... - s = new ImportStatement(loc, imports); - break; - } - goto Ldeclaration; - } - - case TOKfinal: - if (peekNext() == TOKswitch) - { - nextToken(); - isfinal = TRUE; - goto Lswitch; - } - goto Ldeclaration; - - case BASIC_TYPES: - case TOKtypedef: - case TOKalias: - case TOKconst: - case TOKauto: - case TOKextern: - case TOKinvariant: -#if DMDV2 - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKnothrow: - case TOKpure: - case TOKref: - case TOKtls: - case TOKgshared: - case TOKat: -#endif - Ldeclaration: - { Dsymbols *a; - - a = parseDeclarations(STCundefined, NULL); - if (a->dim > 1) - { - Statements *as = new Statements(); - as->reserve(a->dim); - for (size_t i = 0; i < a->dim; i++) - { - Dsymbol *d = a->tdata()[i]; - s = new ExpStatement(loc, d); - as->push(s); - } - s = new CompoundDeclarationStatement(loc, as); - } - else if (a->dim == 1) - { - Dsymbol *d = a->tdata()[0]; - s = new ExpStatement(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 ExpStatement(loc, d); - break; - } - - case TOKenum: - { /* Determine if this is a manifest constant declaration, - * or a conventional enum. - */ - Dsymbol *d; - Token *t = peek(&token); - if (t->value == TOKlcurly || t->value == TOKcolon) - d = parseEnum(); - else if (t->value != TOKidentifier) - goto Ldeclaration; - else - { - t = peek(t); - if (t->value == TOKlcurly || t->value == TOKcolon || - t->value == TOKsemicolon) - d = parseEnum(); - else - goto Ldeclaration; - } - s = new ExpStatement(loc, d); - break; - } - - case TOKmixin: - { t = peek(&token); - if (t->value == TOKlparen) - { // mixin(string) - Expression *e = parseAssignExp(); - check(TOKsemicolon); - if (e->op == TOKmixin) - { - CompileExp *cpe = (CompileExp *)e; - s = new CompileStatement(loc, cpe->e1); - } - else - { - s = new ExpStatement(loc, e); - } - break; - } - Dsymbol *d = parseMixin(); - s = new ExpStatement(loc, d); - break; - } - - case TOKlcurly: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = 0; - - nextToken(); - //if (token.value == TOKsemicolon) - //error("use '{ }' for an empty statement, not a ';'"); - Statements *statements = new Statements(); - while (token.value != TOKrcurly && token.value != TOKeof) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - endloc = this->loc; - s = new CompoundStatement(loc, statements); - if (flags & (PSscope | PScurlyscope)) - s = new ScopeStatement(loc, s); - check(TOKrcurly, "compound statement"); - lookingForElse = lookingForElseSave; - 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_ok)) - { - if (flags & PSsemi) - { if (global.params.warnings) - warning(loc, "use '{ }' for an empty statement, not a ';'"); - } - else - error("use '{ }' for an empty statement, not a ';'"); - } - nextToken(); - s = new ExpStatement(loc, (Expression *)NULL); - break; - - case TOKdo: - { Statement *body; - Expression *condition; - - nextToken(); - Loc lookingForElseSave = lookingForElse; - lookingForElse = 0; - body = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - check(TOKwhile); - check(TOKlparen); - condition = parseExpression(); - check(TOKrparen); - if (token.value == TOKsemicolon) - nextToken(); - else if (!global.params.useDeprecated) - error("do-while statement requires terminating ;"); - 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 - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = 0; - init = parseStatement(0); - lookingForElse = lookingForElseSave; - } - if (token.value == TOKsemicolon) - { - condition = NULL; - nextToken(); - } - else - { - condition = parseExpression(); - check(TOKsemicolon, "for condition"); - } - if (token.value == TOKrparen) - { increment = NULL; - nextToken(); - } - else - { increment = parseExpression(); - check(TOKrparen); - } - body = parseStatement(PSscope); - s = new ForStatement(loc, init, condition, increment, body); - if (init) - s = new ScopeStatement(loc, s); - break; - } - - case TOKforeach: - case TOKforeach_reverse: - { - enum TOK op = token.value; - - nextToken(); - check(TOKlparen); - - Parameters *arguments = new Parameters(); - - while (1) - { - Identifier *ai = NULL; - Type *at; - - StorageClass storageClass = 0; - if (token.value == TOKref -#if D1INOUT - || token.value == TOKinout -#endif - ) - { storageClass = STCref; - nextToken(); - } - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKcomma || t->value == TOKsemicolon) - { ai = token.ident; - at = NULL; // infer argument type - nextToken(); - goto Larg; - } - } - at = parseType(&ai); - if (!ai) - error("no identifier for declarator %s", at->toChars()); - Larg: - Parameter *a = new Parameter(storageClass, at, ai, NULL); - arguments->push(a); - if (token.value == TOKcomma) - { nextToken(); - continue; - } - break; - } - check(TOKsemicolon); - - Expression *aggr = parseExpression(); - if (token.value == TOKslice && arguments->dim == 1) - { - Parameter *a = arguments->tdata()[0]; - delete arguments; - nextToken(); - Expression *upr = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(0); - s = new ForeachRangeStatement(loc, op, a, aggr, upr, body); - } - else - { - check(TOKrparen); - Statement *body = parseStatement(0); - s = new ForeachStatement(loc, op, arguments, aggr, body); - } - break; - } - - case TOKif: - { Parameter *arg = NULL; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - nextToken(); - check(TOKlparen); - - if (token.value == TOKauto) - { - nextToken(); - if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKassign) - { - arg = new Parameter(0, NULL, token.ident, NULL); - nextToken(); - nextToken(); - } - else - { error("= expected following auto identifier"); - goto Lerror; - } - } - else - { error("identifier expected following auto"); - goto Lerror; - } - } - else if (isDeclaration(&token, 2, TOKassign, NULL)) - { - Type *at; - Identifier *ai; - - at = parseType(&ai); - check(TOKassign); - arg = new Parameter(0, at, ai, NULL); - } - - // Check for " ident;" - else if (token.value == TOKidentifier) - { - Token *t = peek(&token); - if (t->value == TOKsemicolon) - { - arg = new Parameter(0, NULL, token.ident, NULL); - nextToken(); - nextToken(); - if (!global.params.useDeprecated) - error("if (v%s e) is deprecated, use if (auto v = e)", t->toChars()); - } - } - - condition = parseExpression(); - check(TOKrparen); - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - ifbody = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - } - if (token.value == TOKelse) - { - Loc elseloc = this->loc; - nextToken(); - elsebody = parseStatement(PSscope); - checkDanglingElse(elseloc); - } - else - elsebody = NULL; - if (condition && ifbody) - s = new IfStatement(loc, arg, condition, ifbody, elsebody); - else - s = NULL; // don't propagate parsing errors - 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: - { - Loc lookingForElseSave = lookingForElse; - lookingForElse = loc; - ifbody = parseStatement(0 /*PSsemi*/); - lookingForElse = lookingForElseSave; - } - elsebody = NULL; - if (token.value == TOKelse) - { - Loc elseloc = this->loc; - nextToken(); - elsebody = parseStatement(0 /*PSsemi*/); - checkDanglingElse(elseloc); - } - s = new ConditionalStatement(loc, condition, ifbody, elsebody); - break; - - case TOKpragma: - { Identifier *ident; - Expressions *args = NULL; - Statement *body; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("pragma(identifier expected"); - goto Lerror; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma && peekNext() != TOKrparen) - args = parseArguments(); // pragma(identifier, args...); - else - check(TOKrparen); // pragma(identifier); - if (token.value == TOKsemicolon) - { nextToken(); - body = NULL; - } - else - body = parseStatement(PSsemi); - s = new PragmaStatement(loc, ident, args, body); - break; - } - - case TOKswitch: - isfinal = FALSE; - goto Lswitch; - - Lswitch: - { - nextToken(); - check(TOKlparen); - Expression *condition = parseExpression(); - check(TOKrparen); - Statement *body = parseStatement(PSscope); - s = new SwitchStatement(loc, condition, body, isfinal); - break; - } - - case TOKcase: - { Expression *exp; - Statements *statements; - Expressions cases; // array of Expression's - Expression *last = NULL; - - while (1) - { - nextToken(); - exp = parseAssignExp(); - cases.push(exp); - if (token.value != TOKcomma) - break; - } - check(TOKcolon); - -#if DMDV2 - /* case exp: .. case last: - */ - if (token.value == TOKslice) - { - if (cases.dim > 1) - error("only one case allowed for start of case range"); - nextToken(); - check(TOKcase); - last = parseAssignExp(); - check(TOKcolon); - } -#endif - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - -#if DMDV2 - if (last) - { - s = new CaseRangeStatement(loc, exp, last, s); - } - else -#endif - { - // Keep cases in order by building the case statements backwards - for (size_t i = cases.dim; i; i--) - { - exp = cases.tdata()[i - 1]; - s = new CaseStatement(loc, exp, s); - } - } - break; - } - - case TOKdefault: - { - Statements *statements; - - nextToken(); - check(TOKcolon); - - statements = new Statements(); - while (token.value != TOKcase && - token.value != TOKdefault && - token.value != TOKeof && - token.value != TOKrcurly) - { - statements->push(parseStatement(PSsemi | PScurlyscope)); - } - s = new CompoundStatement(loc, statements); - s = new ScopeStatement(loc, s); - s = new DefaultStatement(loc, s); - break; - } - - case TOKreturn: - { Expression *exp; - - nextToken(); - if (token.value == TOKsemicolon) - exp = NULL; - else - exp = parseExpression(); - check(TOKsemicolon, "return statement"); - s = new ReturnStatement(loc, exp); - break; - } - - case TOKbreak: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "break statement"); - s = new BreakStatement(loc, ident); - break; - } - - case TOKcontinue: - { Identifier *ident; - - nextToken(); - if (token.value == TOKidentifier) - { ident = token.ident; - nextToken(); - } - else - ident = NULL; - check(TOKsemicolon, "continue statement"); - s = new ContinueStatement(loc, ident); - break; - } - - case TOKgoto: - { Identifier *ident; - - nextToken(); - if (token.value == TOKdefault) - { - nextToken(); - s = new GotoDefaultStatement(loc); - } - else if (token.value == TOKcase) - { - Expression *exp = NULL; - - nextToken(); - if (token.value != TOKsemicolon) - exp = parseExpression(); - s = new GotoCaseStatement(loc, exp); - } - else - { - if (token.value != TOKidentifier) - { error("Identifier expected following goto"); - ident = NULL; - } - else - { ident = token.ident; - nextToken(); - } - s = new GotoStatement(loc, ident); - } - check(TOKsemicolon, "goto statement"); - break; - } - - case TOKsynchronized: - { Expression *exp; - Statement *body; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - exp = parseExpression(); - check(TOKrparen); - } - else - exp = NULL; - body = parseStatement(PSscope); - s = new SynchronizedStatement(loc, exp, body); - break; - } - - case TOKwith: - { Expression *exp; - Statement *body; - - nextToken(); - check(TOKlparen); - exp = parseExpression(); - check(TOKrparen); - body = parseStatement(PSscope); - s = new WithStatement(loc, exp, body); - break; - } - - case TOKtry: - { Statement *body; - Catches *catches = NULL; - Statement *finalbody = NULL; - - nextToken(); - Loc lookingForElseSave = lookingForElse; - lookingForElse = 0; - body = parseStatement(PSscope); - lookingForElse = lookingForElseSave; - while (token.value == TOKcatch) - { - Statement *handler; - Catch *c; - Type *t; - Identifier *id; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlcurly) - { - t = NULL; - id = NULL; - } - else - { - check(TOKlparen); - id = NULL; - t = parseType(&id); - check(TOKrparen); - } - handler = parseStatement(0); - c = new Catch(loc, t, id, handler); - if (!catches) - catches = new Catches(); - 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; use 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; - } - - case TOKimport: - { Dsymbols *imports = new Dsymbols(); - parseImport(imports, 0); - s = new ImportStatement(loc, imports); - break; - } - - default: - error("found '%s' instead of statement", token.toChars()); - goto Lerror; - - Lerror: - while (token.value != TOKrcurly && - token.value != TOKsemicolon && - token.value != TOKeof) - nextToken(); - if (token.value == TOKsemicolon) - nextToken(); - s = NULL; - break; - } - - return s; -} - -void Parser::check(enum TOK value) -{ - check(loc, value); -} - -void Parser::check(Loc loc, enum TOK value) -{ - if (token.value != value) - error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value)); - nextToken(); -} - -void Parser::check(enum TOK value, const char *string) -{ - if (token.value != value) - error("found '%s' when expecting '%s' following %s", - token.toChars(), Token::toChars(value), string); - nextToken(); -} - -void Parser::checkParens(enum TOK value, Expression *e) -{ - if (precedence[e->op] == PREC_rel && !e->parens) - error(loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value)); -} - -/************************************ - * Determine if the scanner is sitting on the start of a declaration. - * Input: - * needId 0 no identifier - * 1 identifier optional - * 2 must have identifier - * Output: - * if *pt is not NULL, it is set to the ending token, which would be endtok - */ - -int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt) -{ - //printf("isDeclaration(needId = %d)\n", needId); - int haveId = 0; - -#if DMDV2 - if ((t->value == TOKconst || - t->value == TOKinvariant || - t->value == TOKimmutable || - t->value == TOKwild || - t->value == TOKshared) && - peek(t)->value != TOKlparen) - { /* const type - * immutable type - * shared type - * wild type - */ - t = peek(t); - } -#endif - - if (!isBasicType(&t)) - { - goto Lisnot; - } - if (!isDeclarator(&t, &haveId, endtok)) - goto Lisnot; - if ( needId == 1 || - (needId == 0 && !haveId) || - (needId == 2 && haveId)) - { if (pt) - *pt = t; - goto Lis; - } - else - goto Lisnot; - -Lis: - //printf("\tis declaration, t = %s\n", t->toChars()); - return TRUE; - -Lisnot: - //printf("\tis not declaration\n"); - return FALSE; -} - -int Parser::isBasicType(Token **pt) -{ - // This code parallels parseBasicType() - Token *t = *pt; - int haveId = 0; - - switch (t->value) - { - case BASIC_TYPES: - t = peek(t); - break; - - case TOKidentifier: - L5: - t = peek(t); - if (t->value == TOKnot) - { - goto L4; - } - goto L3; - while (1) - { - L2: - t = peek(t); - L3: - if (t->value == TOKdot) - { - Ldot: - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - if (t->value != TOKnot) - goto L3; - L4: - /* Seen a ! - * Look for: - * !( args ), !identifier, etc. - */ - t = peek(t); - switch (t->value) - { case TOKidentifier: - goto L5; - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - break; - case BASIC_TYPES: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: - case TOKfile: - case TOKline: - goto L2; - default: - goto Lfalse; - } - } - else - break; - } - break; - - case TOKdot: - goto Ldot; - - case TOKtypeof: - case TOKvector: - /* typeof(exp).identifier... - */ - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - if (!skipParens(t, &t)) - goto Lfalse; - goto L2; - - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKwild: - // const(type) or immutable(type) or shared(type) or wild(type) - t = peek(t); - if (t->value != TOKlparen) - goto Lfalse; - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - { - goto Lfalse; - } - t = peek(t); - break; - - default: - goto Lfalse; - } - *pt = t; - //printf("is\n"); - return TRUE; - -Lfalse: - //printf("is not\n"); - return FALSE; -} - -int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok) -{ // This code parallels parseDeclarator() - Token *t = *pt; - int parens; - - //printf("Parser::isDeclarator()\n"); - //t->print(); - if (t->value == TOKassign) - return FALSE; - - while (1) - { - parens = FALSE; - switch (t->value) - { - case TOKmul: - //case TOKand: - t = peek(t); - continue; - - case TOKlbracket: - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - // [ expression .. expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value == TOKslice) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; - - case TOKidentifier: - if (*haveId) - return FALSE; - *haveId = TRUE; - t = peek(t); - break; - - case TOKlparen: - t = peek(t); - - if (t->value == TOKrparen) - return FALSE; // () is not a declarator - - /* Regard ( identifier ) as not a declarator - * BUG: what about ( *identifier ) in - * f(*p)(x); - * where f is a class instance with overloaded () ? - * Should we just disallow C-style function pointer declarations? - */ - if (t->value == TOKidentifier) - { Token *t2 = peek(t); - if (t2->value == TOKrparen) - return FALSE; - } - - - if (!isDeclarator(&t, haveId, TOKrparen)) - return FALSE; - t = peek(t); - parens = TRUE; - break; - - case TOKdelegate: - case TOKfunction: - t = peek(t); - if (!isParameters(&t)) - return FALSE; - continue; - } - break; - } - - while (1) - { - switch (t->value) - { -#if CARRAYDECL - case TOKlbracket: - parens = FALSE; - t = peek(t); - if (t->value == TOKrbracket) - { - t = peek(t); - } - else if (isDeclaration(t, 0, TOKrbracket, &t)) - { // It's an associative array declaration - t = peek(t); - } - else - { - // [ expression ] - if (!isExpression(&t)) - return FALSE; - if (t->value != TOKrbracket) - return FALSE; - t = peek(t); - } - continue; -#endif - - case TOKlparen: - parens = FALSE; - if (!isParameters(&t)) - return FALSE; -#if DMDV2 - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKpure: - case TOKnothrow: - t = peek(t); - continue; - case TOKat: - t = peek(t); // skip '@' - t = peek(t); // skip identifier - continue; - default: - break; - } - break; - } -#endif - continue; - - // Valid tokens that follow a declaration - case TOKrparen: - case TOKrbracket: - case TOKassign: - case TOKcomma: - case TOKdotdotdot: - case TOKsemicolon: - case TOKlcurly: - case TOKin: - case TOKout: - case TOKbody: - // The !parens is to disallow unnecessary parentheses - if (!parens && (endtok == TOKreserved || endtok == t->value)) - { *pt = t; - return TRUE; - } - return FALSE; - - default: - return FALSE; - } - } -} - - -int Parser::isParameters(Token **pt) -{ // This code parallels parseParameters() - Token *t = *pt; - - //printf("isParameters()\n"); - if (t->value != TOKlparen) - return FALSE; - - t = peek(t); - for (;1; t = peek(t)) - { - L1: - switch (t->value) - { - case TOKrparen: - break; - - case TOKdotdotdot: - t = peek(t); - break; - -#if D1INOUT - case TOKinout: -#endif - case TOKin: - case TOKout: - case TOKref: - case TOKlazy: - case TOKfinal: - case TOKauto: - continue; - - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKwild: - t = peek(t); - if (t->value == TOKlparen) - { - t = peek(t); - if (!isDeclaration(t, 0, TOKrparen, &t)) - return FALSE; - t = peek(t); // skip past closing ')' - goto L2; - } - goto L1; - -#if 0 - case TOKstatic: - continue; - case TOKauto: - case TOKalias: - t = peek(t); - if (t->value == TOKidentifier) - t = peek(t); - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - goto L3; -#endif - - default: - { if (!isBasicType(&t)) - return FALSE; - L2: - int tmp = FALSE; - if (t->value != TOKdotdotdot && - !isDeclarator(&t, &tmp, TOKreserved)) - return FALSE; - if (t->value == TOKassign) - { t = peek(t); - if (!isExpression(&t)) - return FALSE; - } - if (t->value == TOKdotdotdot) - { - t = peek(t); - break; - } - } - if (t->value == TOKcomma) - { - continue; - } - break; - } - break; - } - if (t->value != TOKrparen) - return FALSE; - t = peek(t); - *pt = t; - return TRUE; -} - -int Parser::isExpression(Token **pt) -{ - // This is supposed to determine if something is an expression. - // What it actually does is scan until a closing right bracket - // is found. - - Token *t = *pt; - int brnest = 0; - int panest = 0; - int curlynest = 0; - - for (;; t = peek(t)) - { - switch (t->value) - { - case TOKlbracket: - brnest++; - continue; - - case TOKrbracket: - if (--brnest >= 0) - continue; - break; - - case TOKlparen: - panest++; - continue; - - case TOKcomma: - if (brnest || panest) - continue; - break; - - case TOKrparen: - if (--panest >= 0) - continue; - break; - - case TOKlcurly: - curlynest++; - continue; - - case TOKrcurly: - if (--curlynest >= 0) - continue; - return FALSE; - - case TOKslice: - if (brnest) - continue; - break; - - case TOKsemicolon: - if (curlynest) - continue; - return FALSE; - - case TOKeof: - return FALSE; - - default: - continue; - } - break; - } - - *pt = t; - return TRUE; -} - -/********************************************** - * Skip over - * instance foo.bar(parameters...) - * Output: - * if (pt), *pt is set to the token following the closing ) - * Returns: - * 1 it's valid instance syntax - * 0 invalid instance syntax - */ - -int Parser::isTemplateInstance(Token *t, Token **pt) -{ - t = peek(t); - if (t->value != TOKdot) - { - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - while (t->value == TOKdot) - { - t = peek(t); - if (t->value != TOKidentifier) - goto Lfalse; - t = peek(t); - } - if (t->value != TOKlparen) - goto Lfalse; - - // Skip over the template arguments - while (1) - { - while (1) - { - t = peek(t); - switch (t->value) - { - case TOKlparen: - if (!skipParens(t, &t)) - goto Lfalse; - continue; - case TOKrparen: - break; - case TOKcomma: - break; - case TOKeof: - case TOKsemicolon: - goto Lfalse; - default: - continue; - } - break; - } - - if (t->value != TOKcomma) - break; - } - if (t->value != TOKrparen) - goto Lfalse; - t = peek(t); - if (pt) - *pt = t; - return 1; - -Lfalse: - return 0; -} - -/******************************************* - * Skip parens, brackets. - * Input: - * t is on opening ( - * Output: - * *pt is set to closing token, which is ')' on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipParens(Token *t, Token **pt) -{ - int parens = 0; - - while (1) - { - switch (t->value) - { - case TOKlparen: - parens++; - break; - - case TOKrparen: - parens--; - if (parens < 0) - goto Lfalse; - if (parens == 0) - goto Ldone; - break; - - case TOKeof: - goto Lfalse; - - default: - break; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lfalse: - return 0; -} - -/******************************************* - * Skip attributes. - * Input: - * t is on a candidate attribute - * Output: - * *pt is set to first non-attribute token on success - * Returns: - * !=0 successful - * 0 some parsing error - */ - -int Parser::skipAttributes(Token *t, Token **pt) -{ - while (1) - { - switch (t->value) - { - case TOKconst: - case TOKinvariant: - case TOKimmutable: - case TOKshared: - case TOKwild: - case TOKfinal: - case TOKauto: - case TOKscope: - case TOKoverride: - case TOKabstract: - case TOKsynchronized: - case TOKdeprecated: - case TOKnothrow: - case TOKpure: - case TOKref: - case TOKtls: - case TOKgshared: - //case TOKmanifest: - break; - case TOKat: - t = peek(t); - if (t->value == TOKidentifier) - break; - goto Lerror; - default: - goto Ldone; - } - t = peek(t); - } - - Ldone: - if (*pt) - *pt = t; - return 1; - - Lerror: - 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: - if (peekNext() == TOKgoesto) - goto case_delegate; - - id = token.ident; - nextToken(); - if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin) - { // identifier!(template-argument-list) - TemplateInstance *tempinst; - - tempinst = new TemplateInstance(loc, id); - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tempinst->tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tempinst->tiargs = parseTemplateArgument(); - e = new ScopeExp(loc, tempinst); - } - else - e = new IdentifierExp(loc, id); - break; - - case TOKdollar: - if (!inBrackets) - error("'$' is valid only inside [] of index or slice"); - e = new DollarExp(loc); - nextToken(); - break; - - case TOKdot: - // Signal global scope '.' operator with "" identifier - e = new IdentifierExp(loc, Id::empty); - break; - - case TOKthis: - e = new ThisExp(loc); - nextToken(); - break; - - case TOKsuper: - e = new SuperExp(loc); - nextToken(); - break; - - case TOKint32v: - e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32); - nextToken(); - break; - - case TOKuns32v: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32); - nextToken(); - break; - - case TOKint64v: - e = new IntegerExp(loc, token.int64value, Type::tint64); - nextToken(); - break; - - case TOKuns64v: - e = new IntegerExp(loc, token.uns64value, Type::tuns64); - nextToken(); - break; - - case TOKfloat32v: - e = new RealExp(loc, token.float80value, Type::tfloat32); - nextToken(); - break; - - case TOKfloat64v: - e = new RealExp(loc, token.float80value, Type::tfloat64); - nextToken(); - break; - - case TOKfloat80v: - e = new RealExp(loc, token.float80value, Type::tfloat80); - nextToken(); - break; - - case TOKimaginary32v: - e = new RealExp(loc, token.float80value, Type::timaginary32); - nextToken(); - break; - - case TOKimaginary64v: - e = new RealExp(loc, token.float80value, Type::timaginary64); - nextToken(); - break; - - case TOKimaginary80v: - e = new RealExp(loc, token.float80value, Type::timaginary80); - nextToken(); - break; - - case TOKnull: - e = new NullExp(loc); - nextToken(); - break; - -#if DMDV2 - case TOKfile: - { const char *s = loc.filename ? loc.filename : mod->ident->toChars(); - e = new StringExp(loc, (char *)s, strlen(s), 0); - nextToken(); - break; - } - - case TOKline: - e = new IntegerExp(loc, loc.linnum, Type::tint32); - nextToken(); - break; -#endif - - case TOKtrue: - e = new IntegerExp(loc, 1, Type::tbool); - nextToken(); - break; - - case TOKfalse: - e = new IntegerExp(loc, 0, Type::tbool); - nextToken(); - break; - - case TOKcharv: - e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar); - nextToken(); - break; - - case TOKwcharv: - e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar); - nextToken(); - break; - - case TOKdcharv: - e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar); - nextToken(); - break; - - case TOKstring: - { unsigned char *s; - unsigned len; - unsigned char postfix; - - // cat adjacent strings - s = token.ustring; - len = token.len; - postfix = token.postfix; - while (1) - { - nextToken(); - if (token.value == TOKstring) - { unsigned len1; - unsigned len2; - unsigned char *s2; - - if (token.postfix) - { if (token.postfix != postfix) - error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix); - postfix = token.postfix; - } - - len1 = len; - len2 = token.len; - len = len1 + len2; - s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char)); - memcpy(s2, s, len1 * sizeof(unsigned char)); - memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char)); - s = s2; - } - else - break; - } - e = new StringExp(loc, s, len, postfix); - break; - } - - case BASIC_TYPES_X(t): - nextToken(); - check(TOKdot, t->toChars()); - if (token.value != TOKidentifier) - { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars()); - goto Lerr; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - break; - - case TOKtypeof: - { - t = parseTypeof(); - e = new TypeExp(loc, t); - break; - } - - case TOKvector: - { - t = parseVector(); - e = new TypeExp(loc, t); - break; - } - - case TOKtypeid: - { - nextToken(); - check(TOKlparen, "typeid"); - Object *o; - if (isDeclaration(&token, 0, TOKreserved, NULL)) - { // argument is a type - o = parseType(); - } - else - { // argument is an expression - o = parseAssignExp(); - } - check(TOKrparen); - e = new TypeidExp(loc, o); - break; - } - -#if DMDV2 - case TOKtraits: - { /* __traits(identifier, args...) - */ - Identifier *ident; - Objects *args = NULL; - - nextToken(); - check(TOKlparen); - if (token.value != TOKidentifier) - { error("__traits(identifier, args...) expected"); - goto Lerr; - } - ident = token.ident; - nextToken(); - if (token.value == TOKcomma) - args = parseTemplateArgumentList2(); // __traits(identifier, args...) - else - check(TOKrparen); // __traits(identifier) - - e = new TraitsExp(loc, ident, args); - break; - } -#endif - - case TOKis: - { Type *targ; - Identifier *ident = NULL; - Type *tspec = NULL; - enum TOK tok = TOKreserved; - enum TOK tok2 = TOKreserved; - TemplateParameters *tpl = NULL; - Loc loc = this->loc; - - nextToken(); - if (token.value == TOKlparen) - { - nextToken(); - targ = parseType(&ident); - if (token.value == TOKcolon || token.value == TOKequal) - { - tok = token.value; - nextToken(); - if (tok == TOKequal && - (token.value == TOKtypedef || - token.value == TOKstruct || - token.value == TOKunion || - token.value == TOKclass || - token.value == TOKsuper || - token.value == TOKenum || - token.value == TOKinterface || - token.value == TOKargTypes || -#if DMDV2 - token.value == TOKconst && peek(&token)->value == TOKrparen || - token.value == TOKinvariant && peek(&token)->value == TOKrparen || - token.value == TOKimmutable && peek(&token)->value == TOKrparen || - token.value == TOKshared && peek(&token)->value == TOKrparen || - token.value == TOKwild && peek(&token)->value == TOKrparen || -#endif - token.value == TOKfunction || - token.value == TOKdelegate || - token.value == TOKreturn)) - { - if (token.value == TOKinvariant && !global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - tok2 = token.value; - nextToken(); - } - else - { - tspec = parseType(); - } - } - if (ident && tspec) - { - if (token.value == TOKcomma) - tpl = parseTemplateParameterList(1); - else - { tpl = new TemplateParameters(); - check(TOKrparen); - } - TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL); - tpl->insert(0, tp); - } - else - check(TOKrparen); - } - else - { error("(type identifier : specialization) expected following is"); - goto Lerr; - } - e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl); - break; - } - - case TOKassert: - { Expression *msg = NULL; - - nextToken(); - check(TOKlparen, "assert"); - e = parseAssignExp(); - if (token.value == TOKcomma) - { nextToken(); - msg = parseAssignExp(); - } - check(TOKrparen); - e = new AssertExp(loc, e, msg); - break; - } - - case TOKmixin: - { - nextToken(); - check(TOKlparen, "mixin"); - e = parseAssignExp(); - check(TOKrparen); - e = new CompileExp(loc, e); - break; - } - - case TOKimport: - { - nextToken(); - check(TOKlparen, "import"); - e = parseAssignExp(); - check(TOKrparen); - e = new FileExp(loc, e); - break; - } - - case TOKlparen: - { enum TOK past = peekPastParen(&token)->value; - - if (past == TOKgoesto) - { // (arguments) => expression - goto case_delegate; - } - else if (past == TOKlcurly) - { // (arguments) { statements... } - goto case_delegate; - } - // ( expression ) - nextToken(); - e = parseExpression(); - e->parens = 1; - check(loc, TOKrparen); - break; - } - - case TOKlbracket: - { /* Parse array literals and associative array literals: - * [ value, value, value ... ] - * [ key:value, key:value, key:value ... ] - */ - Expressions *values = new Expressions(); - Expressions *keys = NULL; - - nextToken(); - while (token.value != TOKrbracket && token.value != TOKeof) - { - Expression *e = parseAssignExp(); - if (token.value == TOKcolon && (keys || values->dim == 0)) - { nextToken(); - if (!keys) - keys = new Expressions(); - keys->push(e); - e = parseAssignExp(); - } - else if (keys) - { error("'key:value' expected for associative array literal"); - delete keys; - keys = NULL; - } - values->push(e); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - check(loc, TOKrbracket); - - if (keys) - e = new AssocArrayLiteralExp(loc, keys, values); - else - e = new ArrayLiteralExp(loc, values); - break; - } - - case TOKlcurly: - case TOKfunction: - case TOKdelegate: - case_delegate: - { - TemplateParameters *tpl = NULL; - Parameters *parameters = NULL; - int varargs = 0; - Type *tret = NULL; - StorageClass stc = 0; - enum TOK save = TOKreserved; - Loc loc = this->loc; - - switch (token.value) - { - case TOKfunction: - case TOKdelegate: - save = token.value; - nextToken(); - if (token.value != TOKlparen && token.value != TOKlcurly) - { // function type (parameters) { statements... } - // delegate type (parameters) { statements... } - tret = parseBasicType(); - tret = parseBasicType2(tret); // function return type - } - - if (token.value == TOKlparen) - { // function (parameters) { statements... } - // delegate (parameters) { statements... } - } - else - { // function { statements... } - // delegate { statements... } - break; - } - /* fall through to TOKlparen */ - - case TOKlparen: - Lparen: - { // (parameters) => expression - // (parameters) { statements... } - parameters = parseParameters(&varargs, &tpl); - stc = parsePostfix(); - if (stc & (STCconst | STCimmutable | STCshared | STCwild)) - error("const/immutable/shared/inout attributes are only valid for non-static member functions"); - break; - } - case TOKlcurly: - // { statements... } - break; - - case TOKidentifier: - { // identifier => expression - parameters = new Parameters(); - Identifier *id = Lexer::uniqueId("__T"); - Type *t = new TypeIdentifier(loc, id); - parameters->push(new Parameter(0, t, token.ident, NULL)); - - tpl = new TemplateParameters(); - TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL); - tpl->push(tp); - - nextToken(); - break; - } - default: - assert(0); - } - - if (!parameters) - parameters = new Parameters(); - TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc); - FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL); - - if (token.value == TOKgoesto) - { - check(TOKgoesto); - Loc loc = this->loc; - Expression *ae = parseAssignExp(); - fd->fbody = new ReturnStatement(loc, ae); - fd->endloc = this->loc; - } - else - { - parseContracts(fd); - } - - TemplateDeclaration *td = NULL; - if (tpl) - { // Wrap a template around function fd - Dsymbols *decldefs = new Dsymbols(); - decldefs->push(fd); - td = new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0); - td->literal = 1; // it's a template 'literal' - } - - e = new FuncExp(loc, fd, td); - break; - } - - default: - error("expression expected, not '%s'", token.toChars()); - Lerr: - // Anything for e, as long as it's not NULL - e = new IntegerExp(loc, 0, Type::tint32); - nextToken(); - break; - } - return e; -} - -Expression *Parser::parsePostExp(Expression *e) -{ - Loc loc; - - while (1) - { - loc = this->loc; - switch (token.value) - { - case TOKdot: - nextToken(); - if (token.value == TOKidentifier) - { Identifier *id = token.ident; - - nextToken(); - if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin) - { // identifier!(template-argument-list) - TemplateInstance *tempinst = new TemplateInstance(loc, id); - Objects *tiargs; - nextToken(); - if (token.value == TOKlparen) - // ident!(template_arguments) - tiargs = parseTemplateArgumentList(); - else - // ident!template_argument - tiargs = parseTemplateArgument(); - e = new DotTemplateInstanceExp(loc, e, id, tiargs); - } - else - e = new DotIdExp(loc, e, id); - continue; - } - else if (token.value == TOKnew) - { - e = parseNewExp(e); - continue; - } - else - error("identifier expected following '.', not '%s'", token.toChars()); - break; - - case TOKplusplus: - e = new PostExp(TOKplusplus, loc, e); - break; - - case TOKminusminus: - e = new PostExp(TOKminusminus, loc, e); - break; - - case TOKlparen: - e = new CallExp(loc, e, parseArguments()); - continue; - - case TOKlbracket: - { // array dereferences: - // array[index] - // array[] - // array[lwr .. upr] - Expression *index; - Expression *upr; - - inBrackets++; - nextToken(); - if (token.value == TOKrbracket) - { // array[] - inBrackets--; - e = new SliceExp(loc, e, NULL, NULL); - nextToken(); - } - else - { - index = parseAssignExp(); - if (token.value == TOKslice) - { // array[lwr .. upr] - nextToken(); - upr = parseAssignExp(); - e = new SliceExp(loc, e, index, upr); - } - else - { // array[index, i2, i3, i4, ...] - Expressions *arguments = new Expressions(); - arguments->push(index); - if (token.value == TOKcomma) - { - nextToken(); - while (token.value != TOKrbracket && token.value != TOKeof) - { - Expression *arg = parseAssignExp(); - arguments->push(arg); - if (token.value == TOKrbracket) - break; - check(TOKcomma); - } - } - e = new ArrayExp(loc, e, arguments); - } - check(TOKrbracket); - inBrackets--; - } - continue; - } - - default: - return e; - } - nextToken(); - } -} - -Expression *Parser::parseUnaryExp() -{ Expression *e; - Loc loc = this->loc; - - switch (token.value) - { - case TOKand: - nextToken(); - e = parseUnaryExp(); - e = new AddrExp(loc, e); - break; - - case TOKplusplus: - nextToken(); - e = parseUnaryExp(); - //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - e = new PreExp(TOKpreplusplus, loc, e); - break; - - case TOKminusminus: - nextToken(); - e = parseUnaryExp(); - //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32)); - e = new PreExp(TOKpreminusminus, loc, e); - break; - - case TOKmul: - nextToken(); - e = parseUnaryExp(); - e = new PtrExp(loc, e); - break; - - case TOKmin: - nextToken(); - e = parseUnaryExp(); - e = new NegExp(loc, e); - break; - - case TOKadd: - nextToken(); - e = parseUnaryExp(); - e = new UAddExp(loc, e); - break; - - case TOKnot: - nextToken(); - e = parseUnaryExp(); - e = new NotExp(loc, e); - break; - - case TOKtilde: - nextToken(); - e = parseUnaryExp(); - e = new ComExp(loc, e); - break; - - case TOKdelete: - nextToken(); - e = parseUnaryExp(); - e = new DeleteExp(loc, e); - break; - - case TOKnew: - e = parseNewExp(NULL); - break; - - case TOKcast: // cast(type) expression - { - nextToken(); - check(TOKlparen); - /* Look for cast(), cast(const), cast(immutable), - * cast(shared), cast(shared const), cast(wild), cast(shared wild) - */ - unsigned m; - if (token.value == TOKrparen) - { - m = 0; - goto Lmod1; - } - else if (token.value == TOKconst && peekNext() == TOKrparen) - { - m = MODconst; - goto Lmod2; - } - else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen) - { - if (token.value == TOKinvariant && !global.params.useDeprecated) - error("use of 'invariant' rather than 'immutable' is deprecated"); - m = MODimmutable; - goto Lmod2; - } - else if (token.value == TOKshared && peekNext() == TOKrparen) - { - m = MODshared; - goto Lmod2; - } - else if (token.value == TOKwild && peekNext() == TOKrparen) - { - m = MODwild; - goto Lmod2; - } - else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() == TOKrparen || - token.value == TOKshared && peekNext() == TOKwild && peekNext2() == TOKrparen) - { - m = MODshared | MODwild; - goto Lmod3; - } - else if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() == TOKrparen || - token.value == TOKshared && peekNext() == TOKconst && peekNext2() == TOKrparen) - { - m = MODshared | MODconst; - Lmod3: - nextToken(); - Lmod2: - nextToken(); - Lmod1: - nextToken(); - e = parseUnaryExp(); - e = new CastExp(loc, e, m); - } - else - { - Type *t = parseType(); // ( type ) - check(TOKrparen); - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - } - break; - } - - case TOKwild: - case TOKshared: - case TOKconst: - case TOKinvariant: - case TOKimmutable: // immutable(type)(arguments) - { - Type *t = parseBasicType(); - e = new TypeExp(loc, t); - if (token.value != TOKlparen) - { - error("(arguments) expected following %s", t->toChars()); - return e; - } - e = new CallExp(loc, e, parseArguments()); - break; - } - - - case TOKlparen: - { Token *tk; - - tk = peek(&token); -#if CCASTSYNTAX - // If cast - if (isDeclaration(tk, 0, TOKrparen, &tk)) - { - tk = peek(tk); // skip over right parenthesis - switch (tk->value) - { - case TOKnot: - tk = peek(tk); - if (tk->value == TOKis || tk->value == TOKin) // !is or !in - break; - case TOKdot: - case TOKplusplus: - case TOKminusminus: - case TOKdelete: - case TOKnew: - case TOKlparen: - case TOKidentifier: - case TOKthis: - case TOKsuper: - case TOKint32v: - case TOKuns32v: - case TOKint64v: - case TOKuns64v: - case TOKfloat32v: - case TOKfloat64v: - case TOKfloat80v: - case TOKimaginary32v: - case TOKimaginary64v: - case TOKimaginary80v: - case TOKnull: - case TOKtrue: - case TOKfalse: - case TOKcharv: - case TOKwcharv: - case TOKdcharv: - case TOKstring: -#if 0 - case TOKtilde: - case TOKand: - case TOKmul: - case TOKmin: - case TOKadd: -#endif - case TOKfunction: - case TOKdelegate: - case TOKtypeof: - case TOKvector: -#if DMDV2 - case TOKfile: - case TOKline: -#endif - case BASIC_TYPES: // (type)int.size - { // (type) una_exp - Type *t; - - nextToken(); - t = parseType(); - check(TOKrparen); - - // if .identifier - if (token.value == TOKdot) - { - nextToken(); - if (token.value != TOKidentifier) - { error("Identifier expected following (type)."); - return NULL; - } - e = typeDotIdExp(loc, t, token.ident); - nextToken(); - e = parsePostExp(e); - } - else - { - e = parseUnaryExp(); - e = new CastExp(loc, e, t); - error("C style cast illegal, use %s", e->toChars()); - } - return e; - } - } - } -#endif - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - default: - e = parsePrimaryExp(); - e = parsePostExp(e); - break; - } - assert(e); - - // ^^ is right associative and has higher precedence than the unary operators - while (token.value == TOKpow) - { - nextToken(); - Expression *e2 = parseUnaryExp(); - e = new PowExp(loc, e, e2); - } - - return e; -} - -Expression *Parser::parseMulExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseUnaryExp(); - while (1) - { - switch (token.value) - { - case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue; - case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue; - case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseAddExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseMulExp(); - while (1) - { - switch (token.value) - { - case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue; - case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue; - case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseShiftExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAddExp(); - while (1) - { - switch (token.value) - { - case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue; - case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue; - case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue; - - default: - break; - } - break; - } - return e; -} - -#if DMDV1 -Expression *Parser::parseRelExp() -{ Expression *e; - Expression *e2; - enum TOK op; - Loc loc = this->loc; - - e = parseShiftExp(); - while (1) - { - switch (token.value) - { - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - op = token.value; - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - continue; - - case TOKnot: // could be !in - if (peekNext() == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - continue; - } - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} -#endif - -#if DMDV1 -Expression *Parser::parseEqualExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseRelExp(); - while (1) - { enum TOK value = token.value; - - switch (value) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseRelExp(); - e = new EqualExp(value, loc, e, e2); - continue; - - case TOKidentity: - error("'===' is no longer legal, use 'is' instead"); - goto L1; - - case TOKnotidentity: - error("'!==' is no longer legal, use '!is' instead"); - goto L1; - - case TOKis: - value = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value != TOKis) - break; - nextToken(); - value = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseRelExp(); - e = new IdentityExp(value, loc, e, e2); - continue; - - default: - break; - } - break; - } - return e; -} -#endif - -Expression *Parser::parseCmpExp() -{ Expression *e; - Expression *e2; - Token *t; - Loc loc = this->loc; - - e = parseShiftExp(); - enum TOK op = token.value; - - switch (op) - { - case TOKequal: - case TOKnotequal: - nextToken(); - e2 = parseShiftExp(); - e = new EqualExp(op, loc, e, e2); - break; - - case TOKis: - op = TOKidentity; - goto L1; - - case TOKnot: - // Attempt to identify '!is' - t = peek(&token); - if (t->value == TOKin) - { - nextToken(); - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - e = new NotExp(loc, e); - break; - } - if (t->value != TOKis) - break; - nextToken(); - op = TOKnotidentity; - goto L1; - - L1: - nextToken(); - e2 = parseShiftExp(); - e = new IdentityExp(op, loc, e, e2); - break; - - case TOKlt: - case TOKle: - case TOKgt: - case TOKge: - case TOKunord: - case TOKlg: - case TOKleg: - case TOKule: - case TOKul: - case TOKuge: - case TOKug: - case TOKue: - nextToken(); - e2 = parseShiftExp(); - e = new CmpExp(op, loc, e, e2); - break; - - case TOKin: - nextToken(); - e2 = parseShiftExp(); - e = new InExp(loc, e, e2); - break; - - default: - break; - } - return e; -} - -Expression *Parser::parseAndExp() -{ - Loc loc = this->loc; - - Expression *e = parseCmpExp(); - while (token.value == TOKand) - { - checkParens(TOKand, e); - nextToken(); - Expression *e2 = parseCmpExp(); - checkParens(TOKand, e2); - e = new AndExp(loc,e,e2); - loc = this->loc; - } - return e; -} - -Expression *Parser::parseXorExp() -{ - Loc loc = this->loc; - - Expression *e = parseAndExp(); - while (token.value == TOKxor) - { - checkParens(TOKxor, e); - nextToken(); - Expression *e2 = parseAndExp(); - checkParens(TOKxor, e2); - e = new XorExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrExp() -{ - Loc loc = this->loc; - - Expression *e = parseXorExp(); - while (token.value == TOKor) - { - checkParens(TOKor, e); - nextToken(); - Expression *e2 = parseXorExp(); - checkParens(TOKor, e2); - e = new OrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseAndAndExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseOrExp(); - while (token.value == TOKandand) - { - nextToken(); - e2 = parseOrExp(); - e = new AndAndExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseOrOrExp() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - e = parseAndAndExp(); - while (token.value == TOKoror) - { - nextToken(); - e2 = parseAndAndExp(); - e = new OrOrExp(loc, e, e2); - } - return e; -} - -Expression *Parser::parseCondExp() -{ Expression *e; - Expression *e1; - Expression *e2; - Loc loc = this->loc; - - e = parseOrOrExp(); - if (token.value == TOKquestion) - { - nextToken(); - e1 = parseExpression(); - check(TOKcolon); - e2 = parseCondExp(); - e = new CondExp(loc, e, e1, e2); - } - return e; -} - -Expression *Parser::parseAssignExp() -{ Expression *e; - Expression *e2; - Loc loc; - - e = parseCondExp(); - while (1) - { - loc = this->loc; - switch (token.value) - { -#define X(tok,ector) \ - case tok: nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue; - - X(TOKassign, AssignExp); - X(TOKaddass, AddAssignExp); - X(TOKminass, MinAssignExp); - X(TOKmulass, MulAssignExp); - X(TOKdivass, DivAssignExp); - X(TOKmodass, ModAssignExp); - X(TOKpowass, PowAssignExp); - X(TOKandass, AndAssignExp); - X(TOKorass, OrAssignExp); - X(TOKxorass, XorAssignExp); - X(TOKshlass, ShlAssignExp); - X(TOKshrass, ShrAssignExp); - X(TOKushrass, UshrAssignExp); - X(TOKcatass, CatAssignExp); - -#undef X - default: - break; - } - break; - } - return e; -} - -Expression *Parser::parseExpression() -{ Expression *e; - Expression *e2; - Loc loc = this->loc; - - //printf("Parser::parseExpression() loc = %d\n", loc.linnum); - e = parseAssignExp(); - while (token.value == TOKcomma) - { - nextToken(); - e2 = parseAssignExp(); - e = new CommaExp(loc, e, e2); - loc = this->loc; - } - return e; -} - - -/************************* - * Collect argument list. - * Assume current token is ',', '(' or '['. - */ - -Expressions *Parser::parseArguments() -{ // function call - Expressions *arguments; - Expression *arg; - enum TOK endtok; - - arguments = new Expressions(); - if (token.value == TOKlbracket) - endtok = TOKrbracket; - else - endtok = TOKrparen; - - { - nextToken(); - while (token.value != endtok && token.value != TOKeof) - { - arg = parseAssignExp(); - arguments->push(arg); - if (token.value == endtok) - break; - check(TOKcomma); - } - check(endtok); - } - return arguments; -} - -/******************************************* - */ - -Expression *Parser::parseNewExp(Expression *thisexp) -{ Type *t; - Expressions *newargs; - Expressions *arguments = NULL; - Expression *e; - Loc loc = this->loc; - - nextToken(); - newargs = NULL; - if (token.value == TOKlparen) - { - newargs = parseArguments(); - } - - // An anonymous nested class starts with "class" - if (token.value == TOKclass) - { - nextToken(); - if (token.value == TOKlparen) - arguments = parseArguments(); - - BaseClasses *baseclasses = NULL; - if (token.value != TOKlcurly) - baseclasses = parseBaseClasses(); - - Identifier *id = NULL; - ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses); - - if (token.value != TOKlcurly) - { error("{ members } expected for anonymous class"); - cd->members = NULL; - } - else - { - nextToken(); - Dsymbols *decl = parseDeclDefs(0); - if (token.value != TOKrcurly) - error("class member expected"); - nextToken(); - cd->members = decl; - } - - e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments); - - return e; - } - - t = parseBasicType(); - t = parseBasicType2(t); - if (t->ty == Taarray) - { TypeAArray *taa = (TypeAArray *)t; - Type *index = taa->index; - - Expression *e = index->toExpression(); - if (e) - { arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(taa->next); - } - else - { - error("need size of rightmost array, not type %s", index->toChars()); - return new NullExp(loc); - } - } - else if (t->ty == Tsarray) - { - TypeSArray *tsa = (TypeSArray *)t; - Expression *e = tsa->dim; - - arguments = new Expressions(); - arguments->push(e); - t = new TypeDArray(tsa->next); - } - else if (token.value == TOKlparen) - { - arguments = parseArguments(); - } - e = new NewExp(loc, thisexp, newargs, t, arguments); - return e; -} - -/********************************************** - */ - -void Parser::addComment(Dsymbol *s, unsigned char *blockComment) -{ - s->addComment(combineComments(blockComment, token.lineComment)); - token.lineComment = NULL; -} - - -/********************************** - * Set operator precedence for each operator. - */ - -enum PREC precedence[TOKMAX]; - -void initPrecedence() -{ - for (size_t i = 0; i < TOKMAX; i++) - precedence[i] = PREC_zero; - - precedence[TOKtype] = PREC_expr; - precedence[TOKerror] = PREC_expr; - - precedence[TOKtypeof] = PREC_primary; - precedence[TOKmixin] = PREC_primary; - - precedence[TOKdotvar] = PREC_primary; - precedence[TOKimport] = PREC_primary; - precedence[TOKidentifier] = PREC_primary; - precedence[TOKthis] = PREC_primary; - precedence[TOKsuper] = PREC_primary; - precedence[TOKint64] = PREC_primary; - precedence[TOKfloat64] = PREC_primary; - precedence[TOKcomplex80] = PREC_primary; - precedence[TOKnull] = PREC_primary; - precedence[TOKstring] = PREC_primary; - precedence[TOKarrayliteral] = PREC_primary; - precedence[TOKassocarrayliteral] = PREC_primary; -#if DMDV2 - precedence[TOKfile] = PREC_primary; - precedence[TOKline] = PREC_primary; -#endif - precedence[TOKtypeid] = PREC_primary; - precedence[TOKis] = PREC_primary; - precedence[TOKassert] = PREC_primary; - precedence[TOKhalt] = PREC_primary; - precedence[TOKtemplate] = PREC_primary; - precedence[TOKdsymbol] = PREC_primary; - precedence[TOKfunction] = PREC_primary; - precedence[TOKvar] = PREC_primary; - precedence[TOKsymoff] = PREC_primary; - precedence[TOKstructliteral] = PREC_primary; - precedence[TOKarraylength] = PREC_primary; - precedence[TOKremove] = PREC_primary; - precedence[TOKtuple] = PREC_primary; -#if DMDV2 - precedence[TOKtraits] = PREC_primary; - precedence[TOKdefault] = PREC_primary; - precedence[TOKoverloadset] = PREC_primary; -#endif - - // post - precedence[TOKdotti] = PREC_primary; - precedence[TOKdot] = PREC_primary; - precedence[TOKdottd] = PREC_primary; - precedence[TOKdotexp] = PREC_primary; - precedence[TOKdottype] = PREC_primary; -// precedence[TOKarrow] = PREC_primary; - precedence[TOKplusplus] = PREC_primary; - precedence[TOKminusminus] = PREC_primary; -#if DMDV2 - precedence[TOKpreplusplus] = PREC_primary; - precedence[TOKpreminusminus] = PREC_primary; -#endif - precedence[TOKcall] = PREC_primary; - precedence[TOKslice] = PREC_primary; - precedence[TOKarray] = PREC_primary; - precedence[TOKindex] = PREC_primary; - - precedence[TOKdelegate] = PREC_unary; - precedence[TOKaddress] = PREC_unary; - precedence[TOKstar] = PREC_unary; - precedence[TOKneg] = PREC_unary; - precedence[TOKuadd] = PREC_unary; - precedence[TOKnot] = PREC_unary; - precedence[TOKtobool] = PREC_add; - precedence[TOKtilde] = PREC_unary; - precedence[TOKdelete] = PREC_unary; - precedence[TOKnew] = PREC_unary; - precedence[TOKnewanonclass] = PREC_unary; - precedence[TOKcast] = PREC_unary; - -#if DMDV2 - precedence[TOKvector] = PREC_unary; - precedence[TOKpow] = PREC_pow; -#endif - - precedence[TOKmul] = PREC_mul; - precedence[TOKdiv] = PREC_mul; - precedence[TOKmod] = PREC_mul; - - precedence[TOKadd] = PREC_add; - precedence[TOKmin] = PREC_add; - precedence[TOKcat] = PREC_add; - - precedence[TOKshl] = PREC_shift; - precedence[TOKshr] = PREC_shift; - precedence[TOKushr] = PREC_shift; - - precedence[TOKlt] = PREC_rel; - precedence[TOKle] = PREC_rel; - precedence[TOKgt] = PREC_rel; - precedence[TOKge] = PREC_rel; - precedence[TOKunord] = PREC_rel; - precedence[TOKlg] = PREC_rel; - precedence[TOKleg] = PREC_rel; - precedence[TOKule] = PREC_rel; - precedence[TOKul] = PREC_rel; - precedence[TOKuge] = PREC_rel; - precedence[TOKug] = PREC_rel; - precedence[TOKue] = PREC_rel; - precedence[TOKin] = PREC_rel; - -#if 0 - precedence[TOKequal] = PREC_equal; - precedence[TOKnotequal] = PREC_equal; - precedence[TOKidentity] = PREC_equal; - precedence[TOKnotidentity] = PREC_equal; -#else - /* Note that we changed precedence, so that < and != have the same - * precedence. This change is in the parser, too. - */ - precedence[TOKequal] = PREC_rel; - precedence[TOKnotequal] = PREC_rel; - precedence[TOKidentity] = PREC_rel; - precedence[TOKnotidentity] = PREC_rel; -#endif - - precedence[TOKand] = PREC_and; - - precedence[TOKxor] = PREC_xor; - - precedence[TOKor] = PREC_or; - - precedence[TOKandand] = PREC_andand; - - precedence[TOKoror] = PREC_oror; - - precedence[TOKquestion] = PREC_cond; - - precedence[TOKassign] = PREC_assign; - precedence[TOKconstruct] = PREC_assign; - precedence[TOKblit] = PREC_assign; - precedence[TOKaddass] = PREC_assign; - precedence[TOKminass] = PREC_assign; - precedence[TOKcatass] = PREC_assign; - precedence[TOKmulass] = PREC_assign; - precedence[TOKdivass] = PREC_assign; - precedence[TOKmodass] = PREC_assign; -#if DMDV2 - precedence[TOKpowass] = PREC_assign; -#endif - precedence[TOKshlass] = PREC_assign; - precedence[TOKshrass] = PREC_assign; - precedence[TOKushrass] = PREC_assign; - precedence[TOKandass] = PREC_assign; - precedence[TOKorass] = PREC_assign; - precedence[TOKxorass] = PREC_assign; - - precedence[TOKcomma] = PREC_expr; - precedence[TOKdeclaration] = PREC_expr; -} - - diff --git a/dmd2/parse.h b/dmd2/parse.h deleted file mode 100644 index 716e775a..00000000 --- a/dmd2/parse.h +++ /dev/null @@ -1,187 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_PARSE_H -#define DMD_PARSE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "arraytypes.h" -#include "lexer.h" -#include "enum.h" - -struct Type; -struct TypeQualified; -struct Expression; -struct Declaration; -struct Statement; -struct Import; -struct Initializer; -struct FuncDeclaration; -struct CtorDeclaration; -struct PostBlitDeclaration; -struct DtorDeclaration; -struct StaticCtorDeclaration; -struct StaticDtorDeclaration; -struct SharedStaticCtorDeclaration; -struct SharedStaticDtorDeclaration; -struct ConditionalDeclaration; -struct InvariantDeclaration; -struct UnitTestDeclaration; -struct NewDeclaration; -struct DeleteDeclaration; -struct Condition; -struct Module; -struct ModuleDeclaration; -struct TemplateDeclaration; -struct TemplateInstance; -struct StaticAssert; - -/************************************ - * These control how parseStatement() works. - */ - -enum ParseStatementFlags -{ - PSsemi = 1, // empty ';' statements are allowed, but deprecated - PSscope = 2, // start a new scope - PScurly = 4, // { } statement is required - PScurlyscope = 8, // { } starts a new scope - PSsemi_ok = 0x10, // empty ';' are really ok -}; - - -struct Parser : Lexer -{ - ModuleDeclaration *md; - enum LINK linkage; - Loc endloc; // set to location of last right curly - int inBrackets; // inside [] of array index or slice - Loc lookingForElse; // location of lonely if looking for an else - - Parser(Module *module, unsigned char *base, unsigned length, int doDocComment); - - Dsymbols *parseModule(); - Dsymbols *parseDeclDefs(int once); - Dsymbols *parseAutoDeclarations(StorageClass storageClass, unsigned char *comment); - Dsymbols *parseBlock(); - void composeStorageClass(StorageClass stc); - StorageClass parseAttribute(); - StorageClass parsePostfix(); - Expression *parseConstraint(); - TemplateDeclaration *parseTemplateDeclaration(int ismixin); - TemplateParameters *parseTemplateParameterList(int flag = 0); - Dsymbol *parseMixin(); - Objects *parseTemplateArgumentList(); - Objects *parseTemplateArgumentList2(); - Objects *parseTemplateArgument(); - StaticAssert *parseStaticAssert(); - TypeQualified *parseTypeof(); - Type *parseVector(); - enum LINK parseLinkage(); - Condition *parseDebugCondition(); - Condition *parseVersionCondition(); - Condition *parseStaticIfCondition(); - Dsymbol *parseCtor(); - PostBlitDeclaration *parsePostBlit(); - DtorDeclaration *parseDtor(); - StaticCtorDeclaration *parseStaticCtor(); - StaticDtorDeclaration *parseStaticDtor(); - SharedStaticCtorDeclaration *parseSharedStaticCtor(); - SharedStaticDtorDeclaration *parseSharedStaticDtor(); - InvariantDeclaration *parseInvariant(); - UnitTestDeclaration *parseUnitTest(); - NewDeclaration *parseNew(); - DeleteDeclaration *parseDelete(); - Parameters *parseParameters(int *pvarargs, TemplateParameters **tpl = NULL); - EnumDeclaration *parseEnum(); - Dsymbol *parseAggregate(); - BaseClasses *parseBaseClasses(); - Import *parseImport(Dsymbols *decldefs, int isstatic); - Type *parseType(Identifier **pident = NULL, TemplateParameters **tpl = NULL); - Type *parseBasicType(); - Type *parseBasicType2(Type *t); - Type *parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl = NULL, StorageClass storage_class = 0, int* pdisable = NULL); - Dsymbols *parseDeclarations(StorageClass storage_class, unsigned char *comment); - void parseContracts(FuncDeclaration *f); - void checkDanglingElse(Loc elseloc); - Statement *parseStatement(int flags); - Initializer *parseInitializer(); - Expression *parseDefaultInitExp(); - void check(Loc loc, enum TOK value); - void check(enum TOK value); - void check(enum TOK value, const char *string); - void checkParens(enum TOK value, Expression *e); - int isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt); - int isBasicType(Token **pt); - int isDeclarator(Token **pt, int *haveId, enum TOK endtok); - int isParameters(Token **pt); - int isExpression(Token **pt); - int isTemplateInstance(Token *t, Token **pt); - int skipParens(Token *t, Token **pt); - int skipAttributes(Token *t, Token **pt); - - Expression *parseExpression(); - Expression *parsePrimaryExp(); - Expression *parseUnaryExp(); - Expression *parsePostExp(Expression *e); - Expression *parseMulExp(); - Expression *parseAddExp(); - Expression *parseShiftExp(); -#if DMDV1 - Expression *parseRelExp(); - Expression *parseEqualExp(); -#endif - Expression *parseCmpExp(); - Expression *parseAndExp(); - Expression *parseXorExp(); - Expression *parseOrExp(); - Expression *parseAndAndExp(); - Expression *parseOrOrExp(); - Expression *parseCondExp(); - Expression *parseAssignExp(); - - Expressions *parseArguments(); - - Expression *parseNewExp(Expression *thisexp); - - void addComment(Dsymbol *s, unsigned char *blockComment); -}; - -// Operator precedence - greater values are higher precedence - -enum PREC -{ - PREC_zero, - PREC_expr, - PREC_assign, - PREC_cond, - PREC_oror, - PREC_andand, - PREC_or, - PREC_xor, - PREC_and, - PREC_equal, - PREC_rel, - PREC_shift, - PREC_add, - PREC_mul, - PREC_pow, - PREC_unary, - PREC_primary, -}; - -extern enum PREC precedence[TOKMAX]; - -void initPrecedence(); - -#endif /* DMD_PARSE_H */ diff --git a/dmd2/readme.txt b/dmd2/readme.txt deleted file mode 100644 index 5f2f1516..00000000 --- a/dmd2/readme.txt +++ /dev/null @@ -1,24 +0,0 @@ - - The D Programming Language - Compiler Front End Source - Copyright (c) 1999-2009, by Digital Mars - http://www.digitalmars.com - All Rights Reserved - - -This is the source code to the front end Digital Mars D compiler. -It covers the lexical analysis, parsing, and semantic analysis -of the D Programming Language defined in the documents at -http://www.digitalmars.com/d/ - -These sources are free, they are redistributable and modifiable -under the terms of the GNU General Public License (attached as gpl.txt), -or the Artistic License (attached as artistic.txt). - -The optimizer and code generator sources are -covered under a separate license, backendlicense.txt. - -It does not apply to anything else distributed by Digital Mars, -including D compiler executables. - --Walter Bright diff --git a/dmd2/root/aav.c b/dmd2/root/aav.c deleted file mode 100644 index ca685d42..00000000 --- a/dmd2/root/aav.c +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Implementation of associative arrays. - * - */ - -#include -#include -#include - -#include "aav.h" - -static const size_t prime_list[] = { - 31UL, - 97UL, 389UL, - 1543UL, 6151UL, - 24593UL, 98317UL, - 393241UL, 1572869UL, - 6291469UL, 25165843UL, - 100663319UL, 402653189UL, - 1610612741UL, 4294967291UL, -}; - -struct aaA -{ - aaA *next; - Key key; - Value value; -}; - -struct AA -{ - aaA* *b; - size_t b_length; - size_t nodes; // total number of aaA nodes - aaA* binit[4]; // initial value of b[] -}; - -static const AA bbinit = { NULL, }; - -/**************************************************** - * Determine number of entries in associative array. - */ - -size_t _aaLen(AA* aa) -{ - return aa ? aa->nodes : 0; -} - - -/************************************************* - * Get pointer to value in associative array indexed by key. - * Add entry for key if it is not already there. - */ - -Value* _aaGet(AA** paa, Key key) -{ - //printf("paa = %p\n", paa); - - if (!*paa) - { AA *a = new AA(); - *a = bbinit; - a->b = a->binit; - a->b_length = sizeof(a->binit) / sizeof(a->binit[0]); - *paa = a; - assert((*paa)->b_length == 4); - } - //printf("paa = %p, *paa = %p\n", paa, *paa); - - assert((*paa)->b_length); - size_t i = (size_t)key % (*paa)->b_length; - aaA** pe = &(*paa)->b[i]; - aaA *e; - while ((e = *pe) != NULL) - { - if (key == e->key) - return &e->value; - pe = &e->next; - } - - // Not found, create new elem - //printf("create new one\n"); - e = new aaA(); - e->next = NULL; - e->key = key; - e->value = NULL; - *pe = e; - - size_t nodes = ++(*paa)->nodes; - //printf("length = %d, nodes = %d\n", paa.a.b.length, nodes); - if (nodes > (*paa)->b_length * 4) - { - //printf("rehash\n"); - _aaRehash(paa); - } - - return &e->value; -} - - -/************************************************* - * Get value in associative array indexed by key. - * Returns NULL if it is not already there. - */ - -Value _aaGetRvalue(AA* aa, Key key) -{ - //printf("_aaGetRvalue(key = %p)\n", key); - if (!aa) - return NULL; - - size_t len = aa->b_length; - - if (len) - { - size_t i = (size_t)key % len; - aaA* e = aa->b[i]; - while (e) - { - if (key == e->key) - return e->value; - e = e->next; - } - } - return NULL; // not found -} - - -/******************************************** - * Rehash an array. - */ - -void _aaRehash(AA** paa) -{ - //printf("Rehash\n"); - if (*paa) - { - AA newb = bbinit; - AA *aa = *paa; - size_t len = _aaLen(*paa); - if (len) - { size_t i; - - for (i = 0; i < sizeof(prime_list)/sizeof(prime_list[0]) - 1; i++) - { - if (len <= prime_list[i]) - break; - } - len = prime_list[i]; - newb.b = new aaA*[len]; - memset(newb.b, 0, len * sizeof(aaA*)); - newb.b_length = len; - - for (size_t k = 0; k < aa->b_length; k++) - { aaA *e = aa->b[k]; - while (e) - { aaA* enext = e->next; - size_t j = (size_t)e->key % len; - e->next = newb.b[j]; - newb.b[j] = e; - e = enext; - } - } - if (aa->b != aa->binit) - delete[] aa->b; - - newb.nodes = aa->nodes; - } - - **paa = newb; - } -} - - -#if UNITTEST - -void unittest_aa() -{ - AA* aa = NULL; - Value v = _aaGetRvalue(aa, NULL); - assert(!v); - Value *pv = _aaGet(&aa, NULL); - assert(pv); - *pv = (void *)3; - v = _aaGetRvalue(aa, NULL); - assert(v == (void *)3); -} - -#endif diff --git a/dmd2/root/aav.h b/dmd2/root/aav.h deleted file mode 100644 index 266b5a83..00000000 --- a/dmd2/root/aav.h +++ /dev/null @@ -1,11 +0,0 @@ - -typedef void* Value; -typedef void* Key; - -struct AA; - -size_t _aaLen(AA* aa); -Value* _aaGet(AA** aa, Key key); -Value _aaGetRvalue(AA* aa, Key key); -void _aaRehash(AA** paa); - diff --git a/dmd2/root/array.c b/dmd2/root/array.c deleted file mode 100644 index f3440445..00000000 --- a/dmd2/root/array.c +++ /dev/null @@ -1,257 +0,0 @@ - -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER || __MINGW32__ -#include -#endif - -#if IN_GCC -#include "gdc_alloca.h" -#endif - -#if _WIN32 -#include -#endif - -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "dchar.h" -#include "rmem.h" - - -/********************************* Array ****************************/ - -Array::Array() -{ - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - dim = 0; - allocdim = SMALLARRAYCAP; -} - -Array::~Array() -{ - if (data != &smallarray[0]) - mem.free(data); -} - -void Array::mark() -{ unsigned u; - - mem.mark(data); - for (u = 0; u < dim; u++) - mem.mark(data[u]); // BUG: what if arrays of Object's? -} - -void Array::reserve(unsigned nentries) -{ - //printf("Array::reserve: dim = %d, allocdim = %d, nentries = %d\n", dim, allocdim, nentries); - if (allocdim - dim < nentries) - { - if (allocdim == 0) - { // Not properly initialized, someone memset it to zero - if (nentries <= SMALLARRAYCAP) - { allocdim = SMALLARRAYCAP; - data = SMALLARRAYCAP ? &smallarray[0] : NULL; - } - else - { allocdim = nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - } - } - else if (allocdim == SMALLARRAYCAP) - { - allocdim = dim + nentries; - data = (void **)mem.malloc(allocdim * sizeof(*data)); - memcpy(data, &smallarray[0], dim * sizeof(*data)); - } - else - { allocdim = dim + nentries; - data = (void **)mem.realloc(data, allocdim * sizeof(*data)); - } - } -} - -void Array::setDim(unsigned newdim) -{ - if (dim < newdim) - { - reserve(newdim - dim); - } - dim = newdim; -} - -void Array::fixDim() -{ - if (dim != allocdim) - { - if (allocdim >= SMALLARRAYCAP) - { - if (dim <= SMALLARRAYCAP) - { - memcpy(&smallarray[0], data, dim * sizeof(*data)); - mem.free(data); - } - else - data = (void **)mem.realloc(data, dim * sizeof(*data)); - } - allocdim = dim; - } -} - -void Array::push(void *ptr) -{ - reserve(1); - data[dim++] = ptr; -} - -void *Array::pop() -{ - return data[--dim]; -} - -void Array::shift(void *ptr) -{ - reserve(1); - memmove(data + 1, data, dim * sizeof(*data)); - data[0] = ptr; - dim++; -} - -void Array::insert(unsigned index, void *ptr) -{ - reserve(1); - memmove(data + index + 1, data + index, (dim - index) * sizeof(*data)); - data[index] = ptr; - dim++; -} - - -void Array::insert(unsigned index, Array *a) -{ - if (a) - { unsigned d; - - d = a->dim; - reserve(d); - if (dim != index) - memmove(data + index + d, data + index, (dim - index) * sizeof(*data)); - memcpy(data + index, a->data, d * sizeof(*data)); - dim += d; - } -} - - -/*********************************** - * Append array a to this array. - */ - -void Array::append(Array *a) -{ - insert(dim, a); -} - -void Array::remove(unsigned i) -{ - if (dim - i - 1) - memmove(data + i, data + i + 1, (dim - i - 1) * sizeof(data[0])); - dim--; -} - -char *Array::toChars() -{ - unsigned len; - unsigned u; - char **buf; - char *str; - char *p; - - buf = (char **)malloc(dim * sizeof(char *)); - assert(buf); - len = 2; - for (u = 0; u < dim; u++) - { - buf[u] = ((Object *)data[u])->toChars(); - len += strlen(buf[u]) + 1; - } - str = (char *)mem.malloc(len); - - str[0] = '['; - p = str + 1; - for (u = 0; u < dim; u++) - { - if (u) - *p++ = ','; - len = strlen(buf[u]); - memcpy(p,buf[u],len); - p += len; - } - *p++ = ']'; - *p = 0; - free(buf); - return str; -} - -void Array::zero() -{ - memset(data,0,dim * sizeof(data[0])); -} - -void *Array::tos() -{ - return dim ? data[dim - 1] : NULL; -} - -int -#if _WIN32 - __cdecl -#endif - Array_sort_compare(const void *x, const void *y) -{ - Object *ox = *(Object **)x; - Object *oy = *(Object **)y; - - return ox->compare(oy); -} - -void Array::sort() -{ - if (dim) - { - qsort(data, dim, sizeof(Object *), Array_sort_compare); - } -} - -Array *Array::copy() -{ - Array *a = new Array(); - - a->setDim(dim); - memcpy(a->data, data, dim * sizeof(void *)); - return a; -} - diff --git a/dmd2/root/async.c b/dmd2/root/async.c deleted file mode 100644 index 78f17c68..00000000 --- a/dmd2/root/async.c +++ /dev/null @@ -1,325 +0,0 @@ - -#define _MT 1 - -#include -#include -#include - -#if _WIN32 - -#include -#include -#include - -#include "root.h" - -static unsigned __stdcall startthread(void *p); - -struct FileData -{ - File *file; - int result; - HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ - //printf("aw->filesdim = %p %d\n", this, filesdim); - if (filesdim) - { - unsigned threadaddr; - hThread = (HANDLE) _beginthreadex(NULL, - 0, - &startthread, - this, - 0, - (unsigned *)&threadaddr); - - if (hThread) - { - SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST); - } - else - { - assert(0); - } - } -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - WaitForSingleObject(f->event, INFINITE); - Sleep(0); // give up time slice - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - free(aw); -} - - - -unsigned __stdcall startthread(void *p) -{ - AsyncRead *aw = (AsyncRead *)p; - - //printf("aw->filesdim = %p %d\n", aw, aw->filesdim); - for (size_t i = 0; i < aw->filesdim; i++) - { FileData *f = &aw->files[i]; - - f->result = f->file->read(); - SetEvent(f->event); - } - _endthreadex(EXIT_SUCCESS); - return EXIT_SUCCESS; // if skidding -} - -#elif linux // Posix - -#include -#include -#include - -#include "root.h" - -void *startthread(void *arg); - -void err_abort(int status, const char *msg) -{ - fprintf(stderr, "fatal error = %d, %s\n", status, msg); - exit(EXIT_FAILURE); -} - -struct FileData -{ - File *file; - int result; - - pthread_mutex_t mutex; - pthread_cond_t cond; - int value; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - FileData *f = &files[filesdim]; - f->file = file; - - int status = pthread_mutex_init(&f->mutex, NULL); - if (status != 0) - err_abort(status, "init mutex"); - status = pthread_cond_init(&f->cond, NULL); - if (status != 0) - err_abort(status, "init cond"); - - filesdim++; -} - -void AsyncRead::start() -{ - //printf("aw->filesdim = %p %d\n", this, filesdim); - if (filesdim) - { - pthread_t thread_id; - int status = pthread_create(&thread_id, - NULL, - &startthread, - this); - if (status != 0) - err_abort(status, "create thread"); - } -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - - // Wait for the event - int status = pthread_mutex_lock(&f->mutex); - if (status != 0) - err_abort(status, "lock mutex"); - while (f->value == 0) - { - status = pthread_cond_wait(&f->cond, &f->mutex); - if (status != 0) - err_abort(status, "wait on condition"); - } - status = pthread_mutex_unlock(&f->mutex); - if (status != 0) - err_abort(status, "unlock mutex"); - - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - //printf("AsyncRead::dispose()\n"); - for (int i = 0; i < aw->filesdim; i++) - { - FileData *f = &aw->files[i]; - int status = pthread_cond_destroy(&f->cond); - if (status != 0) - err_abort(status, "cond destroy"); - status = pthread_mutex_destroy(&f->mutex); - if (status != 0) - err_abort(status, "mutex destroy"); - } - free(aw); -} - - -void *startthread(void *p) -{ - AsyncRead *aw = (AsyncRead *)p; - - //printf("startthread: aw->filesdim = %p %d\n", aw, aw->filesdim); - size_t dim = aw->filesdim; - for (size_t i = 0; i < dim; i++) - { FileData *f = &aw->files[i]; - - f->result = f->file->read(); - - // Set event - int status = pthread_mutex_lock(&f->mutex); - if (status != 0) - err_abort(status, "lock mutex"); - f->value = 1; - status = pthread_cond_signal(&f->cond); - if (status != 0) - err_abort(status, "signal condition"); - status = pthread_mutex_unlock(&f->mutex); - if (status != 0) - err_abort(status, "unlock mutex"); - } - - return NULL; // end thread -} - -#else - -#include -#include - -#include "root.h" - -struct FileData -{ - File *file; - int result; - //HANDLE event; -}; - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); - - //HANDLE hThread; - - size_t filesdim; - size_t filesmax; - FileData files[1]; -}; - - -AsyncRead *AsyncRead::create(size_t nfiles) -{ - AsyncRead *aw = (AsyncRead *)calloc(1, sizeof(AsyncRead) + - (nfiles - 1) * sizeof(FileData)); - aw->filesmax = nfiles; - return aw; -} - -void AsyncRead::addFile(File *file) -{ - //printf("addFile(file = %p)\n", file); - //printf("filesdim = %d, filesmax = %d\n", filesdim, filesmax); - assert(filesdim < filesmax); - files[filesdim].file = file; - //files[filesdim].event = CreateEvent(NULL, TRUE, FALSE, NULL); - //ResetEvent(files[filesdim].event); - filesdim++; -} - -void AsyncRead::start() -{ -} - -int AsyncRead::read(size_t i) -{ - FileData *f = &files[i]; - f->result = f->file->read(); - return f->result; -} - -void AsyncRead::dispose(AsyncRead *aw) -{ - free(aw); -} - -#endif diff --git a/dmd2/root/async.h b/dmd2/root/async.h deleted file mode 100644 index 6f25f367..00000000 --- a/dmd2/root/async.h +++ /dev/null @@ -1,33 +0,0 @@ - -// Copyright (c) 2009-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef ASYNC_H -#define ASYNC_H - -#if __DMC__ -#pragma once -#endif - - -/******************* - * Simple interface to read files asynchronously in another - * thread. - */ - -struct AsyncRead -{ - static AsyncRead *create(size_t nfiles); - void addFile(File *file); - void start(); - int read(size_t i); - static void dispose(AsyncRead *); -}; - - -#endif diff --git a/dmd2/root/dchar.c b/dmd2/root/dchar.c deleted file mode 100644 index 0b11a8a4..00000000 --- a/dmd2/root/dchar.c +++ /dev/null @@ -1,482 +0,0 @@ - -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include -#include - -#include "dchar.h" -#include "rmem.h" - -#if M_UNICODE - -// Converts a char string to Unicode - -dchar *Dchar::dup(char *p) -{ - dchar *s; - size_t len; - - if (!p) - return NULL; - len = strlen(p); - s = (dchar *)mem.malloc((len + 1) * sizeof(dchar)); - for (unsigned i = 0; i < len; i++) - { - s[i] = (dchar)(p[i] & 0xFF); - } - s[len] = 0; - return s; -} - -dchar *Dchar::memchr(dchar *p, int c, int count) -{ - int u; - - for (u = 0; u < count; u++) - { - if (p[u] == c) - return p + u; - } - return NULL; -} - -#if _WIN32 && __DMC__ -__declspec(naked) -unsigned Dchar::calcHash(const dchar *str, unsigned len) -{ - __asm - { - mov ECX,4[ESP] - mov EDX,8[ESP] - xor EAX,EAX - test EDX,EDX - je L92 - -LC8: cmp EDX,1 - je L98 - cmp EDX,2 - je LAE - - add EAX,[ECX] -// imul EAX,EAX,025h - lea EAX,[EAX][EAX*8] - add ECX,4 - sub EDX,2 - jmp LC8 - -L98: mov DX,[ECX] - and EDX,0FFFFh - add EAX,EDX - ret - -LAE: add EAX,[ECX] -L92: ret - } -} -#else -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - unsigned hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str; - return hash; - - case 2: - hash += *(const uint32_t *)str; - return hash; - - default: - hash += *(const uint32_t *)str; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} -#endif - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash += *(const uint16_t *)str | 0x20; - return hash; - - case 2: - hash += *(const uint32_t *)str | 0x200020; - return hash; - - default: - hash += *(const uint32_t *)str | 0x200020; - hash *= 37; - str += 2; - len -= 2; - break; - } - } -} - -#elif MCBS - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -#elif UTF8 - -// Specification is: http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335 - -char Dchar::mblen[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1, -}; - -dchar *Dchar::dec(dchar *pstart, dchar *p) -{ - while ((p[-1] & 0xC0) == 0x80) - p--; - return p; -} - -int Dchar::get(dchar *p) -{ - unsigned c; - unsigned char *q = (unsigned char *)p; - - c = q[0]; - switch (mblen[c]) - { - case 2: - c = ((c - 0xC0) << 6) | - (q[1] - 0x80); - break; - - case 3: - c = ((c - 0xE0) << 12) | - ((q[1] - 0x80) << 6) | - (q[2] - 0x80); - break; - - case 4: - c = ((c - 0xF0) << 18) | - ((q[1] - 0x80) << 12) | - ((q[2] - 0x80) << 6) | - (q[3] - 0x80); - break; - - case 5: - c = ((c - 0xF8) << 24) | - ((q[1] - 0x80) << 18) | - ((q[2] - 0x80) << 12) | - ((q[3] - 0x80) << 6) | - (q[4] - 0x80); - break; - - case 6: - c = ((c - 0xFC) << 30) | - ((q[1] - 0x80) << 24) | - ((q[2] - 0x80) << 18) | - ((q[3] - 0x80) << 12) | - ((q[4] - 0x80) << 6) | - (q[5] - 0x80); - break; - } - return c; -} - -dchar *Dchar::put(dchar *p, unsigned c) -{ - if (c <= 0x7F) - { - *p++ = c; - } - else if (c <= 0x7FF) - { - p[0] = 0xC0 + (c >> 6); - p[1] = 0x80 + (c & 0x3F); - p += 2; - } - else if (c <= 0xFFFF) - { - p[0] = 0xE0 + (c >> 12); - p[1] = 0x80 + ((c >> 6) & 0x3F); - p[2] = 0x80 + (c & 0x3F); - p += 3; - } - else if (c <= 0x1FFFFF) - { - p[0] = 0xF0 + (c >> 18); - p[1] = 0x80 + ((c >> 12) & 0x3F); - p[2] = 0x80 + ((c >> 6) & 0x3F); - p[3] = 0x80 + (c & 0x3F); - p += 4; - } - else if (c <= 0x3FFFFFF) - { - p[0] = 0xF8 + (c >> 24); - p[1] = 0x80 + ((c >> 18) & 0x3F); - p[2] = 0x80 + ((c >> 12) & 0x3F); - p[3] = 0x80 + ((c >> 6) & 0x3F); - p[4] = 0x80 + (c & 0x3F); - p += 5; - } - else if (c <= 0x7FFFFFFF) - { - p[0] = 0xFC + (c >> 30); - p[1] = 0x80 + ((c >> 24) & 0x3F); - p[2] = 0x80 + ((c >> 18) & 0x3F); - p[3] = 0x80 + ((c >> 12) & 0x3F); - p[4] = 0x80 + ((c >> 6) & 0x3F); - p[5] = 0x80 + (c & 0x3F); - p += 6; - } - else - assert(0); // not a UCS-4 character - return p; -} - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - - str += 4; - len -= 4; - break; - } - } -} - -#else // ascii - -hash_t Dchar::calcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str; - return hash; - - case 2: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint16_t *)str; -#else - hash += str[0] * 256 + str[1]; -#endif - return hash; - - case 3: - hash *= 37; -#if LITTLE_ENDIAN - hash += (*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]; -#else - hash += (str[0] * 256 + str[1]) * 256 + str[2]; -#endif - return hash; - - default: - hash *= 37; -#if LITTLE_ENDIAN - hash += *(const uint32_t *)str; -#else - hash += ((str[0] * 256 + str[1]) * 256 + str[2]) * 256 + str[3]; -#endif - str += 4; - len -= 4; - break; - } - } -} - -hash_t Dchar::icalcHash(const dchar *str, size_t len) -{ - hash_t hash = 0; - - while (1) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(const uint8_t *)str | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(const uint16_t *)str | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(const uint16_t *)str << 8) + - ((const uint8_t *)str)[2]) | 0x202020; - return hash; - - default: - hash *= 37; - hash += *(const uint32_t *)str | 0x20202020; - str += 4; - len -= 4; - break; - } - } -} - -#endif - -#if 0 -#include - -void main() -{ - // Print out values to hardcode into Dchar::mblen[] - int c; - int s; - - for (c = 0; c < 256; c++) - { - s = 1; - if (c >= 0xC0 && c <= 0xDF) - s = 2; - if (c >= 0xE0 && c <= 0xEF) - s = 3; - if (c >= 0xF0 && c <= 0xF7) - s = 4; - if (c >= 0xF8 && c <= 0xFB) - s = 5; - if (c >= 0xFC && c <= 0xFD) - s = 6; - - printf("%d", s); - if ((c & 15) == 15) - printf(",\n"); - else - printf(","); - } -} -#endif diff --git a/dmd2/root/dchar.h b/dmd2/root/dchar.h deleted file mode 100644 index 2b8df523..00000000 --- a/dmd2/root/dchar.h +++ /dev/null @@ -1,194 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#ifndef DCHAR_H -#define DCHAR_H - -#if __GNUC__ && !_WIN32 -#include "gnuc.h" -#endif - -#if _MSC_VER - // Disable useless warnings about unreferenced functions - #pragma warning (disable : 4514) -#endif - -//#include "root.h" -typedef size_t hash_t; - -#undef TEXT - -// NOTE: All functions accepting pointer arguments must not be NULL - -#if M_UNICODE - -#include -#include - -typedef wchar_t dchar; -#define TEXT(x) L##x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { (void)pstart; return p - 1; } - static int len(const dchar *p) { return wcslen(p); } - static dchar get(dchar *p) { return *p; } - static dchar getprev(dchar *pstart, dchar *p) { (void)pstart; return p[-1]; } - static dchar *put(dchar *p, dchar c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) - { -#if __DMC__ - if (!*s1 && !*s2) // wcscmp is broken - return 0; -#endif - return wcscmp(s1, s2); -#if 0 - return (*s1 == *s2) - ? wcscmp(s1, s2) - : ((int)*s1 - (int)*s2); -#endif - } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars * sizeof(dchar)); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return iswalpha(c); } - static int isUpper(dchar c) { return iswupper(c); } - static int isLower(dchar c) { return iswlower(c); } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? towlower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? towupper(c) : c; } - static dchar *dup(dchar *p) { return ::_wcsdup(p); } // BUG: out of memory? - static dchar *dup(char *p); - static dchar *chr(dchar *p, unsigned c) { return wcschr(p, (dchar)c); } - static dchar *rchr(dchar *p, unsigned c) { return wcsrchr(p, (dchar)c); } - static dchar *memchr(dchar *p, int c, int count); - static dchar *cpy(dchar *s1, dchar *s2) { return wcscpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return wcsstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return wcsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::wcsnicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#elif MCBS - -#include -#include - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax MB_LEN_MAX - -#elif UTF8 - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 6 - -struct Dchar -{ - static char mblen[256]; - - static dchar *inc(dchar *p) { return p + mblen[*p & 0xFF]; } - static dchar *dec(dchar *pstart, dchar *p); - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p); - static int getprev(dchar *pstart, dchar *p) - { return *dec(pstart, p) & 0xFF; } - static dchar *put(dchar *p, unsigned c); - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } - static int isAlpha(dchar c) { return c <= 0x7F ? isalpha(c) : 0; } - static int isUpper(dchar c) { return c <= 0x7F ? isupper(c) : 0; } - static int isLower(dchar c) { return c <= 0x7F ? islower(c) : 0; } - static int isLocaleUpper(dchar c) { return isUpper(c); } - static int isLocaleLower(dchar c) { return isLower(c); } - static int toLower(dchar c) { return isUpper(c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return isLower(c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions - static int icmp(dchar *s1, dchar *s2) { return _mbsicmp(s1, s2); } - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::_mbsnicmp(s1, s2, nchars); } -}; - -#else - -#include - -#ifndef GCC_SAFE_DMD -#include -#endif - -typedef char dchar; -#define TEXT(x) x - -#define Dchar_mbmax 1 - -struct Dchar -{ - static dchar *inc(dchar *p) { return p + 1; } - static dchar *dec(dchar *pstart, dchar *p) { return p - 1; } - static int len(const dchar *p) { return strlen(p); } - static int get(dchar *p) { return *p & 0xFF; } - static int getprev(dchar *pstart, dchar *p) { return p[-1] & 0xFF; } - static dchar *put(dchar *p, unsigned c) { *p = c; return p + 1; } - static int cmp(dchar *s1, dchar *s2) { return strcmp(s1, s2); } - static int memcmp(const dchar *s1, const dchar *s2, int nchars) { return ::memcmp(s1, s2, nchars); } - static int isDigit(dchar c) { return '0' <= c && c <= '9'; } -#ifndef GCC_SAFE_DMD - static int isAlpha(dchar c) { return isalpha((unsigned char)c); } - static int isUpper(dchar c) { return isupper((unsigned char)c); } - static int isLower(dchar c) { return islower((unsigned char)c); } - static int isLocaleUpper(dchar c) { return isupper((unsigned char)c); } - static int isLocaleLower(dchar c) { return islower((unsigned char)c); } - static int toLower(dchar c) { return isupper((unsigned char)c) ? tolower(c) : c; } - static int toLower(dchar *p) { return toLower(*p); } - static int toUpper(dchar c) { return islower((unsigned char)c) ? toupper(c) : c; } - static dchar *dup(dchar *p) { return ::strdup(p); } // BUG: out of memory? -#endif - static dchar *chr(dchar *p, int c) { return strchr(p, c); } - static dchar *rchr(dchar *p, int c) { return strrchr(p, c); } - static dchar *memchr(dchar *p, int c, int count) - { return (dchar *)::memchr(p, c, count); } - static dchar *cpy(dchar *s1, dchar *s2) { return strcpy(s1, s2); } - static dchar *str(dchar *s1, dchar *s2) { return strstr(s1, s2); } - static hash_t calcHash(const dchar *str, size_t len); - - // Case insensitive versions -#ifdef __GNUC__ - static int icmp(dchar *s1, dchar *s2) { return strcasecmp(s1, s2); } -#else - static int icmp(dchar *s1, dchar *s2) { return stricmp(s1, s2); } -#endif - static int memicmp(const dchar *s1, const dchar *s2, int nchars) { return ::memicmp(s1, s2, nchars); } - static hash_t icalcHash(const dchar *str, size_t len); -}; - -#endif -#endif - diff --git a/dmd2/root/dmgcmem.c b/dmd2/root/dmgcmem.c deleted file mode 100644 index 9a283890..00000000 --- a/dmd2/root/dmgcmem.c +++ /dev/null @@ -1,499 +0,0 @@ - - -// Copyright (c) 2000-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ -#include -#include -#endif - -#include "rmem.h" -#include "gc/gc.h" -//#include "printf.h" - -/* This implementation of the storage allocator uses the Digital Mars gc. - */ - -Mem mem; - -//static int nuncollectable; - -extern "C" -{ - void gc_init(); - GC *gc_get(); -} - -void Mem::init() -{ - gc_init(); -} - -char *Mem::strdup(const char *s) -{ - return gc_get()->strdup(s); -} - -void *Mem::malloc(size_t size) -{ - if (gc) // if cached allocator - { -// PRINTF("Using cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); -// GC::file = NULL; -// GC::line = 0; - return ((GC *)gc)->malloc(size); - } - if (this == &mem) // don't cache global mem - { -// PRINTF("Using global gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); -// GC::file = NULL; -// GC::line = 0; - return gc_get()->malloc(size); - } -// PRINTF("Generating cached gc for size %d, file = '%s', line = %d\n", size, GC::file, GC::line); - gc = gc_get(); - return gc->malloc(size); -} - -void *Mem::malloc_uncollectable(size_t size) -{ void *p; - - p = ::malloc(size); - if (!p) - error(); - addroots((char *)p, (char *)p + size); - -#if 0 - ++nuncollectable; - WPRINTF(L"malloc_uncollectable(%u) = %x, n=%d\n", size, p, nuncollectable); -#endif - - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ - return gc_get()->calloc(size, n); -} - -void *Mem::realloc(void *p, size_t size) -{ - return gc_get()->realloc(p, size); -} - -void Mem::free(void *p) -{ - gc_get()->free(p); -} - -void Mem::free_uncollectable(void *p) -{ - if (p) - { removeroots((char *)p); - ::free(p); - -#if 0 - --nuncollectable; - WPRINTF(L"free_uncollectable(%x) n=%d\n", p, nuncollectable); -#endif - -#if 0 - gc_get()->fullcollect(); - - GCStats stats; - - getStats(&stats); - WPRINTF(L"poolsize = %x, usedsize = %x, freelistsize = %x\n", - stats.poolsize, stats.usedsize, stats.freelistsize); -#endif - } -} - -void *Mem::mallocdup(void *o, size_t size) -{ - return gc_get()->mallocdup(o, size); -} - -void Mem::check(void *p) -{ - if (gc) - gc->check(p); - else - gc_get()->check(p); -} - -void Mem::error() -{ -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ - assert(0); -#endif - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ - gc_get()->fullcollect(); - -#if 0 - { - GCStats stats; - - gc_get()->getStats(&stats); - WPRINTF(L"Thread %x ", Thread::getId()); - WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n", - stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks); - } -#endif -} - - -void Mem::fullcollectNoStack() -{ - gc_get()->fullcollectNoStack(); - -#if 0 - { - GCStats stats; - - gc_get()->getStats(&stats); - WPRINTF(L"Thread %x ", Thread::getId()); - WPRINTF(L"poolsize=x%x, usedsize=x%x, freelistsize=x%x, freeblocks=%d, pageblocks=%d\n", - stats.poolsize, stats.usedsize, stats.freelistsize, stats.freeblocks, stats.pageblocks); - } -#endif -} - - -void Mem::mark(void *pointer) -{ - (void) pointer; // for VC /W4 compatibility -} - - -void Mem::addroots(char* pStart, char* pEnd) -{ - gc_get()->addRange(pStart, pEnd); -} - - -void Mem::removeroots(char* pStart) -{ - gc_get()->removeRange(pStart); -} - - -void Mem::setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData) -{ - (void)pClientData; - gc_get()->setFinalizer(pObj, pFn); -} - - -void Mem::setStackBottom(void *stackbottom) -{ - gc_get()->setStackBottom(stackbottom); -} - - -GC *Mem::getThreadGC() -{ - return gc_get(); -} - - -/* =================================================== */ - -#if 1 -void * operator new(size_t m_size) -{ - //PRINTF("Call to global operator new(%d), file = '%s', line = %d\n", m_size, GC::file ? GC::file : "(null)", GC::line); - GC::file = NULL; - GC::line = 0; - return mem.malloc(m_size); -} - -void operator delete(void *p) -{ - //WPRINTF(L"Call to global operator delete\n"); - mem.free(p); -} - -void* operator new[](size_t size) -{ - return operator new(size); -} - -void operator delete[](void *pv) -{ - operator delete(pv); -} -#endif - -void * Mem::operator new(size_t m_size) -{ void *p; - - p = gc_get()->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - mem.error(); - return p; -} - -void * Mem::operator new(size_t m_size, Mem *mem) -{ void *p; - - p = mem->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - ::mem.error(); - return p; -} - -void * Mem::operator new(size_t m_size, GC *gc) -{ void *p; - -// if (!gc) -// WPRINTF(L"gc is NULL\n"); - p = gc->malloc(m_size); - //printf("Mem::operator new(%d) = %p\n", m_size, p); - if (!p) - ::mem.error(); - return p; -} - -void Mem::operator delete(void *p) -{ -// printf("Mem::operator delete(%p)\n", p); - gc_get()->free(p); -} - -/* ============================================================ */ - -/* The following section of code exists to find the right - * garbage collector for this thread. There is one independent instance - * of the collector per thread. - */ - -/* ===================== linux ================================ */ - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ - -#include - -#define LOG 0 // log thread creation / destruction - -extern "C" -{ - -// Key identifying the thread-specific data -static pthread_key_t gc_key; - -/* "Once" variable ensuring that the key for gc_alloc will be allocated - * exactly once. - */ -static pthread_once_t gc_alloc_key_once = PTHREAD_ONCE_INIT; - -/* Forward functions */ -static void gc_alloc_key(); -static void gc_alloc_destroy_gc(void * accu); - - -void gc_init() -{ -#if LOG - WPRINTF(L"Thread %lx: gc_init()\n", pthread_self()); -#endif - pthread_once(&gc_alloc_key_once, gc_alloc_key); -#if LOG - WPRINTF(L"Thread %lx: gc_init() return\n", pthread_self()); -#endif -} - -GC *gc_get() -{ - GC *gc; - - // Get the thread-specific data associated with the key - gc = (GC *) pthread_getspecific(gc_key); - - // It's initially NULL, meaning that we must allocate the buffer first. - if (gc == NULL) - { - GC_LOG(); - gc = new GC(); - gc->init(); - - // Store the buffer pointer in the thread-specific data. - pthread_setspecific(gc_key, (void *) gc); -#if LOG - WPRINTF(L"Thread %lx: allocating gc at %x\n", pthread_self(), gc); -#endif - } - return gc; -} - -// Function to allocate the key for gc_alloc thread-specific data. - -static void gc_alloc_key() -{ - pthread_key_create(&gc_key, gc_alloc_destroy_gc); -#if LOG - WPRINTF(L"Thread %lx: allocated gc key %d\n", pthread_self(), gc_key); -#endif -} - -// Function to free the buffer when the thread exits. -// Called only when the thread-specific data is not NULL. - -static void gc_alloc_destroy_gc(void *gc) -{ -#if LOG - WPRINTF(L"Thread %x: freeing gc at %x\n", pthread_self(), gc); -#endif - delete (GC *)gc; -} - -} - -#endif - -/* ===================== win32 ================================ */ - -#if !defined(linux) && defined(_WIN32) - -#if 1 // single threaded version - -extern "C" -{ - -static GC *gc; - -void gc_init() -{ - if (!gc) - { gc = (GC *)::malloc(sizeof(GC)); - gc->init(); - } -} - -GC *gc_get() -{ - return gc; -} - -} - -#else // multi threaded version - -#include "mutex.h" -#include "thread.h" - -/* This is the win32 version. It suffers from the bug that - * when the thread exits the data structure is not cleared, - * but the memory pool it points to is free'd. - * Thus, if a new thread comes along with the same thread id, - * the data will look initialized, but will point to garbage. - * - * What needs to happen is when a thread exits, the associated - * GC_context data struct is cleared. - */ - -struct GC_context -{ - ThreadId threadid; // identifier of current thread - GC *gc; -}; - -Mutex gc_mutex; - -static GC_context array[64]; - -// Array of pointers to GC_context objects, one per threadid -GC_context *gccontext = array; -unsigned gccontext_allocdim = 64; -unsigned gccontext_dim; - -ThreadId gc_cache_ti; -GC_context *gc_cache_cc; - -extern "C" void gc_init() -{ -} - - -extern "C" GC *gc_get() -{ - /* This works by creating an array of GC_context's, one - * for each thread. We match up by thread id. - */ - - ThreadId ti; - GC_context *cc; - - //PRINTF("gc_get()\n"); - - ti = Thread::getId(); - gc_mutex.acquire(); - - // Used cached version if we can - if (ti == gc_cache_ti) - { - cc = gc_cache_cc; - //exception(L"getGC_context(): cache x%x", ti); - } - else - { - // This does a linear search through gccontext[]. - // A hash table might be faster if there are more - // than a dozen threads. - GC_context *ccp; - GC_context *ccptop = &gccontext[gccontext_dim]; - for (ccp = gccontext; ccp < ccptop; ccp++) - { - cc = ccp; - if (cc->threadid == ti) - { - WPRINTF(L"getGC_context(): existing x%x", ti); - goto Lret; - } - } - - // Do not allocate with garbage collector, as this must reside - // global to all threads. - - assert(gccontext_dim < gccontext_allocdim); - cc = ccp; - memset(cc, 0, sizeof(*cc)); - cc->threadid = ti; - cc->gc = new GC(); - cc->gc->init(); - - gccontext_dim++; - WPRINTF(L"getGC_context(): new x%x\n", ti); - - Lret: - // Cache for next time - gc_cache_ti = ti; - gc_cache_cc = cc; - } - - gc_mutex.release(); - return cc->gc; -} - -#endif - - -#endif diff --git a/dmd2/root/gnuc.c b/dmd2/root/gnuc.c deleted file mode 100644 index 8f33d839..00000000 --- a/dmd2/root/gnuc.c +++ /dev/null @@ -1,55 +0,0 @@ - -// Put functions in here missing from gnu C - -#include "gnuc.h" - -int memicmp(const char *s1, const char *s2, int n) -{ - int result = 0; - - for (int i = 0; i < n; i++) - { char c1 = s1[i]; - char c2 = s2[i]; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - } - return result; -} - -int stricmp(const char *s1, const char *s2) -{ - int result = 0; - - for (;;) - { char c1 = *s1; - char c2 = *s2; - - result = c1 - c2; - if (result) - { - if ('A' <= c1 && c1 <= 'Z') - c1 += 'a' - 'A'; - if ('A' <= c2 && c2 <= 'Z') - c2 += 'a' - 'A'; - result = c1 - c2; - if (result) - break; - } - if (!c1) - break; - s1++; - s2++; - } - return result; -} - diff --git a/dmd2/root/gnuc.h b/dmd2/root/gnuc.h deleted file mode 100644 index 00c9851d..00000000 --- a/dmd2/root/gnuc.h +++ /dev/null @@ -1,8 +0,0 @@ - -#ifndef _GNUC_H -#define _GNUC_H 1 - -int memicmp(const char *s1, const char *s2, int n); -int stricmp(const char *s1, const char *s2); - -#endif diff --git a/dmd2/root/lstring.c b/dmd2/root/lstring.c deleted file mode 100644 index a4e41ed5..00000000 --- a/dmd2/root/lstring.c +++ /dev/null @@ -1,63 +0,0 @@ -// lstring.c - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -#include "dchar.h" -#include "rmem.h" -#include "lstring.h" - -#ifdef _MSC_VER // prevent compiler internal crash -Lstring Lstring::zero; -#else -Lstring Lstring::zero = LSTRING_EMPTY(); -#endif - -Lstring *Lstring::ctor(const dchar *p, unsigned length) -{ - Lstring *s; - - s = alloc(length); - memcpy(s->string, p, length * sizeof(dchar)); - return s; -} - -Lstring *Lstring::alloc(unsigned length) -{ - Lstring *s; - - s = (Lstring *)mem.malloc(size(length)); - s->length = length; - s->string[length] = 0; - return s; -} - -Lstring *Lstring::append(const Lstring *s) -{ - Lstring *t; - - if (!s->length) - return this; - t = alloc(length + s->length); - memcpy(t->string, string, length * sizeof(dchar)); - memcpy(t->string + length, s->string, s->length * sizeof(dchar)); - return t; -} - -Lstring *Lstring::substring(int start, int end) -{ - Lstring *t; - - if (start == end) - return &zero; - t = alloc(end - start); - memcpy(t->string, string + start, (end - start) * sizeof(dchar)); - return t; -} diff --git a/dmd2/root/lstring.h b/dmd2/root/lstring.h deleted file mode 100644 index 17a8e447..00000000 --- a/dmd2/root/lstring.h +++ /dev/null @@ -1,72 +0,0 @@ - -// lstring.h -// length-prefixed strings - -// Copyright (c) 1999-2002 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef LSTRING_H -#define LSTRING_H 1 - -#include "dchar.h" - -struct Lstring -{ - unsigned length; - - // Disable warning about nonstandard extension - #pragma warning (disable : 4200) - dchar string[]; - - static Lstring zero; // 0 length string - - // No constructors because we want to be able to statically - // initialize Lstring's, and Lstrings are of variable size. - - #if M_UNICODE - #define LSTRING(p,length) { length, L##p } - #else - #define LSTRING(p,length) { length, p } - #endif - -#if __GNUC__ - #define LSTRING_EMPTY() { 0 } -#else - #define LSTRING_EMPTY() LSTRING("", 0) -#endif - - static Lstring *ctor(const dchar *p) { return ctor(p, Dchar::len(p)); } - static Lstring *ctor(const dchar *p, unsigned length); - static unsigned size(unsigned length) { return sizeof(Lstring) + (length + 1) * sizeof(dchar); } - static Lstring *alloc(unsigned length); - Lstring *clone(); - - unsigned len() { return length; } - - dchar *toDchars() { return string; } - - hash_t hash() { return Dchar::calcHash(string, length); } - hash_t ihash() { return Dchar::icalcHash(string, length); } - - static int cmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memcmp(s1->string, s2->string, s1->length); - } - - static int icmp(const Lstring *s1, const Lstring *s2) - { - int c = s2->length - s1->length; - return c ? c : Dchar::memicmp(s1->string, s2->string, s1->length); - } - - Lstring *append(const Lstring *s); - Lstring *substring(int start, int end); -}; - -#endif diff --git a/dmd2/root/man.c b/dmd2/root/man.c deleted file mode 100644 index 3770aa96..00000000 --- a/dmd2/root/man.c +++ /dev/null @@ -1,100 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 2008-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include - -#if _WIN32 - -#include - -#pragma comment(lib,"shell32.lib") - -void browse(const char *url) -{ - ShellExecute(NULL, "open", url, NULL, NULL, SW_SHOWNORMAL); -} - -#endif - -#if linux || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[3]; - - const char *browser = getenv("BROWSER"); - if (browser) - browser = strdup(browser); - else - browser = "x-www-browser"; - - args[0] = browser; - args[1] = url; - args[2] = NULL; - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - -#if __APPLE__ - -#include -#include -#include - -void browse(const char *url) -{ - pid_t childpid; - const char *args[5]; - - char *browser = getenv("BROWSER"); - if (browser) - { browser = strdup(browser); - args[0] = browser; - args[1] = url; - args[2] = NULL; - } - else - { - //browser = "/Applications/Safari.app/Contents/MacOS/Safari"; - args[0] = "open"; - args[1] = "-a"; - args[2] = "/Applications/Safari.app"; - args[3] = url; - args[4] = NULL; - } - - childpid = fork(); - if (childpid == 0) - { - execvp(args[0], (char**)args); - perror(args[0]); // failed to execute - return; - } -} - -#endif - - diff --git a/dmd2/root/port.c b/dmd2/root/port.c deleted file mode 100644 index 232faefc..00000000 --- a/dmd2/root/port.c +++ /dev/null @@ -1,796 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#include "port.h" -#if __DMC__ -#include -#include -#include -#include -#include -#include - -double Port::nan = NAN; -double Port::infinity = INFINITY; -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; - -int Port::isNan(double r) -{ - return ::isnan(r); -} - -int Port::isNan(long double r) -{ - return ::isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -int Port::isFinite(double r) -{ - return ::isfinite(r); -} - -int Port::isInfinity(double r) -{ - return (::fpclassify(r) == FP_INFINITE); -} - -int Port::Signbit(double r) -{ - return ::signbit(r); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -long double Port::fmodl(long double x, long double y) -{ - return ::fmodl(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if _MSC_VER - -// Disable useless warnings about unreferenced functions -#pragma warning (disable : 4514) - -#include -#include -#include -#include -#include -#include -#include -#include // for std::numeric_limits - -static unsigned long nanarray[2]= { 0xFFFFFFFF, 0x7FFFFFFF }; -//static unsigned long nanarray[2] = {0,0x7FF80000 }; -double Port::nan = (*(double *)nanarray); - -//static unsigned long infinityarray[2] = {0,0x7FF00000 }; -static double zero = 0; -double Port::infinity = 1 / zero; - -double Port::dbl_max = DBL_MAX; -double Port::dbl_min = DBL_MIN; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = std::numeric_limits::infinity(); -} - -int Port::isNan(double r) -{ - return ::_isnan(r); -} - -int Port::isNan(long double r) -{ - return ::_isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* MSVC doesn't have 80 bit long doubles - */ - return isSignallingNan((double) r); -} - -int Port::isFinite(double r) -{ - return ::_finite(r); -} - -int Port::isInfinity(double r) -{ - return (::_fpclass(r) & (_FPCLASS_NINF | _FPCLASS_PINF)); -} - -int Port::Signbit(double r) -{ - return (long)(((long *)&(r))[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - if (y == 0) - return 1; // even if x is NAN - return ::pow(x, y); -} - -long double Port::fmodl(long double x, long double y) -{ - return ::fmodl(x, y); -} - -unsigned _int64 Port::strtoull(const char *p, char **pend, int base) -{ - unsigned _int64 number = 0; - int c; - int error; -#ifndef ULLONG_MAX - #define ULLONG_MAX ((unsigned _int64)~0I64) -#endif - - while (isspace((unsigned char)*p)) /* skip leading white space */ - p++; - if (*p == '+') - p++; - switch (base) - { case 0: - base = 10; /* assume decimal base */ - if (*p == '0') - { base = 8; /* could be octal */ - p++; - switch (*p) - { case 'x': - case 'X': - base = 16; /* hex */ - p++; - break; -#if BINARY - case 'b': - case 'B': - base = 2; /* binary */ - p++; - break; -#endif - } - } - break; - case 16: /* skip over '0x' and '0X' */ - if (*p == '0' && (p[1] == 'x' || p[1] == 'X')) - p += 2; - break; -#if BINARY - case 2: /* skip over '0b' and '0B' */ - if (*p == '0' && (p[1] == 'b' || p[1] == 'B')) - p += 2; - break; -#endif - } - error = 0; - for (;;) - { c = *p; - if (isdigit(c)) - c -= '0'; - else if (isalpha(c)) - c = (c & ~0x20) - ('A' - 10); - else /* unrecognized character */ - break; - if (c >= base) /* not in number base */ - break; - if ((ULLONG_MAX - c) / base < number) - error = 1; - number = number * base + c; - p++; - } - if (pend) - *pend = (char *)p; - if (error) - { number = ULLONG_MAX; - errno = ERANGE; - } - return number; -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - _ui64toa(ull, buffer, 10); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - _ui64tow(ull, buffer, 10); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ double d; - - if ((__int64) ull < 0) - { - // MSVC doesn't implement the conversion - d = (double) (__int64)(ull - 0x8000000000000000i64); - d += (double)(signed __int64)(0x7FFFFFFFFFFFFFFFi64) + 1.0; - } - else - d = (double)(__int64)ull; - return d; -} - -const char *Port::list_separator() -{ - // LOCALE_SLIST for Windows - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - // LOCALE_SLIST for Windows - return L","; -} - -char *Port::strupr(char *s) -{ - return ::strupr(s); -} - -#endif - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __HAIKU__ - -#include -#if linux -#include -#include -#endif -#if __FreeBSD__ && __i386__ -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = copysign(NAN, 1.0); -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - assert(!signbit(Port::nan)); - -#if __FreeBSD__ && __i386__ - // LDBL_MAX comes out as infinity. Fix. - static unsigned char x[sizeof(long double)] = - { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,0x7F }; - Port::ldbl_max = *(long double *)&x[0]; - // FreeBSD defaults to double precision. Switch to extended precision. - fpsetprec(FP_PE); -#endif -} - -#ifndef __HAIKU__ -#endif -int Port::isNan(double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#elif defined __HAIKU__ || __OpenBSD__ - return isnan(r); -#else - #undef isnan - return ::isnan(r); -#endif -} - -int Port::isNan(long double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#elif defined __HAIKU__ || __OpenBSD__ - return isnan(r); -#else - #undef isnan - return ::isnan(r); -#endif -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#if !defined __HAIKU__ -#endif -int Port::isInfinity(double r) -{ -#if __APPLE__ - return fpclassify(r) == FP_INFINITE; -#elif defined __HAIKU__ || __OpenBSD__ - return isinf(r); -#else - #undef isinf - return ::isinf(r); -#endif -} - -#undef signbit -int Port::Signbit(double r) -{ - union { double d; long long ll; } u; - u.d = r; - return u.ll < 0; -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -long double Port::fmodl(long double x, long double y) -{ -#if __FreeBSD__ || __OpenBSD__ - return ::fmod(x, y); // hack for now, fix later -#else - return ::fmodl(x, y); -#endif -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ -#if __OpenBSD__ - assert(0); -#else - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); -#endif - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - -#if __sun&&__SVR4 - -#define __C99FEATURES__ 1 // Needed on Solaris for NaN and more -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - // gcc nan's have the sign bit set by default, so turn it off - // Need the volatile to prevent gcc from doing incorrect - // constant folding. - volatile long double foo; - foo = NAN; - if (signbit(foo)) // signbit sometimes, not always, set - foo = -foo; // turn off sign bit - Port::nan = foo; -} - -int Port::isNan(double r) -{ - return isnan(r); -} - -int Port::isNan(long double r) -{ - return isnan(r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return finite(r); -} - -int Port::isInfinity(double r) -{ - return isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, sizeof(ulonglong) * 3 + 1, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - -#if IN_GCC - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static double zero = 0; -double Port::nan = NAN; -double Port::infinity = 1 / zero; -double Port::dbl_max = 1.7976931348623157e308; -double Port::dbl_min = 5e-324; -long double Port::ldbl_max = LDBL_MAX; - -#include "d-gcc-real.h" -extern "C" bool real_isnan (const real_t *); - -struct PortInitializer -{ - PortInitializer(); -}; - -static PortInitializer portinitializer; - -PortInitializer::PortInitializer() -{ - Port::infinity = real_t::getinfinity(); - Port::nan = real_t::getnan(real_t::LongDouble); -} - -#undef isnan -int Port::isNan(double r) -{ -#if __APPLE__ - return __inline_isnan(r); -#else - return ::isnan(r); -#endif -} - -int Port::isNan(long double r) -{ - return real_isnan(&r); -} - -int Port::isSignallingNan(double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 51 of 0..63 for 64 bit doubles. - */ - return isNan(r) && !((((unsigned char*)&r)[6]) & 8); -} - -int Port::isSignallingNan(long double r) -{ - /* A signalling NaN is a NaN with 0 as the most significant bit of - * its significand, which is bit 62 of 0..79 for 80 bit reals. - */ - return isNan(r) && !((((unsigned char*)&r)[7]) & 0x40); -} - -#undef isfinite -int Port::isFinite(double r) -{ - return ::finite(r); -} - -#undef isinf -int Port::isInfinity(double r) -{ - return ::isinf(r); -} - -#undef signbit -int Port::Signbit(double r) -{ - return (long)(((long *)&r)[1] & 0x80000000); -} - -double Port::floor(double d) -{ - return ::floor(d); -} - -double Port::pow(double x, double y) -{ - return ::pow(x, y); -} - -unsigned long long Port::strtoull(const char *p, char **pend, int base) -{ - return ::strtoull(p, pend, base); -} - -char *Port::ull_to_string(char *buffer, ulonglong ull) -{ - sprintf(buffer, "%llu", ull); - return buffer; -} - -wchar_t *Port::ull_to_string(wchar_t *buffer, ulonglong ull) -{ - swprintf(buffer, L"%llu", ull); - return buffer; -} - -double Port::ull_to_double(ulonglong ull) -{ - return (double) ull; -} - -const char *Port::list_separator() -{ - return ","; -} - -const wchar_t *Port::wlist_separator() -{ - return L","; -} - -char *Port::strupr(char *s) -{ - char *t = s; - - while (*s) - { - *s = toupper(*s); - s++; - } - - return t; -} - -#endif - diff --git a/dmd2/root/port.h b/dmd2/root/port.h deleted file mode 100644 index d915991d..00000000 --- a/dmd2/root/port.h +++ /dev/null @@ -1,81 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com - -#ifndef PORT_H -#define PORT_H - -// Portable wrapper around compiler/system specific things. -// The idea is to minimize #ifdef's in the app code. - -#ifndef TYPEDEFS -#define TYPEDEFS - -#include - -#if _MSC_VER -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; - -// According to VC 8.0 docs, long double is the same as double -#define strtold strtod -#define strtof strtod - -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -typedef double d_time; - -struct Port -{ - static double nan; - static double infinity; - static double dbl_max; - static double dbl_min; - static long double ldbl_max; - -#if !defined __HAIKU__ || __OpenBSD__ -#elif __GNUC__ - // These conflict with macros in math.h, should rename them - #undef isnan - #undef isfinite - #undef isinfinity - #undef signbit -#endif - static int isNan(double); - static int isNan(long double); - - static int isSignallingNan(double); - static int isSignallingNan(long double); - - static int isFinite(double); - static int isInfinity(double); - static int Signbit(double); - - static double floor(double); - static double pow(double x, double y); - - static long double fmodl(long double x, long double y); - - static ulonglong strtoull(const char *p, char **pend, int base); - - static char *ull_to_string(char *buffer, ulonglong ull); - static wchar_t *ull_to_string(wchar_t *buffer, ulonglong ull); - - // Convert ulonglong to double - static double ull_to_double(ulonglong ull); - - // Get locale-dependent list separator - static const char *list_separator(); - static const wchar_t *wlist_separator(); - - static char *strupr(char *); -}; - -#endif diff --git a/dmd2/root/response.c b/dmd2/root/response.c deleted file mode 100644 index 2096f11b..00000000 --- a/dmd2/root/response.c +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (C) 1990-1998 by Symantec -// Copyright (C) 2000-2011 by Digital Mars -// All Rights Reserved -// http://www.digitalmars.com -// Written by Walter Bright -/* - * This source file is made available for personal use - * only. The license is in /dmd/src/dmd/backendlicense.txt - * For any other uses, please contact Digital Mars. - */ - -#include -#include -#include -#include -#include - -#if _WIN32 -#include -#include -#endif - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 -#include -#include -#include -#include -#include -#include -#endif - -/********************************* - * #include - * int response_expand(int *pargc,char ***pargv); - * - * Expand any response files in command line. - * Response files are arguments that look like: - * @NAME - * The name is first searched for in the environment. If it is not - * there, it is searched for as a file name. - * Arguments are separated by spaces, tabs, or newlines. These can be - * imbedded within arguments by enclosing the argument in '' or "". - * Recursively expands nested response files. - * - * To use, put the line: - * response_expand(&argc,&argv); - * as the first executable statement in main(int argc, char **argv). - * argc and argv are adjusted to be the new command line arguments - * after response file expansion. - * - * Digital Mars's MAKE program can be notified that a program can accept - * long command lines via environment variables by preceding the rule - * line for the program with a *. - * - * Returns: - * 0 success - * !=0 failure (argc, argv unchanged) - */ - -struct Narg -{ - int argc; /* arg count */ - int argvmax; /* dimension of nargv[] */ - char **argv; -}; - -static int addargp(struct Narg *n, char *p) -{ - /* The 2 is to always allow room for a NULL argp at the end */ - if (n->argc + 2 > n->argvmax) - { - n->argvmax = n->argc + 2; - char **ap = n->argv; - ap = (char **) realloc(ap,n->argvmax * sizeof(char *)); - if (!ap) - { if (n->argv) - free(n->argv); - memset(n, 0, sizeof(*n)); - return 1; - } - n->argv = ap; - } - n->argv[n->argc++] = p; - return 0; -} - -int response_expand(int *pargc, char ***pargv) -{ - struct Narg n; - int i; - char *cp; - int recurse = 0; - - n.argc = 0; - n.argvmax = 0; /* dimension of n.argv[] */ - n.argv = NULL; - for(i=0; i<*pargc; ++i) - { - cp = (*pargv)[i]; - if (*cp == '@') - { - char *buffer; - char *bufend; - char *p; - - cp++; - p = getenv(cp); - if (p) - { - buffer = strdup(p); - if (!buffer) - goto noexpand; - bufend = buffer + strlen(buffer); - } - else - { - long length; - int fd; - int nread; - size_t len; - -#if __DMC__ - length = filesize(cp); -#else - struct stat statbuf; - if (stat(cp, &statbuf)) - goto noexpand; - length = statbuf.st_size; -#endif - if (length & 0xF0000000) /* error or file too big */ - goto noexpand; - len = length; - buffer = (char *)malloc(len + 1); - if (!buffer) - goto noexpand; - bufend = &buffer[len]; - /* Read file into buffer */ -#if _WIN32 - fd = _open(cp,O_RDONLY|O_BINARY); -#else - fd = open(cp,O_RDONLY); -#endif - if (fd == -1) - goto noexpand; - nread = read(fd,buffer,len); - close(fd); - - if (nread != len) - goto noexpand; - } - - // The logic of this should match that in setargv() - - for (p = buffer; p < bufend; p++) - { - char *d; - char c,lastc; - unsigned char instring; - int num_slashes,non_slashes; - - switch (*p) - { - case 26: /* ^Z marks end of file */ - goto L2; - - case 0xD: - case 0: - case ' ': - case '\t': - case '\n': - continue; // scan to start of argument - - case '@': - recurse = 1; - default: /* start of new argument */ - if (addargp(&n,p)) - goto noexpand; - instring = 0; - c = 0; - num_slashes = 0; - for (d = p; 1; p++) - { - lastc = c; - if (p >= bufend) - goto Lend; - c = *p; - switch (c) - { - case '"': - /* - Yes this looks strange,but this is so that we are - MS Compatible, tests have shown that: - \\\\"foo bar" gets passed as \\foo bar - \\\\foo gets passed as \\\\foo - \\\"foo gets passed as \"foo - and \"foo gets passed as "foo in VC! - */ - non_slashes = num_slashes % 2; - num_slashes = num_slashes / 2; - for (; num_slashes > 0; num_slashes--) - { - d--; - *d = '\0'; - } - - if (non_slashes) - { - *(d-1) = c; - } - else - { - instring ^= 1; - } - break; - case 26: - Lend: - *d = 0; // terminate argument - goto L2; - - case 0xD: // CR - c = lastc; - continue; // ignore - - case '@': - recurse = 1; - goto Ladd; - - case ' ': - case '\t': - if (!instring) - { - case '\n': - case 0: - *d = 0; // terminate argument - goto Lnextarg; - } - default: - Ladd: - if (c == '\\') - num_slashes++; - else - num_slashes = 0; - *d++ = c; - break; - } -#ifdef _MBCS - if (_istlead (c)) { - *d++ = *++p; - if (*(d - 1) == '\0') { - d--; - goto Lnextarg; - } - } -#endif - } - break; - } - Lnextarg: - ; - } - L2: - ; - } - else if (addargp(&n,(*pargv)[i])) - goto noexpand; - } - if (n.argvmax == 0) - { - n.argvmax = 1; - n.argv = (char **) calloc(n.argvmax, sizeof(char *)); - if (!n.argv) - return 1; - } - else - n.argv[n.argc] = NULL; - if (recurse) - { - /* Recursively expand @filename */ - if (response_expand(&n.argc,&n.argv)) - goto noexpand; - } - *pargc = n.argc; - *pargv = n.argv; - return 0; /* success */ - -noexpand: /* error */ - free(n.argv); - /* BUG: any file buffers are not free'd */ - return 1; -} diff --git a/dmd2/root/rmem.c b/dmd2/root/rmem.c deleted file mode 100644 index 2504ab93..00000000 --- a/dmd2/root/rmem.c +++ /dev/null @@ -1,155 +0,0 @@ - -/* Copyright (c) 2000 Digital Mars */ -/* All Rights Reserved */ - -#include -#include -#include - -#if linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4 -#include "../root/rmem.h" -#else -#include "rmem.h" -#endif - -/* This implementation of the storage allocator uses the standard C allocation package. - */ - -Mem mem; - -void Mem::init() -{ -} - -char *Mem::strdup(const char *s) -{ - char *p; - - if (s) - { - p = ::strdup(s); - if (p) - return p; - error(); - } - return NULL; -} - -void *Mem::malloc(size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - } - return p; -} - -void *Mem::calloc(size_t size, size_t n) -{ void *p; - - if (!size || !n) - p = NULL; - else - { - p = ::calloc(size, n); - if (!p) - error(); - } - return p; -} - -void *Mem::realloc(void *p, size_t size) -{ - if (!size) - { if (p) - { ::free(p); - p = NULL; - } - } - else if (!p) - { - p = ::malloc(size); - if (!p) - error(); - } - else - { - void *psave = p; - p = ::realloc(psave, size); - if (!p) - { free(psave); - error(); - } - } - return p; -} - -void Mem::free(void *p) -{ - if (p) - ::free(p); -} - -void *Mem::mallocdup(void *o, size_t size) -{ void *p; - - if (!size) - p = NULL; - else - { - p = ::malloc(size); - if (!p) - error(); - else - memcpy(p,o,size); - } - return p; -} - -void Mem::error() -{ - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); -} - -void Mem::fullcollect() -{ -} - -void Mem::mark(void *pointer) -{ - (void) pointer; // necessary for VC /W4 -} - -void Mem::setStackBottom(void *bottom) -{ -} - -void Mem::addroots(char* pStart, char* pEnd) -{ -} - - -/* =================================================== */ - -void * operator new(size_t m_size) -{ - void *p = malloc(m_size); - if (p) - return p; - printf("Error: out of memory\n"); - exit(EXIT_FAILURE); - return p; -} - -void operator delete(void *p) -{ - free(p); -} - - diff --git a/dmd2/root/rmem.h b/dmd2/root/rmem.h deleted file mode 100644 index d22145a9..00000000 --- a/dmd2/root/rmem.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (C) 2000-2011 by Digital Mars -// All Rights Reserved - -#ifndef ROOT_MEM_H -#define ROOT_MEM_H - -#include // for size_t - -typedef void (*FINALIZERPROC)(void* pObj, void* pClientData); - -struct GC; // thread specific allocator - -struct Mem -{ - GC *gc; // pointer to our thread specific allocator - Mem() { gc = NULL; } - - void init(); - - // Derive from Mem to get these storage allocators instead of global new/delete - void * operator new(size_t m_size); - void * operator new(size_t m_size, Mem *mem); - void * operator new(size_t m_size, GC *gc); - void operator delete(void *p); - - void * operator new[](size_t m_size); - void operator delete[](void *p); - - char *strdup(const char *s); - void *malloc(size_t size); - void *malloc_uncollectable(size_t size); - void *calloc(size_t size, size_t n); - void *realloc(void *p, size_t size); - void free(void *p); - void free_uncollectable(void *p); - void *mallocdup(void *o, size_t size); - void error(); - void check(void *p); // validate pointer - void fullcollect(); // do full garbage collection - void fullcollectNoStack(); // do full garbage collection, no scan stack - void mark(void *pointer); - void addroots(char* pStart, char* pEnd); - void removeroots(char* pStart); - void setFinalizer(void* pObj, FINALIZERPROC pFn, void* pClientData); - void setStackBottom(void *bottom); - GC *getThreadGC(); // get apartment allocator for this thread -}; - -extern Mem mem; - -#endif /* ROOT_MEM_H */ diff --git a/dmd2/root/root.c b/dmd2/root/root.c deleted file mode 100644 index 926dae28..00000000 --- a/dmd2/root/root.c +++ /dev/null @@ -1,2095 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef POSIX -#define POSIX (linux || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun&&__SVR4) -#endif - -#include -#include -#include -#include -#include -#include -#include - -#if (defined (__SVR4) && defined (__sun)) -#include -#endif - -#if _MSC_VER ||__MINGW32__ -#include -#include -#endif - -#if _WIN32 -#include -#include -#include -#endif - -#ifdef __HAIKU__ -#include -#endif - -#if POSIX -#include -#include -#include -#include -#include -#include -#endif - -#include "port.h" -#include "root.h" -#include "dchar.h" -#include "rmem.h" - -#if 0 //__SC__ //def DEBUG -extern "C" void __cdecl _assert(void *e, void *f, unsigned line) -{ - printf("Assert('%s','%s',%d)\n",e,f,line); - fflush(stdout); - *(char *)0 = 0; -} -#endif - - -/************************************* - * Convert wchar string to ascii string. - */ - -char *wchar2ascii(wchar_t *us) -{ - return wchar2ascii(us, wcslen(us)); -} - -char *wchar2ascii(wchar_t *us, unsigned len) -{ - unsigned i; - char *p; - - p = (char *)mem.malloc(len + 1); - for (i = 0; i <= len; i++) - p[i] = (char) us[i]; - return p; -} - -int wcharIsAscii(wchar_t *us) -{ - return wcharIsAscii(us, wcslen(us)); -} - -int wcharIsAscii(wchar_t *us, unsigned len) -{ - unsigned i; - - for (i = 0; i <= len; i++) - { - if (us[i] & ~0xFF) // if high bits set - return 0; // it's not ascii - } - return 1; -} - - -/*********************************** - * Compare length-prefixed strings (bstr). - */ - -int bstrcmp(unsigned char *b1, unsigned char *b2) -{ - return (*b1 == *b2 && memcmp(b1 + 1, b2 + 1, *b2) == 0) ? 0 : 1; -} - -/*************************************** - * Convert bstr into a malloc'd string. - */ - -char *bstr2str(unsigned char *b) -{ - char *s; - unsigned len; - - len = *b; - s = (char *) mem.malloc(len + 1); - s[len] = 0; - return (char *)memcpy(s,b + 1,len); -} - -/************************************** - * Print error message and exit. - */ - -void error(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} - -#if M_UNICODE -void error(const dchar *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Error: "); - vwprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); - - exit(EXIT_FAILURE); -} -#endif - -void error_mem() -{ - error("out of memory"); -} - -/************************************** - * Print warning message. - */ - -void warning(const char *format, ...) -{ - va_list ap; - - va_start(ap, format); - printf("Warning: "); - vprintf(format, ap); - va_end( ap ); - printf("\n"); - fflush(stdout); -} - -/****************************** Object ********************************/ - -int Object::equals(Object *o) -{ - return o == this; -} - -hash_t Object::hashCode() -{ - return (hash_t) this; -} - -int Object::compare(Object *obj) -{ - return this - obj; -} - -void Object::print() -{ - printf("%s %p\n", toChars(), this); -} - -char *Object::toChars() -{ - return (char *)"Object"; -} - -dchar *Object::toDchars() -{ -#if M_UNICODE - return L"Object"; -#else - return toChars(); -#endif -} - -int Object::dyncast() -{ - return 0; -} - -void Object::toBuffer(OutBuffer *b) -{ - b->writestring("Object"); -} - -void Object::mark() -{ -} - -/****************************** String ********************************/ - -String::String(char *str, int ref) -{ - this->str = ref ? str : mem.strdup(str); - this->ref = ref; -} - -String::~String() -{ - mem.free(str); -} - -void String::mark() -{ - mem.mark(str); -} - -hash_t String::calcHash(const char *str, size_t len) -{ - hash_t hash = 0; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)str; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)str; - return hash; - - case 3: - hash *= 37; - hash += (*(uint16_t *)str << 8) + - ((uint8_t *)str)[2]; - return hash; - - default: - hash *= 37; - hash += *(uint32_t *)str; - str += 4; - len -= 4; - break; - } - } -} - -hash_t String::calcHash(const char *str) -{ - return calcHash(str, strlen(str)); -} - -hash_t String::hashCode() -{ - return calcHash(str, strlen(str)); -} - -unsigned String::len() -{ - return strlen(str); -} - -int String::equals(Object *obj) -{ - return strcmp(str,((String *)obj)->str) == 0; -} - -int String::compare(Object *obj) -{ - return strcmp(str,((String *)obj)->str); -} - -char *String::toChars() -{ - return str; -} - -void String::print() -{ - printf("String '%s'\n",str); -} - - -/****************************** FileName ********************************/ - -FileName::FileName(char *str, int ref) - : String(str,ref) -{ -} - -char *FileName::combine(const char *path, const char *name) -{ char *f; - size_t pathlen; - size_t namelen; - - if (!path || !*path) - return (char *)name; - pathlen = strlen(path); - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -FileName::FileName(char *path, char *name) - : String(combine(path,name),1) -{ -} - -// Split a path into an Array of paths -Strings *FileName::splitPath(const char *path) -{ - char c = 0; // unnecessary initializer is for VC /W4 - const char *p; - OutBuffer buf; - Strings *array; - - array = new Strings(); - if (path) - { - p = path; - do - { char instring = 0; - - while (isspace((unsigned char)*p)) // skip leading whitespace - p++; - buf.reserve(strlen(p) + 1); // guess size of path - for (; ; p++) - { - c = *p; - switch (c) - { - case '"': - instring ^= 1; // toggle inside/outside of string - continue; - -#if MACINTOSH - case ',': -#endif -#if _WIN32 - case ';': -#endif -#if POSIX - case ':': -#endif - p++; - break; // note that ; cannot appear as part - // of a path, quotes won't protect it - - case 0x1A: // ^Z means end of file - case 0: - break; - - case '\r': - continue; // ignore carriage returns - -#if POSIX - case '~': - buf.writestring(getenv("HOME")); - continue; -#endif - -#if 0 - case ' ': - case '\t': // tabs in filenames? - if (!instring) // if not in string - break; // treat as end of path -#endif - default: - buf.writeByte(c); - continue; - } - break; - } - if (buf.offset) // if path is not empty - { - buf.writeByte(0); // to asciiz - array->push(buf.extractData()); - } - } while (c); - } - return array; -} - -hash_t FileName::hashCode() -{ -#if _WIN32 - // We need a different hashCode because it must be case-insensitive - size_t len = strlen(str); - hash_t hash = 0; - unsigned char *s = (unsigned char *)str; - - for (;;) - { - switch (len) - { - case 0: - return hash; - - case 1: - hash *= 37; - hash += *(uint8_t *)s | 0x20; - return hash; - - case 2: - hash *= 37; - hash += *(uint16_t *)s | 0x2020; - return hash; - - case 3: - hash *= 37; - hash += ((*(uint16_t *)s << 8) + - ((uint8_t *)s)[2]) | 0x202020; - break; - - default: - hash *= 37; - hash += *(uint32_t *)s | 0x20202020; - s += 4; - len -= 4; - break; - } - } -#else - // darwin HFS is case insensitive, though... - return String::hashCode(); -#endif -} - -int FileName::compare(Object *obj) -{ - return compare(str, ((FileName *)obj)->str); -} - -int FileName::compare(const char *name1, const char *name2) -{ -#if _WIN32 - return stricmp(name1, name2); -#else - return strcmp(name1, name2); -#endif -} - -int FileName::equals(Object *obj) -{ - return compare(obj) == 0; -} - -int FileName::equals(const char *name1, const char *name2) -{ - return compare(name1, name2) == 0; -} - -/************************************ - * Return !=0 if absolute path name. - */ - -int FileName::absolute(const char *name) -{ -#if _WIN32 - return (*name == '\\') || - (*name == '/') || - (*name && name[1] == ':'); -#elif POSIX - return (*name == '/'); -#else - assert(0); -#endif -} - -/******************************** - * Return filename extension (read-only). - * Points past '.' of extension. - * If there isn't one, return NULL. - */ - -char *FileName::ext(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { case '.': - return e + 1; -#if POSIX - case '/': - break; -#endif -#if _WIN32 - case '\\': - case ':': - case '/': - break; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return NULL; - } -} - -char *FileName::ext() -{ - return ext(str); -} - -/******************************** - * Return mem.malloc'd filename with extension removed. - */ - -char *FileName::removeExt(const char *str) -{ - const char *e = ext(str); - if (e) - { size_t len = (e - str) - 1; - char *n = (char *)mem.malloc(len + 1); - memcpy(n, str, len); - n[len] = 0; - return n; - } - return mem.strdup(str); -} - -/******************************** - * Return filename name excluding path (read-only). - */ - -char *FileName::name(const char *str) -{ - char *e; - size_t len = strlen(str); - - e = (char *)str + len; - for (;;) - { - switch (*e) - { -#if POSIX - case '/': - return e + 1; -#endif -#if _WIN32 - case '/': - case '\\': - return e + 1; - case ':': - /* The ':' is a drive letter only if it is the second - * character or the last character, - * otherwise it is an ADS (Alternate Data Stream) separator. - * Consider ADS separators as part of the file name. - */ - if (e == str + 1 || e == str + len - 1) - return e + 1; -#endif - default: - if (e == str) - break; - e--; - continue; - } - return e; - } -} - -char *FileName::name() -{ - return name(str); -} - -/************************************** - * Return path portion of str. - * Path will does not include trailing path separator. - */ - -char *FileName::path(const char *str) -{ - char *n = name(str); - char *path; - size_t pathlen; - - if (n > str) - { -#if POSIX - if (n[-1] == '/') - n--; -#elif _WIN32 - if (n[-1] == '\\' || n[-1] == '/') - n--; -#else - assert(0); -#endif - } - pathlen = n - str; - path = (char *)mem.malloc(pathlen + 1); - memcpy(path, str, pathlen); - path[pathlen] = 0; - return path; -} - -/************************************** - * Replace filename portion of path. - */ - -const char *FileName::replaceName(const char *path, const char *name) -{ char *f; - char *n; - size_t pathlen; - size_t namelen; - - if (absolute(name)) - return name; - - n = FileName::name(path); - if (n == path) - return name; - pathlen = n - path; - namelen = strlen(name); - f = (char *)mem.malloc(pathlen + 1 + namelen + 1); - memcpy(f, path, pathlen); -#if POSIX - if (path[pathlen - 1] != '/') - { f[pathlen] = '/'; - pathlen++; - } -#elif _WIN32 - if (path[pathlen - 1] != '\\' && - path[pathlen - 1] != '/' && - path[pathlen - 1] != ':') - { f[pathlen] = '\\'; - pathlen++; - } -#else - assert(0); -#endif - memcpy(f + pathlen, name, namelen + 1); - return f; -} - -/*************************** - */ - -FileName *FileName::defaultExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - return new FileName((char *)name, 0); - - len = strlen(name); - extlen = strlen(ext); - s = (char *)alloca(len + 1 + extlen + 1); - memcpy(s,name,len); - s[len] = '.'; - memcpy(s + len + 1, ext, extlen + 1); - return new FileName(s, 0); -} - -/*************************** - */ - -FileName *FileName::forceExt(const char *name, const char *ext) -{ - char *e; - char *s; - size_t len; - size_t extlen; - - e = FileName::ext(name); - if (e) // if already has an extension - { - len = e - name; - extlen = strlen(ext); - - s = (char *)alloca(len + extlen + 1); - memcpy(s,name,len); - memcpy(s + len, ext, extlen + 1); - return new FileName(s, 0); - } - else - return defaultExt(name, ext); // doesn't have one -} - -/****************************** - * Return !=0 if extensions match. - */ - -int FileName::equalsExt(const char *ext) -{ const char *e; - - e = FileName::ext(); - if (!e && !ext) - return 1; - if (!e || !ext) - return 0; -#if POSIX - return strcmp(e,ext) == 0; -#elif _WIN32 - return stricmp(e,ext) == 0; -#else - assert(0); -#endif -} - -/************************************* - * Copy file from this to to. - */ - -void FileName::CopyTo(FileName *to) -{ - File file(this); - -#if _WIN32 - file.touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); // keep same file time -#elif POSIX - file.touchtime = mem.malloc(sizeof(struct stat)); // keep same file time -#else - assert(0); -#endif - file.readv(); - file.name = to; - file.writev(); -} - -/************************************* - * Search Path for file. - * Input: - * cwd if !=0, search current directory before searching path - */ - -char *FileName::searchPath(Strings *path, const char *name, int cwd) -{ - if (absolute(name)) - { - return exists(name) ? (char *)name : NULL; - } - if (cwd) - { - if (exists(name)) - return (char *)name; - } - if (path) - { unsigned i; - - for (i = 0; i < path->dim; i++) - { - char *p = path->tdata()[i]; - char *n = combine(p, name); - - if (exists(n)) - return n; - } - } - return NULL; -} - - -/************************************* - * Search Path for file in a safe manner. - * - * Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory - * ('Path Traversal') attacks. - * http://cwe.mitre.org/data/definitions/22.html - * More info: - * https://www.securecoding.cert.org/confluence/display/seccode/FIO02-C.+Canonicalize+path+names+originating+from+untrusted+sources - * Returns: - * NULL file not found - * !=NULL mem.malloc'd file name - */ - -char *FileName::safeSearchPath(Strings *path, const char *name) -{ -#if _WIN32 - /* Disallow % / \ : and .. in name characters - */ - for (const char *p = name; *p; p++) - { - char c = *p; - if (c == '\\' || c == '/' || c == ':' || c == '%' || - (c == '.' && p[1] == '.')) - { - return NULL; - } - } - - return FileName::searchPath(path, name, 0); -#elif POSIX - /* Even with realpath(), we must check for // and disallow it - */ - for (const char *p = name; *p; p++) - { - char c = *p; - if (c == '/' && p[1] == '/') - { - return NULL; - } - } - - if (path) - { unsigned i; - - /* Each path is converted to a cannonical name and then a check is done to see - * that the searched name is really a child one of the the paths searched. - */ - for (i = 0; i < path->dim; i++) - { - char *cname = NULL; - char *cpath = canonicalName(path->tdata()[i]); - //printf("FileName::safeSearchPath(): name=%s; path=%s; cpath=%s\n", - // name, (char *)path->data[i], cpath); - if (cpath == NULL) - goto cont; - cname = canonicalName(combine(cpath, name)); - //printf("FileName::safeSearchPath(): cname=%s\n", cname); - if (cname == NULL) - goto cont; - //printf("FileName::safeSearchPath(): exists=%i " - // "strncmp(cpath, cname, %i)=%i\n", exists(cname), - // strlen(cpath), strncmp(cpath, cname, strlen(cpath))); - // exists and name is *really* a "child" of path - if (exists(cname) && strncmp(cpath, cname, strlen(cpath)) == 0) - { - free(cpath); - char *p = mem.strdup(cname); - free(cname); - return p; - } -cont: - if (cpath) - free(cpath); - if (cname) - free(cname); - } - } - return NULL; -#else - assert(0); -#endif -} - - -int FileName::exists(const char *name) -{ -#if POSIX - struct stat st; - - if (stat(name, &st) < 0) - return 0; - if (S_ISDIR(st.st_mode)) - return 2; - return 1; -#elif _WIN32 - DWORD dw; - int result; - - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void FileName::ensurePathExists(const char *path) -{ - //printf("FileName::ensurePathExists(%s)\n", path ? path : ""); - if (path && *path) - { - if (!exists(path)) - { - char *p = FileName::path(path); - if (*p) - { -#if _WIN32 - size_t len = strlen(path); - if (len > 2 && p[-1] == ':' && path + 2 == p) - { mem.free(p); - return; - } -#endif - ensurePathExists(p); - mem.free(p); - } -#if _WIN32 - if (path[strlen(path) - 1] != '\\') -#endif -#if POSIX - if (path[strlen(path) - 1] != '\\') -#endif - { - //printf("mkdir(%s)\n", path); -#if _WIN32 - if (_mkdir(path)) -#endif -#if POSIX - if (mkdir(path, 0777)) -#endif - { - /* Don't error out if another instance of dmd just created - * this directory - */ - if (errno != EEXIST) - error("cannot create directory %s", path); - } - } - } - } -} - - -/****************************************** - * Return canonical version of name in a malloc'd buffer. - * This code is high risk. - */ -char *FileName::canonicalName(const char *name) -{ -#if linux - // Lovely glibc extension to do it for us - return canonicalize_file_name(name); -#elif POSIX - #if _POSIX_VERSION >= 200809L || defined (linux) - // NULL destination buffer is allowed and preferred - return realpath(name, NULL); - #else - char *cname = NULL; - #if PATH_MAX - /* PATH_MAX must be defined as a constant in , - * otherwise using it is unsafe due to TOCTOU - */ - size_t path_max = (size_t)PATH_MAX; - if (path_max > 0) - { - /* Need to add one to PATH_MAX because of realpath() buffer overflow bug: - * http://isec.pl/vulnerabilities/isec-0011-wu-ftpd.txt - */ - cname = (char *)malloc(path_max + 1); - if (cname == NULL) - return NULL; - } - #endif - return realpath(name, cname); - #endif -#elif _WIN32 - /* Apparently, there is no good way to do this on Windows. - * GetFullPathName isn't it. - */ - assert(0); - return NULL; -#else - assert(0); - return NULL; -#endif -} - - -/****************************** File ********************************/ - -File::File(FileName *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = n; -} - -File::File(char *n) -{ - ref = 0; - buffer = NULL; - len = 0; - touchtime = NULL; - name = new FileName(n, 0); -} - -File::~File() -{ - if (buffer) - { - if (ref == 0) - mem.free(buffer); -#if _WIN32 - else if (ref == 2) - UnmapViewOfFile(buffer); -#endif - } - if (touchtime) - mem.free(touchtime); -} - -void File::mark() -{ - mem.mark(buffer); - mem.mark(touchtime); - mem.mark(name); -} - -/************************************* - */ - -int File::read() -{ -#if POSIX - off_t size; - ssize_t numread; - int fd; - struct stat buf; - int result = 0; - char *name; - - name = this->name->toChars(); - //printf("File::read('%s')\n",name); - fd = open(name, O_RDONLY); - if (fd == -1) - { - //printf("\topen error, errno = %d\n",errno); - goto err1; - } - - if (!ref) - ::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 *) ::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: - ::free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#elif _WIN32 - DWORD size; - DWORD numread; - HANDLE h; - int result = 0; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,0); - if (h == INVALID_HANDLE_VALUE) - goto err1; - - if (!ref) - ::free(buffer); - ref = 0; - - size = GetFileSize(h,NULL); - buffer = (unsigned char *) ::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: - ::free(buffer); - buffer = NULL; - len = 0; - -err1: - result = 1; - return result; -#else - assert(0); -#endif -} - -/***************************** - * Read a file with memory mapped file I/O. - */ - -int File::mmread() -{ -#if POSIX - return read(); -#elif _WIN32 - HANDLE hFile; - HANDLE hFileMap; - DWORD size; - char *name; - - name = this->name->toChars(); - hFile = CreateFile(name, GENERIC_READ, - FILE_SHARE_READ, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - goto Lerr; - size = GetFileSize(hFile, NULL); - //printf(" file created, size %d\n", size); - - hFileMap = CreateFileMapping(hFile,NULL,PAGE_READONLY,0,size,NULL); - if (CloseHandle(hFile) != TRUE) - goto Lerr; - - if (hFileMap == NULL) - goto Lerr; - - //printf(" mapping created\n"); - - if (!ref) - mem.free(buffer); - ref = 2; - buffer = (unsigned char *)MapViewOfFileEx(hFileMap, FILE_MAP_READ,0,0,size,NULL); - if (CloseHandle(hFileMap) != TRUE) - goto Lerr; - if (buffer == NULL) // mapping view failed - goto Lerr; - - len = size; - //printf(" buffer = %p\n", buffer); - - return 0; - -Lerr: - return GetLastError(); // failure -#else - assert(0); -#endif -} - -/********************************************* - * Write a file. - * Returns: - * 0 success - */ - -int File::write() -{ -#if POSIX - int fd; - ssize_t numwritten; - char *name; - - name = this->name->toChars(); - fd = open(name, O_CREAT | O_WRONLY | O_TRUNC, 0644); - if (fd == -1) - goto err; - - numwritten = ::write(fd, buffer, len); - if (len != numwritten) - goto err2; - - if (close(fd) == -1) - goto err; - - if (touchtime) - { struct utimbuf ubuf; - - ubuf.actime = ((struct stat *)touchtime)->st_atime; - ubuf.modtime = ((struct stat *)touchtime)->st_mtime; - if (utime(name, &ubuf)) - goto err; - } - return 0; - -err2: - close(fd); - ::remove(name); -err: - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); - DeleteFileA(name); -err: - return 1; -#else - assert(0); -#endif -} - -/********************************************* - * Append to a file. - * Returns: - * 0 success - */ - -int File::append() -{ -#if POSIX - return 1; -#elif _WIN32 - HANDLE h; - DWORD numwritten; - char *name; - - name = this->name->toChars(); - h = CreateFileA(name,GENERIC_WRITE,0,NULL,OPEN_ALWAYS, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL); - if (h == INVALID_HANDLE_VALUE) - goto err; - -#if 1 - SetFilePointer(h, 0, NULL, FILE_END); -#else // INVALID_SET_FILE_POINTER doesn't seem to have a definition - if (SetFilePointer(h, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER) - goto err; -#endif - - if (WriteFile(h,buffer,len,&numwritten,NULL) != TRUE) - goto err2; - - if (len != numwritten) - goto err2; - - if (touchtime) { - SetFileTime(h, NULL, NULL, &((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime); - } - if (!CloseHandle(h)) - goto err; - return 0; - -err2: - CloseHandle(h); -err: - return 1; -#else - assert(0); -#endif -} - -/************************************** - */ - -void File::readv() -{ - if (read()) - error("Error reading file '%s'\n",name->toChars()); -} - -/************************************** - */ - -void File::mmreadv() -{ - if (mmread()) - readv(); -} - -void File::writev() -{ - if (write()) - error("Error writing file '%s'\n",name->toChars()); -} - -void File::appendv() -{ - if (write()) - error("Error appending to file '%s'\n",name->toChars()); -} - -/******************************************* - * Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - -int File::exists() -{ -#if POSIX - return 0; -#elif _WIN32 - DWORD dw; - int result; - char *name; - - name = this->name->toChars(); - if (touchtime) - dw = ((WIN32_FIND_DATAA *)touchtime)->dwFileAttributes; - else - dw = GetFileAttributesA(name); - if (dw == -1L) - result = 0; - else if (dw & FILE_ATTRIBUTE_DIRECTORY) - result = 2; - else - result = 1; - return result; -#else - assert(0); -#endif -} - -void File::remove() -{ -#if POSIX - ::remove(this->name->toChars()); -#elif _WIN32 - DeleteFileA(this->name->toChars()); -#else - assert(0); -#endif -} - -Files *File::match(char *n) -{ - return match(new FileName(n, 0)); -} - -Files *File::match(FileName *n) -{ -#if POSIX - return NULL; -#elif _WIN32 - HANDLE h; - WIN32_FIND_DATAA fileinfo; - Files *a; - char *c; - char *name; - - a = new Files(); - c = n->toChars(); - name = n->name(); - h = FindFirstFileA(c,&fileinfo); - if (h != INVALID_HANDLE_VALUE) - { - do - { - // Glue path together with name - char *fn; - File *f; - - fn = (char *)mem.malloc(name - c + strlen(fileinfo.cFileName) + 1); - memcpy(fn, c, name - c); - strcpy(fn + (name - c), fileinfo.cFileName); - f = new File(fn); - f->touchtime = mem.malloc(sizeof(WIN32_FIND_DATAA)); - memcpy(f->touchtime, &fileinfo, sizeof(fileinfo)); - a->push(f); - } while (FindNextFileA(h,&fileinfo) != FALSE); - FindClose(h); - } - return a; -#else - assert(0); -#endif -} - -int File::compareTime(File *f) -{ -#if POSIX - return 0; -#elif _WIN32 - if (!touchtime) - stat(); - if (!f->touchtime) - f->stat(); - return CompareFileTime(&((WIN32_FIND_DATAA *)touchtime)->ftLastWriteTime, &((WIN32_FIND_DATAA *)f->touchtime)->ftLastWriteTime); -#else - assert(0); -#endif -} - -void File::stat() -{ -#if POSIX - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(struct stat)); - } -#elif _WIN32 - HANDLE h; - - if (!touchtime) - { - touchtime = mem.calloc(1, sizeof(WIN32_FIND_DATAA)); - } - h = FindFirstFileA(name->toChars(),(WIN32_FIND_DATAA *)touchtime); - if (h != INVALID_HANDLE_VALUE) - { - FindClose(h); - } -#else - assert(0); -#endif -} - -void File::checkoffset(size_t offset, size_t nbytes) -{ - if (offset > len || offset + nbytes > len) - error("Corrupt file '%s': offset x%zx off end of file",toChars(),offset); -} - -char *File::toChars() -{ - return name->toChars(); -} - - -/************************* OutBuffer *************************/ - -OutBuffer::OutBuffer() -{ - data = NULL; - offset = 0; - size = 0; -} - -OutBuffer::~OutBuffer() -{ - mem.free(data); -} - -char *OutBuffer::extractData() -{ - char *p; - - p = (char *)data; - data = NULL; - offset = 0; - size = 0; - return p; -} - -void OutBuffer::mark() -{ - mem.mark(data); -} - -void OutBuffer::reserve(unsigned nbytes) -{ - //printf("OutBuffer::reserve: size = %d, offset = %d, nbytes = %d\n", size, offset, nbytes); - if (size - offset < nbytes) - { - size = (offset + nbytes) * 2; - data = (unsigned char *)mem.realloc(data, size); - } -} - -void OutBuffer::reset() -{ - offset = 0; -} - -void OutBuffer::setsize(unsigned size) -{ - offset = size; -} - -void OutBuffer::write(const void *data, unsigned nbytes) -{ - reserve(nbytes); - memcpy(this->data + offset, data, nbytes); - offset += nbytes; -} - -void OutBuffer::writebstring(unsigned char *string) -{ - write(string,*string + 1); -} - -void OutBuffer::writestring(const char *string) -{ - write(string,strlen(string)); -} - -void OutBuffer::writedstring(const char *string) -{ -#if M_UNICODE - for (; *string; string++) - { - writedchar(*string); - } -#else - write(string,strlen(string)); -#endif -} - -void OutBuffer::writedstring(const wchar_t *string) -{ -#if M_UNICODE - write(string,wcslen(string) * sizeof(wchar_t)); -#else - for (; *string; string++) - { - writedchar(*string); - } -#endif -} - -void OutBuffer::prependstring(const char *string) -{ unsigned len; - - len = strlen(string); - reserve(len); - memmove(data + len, data, offset); - memcpy(data, string, len); - offset += len; -} - -void OutBuffer::writenl() -{ -#if _WIN32 -#if M_UNICODE - write4(0x000A000D); // newline is CR,LF on Microsoft OS's -#else - writeword(0x0A0D); // newline is CR,LF on Microsoft OS's -#endif -#else -#if M_UNICODE - writeword('\n'); -#else - writeByte('\n'); -#endif -#endif -} - -void OutBuffer::writeByte(unsigned b) -{ - reserve(1); - this->data[offset] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeUTF8(unsigned b) -{ - reserve(6); - if (b <= 0x7F) - { - this->data[offset] = (unsigned char)b; - offset++; - } - else if (b <= 0x7FF) - { - this->data[offset + 0] = (unsigned char)((b >> 6) | 0xC0); - this->data[offset + 1] = (unsigned char)((b & 0x3F) | 0x80); - offset += 2; - } - else if (b <= 0xFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 12) | 0xE0); - this->data[offset + 1] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)((b & 0x3F) | 0x80); - offset += 3; - } - else if (b <= 0x1FFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 18) | 0xF0); - this->data[offset + 1] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)((b & 0x3F) | 0x80); - offset += 4; - } - else if (b <= 0x3FFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 24) | 0xF8); - this->data[offset + 1] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)((b & 0x3F) | 0x80); - offset += 5; - } - else if (b <= 0x7FFFFFFF) - { - this->data[offset + 0] = (unsigned char)((b >> 30) | 0xFC); - this->data[offset + 1] = (unsigned char)(((b >> 24) & 0x3F) | 0x80); - this->data[offset + 2] = (unsigned char)(((b >> 18) & 0x3F) | 0x80); - this->data[offset + 3] = (unsigned char)(((b >> 12) & 0x3F) | 0x80); - this->data[offset + 4] = (unsigned char)(((b >> 6) & 0x3F) | 0x80); - this->data[offset + 5] = (unsigned char)((b & 0x3F) | 0x80); - offset += 6; - } - else - assert(0); -} - -void OutBuffer::writedchar(unsigned b) -{ - reserve(Dchar_mbmax * sizeof(dchar)); - offset = (unsigned char *)Dchar::put((dchar *)(this->data + offset), (dchar)b) - - this->data; -} - -void OutBuffer::prependbyte(unsigned b) -{ - reserve(1); - memmove(data + 1, data, offset); - data[0] = (unsigned char)b; - offset++; -} - -void OutBuffer::writeword(unsigned w) -{ - reserve(2); - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; -} - -void OutBuffer::writeUTF16(unsigned w) -{ - reserve(4); - if (w <= 0xFFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)w; - offset += 2; - } - else if (w <= 0x10FFFF) - { - *(unsigned short *)(this->data + offset) = (unsigned short)((w >> 10) + 0xD7C0); - *(unsigned short *)(this->data + offset + 2) = (unsigned short)((w & 0x3FF) | 0xDC00); - offset += 4; - } - else - assert(0); -} - -void OutBuffer::write4(unsigned w) -{ - reserve(4); - *(unsigned *)(this->data + offset) = w; - offset += 4; -} - -void OutBuffer::write(OutBuffer *buf) -{ - if (buf) - { reserve(buf->offset); - memcpy(data + offset, buf->data, buf->offset); - offset += buf->offset; - } -} - -void OutBuffer::write(Object *obj) -{ - if (obj) - { - writestring(obj->toChars()); - } -} - -void OutBuffer::fill0(unsigned nbytes) -{ - reserve(nbytes); - memset(data + offset,0,nbytes); - offset += nbytes; -} - -void OutBuffer::align(unsigned size) -{ unsigned nbytes; - - nbytes = ((offset + size - 1) & ~(size - 1)) - offset; - fill0(nbytes); -} - - -//////////////////////////////////////////////////////////////// -// The compiler shipped with Visual Studio 2005 (and possible -// other versions) does not support C99 printf format specfiers -// such as %z and %j -#if _MSC_VER -using std::string; -using std::wstring; - -template -inline void -search_and_replace(S& str, const S& what, const S& replacement) -{ - assert(!what.empty()); - size_t pos = str.find(what); - while (pos != S::npos) - { - str.replace(pos, what.size(), replacement); - pos = str.find(what, pos + replacement.size()); - } -} -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) \ - S tmp = f; \ - search_and_replace(fmt, S("%z"), S("%l")); \ - search_and_replace(fmt, S("%j"), S("%i")); \ - f = tmp.c_str(); -#else -#define WORKAROUND_C99_SPECIFIERS_BUG(S,tmp,f) -#endif - -void OutBuffer::vprintf(const char *format, va_list args) -{ - char buffer[128]; - char *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(string, fmt, format); - - p = buffer; - psize = sizeof(buffer); - for (;;) - { -#if _WIN32 - count = _vsnprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); -/* - The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() - are equivalent to the functions printf(), fprintf(), sprintf(), - snprintf(), respectively, except that they are called with a - va_list instead of a variable number of arguments. These - functions do not call the va_end macro. Consequently, the value - of ap is undefined after the call. The application should call - va_end(ap) itself afterwards. - */ - count = vsnprintf(p,psize,format,va); - va_end(va); - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (char *) alloca(psize); // buffer too small, try again with larger size - } - write(p,count); -} - -#if M_UNICODE -void OutBuffer::vprintf(const wchar_t *format, va_list args) -{ - dchar buffer[128]; - dchar *p; - unsigned psize; - int count; - - WORKAROUND_C99_SPECIFIERS_BUG(wstring, fmt, format); - - p = buffer; - psize = sizeof(buffer) / sizeof(buffer[0]); - for (;;) - { -#if _WIN32 - count = _vsnwprintf(p,psize,format,args); - if (count != -1) - break; - psize *= 2; -#elif POSIX - va_list va; - va_copy(va, args); - count = vsnwprintf(p,psize,format,va); - va_end(va); - - if (count == -1) - psize *= 2; - else if (count >= psize) - psize = count + 1; - else - break; -#else - assert(0); -#endif - p = (dchar *) alloca(psize * 2); // buffer too small, try again with larger size - } - write(p,count * 2); -} -#endif - -void OutBuffer::printf(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} - -#if M_UNICODE -void OutBuffer::printf(const wchar_t *format, ...) -{ - va_list ap; - va_start(ap, format); - vprintf(format,ap); - va_end(ap); -} -#endif - -void OutBuffer::bracket(char left, char right) -{ - reserve(2); - memmove(data + 1, data, offset); - data[0] = left; - data[offset + 1] = right; - offset += 2; -} - -/****************** - * Insert left at i, and right at j. - * Return index just past right. - */ - -unsigned OutBuffer::bracket(unsigned i, const char *left, unsigned j, const char *right) -{ - size_t leftlen = strlen(left); - size_t rightlen = strlen(right); - reserve(leftlen + rightlen); - insert(i, left, leftlen); - insert(j + leftlen, right, rightlen); - return j + leftlen + rightlen; -} - -void OutBuffer::spread(unsigned offset, unsigned nbytes) -{ - reserve(nbytes); - memmove(data + offset + nbytes, data + offset, - this->offset - offset); - this->offset += nbytes; -} - -/**************************************** - * Returns: offset + nbytes - */ - -unsigned OutBuffer::insert(unsigned offset, const void *p, unsigned nbytes) -{ - spread(offset, nbytes); - memmove(data + offset, p, nbytes); - return offset + nbytes; -} - -void OutBuffer::remove(unsigned offset, unsigned nbytes) -{ - memmove(data + offset, data + offset + nbytes, this->offset - (offset + nbytes)); - this->offset -= nbytes; -} - -char *OutBuffer::toChars() -{ - writeByte(0); - return (char *)data; -} - -/********************************* Bits ****************************/ - -Bits::Bits() -{ - data = NULL; - bitdim = 0; - allocdim = 0; -} - -Bits::~Bits() -{ - mem.free(data); -} - -void Bits::mark() -{ - mem.mark(data); -} - -void Bits::resize(unsigned bitdim) -{ - unsigned allocdim; - unsigned mask; - - allocdim = (bitdim + 31) / 32; - data = (unsigned *)mem.realloc(data, allocdim * sizeof(data[0])); - if (this->allocdim < allocdim) - memset(data + this->allocdim, 0, (allocdim - this->allocdim) * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= ~mask; - - this->bitdim = bitdim; - this->allocdim = allocdim; -} - -void Bits::set(unsigned bitnum) -{ - data[bitnum / 32] |= 1 << (bitnum & 31); -} - -void Bits::clear(unsigned bitnum) -{ - data[bitnum / 32] &= ~(1 << (bitnum & 31)); -} - -int Bits::test(unsigned bitnum) -{ - return data[bitnum / 32] & (1 << (bitnum & 31)); -} - -void Bits::set() -{ unsigned mask; - - memset(data, ~0, allocdim * sizeof(data[0])); - - // Clear other bits in last word - mask = (1 << (bitdim & 31)) - 1; - if (mask) - data[allocdim - 1] &= mask; -} - -void Bits::clear() -{ - memset(data, 0, allocdim * sizeof(data[0])); -} - -void Bits::copy(Bits *from) -{ - assert(bitdim == from->bitdim); - memcpy(data, from->data, allocdim * sizeof(data[0])); -} - -Bits *Bits::clone() -{ - Bits *b; - - b = new Bits(); - b->resize(bitdim); - b->copy(this); - return b; -} - -void Bits::sub(Bits *b) -{ - unsigned u; - - for (u = 0; u < allocdim; u++) - data[u] &= ~b->data[u]; -} - - - - - - - - - - - - - - - diff --git a/dmd2/root/root.h b/dmd2/root/root.h deleted file mode 100644 index bac6036e..00000000 --- a/dmd2/root/root.h +++ /dev/null @@ -1,417 +0,0 @@ - - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef ROOT_H -#define ROOT_H - -#include -#include -#ifdef DEBUG -#include -#endif - -#if __DMC__ -#pragma once -#endif - -typedef size_t hash_t; - -#include "dchar.h" - -char *wchar2ascii(wchar_t *); -int wcharIsAscii(wchar_t *); -char *wchar2ascii(wchar_t *, unsigned len); -int wcharIsAscii(wchar_t *, unsigned len); - -int bstrcmp(unsigned char *s1, unsigned char *s2); -char *bstr2str(unsigned char *b); -void error(const char *format, ...); -void error(const wchar_t *format, ...); -void warning(const char *format, ...); - -#ifndef TYPEDEFS -#define TYPEDEFS - -#if _MSC_VER -#include // for _isnan -#include // for alloca -// According to VC 8.0 docs, long double is the same as double -#define strtold strtod -#define strtof strtod -#define isnan _isnan - -typedef __int64 longlong; -typedef unsigned __int64 ulonglong; -#else -typedef long long longlong; -typedef unsigned long long ulonglong; -#endif - -#endif - -longlong randomx(); - -/* - * Root of our class library. - */ - -struct OutBuffer; - -// Can't include arraytypes.h here, need to declare these directly. -template struct ArrayBase; -typedef ArrayBase Files; -typedef ArrayBase Strings; - - -struct Object -{ - Object() { } - virtual ~Object() { } - - virtual int equals(Object *o); - - /** - * Returns a hash code, useful for things like building hash tables of Objects. - */ - virtual hash_t hashCode(); - - /** - * Return <0, ==0, or >0 if this is less than, equal to, or greater than obj. - * Useful for sorting Objects. - */ - virtual int compare(Object *obj); - - /** - * Pretty-print an Object. Useful for debugging the old-fashioned way. - */ - virtual void print(); - - virtual char *toChars(); - virtual dchar *toDchars(); - virtual void toBuffer(OutBuffer *buf); - - /** - * Used as a replacement for dynamic_cast. Returns a unique number - * defined by the library user. For Object, the return value is 0. - */ - virtual int dyncast(); - - /** - * Marks pointers for garbage collector by calling mem.mark() for all pointers into heap. - */ - /*virtual*/ // not used, disable for now - void mark(); -}; - -struct String : Object -{ - int ref; // != 0 if this is a reference to someone else's string - char *str; // the string itself - - String(char *str, int ref = 1); - - ~String(); - - static hash_t calcHash(const char *str, size_t len); - static hash_t calcHash(const char *str); - hash_t hashCode(); - unsigned len(); - int equals(Object *obj); - int compare(Object *obj); - char *toChars(); - void print(); - void mark(); -}; - -struct FileName : String -{ - FileName(char *str, int ref); - FileName(char *path, char *name); - hash_t hashCode(); - int equals(Object *obj); - static int equals(const char *name1, const char *name2); - int compare(Object *obj); - static int compare(const char *name1, const char *name2); - static int absolute(const char *name); - static char *ext(const char *); - char *ext(); - static char *removeExt(const char *str); - static char *name(const char *); - char *name(); - static char *path(const char *); - static const char *replaceName(const char *path, const char *name); - - static char *combine(const char *path, const char *name); - static Strings *splitPath(const char *path); - static FileName *defaultExt(const char *name, const char *ext); - static FileName *forceExt(const char *name, const char *ext); - int equalsExt(const char *ext); - - void CopyTo(FileName *to); - static char *searchPath(Strings *path, const char *name, int cwd); - static char *safeSearchPath(Strings *path, const char *name); - static int exists(const char *name); - static void ensurePathExists(const char *path); - static char *canonicalName(const char *name); -}; - -struct File : Object -{ - int ref; // != 0 if this is a reference to someone else's buffer - unsigned char *buffer; // data for our file - unsigned len; // amount of data in buffer[] - void *touchtime; // system time to use for file - - FileName *name; // name of our file - - File(char *); - File(FileName *); - ~File(); - - void mark(); - - char *toChars(); - - /* Read file, return !=0 if error - */ - - int read(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void readv(); - - /* Read file, return !=0 if error - */ - - int mmread(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void mmreadv(); - - /* Write file, return !=0 if error - */ - - int write(); - - /* Write file, either succeed or fail - * with error message & exit. - */ - - void writev(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - /* Append to file, return !=0 if error - */ - - int append(); - - /* Append to file, either succeed or fail - * with error message & exit. - */ - - void appendv(); - - /* Return !=0 if file exists. - * 0: file doesn't exist - * 1: normal file - * 2: directory - */ - - int exists(); - - /* Given wildcard filespec, return an array of - * matching File's. - */ - - static Files *match(char *); - static Files *match(FileName *); - - // Compare file times. - // Return <0 this < f - // =0 this == f - // >0 this > f - int compareTime(File *f); - - // Read system file statistics - void stat(); - - /* Set buffer - */ - - void setbuffer(void *buffer, unsigned len) - { - this->buffer = (unsigned char *)buffer; - this->len = len; - } - - void checkoffset(size_t offset, size_t nbytes); - - void remove(); // delete file -}; - -struct OutBuffer : Object -{ - unsigned char *data; - unsigned offset; - unsigned size; - - OutBuffer(); - ~OutBuffer(); - char *extractData(); - void mark(); - - void reserve(unsigned nbytes); - void setsize(unsigned size); - void reset(); - void write(const void *data, unsigned nbytes); - void writebstring(unsigned char *string); - void writestring(const char *string); - void writedstring(const char *string); - void writedstring(const wchar_t *string); - void prependstring(const char *string); - void writenl(); // write newline - void writeByte(unsigned b); - void writebyte(unsigned b) { writeByte(b); } - void writeUTF8(unsigned b); - void writedchar(unsigned b); - void prependbyte(unsigned b); - void writeword(unsigned w); - void writeUTF16(unsigned w); - void write4(unsigned w); - void write(OutBuffer *buf); - void write(Object *obj); - void fill0(unsigned nbytes); - void align(unsigned size); - void vprintf(const char *format, va_list args); - void printf(const char *format, ...); -#if M_UNICODE - void vprintf(const unsigned short *format, va_list args); - void printf(const unsigned short *format, ...); -#endif - void bracket(char left, char right); - unsigned bracket(unsigned i, const char *left, unsigned j, const char *right); - void spread(unsigned offset, unsigned nbytes); - unsigned insert(unsigned offset, const void *data, unsigned nbytes); - void remove(unsigned offset, unsigned nbytes); - char *toChars(); - char *extractString(); -}; - -struct Array : Object -{ - unsigned dim; - void **data; - - private: - unsigned allocdim; - #define SMALLARRAYCAP 1 - void *smallarray[SMALLARRAYCAP]; // inline storage for small arrays - - public: - Array(); - ~Array(); - //Array(const Array&); - void mark(); - char *toChars(); - - void reserve(unsigned nentries); - void setDim(unsigned newdim); - void fixDim(); - void push(void *ptr); - void *pop(); - void shift(void *ptr); - void insert(unsigned index, void *ptr); - void insert(unsigned index, Array *a); - void append(Array *a); - void remove(unsigned i); - void zero(); - void *tos(); - void sort(); - Array *copy(); -}; - -template -struct ArrayBase : Array -{ - TYPE **tdata() - { - return (TYPE **)data; - } - - TYPE*& operator[] (size_t index) - { -#ifdef DEBUG - assert(index < dim); -#endif - return ((TYPE **)data)[index]; - } - - void insert(size_t index, TYPE *v) - { - Array::insert(index, (void *)v); - } - - void insert(size_t index, ArrayBase *a) - { - Array::insert(index, (Array *)a); - } - - void append(ArrayBase *a) - { - Array::append((Array *)a); - } - - void push(TYPE *a) - { - Array::push((void *)a); - } - - ArrayBase *copy() - { - return (ArrayBase *)Array::copy(); - } -}; - -struct Bits : Object -{ - unsigned bitdim; - unsigned allocdim; - unsigned *data; - - Bits(); - ~Bits(); - void mark(); - - void resize(unsigned bitdim); - - void set(unsigned bitnum); - void clear(unsigned bitnum); - int test(unsigned bitnum); - - void set(); - void clear(); - void copy(Bits *from); - Bits *clone(); - - void sub(Bits *b); -}; - -#endif diff --git a/dmd2/root/speller.c b/dmd2/root/speller.c deleted file mode 100644 index d6437379..00000000 --- a/dmd2/root/speller.c +++ /dev/null @@ -1,257 +0,0 @@ - -#include -#include -#include -#include - -#if __sun&&__SVR4 -#include -#endif - -#include "speller.h" - -const char idchars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; - -/************************************************** - * Looks for correct spelling. - * Currently only looks a 'distance' of one from the seed[]. - * This does an exhaustive search, so can potentially be very slow. - * Input: - * seed wrongly spelled word - * fp search function - * fparg argument to search function - * charset character set - * Returns: - * NULL no correct spellings found - * void* value returned by fp() for first possible correct spelling - */ - -void *spellerY(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, - const char *charset, size_t index) -{ - if (!seedlen) - return NULL; - assert(seed[seedlen] == 0); - - char tmp[30]; - char *buf; - if (seedlen <= sizeof(tmp) - 2) - buf = tmp; - else - { - buf = (char *)alloca(seedlen + 2); // leave space for extra char - if (!buf) - return NULL; // no matches - } - - memcpy(buf, seed, index); - - /* Delete at seed[index] */ - if (index < seedlen) - { - memcpy(buf + index, seed + index + 1, seedlen - index); - assert(buf[seedlen - 1] == 0); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - - if (charset && *charset) - { - /* Substitutions */ - if (index < seedlen) - { - memcpy(buf, seed, seedlen + 1); - for (const char *s = charset; *s; s++) - { - buf[index] = *s; - - //printf("sub buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - assert(buf[seedlen] == 0); - } - - /* Insertions */ - memcpy (buf + index + 1, seed + index, seedlen + 1 - index); - - for (const char *s = charset; *s; s++) - { - buf[index] = *s; - - //printf("ins buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - } - assert(buf[seedlen + 1] == 0); - } - - return NULL; // didn't find any corrections -} - -void *spellerX(const char *seed, size_t seedlen, fp_speller_t fp, void *fparg, - const char *charset, int flag) -{ - if (!seedlen) - return NULL; - - char tmp[30]; - char *buf; - if (seedlen <= sizeof(tmp) - 2) - buf = tmp; - else - { - buf = (char *)alloca(seedlen + 2); // leave space for extra char - if (!buf) - return NULL; // no matches - } - - /* Deletions */ - memcpy(buf, seed + 1, seedlen); - for (size_t i = 0; i < seedlen; i++) - { - //printf("del buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen - 1, fp, fparg, charset, i); - else - p = (*fp)(fparg, buf); - if (p) - return p; - - buf[i] = seed[i]; - } - - /* Transpositions */ - if (!flag) - { - memcpy(buf, seed, seedlen + 1); - for (size_t i = 0; i + 1 < seedlen; i++) - { - // swap [i] and [i + 1] - buf[i] = seed[i + 1]; - buf[i + 1] = seed[i]; - - //printf("tra buf = '%s'\n", buf); - void *p = (*fp)(fparg, buf); - if (p) - return p; - - buf[i] = seed[i]; - } - } - - if (charset && *charset) - { - /* Substitutions */ - memcpy(buf, seed, seedlen + 1); - for (size_t i = 0; i < seedlen; i++) - { - for (const char *s = charset; *s; s++) - { - buf[i] = *s; - - //printf("sub buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen, fp, fparg, charset, i + 1); - else - p = (*fp)(fparg, buf); - if (p) - return p; - } - buf[i] = seed[i]; - } - - /* Insertions */ - memcpy(buf + 1, seed, seedlen + 1); - for (size_t i = 0; i <= seedlen; i++) // yes, do seedlen+1 iterations - { - for (const char *s = charset; *s; s++) - { - buf[i] = *s; - - //printf("ins buf = '%s'\n", buf); - void *p; - if (flag) - p = spellerY(buf, seedlen + 1, fp, fparg, charset, i + 1); - else - p = (*fp)(fparg, buf); - if (p) - return p; - } - buf[i] = seed[i]; // going past end of seed[] is ok, as we hit the 0 - } - } - - return NULL; // didn't find any corrections -} - -void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset) -{ - size_t seedlen = strlen(seed); - for (int distance = 0; distance < 2; distance++) - { void *p = spellerX(seed, seedlen, fp, fparg, charset, distance); - if (p) - return p; -// if (seedlen > 10) -// break; - } - return NULL; // didn't find it -} - - -#if UNITTEST - -#include -#include -#include - -void *speller_test(void *fparg, const char *s) -{ - //printf("speller_test(%s, %s)\n", fparg, s); - if (strcmp((char *)fparg, s) == 0) - return fparg; - return NULL; -} - -void unittest_speller() -{ - static const char *cases[][3] = - { - { "hello", "hell", "y" }, - { "hello", "hel", "y" }, - { "hello", "ello", "y" }, - { "hello", "llo", "y" }, - { "hello", "hellox", "y" }, - { "hello", "helloxy", "y" }, - { "hello", "xhello", "y" }, - { "hello", "xyhello", "y" }, - { "hello", "ehllo", "y" }, - { "hello", "helol", "y" }, - { "hello", "abcd", "n" }, - //{ "ehllo", "helol", "y" }, - { "hello", "helxxlo", "y" }, - { "hello", "ehlxxlo", "n" }, - { "hello", "heaao", "y" }, - { "_123456789_123456789_123456789_123456789", "_123456789_123456789_123456789_12345678", "y" }, - }; - //printf("unittest_speller()\n"); - const void *p = speller("hello", &speller_test, (void *)"hell", idchars); - assert(p != NULL); - for (int i = 0; i < sizeof(cases)/sizeof(cases[0]); i++) - { - //printf("case [%d]\n", i); - void *p = speller(cases[i][0], &speller_test, (void *)cases[i][1], idchars); - if (p) - assert(cases[i][2][0] == 'y'); - else - assert(cases[i][2][0] == 'n'); - } - //printf("unittest_speller() success\n"); -} - -#endif diff --git a/dmd2/root/speller.h b/dmd2/root/speller.h deleted file mode 100644 index bfffb739..00000000 --- a/dmd2/root/speller.h +++ /dev/null @@ -1,7 +0,0 @@ - -typedef void *(fp_speller_t)(void *, const char *); - -extern const char idchars[]; - -void *speller(const char *seed, fp_speller_t fp, void *fparg, const char *charset); - diff --git a/dmd2/root/stringtable.c b/dmd2/root/stringtable.c deleted file mode 100644 index f1c0044a..00000000 --- a/dmd2/root/stringtable.c +++ /dev/null @@ -1,139 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#include -#include -#include - -#include "root.h" -#include "rmem.h" -#include "dchar.h" -#include "lstring.h" -#include "stringtable.h" - -void StringTable::init(unsigned size) -{ - table = (void **)mem.calloc(size, sizeof(void *)); - tabledim = size; - count = 0; -} - -StringTable::~StringTable() -{ - unsigned i; - - // Zero out dangling pointers to help garbage collector. - // Should zero out StringEntry's too. - for (i = 0; i < count; i++) - table[i] = NULL; - - mem.free(table); - table = NULL; -} - -struct StringEntry -{ - StringEntry *left; - StringEntry *right; - hash_t hash; - - StringValue value; - - static StringEntry *alloc(const dchar *s, unsigned len); -}; - -StringEntry *StringEntry::alloc(const dchar *s, unsigned len) -{ - StringEntry *se; - - se = (StringEntry *) mem.calloc(1,sizeof(StringEntry) - sizeof(Lstring) + Lstring::size(len)); - se->value.lstring.length = len; - se->hash = Dchar::calcHash(s,len); - memcpy(se->value.lstring.string, s, len * sizeof(dchar)); - return se; -} - -void **StringTable::search(const dchar *s, unsigned len) -{ - hash_t hash; - unsigned u; - int cmp; - StringEntry **se; - - //printf("StringTable::search(%p,%d)\n",s,len); - hash = Dchar::calcHash(s,len); - u = hash % tabledim; - se = (StringEntry **)&table[u]; - //printf("\thash = %d, u = %d\n",hash,u); - while (*se) - { - cmp = (*se)->hash - hash; - if (cmp == 0) - { - cmp = (*se)->value.lstring.len() - len; - if (cmp == 0) - { - cmp = Dchar::memcmp(s,(*se)->value.lstring.toDchars(),len); - if (cmp == 0) - break; - } - } - if (cmp < 0) - se = &(*se)->left; - else - se = &(*se)->right; - } - //printf("\treturn %p, %p\n",se, (*se)); - return (void **)se; -} - -StringValue *StringTable::lookup(const dchar *s, unsigned len) -{ StringEntry *se; - - se = *(StringEntry **)search(s,len); - if (se) - return &se->value; - else - return NULL; -} - -StringValue *StringTable::update(const dchar *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (!se) // not in table: so create new entry - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} - -StringValue *StringTable::insert(const dchar *s, unsigned len) -{ StringEntry **pse; - StringEntry *se; - - pse = (StringEntry **)search(s,len); - se = *pse; - if (se) - return NULL; // error: already in table - else - { - se = StringEntry::alloc(s, len); - *pse = se; - } - return &se->value; -} - - - - diff --git a/dmd2/root/stringtable.h b/dmd2/root/stringtable.h deleted file mode 100644 index ce714587..00000000 --- a/dmd2/root/stringtable.h +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - - -#ifndef STRINGTABLE_H -#define STRINGTABLE_H - -#if __SC__ -#pragma once -#endif - -#include "root.h" -#include "dchar.h" -#include "lstring.h" - -struct StringValue -{ - union - { int intvalue; - void *ptrvalue; - dchar *string; - }; - Lstring lstring; -}; - -struct StringTable -{ - void **table; - unsigned count; - unsigned tabledim; - - void init(unsigned size = 37); - ~StringTable(); - - StringValue *lookup(const dchar *s, unsigned len); - StringValue *insert(const dchar *s, unsigned len); - StringValue *update(const dchar *s, unsigned len); - -private: - void **search(const dchar *s, unsigned len); -}; - -#endif diff --git a/dmd2/scope.c b/dmd2/scope.c deleted file mode 100644 index a23654e9..00000000 --- a/dmd2/scope.c +++ /dev/null @@ -1,403 +0,0 @@ - -// Copyright (c) 1999-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "speller.h" - -#include "mars.h" -#include "init.h" -#include "identifier.h" -#include "attrib.h" -#include "dsymbol.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "module.h" -#include "id.h" -#include "lexer.h" - -Scope *Scope::freelist = NULL; - -void *Scope::operator new(size_t size) -{ - if (freelist) - { - Scope *s = freelist; - freelist = s->enclosing; - //printf("freelist %p\n", s); - assert(s->flags & SCOPEfree); - s->flags &= ~SCOPEfree; - return s; - } - - void *p = ::operator new(size); - //printf("new %p\n", p); - return p; -} - -Scope::Scope() -{ // Create root scope - - //printf("Scope::Scope() %p\n", this); - this->module = NULL; - this->scopesym = NULL; - this->sd = NULL; - this->enclosing = NULL; - this->parent = NULL; - this->sw = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->tinst = NULL; - this->sbreak = NULL; - this->scontinue = NULL; - this->fes = NULL; - this->structalign = global.structalign; - this->func = NULL; - this->slabel = NULL; - this->linkage = LINKd; - this->protection = PROTpublic; - this->explicitProtection = 0; - this->stc = 0; - this->offset = 0; - this->inunion = 0; - this->incontract = 0; - this->nofree = 0; - this->noctor = 0; - this->noaccesscheck = 0; - this->mustsemantic = 0; - this->intypeof = 0; - this->parameterSpecialization = 0; - this->ignoreTemplates = 0; - this->callSuper = 0; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = NULL; -} - -Scope::Scope(Scope *enclosing) -{ - //printf("Scope::Scope(enclosing = %p) %p\n", enclosing, this); - assert(!(enclosing->flags & SCOPEfree)); - this->module = enclosing->module; - this->func = enclosing->func; - this->parent = enclosing->parent; - this->scopesym = NULL; - this->sd = NULL; - this->sw = enclosing->sw; - this->enclosingFinally = enclosing->enclosingFinally; - this->enclosingScopeExit = enclosing->enclosingScopeExit; - this->tinst = enclosing->tinst; - this->sbreak = enclosing->sbreak; - this->scontinue = enclosing->scontinue; - this->fes = enclosing->fes; - this->structalign = enclosing->structalign; - this->enclosing = enclosing; -#ifdef DEBUG - if (enclosing->enclosing) - assert(!(enclosing->enclosing->flags & SCOPEfree)); - if (this == enclosing->enclosing) - { - printf("this = %p, enclosing = %p, enclosing->enclosing = %p\n", this, enclosing, enclosing->enclosing); - } - assert(this != enclosing->enclosing); -#endif - this->slabel = NULL; - this->linkage = enclosing->linkage; - this->protection = enclosing->protection; - this->explicitProtection = enclosing->explicitProtection; - this->stc = enclosing->stc; - this->offset = 0; - this->inunion = enclosing->inunion; - this->incontract = enclosing->incontract; - this->nofree = 0; - this->noctor = enclosing->noctor; - this->noaccesscheck = enclosing->noaccesscheck; - this->mustsemantic = enclosing->mustsemantic; - this->intypeof = enclosing->intypeof; - this->parameterSpecialization = enclosing->parameterSpecialization; - this->ignoreTemplates = enclosing->ignoreTemplates; - this->callSuper = enclosing->callSuper; - this->flags = 0; - this->anonAgg = NULL; - this->lastdc = NULL; - this->lastoffset = 0; - this->docbuf = enclosing->docbuf; - assert(this != enclosing); -} - -Scope *Scope::createGlobal(Module *module) -{ - Scope *sc; - - sc = new Scope(); - sc->module = module; - sc->scopesym = new ScopeDsymbol(); - sc->scopesym->symtab = new DsymbolTable(); - - // Add top level package as member of this global scope - Dsymbol *m = module; - while (m->parent) - m = m->parent; - m->addMember(NULL, sc->scopesym, 1); - m->parent = NULL; // got changed by addMember() - - // Create the module scope underneath the global scope - sc = sc->push(module); - sc->parent = module; - return sc; -} - -Scope *Scope::push() -{ - //printf("Scope::push()\n"); - Scope *s = new Scope(this); - assert(this != s); - return s; -} - -Scope *Scope::push(ScopeDsymbol *ss) -{ - //printf("Scope::push(%s)\n", ss->toChars()); - Scope *s = push(); - s->scopesym = ss; - return s; -} - -Scope *Scope::pop() -{ - //printf("Scope::pop() %p nofree = %d\n", this, nofree); - Scope *enc = enclosing; - - if (enclosing) - enclosing->callSuper |= callSuper; - - if (!nofree) - { enclosing = freelist; - freelist = this; - flags |= SCOPEfree; - } - - return enc; -} - -void Scope::mergeCallSuper(Loc loc, unsigned cs) -{ - // This does a primitive flow analysis to support the restrictions - // regarding when and how constructors can appear. - // It merges the results of two paths. - // The two paths are callSuper and cs; the result is merged into callSuper. - - if (cs != callSuper) - { int a; - int b; - - callSuper |= cs & (CSXany_ctor | CSXlabel); - if (cs & CSXreturn) - { - } - else if (callSuper & CSXreturn) - { - callSuper = cs | (callSuper & (CSXany_ctor | CSXlabel)); - } - else - { - a = (cs & (CSXthis_ctor | CSXsuper_ctor)) != 0; - b = (callSuper & (CSXthis_ctor | CSXsuper_ctor)) != 0; - if (a != b) - error(loc, "one path skips constructor"); - callSuper |= cs; - } - } -} - -Dsymbol *Scope::search(Loc loc, Identifier *ident, Dsymbol **pscopesym) -{ Dsymbol *s; - Scope *sc; - - //printf("Scope::search(%p, '%s')\n", this, ident->toChars()); - if (ident == Id::empty) - { - // Look for module scope - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - s = sc->scopesym->isModule(); - if (s) - { - //printf("\tfound %s.%s\n", s->parent ? s->parent->toChars() : "", s->toChars()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - return NULL; - } - - for (sc = this; sc; sc = sc->enclosing) - { - assert(sc != sc->enclosing); - if (sc->scopesym) - { - //printf("\tlooking in scopesym '%s', kind = '%s'\n", sc->scopesym->toChars(), sc->scopesym->kind()); - s = sc->scopesym->search(loc, ident, 0); - if (s) - { - if ((global.params.warnings || - global.params.Dversion > 1) && - ident == Id::length && - sc->scopesym->isArrayScopeSymbol() && - sc->enclosing && - sc->enclosing->search(loc, ident, NULL)) - { - warning(s->loc, "array 'length' hides other 'length' name in outer scope"); - } - - //printf("\tfound %s.%s, kind = '%s'\n", s->parent ? s->parent->toChars() : "", s->toChars(), s->kind()); - if (pscopesym) - *pscopesym = sc->scopesym; - return s; - } - } - } - - return NULL; -} - -Dsymbol *Scope::insert(Dsymbol *s) -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - if (sc->scopesym) - { - //printf("\t\tsc->scopesym = %p\n", sc->scopesym); - if (!sc->scopesym->symtab) - sc->scopesym->symtab = new DsymbolTable(); - return sc->scopesym->symtabInsert(s); - } - } - assert(0); - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -ClassDeclaration *Scope::getClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - ClassDeclaration *cd; - - if (sc->scopesym) - { - cd = sc->scopesym->isClassDeclaration(); - if (cd) - return cd; - } - } - return NULL; -} - -/******************************************** - * Search enclosing scopes for ClassDeclaration. - */ - -AggregateDeclaration *Scope::getStructClassScope() -{ Scope *sc; - - for (sc = this; sc; sc = sc->enclosing) - { - AggregateDeclaration *ad; - - if (sc->scopesym) - { - ad = sc->scopesym->isClassDeclaration(); - if (ad) - return ad; - else - { ad = sc->scopesym->isStructDeclaration(); - if (ad) - return ad; - } - } - } - return NULL; -} - -/******************************************* - * For TemplateDeclarations, we need to remember the Scope - * where it was declared. So mark the Scope as not - * to be free'd. - */ - -void Scope::setNoFree() -{ Scope *sc; - //int i = 0; - - //printf("Scope::setNoFree(this = %p)\n", this); - for (sc = this; sc; sc = sc->enclosing) - { - //printf("\tsc = %p\n", sc); - sc->nofree = 1; - - assert(!(flags & SCOPEfree)); - //assert(sc != sc->enclosing); - //assert(!sc->enclosing || sc != sc->enclosing->enclosing); - //if (++i == 10) - //assert(0); - } -} - - -/************************************************ - * Given the failed search attempt, try to find - * one with a close spelling. - */ - -void *scope_search_fp(void *arg, const char *seed) -{ - //printf("scope_search_fp('%s')\n", seed); - - /* If not in the lexer's string table, it certainly isn't in the symbol table. - * Doing this first is a lot faster. - */ - size_t len = strlen(seed); - if (!len) - return NULL; - StringValue *sv = Lexer::stringtable.lookup(seed, len); - if (!sv) - return NULL; - Identifier *id = (Identifier *)sv->ptrvalue; - assert(id); - - Scope *sc = (Scope *)arg; - Module::clearCache(); - Dsymbol *s = sc->search(0, id, NULL); - return s; -} - -Dsymbol *Scope::search_correct(Identifier *ident) -{ - if (global.gag) - return NULL; // don't do it for speculative compiles; too time consuming - - return (Dsymbol *)speller(ident->toChars(), &scope_search_fp, this, idchars); -} diff --git a/dmd2/scope.h b/dmd2/scope.h deleted file mode 100644 index ea725f09..00000000 --- a/dmd2/scope.h +++ /dev/null @@ -1,129 +0,0 @@ - -// Copyright (c) 1999-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_SCOPE_H -#define DMD_SCOPE_H - -#ifdef __DMC__ -#pragma once -#endif - -struct Dsymbol; -struct ScopeDsymbol; -struct Identifier; -struct Module; -struct Statement; -struct SwitchStatement; -struct TryFinallyStatement; -struct LabelStatement; -struct ForeachStatement; -struct ClassDeclaration; -struct AggregateDeclaration; -struct AnonymousAggregateDeclaration; -struct FuncDeclaration; -struct DocComment; -struct TemplateInstance; - -#if IN_LLVM -struct EnclosingHandler; -struct AnonDeclaration; -#endif - -#if __GNUC__ -// Requires a full definition for PROT and LINK -#include "dsymbol.h" // PROT -#include "mars.h" // LINK -#else -enum LINK; -enum PROT; -#endif - -struct Scope -{ - Scope *enclosing; // enclosing Scope - - Module *module; // Root module - ScopeDsymbol *scopesym; // current symbol - ScopeDsymbol *sd; // if in static if, and declaring new symbols, - // sd gets the addMember() - FuncDeclaration *func; // function we are in - Dsymbol *parent; // parent to use - LabelStatement *slabel; // enclosing labelled statement - SwitchStatement *sw; // enclosing switch statement - TryFinallyStatement *enclosingFinally; // enclosing try finally statement; set inside its finally block - TemplateInstance *tinst; // enclosing template instance - Statement *enclosingScopeExit; // enclosing statement that wants to do something on scope exit - Statement *sbreak; // enclosing statement that supports "break" - Statement *scontinue; // enclosing statement that supports "continue" - ForeachStatement *fes; // if nested function for ForeachStatement, this is it - unsigned offset; // next offset to use in aggregate - int inunion; // we're processing members of a union - int incontract; // we're inside contract code - int nofree; // set if shouldn't free it - int noctor; // set if constructor calls aren't allowed - int intypeof; // in typeof(exp) - int parameterSpecialization; // if in template parameter specialization - int noaccesscheck; // don't do access checks - int mustsemantic; // cannot defer semantic() - int ignoreTemplates; // set if newly instantiated templates should be ignored when codegen'ing - - unsigned callSuper; // primitive flow analysis for constructors -#define CSXthis_ctor 1 // called this() -#define CSXsuper_ctor 2 // called super() -#define CSXthis 4 // referenced this -#define CSXsuper 8 // referenced super -#define CSXlabel 0x10 // seen a label -#define CSXreturn 0x20 // seen a return statement -#define CSXany_ctor 0x40 // either this() or super() was called - - unsigned structalign; // alignment for struct members - enum LINK linkage; // linkage for external functions - - enum PROT protection; // protection for class members - int explicitProtection; // set if in an explicit protection attribute - - StorageClass stc; // storage class - - unsigned flags; -#define SCOPEctor 1 // constructor type -#define SCOPEstaticif 2 // inside static if -#define SCOPEfree 4 // is on free list -#define SCOPEstaticassert 8 // inside static assert -#define SCOPEdebug 0x10 // inside debug conditional - - AnonymousAggregateDeclaration *anonAgg; // for temporary analysis - - DocComment *lastdc; // documentation comment for last symbol at this scope - unsigned lastoffset; // offset in docbuf of where to insert next dec - OutBuffer *docbuf; // buffer for documentation output - - static Scope *freelist; - static void *operator new(size_t sz); - static Scope *createGlobal(Module *module); - - Scope(); - Scope(Module *module); - Scope(Scope *enclosing); - - Scope *push(); - Scope *push(ScopeDsymbol *ss); - Scope *pop(); - - void mergeCallSuper(Loc loc, unsigned cs); - - Dsymbol *search(Loc loc, Identifier *ident, Dsymbol **pscopesym); - Dsymbol *search_correct(Identifier *ident); - Dsymbol *insert(Dsymbol *s); - - ClassDeclaration *getClassScope(); - AggregateDeclaration *getStructClassScope(); - void setNoFree(); -}; - -#endif /* DMD_SCOPE_H */ diff --git a/dmd2/sideeffect.c b/dmd2/sideeffect.c deleted file mode 100644 index a80f874e..00000000 --- a/dmd2/sideeffect.c +++ /dev/null @@ -1,250 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "mars.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "statement.h" -#include "mtype.h" -#include "utf.h" -#include "declaration.h" -#include "aggregate.h" -#include "scope.h" -#include "attrib.h" - -int lambdaHasSideEffect(Expression *e, void *param); - -/******************************************** - * Determine if Expression has any side effects. - */ - -bool Expression::hasSideEffect() -{ - bool has = FALSE; - apply(&lambdaHasSideEffect, &has); - return has; -} - -int lambdaHasSideEffect(Expression *e, void *param) -{ - bool *phas = (bool *)param; - switch (e->op) - { - // Sort the cases by most frequently used first - case TOKassign: - case TOKplusplus: - case TOKminusminus: - case TOKdeclaration: - case TOKconstruct: - case TOKblit: - case TOKaddass: - case TOKminass: - case TOKcatass: - case TOKmulass: - case TOKdivass: - case TOKmodass: - case TOKshlass: - case TOKshrass: - case TOKushrass: - case TOKandass: - case TOKorass: - case TOKxorass: - case TOKpowass: - case TOKin: - case TOKremove: - case TOKassert: - case TOKhalt: - case TOKdelete: - case TOKnew: - case TOKnewanonclass: - *phas = TRUE; - break; - - case TOKcall: - { CallExp *ce = (CallExp *)e; - - /* Calling a function or delegate that is pure nothrow - * has no side effects. - */ - if (ce->e1->type) - { - Type *t = ce->e1->type->toBasetype(); - if ((t->ty == Tfunction && ((TypeFunction *)t)->purity > PUREweak && - ((TypeFunction *)t)->isnothrow) - || - (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->purity > PUREweak && - ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) - ) - { - } - else - *phas = TRUE; - } - break; - } - - case TOKcast: - { CastExp *ce = (CastExp *)e; - - /* if: - * cast(classtype)func() // because it may throw - */ - if (ce->to->ty == Tclass && ce->e1->op == TOKcall && ce->e1->type->ty == Tclass) - *phas = TRUE; - break; - } - - default: - break; - } - return *phas; // stop walking if we determine this expression has side effects -} - - -/*********************************** - * The result of this expression will be discarded. - * Complain if the operation has no side effects (and hence is meaningless). - */ -void Expression::discardValue() -{ - bool has = FALSE; - lambdaHasSideEffect(this, &has); - if (!has) - { - switch (op) - { - case TOKcast: - { CastExp *ce = (CastExp *)this; - if (ce->to->equals(Type::tvoid)) - { /* - * Don't complain about an expression with no effect if it was cast to void - */ - ce->e1->useValue(); - break; - } - goto Ldefault; // complain - } - - case TOKerror: - break; - - case TOKcall: - /* Don't complain about calling functions with no effect, - * because purity and nothrow are inferred, and because some of the - * runtime library depends on it. Needs more investigation. - */ - break; - - case TOKimport: - error("%s has no effect", toChars()); - break; - - case TOKandand: - { AndAndExp *aae = (AndAndExp *)this; - aae->e1->useValue(); - aae->e2->discardValue(); - break; - } - - case TOKoror: - { OrOrExp *ooe = (OrOrExp *)this; - ooe->e1->useValue(); - ooe->e2->discardValue(); - break; - } - - case TOKquestion: - { CondExp *ce = (CondExp *)this; - ce->econd->useValue(); - ce->e1->discardValue(); - ce->e2->discardValue(); - break; - } - - case TOKcomma: - { CommaExp *ce = (CommaExp *)this; - - /* Check for compiler-generated code of the form auto __tmp, e, __tmp; - * In such cases, only check e for side effect (it's OK for __tmp to have - * no side effect). - * See Bugzilla 4231 for discussion - */ - CommaExp* firstComma = ce; - while (firstComma->e1->op == TOKcomma) - firstComma = (CommaExp *)firstComma->e1; - if (firstComma->e1->op == TOKdeclaration && - ce->e2->op == TOKvar && - ((DeclarationExp *)firstComma->e1)->declaration == ((VarExp*)ce->e2)->var) - { - ce->e1->useValue(); - break; - } - // Don't check e1 until we cast(void) the a,b code generation - //ce->e1->discardValue(); - ce->e2->discardValue(); - break; - } - - case TOKtuple: - /* Pass without complaint if any of the tuple elements have side effects. - * Ideally any tuple elements with no side effects should raise an error, - * this needs more investigation as to what is the right thing to do. - */ - if (!hasSideEffect()) - goto Ldefault; - break; - - default: - Ldefault: - error("%s has no effect in expression (%s)", - Token::toChars(op), toChars()); - break; - } - } - else - { - useValue(); - } -} - -/* This isn't used yet because the only way an expression has an unused sub-expression - * is with the CommaExp, and that currently generates messages from rewrites into comma - * expressions. Needs more investigation. - */ -void Expression::useValue() -{ -#if 0 - // Disabled because need to cast(void) the a,b code generation - void *p; - apply(&lambdaUseValue, &p); -#endif -} - -#if 0 -int lambdaUseValue(Expression *e, void *param) -{ - switch (e->op) - { - case TOKcomma: - { CommaExp *ce = (CommaExp *)e; - discardValue(ce->E1); - break; - } - - default: - break; - } - return 0; -} -#endif diff --git a/dmd2/statement.c b/dmd2/statement.c deleted file mode 100644 index 61aca6d4..00000000 --- a/dmd2/statement.c +++ /dev/null @@ -1,5287 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "rmem.h" - -#include "statement.h" -#include "expression.h" -#include "cond.h" -#include "init.h" -#include "staticassert.h" -#include "mtype.h" -#include "scope.h" -#include "declaration.h" -#include "aggregate.h" -#include "id.h" -#include "hdrgen.h" -#include "parse.h" -#include "template.h" -#include "attrib.h" - -#if IN_LLVM -#if defined(_MSC_VER) -#include -#else -#include -#endif - -// sizes based on those from tollvm.cpp:DtoMutexType() -int os_critsecsize() -{ -#if defined(_MSC_VER) - // TODO Check size - return 68; -#else - if (global.params.os == OSWindows) - return 68; - else if (global.params.os == OSFreeBSD) - return sizeof(size_t); - else - return sizeof(pthread_mutex_t); -#endif -} -#elif IN_DMD - -extern int os_critsecsize32(); -extern int os_critsecsize64(); - -#endif - -/******************************** Statement ***************************/ - -Statement::Statement(Loc loc) - : loc(loc) -{ - // If this is an in{} contract scope statement (skip for determining - // inlineStatus of a function body for header content) - incontract = 0; -} - -Statement *Statement::syntaxCopy() -{ - assert(0); - return NULL; -} - -void Statement::print() -{ - fprintf(stdmsg, "%s\n", toChars()); - fflush(stdmsg); -} - -char *Statement::toChars() -{ OutBuffer *buf; - HdrGenState hgs; - - buf = new OutBuffer(); - toCBuffer(buf, &hgs); - return buf->toChars(); -} - -void Statement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("Statement::toCBuffer()"); - buf->writenl(); -} - -Statement *Statement::semantic(Scope *sc) -{ - return this; -} - -Statement *Statement::semanticNoScope(Scope *sc) -{ - //printf("Statement::semanticNoScope() %s\n", toChars()); - Statement *s = this; - if (!s->isCompoundStatement() && !s->isScopeStatement()) - { - s = new CompoundStatement(loc, this); // so scopeCode() gets called - } - s = s->semantic(sc); - return s; -} - -// Same as semanticNoScope(), but do create a new scope - -Statement *Statement::semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue) -{ - Scope *scd = sc->push(); - if (sbreak) - scd->sbreak = sbreak; - if (scontinue) - scd->scontinue = scontinue; - Statement *s = semanticNoScope(scd); - scd->pop(); - return s; -} - -void Statement::error(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::verror(loc, format, ap); - va_end( ap ); -} - -void Statement::warning(const char *format, ...) -{ - va_list ap; - va_start(ap, format); - ::vwarning(loc, format, ap); - va_end( ap ); -} - -int Statement::hasBreak() -{ - //printf("Statement::hasBreak()\n"); - return FALSE; -} - -int Statement::hasContinue() -{ - return FALSE; -} - -// TRUE if statement uses exception handling - -int Statement::usesEH() -{ - return FALSE; -} - -/* Only valid after semantic analysis - * If 'mustNotThrow' is true, generate an error if it throws - */ -int Statement::blockExit(bool mustNotThrow) -{ - printf("Statement::blockExit(%p)\n", this); - printf("%s\n", toChars()); - assert(0); - return BEany; -} - -// TRUE if statement 'comes from' somewhere else, like a goto - -int Statement::comeFrom() -{ - //printf("Statement::comeFrom()\n"); - return FALSE; -} - -// Return TRUE if statement has no code in it -int Statement::isEmpty() -{ - //printf("Statement::isEmpty()\n"); - return FALSE; -} - -Statement *Statement::last() -{ - return this; -} - -/**************************************** - * If this statement has code that needs to run in a finally clause - * at the end of the current scope, return that code in the form of - * a Statement. - * Output: - * *sentry code executed upon entry to the scope - * *sexception code executed upon exit from the scope via exception - * *sfinally code executed in finally block - */ - -Statement *Statement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("Statement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - return this; -} - -/********************************* - * Flatten out the scope by presenting the statement - * as an array of statements. - * Returns NULL if no flattening necessary. - */ - -Statements *Statement::flatten(Scope *sc) -{ - return NULL; -} - - -/******************************** PeelStatement ***************************/ - -PeelStatement::PeelStatement(Statement *s) - : Statement(s->loc) -{ - this->s = s; -} - -Statement *PeelStatement::semantic(Scope *sc) -{ - /* "peel" off this wrapper, and don't run semantic() - * on the result. - */ - return s; -} - -/******************************** ExpStatement ***************************/ - -ExpStatement::ExpStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -ExpStatement::ExpStatement(Loc loc, Dsymbol *declaration) - : Statement(loc) -{ - this->exp = new DeclarationExp(loc, declaration); -} - -Statement *ExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - ExpStatement *es = new ExpStatement(loc, e); - return es; -} - -void ExpStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (exp) - { exp->toCBuffer(buf, hgs); - if (exp->op != TOKdeclaration) - { buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); - } - } - else - { - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); - } -} - -Statement *ExpStatement::semantic(Scope *sc) -{ - if (exp) - { - //printf("ExpStatement::semantic() %s\n", exp->toChars()); - -#if 0 // Doesn't work because of difficulty dealing with things like a.b.c!(args).Foo!(args) - // See if this should be rewritten as a TemplateMixin - if (exp->op == TOKdeclaration) - { DeclarationExp *de = (DeclarationExp *)exp; - Dsymbol *s = de->declaration; - - printf("s: %s %s\n", s->kind(), s->toChars()); - VarDeclaration *v = s->isVarDeclaration(); - if (v) - { - printf("%s, %d\n", v->type->toChars(), v->type->ty); - } - } -#endif - - exp = exp->semantic(sc); - exp = exp->addDtorHook(sc); - exp = resolveProperties(sc, exp); - exp->discardValue(); - exp = exp->optimize(0); - } - return this; -} - -int ExpStatement::blockExit(bool mustNotThrow) -{ 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(mustNotThrow)) - result |= BEthrow; - } - return result; -} - -int ExpStatement::isEmpty() -{ - return exp == NULL; -} - -Statement *ExpStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ExpStatement::scopeCode()\n"); - //print(); - - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - - if (exp) - { - if (exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)(exp); - VarDeclaration *v = de->declaration->isVarDeclaration(); - if (v && !v->noscope && !v->isDataseg()) - { - Expression *e = v->edtor; - if (e) - { - //printf("dtor is: "); e->print(); -#if 0 - if (v->type->toBasetype()->ty == Tstruct) - { /* Need a 'gate' to turn on/off destruction, - * in case v gets moved elsewhere. - */ - Identifier *id = Lexer::uniqueId("__runDtor"); - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(1)); - VarDeclaration *rd = new VarDeclaration(loc, Type::tint32, id, ie); - *sentry = new ExpStatement(loc, rd); - v->rundtor = rd; - - /* Rewrite e as: - * rundtor && e - */ - Expression *ve = new VarExp(loc, v->rundtor); - e = new AndAndExp(loc, ve, e); - e->type = Type::tbool; - } -#endif - *sfinally = new DtorExpStatement(loc, e, v); - } - v->noscope = 1; // don't add in dtor again - } - } - } - return this; -} - - -/******************************** DtorExpStatement ***************************/ - -DtorExpStatement::DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v) - : ExpStatement(loc, exp) -{ - this->var = v; -} - -Statement *DtorExpStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - DtorExpStatement *es = new DtorExpStatement(loc, e, var); - return es; -} - -/******************************** CompileStatement ***************************/ - -CompileStatement::CompileStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *CompileStatement::syntaxCopy() -{ - Expression *e = exp->syntaxCopy(); - CompileStatement *es = new CompileStatement(loc, e); - return es; -} - -void CompileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("mixin("); - exp->toCBuffer(buf, hgs); - buf->writestring(");"); - if (!hgs->FLinit.init) - buf->writenl(); -} - -Statements *CompileStatement::flatten(Scope *sc) -{ - //printf("CompileStatement::flatten() %s\n", exp->toChars()); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - exp = exp->optimize(WANTvalue | WANTinterpret); - if (exp->op == TOKerror) - return NULL; - StringExp *se = exp->toString(); - if (!se) - { error("argument to mixin must be a string, not (%s)", exp->toChars()); - return NULL; - } - se = se->toUTF8(sc); - Parser p(sc->module, (unsigned char *)se->string, se->len, 0); - p.loc = loc; - p.nextToken(); - - Statements *a = new Statements(); - while (p.token.value != TOKeof) - { - Statement *s = p.parseStatement(PSsemi | PScurlyscope); - if (s) // if no parsing errors - a->push(s); - } - return a; -} - -Statement *CompileStatement::semantic(Scope *sc) -{ - //printf("CompileStatement::semantic() %s\n", exp->toChars()); - Statements *a = flatten(sc); - if (!a) - return NULL; - Statement *s = new CompoundStatement(loc, a); - return s->semantic(sc); -} - -int CompileStatement::blockExit(bool mustNotThrow) -{ - assert(global.errors); - return BEfallthru; -} - - -/******************************** CompoundStatement ***************************/ - -CompoundStatement::CompoundStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1, Statement *s2) - : Statement(loc) -{ - statements = new Statements(); - statements->reserve(2); - statements->push(s1); - statements->push(s2); -} - -CompoundStatement::CompoundStatement(Loc loc, Statement *s1) - : Statement(loc) -{ - statements = new Statements(); - statements->push(s1); -} - -Statement *CompoundStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; - } - CompoundStatement *cs = new CompoundStatement(loc, a); - return cs; -} - - -Statement *CompoundStatement::semantic(Scope *sc) -{ Statement *s; - - //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", this, sc); - -#if 0 - for (size_t i = 0; i < statements->dim; i++) - { - s = (*statements)[i]; - if (s) - printf("[%d]: %s", i, s->toChars()); - } -#endif - - for (size_t i = 0; i < statements->dim; ) - { - s = (*statements)[i]; - if (s) - { Statements *a = s->flatten(sc); - - if (a) - { - statements->remove(i); - statements->insert(i, a); - continue; - } - s = s->semantic(sc); - (*statements)[i] = s; - if (s) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - (*statements)[i] = s->scopeCode(sc, &sentry, &sexception, &sfinally); - if (sentry) - { - sentry = sentry->semantic(sc); - statements->insert(i, sentry); - i++; - } - if (sexception) - sexception = sexception->semantic(sc); - if (sexception) - { - if (i + 1 == statements->dim && !sfinally) - { - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; - * try { s1; s2; } - * catch (Object __o) - * { sexception; throw __o; } - */ - Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) - { - a->push((*statements)[j]); - } - Statement *body = new CompoundStatement(0, a); - body = new ScopeStatement(0, body); - - Identifier *id = Lexer::uniqueId("__o"); - - Statement *handler = sexception; - if (sexception->blockExit(FALSE) & BEfallthru) - { handler = new ThrowStatement(0, new IdentifierExp(0, id)); - handler = new CompoundStatement(0, sexception, handler); - } - - Catches *catches = new Catches(); - Catch *ctch = new Catch(0, NULL, id, handler); - catches->push(ctch); - s = new TryCatchStatement(0, body, catches); - - if (sfinally) - s = new TryFinallyStatement(0, s, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - else if (sfinally) - { - if (0 && i + 1 == statements->dim) - { - statements->push(sfinally); - } - else - { - /* Rewrite: - * s; s1; s2; - * As: - * s; try { s1; s2; } finally { sfinally; } - */ - Statements *a = new Statements(); - for (size_t j = i + 1; j < statements->dim; j++) - { - a->push((*statements)[j]); - } - Statement *body = new CompoundStatement(0, a); - s = new TryFinallyStatement(0, body, sfinally); - s = s->semantic(sc); - statements->setDim(i + 1); - statements->push(s); - break; - } - } - } - } - i++; - } - if (statements->dim == 1 && !isAsmBlockStatement()) - { - return (*statements)[0]; - } - return this; -} - -Statements *CompoundStatement::flatten(Scope *sc) -{ - return statements; -} - -ReturnStatement *CompoundStatement::isReturnStatement() -{ - ReturnStatement *rs = NULL; - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - rs = s->isReturnStatement(); - if (rs) - break; - } - } - return rs; -} - -Statement *CompoundStatement::last() -{ - Statement *s = NULL; - - for (size_t i = statements->dim; i; --i) - { s = (*statements)[i - 1]; - if (s) - { - s = s->last(); - if (s) - break; - } - } - return s; -} - -void CompoundStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s->toCBuffer(buf, hgs); - } -} - -int CompoundStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int CompoundStatement::blockExit(bool mustNotThrow) -{ - //printf("CompoundStatement::blockExit(%p) %d\n", this, statements->dim); - int result = BEfallthru; - Statement *slast = NULL; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - //printf("result = x%x\n", result); - //printf("%s\n", s->toChars()); - if (global.params.warnings && result & BEfallthru && slast) - { - slast = slast->last(); - if (slast && (slast->isCaseStatement() || slast->isDefaultStatement()) && - (s->isCaseStatement() || s->isDefaultStatement())) - { - // Allow if last case/default was empty - CaseStatement *sc = slast->isCaseStatement(); - DefaultStatement *sd = slast->isDefaultStatement(); - if (sc && sc->statement->isEmpty()) - ; - else if (sd && sd->statement->isEmpty()) - ; - else - s->error("switch case fallthrough - use 'goto %s;' if intended", - s->isCaseStatement() ? "case" : "default"); - } - } - - if (!(result & BEfallthru) && !s->comeFrom()) - { - if (s->blockExit(mustNotThrow) != BEhalt && !s->isEmpty()) - s->warning("statement is not reachable"); - } - else - { - result &= ~BEfallthru; - result |= s->blockExit(mustNotThrow); - } - slast = s; - } - } - return result; -} - -int CompoundStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("CompoundStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - -int CompoundStatement::isEmpty() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && !s->isEmpty()) - return FALSE; - } - return TRUE; -} - - -/******************************** CompoundDeclarationStatement ***************************/ - -CompoundDeclarationStatement::CompoundDeclarationStatement(Loc loc, Statements *s) - : CompoundStatement(loc, s) -{ - statements = s; -} - -Statement *CompoundDeclarationStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; - } - CompoundDeclarationStatement *cs = new CompoundDeclarationStatement(loc, a); - return cs; -} - -void CompoundDeclarationStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - int nwritten = 0; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - ExpStatement *ds; - if (s && - (ds = s->isExpStatement()) != NULL && - ds->exp->op == TOKdeclaration) - { - DeclarationExp *de = (DeclarationExp *)ds->exp; - Declaration *d = de->declaration->isDeclaration(); - assert(d); - VarDeclaration *v = d->isVarDeclaration(); - if (v) - { - /* This essentially copies the part of VarDeclaration::toCBuffer() - * that does not print the type. - * Should refactor this. - */ - if (nwritten) - { - buf->writeByte(','); - buf->writestring(v->ident->toChars()); - } - else - { - StorageClassDeclaration::stcToCBuffer(buf, v->storage_class); - if (v->type) - v->type->toCBuffer(buf, v->ident, hgs); - else - buf->writestring(v->ident->toChars()); - } - - if (v->init) - { buf->writestring(" = "); -#if DMDV2 - ExpInitializer *ie = v->init->isExpInitializer(); - if (ie && (ie->exp->op == TOKconstruct || ie->exp->op == TOKblit)) - ((AssignExp *)ie->exp)->e2->toCBuffer(buf, hgs); - else -#endif - v->init->toCBuffer(buf, hgs); - } - } - else - d->toCBuffer(buf, hgs); - nwritten++; - } - } - buf->writeByte(';'); - if (!hgs->FLinit.init) - buf->writenl(); -} - -/**************************** UnrolledLoopStatement ***************************/ - -UnrolledLoopStatement::UnrolledLoopStatement(Loc loc, Statements *s) - : Statement(loc) -{ - statements = s; -} - -Statement *UnrolledLoopStatement::syntaxCopy() -{ - Statements *a = new Statements(); - a->setDim(statements->dim); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - s = s->syntaxCopy(); - (*a)[i] = s; - } - UnrolledLoopStatement *cs = new UnrolledLoopStatement(loc, a); - return cs; -} - - -Statement *UnrolledLoopStatement::semantic(Scope *sc) -{ - //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", this, sc); - - sc->noctor++; - Scope *scd = sc->push(); - scd->sbreak = this; - scd->scontinue = this; - - for (size_t i = 0; i < statements->dim; i++) - { - Statement *s = (*statements)[i]; - if (s) - { - //printf("[%d]: %s\n", i, s->toChars()); - s = s->semantic(scd); - (*statements)[i] = s; - } - } - - scd->pop(); - sc->noctor--; - return this; -} - -void UnrolledLoopStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("unrolled {"); - buf->writenl(); - - for (size_t i = 0; i < statements->dim; i++) - { Statement *s; - - s = (*statements)[i]; - if (s) - s->toCBuffer(buf, hgs); - } - - buf->writeByte('}'); - buf->writenl(); -} - -int UnrolledLoopStatement::hasBreak() -{ - return TRUE; -} - -int UnrolledLoopStatement::hasContinue() -{ - return TRUE; -} - -int UnrolledLoopStatement::usesEH() -{ - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s && s->usesEH()) - return TRUE; - } - return FALSE; -} - -int UnrolledLoopStatement::blockExit(bool mustNotThrow) -{ - int result = BEfallthru; - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - if (s) - { - int r = s->blockExit(mustNotThrow); - result |= r & ~(BEbreak | BEcontinue); - } - } - return result; -} - - -int UnrolledLoopStatement::comeFrom() -{ int comefrom = FALSE; - - //printf("UnrolledLoopStatement::comeFrom()\n"); - for (size_t i = 0; i < statements->dim; i++) - { Statement *s = (*statements)[i]; - - if (!s) - continue; - - comefrom |= s->comeFrom(); - } - return comefrom; -} - - -/******************************** ScopeStatement ***************************/ - -ScopeStatement::ScopeStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -} - -Statement *ScopeStatement::syntaxCopy() -{ - Statement *s; - - s = statement ? statement->syntaxCopy() : NULL; - s = new ScopeStatement(loc, s); - return s; -} - - -Statement *ScopeStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("ScopeStatement::semantic(sc = %p)\n", sc); - if (statement) - { Statements *a; - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - a = statement->flatten(sc); - if (a) - { - statement = new CompoundStatement(loc, a); - } - - statement = statement->semantic(sc); - if (statement) - { - Statement *sentry; - Statement *sexception; - Statement *sfinally; - - statement = statement->scopeCode(sc, &sentry, &sexception, &sfinally); - assert(!sentry); - assert(!sexception); - if (sfinally) - { - //printf("adding sfinally\n"); - sfinally = sfinally->semantic(sc); - statement = new CompoundStatement(loc, statement, sfinally); - } - } - - sc->pop(); - } - return this; -} - -int ScopeStatement::hasBreak() -{ - //printf("ScopeStatement::hasBreak() %s\n", toChars()); - return statement ? statement->hasBreak() : FALSE; -} - -int ScopeStatement::hasContinue() -{ - return statement ? statement->hasContinue() : FALSE; -} - -int ScopeStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int ScopeStatement::blockExit(bool mustNotThrow) -{ - //printf("ScopeStatement::blockExit(%p)\n", statement); - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -int ScopeStatement::comeFrom() -{ - //printf("ScopeStatement::comeFrom()\n"); - return statement ? statement->comeFrom() : FALSE; -} - -int ScopeStatement::isEmpty() -{ - //printf("ScopeStatement::isEmpty() %d\n", statement ? statement->isEmpty() : TRUE); - return statement ? statement->isEmpty() : TRUE; -} - -void ScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writeByte('{'); - buf->writenl(); - - if (statement) - statement->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); -} - -/******************************** WhileStatement ***************************/ - -WhileStatement::WhileStatement(Loc loc, Expression *c, Statement *b) - : Statement(loc) -{ - condition = c; - body = b; -} - -Statement *WhileStatement::syntaxCopy() -{ - WhileStatement *s = new WhileStatement(loc, condition->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - - -Statement *WhileStatement::semantic(Scope *sc) -{ - /* Rewrite as a for(;condition;) loop - */ - - Statement *s = new ForStatement(loc, NULL, condition, NULL, body); - s = s->semantic(sc); - return s; -} - -int WhileStatement::hasBreak() -{ - return TRUE; -} - -int WhileStatement::hasContinue() -{ - return TRUE; -} - -int WhileStatement::usesEH() -{ - assert(0); - return body ? body->usesEH() : 0; -} - -int WhileStatement::blockExit(bool mustNotThrow) -{ - assert(0); - //printf("WhileStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (body) - { result |= body->blockExit(mustNotThrow); - if (result & BEbreak) - result |= BEfallthru; - } - } - else if (condition->isBool(FALSE)) - { - result |= BEfallthru; - } - else - { - if (body) - result |= body->blockExit(mustNotThrow); - result |= BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int WhileStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void WhileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); -} - -/******************************** DoStatement ***************************/ - -DoStatement::DoStatement(Loc loc, Statement *b, Expression *c) - : Statement(loc) -{ - body = b; - condition = c; -} - -Statement *DoStatement::syntaxCopy() -{ - DoStatement *s = new DoStatement(loc, body ? body->syntaxCopy() : NULL, condition->syntaxCopy()); - return s; -} - - -Statement *DoStatement::semantic(Scope *sc) -{ - sc->noctor++; - if (body) - body = body->semanticScope(sc, this, this); - sc->noctor--; - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - - condition = condition->checkToBoolean(sc); - - return this; -} - -int DoStatement::hasBreak() -{ - return TRUE; -} - -int DoStatement::hasContinue() -{ - return TRUE; -} - -int DoStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int DoStatement::blockExit(bool mustNotThrow) -{ int result; - - if (body) - { result = body->blockExit(mustNotThrow); - if (result == BEbreak) - return BEfallthru; - if (result & BEcontinue) - result |= BEfallthru; - } - else - result = BEfallthru; - if (result & BEfallthru) - { - if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - if (!(result & BEbreak) && condition->isBool(TRUE)) - result &= ~BEfallthru; - } - result &= ~(BEbreak | BEcontinue); - return result; -} - - -int DoStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void DoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("do"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writestring("while ("); - condition->toCBuffer(buf, hgs); - buf->writestring(");"); -} - -/******************************** ForStatement ***************************/ - -ForStatement::ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body) - : Statement(loc) -{ - this->init = init; - this->condition = condition; - this->increment = increment; - this->body = body; -} - -Statement *ForStatement::syntaxCopy() -{ - Statement *i = NULL; - if (init) - i = init->syntaxCopy(); - Expression *c = NULL; - if (condition) - c = condition->syntaxCopy(); - Expression *inc = NULL; - if (increment) - inc = increment->syntaxCopy(); - ForStatement *s = new ForStatement(loc, i, c, inc, body->syntaxCopy()); - return s; -} - -Statement *ForStatement::semantic(Scope *sc) -{ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - if (init) - init = init->semantic(sc); - sc->noctor++; - if (condition) - { - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - condition = condition->optimize(WANTvalue); - condition = condition->checkToBoolean(sc); - } - if (increment) - { increment = increment->semantic(sc); - increment = resolveProperties(sc, increment); - increment = increment->optimize(0); - } - - sc->sbreak = this; - sc->scontinue = this; - if (body) - body = body->semanticNoScope(sc); - sc->noctor--; - - sc->pop(); - return this; -} - -Statement *ForStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("ForStatement::scopeCode()\n"); - //print(); - if (init) - init = init->scopeCode(sc, sentry, sexception, sfinally); - else - Statement::scopeCode(sc, sentry, sexception, sfinally); - return this; -} - -int ForStatement::hasBreak() -{ - //printf("ForStatement::hasBreak()\n"); - return TRUE; -} - -int ForStatement::hasContinue() -{ - return TRUE; -} - -int ForStatement::usesEH() -{ - return (init && init->usesEH()) || body->usesEH(); -} - -int ForStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (init) - { result = init->blockExit(mustNotThrow); - if (!(result & BEfallthru)) - return result; - } - if (condition) - { if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - if (condition->isBool(TRUE)) - result &= ~BEfallthru; - else if (condition->isBool(FALSE)) - return result; - } - else - result &= ~BEfallthru; // the body must do the exiting - if (body) - { int r = body->blockExit(mustNotThrow); - if (r & (BEbreak | BEgoto)) - result |= BEfallthru; - result |= r & ~(BEfallthru | BEbreak | BEcontinue); - } - if (increment && increment->canThrow(mustNotThrow)) - result |= BEthrow; - return result; -} - - -int ForStatement::comeFrom() -{ - //printf("ForStatement::comeFrom()\n"); - if (body) - { int result = body->comeFrom(); - //printf("result = %d\n", result); - return result; - } - return FALSE; -} - -void ForStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("for ("); - if (init) - { - hgs->FLinit.init++; - init->toCBuffer(buf, hgs); - hgs->FLinit.init--; - } - else - buf->writebyte(';'); - if (condition) - { buf->writebyte(' '); - condition->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - if (increment) - { buf->writebyte(' '); - increment->toCBuffer(buf, hgs); - } - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/******************************** ForeachStatement ***************************/ - -ForeachStatement::ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, - Expression *aggr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arguments = arguments; - this->aggr = aggr; - this->body = body; - - this->key = NULL; - this->value = NULL; - - this->func = NULL; - - this->cases = NULL; - this->gotos = NULL; -} - -Statement *ForeachStatement::syntaxCopy() -{ - Parameters *args = Parameter::arraySyntaxCopy(arguments); - Expression *exp = aggr->syntaxCopy(); - ForeachStatement *s = new ForeachStatement(loc, op, args, exp, - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachStatement::semantic(Scope *sc) -{ - //printf("ForeachStatement::semantic() %p\n", this); - ScopeDsymbol *sym; - Statement *s = this; - size_t dim = arguments->dim; - TypeAArray *taa = NULL; - Dsymbol *sapply = NULL; - - Type *tn = NULL; - Type *tnv = NULL; - - func = sc->func; - if (func->fes) - func = func->fes->func; - - if (!inferAggregate(sc, sapply)) - { - error("invalid foreach aggregate %s", aggr->toChars()); - return this; - } - - /* Check for inference errors - */ - if (!inferApplyArgTypes(sc, sapply)) - { - //printf("dim = %d, arguments->dim = %d\n", dim, arguments->dim); - error("cannot uniquely infer foreach argument types"); - return this; - } - - Type *tab = aggr->type->toBasetype(); - - if (tab->ty == Ttuple) // don't generate new scope for tuple loops - { - if (dim < 1 || dim > 2) - { - error("only one (value) or two (key,value) arguments for tuple foreach"); - return s; - } - - TypeTuple *tuple = (TypeTuple *)tab; - Statements *statements = new Statements(); - //printf("aggr: op = %d, %s\n", aggr->op, aggr->toChars()); - size_t n; - TupleExp *te = NULL; - Expression *prelude = NULL; - if (aggr->op == TOKtuple) // expression tuple - { te = (TupleExp *)aggr; - n = te->exps->dim; - - if (te->exps->dim > 0 && (*te->exps)[0]->op == TOKdotvar && - ((DotVarExp *)(*te->exps)[0])->e1->isTemp()) - { - CommaExp *ce = (CommaExp *)((DotVarExp *)(*te->exps)[0])->e1; - - prelude = ce->e1; - ((DotVarExp *)(*te->exps)[0])->e1 = ce->e2; - } - } - else if (aggr->op == TOKtype) // type tuple - { - n = Parameter::dim(tuple->arguments); - } - else - assert(0); - for (size_t j = 0; j < n; j++) - { size_t k = (op == TOKforeach) ? j : n - 1 - j; - Expression *e; - Type *t; - if (te) - e = (*te->exps)[k]; - else - t = Parameter::getNth(tuple->arguments, k)->type; - Parameter *arg = (*arguments)[0]; - Statements *st = new Statements(); - - if (dim == 2) - { // Declare key - if (arg->storageClass & (STCout | STCref | STClazy)) - error("no storage class for key %s", arg->ident->toChars()); - arg->type = arg->type->semantic(loc, sc); - TY keyty = arg->type->ty; - if (keyty != Tint32 && keyty != Tuns32) - { - if (global.params.is64bit) - { - if (keyty != Tint64 && keyty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", arg->type->toChars()); - } - else - error("foreach: key type must be int or uint, not %s", arg->type->toChars()); - } - Initializer *ie = new ExpInitializer(0, new IntegerExp(k)); - VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, ie); - var->storage_class |= STCmanifest; - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - arg = (*arguments)[1]; // value - } - // Declare value - if (arg->storageClass & (STCout | STClazy) || - arg->storageClass & STCref && !te) - error("no storage class for value %s", arg->ident->toChars()); - Dsymbol *var; - if (te) - { Type *tb = e->type->toBasetype(); - Dsymbol *s = NULL; - if ((tb->ty == Tfunction || tb->ty == Tsarray) && e->op == TOKvar) - s = ((VarExp *)e)->var; - else if (e->op == TOKtemplate) - s =((TemplateExp *)e)->td; - else if (e->op == TOKimport) - s =((ScopeExp *)e)->sds; - - if (s) - { - var = new AliasDeclaration(loc, arg->ident, s); - if (arg->storageClass & STCref) - error("symbol %s cannot be ref", s->toChars()); - } - else - { - arg->type = e->type; - Initializer *ie = new ExpInitializer(0, e); - VarDeclaration *v = new VarDeclaration(loc, arg->type, arg->ident, ie); - if (arg->storageClass & STCref) - v->storage_class |= STCref | STCforeach; - if (e->isConst() || e->op == TOKstring) - { if (v->storage_class & STCref) - error("constant value %s cannot be ref", ie->toChars()); - else - v->storage_class |= STCmanifest; - } - var = v; - } - } - else - { - var = new AliasDeclaration(loc, arg->ident, t); - } - DeclarationExp *de = new DeclarationExp(loc, var); - st->push(new ExpStatement(loc, de)); - - st->push(body->syntaxCopy()); - s = new CompoundStatement(loc, st); - s = new ScopeStatement(loc, s); - statements->push(s); - } - - s = new UnrolledLoopStatement(loc, statements); - if (prelude) - s = new CompoundStatement(loc, - new ExpStatement(prelude->loc, prelude), s); - s = s->semantic(sc); - return s; - } - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - -Lagain: - switch (tab->ty) - { - case Tarray: - case Tsarray: - if (!checkForArgTypes()) - return this; - - if (dim < 1 || dim > 2) - { - error("only one or two arguments for array foreach"); - break; - } - - /* Look for special case of parsing char types out of char type - * array. - */ - tn = tab->nextOf()->toBasetype(); - if (tn->ty == Tchar || tn->ty == Twchar || tn->ty == Tdchar) - { Parameter *arg; - - int i = (dim == 1) ? 0 : 1; // index of value - arg = (*arguments)[i]; - arg->type = arg->type->semantic(loc, sc); - tnv = arg->type->toBasetype(); - if (tnv->ty != tn->ty && - (tnv->ty == Tchar || tnv->ty == Twchar || tnv->ty == Tdchar)) - { - if (arg->storageClass & STCref) - error("foreach: value of UTF conversion cannot be ref"); - if (dim == 2) - { arg = (*arguments)[0]; - if (arg->storageClass & STCref) - error("foreach: key cannot be ref"); - } - goto Lapply; - } - } - - for (size_t i = 0; i < dim; i++) - { // Declare args - Parameter *arg = (*arguments)[i]; - Type *argtype = arg->type->semantic(loc, sc); - VarDeclaration *var; - - var = new VarDeclaration(loc, argtype, arg->ident, NULL); - var->storage_class |= STCforeach; - var->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - if (var->storage_class & (STCref | STCout)) - var->storage_class |= STCnodtor; - if (dim == 2 && i == 0) - { key = var; - //var->storage_class |= STCfinal; - } - else - { - value = var; - /* Reference to immutable data should be marked as const - */ - if (var->storage_class & STCref && !tn->isMutable()) - { - var->storage_class |= STCconst; - } - } -#if 0 - DeclarationExp *de = new DeclarationExp(loc, var); - de->semantic(sc); -#endif - } - -#if 1 - { - /* Convert to a ForStatement - * foreach (key, value; a) body => - * for (T[] tmp = a[], size_t key; key < tmp.length; ++key) - * { T value = tmp[k]; body } - * - * foreach_reverse (key, value; a) body => - * for (T[] tmp = a[], size_t key = tmp.length; key--; ) - * { T value = tmp[k]; body } - */ - Identifier *id = Lexer::uniqueId("__aggr"); - ExpInitializer *ie = new ExpInitializer(loc, new SliceExp(loc, aggr, NULL, NULL)); - VarDeclaration *tmp = new VarDeclaration(loc, tab->nextOf()->arrayOf(), id, ie); - - Expression *tmp_length = new DotIdExp(loc, new VarExp(loc, tmp), Id::length); - - if (!key) - { - Identifier *idkey = Lexer::uniqueId("__key"); - key = new VarDeclaration(loc, Type::tsize_t, idkey, NULL); - } - if (op == TOKforeach_reverse) - key->init = new ExpInitializer(loc, tmp_length); - else - key->init = new ExpInitializer(loc, new IntegerExp(0)); - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - cs->push(new ExpStatement(loc, key)); - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - // key-- - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - else - // key < tmp.length - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), tmp_length); - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - - // T value = tmp[key]; - value->init = new ExpInitializer(loc, new IndexExp(loc, new VarExp(loc, tmp), new VarExp(loc, key))); - Statement *ds = new ExpStatement(loc, value); - - body = new CompoundStatement(loc, ds, body); - - s = new ForStatement(loc, forinit, cond, increment, body); - s = s->semantic(sc); - break; - } -#else - if (tab->nextOf()->implicitConvTo(value->type) < MATCHconst) - { - if (aggr->op == TOKstring) - aggr = aggr->implicitCastTo(sc, value->type->arrayOf()); - else - error("foreach: %s is not an array of %s", - tab->toChars(), value->type->toChars()); - } - - if (key) - { - if (key->type->ty != Tint32 && key->type->ty != Tuns32) - { - if (global.params.is64bit) - { - if (key->type->ty != Tint64 && key->type->ty != Tuns64) - error("foreach: key type must be int or uint, long or ulong, not %s", key->type->toChars()); - } - else - error("foreach: key type must be int or uint, not %s", key->type->toChars()); - } - - if (key->storage_class & (STCout | STCref)) - error("foreach: key cannot be out or ref"); - } - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - break; -#endif - - case Taarray: - if (!checkForArgTypes()) - return this; - - taa = (TypeAArray *)tab; - if (dim < 1 || dim > 2) - { - error("only one or two arguments for associative array foreach"); - break; - } -#if SARRAYVALUE - /* This only works if Key or Value is a static array. - */ - tab = taa->getImpl()->type; - goto Lagain; -#else - if (op == TOKforeach_reverse) - { - error("no reverse iteration on associative arrays"); - } - goto Lapply; -#endif - case Tclass: - case Tstruct: -#if DMDV2 - /* Prefer using opApply, if it exists - */ - if (sapply) - goto Lapply; - - { /* Look for range iteration, i.e. the properties - * .empty, .next, .retreat, .head and .rear - * foreach (e; aggr) { ... } - * translates to: - * for (auto __r = aggr[]; !__r.empty; __r.next) - * { auto e = __r.head; - * ... - * } - */ - AggregateDeclaration *ad = (tab->ty == Tclass) - ? (AggregateDeclaration *)((TypeClass *)tab)->sym - : (AggregateDeclaration *)((TypeStruct *)tab)->sym; - Identifier *idhead; - Identifier *idnext; - if (op == TOKforeach) - { idhead = Id::Ffront; - idnext = Id::FpopFront; - } - else - { idhead = Id::Fback; - idnext = Id::FpopBack; - } - Dsymbol *shead = search_function(ad, idhead); - if (!shead) - goto Lapply; - - /* Generate a temporary __r and initialize it with the aggregate. - */ - Identifier *id = Identifier::generateId("__r"); - VarDeclaration *r = new VarDeclaration(loc, NULL, id, new ExpInitializer(loc, aggr)); - Statement *init = new ExpStatement(loc, r); - - // !__r.empty - Expression *e = new VarExp(loc, r); - e = new DotIdExp(loc, e, Id::Fempty); - Expression *condition = new NotExp(loc, e); - - // __r.next - e = new VarExp(loc, r); - Expression *increment = new CallExp(loc, new DotIdExp(loc, e, idnext)); - - /* Declaration statement for e: - * auto e = __r.idhead; - */ - e = new VarExp(loc, r); - Expression *einit = new DotIdExp(loc, e, idhead); - Statement *makeargs, *forbody; - if (dim == 1) - { - Parameter *arg = (*arguments)[0]; - VarDeclaration *ve = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, einit)); - ve->storage_class |= STCforeach; - ve->storage_class |= arg->storageClass & (STCin | STCout | STCref | STC_TYPECTOR); - - DeclarationExp *de = new DeclarationExp(loc, ve); - makeargs = new ExpStatement(loc, de); - } - else - { - Identifier *id = Lexer::uniqueId("__front"); - ExpInitializer *ei = new ExpInitializer(loc, einit); - VarDeclaration *vd = new VarDeclaration(loc, NULL, id, ei); - vd->storage_class |= STCctfe | STCref | STCforeach; - - Expression *de = new DeclarationExp(loc, vd); - makeargs = new ExpStatement(loc, de); - - Expression *ve = new VarExp(loc, vd); - ve->type = shead->isDeclaration()->type; - if (ve->type->toBasetype()->ty == Tfunction) - ve->type = ve->type->toBasetype()->nextOf(); - if (!ve->type || ve->type->ty == Terror) - goto Lrangeerr; - - // Resolve inout qualifier of front type - ve->type = ve->type->substWildTo(tab->mod); - - Expressions *exps = new Expressions(); - exps->push(ve); - int pos = 0; - while (exps->dim < dim) - { - pos = expandAliasThisTuples(exps, pos); - if (pos == -1) - break; - } - if (exps->dim != dim) - goto Lrangeerr; - - for (size_t i = 0; i < dim; i++) - { - Parameter *arg = (*arguments)[i]; - Expression *exp = (*exps)[i]; - #if 0 - printf("[%d] arg = %s %s, exp = %s %s\n", i, - arg->type ? arg->type->toChars() : "?", arg->ident->toChars(), - exp->type->toChars(), exp->toChars()); - #endif - if (arg->type && !exp->implicitConvTo(arg->type)) - goto Lrangeerr; - if (!arg->type) - arg->type = exp->type; - - VarDeclaration *var = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, exp)); - var->storage_class |= STCctfe | STCref | STCforeach; - DeclarationExp *de = new DeclarationExp(loc, var); - makeargs = new CompoundStatement(loc, makeargs, new ExpStatement(loc, de)); - } - - } - - forbody = new CompoundStatement(loc, - makeargs, this->body); - - s = new ForStatement(loc, init, condition, increment, forbody); -#if 0 - printf("init: %s\n", init->toChars()); - printf("condition: %s\n", condition->toChars()); - printf("increment: %s\n", increment->toChars()); - printf("body: %s\n", forbody->toChars()); -#endif - s = s->semantic(sc); - break; - - Lrangeerr: - error("cannot infer argument types"); - break; - } -#endif - case Tdelegate: - Lapply: - { - FuncDeclaration *fdapply; - Expression *ec; - Expression *e; - TypeDelegate* dgty; - TypeDelegate* dgty2; - TypeDelegate* fldeTy; - - if (!checkForArgTypes()) - { body = body->semanticNoScope(sc); - return this; - } - - Type *tret = func->type->nextOf(); - - // Need a variable to hold value from any return statements in body. - if (!sc->func->vresult && tret && tret != Type::tvoid) - { - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->semantic(sc); - if (!sc->insert(v)) - assert(0); - v->parent = sc->func; - sc->func->vresult = v; - } - - TypeFunction *tfld = NULL; - if (sapply) - { FuncDeclaration *fdapply = sapply->isFuncDeclaration(); - if (fdapply) - { assert(fdapply->type && fdapply->type->ty == Tfunction); - tfld = (TypeFunction *)fdapply->type->semantic(loc, sc); - goto Lget; - } - else if (tab->ty == Tdelegate) - { - tfld = (TypeFunction *)tab->nextOf(); - Lget: - //printf("tfld = %s\n", tfld->toChars()); - if (tfld->parameters->dim == 1) - { - Parameter *p = Parameter::getNth(tfld->parameters, 0); - if (p->type && p->type->ty == Tdelegate) - { Type *t = p->type->semantic(loc, sc); - assert(t->ty == Tdelegate); - tfld = (TypeFunction *)t->nextOf(); - } - } - } - } - - /* Turn body into the function literal: - * int delegate(ref T arg) { body } - */ - Parameters *args = new Parameters(); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = (*arguments)[i]; - StorageClass stc = STCref; - Identifier *id; - - arg->type = arg->type->semantic(loc, sc); - if (tfld) - { Parameter *prm = Parameter::getNth(tfld->parameters, i); - //printf("\tprm = %s%s\n", (prm->storageClass&STCref?"ref ":""), prm->ident->toChars()); - stc = prm->storageClass & STCref; - id = arg->ident; // argument copy is not need. - if ((arg->storageClass & STCref) != stc) - { if (!stc) - error("foreach: cannot make %s ref", arg->ident->toChars()); - goto LcopyArg; - } - } - else if (arg->storageClass & STCref) - { // default delegate parameters are marked as ref, then - // argument copy is not need. - id = arg->ident; - } - else - { // Make a copy of the ref argument so it isn't - // a reference. - LcopyArg: - id = Lexer::uniqueId("__applyArg", i); - - Initializer *ie = new ExpInitializer(0, new IdentifierExp(0, id)); - VarDeclaration *v = new VarDeclaration(0, arg->type, arg->ident, ie); - s = new ExpStatement(0, v); - body = new CompoundStatement(loc, s, body); - } - args->push(new Parameter(stc, arg->type, id, NULL)); - } - tfld = new TypeFunction(args, Type::tint32, 0, LINKd); - cases = new Statements(); - gotos = new CompoundStatements(); - FuncLiteralDeclaration *fld = new FuncLiteralDeclaration(loc, 0, tfld, TOKdelegate, this); - fld->fbody = body; - Expression *flde = new FuncExp(loc, fld); - flde = flde->semantic(sc); - fld->tookAddressOf = 0; - - // Resolve any forward referenced goto's - for (size_t i = 0; i < gotos->dim; i++) - { CompoundStatement *cs = (*gotos)[i]; - GotoStatement *gs = (GotoStatement *)(*cs->statements)[0]; - - if (!gs->label->statement) - { // 'Promote' it to this scope, and replace with a return - cases->push(gs); - s = new ReturnStatement(0, new IntegerExp(cases->dim + 1)); - (*cs->statements)[0] = s; - } - } - - if (taa) - { - // Check types - Parameter *arg = (*arguments)[0]; - if (dim == 2) - { - if (arg->storageClass & STCref) - error("foreach: index cannot be ref"); - if (!arg->type->equals(taa->index)) - error("foreach: index must be type %s, not %s", taa->index->toChars(), arg->type->toChars()); - arg = (*arguments)[1]; - } - if (!arg->type->equals(taa->nextOf())) - error("foreach: value must be type %s, not %s", taa->nextOf()->toChars(), arg->type->toChars()); - - /* Call: - * _aaApply(aggr, keysize, flde) - */ - //LDC: Build arguments. - static FuncDeclaration *aaApply2_fd = NULL; - static TypeDelegate* aaApply2_dg; - if(!aaApply2_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, aaApply2_dg, NULL, NULL)); - aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tint32, "_aaApply2"); - } - static FuncDeclaration *aaApply_fd = NULL; - static TypeDelegate* aaApply_dg; - if(!aaApply_fd) { - Parameters* args = new Parameters; - args->push(new Parameter(STCin, Type::tvoid->pointerTo(), NULL, NULL)); // FIXME: Real parameter type is AA. - args->push(new Parameter(STCin, Type::tsize_t, NULL, NULL)); - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, aaApply_dg, NULL, NULL)); - aaApply_fd = FuncDeclaration::genCfunc(args, Type::tint32, "_aaApply"); - } - if (dim == 2) { - fdapply = aaApply2_fd; - fldeTy = aaApply2_dg; - } else { - fdapply = aaApply_fd; - fldeTy = aaApply_dg; - } - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - exps->push(aggr); - size_t keysize = taa->index->size(); - keysize = (keysize + (PTRSIZE-1)) & ~(PTRSIZE-1); - exps->push(new IntegerExp(0, keysize, Type::tsize_t)); - -#if IN_LLVM - // LDC paint delegate argument to the type runtime expects - if (!fldeTy->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = fldeTy; - } -#endif - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tint32; // don't run semantic() on e - } - else if (tab->ty == Tarray || tab->ty == Tsarray) - { - /* Call: - * _aApply(aggr, flde) - */ - static char fntab[9][3] = - { "cc","cw","cd", - "wc","cc","wd", - "dc","dw","dd" - }; - char fdname[7+1+2+ sizeof(dim)*3 + 1]; - int flag; - - switch (tn->ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: assert(0); - } - switch (tnv->ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: assert(0); - } - const char *r = (op == TOKforeach_reverse) ? "R" : ""; -#ifdef __MINGW32__ - int j = sprintf(fdname, "_aApply%s%.*s%lu", r, 2, fntab[flag], dim); -#else - int j = sprintf(fdname, "_aApply%s%.*s%zu", r, 2, fntab[flag], dim); -#endif - assert(j < sizeof(fdname)); - //LDC: Build arguments. - Parameters* args = new Parameters; - args->push(new Parameter(STCin, tn->arrayOf(), NULL, NULL)); - if (dim == 2) { - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tint32, fdname); - } else { - Parameters* dgargs = new Parameters; - dgargs->push(new Parameter(STCin, Type::tvoidptr, NULL, NULL)); - dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tint32, 0, LINKd)); - args->push(new Parameter(STCin, dgty, NULL, NULL)); - fdapply = FuncDeclaration::genCfunc(args, Type::tint32, fdname); - } - - ec = new VarExp(0, fdapply); - Expressions *exps = new Expressions(); - if (tab->ty == Tsarray) - aggr = aggr->castTo(sc, tn->arrayOf()); - exps->push(aggr); - - // LDC paint delegate argument to the type runtime expects - if (!dgty->equals(flde->type)) - { - flde = new CastExp(loc, flde, flde->type); - flde->type = dgty; - } - exps->push(flde); - e = new CallExp(loc, ec, exps); - e->type = Type::tint32; // don't run semantic() on e - } - else if (tab->ty == Tdelegate) - { - /* Call: - * aggr(flde) - */ - Expressions *exps = new Expressions(); - exps->push(flde); - if (aggr->op == TOKdelegate && - ((DelegateExp *)aggr)->func->isNested()) - // See Bugzilla 3560 - e = new CallExp(loc, ((DelegateExp *)aggr)->e1, exps); - else - e = new CallExp(loc, aggr, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - else - { - assert(tab->ty == Tstruct || tab->ty == Tclass); - Expressions *exps = new Expressions(); - assert(sapply); -#if 0 - TemplateDeclaration *td; - if (sapply && - (td = sapply->isTemplateDeclaration()) != NULL) - { /* Call: - * aggr.apply!(fld)() - */ - Objects *tiargs = new Objects(); - tiargs->push(fld); - ec = new DotTemplateInstanceExp(loc, aggr, sapply->ident, tiargs); - } - else -#endif - { - /* Call: - * aggr.apply(flde) - */ - ec = new DotIdExp(loc, aggr, sapply->ident); - exps->push(flde); - } - e = new CallExp(loc, ec, exps); - e = e->semantic(sc); - if (e->type != Type::tint32) - error("opApply() function for %s must return an int", tab->toChars()); - } - - if (!cases->dim) - // Easy case, a clean exit from the loop - s = new ExpStatement(loc, e); - else - { // Construct a switch statement around the return value - // of the apply function. - Statements *a = new Statements(); - - // default: break; takes care of cases 0 and 1 - s = new BreakStatement(0, NULL); - s = new DefaultStatement(0, s); - a->push(s); - - // cases 2... - for (size_t i = 0; i < cases->dim; i++) - { - s = (*cases)[i]; - s = new CaseStatement(0, new IntegerExp(i + 2), s); - a->push(s); - } - - s = new CompoundStatement(loc, a); - s = new SwitchStatement(loc, e, s, FALSE); - } - s = s->semantic(sc); - break; - } - case Terror: - s = NULL; - break; - - default: - error("foreach: %s is not an aggregate type", aggr->type->toChars()); - s = NULL; // error recovery - break; - } - sc->noctor--; - sc->pop(); - return s; -} - -bool ForeachStatement::checkForArgTypes() -{ bool result = TRUE; - - for (size_t i = 0; i < arguments->dim; i++) - { Parameter *arg = (*arguments)[i]; - if (!arg->type) - { - error("cannot infer type for %s", arg->ident->toChars()); - arg->type = Type::terror; - result = FALSE; - } - } - return result; -} - -int ForeachStatement::hasBreak() -{ - return TRUE; -} - -int ForeachStatement::hasContinue() -{ - return TRUE; -} - -int ForeachStatement::usesEH() -{ - return body->usesEH(); -} - -int ForeachStatement::blockExit(bool mustNotThrow) -{ int result = BEfallthru; - - if (aggr->canThrow(mustNotThrow)) - result |= BEthrow; - - if (body) - { - result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachStatement::comeFrom() -{ - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - for (size_t i = 0; i < arguments->dim; i++) - { - Parameter *a = (*arguments)[i]; - if (i) - buf->writestring(", "); - if (a->storageClass & STCref) - buf->writestring((global.params.Dversion == 1) - ? (char*)"inout " : (char*)"ref "); - if (a->type) - a->type->toCBuffer(buf, a->ident, hgs); - else - buf->writestring(a->ident->toChars()); - } - buf->writestring("; "); - aggr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/**************************** ForeachRangeStatement ***************************/ - -#if DMDV2 - -ForeachRangeStatement::ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, - Expression *lwr, Expression *upr, Statement *body) - : Statement(loc) -{ - this->op = op; - this->arg = arg; - this->lwr = lwr; - this->upr = upr; - this->body = body; - - this->key = NULL; -} - -Statement *ForeachRangeStatement::syntaxCopy() -{ - ForeachRangeStatement *s = new ForeachRangeStatement(loc, op, - arg->syntaxCopy(), - lwr->syntaxCopy(), - upr->syntaxCopy(), - body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *ForeachRangeStatement::semantic(Scope *sc) -{ - //printf("ForeachRangeStatement::semantic() %p\n", this); - Statement *s = this; - - lwr = lwr->semantic(sc); - lwr = resolveProperties(sc, lwr); - lwr = lwr->optimize(WANTvalue); - if (!lwr->type) - { - error("invalid range lower bound %s", lwr->toChars()); - return this; - } - - upr = upr->semantic(sc); - upr = resolveProperties(sc, upr); - upr = upr->optimize(WANTvalue); - if (!upr->type) - { - error("invalid range upper bound %s", upr->toChars()); - return this; - } - - if (arg->type) - { - arg->type = arg->type->semantic(loc, sc); - lwr = lwr->implicitCastTo(sc, arg->type); - upr = upr->implicitCastTo(sc, arg->type); - } - else - { - /* Must infer types from lwr and upr - */ - Type *tlwr = lwr->type->toBasetype(); - if (tlwr->ty == Tstruct || tlwr->ty == Tclass) - { - /* Just picking the first really isn't good enough. - */ - arg->type = lwr->type->mutableOf(); - } - else - { - AddExp ea(loc, lwr, upr); - Expression *e = ea.typeCombine(sc); - arg->type = ea.type->mutableOf(); - lwr = ea.e1; - upr = ea.e2; - } - } -#if 1 - /* Convert to a for loop: - * foreach (key; lwr .. upr) => - * for (auto key = lwr, auto tmp = upr; key < tmp; ++key) - * - * foreach_reverse (key; lwr .. upr) => - * for (auto tmp = lwr, auto key = upr; key-- > tmp;) - */ - - ExpInitializer *ie = new ExpInitializer(loc, (op == TOKforeach) ? lwr : upr); - key = new VarDeclaration(loc, arg->type, arg->ident, ie); - - Identifier *id = Lexer::uniqueId("__limit"); - ie = new ExpInitializer(loc, (op == TOKforeach) ? upr : lwr); - VarDeclaration *tmp = new VarDeclaration(loc, arg->type, id, ie); - - Statements *cs = new Statements(); - // Keep order of evaluation as lwr, then upr - if (op == TOKforeach) - { - cs->push(new ExpStatement(loc, key)); - cs->push(new ExpStatement(loc, tmp)); - } - else - { - cs->push(new ExpStatement(loc, tmp)); - cs->push(new ExpStatement(loc, key)); - } - Statement *forinit = new CompoundDeclarationStatement(loc, cs); - - Expression *cond; - if (op == TOKforeach_reverse) - { - cond = new PostExp(TOKminusminus, loc, new VarExp(loc, key)); - if (arg->type->isscalar()) - // key-- > tmp - cond = new CmpExp(TOKgt, loc, cond, new VarExp(loc, tmp)); - else - // key-- != tmp - cond = new EqualExp(TOKnotequal, loc, cond, new VarExp(loc, tmp)); - } - else - { - if (arg->type->isscalar()) - // key < tmp - cond = new CmpExp(TOKlt, loc, new VarExp(loc, key), new VarExp(loc, tmp)); - else - // key != tmp - cond = new EqualExp(TOKnotequal, loc, new VarExp(loc, key), new VarExp(loc, tmp)); - } - - Expression *increment = NULL; - if (op == TOKforeach) - // key += 1 - //increment = new AddAssignExp(loc, new VarExp(loc, key), new IntegerExp(1)); - increment = new PreExp(TOKpreplusplus, loc, new VarExp(loc, key)); - - ForStatement *fs = new ForStatement(loc, forinit, cond, increment, body); - s = fs->semantic(sc); - return s; -#else - if (!arg->type->isscalar()) - error("%s is not a scalar type", arg->type->toChars()); - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - sc->noctor++; - - key = new VarDeclaration(loc, arg->type, arg->ident, NULL); - DeclarationExp *de = new DeclarationExp(loc, key); - de->semantic(sc); - - if (key->storage_class) - error("foreach range: key cannot have storage class"); - - sc->sbreak = this; - sc->scontinue = this; - body = body->semantic(sc); - - sc->noctor--; - sc->pop(); - return s; -#endif -} - -int ForeachRangeStatement::hasBreak() -{ - return TRUE; -} - -int ForeachRangeStatement::hasContinue() -{ - return TRUE; -} - -int ForeachRangeStatement::usesEH() -{ - assert(0); - return body->usesEH(); -} - -int ForeachRangeStatement::blockExit(bool mustNotThrow) -{ - assert(0); - int result = BEfallthru; - - if (lwr && lwr->canThrow(mustNotThrow)) - result |= BEthrow; - else if (upr && upr->canThrow(mustNotThrow)) - result |= BEthrow; - - if (body) - { - result |= body->blockExit(mustNotThrow) & ~(BEbreak | BEcontinue); - } - return result; -} - - -int ForeachRangeStatement::comeFrom() -{ - assert(0); - if (body) - return body->comeFrom(); - return FALSE; -} - -void ForeachRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(op)); - buf->writestring(" ("); - - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - buf->writestring(arg->ident->toChars()); - - buf->writestring("; "); - lwr->toCBuffer(buf, hgs); - buf->writestring(" .. "); - upr->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -#endif - -/******************************** IfStatement ***************************/ - -IfStatement::IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->arg = arg; - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; - this->match = NULL; -} - -Statement *IfStatement::syntaxCopy() -{ - Statement *i = NULL; - if (ifbody) - i = ifbody->syntaxCopy(); - - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - - Parameter *a = arg ? arg->syntaxCopy() : NULL; - IfStatement *s = new IfStatement(loc, a, condition->syntaxCopy(), i, e); - return s; -} - -Statement *IfStatement::semantic(Scope *sc) -{ - // Evaluate at runtime - unsigned cs0 = sc->callSuper; - unsigned cs1; - - Scope *scd; - if (arg) - { /* Declare arg, which we will set to be the - * result of condition. - */ - ScopeDsymbol *sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - scd = sc->push(sym); - - match = new VarDeclaration(loc, arg->type, arg->ident, new ExpInitializer(loc, condition)); - match->parent = sc->func; - - DeclarationExp *de = new DeclarationExp(loc, match); - VarExp *ve = new VarExp(0, match); - condition = new CommaExp(loc, de, ve); - condition = condition->semantic(scd); - - if (match->edtor) - { - Statement *sdtor = new ExpStatement(loc, match->edtor); - sdtor = new OnScopeStatement(loc, TOKon_scope_exit, sdtor); - ifbody = new CompoundStatement(loc, sdtor, ifbody); - match->noscope = 1; - } - } - else - { - condition = condition->semantic(sc); - condition = condition->addDtorHook(sc); - condition = resolveProperties(sc, condition); - scd = sc->push(); - } - - // Convert to boolean after declaring arg so this works: - // if (S arg = S()) {} - // where S is a struct that defines opCast!bool. - condition = condition->checkToBoolean(sc); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - condition = condition->optimize(WANTflags); - ifbody = ifbody->semanticNoScope(scd); - scd->pop(); - - cs1 = sc->callSuper; - sc->callSuper = cs0; - if (elsebody) - elsebody = elsebody->semanticScope(sc, NULL, NULL); - sc->mergeCallSuper(loc, cs1); - - return this; -} - -int IfStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int IfStatement::blockExit(bool mustNotThrow) -{ - //printf("IfStatement::blockExit(%p)\n", this); - - int result = BEnone; - if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - if (condition->isBool(TRUE)) - { - if (ifbody) - result |= ifbody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - else if (condition->isBool(FALSE)) - { - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - else - { - if (ifbody) - result |= ifbody->blockExit(mustNotThrow); - else - result |= BEfallthru; - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - else - result |= BEfallthru; - } - //printf("IfStatement::blockExit(%p) = x%x\n", this, result); - return result; -} - - -void IfStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("if ("); - if (arg) - { - if (arg->type) - arg->type->toCBuffer(buf, arg->ident, hgs); - else - { buf->writestring("auto "); - buf->writestring(arg->ident->toChars()); - } - buf->writestring(" = "); - } - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - ifbody->toCBuffer(buf, hgs); - if (elsebody) - { buf->writestring("else"); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - } -} - -/******************************** ConditionalStatement ***************************/ - -ConditionalStatement::ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody) - : Statement(loc) -{ - this->condition = condition; - this->ifbody = ifbody; - this->elsebody = elsebody; -} - -Statement *ConditionalStatement::syntaxCopy() -{ - Statement *e = NULL; - if (elsebody) - e = elsebody->syntaxCopy(); - ConditionalStatement *s = new ConditionalStatement(loc, - condition->syntaxCopy(), ifbody->syntaxCopy(), e); - return s; -} - -Statement *ConditionalStatement::semantic(Scope *sc) -{ - //printf("ConditionalStatement::semantic()\n"); - - // If we can short-circuit evaluate the if statement, don't do the - // semantic analysis of the skipped code. - // This feature allows a limited form of conditional compilation. - if (condition->include(sc, NULL)) - { - DebugCondition *dc = condition->isDebugCondition(); - if (dc) - { - sc = sc->push(); - sc->flags |= SCOPEdebug; - ifbody = ifbody->semantic(sc); - sc->pop(); - } - else - ifbody = ifbody->semantic(sc); - return ifbody; - } - else - { - if (elsebody) - elsebody = elsebody->semantic(sc); - return elsebody; - } -} - -Statements *ConditionalStatement::flatten(Scope *sc) -{ - Statement *s; - - //printf("ConditionalStatement::flatten()\n"); - if (condition->include(sc, NULL)) - { - DebugCondition *dc = condition->isDebugCondition(); - if (dc) - s = new DebugStatement(loc, ifbody); - else - s = ifbody; - } - else - s = elsebody; - - Statements *a = new Statements(); - a->push(s); - return a; -} - -int ConditionalStatement::usesEH() -{ - return (ifbody && ifbody->usesEH()) || (elsebody && elsebody->usesEH()); -} - -int ConditionalStatement::blockExit(bool mustNotThrow) -{ - int result = ifbody->blockExit(mustNotThrow); - if (elsebody) - result |= elsebody->blockExit(mustNotThrow); - return result; -} - -void ConditionalStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - condition->toCBuffer(buf, hgs); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - if (ifbody) - ifbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - if (elsebody) - { - buf->writestring("else"); - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - elsebody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); - } - buf->writenl(); -} - - -/******************************** PragmaStatement ***************************/ - -PragmaStatement::PragmaStatement(Loc loc, Identifier *ident, Expressions *args, Statement *body) - : Statement(loc) -{ - this->ident = ident; - this->args = args; - this->body = body; -} - -Statement *PragmaStatement::syntaxCopy() -{ - Statement *b = NULL; - if (body) - b = body->syntaxCopy(); - PragmaStatement *s = new PragmaStatement(loc, - ident, Expression::arraySyntaxCopy(args), b); - return s; -} - -Statement *PragmaStatement::semantic(Scope *sc) -{ // Should be merged with PragmaDeclaration - //printf("PragmaStatement::semantic() %s\n", toChars()); - //printf("body = %p\n", body); - if (ident == Id::msg) - { - if (args) - { - for (size_t i = 0; i < args->dim; i++) - { - Expression *e = (*args)[i]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - StringExp *se = e->toString(); - if (se) - { - fprintf(stdmsg, "%.*s", (int)se->len, (char *)se->string); - } - else - fprintf(stdmsg, "%s", e->toChars()); - } - fprintf(stdmsg, "\n"); - } - } - else if (ident == Id::lib) - { -#if 1 - /* Should this be allowed? - */ - error("pragma(lib) not allowed as statement"); -#else - if (!args || args->dim != 1) - error("string expected for library name"); - else - { - Expression *e = (*args)[0]; - - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - (*args)[0] = e; - StringExp *se = e->toString(); - if (!se) - error("string expected for library name, not '%s'", e->toChars()); - else if (global.params.verbose) - { - char *name = (char *)mem.malloc(se->len + 1); - memcpy(name, se->string, se->len); - name[se->len] = 0; - printf("library %s\n", name); - mem.free(name); - } - } -#endif - } - - // LDC - else if (ident == Id::allow_inline) - { - sc->func->allowInlining = true; - } -#if DMDV2 - else if (ident == Id::startaddress) - { - if (!args || args->dim != 1) - error("function name expected for start address"); - else - { - Expression *e = (*args)[0]; - e = e->semantic(sc); - e = e->optimize(WANTvalue | WANTinterpret); - (*args)[0] = e; - Dsymbol *sa = getDsymbol(e); - if (!sa || !sa->isFuncDeclaration()) - error("function name expected for start address, not '%s'", e->toChars()); - if (body) - { - body = body->semantic(sc); - } - return this; - } - } -#endif - else - error("unrecognized pragma(%s)", ident->toChars()); - - if (body) - { - body = body->semantic(sc); - } - return body; -} - -int PragmaStatement::usesEH() -{ - return body && body->usesEH(); -} - -int PragmaStatement::blockExit(bool mustNotThrow) -{ - 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(mustNotThrow); -#endif - return result; -} - - -void PragmaStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("pragma ("); - buf->writestring(ident->toChars()); - if (args && args->dim) - { - buf->writestring(", "); - argsToCBuffer(buf, args, hgs); - } - buf->writeByte(')'); - if (body) - { - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - - body->toCBuffer(buf, hgs); - - buf->writeByte('}'); - buf->writenl(); - } - else - { - buf->writeByte(';'); - buf->writenl(); - } -} - - -/******************************** StaticAssertStatement ***************************/ - -StaticAssertStatement::StaticAssertStatement(StaticAssert *sa) - : Statement(sa->loc) -{ - this->sa = sa; -} - -Statement *StaticAssertStatement::syntaxCopy() -{ - StaticAssertStatement *s = new StaticAssertStatement((StaticAssert *)sa->syntaxCopy(NULL)); - return s; -} - -Statement *StaticAssertStatement::semantic(Scope *sc) -{ - sa->semantic2(sc); - return NULL; -} - -int StaticAssertStatement::blockExit(bool mustNotThrow) -{ - return BEfallthru; -} - -void StaticAssertStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - sa->toCBuffer(buf, hgs); -} - - -/******************************** SwitchStatement ***************************/ - -SwitchStatement::SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal) - : Statement(loc) -{ - this->condition = c; - this->body = b; - this->isFinal = isFinal; - sdefault = NULL; - cases = NULL; - hasNoDefault = 0; - hasVars = 0; -#if IN_LLVM - enclosingScopeExit = NULL; -#endif -} - -Statement *SwitchStatement::syntaxCopy() -{ - SwitchStatement *s = new SwitchStatement(loc, - condition->syntaxCopy(), body->syntaxCopy(), isFinal); - return s; -} - -Statement *SwitchStatement::semantic(Scope *sc) -{ - //printf("SwitchStatement::semantic(%p)\n", this); - assert(!cases); // ensure semantic() is only run once - -#if IN_LLVM - enclosingScopeExit = sc->enclosingScopeExit; -#endif - - condition = condition->semantic(sc); - condition = resolveProperties(sc, condition); - if (condition->type->isString()) - { - // If it's not an array, cast it to one - if (condition->type->ty != Tarray) - { - condition = condition->implicitCastTo(sc, condition->type->nextOf()->arrayOf()); - } - condition->type = condition->type->constOf(); - } - else - { condition = condition->integralPromotions(sc); - condition->checkIntegral(); - } - condition = condition->optimize(WANTvalue); - - sc = sc->push(); - sc->sbreak = this; - sc->sw = this; - - cases = new CaseStatements(); - sc->noctor++; // BUG: should use Scope::mergeCallSuper() for each case instead - body = body->semantic(sc); - sc->noctor--; - - // Resolve any goto case's with exp - for (size_t i = 0; i < gotoCases.dim; i++) - { - GotoCaseStatement *gcs = gotoCases[i]; - - if (!gcs->exp) - { - gcs->error("no case statement following goto case;"); - break; - } - - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (!scx->sw) - continue; - for (size_t j = 0; j < scx->sw->cases->dim; j++) - { - CaseStatement *cs = (*scx->sw->cases)[j]; - - if (cs->exp->equals(gcs->exp)) - { - gcs->cs = cs; - goto Lfoundcase; - } - } - } - gcs->error("case %s not found", gcs->exp->toChars()); - - Lfoundcase: - ; - } - - bool needswitcherror = FALSE; -#if DMDV2 - if (isFinal) - { Type *t = condition->type; - while (t->ty == Ttypedef) - { // Don't use toBasetype() because that will skip past enums - t = ((TypeTypedef *)t)->sym->basetype; - } - if (condition->type->ty == Tenum) - { TypeEnum *te = (TypeEnum *)condition->type; - EnumDeclaration *ed = te->toDsymbol(sc)->isEnumDeclaration(); - assert(ed); - size_t dim = ed->members->dim; - for (size_t i = 0; i < dim; i++) - { - EnumMember *em = (*ed->members)[i]->isEnumMember(); - if (em) - { - for (size_t j = 0; j < cases->dim; j++) - { CaseStatement *cs = (*cases)[j]; - if (cs->exp->equals(em->value)) - goto L1; - } - error("enum member %s not represented in final switch", em->toChars()); - } - L1: - ; - } - } - else - needswitcherror = TRUE; - } -#endif - - if (!sc->sw->sdefault && (!isFinal || needswitcherror)) - { hasNoDefault = 1; - - if (!global.params.useDeprecated && !isFinal) - error("non-final switch statement without a default is deprecated"); - - // Generate runtime error if the default is hit - Statements *a = new Statements(); - CompoundStatement *cs; - Statement *s; - - if (global.params.useSwitchError) - s = new SwitchErrorStatement(loc); - else - { Expression *e = new HaltExp(loc); - s = new ExpStatement(loc, e); - } - - a->reserve(2); - sc->sw->sdefault = new DefaultStatement(loc, s); - a->push(sc->sw->sdefault); - a->push(body); - cs = new CompoundStatement(loc, a); - body = cs; - } - - sc->pop(); - return this; -} - -int SwitchStatement::hasBreak() -{ - return TRUE; -} - -int SwitchStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int SwitchStatement::blockExit(bool mustNotThrow) -{ int result = BEnone; - if (condition->canThrow(mustNotThrow)) - result |= BEthrow; - - if (body) - { result |= body->blockExit(mustNotThrow); - if (result & BEbreak) - { result |= BEfallthru; - result &= ~BEbreak; - } - } - else - result |= BEfallthru; - - return result; -} - - -void SwitchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(isFinal ? "final switch (" : "switch ("); - condition->toCBuffer(buf, hgs); - buf->writebyte(')'); - buf->writenl(); - if (body) - { - if (!body->isScopeStatement()) - { buf->writebyte('{'); - buf->writenl(); - body->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); - } - else - { - body->toCBuffer(buf, hgs); - } - } -} - -/******************************** CaseStatement ***************************/ - -CaseStatement::CaseStatement(Loc loc, Expression *exp, Statement *s) - : Statement(loc) -{ - this->exp = exp; - this->statement = s; - index = 0; - cblock = NULL; - bodyBB = NULL; - llvmIdx = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *CaseStatement::syntaxCopy() -{ - CaseStatement *s = new CaseStatement(loc, exp->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseStatement::semantic() %s\n", toChars()); - exp = exp->semantic(sc); - if (sw) - { -#if IN_LLVM - enclosingScopeExit = sc->enclosingScopeExit; - if (enclosingScopeExit != sw->enclosingScopeExit) - { - error("case must be inside the same try, synchronized or volatile level as switch"); - } -#endif - exp = exp->implicitCastTo(sc, sw->condition->type); - exp = exp->optimize(WANTvalue); - - /* This is where variables are allowed as case expressions. - */ - if (exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - Type *t = exp->type->toBasetype(); - if (v && (t->isintegral() || t->ty == Tclass)) - { /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw->hasVars = 1; - if (sw->isFinal) - error("case variables not allowed in final switch statements"); - goto L1; - } - } - else - exp = exp->optimize(WANTvalue | WANTinterpret); - - if (exp->op != TOKstring && exp->op != TOKint64 && exp->op != TOKerror) - { - error("case must be a string or an integral constant, not %s", exp->toChars()); - exp = new IntegerExp(0); - } - - L1: - for (size_t i = 0; i < sw->cases->dim; i++) - { - CaseStatement *cs = (*sw->cases)[i]; - - //printf("comparing '%s' with '%s'\n", exp->toChars(), cs->exp->toChars()); - if (cs->exp->equals(exp)) - { error("duplicate case %s in switch statement", exp->toChars()); - break; - } - } - - sw->cases->push(this); - - // Resolve any goto case's with no exp to this case statement - for (size_t i = 0; i < sw->gotoCases.dim; i++) - { - GotoCaseStatement *gcs = sw->gotoCases[i]; - - if (!gcs->exp) - { - gcs->cs = this; - sw->gotoCases.remove(i); // remove from array - } - } -#if IN_DMD - if (sc->sw->tf != sc->tf) - error("switch and case are in different finally blocks"); -#endif - } - else - error("case not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int CaseStatement::compare(Object *obj) -{ - // Sort cases so we can do an efficient lookup - CaseStatement *cs2 = (CaseStatement *)(obj); - - return exp->compare(cs2->exp); -} - -int CaseStatement::usesEH() -{ - return statement->usesEH(); -} - -int CaseStatement::blockExit(bool mustNotThrow) -{ - return statement->blockExit(mustNotThrow); -} - - -int CaseStatement::comeFrom() -{ - return TRUE; -} - -void CaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - exp->toCBuffer(buf, hgs); - buf->writebyte(':'); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -/******************************** CaseRangeStatement ***************************/ - -#if DMDV2 - -CaseRangeStatement::CaseRangeStatement(Loc loc, Expression *first, - Expression *last, Statement *s) - : Statement(loc) -{ - this->first = first; - this->last = last; - this->statement = s; -} - -Statement *CaseRangeStatement::syntaxCopy() -{ - CaseRangeStatement *s = new CaseRangeStatement(loc, - first->syntaxCopy(), last->syntaxCopy(), statement->syntaxCopy()); - return s; -} - -Statement *CaseRangeStatement::semantic(Scope *sc) -{ SwitchStatement *sw = sc->sw; - - //printf("CaseRangeStatement::semantic() %s\n", toChars()); - if (sw->isFinal) - error("case ranges not allowed in final switch"); - - first = first->semantic(sc); - first = first->implicitCastTo(sc, sw->condition->type); - first = first->optimize(WANTvalue | WANTinterpret); - - - last = last->semantic(sc); - last = last->implicitCastTo(sc, sw->condition->type); - last = last->optimize(WANTvalue | WANTinterpret); - - if (first->op == TOKerror || last->op == TOKerror) - return statement ? statement->semantic(sc) : NULL; - - uinteger_t fval = first->toInteger(); - uinteger_t lval = last->toInteger(); - - - if ( (first->type->isunsigned() && fval > lval) || - (!first->type->isunsigned() && (sinteger_t)fval > (sinteger_t)lval)) - { - error("first case %s is greater than last case %s", - first->toChars(), last->toChars()); - lval = fval; - } - - if (lval - fval > 256) - { error("had %llu cases which is more than 256 cases in case range", lval - fval); - lval = fval + 256; - } - - /* This works by replacing the CaseRange with an array of Case's. - * - * case a: .. case b: s; - * => - * case a: - * [...] - * case b: - * s; - */ - - Statements *statements = new Statements(); - for (uinteger_t i = fval; i != lval + 1; i++) - { - Statement *s = statement; - if (i != lval) // if not last case - s = new ExpStatement(loc, (Expression *)NULL); - Expression *e = new IntegerExp(loc, i, first->type); - Statement *cs = new CaseStatement(loc, e, s); - statements->push(cs); - } - Statement *s = new CompoundStatement(loc, statements); - s = s->semantic(sc); - return s; -} - -void CaseRangeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("case "); - first->toCBuffer(buf, hgs); - buf->writestring(": .. case "); - last->toCBuffer(buf, hgs); - buf->writebyte(':'); - buf->writenl(); - statement->toCBuffer(buf, hgs); -} - -#endif - -/******************************** DefaultStatement ***************************/ - -DefaultStatement::DefaultStatement(Loc loc, Statement *s) - : Statement(loc) -{ - this->statement = s; -#if IN_GCC -+ cblock = NULL; -#endif - bodyBB = NULL; - // LDC - enclosingScopeExit = NULL; -} - -Statement *DefaultStatement::syntaxCopy() -{ - DefaultStatement *s = new DefaultStatement(loc, statement->syntaxCopy()); - return s; -} - -Statement *DefaultStatement::semantic(Scope *sc) -{ - //printf("DefaultStatement::semantic()\n"); - if (sc->sw) - { - if (sc->sw->sdefault) - { - error("switch statement already has a default"); - } - sc->sw->sdefault = this; - -#if IN_LLVM - enclosingScopeExit = sc->sw->enclosingScopeExit; - - if (sc->sw->isFinal) - { - error("default statement not allowed in final switch statement"); - } -#endif - } - else - error("default not in switch statement"); - statement = statement->semantic(sc); - return this; -} - -int DefaultStatement::usesEH() -{ - return statement->usesEH(); -} - -int DefaultStatement::blockExit(bool mustNotThrow) -{ - return statement->blockExit(mustNotThrow); -} - - -int DefaultStatement::comeFrom() -{ - return TRUE; -} - -void DefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("default:\n"); - statement->toCBuffer(buf, hgs); -} - -/******************************** GotoDefaultStatement ***************************/ - -GotoDefaultStatement::GotoDefaultStatement(Loc loc) - : Statement(loc) -{ - sw = NULL; -} - -Statement *GotoDefaultStatement::syntaxCopy() -{ - GotoDefaultStatement *s = new GotoDefaultStatement(loc); - return s; -} - -Statement *GotoDefaultStatement::semantic(Scope *sc) -{ - sw = sc->sw; - if (!sw) - error("goto default not in switch statement"); - return this; -} - -int GotoDefaultStatement::blockExit(bool mustNotThrow) -{ - return BEgoto; -} - - -void GotoDefaultStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto default;\n"); -} - -/******************************** GotoCaseStatement ***************************/ - -GotoCaseStatement::GotoCaseStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - cs = NULL; - this->exp = exp; - sw = NULL; -} - -Statement *GotoCaseStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - GotoCaseStatement *s = new GotoCaseStatement(loc, e); - return s; -} - -Statement *GotoCaseStatement::semantic(Scope *sc) -{ - if (exp) - exp = exp->semantic(sc); - - if (!sc->sw) - error("goto case not in switch statement"); - else - { - sw = sc->sw; - sc->sw->gotoCases.push(this); - if (exp) - { - exp = exp->implicitCastTo(sc, sc->sw->condition->type); - exp = exp->optimize(WANTvalue); - } - } - return this; -} - -int GotoCaseStatement::blockExit(bool mustNotThrow) -{ - return BEgoto; -} - - -void GotoCaseStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto case"); - if (exp) - { buf->writebyte(' '); - exp->toCBuffer(buf, hgs); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SwitchErrorStatement ***************************/ - -SwitchErrorStatement::SwitchErrorStatement(Loc loc) - : Statement(loc) -{ -} - -int SwitchErrorStatement::blockExit(bool mustNotThrow) -{ - // Switch errors are non-recoverable - return BEhalt; -} - - -void SwitchErrorStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("SwitchErrorStatement::toCBuffer()"); - buf->writenl(); -} - -/******************************** ReturnStatement ***************************/ - -ReturnStatement::ReturnStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ReturnStatement::syntaxCopy() -{ - Expression *e = NULL; - if (exp) - e = exp->syntaxCopy(); - ReturnStatement *s = new ReturnStatement(loc, e); - return s; -} - -Statement *ReturnStatement::semantic(Scope *sc) -{ - //printf("ReturnStatement::semantic() %s\n", toChars()); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - Scope *scx = sc; - int implicit0 = 0; - Expression *eorg = NULL; - - if (fd->fes) - fd = fd->fes->func; // fd is now function enclosing foreach - - Type *tret = fd->type->nextOf(); - if (fd->tintro) - /* We'll be implicitly casting the return expression to tintro - */ - tret = fd->tintro->nextOf(); - Type *tbret = NULL; - - if (tret) - tbret = tret->toBasetype(); - - // main() returns 0, even if it returns void - if (!exp && (!tbret || tbret->ty == Tvoid) && fd->isMain()) - { implicit0 = 1; - exp = new IntegerExp(0); - } - - if (sc->incontract || scx->incontract) - error("return statements cannot be in contracts"); - if (sc->enclosingFinally || scx->enclosingFinally) - error("return statements cannot be in finally, scope(exit) or scope(success) bodies"); - - if (fd->isCtorDeclaration()) - { - // Constructors implicitly do: - // return this; - if (exp && exp->op != TOKthis) - error("cannot return expression from constructor"); - exp = new ThisExp(0); - exp->type = tret; - } - - if (!exp) - fd->nrvo_can = 0; - - if (exp) - { - fd->hasReturnExp |= 1; - - if (exp->op == TOKfunction && tbret) - ((FuncExp *)exp)->setType(tbret); - - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (!((TypeFunction *)fd->type)->isref) - exp = exp->optimize(WANTvalue); - - if (fd->nrvo_can && exp->op == TOKvar) - { VarExp *ve = (VarExp *)exp; - VarDeclaration *v = ve->var->isVarDeclaration(); - - if (((TypeFunction *)fd->type)->isref) - // Function returns a reference - fd->nrvo_can = 0; - else if (!v || v->isOut() || v->isRef()) - fd->nrvo_can = 0; -// else if (tbret->ty == Tstruct && ((TypeStruct *)tbret)->sym->dtor) -// // Struct being returned has destructors -// fd->nrvo_can = 0; - else if (fd->nrvo_var == NULL) - { if (!v->isDataseg() && !v->isParameter() && v->toParent2() == fd) - { //printf("Setting nrvo to %s\n", v->toChars()); - fd->nrvo_var = v; - } - else - fd->nrvo_can = 0; - } - else if (fd->nrvo_var != v) - fd->nrvo_can = 0; - } - else - fd->nrvo_can = 0; - - if (fd->inferRetType) - { TypeFunction *tf = (TypeFunction *)fd->type; - assert(tf->ty == Tfunction); - Type *tfret = tf->nextOf(); - if (tfret) - { - if (tfret != Type::terror) - { - if (!exp->type->equals(tfret)) - { - int m1 = exp->type->implicitConvTo(tfret); - int m2 = tfret->implicitConvTo(exp->type); - //printf("exp->type = %s m2<-->m1 tret %s\n", exp->type->toChars(), tfret->toChars()); - //printf("m1 = %d, m2 = %d\n", m1, m2); - - if (m1 && m2) - ; - else if (!m1 && m2) - tf->next = exp->type; - else if (m1 && !m2) - ; - else - error("mismatched function return type inference of %s and %s", - exp->type->toChars(), tfret->toChars()); - } - } - - /* The "refness" is determined by the first return statement, - * not all of them. This means: - * return 3; return x; // ok, x can be a value - * return x; return 3; // error, 3 is not an lvalue - */ - } - else - { - if (tf->isref) - { /* Determine "refness" of function return: - * if it's an lvalue, return by ref, else return by value - */ - if (exp->isLvalue()) - { - /* Return by ref - * (but first ensure it doesn't fail the "check for - * escaping reference" test) - */ - unsigned errors = global.startGagging(); - exp->checkEscapeRef(); - if (global.endGagging(errors)) - { tf->isref = FALSE; // return by value - } - } - else - tf->isref = FALSE; // return by value - } - tf->next = exp->type; - //fd->type = tf->semantic(loc, sc); // Removed with 6902 - if (!fd->tintro) - { tret = fd->type->nextOf(); - tbret = tret->toBasetype(); - } - } - if (fd->returnLabel) - eorg = exp; - } - else if (tbret->ty != Tvoid) - { - if (fd->isPureBypassingInference() == PUREstrong && - !exp->type->implicitConvTo(tret) && - exp->type->invariantOf()->implicitConvTo(tret)) - { - exp = exp->castTo(sc, exp->type->invariantOf()); - } - if (fd->tintro) - exp = exp->implicitCastTo(sc, fd->type->nextOf()); - - // eorg isn't casted to tret (== fd->tintro->nextOf()) - if (fd->returnLabel) - eorg = exp->copy(); - exp = exp->implicitCastTo(sc, tret); - - if (!((TypeFunction *)fd->type)->isref) - exp = exp->optimize(WANTvalue); - } - } - else if (fd->inferRetType) - { - if (fd->type->nextOf()) - { - if (fd->type->nextOf()->ty != Tvoid) - error("mismatched function return type inference of void and %s", - fd->type->nextOf()->toChars()); - } - else - { - ((TypeFunction *)fd->type)->next = Type::tvoid; - //fd->type = fd->type->semantic(loc, sc); // Remove with7321, same as 6902 - if (!fd->tintro) - { tret = Type::tvoid; - tbret = tret; - } - } - } - else if (tbret->ty != Tvoid) // if non-void return - error("return expression expected"); - - if (sc->fes) - { - Statement *s; - - if (exp && !implicit0) - { - exp = exp->implicitCastTo(sc, tret); - } - if (!exp || exp->op == TOKint64 || exp->op == TOKfloat64 || - exp->op == TOKimaginary80 || exp->op == TOKcomplex80 || - exp->op == TOKthis || exp->op == TOKsuper || exp->op == TOKnull || - exp->op == TOKstring) - { - sc->fes->cases->push(this); - // Construct: return cases->dim+1; - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - } - else if (fd->type->nextOf()->toBasetype() == Type::tvoid) - { - s = new ReturnStatement(0, NULL); - sc->fes->cases->push(s); - - // Construct: { exp; return cases->dim + 1; } - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - else - { - // Construct: return vresult; - if (!fd->vresult) - { // Declare vresult - VarDeclaration *v = new VarDeclaration(loc, tret, Id::result, NULL); - v->noscope = 1; - v->storage_class |= STCresult; - v->semantic(scx); - if (!scx->insert(v)) - assert(0); - v->parent = fd; - fd->vresult = v; - } - - s = new ReturnStatement(0, new VarExp(0, fd->vresult)); - sc->fes->cases->push(s); - - // Construct: { vresult = exp; return cases->dim + 1; } - exp = new ConstructExp(loc, new VarExp(0, fd->vresult), exp); - exp = exp->semantic(sc); - Statement *s1 = new ExpStatement(loc, exp); - Statement *s2 = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - s = new CompoundStatement(loc, s1, s2); - } - return s; - } - - if (exp) - { - if (((TypeFunction *)fd->type)->isref && !fd->isCtorDeclaration()) - { // Function returns a reference - if (tret->isMutable()) - exp = exp->modifiableLvalue(sc, exp); - else - exp = exp->toLvalue(sc, exp); - - exp->checkEscapeRef(); - } - else - { - //exp->dump(0); - //exp->print(); - exp->checkEscape(); - } - - if (fd->returnLabel && tbret->ty != Tvoid) - { - assert(fd->vresult); - VarExp *v = new VarExp(0, fd->vresult); - - assert(eorg); - exp = new ConstructExp(loc, v, eorg); - exp = exp->semantic(sc); - } - } - - /* BUG: need to issue an error on: - * this - * { if (x) return; - * super(); - * } - */ - - if (sc->callSuper & CSXany_ctor && - !(sc->callSuper & (CSXthis_ctor | CSXsuper_ctor))) - error("return without calling constructor"); - - sc->callSuper |= CSXreturn; - - // See if all returns are instead to be replaced with a goto returnLabel; - if (fd->returnLabel) - { - GotoStatement *gs = new GotoStatement(loc, Id::returnLabel); - - gs->label = fd->returnLabel; - if (exp) - { /* Replace: return exp; - * with: exp; goto returnLabel; - */ - Statement *s = new ExpStatement(0, exp); - return new CompoundStatement(loc, s, gs); - } - return gs; - } - - if (exp && tbret->ty == Tvoid && !implicit0) - { - /* Replace: - * return exp; - * with: - * exp; return; - */ - Statement *s = new ExpStatement(loc, exp); - s = s->semantic(sc); - - if (exp->type->ty != Tvoid) - { - error("cannot return non-void from void function"); - } - - exp = NULL; - return new CompoundStatement(loc, s, this); - } - - if (exp) - { if (exp->op == TOKcall) - valueNoDtor(exp); - else - { - Expression *e = exp->isTemp(); - if (e) - exp = e; // don't need temporary - } - } - - return this; -} - -int ReturnStatement::blockExit(bool mustNotThrow) -{ int result = BEreturn; - - if (exp && exp->canThrow(mustNotThrow)) - result |= BEthrow; - return result; -} - - -void ReturnStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("return "); - if (exp) - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** BreakStatement ***************************/ - -BreakStatement::BreakStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *BreakStatement::syntaxCopy() -{ - BreakStatement *s = new BreakStatement(loc, ident); - return s; -} - -Statement *BreakStatement::semantic(Scope *sc) -{ - //printf("BreakStatement::semantic()\n"); - // If: - // break Identifier; - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases->push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - return s; - } - break; // can't break to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasBreak()) - error("label '%s' has no break", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot break out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for break not found", ident->toChars()); - } - else if (!sc->sbreak) - { - if (sc->fes) - { Statement *s; - - // Replace break; with return 1; - s = new ReturnStatement(0, new IntegerExp(1)); - return s; - } - error("break is not inside a loop or switch"); - } - return this; -} - -int BreakStatement::blockExit(bool mustNotThrow) -{ - //printf("BreakStatement::blockExit(%p) = x%x\n", this, ident ? BEgoto : BEbreak); - return ident ? BEgoto : BEbreak; -} - - -void BreakStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("break"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** ContinueStatement ***************************/ - -ContinueStatement::ContinueStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; -} - -Statement *ContinueStatement::syntaxCopy() -{ - ContinueStatement *s = new ContinueStatement(loc, ident); - return s; -} - -Statement *ContinueStatement::semantic(Scope *sc) -{ - //printf("ContinueStatement::semantic() %p\n", this); - if (ident) - { - Scope *scx; - FuncDeclaration *thisfunc = sc->func; - - for (scx = sc; scx; scx = scx->enclosing) - { - LabelStatement *ls; - - if (scx->func != thisfunc) // if in enclosing function - { - if (sc->fes) // if this is the body of a foreach - { - for (; scx; scx = scx->enclosing) - { - ls = scx->slabel; - if (ls && ls->ident == ident && ls->statement == sc->fes) - { - // Replace continue ident; with return 0; - return new ReturnStatement(0, new IntegerExp(0)); - } - } - - /* Post this statement to the fes, and replace - * it with a return value that caller will put into - * a switch. Caller will figure out where the break - * label actually is. - * Case numbers start with 2, not 0, as 0 is continue - * and 1 is break. - */ - Statement *s; - sc->fes->cases->push(this); - s = new ReturnStatement(0, new IntegerExp(sc->fes->cases->dim + 1)); - return s; - } - break; // can't continue to it - } - - ls = scx->slabel; - if (ls && ls->ident == ident) - { - Statement *s = ls->statement; - - if (!s->hasContinue()) - error("label '%s' has no continue", ident->toChars()); - if (ls->enclosingFinally != sc->enclosingFinally) - error("cannot continue out of finally block"); - - this->target = ls; - return this; - } - } - error("enclosing label '%s' for continue not found", ident->toChars()); - } - else if (!sc->scontinue) - { - if (sc->fes) - { Statement *s; - - // Replace continue; with return 0; - s = new ReturnStatement(0, new IntegerExp(0)); - return s; - } - error("continue is not inside a loop"); - } - return this; -} - -int ContinueStatement::blockExit(bool mustNotThrow) -{ - return ident ? BEgoto : BEcontinue; -} - - -void ContinueStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("continue"); - if (ident) - { buf->writebyte(' '); - buf->writestring(ident->toChars()); - } - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** SynchronizedStatement ***************************/ - -SynchronizedStatement::SynchronizedStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - this->esync = NULL; - // LDC - this->llsync = NULL; -} - -SynchronizedStatement::SynchronizedStatement(Loc loc, elem *esync, Statement *body) - : Statement(loc) -{ - this->exp = NULL; - this->body = body; - this->esync = esync; - // LDC - this->llsync = NULL; -} - -Statement *SynchronizedStatement::syntaxCopy() -{ - Expression *e = exp ? exp->syntaxCopy() : NULL; - SynchronizedStatement *s = new SynchronizedStatement(loc, e, body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *SynchronizedStatement::semantic(Scope *sc) -{ - if (exp) - { - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - ClassDeclaration *cd = exp->type->isClassHandle(); - if (!cd) - error("can only synchronize on class objects, not '%s'", exp->type->toChars()); - else if (cd->isInterfaceDeclaration()) - { /* Cast the interface to an object, as the object has the monitor, - * not the interface. - */ - Type *t = new TypeIdentifier(0, Id::Object); - - t = t->semantic(0, sc); - exp = new CastExp(loc, exp, t); - exp = exp->semantic(sc); - } - -#if 1 - /* Rewrite as: - * auto tmp = exp; - * _d_monitorenter(tmp); - * try { body } finally { _d_monitorexit(tmp); } - */ - Identifier *id = Lexer::uniqueId("__sync"); - ExpInitializer *ie = new ExpInitializer(loc, exp); - VarDeclaration *tmp = new VarDeclaration(loc, exp->type, id, ie); - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - -#if IN_LLVM - // LDC: Build args - Parameters* args = new Parameters; - args->push(new Parameter(STCin, ClassDeclaration::object->type, NULL, NULL)); - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorenter); -#endif - Expression *e = new CallExp(loc, new VarExp(loc, fdenter), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - -#if IN_LLVM - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::monitorexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::monitorexit); -#endif - e = new CallExp(loc, new VarExp(loc, fdexit), new VarExp(loc, tmp)); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); -#endif - } -#if 1 - else - { /* Generate our own critical section, then rewrite as: - * __gshared byte[CriticalSection.sizeof] critsec; - * _d_criticalenter(critsec.ptr); - * try { body } finally { _d_criticalexit(critsec.ptr); } - */ - Identifier *id = Lexer::uniqueId("__critsec"); - Type *t = new TypeSArray(Type::tint8, new IntegerExp(PTRSIZE + os_critsecsize())); - VarDeclaration *tmp = new VarDeclaration(loc, t, id, NULL); - tmp->storage_class |= STCgshared | STCstatic; - - Statements *cs = new Statements(); - cs->push(new ExpStatement(loc, tmp)); - -#if IN_LLVM - // LDC: Build args - Parameters* args = new Parameters; - args->push(new Parameter(STCin, t->pointerTo(), NULL, NULL)); - - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalenter); -#else - FuncDeclaration *fdenter = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalenter); -#endif - Expression *e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdenter), e); - e->type = Type::tvoid; // do not run semantic on e - cs->push(new ExpStatement(loc, e)); - -#if IN_LLVM - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(args, Type::tvoid, Id::criticalexit); -#else - FuncDeclaration *fdexit = FuncDeclaration::genCfunc(Type::tvoid, Id::criticalexit); -#endif - e = new DotIdExp(loc, new VarExp(loc, tmp), Id::ptr); - e = e->semantic(sc); - e = new CallExp(loc, new VarExp(loc, fdexit), e); - e->type = Type::tvoid; // do not run semantic on e - Statement *s = new ExpStatement(loc, e); - s = new TryFinallyStatement(loc, body, s); - cs->push(s); - - s = new CompoundStatement(loc, cs); - return s->semantic(sc); - } -#endif - if (body) - { - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - body = body->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - } - return this; -} - -int SynchronizedStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int SynchronizedStatement::usesEH() -{ - return TRUE; -} - -int SynchronizedStatement::blockExit(bool mustNotThrow) -{ - return body ? body->blockExit(mustNotThrow) : BEfallthru; -} - - -void SynchronizedStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("synchronized"); - if (exp) - { buf->writebyte('('); - exp->toCBuffer(buf, hgs); - buf->writebyte(')'); - } - if (body) - { - buf->writebyte(' '); - body->toCBuffer(buf, hgs); - } -} - -/******************************** WithStatement ***************************/ - -WithStatement::WithStatement(Loc loc, Expression *exp, Statement *body) - : Statement(loc) -{ - this->exp = exp; - this->body = body; - wthis = NULL; -} - -Statement *WithStatement::syntaxCopy() -{ - WithStatement *s = new WithStatement(loc, exp->syntaxCopy(), body ? body->syntaxCopy() : NULL); - return s; -} - -Statement *WithStatement::semantic(Scope *sc) -{ ScopeDsymbol *sym; - Initializer *init; - - //printf("WithStatement::semantic()\n"); - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - return NULL; - if (exp->op == TOKimport) - { ScopeExp *es = (ScopeExp *)exp; - - sym = es->sds; - } - else if (exp->op == TOKtype) - { TypeExp *es = (TypeExp *)exp; - - Dsymbol *s = es->type->toDsymbol(sc); - sym = s ? s->isScopeDsymbol() : NULL; - if (!sym) - { error("with type %s has no members", es->toChars()); - if (body) - body = body->semantic(sc); - return this; - } - } - else - { Type *t = exp->type; - - assert(t); - t = t->toBasetype(); - if (t->isClassHandle()) - { - init = new ExpInitializer(loc, exp); - wthis = new VarDeclaration(loc, exp->type, Id::withSym, init); - wthis->semantic(sc); - - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else if (t->ty == Tstruct) - { - Expression *e = exp->addressOf(sc); - init = new ExpInitializer(loc, e); - wthis = new VarDeclaration(loc, e->type, Id::withSym, init); - wthis->semantic(sc); - sym = new WithScopeSymbol(this); - sym->parent = sc->scopesym; - } - else - { error("with expressions must be class objects, not '%s'", exp->type->toChars()); - return NULL; - } - } - sc = sc->push(sym); - - if (body) - body = body->semantic(sc); - - sc->pop(); - - return this; -} - -void WithStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("with ("); - exp->toCBuffer(buf, hgs); - buf->writestring(")\n"); - if (body) - body->toCBuffer(buf, hgs); -} - -int WithStatement::usesEH() -{ - return body ? body->usesEH() : 0; -} - -int WithStatement::blockExit(bool mustNotThrow) -{ - int result = BEnone; - if (exp->canThrow(mustNotThrow)) - result = BEthrow; - if (body) - result |= body->blockExit(mustNotThrow); - else - result |= BEfallthru; - return result; -} - - -/******************************** TryCatchStatement ***************************/ - -TryCatchStatement::TryCatchStatement(Loc loc, Statement *body, Catches *catches) - : Statement(loc) -{ - this->body = body; - this->catches = catches; -} - -Statement *TryCatchStatement::syntaxCopy() -{ - Catches *a = new Catches(); - a->setDim(catches->dim); - for (size_t i = 0; i < a->dim; i++) - { Catch *c; - - c = (*catches)[i]; - c = c->syntaxCopy(); - (*a)[i] = c; - } - TryCatchStatement *s = new TryCatchStatement(loc, body->syntaxCopy(), a); - return s; -} - -Statement *TryCatchStatement::semantic(Scope *sc) -{ - body = body->semanticScope(sc, NULL /*this*/, NULL); - - /* Even if body is NULL, still do semantic analysis on catches - */ - for (size_t i = 0; i < catches->dim; i++) - { Catch *c = (*catches)[i]; - c->semantic(sc); - - // Determine if current catch 'hides' any previous catches - for (size_t j = 0; j < i; j++) - { Catch *cj = (*catches)[j]; - char *si = c->loc.toChars(); - char *sj = cj->loc.toChars(); - - if (c->type->toBasetype()->implicitConvTo(cj->type->toBasetype())) - error("catch at %s hides catch at %s", sj, si); - } - } - - if (!body || body->isEmpty()) - { - return NULL; - } - return this; -} - -int TryCatchStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryCatchStatement::usesEH() -{ - return TRUE; -} - -int TryCatchStatement::blockExit(bool mustNotThrow) -{ - assert(body); - int result = body->blockExit(false); - - int catchresult = 0; - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (*catches)[i]; - if (c->type == Type::terror) - continue; - - catchresult |= c->blockExit(mustNotThrow); - - /* If we're catching Object, then there is no throwing - */ - Identifier *id = c->type->toBasetype()->isClassHandle()->ident; - if (id == Id::Object || id == Id::Throwable || id == Id::Exception) - { - result &= ~BEthrow; - } - } - if (mustNotThrow && (result & BEthrow)) - { - body->blockExit(mustNotThrow); // now explain why this is nothrow - } - return result | catchresult; -} - - -void TryCatchStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("try"); - buf->writenl(); - if (body) - body->toCBuffer(buf, hgs); - for (size_t i = 0; i < catches->dim; i++) - { - Catch *c = (*catches)[i]; - c->toCBuffer(buf, hgs); - } -} - -/******************************** Catch ***************************/ - -Catch::Catch(Loc loc, Type *t, Identifier *id, Statement *handler) -{ - //printf("Catch(%s, loc = %s)\n", id->toChars(), loc.toChars()); - this->loc = loc; - this->type = t; - this->ident = id; - this->handler = handler; - var = NULL; - internalCatch = false; -} - -Catch *Catch::syntaxCopy() -{ - Catch *c = new Catch(loc, - (type ? type->syntaxCopy() : NULL), - ident, - (handler ? handler->syntaxCopy() : NULL)); - c->internalCatch = internalCatch; - return c; -} - -void Catch::semantic(Scope *sc) -{ ScopeDsymbol *sym; - - //printf("Catch::semantic(%s)\n", ident->toChars()); - -#ifndef IN_GCC - if (sc->enclosingFinally) - { - /* This is because the _d_local_unwind() gets the stack munged - * up on this. The workaround is to place any try-catches into - * a separate function, and call that. - * To fix, have the compiler automatically convert the finally - * body into a nested function. - */ - error(loc, "cannot put catch statement inside finally block"); - } -#endif - - sym = new ScopeDsymbol(); - sym->parent = sc->scopesym; - sc = sc->push(sym); - - if (!type) - type = new TypeIdentifier(0, Id::Throwable); - type = type->semantic(loc, sc); - ClassDeclaration *cd = type->toBasetype()->isClassHandle(); - if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL))) - { - if (type != Type::terror) - { error(loc, "can only catch class objects derived from Throwable, not '%s'", type->toChars()); - type = Type::terror; - } - } - else if (sc->func && - !sc->intypeof && - !internalCatch && - cd != ClassDeclaration::exception && - !ClassDeclaration::exception->isBaseOf(cd, NULL) && - sc->func->setUnsafe()) - { - error(loc, "can only catch class objects derived from Exception in @safe code, not '%s'", type->toChars()); - type = Type::terror; - } - else if (ident) - { - var = new VarDeclaration(loc, type, ident, NULL); - var->parent = sc->parent; - sc->insert(var); - } - handler = handler->semantic(sc); - - sc->pop(); -} - -int Catch::blockExit(bool mustNotThrow) -{ - return handler ? handler->blockExit(mustNotThrow) : BEfallthru; -} - -void Catch::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("catch"); - if (type) - { buf->writebyte('('); - type->toCBuffer(buf, ident, hgs); - buf->writebyte(')'); - } - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - if (handler) - handler->toCBuffer(buf, hgs); - buf->writebyte('}'); - buf->writenl(); -} - -/****************************** TryFinallyStatement ***************************/ - -TryFinallyStatement::TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody) - : Statement(loc) -{ - this->body = body; - this->finalbody = finalbody; -} - -Statement *TryFinallyStatement::syntaxCopy() -{ - TryFinallyStatement *s = new TryFinallyStatement(loc, - body->syntaxCopy(), finalbody->syntaxCopy()); - return s; -} - -Statement *TryFinallyStatement::semantic(Scope *sc) -{ - //printf("TryFinallyStatement::semantic()\n"); - - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - body = body->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - - sc = sc->push(); - sc->enclosingFinally = this; - sc->sbreak = NULL; - sc->scontinue = NULL; // no break or continue out of finally block - finalbody = finalbody->semanticNoScope(sc); - sc->pop(); - if (!body) - return finalbody; - if (!finalbody) - return body; - if (body->blockExit(false) == BEfallthru) - { Statement *s = new CompoundStatement(loc, body, finalbody); - return s; - } - return this; -} - -void TryFinallyStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("try\n{\n"); - body->toCBuffer(buf, hgs); - buf->printf("}\nfinally\n{\n"); - finalbody->toCBuffer(buf, hgs); - buf->writeByte('}'); - buf->writenl(); -} - -int TryFinallyStatement::hasBreak() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::hasContinue() -{ - return FALSE; //TRUE; -} - -int TryFinallyStatement::usesEH() -{ - return TRUE; -} - -int TryFinallyStatement::blockExit(bool mustNotThrow) -{ - if (body) - return body->blockExit(mustNotThrow); - return BEfallthru; -} - - -/****************************** OnScopeStatement ***************************/ - -OnScopeStatement::OnScopeStatement(Loc loc, TOK tok, Statement *statement) - : Statement(loc) -{ - this->tok = tok; - this->statement = statement; -} - -Statement *OnScopeStatement::syntaxCopy() -{ - OnScopeStatement *s = new OnScopeStatement(loc, - tok, statement->syntaxCopy()); - return s; -} - -Statement *OnScopeStatement::semantic(Scope *sc) -{ - /* semantic is called on results of scopeCode() */ - return this; -} - -int OnScopeStatement::blockExit(bool mustNotThrow) -{ // At this point, this statement is just an empty placeholder - return BEfallthru; -} - -void OnScopeStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(Token::toChars(tok)); - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); -} - -int OnScopeStatement::usesEH() -{ - return 1; -} - -Statement *OnScopeStatement::scopeCode(Scope *sc, Statement **sentry, Statement **sexception, Statement **sfinally) -{ - //printf("OnScopeStatement::scopeCode()\n"); - //print(); - *sentry = NULL; - *sexception = NULL; - *sfinally = NULL; - switch (tok) - { - case TOKon_scope_exit: - *sfinally = statement; - break; - - case TOKon_scope_failure: - *sexception = statement; - break; - - case TOKon_scope_success: - { - /* Create: - * sentry: bool x = false; - * sexception: x = true; - * sfinally: if (!x) statement; - */ - Identifier *id = Lexer::uniqueId("__os"); - - ExpInitializer *ie = new ExpInitializer(loc, new IntegerExp(0, 0, Type::tbool)); - VarDeclaration *v = new VarDeclaration(loc, Type::tbool, id, ie); - *sentry = new ExpStatement(loc, v); - - Expression *e = new IntegerExp(0, 1, Type::tbool); - e = new AssignExp(0, new VarExp(0, v), e); - *sexception = new ExpStatement(0, e); - - e = new VarExp(0, v); - e = new NotExp(0, e); - *sfinally = new IfStatement(0, NULL, e, statement, NULL); - - break; - } - - default: - assert(0); - } - return NULL; -} - -/******************************** ThrowStatement ***************************/ - -ThrowStatement::ThrowStatement(Loc loc, Expression *exp) - : Statement(loc) -{ - this->exp = exp; -} - -Statement *ThrowStatement::syntaxCopy() -{ - ThrowStatement *s = new ThrowStatement(loc, exp->syntaxCopy()); - return s; -} - -Statement *ThrowStatement::semantic(Scope *sc) -{ - //printf("ThrowStatement::semantic()\n"); - - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - fd->hasReturnExp |= 2; - -#if DMDV1 - // See bugzilla 3388. Should this be or not? - if (sc->incontract) - error("Throw statements cannot be in contracts"); -#endif - exp = exp->semantic(sc); - exp = resolveProperties(sc, exp); - if (exp->op == TOKerror) - return this; - ClassDeclaration *cd = exp->type->toBasetype()->isClassHandle(); - if (!cd || ((cd != ClassDeclaration::throwable) && !ClassDeclaration::throwable->isBaseOf(cd, NULL))) - error("can only throw class objects derived from Throwable, not type %s", exp->type->toChars()); - - return this; -} - -int ThrowStatement::blockExit(bool mustNotThrow) -{ - if (mustNotThrow) - error("%s is thrown but not caught", exp->type->toChars()); - return BEthrow; // obviously -} - - -void ThrowStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("throw "); - exp->toCBuffer(buf, hgs); - buf->writeByte(';'); - buf->writenl(); -} - -/******************************** VolatileStatement **************************/ - -VolatileStatement::VolatileStatement(Loc loc, Statement *statement) - : Statement(loc) -{ - this->statement = statement; -} - -Statement *VolatileStatement::syntaxCopy() -{ - VolatileStatement *s = new VolatileStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; -} - -Statement *VolatileStatement::semantic(Scope *sc) -{ - if (statement) - { - Statement* oldScopeExit = sc->enclosingScopeExit; - sc->enclosingScopeExit = this; - statement = statement->semantic(sc); - sc->enclosingScopeExit = oldScopeExit; - } - return this; -} - -Statements *VolatileStatement::flatten(Scope *sc) -{ - Statements *a; - - a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (size_t i = 0; i < a->dim; i++) - { Statement *s = (*a)[i]; - - s = new VolatileStatement(loc, s); - (*a)[i] = s; - } - } - - return a; -} - -int VolatileStatement::blockExit(bool mustNotThrow) -{ - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -void VolatileStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("volatile"); - if (statement) - { if (statement->isScopeStatement()) - buf->writenl(); - else - buf->writebyte(' '); - statement->toCBuffer(buf, hgs); - } -} - - -/******************************** DebugStatement **************************/ - -DebugStatement::DebugStatement(Loc loc, Statement *statement) - : Statement(loc) -{ - this->statement = statement; -} - -Statement *DebugStatement::syntaxCopy() -{ - DebugStatement *s = new DebugStatement(loc, - statement ? statement->syntaxCopy() : NULL); - return s; -} - -Statement *DebugStatement::semantic(Scope *sc) -{ - if (statement) - { - sc = sc->push(); - sc->flags |= SCOPEdebug; - statement = statement->semantic(sc); - sc->pop(); - } - return statement; -} - -Statements *DebugStatement::flatten(Scope *sc) -{ - Statements *a = statement ? statement->flatten(sc) : NULL; - if (a) - { for (size_t i = 0; i < a->dim; i++) - { Statement *s = (*a)[i]; - - s = new DebugStatement(loc, s); - (*a)[i] = s; - } - } - - return a; -} - -void DebugStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - if (statement) - { - statement->toCBuffer(buf, hgs); - } -} - - -/******************************** GotoStatement ***************************/ - -GotoStatement::GotoStatement(Loc loc, Identifier *ident) - : Statement(loc) -{ - this->ident = ident; - this->label = NULL; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; -} - -Statement *GotoStatement::syntaxCopy() -{ - GotoStatement *s = new GotoStatement(loc, ident); - return s; -} - -Statement *GotoStatement::semantic(Scope *sc) -{ FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("GotoStatement::semantic()\n"); - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - label = fd->searchLabel(ident); - if (!label->statement && sc->fes) - { - /* Either the goto label is forward referenced or it - * is in the function that the enclosing foreach is in. - * Can't know yet, so wrap the goto in a compound statement - * so we can patch it later, and add it to a 'look at this later' - * list. - */ - Statements *a = new Statements(); - CompoundStatement *s; - - a->push(this); - s = new CompoundStatement(loc, a); - sc->fes->gotos->push(s); // 'look at this later' list - return s; - } - if (label->statement && label->statement->enclosingFinally != sc->enclosingFinally) - error("cannot goto in or out of finally block"); - return this; -} - -int GotoStatement::blockExit(bool mustNotThrow) -{ - //printf("GotoStatement::blockExit(%p)\n", this); - return BEgoto; -} - - -void GotoStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("goto "); - buf->writestring(ident->toChars()); - buf->writebyte(';'); - buf->writenl(); -} - -/******************************** LabelStatement ***************************/ - -LabelStatement::LabelStatement(Loc loc, Identifier *ident, Statement *statement) - : Statement(loc) -{ - this->ident = ident; - this->statement = statement; - this->enclosingFinally = NULL; - this->enclosingScopeExit = NULL; - this->lblock = NULL; - this->fwdrefs = NULL; - this->asmLabel = false; -} - -Statement *LabelStatement::syntaxCopy() -{ - LabelStatement *s = new LabelStatement(loc, ident, statement->syntaxCopy()); - return s; -} - -Statement *LabelStatement::semantic(Scope *sc) -{ LabelDsymbol *ls; - FuncDeclaration *fd = sc->parent->isFuncDeclaration(); - - //printf("LabelStatement::semantic()\n"); - ls = fd->searchLabel(ident); - if (ls->statement) - error("Label '%s' already defined", ls->toChars()); - else - ls->statement = this; - - enclosingFinally = sc->enclosingFinally; - enclosingScopeExit = sc->enclosingScopeExit; - - sc = sc->push(); - sc->scopesym = sc->enclosing->scopesym; - sc->callSuper |= CSXlabel; - sc->slabel = this; - if (statement) - statement = statement->semanticNoScope(sc); - sc->pop(); - - // LDC put in labmap - fd->labmap[ident->toChars()] = this; - - return this; -} - -Statements *LabelStatement::flatten(Scope *sc) -{ - Statements *a = NULL; - - if (statement) - { - a = statement->flatten(sc); - if (a) - { - if (!a->dim) - { - a->push(new ExpStatement(loc, (Expression *)NULL)); - } - Statement *s = (*a)[0]; - - s = new LabelStatement(loc, ident, s); - (*a)[0] = s; - } - } - - return a; -} - - -int LabelStatement::usesEH() -{ - return statement ? statement->usesEH() : FALSE; -} - -int LabelStatement::blockExit(bool mustNotThrow) -{ - //printf("LabelStatement::blockExit(%p)\n", this); - return statement ? statement->blockExit(mustNotThrow) : BEfallthru; -} - - -int LabelStatement::comeFrom() -{ - //printf("LabelStatement::comeFrom()\n"); - return TRUE; -} - -void LabelStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(ident->toChars()); - buf->writebyte(':'); - buf->writenl(); - if (statement) - statement->toCBuffer(buf, hgs); -} - - -/******************************** LabelDsymbol ***************************/ - -LabelDsymbol::LabelDsymbol(Identifier *ident) - : Dsymbol(ident) -{ - statement = NULL; -#if IN_GCC - asmLabelNum = 0; -#endif -} - -LabelDsymbol *LabelDsymbol::isLabel() // is this a LabelDsymbol()? -{ - return this; -} - -#if !IN_LLVM - -/************************ AsmStatement ***************************************/ - -AsmStatement::AsmStatement(Loc loc, Token *tokens) - : Statement(loc) -{ - this->tokens = tokens; - asmcode = NULL; - asmalign = 0; - refparam = FALSE; - naked = FALSE; - regs = 0; -} - -Statement *AsmStatement::syntaxCopy() -{ - return new AsmStatement(loc, tokens); -} - - - -int AsmStatement::comeFrom() -{ - return TRUE; -} - -int AsmStatement::blockExit(bool mustNotThrow) -{ - if (mustNotThrow) - error("asm statements are assumed to throw", toChars()); - // Assume the worst - return BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt; -} - -void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("asm { "); - Token *t = tokens; - while (t) - { - buf->writestring(t->toChars()); - if (t->next && - t->value != TOKmin && - t->value != TOKcomma && - t->next->value != TOKcomma && - t->value != TOKlbracket && - t->next->value != TOKlbracket && - t->next->value != TOKrbracket && - t->value != TOKlparen && - t->next->value != TOKlparen && - t->next->value != TOKrparen && - t->value != TOKdot && - t->next->value != TOKdot) - { - buf->writebyte(' '); - } - t = t->next; - } - buf->writestring("; }"); - buf->writenl(); -} - -#endif - -/************************ ImportStatement ***************************************/ - -ImportStatement::ImportStatement(Loc loc, Dsymbols *imports) - : Statement(loc) -{ - this->imports = imports; -} - -Statement *ImportStatement::syntaxCopy() -{ - Dsymbols *m = new Dsymbols(); - m->setDim(imports->dim); - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = (*imports)[i]; - (*m)[i] = s->syntaxCopy(NULL); - } - return new ImportStatement(loc, m); -} - -Statement *ImportStatement::semantic(Scope *sc) -{ - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = (*imports)[i]; - s->semantic(sc); - sc->insert(s); - } - return this; -} - -int ImportStatement::blockExit(bool mustNotThrow) -{ - return BEfallthru; -} - -int ImportStatement::isEmpty() -{ - return TRUE; -} - -void ImportStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - for (size_t i = 0; i < imports->dim; i++) - { Dsymbol *s = (*imports)[i]; - s->toCBuffer(buf, hgs); - } -} diff --git a/dmd2/statement.h b/dmd2/statement.h deleted file mode 100644 index 06fbe750..00000000 --- a/dmd2/statement.h +++ /dev/null @@ -1,1011 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 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 ExpStatement; -struct DefaultStatement; -struct VarDeclaration; -struct Condition; -struct Module; -struct Token; -struct InlineCostState; -struct InlineDoState; -struct InlineScanState; -struct ReturnStatement; -struct CompoundStatement; -struct Parameter; -struct StaticAssert; -struct AsmStatement; -#if IN_LLVM -struct AsmBlockStatement; -#endif -struct GotoStatement; -struct ScopeStatement; -struct TryCatchStatement; -struct TryFinallyStatement; -struct CaseStatement; -struct DefaultStatement; -struct LabelStatement; -struct HdrGenState; -struct InterState; -#if IN_LLVM -struct CaseStatement; -struct LabelStatement; -struct VolatileStatement; -struct SynchronizedStatement; -#endif - -enum TOK; - -#if IN_LLVM -namespace llvm -{ - class Value; - class BasicBlock; - class ConstantInt; -} -#endif - -// Back end -struct IRState; -struct Blockx; -#if IN_LLVM -struct DValue; -typedef DValue elem; -#endif - -#if IN_GCC -union tree_node; typedef union tree_node block; -//union tree_node; typedef union tree_node elem; -#else -struct block; -//struct elem; -#endif -struct code; - -/* How a statement exits; this is returned by blockExit() - */ -enum BE -{ - BEnone = 0, - BEfallthru = 1, - BEthrow = 2, - BEreturn = 4, - BEgoto = 8, - BEhalt = 0x10, - BEbreak = 0x20, - BEcontinue = 0x40, - BEany = (BEfallthru | BEthrow | BEreturn | BEgoto | BEhalt), -}; - -struct Statement : Object -{ - Loc loc; - virtual ~Statement() {} - - Statement(Loc loc); - virtual Statement *syntaxCopy(); - - void print(); - char *toChars(); - - void error(const char *format, ...) IS_PRINTF(2); - void warning(const char *format, ...) IS_PRINTF(2); - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual AsmBlockStatement *isAsmBlockStatement() { return NULL; } - int incontract; - virtual ScopeStatement *isScopeStatement() { return NULL; } - virtual Statement *semantic(Scope *sc); - Statement *semanticScope(Scope *sc, Statement *sbreak, Statement *scontinue); - Statement *semanticNoScope(Scope *sc); - virtual int hasBreak(); - virtual int hasContinue(); - virtual int usesEH(); - virtual int blockExit(bool mustNotThrow); - virtual int comeFrom(); - virtual int isEmpty(); - virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - virtual Statements *flatten(Scope *sc); - virtual Expression *interpret(InterState *istate); - virtual Statement *last(); - - virtual int inlineCost(InlineCostState *ics); - virtual Expression *doInline(InlineDoState *ids); - virtual Statement *doInlineStatement(InlineDoState *ids); - virtual Statement *inlineScan(InlineScanState *iss); - - // Back end - virtual void toIR(IRState *irs); - - // Avoid dynamic_cast - virtual ExpStatement *isExpStatement() { return NULL; } - virtual CompoundStatement *isCompoundStatement() { return NULL; } - virtual ReturnStatement *isReturnStatement() { return NULL; } - virtual IfStatement *isIfStatement() { return NULL; } - virtual CaseStatement *isCaseStatement() { return NULL; } - virtual DefaultStatement *isDefaultStatement() { return NULL; } - virtual LabelStatement *isLabelStatement() { return NULL; } - -#if IN_LLVM - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -#endif -}; - -struct PeelStatement : Statement -{ - Statement *s; - - PeelStatement(Statement *s); - Statement *semantic(Scope *sc); -}; - -struct ExpStatement : Statement -{ - Expression *exp; - - ExpStatement(Loc loc, Expression *exp); - ExpStatement(Loc loc, Dsymbol *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - int isEmpty(); - Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - ExpStatement *isExpStatement() { return this; } -#if IN_LLVM - void toNakedIR(IRState *irs); -#endif -}; - -struct DtorExpStatement : ExpStatement -{ - /* Wraps an expression that is the destruction of 'var' - */ - - VarDeclaration *var; - - DtorExpStatement(Loc loc, Expression *exp, VarDeclaration *v); - Statement *syntaxCopy(); - 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); - int blockExit(bool mustNotThrow); -}; - -struct CompoundStatement : Statement -{ - Statements *statements; - - CompoundStatement(Loc loc, Statements *s); - CompoundStatement(Loc loc, Statement *s1); - CompoundStatement(Loc loc, Statement *s1, Statement *s2); - virtual Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - virtual Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - int isEmpty(); - virtual Statements *flatten(Scope *sc); - ReturnStatement *isReturnStatement(); - Expression *interpret(InterState *istate); - Statement *last(); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - virtual void toIR(IRState *irs); - -#if IN_LLVM - virtual void toNakedIR(IRState *irs); - virtual AsmBlockStatement* endsWithAsm(); -#endif - - virtual CompoundStatement *isCompoundStatement() { return this; } -}; - -struct CompoundDeclarationStatement : CompoundStatement -{ - CompoundDeclarationStatement(Loc loc, Statements *s); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -/* The purpose of this is so that continue will go to the next - * of the statements, and break will go to the end of the statements. - */ -struct UnrolledLoopStatement : Statement -{ - Statements *statements; - - UnrolledLoopStatement(Loc loc, Statements *statements); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(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(bool mustNotThrow); - int comeFrom(); - int isEmpty(); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct WhileStatement : Statement -{ - Expression *condition; - Statement *body; - - WhileStatement(Loc loc, Expression *c, Statement *b); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct DoStatement : Statement -{ - Statement *body; - Expression *condition; - - DoStatement(Loc loc, Statement *b, Expression *c); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ForStatement : Statement -{ - Statement *init; - Expression *condition; - Expression *increment; - Statement *body; - - ForStatement(Loc loc, Statement *init, Expression *condition, Expression *increment, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Statement *inlineScan(InlineScanState *iss); - Statement *doInlineStatement(InlineDoState *ids); - - void toIR(IRState *irs); -}; - -struct ForeachStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Parameters *arguments; // array of Parameter*'s - Expression *aggr; - Statement *body; - - VarDeclaration *key; - VarDeclaration *value; - - FuncDeclaration *func; // function we're lexically in - - Statements *cases; // put breaks, continues, gotos and returns here - CompoundStatements *gotos; // forward referenced goto's go here - - ForeachStatement(Loc loc, enum TOK op, Parameters *arguments, Expression *aggr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - bool checkForArgTypes(); - int inferAggregate(Scope *sc, Dsymbol *&sapply); - int inferApplyArgTypes(Scope *sc, Dsymbol *&sapply); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -#if DMDV2 -struct ForeachRangeStatement : Statement -{ - enum TOK op; // TOKforeach or TOKforeach_reverse - Parameter *arg; // loop index variable - Expression *lwr; - Expression *upr; - Statement *body; - - VarDeclaration *key; - - ForeachRangeStatement(Loc loc, enum TOK op, Parameter *arg, - Expression *lwr, Expression *upr, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; -#endif - -struct IfStatement : Statement -{ - Parameter *arg; - Expression *condition; - Statement *ifbody; - Statement *elsebody; - - VarDeclaration *match; // for MatchExpression results - - IfStatement(Loc loc, Parameter *arg, Expression *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(bool mustNotThrow); - IfStatement *isIfStatement() { return this; } - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct ConditionalStatement : Statement -{ - Condition *condition; - Statement *ifbody; - Statement *elsebody; - - ConditionalStatement(Loc loc, Condition *condition, Statement *ifbody, Statement *elsebody); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - - 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(bool mustNotThrow); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct StaticAssertStatement : Statement -{ - StaticAssert *sa; - - StaticAssertStatement(StaticAssert *sa); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct SwitchStatement : Statement -{ - Expression *condition; - Statement *body; - bool isFinal; - - DefaultStatement *sdefault; - - GotoCaseStatements gotoCases; // array of unresolved GotoCaseStatement's - CaseStatements *cases; // array of CaseStatement's - int hasNoDefault; // !=0 if no default statement - int hasVars; // !=0 if has variable case values - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - SwitchStatement(Loc loc, Expression *c, Statement *b, bool isFinal); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct CaseStatement : Statement -{ - Expression *exp; - Statement *statement; - - int index; // which case it is (since we sort this) - block *cblock; // back end: label for the block - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - CaseStatement(Loc loc, Expression *exp, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int compare(Object *obj); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - CaseStatement *isCaseStatement() { return this; } - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - llvm::BasicBlock* bodyBB; - llvm::Value* llvmIdx; -#endif -}; - -#if DMDV2 - -struct CaseRangeStatement : Statement -{ - Expression *first; - Expression *last; - Statement *statement; - - CaseRangeStatement(Loc loc, Expression *first, Expression *last, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif - -struct DefaultStatement : Statement -{ - Statement *statement; -#if IN_GCC - block *cblock; // back end: label for the block -#endif - -#if IN_LLVM - Statement *enclosingScopeExit; -#endif - - DefaultStatement(Loc loc, Statement *s); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - DefaultStatement *isDefaultStatement() { return this; } - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - -#if IN_LLVM - llvm::BasicBlock* bodyBB; -#endif -}; - -struct GotoDefaultStatement : Statement -{ - SwitchStatement *sw; - - GotoDefaultStatement(Loc loc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct GotoCaseStatement : Statement -{ - Expression *exp; // NULL, or which case to goto - CaseStatement *cs; // case statement it resolves to - SwitchStatement *sw; - - GotoCaseStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct SwitchErrorStatement : Statement -{ - SwitchErrorStatement(Loc loc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); -}; - -struct ReturnStatement : Statement -{ - Expression *exp; - - ReturnStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - - ReturnStatement *isReturnStatement() { return this; } -}; - -struct BreakStatement : Statement -{ - Identifier *ident; - - BreakStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - -#if IN_LLVM - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -#endif -}; - -struct ContinueStatement : Statement -{ - Identifier *ident; - - ContinueStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Expression *interpret(InterState *istate); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - void toIR(IRState *irs); - -#if IN_LLVM - // LDC: only set if ident is set: label statement to jump to - LabelStatement *target; -#endif -}; - -struct SynchronizedStatement : Statement -{ - Expression *exp; - Statement *body; - - SynchronizedStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - -// Back end - elem *esync; - SynchronizedStatement(Loc loc, elem *esync, Statement *body); - void toIR(IRState *irs); -#if IN_LLVM - llvm::Value* llsync; -#endif -}; - -struct WithStatement : Statement -{ - Expression *exp; - Statement *body; - VarDeclaration *wthis; - - WithStatement(Loc loc, Expression *exp, Statement *body); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct TryCatchStatement : Statement -{ - Statement *body; - Catches *catches; - - TryCatchStatement(Loc loc, Statement *body, Catches *catches); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int hasBreak(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct Catch : Object -{ - Loc loc; - Type *type; - Identifier *ident; - VarDeclaration *var; - Statement *handler; - bool internalCatch; - - Catch(Loc loc, Type *t, Identifier *id, Statement *handler); - Catch *syntaxCopy(); - void semantic(Scope *sc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct TryFinallyStatement : Statement -{ - Statement *body; - Statement *finalbody; - - TryFinallyStatement(Loc loc, Statement *body, Statement *finalbody); - Statement *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int hasBreak(); - int hasContinue(); - int usesEH(); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct OnScopeStatement : Statement -{ - TOK tok; - Statement *statement; - - OnScopeStatement(Loc loc, TOK tok, Statement *statement); - Statement *syntaxCopy(); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Statement *semantic(Scope *sc); - int usesEH(); - Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); -}; - -struct ThrowStatement : Statement -{ - Expression *exp; - - ThrowStatement(Loc loc, Expression *exp); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct VolatileStatement : Statement -{ - Statement *statement; - - VolatileStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int blockExit(bool mustNotThrow); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - - void toIR(IRState *irs); -}; - -struct DebugStatement : Statement -{ - Statement *statement; - - DebugStatement(Loc loc, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct GotoStatement : Statement -{ - Identifier *ident; - LabelDsymbol *label; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - - GotoStatement(Loc loc, Identifier *ident); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - Expression *interpret(InterState *istate); - - void toIR(IRState *irs); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -struct LabelStatement : Statement -{ - Identifier *ident; - Statement *statement; - TryFinallyStatement *enclosingFinally; - Statement* enclosingScopeExit; - block *lblock; // back end - - Blocks *fwdrefs; // forward references to this LabelStatement - - LabelStatement(Loc loc, Identifier *ident, Statement *statement); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - Statements *flatten(Scope *sc); - int usesEH(); - int blockExit(bool mustNotThrow); - int comeFrom(); - Expression *interpret(InterState *istate); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - Statement *inlineScan(InlineScanState *iss); - LabelStatement *isLabelStatement() { return this; } - - void toIR(IRState *irs); - -#if IN_LLVM - bool asmLabel; // for labels inside inline assembler - void toNakedIR(IRState *irs); -#endif -}; - -struct LabelDsymbol : Dsymbol -{ - LabelStatement *statement; -#if IN_GCC - unsigned asmLabelNum; // GCC-specific -#endif - - LabelDsymbol(Identifier *ident); - LabelDsymbol *isLabel(); -}; - -struct AsmStatement : Statement -{ - Token *tokens; - code *asmcode; - unsigned asmalign; // alignment of this statement - unsigned regs; // mask of registers modified (must match regm_t in back end) - unsigned char refparam; // !=0 if function parameter is referenced - unsigned char naked; // !=0 if function is to be naked - - AsmStatement(Loc loc, Token *tokens); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - 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); - - #if IN_LLVM - // non-zero if this is a branch, contains the target labels identifier - Identifier* isBranchToLabel; - - void toNakedIR(IRState *irs); -#endif -}; - -struct ImportStatement : Statement -{ - Dsymbols *imports; // Array of Import's - - ImportStatement(Loc loc, Dsymbols *imports); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - int blockExit(bool mustNotThrow); - int isEmpty(); - Expression *interpret(InterState *istate); - - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - - int inlineCost(InlineCostState *ics); - Expression *doInline(InlineDoState *ids); - Statement *doInlineStatement(InlineDoState *ids); - - void toIR(IRState *irs); -}; - -struct AsmBlockStatement : CompoundStatement -{ - TryFinallyStatement* enclosingFinally; - Statement* enclosingScopeExit; - - AsmBlockStatement(Loc loc, Statements *s); - Statements *flatten(Scope *sc); - Statement *syntaxCopy(); - Statement *semantic(Scope *sc); - - CompoundStatement *isCompoundStatement() { return NULL; } - AsmBlockStatement *isAsmBlockStatement() { return this; } - - void toIR(IRState *irs); - void toNakedIR(IRState *irs); - AsmBlockStatement* endsWithAsm(); - - llvm::Value* abiret; -}; - -#endif /* DMD_STATEMENT_H */ diff --git a/dmd2/staticassert.c b/dmd2/staticassert.c deleted file mode 100644 index 8e3dcefa..00000000 --- a/dmd2/staticassert.c +++ /dev/null @@ -1,127 +0,0 @@ - -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// http://www.dsource.org/projects/dmd/browser/trunk/src/staticassert.c -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include - -#include "dsymbol.h" -#include "staticassert.h" -#include "expression.h" -#include "id.h" -#include "hdrgen.h" -#include "scope.h" -#include "template.h" -#include "declaration.h" - - -/********************************* AttribDeclaration ****************************/ - -StaticAssert::StaticAssert(Loc loc, Expression *exp, Expression *msg) - : Dsymbol(Id::empty) -{ - this->loc = loc; - this->exp = exp; - this->msg = msg; -} - -Dsymbol *StaticAssert::syntaxCopy(Dsymbol *s) -{ - StaticAssert *sa; - - assert(!s); - sa = new StaticAssert(loc, exp->syntaxCopy(), msg ? msg->syntaxCopy() : NULL); - return sa; -} - -int StaticAssert::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - return 0; // we didn't add anything -} - -void StaticAssert::semantic(Scope *sc) -{ -} - -void StaticAssert::semantic2(Scope *sc) -{ - //printf("StaticAssert::semantic2() %s\n", toChars()); - ScopeDsymbol *sd = new ScopeDsymbol(); - sc = sc->push(sd); - sc->flags |= SCOPEstaticassert; - ++sc->ignoreTemplates; - Expression *e = exp->semantic(sc); - sc = sc->pop(); - if (e->type == Type::terror) - return; - unsigned olderrs = global.errors; - e = e->optimize(WANTvalue | WANTinterpret); - if (global.errors != olderrs) - { - errorSupplemental(loc, "while evaluating: static assert(%s)", exp->toChars()); - } - else if (e->isBool(FALSE)) - { - if (msg) - { HdrGenState hgs; - OutBuffer buf; - - msg = msg->semantic(sc); - msg = msg->optimize(WANTvalue | WANTinterpret); - hgs.console = 1; - msg->toCBuffer(&buf, &hgs); - error("%s", buf.toChars()); - } - else - error("(%s) is false", exp->toChars()); - if (sc->tinst) - sc->tinst->printInstantiationTrace(); - if (!global.gag) - fatal(); - } - else if (!e->isBool(TRUE)) - { - error("(%s) is not evaluatable at compile time", exp->toChars()); - } -} - -int StaticAssert::oneMember(Dsymbol **ps, Identifier *ident) -{ - //printf("StaticAssert::oneMember())\n"); - *ps = NULL; - return TRUE; -} - -void StaticAssert::inlineScan() -{ -} - -void StaticAssert::toObjFile(int multiobj) -{ -} - -const char *StaticAssert::kind() -{ - return "static assert"; -} - -void StaticAssert::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring(kind()); - buf->writeByte('('); - exp->toCBuffer(buf, hgs); - if (msg) - { - buf->writeByte(','); - msg->toCBuffer(buf, hgs); - } - buf->writestring(");"); - buf->writenl(); -} diff --git a/dmd2/staticassert.h b/dmd2/staticassert.h deleted file mode 100644 index 8d64416c..00000000 --- a/dmd2/staticassert.h +++ /dev/null @@ -1,41 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_STATICASSERT_H -#define DMD_STATICASSERT_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct Expression; -struct HdrGenState; - -struct StaticAssert : Dsymbol -{ - Expression *exp; - Expression *msg; - - StaticAssert(Loc loc, Expression *exp, Expression *msg); - - Dsymbol *syntaxCopy(Dsymbol *s); - int addMember(Scope *sc, ScopeDsymbol *sd, int memnum); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void inlineScan(); - int oneMember(Dsymbol **ps, Identifier *ident); - void toObjFile(int multiobj); - const char *kind(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; - -#endif diff --git a/dmd2/struct.c b/dmd2/struct.c deleted file mode 100644 index b2ffef2a..00000000 --- a/dmd2/struct.c +++ /dev/null @@ -1,738 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" -#include "aggregate.h" -#include "scope.h" -#include "mtype.h" -#include "declaration.h" -#include "module.h" -#include "id.h" -#include "statement.h" -#include "template.h" - -FuncDeclaration *StructDeclaration::xerreq; // object.xopEquals - -/********************************* AggregateDeclaration ****************************/ - -AggregateDeclaration::AggregateDeclaration(Loc loc, Identifier *id) - : ScopeDsymbol(id) -{ - this->loc = loc; - - storage_class = 0; - protection = PROTpublic; - type = NULL; - handle = NULL; - scope = 0; - structsize = 0; // size of struct - alignsize = 0; // size of struct for alignment purposes - structalign = 0; // struct member alignment in effect - hasUnions = 0; - sizeok = 0; // size not determined yet - deferred = NULL; - isdeprecated = false; - inv = NULL; - aggNew = NULL; - aggDelete = NULL; - -#if IN_DMD - stag = NULL; - sinit = NULL; -#endif - isnested = 0; - vthis = NULL; - -#if DMDV2 - ctor = NULL; - defaultCtor = NULL; - aliasthis = NULL; - noDefaultCtor = FALSE; -#endif - dtor = NULL; - -#if IN_LLVM - availableExternally = true; // assume this unless proven otherwise -#endif -} - -enum PROT AggregateDeclaration::prot() -{ - return protection; -} - -void AggregateDeclaration::semantic2(Scope *sc) -{ - //printf("AggregateDeclaration::semantic2(%s)\n", toChars()); - if (scope && members) - { error("has forward references"); - return; - } - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic2(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::semantic3(Scope *sc) -{ -#if IN_LLVM - if (!global.params.useAvailableExternally) - availableExternally = false; -#endif - - //printf("AggregateDeclaration::semantic3(%s)\n", toChars()); - if (members) - { - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - } - sc->pop(); - } -} - -void AggregateDeclaration::inlineScan() -{ - //printf("AggregateDeclaration::inlineScan(%s)\n", toChars()); - if (members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("inline scan aggregate symbol '%s'\n", s->toChars()); - s->inlineScan(); - } - } -} - -unsigned AggregateDeclaration::size(Loc loc) -{ - //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); - if (!members) - error(loc, "unknown size"); - if (sizeok != 1 && scope) - semantic(NULL); - if (sizeok != 1) - { error(loc, "no size yet for forward reference"); - //*(char*)0=0; - } - return structsize; -} - -Type *AggregateDeclaration::getType() -{ - return type; -} - -int AggregateDeclaration::isDeprecated() -{ - return isdeprecated; -} - -int AggregateDeclaration::isExport() -{ - return protection == PROTexport; -} - -/**************************** - * Do byte or word alignment as necessary. - * Align sizes of 0, as we may not know array sizes yet. - */ - -void AggregateDeclaration::alignmember( - unsigned salign, // struct alignment that is in effect - unsigned size, // alignment requirement of field - unsigned *poffset) -{ - //printf("salign = %d, size = %d, offset = %d\n",salign,size,offset); - if (salign > 1) - { - assert(size != 3); - unsigned sa = size; - if (sa == 0 || salign < sa) - sa = salign; - *poffset = (*poffset + sa - 1) & ~(sa - 1); - } - //printf("result = %d\n",offset); -} - - -void AggregateDeclaration::addField(Scope *sc, VarDeclaration *v) -{ - unsigned memsize; // size of member - unsigned memalignsize; // size of member for alignment purposes - unsigned xalign; // alignment boundaries - - //printf("AggregateDeclaration::addField('%s') %s\n", v->toChars(), toChars()); - assert(!(v->storage_class & (STCstatic | STCextern | STCparameter | STCtls))); - - // Check for forward referenced types which will fail the size() call - Type *t = v->type->toBasetype(); - if (v->storage_class & STCref) - { // References are the size of a pointer - t = Type::tvoidptr; - } - if (t->ty == Tstruct /*&& isStructDeclaration()*/) - { TypeStruct *ts = (TypeStruct *)t; -#if DMDV2 - if (ts->sym == this) - { - error("cannot have field %s with same struct type", v->toChars()); - } -#endif - - if (ts->sym->sizeok != 1 && ts->sym->scope) - ts->sym->semantic(NULL); - if (ts->sym->sizeok != 1) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - } - if (t->ty == Tident) - { - sizeok = 2; // cannot finish; flag as forward referenced - return; - } - - memsize = t->size(loc); - memalignsize = t->alignsize(); - xalign = t->memalign(sc->structalign); -#if 0 - alignmember(xalign, memalignsize, &sc->offset); - v->offset = sc->offset; - sc->offset += memsize; - if (sc->offset > structsize) - structsize = sc->offset; -#else - unsigned ofs = sc->offset; - alignmember(xalign, memalignsize, &ofs); - v->offset = ofs; - ofs += memsize; - if (ofs > structsize) - structsize = ofs; - if (!isUnionDeclaration()) - sc->offset = ofs; -#endif - if (global.params.is64bit && sc->structalign == 8 && memalignsize == 16 && isUnionDeclaration()) - /* Not sure how to handle this */ - ; - else if (sc->structalign < memalignsize) - memalignsize = sc->structalign; - if (alignsize < memalignsize) - alignsize = memalignsize; - //printf("\t%s: alignsize = %d\n", toChars(), alignsize); - - v->storage_class |= STCfield; - //printf(" addField '%s' to '%s' at offset %d, size = %d\n", v->toChars(), toChars(), v->offset, memsize); - fields.push(v); -} - - -/**************************************** - * Returns !=0 if there's an extra member which is the 'this' - * pointer to the enclosing context (enclosing aggregate or function) - */ - -int AggregateDeclaration::isNested() -{ - return isnested; -} - -/**************************************** - * If field[indx] is not part of a union, return indx. - * Otherwise, return the lowest field index of the union. - */ -int AggregateDeclaration::firstFieldInUnion(int indx) -{ - if (isUnionDeclaration()) - return 0; - VarDeclaration * vd = fields.tdata()[indx]; - int firstNonZero = indx; // first index in the union with non-zero size - for (; ;) - { - if (indx == 0) - return firstNonZero; - VarDeclaration * v = fields.tdata()[indx - 1]; - if (v->offset != vd->offset) - return firstNonZero; - --indx; - /* If it is a zero-length field, it's ambiguous: we don't know if it is - * in the union unless we find an earlier non-zero sized field with the - * same offset. - */ - if (v->size(loc) != 0) - firstNonZero = indx; - } -} - -/**************************************** - * Count the number of fields starting at firstIndex which are part of the - * same union as field[firstIndex]. If not a union, return 1. - */ -int AggregateDeclaration::numFieldsInUnion(int firstIndex) -{ - VarDeclaration * vd = fields.tdata()[firstIndex]; - /* If it is a zero-length field, AND we can't find an earlier non-zero - * sized field with the same offset, we assume it's not part of a union. - */ - if (vd->size(loc) == 0 && !isUnionDeclaration() && - firstFieldInUnion(firstIndex) == firstIndex) - return 1; - int count = 1; - for (size_t i = firstIndex+1; i < fields.dim; ++i) - { - VarDeclaration * v = fields.tdata()[i]; - // If offsets are different, they are not in the same union - if (v->offset != vd->offset) - break; - ++count; - } - return count; -} - -/********************************* StructDeclaration ****************************/ - -StructDeclaration::StructDeclaration(Loc loc, Identifier *id) - : AggregateDeclaration(loc, id) -{ - zeroInit = 0; // assume false until we do semantic processing -#if DMDV2 - hasIdentityAssign = 0; - hasIdentityEquals = 0; - cpctor = NULL; - postblit = NULL; - - xeq = NULL; -#endif - - // For forward references - type = new TypeStruct(this); - -#if MODULEINFO_IS_STRUCT - if (id == Id::ModuleInfo) - { - if (Module::moduleinfo) - Module::moduleinfo->error("only object.d can define this reserved class name"); - Module::moduleinfo = this; - } -#endif -} - -Dsymbol *StructDeclaration::syntaxCopy(Dsymbol *s) -{ - StructDeclaration *sd; - - if (s) - sd = (StructDeclaration *)s; - else - sd = new StructDeclaration(loc, ident); - ScopeDsymbol::syntaxCopy(sd); - return sd; -} - -void StructDeclaration::semantic(Scope *sc) -{ - Scope *sc2; - - //printf("+StructDeclaration::semantic(this=%p, %s '%s', sizeok = %d)\n", this, parent->toChars(), toChars(), sizeok); - - //static int count; if (++count == 20) halt(); - - assert(type); - if (!members) // if forward reference - return; - - if (symtab) - { if (sizeok == 1 || !scope) - { //printf("already completed\n"); - scope = NULL; - return; // semantic() already completed - } - } - else - symtab = new DsymbolTable(); - - Scope *scx = NULL; - if (scope) - { sc = scope; - scx = scope; // save so we don't make redundant copies - scope = NULL; - } - - int errors = global.gaggedErrors; - - unsigned dprogress_save = Module::dprogress; - - parent = sc->parent; - type = type->semantic(loc, sc); -#if STRUCTTHISREF - handle = type; -#else - handle = type->pointerTo(); -#endif - structalign = sc->structalign; - protection = sc->protection; - storage_class |= sc->stc; - if (sc->stc & STCdeprecated) - isdeprecated = true; - assert(!isAnonymous()); - if (sc->stc & STCabstract) - error("structs, unions cannot be abstract"); -#if DMDV2 - if (storage_class & STCimmutable) - type = type->addMod(MODimmutable); - if (storage_class & STCconst) - type = type->addMod(MODconst); - if (storage_class & STCshared) - type = type->addMod(MODshared); -#endif - - if (sizeok == 0) // if not already done the addMember step - { - int hasfunctions = 0; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("adding member '%s' to '%s'\n", s->toChars(), this->toChars()); - s->addMember(sc, this, 1); - if (s->isFuncDeclaration()) - hasfunctions = 1; - } - - // If nested struct, add in hidden 'this' pointer to outer scope - if (hasfunctions && !(storage_class & STCstatic)) - { Dsymbol *s = toParent2(); - if (s) - { - AggregateDeclaration *ad = s->isAggregateDeclaration(); - FuncDeclaration *fd = s->isFuncDeclaration(); - - TemplateInstance *ti; - if (ad && (ti = ad->parent->isTemplateInstance()) != NULL && ti->isnested || fd) - { isnested = 1; - Type *t; - if (ad) - t = ad->handle; - else if (fd) - { AggregateDeclaration *ad = fd->isMember2(); - if (ad) - t = ad->handle; - else - t = Type::tvoidptr; - } - else - assert(0); - if (t->ty == Tstruct) - t = Type::tvoidptr; // t should not be a ref type - assert(!vthis); - vthis = new ThisDeclaration(loc, t); - //vthis->storage_class |= STCref; - members->push(vthis); - } - } - } - } - - sizeok = 0; - sc2 = sc->push(this); - sc2->stc &= STCsafe | STCtrusted | STCsystem; - sc2->parent = this; - if (isUnionDeclaration()) - sc2->inunion = 1; - sc2->protection = PROTpublic; - sc2->explicitProtection = 0; - - size_t members_dim = members->dim; - - /* Set scope so if there are forward references, we still might be able to - * resolve individual members like enums. - */ - for (size_t i = 0; i < members_dim; i++) - { Dsymbol *s = (*members)[i]; - /* There are problems doing this in the general case because - * Scope keeps track of things like 'offset' - */ - if (s->isEnumDeclaration() || (s->isAggregateDeclaration() && s->ident)) - { - //printf("setScope %s %s\n", s->kind(), s->toChars()); - s->setScope(sc2); - } - } - - for (size_t i = 0; i < members_dim; i++) - { - Dsymbol *s = (*members)[i]; - - /* If this is the last member, see if we can finish setting the size. - * This could be much better - finish setting the size after the last - * field was processed. The problem is the chicken-and-egg determination - * of when that is. See Bugzilla 7426 for more info. - */ - if (i + 1 == members_dim) - { - if (sizeok == 0 && s->isAliasDeclaration()) - finalizeSize(); - } - s->semantic(sc2); - } - - if (sizeok == 2) - { // semantic() failed because of forward references. - // Unwind what we did, and defer it for later - fields.setDim(0); - structsize = 0; - alignsize = 0; - structalign = 0; - - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - - Module::dprogress = dprogress_save; - //printf("\tdeferring %s\n", toChars()); - return; - } - - finalizeSize(); - Module::dprogress++; - - //printf("-StructDeclaration::semantic(this=%p, '%s')\n", this, toChars()); - - // Determine if struct is all zeros or not - zeroInit = 1; - for (size_t i = 0; i < fields.dim; i++) - { - Dsymbol *s = fields.tdata()[i]; - VarDeclaration *vd = s->isVarDeclaration(); - if (vd && !vd->isDataseg()) - { - if (vd->init) - { - // Should examine init to see if it is really all 0's - zeroInit = 0; - break; - } - else - { - if (!vd->type->isZeroInit(loc)) - { - zeroInit = 0; - break; - } - } - } - } - -#if DMDV1 - /* This doesn't work for DMDV2 because (ref S) and (S) parameter - * lists will overload the same. - */ - /* The TypeInfo_Struct is expecting an opEquals and opCmp with - * a parameter that is a pointer to the struct. But if there - * isn't one, but is an opEquals or opCmp with a value, write - * another that is a shell around the value: - * int opCmp(struct *p) { return opCmp(*p); } - */ - - TypeFunction *tfeqptr; - { - Parameters *arguments = new Parameters; - Parameter *arg = new Parameter(STCin, handle, Id::p, NULL); - - arguments->push(arg); - tfeqptr = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeqptr = (TypeFunction *)tfeqptr->semantic(0, sc); - } - - TypeFunction *tfeq; - { - Parameters *arguments = new Parameters; - Parameter *arg = new Parameter(STCin, type, NULL, NULL); - - arguments->push(arg); - tfeq = new TypeFunction(arguments, Type::tint32, 0, LINKd); - tfeq = (TypeFunction *)tfeq->semantic(0, sc); - } - - Identifier *id = Id::eq; - for (int i = 0; i < 2; i++) - { - Dsymbol *s = search_function(this, id); - FuncDeclaration *fdx = s ? s->isFuncDeclaration() : NULL; - if (fdx) - { FuncDeclaration *fd = fdx->overloadExactMatch(tfeqptr, getModule()); - if (!fd) - { fd = fdx->overloadExactMatch(tfeq, getModule()); - if (fd) - { // Create the thunk, fdptr - FuncDeclaration *fdptr = new FuncDeclaration(loc, loc, fdx->ident, STCundefined, tfeqptr); - Expression *e = new IdentifierExp(loc, Id::p); - e = new PtrExp(loc, e); - Expressions *args = new Expressions(); - args->push(e); - e = new IdentifierExp(loc, id); - e = new CallExp(loc, e, args); - fdptr->fbody = new ReturnStatement(loc, e); - ScopeDsymbol *s = fdx->parent->isScopeDsymbol(); - assert(s); - s->members->push(fdptr); - fdptr->addMember(sc, s, 1); - fdptr->semantic(sc2); - } - } - } - - id = Id::cmp; - } -#endif -#if DMDV2 - dtor = buildDtor(sc2); - postblit = buildPostBlit(sc2); - cpctor = buildCpCtor(sc2); - - buildOpAssign(sc2); - hasIdentityEquals = (buildOpEquals(sc2) != NULL); - - xeq = buildXopEquals(sc2); -#endif - - sc2->pop(); - - /* Look for special member functions. - */ -#if DMDV2 - ctor = search(0, Id::ctor, 0); -#endif - inv = (InvariantDeclaration *)search(0, Id::classInvariant, 0); - aggNew = (NewDeclaration *)search(0, Id::classNew, 0); - aggDelete = (DeleteDeclaration *)search(0, Id::classDelete, 0); - - if (sc->func) - { - semantic2(sc); - semantic3(sc); - } - - if (global.gag && global.gaggedErrors != errors) - { // The type is no good, yet the error messages were gagged. - type = Type::terror; - } - - if (deferred && !global.gag) - { - deferred->semantic2(sc); - deferred->semantic3(sc); - } -} - -Dsymbol *StructDeclaration::search(Loc loc, Identifier *ident, int flags) -{ - //printf("%s.StructDeclaration::search('%s')\n", toChars(), ident->toChars()); - - if (scope && !symtab) - semantic(scope); - - if (!members || !symtab) - { - error("is forward referenced when looking for '%s'", ident->toChars()); - return NULL; - } - - return ScopeDsymbol::search(loc, ident, flags); -} - -void StructDeclaration::finalizeSize() -{ - // 0 sized struct's are set to 1 byte - if (structsize == 0) - { - structsize = 1; - alignsize = 1; - } - - // Round struct size up to next alignsize boundary. - // This will ensure that arrays of structs will get their internals - // aligned properly. - structsize = (structsize + alignsize - 1) & ~(alignsize - 1); - - sizeok = 1; -} - -void StructDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->printf("%s ", kind()); - if (!isAnonymous()) - buf->writestring(toChars()); - if (!members) - { - buf->writeByte(';'); - buf->writenl(); - return; - } - buf->writenl(); - buf->writeByte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - - buf->writestring(" "); - s->toCBuffer(buf, hgs); - } - buf->writeByte('}'); - buf->writenl(); -} - - -const char *StructDeclaration::kind() -{ - return "struct"; -} - -/********************************* UnionDeclaration ****************************/ - -UnionDeclaration::UnionDeclaration(Loc loc, Identifier *id) - : StructDeclaration(loc, id) -{ - hasUnions = 1; -} - -Dsymbol *UnionDeclaration::syntaxCopy(Dsymbol *s) -{ - UnionDeclaration *ud; - - if (s) - ud = (UnionDeclaration *)s; - else - ud = new UnionDeclaration(loc, ident); - StructDeclaration::syntaxCopy(ud); - return ud; -} - - -const char *UnionDeclaration::kind() -{ - return "union"; -} - - diff --git a/dmd2/template.c b/dmd2/template.c deleted file mode 100644 index fa634815..00000000 --- a/dmd2/template.c +++ /dev/null @@ -1,6285 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2012 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Handle template implementation - -#include -#include - -#include "root.h" -#include "aav.h" -#include "rmem.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" -#include "id.h" - -#if WINDOWS_SEH -#include -long __cdecl __ehfilter(LPEXCEPTION_POINTERS ep); -#endif - -#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(o); - if (!o || o->dyncast() != DYNCAST_EXPRESSION) - return NULL; - return (Expression *)o; -} - -Dsymbol *isDsymbol(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_DSYMBOL) - return NULL; - return (Dsymbol *)o; -} - -Type *isType(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TYPE) - return NULL; - return (Type *)o; -} - -Tuple *isTuple(Object *o) -{ - //return dynamic_cast(o); - if (!o || o->dyncast() != DYNCAST_TUPLE) - return NULL; - return (Tuple *)o; -} - -/************************************** - * Is this Object an error? - */ -int isError(Object *o) -{ - Type *t = isType(o); - if (t) - return (t->ty == Terror); - Expression *e = isExpression(o); - if (e) - return (e->op == TOKerror); - Tuple *v = isTuple(o); - if (v) - return arrayObjectIsError(&v->objects); - return 0; -} - -/************************************** - * Are any of the Objects an error? - */ -int arrayObjectIsError(Objects *args) -{ - for (size_t i = 0; i < args->dim; i++) - { - Object *o = args->tdata()[i]; - if (isError(o)) - return 1; - } - return 0; -} - -/*********************** - * 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 *u1 = isTuple(o1); - Tuple *u2 = isTuple(o2); - - //printf("\t match t1 %p t2 %p, e1 %p e2 %p, s1 %p s2 %p, u1 %p u2 %p\n", t1,t2,e1,e2,s1,s2,u1,u2); - - /* 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 (s1) - { - VarDeclaration *v1 = s1->isVarDeclaration(); - if (v1 && v1->storage_class & STCmanifest) - { ExpInitializer *ei1 = v1->init->isExpInitializer(); - if (ei1) - e1 = ei1->exp, s1 = NULL; - } - } - if (s2) - { - VarDeclaration *v2 = s2->isVarDeclaration(); - if (v2 && v2->storage_class & STCmanifest) - { ExpInitializer *ei2 = v2->init->isExpInitializer(); - if (ei2) - e2 = ei2->exp, s2 = NULL; - } - } - - 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 - } - } - } - } - - //printf("t1 = %s\n", t1->toChars()); - //printf("t2 = %s\n", t2->toChars()); - if (!t2 || !t1->equals(t2)) - goto Lnomatch; - } - else if (e1) - { -#if 0 - if (e1 && e2) - { - printf("match %d\n", e1->equals(e2)); - e1->print(); - e2->print(); - e1->type->print(); - e2->type->print(); - } -#endif - if (!e2) - goto Lnomatch; - if (!e1->equals(e2)) - goto Lnomatch; - } - else if (s1) - { - if (!s2 || !s1->equals(s2) || s1->parent != s2->parent) - goto Lnomatch; - } - else if (u1) - { - if (!u2) - goto Lnomatch; - if (u1->objects.dim != u2->objects.dim) - goto Lnomatch; - for (size_t i = 0; i < u1->objects.dim; i++) - { - if (!match(u1->objects.tdata()[i], - u2->objects.tdata()[i], - tempdecl, sc)) - goto Lnomatch; - } - } - //printf("match\n"); - return 1; // match - -Lnomatch: - //printf("nomatch\n"); - return 0; // nomatch; -} - - -/************************************ - * Match an array of them. - */ -int arrayObjectMatch(Objects *oa1, Objects *oa2, TemplateDeclaration *tempdecl, Scope *sc) -{ - if (oa1 == oa2) - return 1; - if (oa1->dim != oa2->dim) - return 0; - for (size_t j = 0; j < oa1->dim; j++) - { Object *o1 = oa1->tdata()[j]; - Object *o2 = oa2->tdata()[j]; - if (!match(o1, o2, tempdecl, sc)) - { - return 0; - } - } - return 1; -} - -/**************************************** - * This makes a 'pretty' version of the template arguments. - * It's analogous to genIdent() which makes a mangled version. - */ - -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); - /* The logic of this should match what genIdent() does. The _dynamic_cast() - * function relies on all the pretty strings to be unique for different classes - * (see Bugzilla 7375). - * Perhaps it would be better to demangle what genIdent() does. - */ - if (t) - { //printf("\tt: %s ty = %d\n", t->toChars(), t->ty); - t->toCBuffer(buf, NULL, hgs); - } - else if (e) - { - if (e->op == TOKvar) - e = e->optimize(WANTvalue); // added to fix Bugzilla 7375 - 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 = (*args)[i]; - ObjectToCBuffer(buf, hgs, o); - } - } - else if (!oarg) - { - buf->writestring("NULL"); - } - else - { -#ifdef DEBUG - printf("bad Object = %p\n", oarg); -#endif - assert(0); - } -} - -#if DMDV2 -Object *objectSyntaxCopy(Object *o) -{ - if (!o) - return NULL; - Type *t = isType(o); - if (t) - return t->syntaxCopy(); - Expression *e = isExpression(o); - if (e) - return e->syntaxCopy(); - return o; -} -#endif - - -/* ======================== TemplateDeclaration ============================= */ - -TemplateDeclaration::TemplateDeclaration(Loc loc, Identifier *id, - TemplateParameters *parameters, Expression *constraint, Dsymbols *decldefs, int ismixin) - : 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 = parameters->tdata()[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->constraint = constraint; - this->members = decldefs; - this->overnext = NULL; - this->overroot = NULL; - this->semanticRun = 0; - this->onemember = NULL; - this->literal = 0; - this->ismixin = ismixin; - this->previous = NULL; - - // Compute in advance for Ddoc's use - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - onemember = s; - s->parent = this; - } - } -} - -Dsymbol *TemplateDeclaration::syntaxCopy(Dsymbol *) -{ - //printf("TemplateDeclaration::syntaxCopy()\n"); - TemplateDeclaration *td; - TemplateParameters *p; - - p = NULL; - if (parameters) - { - p = new TemplateParameters(); - p->setDim(parameters->dim); - for (size_t i = 0; i < p->dim; i++) - { TemplateParameter *tp = (*parameters)[i]; - p->tdata()[i] = tp->syntaxCopy(); - } - } - Expression *e = NULL; - if (constraint) - e = constraint->syntaxCopy(); - Dsymbols *d = Dsymbol::arraySyntaxCopy(members); - td = new TemplateDeclaration(loc, ident, p, e, d, ismixin); - -#if IN_LLVM - td->intrinsicName = intrinsicName; -#endif - - return td; -} - -void TemplateDeclaration::semantic(Scope *sc) -{ -#if LOG - printf("TemplateDeclaration::semantic(this = %p, id = '%s')\n", this, ident->toChars()); - printf("sc->stc = %llx\n", sc->stc); - printf("sc->module = %s\n", sc->module->toChars()); -#endif - if (semanticRun) - return; // semantic() already run - semanticRun = 1; - - if (sc->module && sc->module->ident == Id::object && ident == Id::AssociativeArray) - { Type::associativearray = this; - } - - if (sc->func) - { -#if DMDV1 - error("cannot declare template at function scope %s", sc->func->toChars()); -#endif - } - - if (/*global.params.useArrayBounds &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleArray(); - } - - if (/*global.params.useAssert &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - //sc->module->toModuleAssert(); - } - -#if DMDV2 - if (/*global.params.useUnitTests &&*/ sc->module) - { - // Generate this function as it may be used - // when template is instantiated in other modules - // FIXME: LDC - // sc->module->toModuleUnittest(); - } -#endif - - /* 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; - paramscope->stc = 0; - - if (!parent) - parent = sc->parent; - - if (global.params.doDocComments) - { - origParameters = new TemplateParameters(); - origParameters->setDim(parameters->dim); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - origParameters->tdata()[i] = tp->syntaxCopy(); - } - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - tp->declareParameter(paramscope); - } - - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - tp->semantic(paramscope); - if (i + 1 != parameters->dim && tp->isTemplateTupleParameter()) - error("template tuple parameter must be last one"); - } - - paramscope->pop(); - - // Compute again - onemember = NULL; - if (members) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, ident) && s) - { - 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 (size_t i = 0; i < f->parameters->dim; i++) - { TemplateParameter *p1 = f->parameters->tdata()[i]; - TemplateParameter *p2 = f2->parameters->tdata()[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; -} - -/**************************** - * Declare all the function parameters as variables - * and add them to the scope - */ -void TemplateDeclaration::makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs) -{ - /* We do this ONLY if there is only one function in the template. - */ - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - if (fd) - { - /* - Making parameters is similar to FuncDeclaration::semantic3 - */ - paramscope->parent = fd; - - TypeFunction *tf = (TypeFunction *)fd->type->syntaxCopy(); - - // Shouldn't run semantic on default arguments and return type. - for (int i = 0; iparameters->dim; i++) - tf->parameters->tdata()[i]->defaultArg = NULL; - tf->next = NULL; - - // Resolve parameter types and 'auto ref's. - tf->fargs = fargs; - tf = (TypeFunction *)tf->semantic(loc, paramscope); - - Parameters *fparameters = tf->parameters; - int fvarargs = tf->varargs; - - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(fparameters, i); - // Remove addMod same as func.d L1065 of FuncDeclaration::semantic3 - //Type *vtype = fparam->type; - //if (fd->type && fd->isPure()) - // vtype = vtype->addMod(MODconst); - fparam->storageClass &= (STCin | STCout | STCref | STClazy | STCfinal | STC_TYPECTOR | STCnodtor); - fparam->storageClass |= STCparameter; - if (fvarargs == 2 && i + 1 == nfparams) - fparam->storageClass |= STCvariadic; - } - for (size_t i = 0; i < fparameters->dim; i++) - { - Parameter *fparam = fparameters->tdata()[i]; - if (!fparam->ident) - continue; // don't add it, if it has no name - VarDeclaration *v = new VarDeclaration(loc, fparam->type, fparam->ident, NULL); - v->storage_class = fparam->storageClass; - v->semantic(paramscope); - if (!paramscope->insert(v)) - error("parameter %s.%s is already defined", toChars(), v->toChars()); - else - v->parent = this; - } - } -} - -/*************************************** - * Given that ti is an instance of this TemplateDeclaration, - * deduce the types of the parameters to this, and store - * those deduced types in dedtypes[]. - * Input: - * flag 1: don't do semantic() because of dummy types - * 2: don't change types in matchArg() - * Output: - * dedtypes deduced arguments - * Return match level. - */ - -MATCH TemplateDeclaration::matchWithInstance(TemplateInstance *ti, - Objects *dedtypes, Expressions *fargs, int flag) -{ MATCH m; - size_t 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->tdata()[0]); -#endif - dedtypes->zero(); - - size_t 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); - paramscope->stc = 0; - - // Attempt type deduction - m = MATCHexact; - for (size_t i = 0; i < dedtypes_dim; i++) - { MATCH m2; - TemplateParameter *tp = parameters->tdata()[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 (size_t i = 0; i < dedtypes_dim; i++) - { - if (!dedtypes->tdata()[i]) - { assert(i < ti->tiargs->dim); - dedtypes->tdata()[i] = (Type *)ti->tiargs->tdata()[i]; - } - } - } - -#if DMDV2 - if (m && constraint && !flag) - { /* Check to see if constraint is satisfied. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - Scope *sc = paramscope->push(); - - /* There's a chicken-and-egg problem here. We don't know yet if this template - * instantiation will be a local one (isnested is set), and we won't know until - * after selecting the correct template. Thus, function we're nesting inside - * is not on the sc scope chain, and this can cause errors in FuncDeclaration::getLevel(). - * Workaround the problem by setting a flag to relax the checking on frame errors. - */ - sc->flags |= SCOPEstaticif; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(sc); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - sc->pop(); - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if LOGM - // Print out the results - printf("--------------------------\n"); - printf("template %s\n", toChars()); - printf("instance %s\n", ti->toChars()); - if (m) - { - for (size_t i = 0; i < dedtypes_dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - Object *oarg; - - printf(" [%d]", i); - - if (i < ti->tiargs->dim) - oarg = ti->tiargs->tdata()[i]; - else - oarg = NULL; - tp->print(oarg, dedtypes->tdata()[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: - * match this is at least as specialized as td2 - * 0 td2 is more specialized than this - */ - -MATCH TemplateDeclaration::leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs) -{ - /* 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 (size_t i = 0; i < ti.tiargs->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - - Object *p = (Object *)tp->dummyArg(); - if (p) - ti.tiargs->tdata()[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 - MATCH m = td2->matchWithInstance(&ti, &dedtypes, fargs, 1); - if (m) - { - /* A non-variadic template is more specialized than a - * variadic one. - */ - if (isVariadic() && !td2->isVariadic()) - goto L1; - -#if LOG_LEASTAS - printf(" matches %d, so is least as specialized\n", m); -#endif - return m; - } - L1: -#if LOG_LEASTAS - printf(" doesn't match, so is not as specialized\n"); -#endif - return MATCHnomatch; -} - - -/************************************************* - * Match function arguments against a specific template function. - * Input: - * loc instantiation location - * targsi Expression/Type initial list of template arguments - * ethis 'this' argument if !NULL - * fargs arguments to function - * Output: - * dedargs Expression/Type deduced template arguments - * Returns: - * match level - */ - -MATCH TemplateDeclaration::deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, - Expression *ethis, Expressions *fargs, - Objects *dedargs) -{ - 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(); - Parameters *fparameters; // function parameter list - int fvarargs; // function varargs - Objects dedtypes; // for T:T*, the dedargs is the T*, dedtypes is the T - unsigned wildmatch = 0; - - TypeFunction *tf = (TypeFunction *)fd->type; - -#if 0 - printf("\nTemplateDeclaration::deduceFunctionTemplateMatch() %s\n", toChars()); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *e = fargs->tdata()[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e->toChars(), e->type->toChars()); - } - printf("fd = %s\n", fd->toChars()); - printf("fd->type = %s\n", fd->type->toChars()); - if (ethis) - printf("ethis->type = %s\n", ethis->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); - paramscope->stc = 0; - - TemplateTupleParameter *tp = isVariadic(); - int tp_is_declared = 0; - -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - - nargsi = 0; - if (targsi) - { // Set initial template arguments - - nargsi = targsi->dim; - size_t n = parameters->dim; - if (tp) - n--; - if (nargsi > n) - { if (!tp) - goto Lnomatch; - - /* The extra initial template arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - assert(parameters->dim); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nargsi - n; - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { - t->objects.tdata()[i] = targsi->tdata()[n + i]; - } - declareParameter(paramscope, tp, t); - tp_is_declared = 1; - } - else - n = nargsi; - - memcpy(dedargs->tdata(), targsi->tdata(), n * sizeof(*dedargs->tdata())); - - for (size_t i = 0; i < n; i++) - { assert(i < parameters->dim); - TemplateParameter *tp = parameters->tdata()[i]; - MATCH m; - Declaration *sparam = NULL; - - m = tp->matchArg(paramscope, dedargs, i, parameters, &dedtypes, &sparam); - //printf("\tdeduceType m = %d\n", m); - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - sparam->semantic(paramscope); - if (!paramscope->insert(sparam)) - goto Lnomatch; - } - } -#if 0 - for (size_t i = 0; i < dedargs->dim; i++) - { - printf("\tdedarg[%d] = ", i); - Object *oarg = dedargs->tdata()[i]; - if (oarg) printf("%s", oarg->toChars()); - printf("\n"); - } -#endif - - fparameters = fd->getParameters(&fvarargs); - nfparams = Parameter::dim(fparameters); // number of function parameters - nfargs = fargs ? fargs->dim : 0; // number of function arguments - - /* Check for match of function arguments with variadic template - * parameter, such as: - * - * template Foo(T, A...) { void Foo(T t, A a); } - * void main() { Foo(1,2,3); } - */ - if (tp) // if variadic - { - if (nfparams == 0 && nfargs != 0) // if no function parameters - { - if (tp_is_declared) - goto L2; - Tuple *t = new Tuple(); - //printf("t = %p\n", t); - dedargs->tdata()[parameters->dim - 1] = t; - declareParameter(paramscope, tp, t); - goto L2; - } - else if (nfargs < nfparams - 1) - goto L1; - else - { - /* Figure out which of the function parameters matches - * the tuple template parameter. Do this by matching - * type identifiers. - * Set the index of this function parameter to fptupindex. - */ - for (fptupindex = 0; fptupindex < nfparams; fptupindex++) - { - Parameter *fparam = fparameters->tdata()[fptupindex]; - if (fparam->type->ty != Tident) - continue; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (!tp->ident->equals(tid->ident) || tid->idents.dim) - continue; - - if (fvarargs) // variadic function doesn't - goto Lnomatch; // go with variadic template - - if (tp_is_declared) - goto L2; - - // Apply function parameter storage classes to parameter type - tid = (TypeIdentifier *)tid->addStorageClass(fparam->storageClass); - - /* The types of the function arguments - * now form the tuple argument. - */ - Tuple *t = new Tuple(); - dedargs->tdata()[parameters->dim - 1] = t; - - tuple_dim = nfargs - (nfparams - 1); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Expression *farg = fargs->tdata()[fptupindex + i]; - unsigned mod = farg->type->mod; - Type *tt; - MATCH m; - - #define X(U,T) ((U) << 4) | (T) - if (tid->mod & MODwild) - { - switch (X(tid->mod, mod)) - { - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - - if (mod & MODwild) - wildmatch |= MODwild; - else if (mod == 0) - wildmatch |= MODmutable; - else - wildmatch |= (mod & ~MODshared); - tt = farg->type->mutableOf(); - m = MATCHconst; - goto Lx; - - default: - break; - } - } - - switch (X(tid->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - - tt = farg->type; - m = MATCHexact; - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - - tt = farg->type->mutableOf()->unSharedOf(); - m = MATCHexact; - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - - tt = farg->type->mutableOf(); - m = MATCHconst; - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = farg->type->unSharedOf(); - m = MATCHconst; - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODconst, MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - m = MATCHnomatch; - break; - - default: - assert(0); - } - #undef X - - Lx: - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - - t->objects.tdata()[i] = tt; - } - declareParameter(paramscope, tp, t); - goto L2; - } - fptupindex = -1; - } - } - -L1: - if (nfparams == nfargs) - ; - else if (nfargs > nfparams) - { - if (fvarargs == 0) - goto Lnomatch; // too many args, no match - match = MATCHconvert; // match ... with a conversion - } - -L2: -#if DMDV2 - if (ethis) - { - // Match 'ethis' to any TemplateThisParameter's - for (size_t i = 0; i < parameters->dim; i++) - { TemplateParameter *tp = parameters->tdata()[i]; - TemplateThisParameter *ttp = tp->isTemplateThisParameter(); - if (ttp) - { MATCH m; - - Type *t = new TypeIdentifier(0, ttp->ident); - m = ethis->type->deduceType(paramscope, t, parameters, &dedtypes); - if (!m) - goto Lnomatch; - if (m < match) - match = m; // pick worst match - } - } - - // Match attributes of ethis against attributes of fd - if (fd->type) - { - Type *tthis = ethis->type; - unsigned mod = fd->type->mod; - StorageClass stc = scope->stc | fd->storage_class2; - // Propagate parent storage class (see bug 5504) - Dsymbol *p = parent; - while (p->isTemplateDeclaration() || p->isTemplateInstance()) - p = p->parent; - AggregateDeclaration *ad = p->isAggregateDeclaration(); - if (ad) - stc |= ad->storage_class; - - if (stc & (STCshared | STCsynchronized)) - mod |= MODshared; - if (stc & STCimmutable) - mod |= MODimmutable; - if (stc & STCconst) - mod |= MODconst; - if (stc & STCwild) - mod |= MODwild; - // Fix mod - if (mod & MODimmutable) - mod = MODimmutable; - if (mod & MODconst) - mod &= ~STCwild; - if (tthis->mod != mod) - { - if (!MODmethodConv(tthis->mod, mod)) - goto Lnomatch; - if (MATCHconst < match) - match = MATCHconst; - } - } - } -#endif - - // Loop through the function parameters - for (size_t parami = 0; parami < nfparams; parami++) - { - /* Skip over function parameters which wound up - * as part of a template tuple parameter. - */ - if (parami == fptupindex) - continue; - /* Set i = index into function arguments - * Function parameters correspond to function arguments as follows. - * Note that tuple_dim may be zero, and there may be default or - * variadic arguments at the end. - * arg [0..fptupindex] == param[0..fptupindex] - * arg [fptupindex..fptupindex+tuple_dim] == param[fptupindex] - * arg[fputupindex+dim.. ] == param[fptupindex+1.. ] - */ - size_t i = parami; - if (fptupindex >= 0 && parami > fptupindex) - i += tuple_dim - 1; - - Parameter *fparam = Parameter::getNth(fparameters, parami); - - if (i >= nfargs) // if not enough arguments - { - if (fparam->defaultArg) - { /* Default arguments do not participate in template argument - * deduction. - */ - goto Lmatch; - } - } - else - { - Expression *farg = fargs->tdata()[i]; -Lretry: -#if 0 - printf("\tfarg->type = %s\n", farg->type->toChars()); - printf("\tfparam->type = %s\n", fparam->type->toChars()); -#endif - Type *argtype = farg->type; - - // Apply function parameter storage classes to parameter types - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - -#if DMDV2 - /* Allow string literals which are type [] to match with [dim] - */ - if (farg->op == TOKstring) - { StringExp *se = (StringExp *)farg; - if (!se->committed && argtype->ty == Tarray && - fparam->type->toBasetype()->ty == Tsarray) - { - argtype = new TypeSArray(argtype->nextOf(), new IntegerExp(se->loc, se->len, Type::tindex)); - argtype = argtype->semantic(se->loc, NULL); - argtype = argtype->invariantOf(); - } - } - - /* Allow implicit function literals to delegate conversion - */ - if (farg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)farg; - Type *tp = fparam->type; - if (tp->ty == Tdelegate && - fe->type->ty == Tpointer && fe->type->nextOf()->ty == Tfunction && - fe->tok == TOKreserved) - { Type *tdg = new TypeDelegate(fe->type->nextOf()); - tdg = tdg->semantic(loc, sc); - farg = fe->inferType(sc, tdg); - } - else if (fe->type == Type::tvoid) - { - farg = fe->inferType(sc, tp); - if (!farg) - goto Lvarargs; - } - argtype = farg->type; - } - - /* Remove top const for dynamic array types and pointer types - */ - if ((argtype->ty == Tarray || argtype->ty == Tpointer) && - !argtype->isMutable() && - (!(fparam->storageClass & STCref) || - (fparam->storageClass & STCauto) && !farg->isLvalue())) - { - argtype = argtype->mutableOf(); - } -#endif - - if (fvarargs == 2 && i + 1 == nfparams && i + 1 < nfargs) - goto Lvarargs; - - MATCH m; - m = argtype->deduceType(paramscope, fparam->type, parameters, &dedtypes, - tf->hasWild() ? &wildmatch : NULL); - //printf("\tdeduceType m = %d\n", m); - //if (tf->hasWild()) - // printf("\twildmatch = x%x m = %d\n", wildmatch, m); - - /* If no match, see if there's a conversion to a delegate - */ - if (!m) - { Type *tbp = fparam->type->toBasetype(); - Type *tba = farg->type->toBasetype(); - AggregateDeclaration *ad; - if (tbp->ty == Tdelegate) - { - TypeDelegate *td = (TypeDelegate *)fparam->type->toBasetype(); - TypeFunction *tf = (TypeFunction *)td->next; - - if (!tf->varargs && Parameter::dim(tf->parameters) == 0) - { - m = farg->type->deduceType(paramscope, tf->next, parameters, &dedtypes); - if (!m && tf->next->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - //printf("\tm2 = %d\n", m); - } - else if (tba->ty == Tclass) - { - ad = ((TypeClass *)tba)->sym; - goto Lad; - } - else if (tba->ty == Tstruct) - { - ad = ((TypeStruct *)tba)->sym; - Lad: - if (ad->aliasthis) - { /* If a semantic error occurs while doing alias this, - * eg purity(bug 7295), just regard it as not a match. - */ - unsigned olderrors = global.startGagging(); - Expression *e = new DotIdExp(farg->loc, farg, ad->aliasthis->ident); - e = e->semantic(sc); - e = resolveProperties(sc, e); - if (!global.endGagging(olderrors)) - { farg = e; - goto Lretry; - } - } - } - } - - if (m && (fparam->storageClass & (STCref | STCauto)) == STCref) - { if (!farg->isLvalue()) - goto Lnomatch; - } - if (m && (fparam->storageClass & STCout)) - { if (!farg->isLvalue()) - goto Lnomatch; - } - if (!m && (fparam->storageClass & STClazy) && fparam->type->ty == Tvoid && - farg->type->ty != Tvoid) - m = MATCHconvert; - - if (m) - { if (m < match) - match = m; // pick worst match - continue; - } - } - - Lvarargs: - /* The following code for variadic arguments closely - * matches TypeFunction::callMatch() - */ - if (!(fvarargs == 2 && i + 1 == nfparams)) - goto Lnomatch; - - /* Check for match with function parameter T... - */ - Type *tb = fparam->type->toBasetype(); - switch (tb->ty) - { - // Perhaps we can do better with this, see TypeFunction::callMatch() - case Tsarray: - { TypeSArray *tsa = (TypeSArray *)tb; - dinteger_t sz = tsa->dim->toInteger(); - if (sz != nfargs - i) - goto Lnomatch; - } - case Tarray: - { TypeArray *ta = (TypeArray *)tb; - for (; i < nfargs; i++) - { - Expression *arg = fargs->tdata()[i]; - assert(arg); - - if (arg->op == TOKfunction) - { FuncExp *fe = (FuncExp *)arg; - Type *tp = tb->nextOf(); - if (tp->ty == Tdelegate && - fe->type->ty == Tpointer && fe->type->nextOf()->ty == Tfunction && - fe->tok == TOKreserved) - { tp = new TypeDelegate(fe->type->nextOf()); - tp = tp->semantic(loc, sc); - arg = fe->inferType(sc, tp); - } - else if (arg->type == Type::tvoid) - { - arg = fe->inferType(sc, tp); - if (!arg) - goto Lnomatch; - } - } - - MATCH m; - /* If lazy array of delegates, - * convert arg(s) to delegate(s) - */ - Type *tret = fparam->isLazyArray(); - if (tret) - { - if (ta->next->equals(arg->type)) - { m = MATCHexact; - } - else - { - m = arg->implicitConvTo(tret); - if (m == MATCHnomatch) - { - if (tret->toBasetype()->ty == Tvoid) - m = MATCHconvert; - } - } - } - else - { - m = arg->type->deduceType(paramscope, ta->next, parameters, &dedtypes); - //m = arg->implicitConvTo(ta->next); - } - if (m == MATCHnomatch) - goto Lnomatch; - if (m < match) - match = m; - } - goto Lmatch; - } - case Tclass: - case Tident: - goto Lmatch; - - default: - goto Lnomatch; - } - } - -Lmatch: - - for (size_t i = nargsi; i < dedargs->dim; i++) - { - TemplateParameter *tparam = parameters->tdata()[i]; - //printf("tparam[%d] = %s\n", i, tparam->ident->toChars()); - /* For T:T*, the dedargs is the T*, dedtypes is the T - * But for function templates, we really need them to match - */ - Object *oarg = dedargs->tdata()[i]; - Object *oded = dedtypes.tdata()[i]; - //printf("1dedargs[%d] = %p, dedtypes[%d] = %p\n", i, oarg, i, oded); - //if (oarg) printf("oarg: %s\n", oarg->toChars()); - //if (oded) printf("oded: %s\n", oded->toChars()); - if (!oarg) - { - if (oded) - { - if (tparam->specialization()) - { /* The specialization can work as long as afterwards - * the oded == oarg - */ - Declaration *sparam; - dedargs->tdata()[i] = oded; - MATCH m2 = tparam->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.tdata()[i] != oded) - error("specialization not allowed for deduced parameter %s", tparam->ident->toChars()); - } - } - else - { oded = tparam->defaultArg(loc, paramscope); - if (!oded) - { - if (tp && // if tuple parameter and - fptupindex < 0 && // tuple parameter was not in function parameter list and - nargsi == dedargs->dim - 1) // we're one argument short (i.e. no tuple argument) - { // make tuple argument an empty tuple - oded = (Object *)new Tuple(); - } - else - goto Lnomatch; - } - } - declareParameter(paramscope, tparam, oded); - dedargs->tdata()[i] = oded; - } - } - -#if DMDV2 - if (constraint) - { /* Check to see if constraint is satisfied. - * Most of this code appears twice; this is a good candidate for refactoring. - */ - makeParamNamesVisibleInConstraint(paramscope, fargs); - Expression *e = constraint->syntaxCopy(); - paramscope->ignoreTemplates++; - paramscope->flags |= SCOPEstaticif; - - /* Detect recursive attempts to instantiate this template declaration, - * Bugzilla 4072 - * void foo(T)(T x) if (is(typeof(foo(x)))) { } - * static assert(!is(typeof(foo(7)))); - * Recursive attempts are regarded as a constraint failure. - */ - int nmatches = 0; - for (Previous *p = previous; p; p = p->prev) - { - if (arrayObjectMatch(p->dedargs, dedargs, this, sc)) - { - //printf("recursive, no match p->sc=%p %p %s\n", p->sc, this, this->toChars()); - /* It must be a subscope of p->sc, other scope chains are not recursive - * instantiations. - */ - for (Scope *scx = sc; scx; scx = scx->enclosing) - { - if (scx == p->sc) - goto Lnomatch; - } - } - /* BUG: should also check for ref param differences - */ - } - - Previous pr; - pr.prev = previous; - pr.sc = paramscope; - pr.dedargs = dedargs; - previous = ≺ // add this to threaded list - - int nerrors = global.errors; - - FuncDeclaration *fd = onemember && onemember->toAlias() ? - onemember->toAlias()->isFuncDeclaration() : NULL; - Dsymbol *s = parent; - while (s->isTemplateInstance() || s->isTemplateMixin()) - s = s->parent; - AggregateDeclaration *ad = s->isAggregateDeclaration(); - VarDeclaration *vthissave; - if (fd && ad) - { - vthissave = fd->vthis; - fd->vthis = fd->declareThis(paramscope, ad); - } - - e = e->semantic(paramscope); - - if (fd && fd->vthis) - fd->vthis = vthissave; - - previous = pr.prev; // unlink from threaded list - - if (nerrors != global.errors) // if any errors from evaluating the constraint, no match - goto Lnomatch; - - e = e->optimize(WANTvalue | WANTinterpret); - if (e->isBool(TRUE)) - ; - else if (e->isBool(FALSE)) - goto Lnomatch; - else - { - e->error("constraint %s is not constant or does not evaluate to a bool", e->toChars()); - } - } -#endif - -#if 0 - for (i = 0; i < dedargs->dim; i++) - { Type *t = dedargs->tdata()[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, and install it in the scope sc. - */ - -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; - - // See if tp->ident already exists with a matching definition - Dsymbol *scopesym; - s = sc->search(loc, tp->ident, &scopesym); - if (s && scopesym == sc->scopesym) - { - TupleDeclaration *td = s->isTupleDeclaration(); - if (va && td) - { Tuple tup; - tup.objects = *td->objects; - if (match(va, &tup, this, sc)) - { - return; - } - } - } - - 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(); - - Type *t = tvp ? tvp->valType : NULL; - - VarDeclaration *v = new VarDeclaration(loc, t, tp->ident, init); - v->storage_class = STCmanifest; - s = v; - } - else if (va) - { - //printf("\ttuple\n"); - s = new TupleDeclaration(loc, tp->ident, &va->objects); - } - 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 = (parameters->tdata()[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 - * ethis if !NULL, the 'this' pointer argument - * fargs arguments to function - * flags 1: do not issue error message on no match, just return NULL - */ - -FuncDeclaration *TemplateDeclaration::deduceFunctionTemplate(Scope *sc, Loc loc, - Objects *targsi, Expression *ethis, Expressions *fargs, int flags) -{ - MATCH m_best = MATCHnomatch; - TemplateDeclaration *td_ambig = NULL; - TemplateDeclaration *td_best = NULL; - Objects *tdargs = new Objects(); - TemplateInstance *ti; - FuncDeclaration *fd_best; - -#if 0 - printf("TemplateDeclaration::deduceFunctionTemplate() %s\n", toChars()); - printf(" targsi:\n"); - if (targsi) - { for (size_t i = 0; i < targsi->dim; i++) - { Object *arg = targsi->tdata()[i]; - printf("\t%s\n", arg->toChars()); - } - } - printf(" fargs:\n"); - for (size_t i = 0; i < fargs->dim; i++) - { Expression *arg = fargs->tdata()[i]; - printf("\t%s %s\n", arg->type->toChars(), arg->toChars()); - //printf("\tty = %d\n", arg->type->ty); - } - printf("stc = %llx\n", scope->stc); -#endif - - for (TemplateDeclaration *td = this; td; td = td->overnext) - { - if (!td->semanticRun) - { - error("forward reference to template %s", td->toChars()); - goto Lerror; - } - if (!td->onemember || !td->onemember->toAlias()->isFuncDeclaration()) - { - error("is not a function template"); - goto Lerror; - } - - MATCH m; - Objects dedargs; - FuncDeclaration *fd = NULL; - - m = td->deduceFunctionTemplateMatch(sc, loc, targsi, ethis, fargs, &dedargs); - //printf("deduceFunctionTemplateMatch = %d\n", m); - if (!m) // if no match - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //printf("1: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - else if (c1 < c2) - goto Ltd_best; - } - - if (!fd_best) - { - fd_best = td_best->doHeaderInstantiation(sc, tdargs, fargs); - if (!fd_best) - goto Lerror; - } - { - tdargs->setDim(dedargs.dim); - memcpy(tdargs->data, dedargs.data, tdargs->dim * sizeof(void *)); - fd = td->doHeaderInstantiation(sc, tdargs, fargs); - if (!fd) - goto Lerror; - } - assert(fd && fd_best); - - { - // Disambiguate by tf->callMatch - TypeFunction *tf1 = (TypeFunction *)fd->type; - TypeFunction *tf2 = (TypeFunction *)fd_best->type; - MATCH c1 = (MATCH) tf1->callMatch(fd->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - MATCH c2 = (MATCH) tf2->callMatch(fd_best->needThis() && !fd->isCtorDeclaration() ? ethis : NULL, fargs); - //printf("2: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - { - // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd->leastAsSpecialized(fd_best); - MATCH c2 = fd_best->leastAsSpecialized(fd); - //printf("3: c1 = %d, c2 = %d\n", c1, c2); - - if (c1 > c2) - goto Ltd; - if (c1 < c2) - goto Ltd_best; - } - - 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; - fd_best = fd; - m_best = m; - tdargs->setDim(dedargs.dim); - memcpy(tdargs->tdata(), dedargs.tdata(), tdargs->dim * sizeof(void *)); - continue; - } - if (!td_best) - { - if (!(flags & 1)) - error(loc, "does not match any function template declaration"); - goto Lerror; - } - if (td_ambig) - { - error(loc, "%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best with arguments tdargs. - * Now instantiate the template. - */ - assert((size_t)td_best->scope > 0x10000); - ti = new TemplateInstance(loc, td_best, tdargs); - ti->semantic(sc, fargs); - fd_best = ti->toAlias()->isFuncDeclaration(); - if (!fd_best || !((TypeFunction*)fd_best->type)->callMatch(ethis, fargs, flags)) - goto Lerror; - return fd_best; - - Lerror: -#if DMDV2 - if (!(flags & 1)) -#endif - { - HdrGenState hgs; - - OutBuffer bufa; - Objects *args = targsi; - if (args) - { for (size_t i = 0; i < args->dim; i++) - { - if (i) - bufa.writeByte(','); - Object *oarg = args->tdata()[i]; - ObjectToCBuffer(&bufa, &hgs, oarg); - } - } - - OutBuffer buf; - argExpTypesToCBuffer(&buf, fargs, &hgs); - error(loc, "cannot deduce template function from argument types !(%s)(%s)", - bufa.toChars(), buf.toChars()); - } - return NULL; -} - -/************************************************* - * Limited function template instantiation for using fd->leastAsSpecialized() - */ -FuncDeclaration *TemplateDeclaration::doHeaderInstantiation(Scope *sc, - Objects *tdargs, Expressions *fargs) -{ - FuncDeclaration *fd = onemember->toAlias()->isFuncDeclaration(); - if (!fd) - return NULL; - -#if 0 - printf("doHeaderInstantiation this = %s\n", toChars()); - for (size_t i = 0; i < tdargs->dim; ++i) - printf("\ttdargs[%d] = %s\n", i, ((Object *)tdargs->data[i])->toChars()); -#endif - - assert((size_t)scope > 0x10000); - TemplateInstance *ti = new TemplateInstance(loc, this, tdargs); - ti->tinst = sc->tinst; - { - ti->tdtypes.setDim(ti->tempdecl->parameters->dim); - if (!ti->tempdecl->matchWithInstance(ti, &ti->tdtypes, fargs, 2)) - return NULL; - } - - ti->parent = parent; - - // function body and contracts are not need - //fd = fd->syntaxCopy(NULL)->isFuncDeclaration(); - fd = new FuncDeclaration(fd->loc, fd->endloc, fd->ident, fd->storage_class, fd->type->syntaxCopy()); - fd->parent = ti; - - Scope *scope = this->scope; - - ti->argsym = new ScopeDsymbol(); - ti->argsym->parent = scope->parent; - scope = scope->push(ti->argsym); - - Scope *paramscope = scope->push(); - paramscope->stc = 0; - ti->declareParameters(paramscope); - paramscope->pop(); - - { - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - - Scope *sc2; - sc2 = scope->push(ti); - sc2->parent = /*isnested ? sc->parent :*/ ti; - sc2->tinst = ti; - - { - Scope *sc = sc2; - sc = sc->push(); - - if (fd->isCtorDeclaration()) - sc->flags |= SCOPEctor; - fd->type = fd->type->semantic(fd->loc, sc); - sc = sc->pop(); - } - //printf("\t[%s] fd->type = %s, mod = %x, ", loc.toChars(), fd->type->toChars(), fd->type->mod); - //printf("fd->needThis() = %d\n", fd->needThis()); - - sc2->pop(); - scope->pop(); - - return fd; -} - -bool TemplateDeclaration::hasStaticCtorOrDtor() -{ - return FALSE; // don't scan uninstantiated templates -} - -void TemplateDeclaration::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ -#if 0 // Should handle template functions for doc generation - if (onemember && onemember->isFuncDeclaration()) - buf->writestring("foo "); -#endif - if (hgs->ddoc) - buf->writestring(kind()); - else - buf->writestring("template"); - buf->writeByte(' '); - buf->writestring(ident->toChars()); - buf->writeByte('('); - for (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (hgs->ddoc) - tp = origParameters->tdata()[i]; - if (i) - buf->writeByte(','); - tp->toCBuffer(buf, hgs); - } - buf->writeByte(')'); -#if DMDV2 - if (constraint) - { buf->writestring(" if ("); - constraint->toCBuffer(buf, hgs); - buf->writeByte(')'); - } -#endif - - if (hgs->hdrgen) - { - hgs->tpltMember++; - buf->writenl(); - buf->writebyte('{'); - buf->writenl(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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 (size_t i = 0; i < parameters->dim; i++) - { - TemplateParameter *tp = parameters->tdata()[i]; - if (i) - buf.writeByte(','); - tp->toCBuffer(&buf, &hgs); - } - buf.writeByte(')'); -#if DMDV2 - if (constraint) - { buf.writestring(" if ("); - constraint->toCBuffer(&buf, &hgs); - buf.writeByte(')'); - } -#endif - 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 = parameters->tdata()[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, unsigned *wildmatch) -{ -#if 0 - printf("Type::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - 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 = parameters->tdata()[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, wildmatch); - } - - TemplateParameter *tp = parameters->tdata()[i]; - - // Found the corresponding parameter tp - if (!tp->isTemplateTypeParameter()) - goto Lnomatch; - Type *tt = this; - Type *at = (Type *)dedtypes->tdata()[i]; - - // 7*7 == 49 cases - - #define X(U,T) ((U) << 4) | (T) - - if (wildmatch && (tparam->mod & MODwild)) - { - switch (X(tparam->mod, mod)) - { - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - - if (!at) - { - if (mod & MODwild) - *wildmatch |= MODwild; - else if (mod == 0) - *wildmatch |= MODmutable; - else - *wildmatch |= (mod & ~MODshared); - tt = mutableOf(); - dedtypes->tdata()[i] = tt; - goto Lconst; - } - - //printf("\t> tt = %s, at = %s\n", tt->toChars(), at->toChars()); - //printf("\t> tt->implicitConvTo(at->constOf()) = %d\n", tt->implicitConvTo(at->constOf())); - //printf("\t> at->implicitConvTo(tt->constOf()) = %d\n", at->implicitConvTo(tt->constOf())); - - if (tt->equals(at)) - { - goto Lconst; - } - else if (tt->implicitConvTo(at->constOf())) - { - dedtypes->tdata()[i] = at->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - else if (at->implicitConvTo(tt->constOf())) - { - dedtypes->tdata()[i] = tt->constOf()->mutableOf(); - *wildmatch |= MODconst; - goto Lconst; - } - goto Lnomatch; - - default: - break; - } - } - - switch (X(tparam->mod, mod)) - { - case X(0, 0): - case X(0, MODconst): - case X(0, MODimmutable): - case X(0, MODshared): - case X(0, MODconst | MODshared): - case X(0, MODwild): - case X(0, MODwild | MODshared): - // foo(U:U) T => T - // foo(U:U) const(T) => const(T) - // foo(U:U) immutable(T) => immutable(T) - // foo(U:U) shared(T) => shared(T) - // foo(U:U) const(shared(T)) => const(shared(T)) - // foo(U:U) wild(T) => wild(T) - // foo(U:U) wild(shared(T)) => wild(shared(T)) - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, MODconst): - case X(MODimmutable, MODimmutable): - case X(MODshared, MODshared): - case X(MODconst | MODshared, MODconst | MODshared): - case X(MODwild, MODwild): - case X(MODwild | MODshared, MODwild | MODshared): - // foo(U:const(U)) const(T) => T - // foo(U:immutable(U)) immutable(T) => T - // foo(U:shared(U)) shared(T) => T - // foo(U:const(shared(U)) const(shared(T)) => T - // foo(U:wild(U)) wild(T) => T - // foo(U:wild(shared(U)) wild(shared(T)) => T - tt = mutableOf()->unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lexact; - } - break; - - case X(MODconst, 0): - case X(MODconst, MODimmutable): - case X(MODconst, MODconst | MODshared): - case X(MODconst | MODshared, MODimmutable): - case X(MODconst, MODwild): - case X(MODconst, MODwild | MODshared): - // foo(U:const(U)) T => T - // foo(U:const(U)) immutable(T) => T - // foo(U:const(U)) const(shared(T)) => shared(T) - // foo(U:const(shared(U)) immutable(T) => T - // foo(U:const(U)) wild(shared(T)) => shared(T) - tt = mutableOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODshared, MODconst | MODshared): - case X(MODconst | MODshared, MODshared): - case X(MODshared, MODwild | MODshared): - // foo(U:shared(U)) const(shared(T)) => const(T) - // foo(U:const(shared(U)) shared(T) => T - // foo(U:shared(U)) wild(shared(T)) => wild(T) - tt = unSharedOf(); - if (!at) - { dedtypes->tdata()[i] = tt; - goto Lconst; - } - break; - - case X(MODimmutable, 0): - case X(MODimmutable, MODconst): - case X(MODimmutable, MODshared): - case X(MODimmutable, MODconst | MODshared): - case X(MODconst, MODshared): - case X(MODshared, 0): - case X(MODshared, MODconst): - case X(MODshared, MODimmutable): - case X(MODconst | MODshared, 0): - case X(MODconst | MODshared, MODconst): - case X(MODimmutable, MODwild): - case X(MODshared, MODwild): - case X(MODconst | MODshared, MODwild): - case X(MODwild, 0): - case X(MODwild, MODconst): - case X(MODwild, MODimmutable): - case X(MODwild, MODshared): - case X(MODwild, MODconst | MODshared): - case X(MODwild | MODshared, 0): - case X(MODwild | MODshared, MODconst): - case X(MODwild | MODshared, MODimmutable): - case X(MODwild | MODshared, MODshared): - case X(MODwild | MODshared, MODconst | MODshared): - case X(MODwild | MODshared, MODwild): - case X(MODimmutable, MODwild | MODshared): - case X(MODconst | MODshared, MODwild | MODshared): - case X(MODwild, MODwild | MODshared): - - // foo(U:immutable(U)) T => nomatch - // foo(U:immutable(U)) const(T) => nomatch - // foo(U:immutable(U)) shared(T) => nomatch - // foo(U:immutable(U)) const(shared(T)) => nomatch - // foo(U:const(U)) shared(T) => nomatch - // foo(U:shared(U)) T => nomatch - // foo(U:shared(U)) const(T) => nomatch - // foo(U:shared(U)) immutable(T) => nomatch - // foo(U:const(shared(U)) T => nomatch - // foo(U:const(shared(U)) const(T) => nomatch - // foo(U:immutable(U)) wild(T) => nomatch - // foo(U:shared(U)) wild(T) => nomatch - // foo(U:const(shared(U)) wild(T) => nomatch - // foo(U:wild(U)) T => nomatch - // foo(U:wild(U)) const(T) => nomatch - // foo(U:wild(U)) immutable(T) => nomatch - // foo(U:wild(U)) shared(T) => nomatch - // foo(U:wild(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) T => nomatch - // foo(U:wild(shared(U)) const(T) => nomatch - // foo(U:wild(shared(U)) immutable(T) => nomatch - // foo(U:wild(shared(U)) shared(T) => nomatch - // foo(U:wild(shared(U)) const(shared(T)) => nomatch - // foo(U:wild(shared(U)) wild(T) => nomatch - // foo(U:immutable(U)) wild(shared(T)) => nomatch - // foo(U:const(shared(U))) wild(shared(T)) => nomatch - // foo(U:wild(U)) wild(shared(T)) => nomatch - //if (!at) - goto Lnomatch; - break; - - default: - assert(0); - } - #undef X - - if (tt->equals(at)) - goto Lexact; - else if (tt->ty == Tclass && at->ty == Tclass) - { - return tt->implicitConvTo(at); - } - else if (tt->ty == Tsarray && at->ty == Tarray && - tt->nextOf()->implicitConvTo(at->nextOf()) >= MATCHconst) - { - goto Lexact; - } - else - goto Lnomatch; - } - else if (tparam->ty == Ttypeof) - { - /* Need a loc to go with the semantic routine. - */ - Loc loc; - if (parameters->dim) - { - TemplateParameter *tp = parameters->tdata()[0]; - loc = tp->loc; - } - - tparam = tparam->semantic(loc, sc); - } - - if (ty != tparam->ty) - { -#if DMDV2 - // Can't instantiate AssociativeArray!() without a scope - if (tparam->ty == Taarray && !((TypeAArray*)tparam)->sc) - ((TypeAArray*)tparam)->sc = sc; - - MATCH m = implicitConvTo(tparam); - if (m == MATCHnomatch) - { - Type *at = aliasthisOf(); - if (at) - m = at->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - } - return m; -#else - return implicitConvTo(tparam); -#endif - } - - if (nextOf()) - return nextOf()->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - -Lexact: - return MATCHexact; - -Lnomatch: - return MATCHnomatch; - -#if DMDV2 -Lconst: - return MATCHconst; -#endif -} - -#if DMDV2 -MATCH TypeDArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeDArray::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} -#endif - -MATCH TypeSArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#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 == Tarray) - { MATCH m; - - m = next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - if (m == MATCHexact) - m = MATCHconvert; - return m; - } - - Identifier *id = NULL; - if (tparam->ty == Tsarray) - { - TypeSArray *tp = (TypeSArray *)tparam; - if (tp->dim->op == TOKvar && - ((VarExp *)tp->dim)->var->storage_class & STCtemplateparameter) - { - id = ((VarExp *)tp->dim)->var->ident; - } - else if (dim->toInteger() != tp->dim->toInteger()) - return MATCHnomatch; - } - else if (tparam->ty == Taarray) - { - TypeAArray *tp = (TypeAArray *)tparam; - if (tp->index->ty == Tident && - ((TypeIdentifier *)tp->index)->idents.dim == 0) - { - id = ((TypeIdentifier *)tp->index)->ident; - } - } - if (id) - { - // This code matches code in TypeInstance::deduceType() - int i = templateIdentifierLookup(id, parameters); - if (i == -1) - goto Lnomatch; - TemplateParameter *tprm = parameters->tdata()[i]; - TemplateValueParameter *tvp = tprm->isTemplateValueParameter(); - if (!tvp) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[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->tdata()[i] = dim; - } - return next->deduceType(sc, tparam->nextOf(), parameters, dedtypes, wildmatch); - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - - Lnomatch: - return MATCHnomatch; -} - -MATCH TypeAArray::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ -#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, wildmatch)) - { - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeFunction::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //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 = Parameter::dim(this->parameters); - size_t nfparams = Parameter::dim(tp->parameters); - - // bug 2579 fix: Apply function parameter storage classes to parameter types - for (size_t i = 0; i < nfparams; i++) - { - Parameter *fparam = Parameter::getNth(tp->parameters, i); - fparam->type = fparam->type->addStorageClass(fparam->storageClass); - fparam->storageClass &= ~(STC_TYPECTOR | STCin); - } - //printf("\t-> this = %d, ", ty); print(); - //printf("\t-> tparam = %d, ", tparam->ty); tparam->print(); - - /* See if tuple match - */ - if (nfparams > 0 && nfargs >= nfparams - 1) - { - /* See if 'A' of the template parameter matches 'A' - * of the type of the last function parameter. - */ - Parameter *fparam = Parameter::getNth(tp->parameters, nfparams - 1); - assert(fparam); - assert(fparam->type); - if (fparam->type->ty != Tident) - goto L1; - TypeIdentifier *tid = (TypeIdentifier *)fparam->type; - if (tid->idents.dim) - goto L1; - - /* Look through parameters to find tuple matching tid->ident - */ - size_t tupi = 0; - for (; 1; tupi++) - { if (tupi == parameters->dim) - goto L1; - TemplateParameter *t = parameters->tdata()[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. - */ - size_t tuple_dim = nfargs - (nfparams - 1); - - /* See if existing tuple, and whether it matches or not - */ - Object *o = dedtypes->tdata()[tupi]; - if (o) - { // Existing deduced argument must be a tuple, and must match - Tuple *t = isTuple(o); - if (!t || t->objects.dim != tuple_dim) - return MATCHnomatch; - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - if (!arg->type->equals(t->objects.tdata()[i])) - return MATCHnomatch; - } - } - else - { // Create new tuple - Tuple *t = new Tuple(); - t->objects.setDim(tuple_dim); - for (size_t i = 0; i < tuple_dim; i++) - { Parameter *arg = Parameter::getNth(this->parameters, nfparams - 1 + i); - t->objects.tdata()[i] = arg->type; - } - dedtypes->tdata()[tupi] = 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++) - { - Parameter *a = Parameter::getNth(this->parameters, i); - Parameter *ap = Parameter::getNth(tp->parameters, i); - if (a->storageClass != ap->storageClass || - !a->type->deduceType(sc, ap->type, parameters, dedtypes, wildmatch)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeIdentifier::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tident) - { - TypeIdentifier *tp = (TypeIdentifier *)tparam; - - for (size_t i = 0; i < idents.dim; i++) - { - Identifier *id1 = idents.tdata()[i]; - Identifier *id2 = tp->idents.tdata()[i]; - - if (!id1->equals(id2)) - return MATCHnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeInstance::deduceType(Scope *sc, - Type *tparam, TemplateParameters *parameters, - Objects *dedtypes, unsigned *wildmatch) -{ -#if 0 - printf("TypeInstance::deduceType()\n"); - printf("\tthis = %d, ", ty); print(); - printf("\ttparam = %d, ", tparam->ty); tparam->print(); -#endif - - // 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 = parameters->tdata()[i]; - // This logic duplicates tpx->matchArg() - TemplateAliasParameter *ta = tpx->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Object *sa = tempinst->tempdecl; - if (!sa) - goto Lnomatch; - if (ta->specAlias && sa != ta->specAlias) - goto Lnomatch; - if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *s = dedtypes->tdata()[i]; - - if (s != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - } - } - else if (tempinst->tempdecl != tp->tempinst->tempdecl) - goto Lnomatch; - - L2: - - for (size_t i = 0; 1; i++) - { - //printf("\ttest: tempinst->tiargs[%d]\n", i); - Object *o1; - if (i < tempinst->tiargs->dim) - o1 = tempinst->tiargs->tdata()[i]; - else if (i < tempinst->tdtypes.dim && i < tp->tempinst->tiargs->dim) - // Pick up default arg - o1 = tempinst->tdtypes.tdata()[i]; - else - break; - - if (i >= tp->tempinst->tiargs->dim) - goto Lnomatch; - - Object *o2 = tp->tempinst->tiargs->tdata()[i]; - - 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); -#if 0 - if (t1) printf("t1 = %s\n", t1->toChars()); - if (t2) printf("t2 = %s\n", t2->toChars()); - if (e1) printf("e1 = %s\n", e1->toChars()); - if (e2) printf("e2 = %s\n", e2->toChars()); - if (s1) printf("s1 = %s\n", s1->toChars()); - if (s2) printf("s2 = %s\n", s2->toChars()); - if (v1) printf("v1 = %s\n", v1->toChars()); - if (v2) printf("v2 = %s\n", v2->toChars()); -#endif - - TemplateTupleParameter *ttp; - int j; - if (t2 && - t2->ty == Tident && - i == tp->tempinst->tiargs->dim - 1 && - i == tempinst->tempdecl->parameters->dim - 1 && - (ttp = tempinst->tempdecl->isVariadic()) != NULL) - { - /* Given: - * struct A(B...) {} - * alias A!(int, float) X; - * static if (!is(X Y == A!(Z), Z)) - * deduce that Z is a tuple(int, float) - */ - - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - - /* Create tuple from remaining args - */ - Tuple *vt = new Tuple(); - size_t vtdim = tempinst->tiargs->dim - i; - vt->objects.setDim(vtdim); - for (size_t k = 0; k < vtdim; k++) - vt->objects.tdata()[k] = tempinst->tiargs->tdata()[i + k]; - - Tuple *v = (Tuple *)dedtypes->tdata()[j]; - if (v) - { - if (!match(v, vt, tempinst->tempdecl, sc)) - goto Lnomatch; - } - else - dedtypes->tdata()[j] = vt; - break; //return MATCHexact; - } - - if (t1 && t2) - { - if (!t1->deduceType(sc, t2, parameters, dedtypes, wildmatch)) - 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 = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateValueParameter *tv = tp->isTemplateValueParameter(); - if (!tv) - goto Lnomatch; - Expression *e = (Expression *)dedtypes->tdata()[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->tdata()[j] = e1; - } - } - else if (s1 && t2 && t2->ty == Tident) - { - j = templateParameterLookup(t2, parameters); - if (j == -1) - goto Lnomatch; - TemplateParameter *tp = parameters->tdata()[j]; - // BUG: use tp->matchArg() instead of the following - TemplateAliasParameter *ta = tp->isTemplateAliasParameter(); - if (!ta) - goto Lnomatch; - Dsymbol *s = (Dsymbol *)dedtypes->tdata()[j]; - if (s) - { - if (!s1->equals(s)) - goto Lnomatch; - } - else - { - dedtypes->tdata()[j] = s1; - } - } - else if (s1 && s2) - { - if (!s1->equals(s2)) - goto Lnomatch; - } - // BUG: Need to handle tuple parameters - else - goto Lnomatch; - } - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - -Lnomatch: - //printf("no match\n"); - return MATCHnomatch; -} - -MATCH TypeStruct::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //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, wildmatch); - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[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, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - } - - // Extra check - if (tparam && tparam->ty == Tstruct) - { - TypeStruct *tp = (TypeStruct *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeEnum::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Tenum) - { - TypeEnum *tp = (TypeEnum *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -MATCH TypeTypedef::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - // Extra check - if (tparam && tparam->ty == Ttypedef) - { - TypeTypedef *tp = (TypeTypedef *)tparam; - - if (sym != tp->sym) - return MATCHnomatch; - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* Helper for TypeClass::deduceType(). - * Classes can match with implicit conversion to a base class or interface. - * This is complicated, because there may be more than one base class which - * matches. In such cases, one or more parameters remain ambiguous. - * For example, - * - * interface I(X, Y) {} - * class C : I(uint, double), I(char, double) {} - * C x; - * foo(T, U)( I!(T, U) x) - * - * deduces that U is double, but T remains ambiguous (could be char or uint). - * - * Given a baseclass b, and initial deduced types 'dedtypes', this function - * tries to match tparam with b, and also tries all base interfaces of b. - * If a match occurs, numBaseClassMatches is incremented, and the new deduced - * types are ANDed with the current 'best' estimate for dedtypes. - */ -void deduceBaseClassParameters(BaseClass *b, - Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, - Objects *best, int &numBaseClassMatches) -{ - TemplateInstance *parti = b->base ? b->base->parent->isTemplateInstance() : NULL; - if (parti) - { - // Make a temporary copy of dedtypes so we don't destroy it - Objects *tmpdedtypes = new Objects(); - tmpdedtypes->setDim(dedtypes->dim); - memcpy(tmpdedtypes->tdata(), dedtypes->tdata(), dedtypes->dim * sizeof(void *)); - - TypeInstance *t = new TypeInstance(0, parti); - MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes); - if (m != MATCHnomatch) - { - // If this is the first ever match, it becomes our best estimate - if (numBaseClassMatches==0) - memcpy(best->tdata(), tmpdedtypes->tdata(), tmpdedtypes->dim * sizeof(void *)); - else for (size_t k = 0; k < tmpdedtypes->dim; ++k) - { - // If we've found more than one possible type for a parameter, - // mark it as unknown. - if (tmpdedtypes->tdata()[k] != best->tdata()[k]) - best->tdata()[k] = dedtypes->tdata()[k]; - } - ++numBaseClassMatches; - } - } - // Now recursively test the inherited interfaces - for (size_t j = 0; j < b->baseInterfaces_dim; ++j) - { - deduceBaseClassParameters( &(b->baseInterfaces)[j], - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - -} - -MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, unsigned *wildmatch) -{ - //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); - MATCH m = t->deduceType(sc, tparam, parameters, dedtypes, wildmatch); - // Even if the match fails, there is still a chance it could match - // a base class. - if (m != MATCHnomatch) - return m; - } - - /* Match things like: - * S!(T).foo - */ - TypeInstance *tpi = (TypeInstance *)tparam; - if (tpi->idents.dim) - { Identifier *id = tpi->idents.tdata()[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, wildmatch); - tpi->idents.dim++; - return m; - } - } - } - - // If it matches exactly or via implicit conversion, we're done - MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); - if (m != MATCHnomatch) - return m; - - /* There is still a chance to match via implicit conversion to - * a base class or interface. Because there could be more than one such - * match, we need to check them all. - */ - - int numBaseClassMatches = 0; // Have we found an interface match? - - // Our best guess at dedtypes - Objects *best = new Objects(); - best->setDim(dedtypes->dim); - - ClassDeclaration *s = sym; - while(s && s->baseclasses->dim > 0) - { - // Test the base class - deduceBaseClassParameters((s->baseclasses->tdata()[0]), - sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - - // Test the interfaces inherited by the base class - for (size_t i = 0; i < s->interfaces_dim; ++i) - { - BaseClass *b = s->interfaces[i]; - deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, - best, numBaseClassMatches); - } - s = ((s->baseclasses->tdata()[0]))->base; - } - - if (numBaseClassMatches == 0) - return MATCHnomatch; - - // If we got at least one match, copy the known types into dedtypes - memcpy(dedtypes->tdata(), best->tdata(), best->dim * sizeof(void *)); - return MATCHconvert; - } - - // Extra check - if (tparam && tparam->ty == Tclass) - { - TypeClass *tp = (TypeClass *)tparam; - - //printf("\t%d\n", (MATCH) implicitConvTo(tp)); - return implicitConvTo(tp); - } - return Type::deduceType(sc, tparam, parameters, dedtypes, wildmatch); -} - -/* ======================== 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 - -Type *TemplateTypeParameter::tdummy = NULL; - -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, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - //printf("TemplateTypeParameter::matchArg()\n"); - Object *oarg; - MATCH m = MATCHexact; - Type *ta; - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - { - goto Lnomatch; - } - } - } - - ta = isType(oarg); - if (!ta) - { - //printf("%s %p %p %p\n", oarg->toChars(), isExpression(oarg), isDsymbol(oarg), isTuple(oarg)); - goto Lnomatch; - } - //printf("ta is %s\n", ta->toChars()); - - if (specType) - { - if (!ta || ta == tdummy) - goto Lnomatch; - - //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta->toChars(), specType->toChars()); - MATCH m2 = ta->deduceType(sc, specType, parameters, dedtypes); - if (m2 == MATCHnomatch) - { //printf("\tfailed deduceType\n"); - goto Lnomatch; - } - - if (m2 < m) - m = m2; - if (dedtypes->tdata()[i]) - ta = (Type *)dedtypes->tdata()[i]; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced type - Type *t = (Type *)dedtypes->tdata()[i]; - - if (!t->equals(ta)) - { //printf("t = %s ta = %s\n", t->toChars(), ta->toChars()); - goto Lnomatch; - } - } - else - { - // So that matches with specializations are better - m = MATCHconvert; - } - } - dedtypes->tdata()[i] = ta; - - *psparam = new AliasDeclaration(loc, ident, ta); - //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("\tParameter: %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 (?) - if (!tdummy) - tdummy = new TypeIdentifier(loc, ident); - t = tdummy; - } - return (void *)t; -} - - -Object *TemplateTypeParameter::specialization() -{ - return specType; -} - - -Object *TemplateTypeParameter::defaultArg(Loc loc, 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 *specType, Object *specAlias, Object *defaultAlias) - : TemplateParameter(loc, ident) -{ - this->ident = ident; - this->specType = specType; - this->specAlias = specAlias; - this->defaultAlias = defaultAlias; -} - -TemplateAliasParameter *TemplateAliasParameter::isTemplateAliasParameter() -{ - return this; -} - -TemplateParameter *TemplateAliasParameter::syntaxCopy() -{ - TemplateAliasParameter *tp = new TemplateAliasParameter(loc, ident, specType, specAlias, defaultAlias); - if (tp->specType) - tp->specType = specType->syntaxCopy(); - tp->specAlias = objectSyntaxCopy(specAlias); - tp->defaultAlias = objectSyntaxCopy(defaultAlias); - 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()); -} - -Object *aliasParameterSemantic(Loc loc, Scope *sc, Object *o) -{ - if (o) - { - Expression *ea = isExpression(o); - Type *ta = isType(o); - if (ta) - { Dsymbol *s = ta->toDsymbol(sc); - if (s) - o = s; - else - o = ta->semantic(loc, sc); - } - else if (ea) - { - ea = ea->semantic(sc); - o = ea->optimize(WANTvalue | WANTinterpret); - } - } - return o; -} - -void TemplateAliasParameter::semantic(Scope *sc) -{ - if (specType) - { - specType = specType->semantic(loc, sc); - } - specAlias = aliasParameterSemantic(loc, sc, specAlias); -#if 0 // Don't do semantic() until instantiation - if (defaultAlias) - defaultAlias = defaultAlias->semantic(loc, sc); -#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, - size_t i, TemplateParameters *parameters, Objects *dedtypes, - Declaration **psparam) -{ - Object *sa; - Object *oarg; - Expression *ea; - Dsymbol *s; - - //printf("TemplateAliasParameter::matchArg()\n"); - - if (i < tiargs->dim) - oarg = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - sa = getDsymbol(oarg); - if (sa) - { - /* specType means the alias must be a declaration with a type - * that matches specType. - */ - if (specType) - { Declaration *d = ((Dsymbol *)sa)->isDeclaration(); - if (!d) - goto Lnomatch; - if (!d->type->equals(specType)) - goto Lnomatch; - } - } - else - { - sa = oarg; - ea = isExpression(oarg); - if (ea) - { if (specType) - { - if (!ea->type->equals(specType)) - goto Lnomatch; - } - } - else - goto Lnomatch; - } - - if (specAlias) - { - if (sa == sdummy) - goto Lnomatch; - if (sa != specAlias) - goto Lnomatch; - } - else if (dedtypes->tdata()[i]) - { // Must match already deduced symbol - Object *si = dedtypes->tdata()[i]; - - if (!sa || si != sa) - goto Lnomatch; - } - dedtypes->tdata()[i] = sa; - - s = isDsymbol(sa); - if (s) - *psparam = new AliasDeclaration(loc, ident, s); - else - { - assert(ea); - - // Declare manifest constant - Initializer *init = new ExpInitializer(loc, ea); - VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init); - v->storage_class = STCmanifest; - v->semantic(sc); - *psparam = v; - } - return MATCHexact; - -Lnomatch: - *psparam = NULL; - //printf("\tm = %d\n", MATCHnomatch); - return MATCHnomatch; -} - - -void TemplateAliasParameter::print(Object *oarg, Object *oded) -{ - printf(" %s\n", ident->toChars()); - - Dsymbol *sa = isDsymbol(oded); - assert(sa); - - printf("\tParameter alias: %s\n", sa->toChars()); -} - -void TemplateAliasParameter::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("alias "); - if (specType) - { HdrGenState hgs1; - specType->toCBuffer(buf, ident, &hgs1); - } - else - buf->writestring(ident->toChars()); - if (specAlias) - { - buf->writestring(" : "); - ObjectToCBuffer(buf, hgs, specAlias); - } - if (defaultAlias) - { - buf->writestring(" = "); - ObjectToCBuffer(buf, hgs, defaultAlias); - } -} - - -void *TemplateAliasParameter::dummyArg() -{ Object *s; - - s = specAlias; - if (!s) - { - if (!sdummy) - sdummy = new Dsymbol(); - s = sdummy; - } - return (void*)s; -} - - -Object *TemplateAliasParameter::specialization() -{ - return specAlias; -} - - -Object *TemplateAliasParameter::defaultArg(Loc loc, Scope *sc) -{ - Object *da = defaultAlias; - Type *ta = isType(defaultAlias); - if (ta) - { - if (ta->ty == Tinstance) - { - // If the default arg is a template, instantiate for each type - da = ta->syntaxCopy(); - } - } - - Object *o = aliasParameterSemantic(loc, sc, da); - return o; -} - -/* ======================== TemplateValueParameter ========================== */ - -// value-parameter - -AA *TemplateValueParameter::edummies = 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) - { - if (valType != Type::terror) - 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, - size_t 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 = tiargs->tdata()[i]; - else - { // Get default argument instead - oarg = defaultArg(loc, sc); - if (!oarg) - { assert(i < dedtypes->dim); - // It might have already been deduced - oarg = dedtypes->tdata()[i]; - if (!oarg) - goto Lnomatch; - } - } - - ei = isExpression(oarg); - Type *vt; - - if (!ei && oarg) - goto Lnomatch; - - if (ei && ei->op == TOKvar) - { // Resolve const variables that we had skipped earlier - ei = ei->optimize(WANTvalue | WANTinterpret); - } - - //printf("\tvalType: %s, ty = %d\n", valType->toChars(), valType->ty); - vt = valType->semantic(0, sc); - //printf("ei: %s, ei->type: %s\n", ei->toChars(), ei->type->toChars()); - //printf("vt = %s\n", vt->toChars()); - - if (ei->type) - { - m = (MATCH)ei->implicitConvTo(vt); - //printf("m: %d\n", m); - if (!m) - goto Lnomatch; - } - - if (specValue) - { - if (!ei || _aaGetRvalue(edummies, ei->type) == ei) - 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->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - //printf("\tei: %s, %s\n", ei->toChars(), ei->type->toChars()); - //printf("\te : %s, %s\n", e->toChars(), e->type->toChars()); - if (!ei->equals(e)) - goto Lnomatch; - } - else - { - if (dedtypes->tdata()[i]) - { // Must match already deduced value - Expression *e = (Expression *)dedtypes->tdata()[i]; - - if (!ei || !ei->equals(e)) - goto Lnomatch; - } - else if (m != MATCHexact) - { - ei = ei->implicitCastTo(sc, vt); - ei = ei->optimize(WANTvalue | WANTinterpret); - } - } - dedtypes->tdata()[i] = ei; - - init = new ExpInitializer(loc, ei); - sparam = new VarDeclaration(loc, vt, ident, init); - sparam->storage_class = STCmanifest; - *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("\tParameter 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 - Expression **pe = (Expression **)_aaGet(&edummies, valType); - if (!*pe) - *pe = valType->defaultInit(); - e = *pe; - } - return (void *)e; -} - - -Object *TemplateValueParameter::specialization() -{ - return specValue; -} - - -Object *TemplateValueParameter::defaultArg(Loc loc, Scope *sc) -{ - Expression *e = defaultValue; - if (e) - { - e = e->syntaxCopy(); - e = e->semantic(sc); -#if DMDV2 - e = e->resolveLoc(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 - } - - return 0; -} - -MATCH TemplateTupleParameter::matchArg(Scope *sc, Objects *tiargs, - size_t 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 (dedtypes->tdata()[i] && isTuple(dedtypes->tdata()[i])) - // It was already been deduced - ovar = isTuple(dedtypes->tdata()[i]); - else if (i + 1 == tiargs->dim && isTuple(tiargs->tdata()[i])) - ovar = isTuple(tiargs->tdata()[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.tdata()[j] = tiargs->tdata()[i + j]; - } - } - *psparam = new TupleDeclaration(loc, ident, &ovar->objects); - dedtypes->tdata()[i] = 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 (size_t i = 0; i < v->objects.dim; i++) - { - if (i) - printf(", "); - - Object *o = v->objects.tdata()[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(Loc loc, 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->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = 0; - this->semantictiargsdone = 0; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 0; - this->isnested = NULL; - this->errors = 0; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif -} - -/***************** - * This constructor is only called when we figured out which function - * template to instantiate. - */ - -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->tinst = NULL; - this->argsym = NULL; - this->aliasdecl = NULL; - this->semanticRun = 0; - this->semantictiargsdone = 1; - this->withsym = NULL; - this->nest = 0; - this->havetempdecl = 1; - this->isnested = NULL; - this->errors = 0; - this->speculative = 0; - this->ignore = true; - -#if IN_LLVM - this->tinst = NULL; - this->emittedInModule = NULL; - this->tmodule = NULL; -#endif - - 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++) - { - a->tdata()[i] = objectSyntaxCopy(objs->tdata()[i]); - } - } - return a; -} - -Dsymbol *TemplateInstance::syntaxCopy(Dsymbol *s) -{ - TemplateInstance *ti; - - 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) -{ - semantic(sc, NULL); -} - -void TemplateInstance::semantic(Scope *sc, Expressions *fargs) -{ - //printf("TemplateInstance::semantic('%s', this=%p, gag = %d, sc = %p)\n", toChars(), this, global.gag, sc); - if (global.errors && name != Id::AssociativeArray) - { - //printf("not instantiating %s due to %d errors\n", toChars(), global.errors); - if (!global.gag) - { - /* Trying to soldier on rarely generates useful messages - * at this point. - */ - fatal(); - } -// return; - } - if (!sc->ignoreTemplates) - ignore = false; -#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; - } - - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - if (semanticRun != 0) - { -#if LOG - printf("Recursive template expansion\n"); -#endif - error(loc, "recursive template expansion"); -// inst = this; - return; - } - semanticRun = 1; -#if IN_LLVM - // get the enclosing template instance from the scope tinst - tinst = sc->tinst; - - // get the module of the outermost enclosing instantiation - if (tinst) - tmodule = tinst->tmodule; - else - tmodule = sc->module; - //printf("%s in %s\n", toChars(), tmodule->toChars()); -#endif - -#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, fargs, 2)) - { - error("incompatible arguments for template instantiation"); - inst = this; - return; - } - } - else - { - /* Run semantic on each argument, place results in tiargs[] - * (if we havetempdecl, then tiargs is already evaluated) - */ - semanticTiargs(sc); - if (arrayObjectIsError(tiargs)) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - - tempdecl = findTemplateDeclaration(sc); - if (tempdecl) - tempdecl = findBestMatch(sc, fargs); - if (!tempdecl || global.errors) - { inst = this; - //printf("error return %p, %d\n", tempdecl, global.errors); - return; // error recovery - } - } - - // If tempdecl is a mixin, disallow it - if (tempdecl->ismixin) - error("mixin templates are not regular templates"); - - hasNestedArgs(tiargs); - - /* See if there is an existing TemplateInstantiation that already - * implements the typeargs. If so, just refer to that one instead. - */ - - for (size_t i = 0; i < tempdecl->instances.dim; i++) - { - TemplateInstance *ti = tempdecl->instances.tdata()[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) - { - //printf("test2 isnested %s ti->isnested %s\n", isnested ? isnested->toChars() : "", ti->isnested ? ti->isnested->toChars() : ""); - continue; - } -#if 0 - if (isnested && sc->parent != ti->parent) - continue; -#endif - if (!arrayObjectMatch(&tdtypes, &ti->tdtypes, tempdecl, sc)) - goto L1; - - /* Template functions may have different instantiations based on - * "auto ref" parameters. - */ - if (fargs) - { - FuncDeclaration *fd = ti->toAlias()->isFuncDeclaration(); - if (fd) - { - Parameters *fparameters = fd->getParameters(NULL); - size_t nfparams = Parameter::dim(fparameters); // Num function parameters - for (size_t j = 0; j < nfparams && j < fargs->dim; j++) - { Parameter *fparam = Parameter::getNth(fparameters, j); - Expression *farg = fargs->tdata()[j]; - if (fparam->storageClass & STCauto) // if "auto ref" - { - if (farg->isLvalue()) - { if (!(fparam->storageClass & STCref)) - goto L1; // auto ref's don't match - } - else - { if (fparam->storageClass & STCref) - goto L1; // auto ref's don't match - } - } - } - } - } - - // It's a match - inst = ti; - parent = ti->parent; - - // If both this and the previous instantiation were speculative, - // use the number of errors that happened last time. - if (inst->speculative && global.gag) - { - global.errors += inst->errors; - global.gaggedErrors += inst->errors; - } - - // If the first instantiation was speculative, but this is not: - if (inst->speculative && !global.gag) - { - // If the first instantiation had failed, re-run semantic, - // so that error messages are shown. - if (inst->errors) - goto L1; - // It had succeeded, mark it is a non-speculative instantiation, - // and reuse it. - inst->speculative = 0; - } - -#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 '%s'\n", tempdecl->parent->toChars(), toChars()); - printf("\ttempdecl %s\n", tempdecl->toChars()); -#endif - unsigned errorsave = global.errors; - inst = this; - // Mark as speculative if we are instantiated from inside is(typeof()) - if (global.gag && sc->intypeof) - speculative = 1; - - int tempdecl_instance_idx = tempdecl->instances.dim; - tempdecl->instances.push(this); - parent = tempdecl->parent; - //printf("parent = '%s'\n", parent->kind()); - - ident = genIdent(tiargs); // 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. Store the place we added it to - // in target_symbol_list(_idx) so we can remove it later if we encounter - // an error. -#if 1 - int dosemantic3 = 0; - Dsymbols *target_symbol_list = NULL; - int target_symbol_list_idx; - - if (!sc->parameterSpecialization) - { Dsymbols *a; - - Scope *scx = sc; -#if 0 - for (scx = sc; scx; scx = scx->enclosing) - if (scx->scopesym) - break; -#endif - - //if (scx && scx->scopesym) printf("3: scx is %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - if (scx && scx->scopesym && - scx->scopesym->members && !scx->scopesym->isTemplateMixin() -#if 0 // removed because it bloated compile times - /* The problem is if A imports B, and B imports A, and both A - * and B instantiate the same template, does the compilation of A - * or the compilation of B do the actual instantiation? - * - * see bugzilla 2500. - */ - && !scx->module->selfImports() -#endif - ) - { - //printf("\t1: adding to %s %s\n", scx->scopesym->kind(), scx->scopesym->toChars()); - a = scx->scopesym->members; - } - else - { Module *m = sc->module->importedFrom; - //printf("\t2: adding to module %s instead of module %s\n", m->toChars(), sc->module->toChars()); - a = m->members; - if (m->semanticRun >= 3) - { - dosemantic3 = 1; - } - } - for (int i = 0; 1; i++) - { - if (i == a->dim) - { - target_symbol_list = a; - target_symbol_list_idx = i; - a->push(this); - break; - } - if (this == a->tdata()[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 (!tempdecl->semanticRun) - { - error("template instantiation %s forward references template declaration %s\n", toChars(), 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); -// scope->stc = 0; - - // Declare each template parameter as an alias for the argument type - Scope *paramscope = scope->push(); - paramscope->stc = 0; - declareParameters(paramscope); - paramscope->pop(); - - // Add members of template instance to template instance symbol table -// parent = scope->scopesym; - symtab = new DsymbolTable(); - int memnum = 0; - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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, tempdecl->ident) && s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - -#if IN_LLVM - // LDC propagate internal information - if (tempdecl->llvmInternal) { - s->llvmInternal = tempdecl->llvmInternal; - if (FuncDeclaration* fd = s->isFuncDeclaration()) { - fd->intrinsicName = tempdecl->intrinsicName; - } - } -#endif - } - } - - /* If function template declaration - */ - if (fargs && aliasdecl) - { - FuncDeclaration *fd = aliasdecl->toAlias()->isFuncDeclaration(); - if (fd) - { - /* Transmit fargs to type so that TypeFunction::semantic() can - * resolve any "auto ref" storage classes. - */ - TypeFunction *tf = (TypeFunction *)fd->type; - if (tf && tf->ty == Tfunction) - tf->fargs = fargs; - } - } - - // Do semantic() analysis on template instance members -#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; - sc2->tinst = this; - -#if WINDOWS_SEH - __try - { -#endif - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - - for (size_t i = 0; i < members->dim; i++) - { Dsymbol *s = (*members)[i]; - s->setScope(sc2); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - //printf("\t[%d] semantic on '%s' %p kind %s in '%s'\n", i, s->toChars(), s, s->kind(), this->toChars()); - //printf("test: isnested = %d, sc2->parent = %s\n", isnested, sc2->parent->toChars()); -// if (isnested) -// s->parent = sc->parent; - //printf("test3: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - s->semantic(sc2); - //printf("test4: isnested = %d, s->parent = %s\n", isnested, s->parent->toChars()); - sc2->module->runDeferredSemantic(); - } - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#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 = Module::deferred.tdata()[i]; - - if (sd->parent == this) - { - //printf("deferred %s %s\n", sd->parent->toChars(), sd->toChars()); - AggregateDeclaration *ad = sd->isAggregateDeclaration(); - if (ad) - ad->deferred = this; - goto Laftersemantic; - } - } - - /* ConditionalDeclaration may introduce eponymous declaration, - * so we should find it once again after semantic. - */ - if (members->dim) - { - Dsymbol *s; - if (Dsymbol::oneMembers(members, &s, tempdecl->ident) && s) - { - if (!aliasdecl || aliasdecl->toAlias() != s) - { - //printf("s->kind = '%s'\n", s->kind()); - //s->print(); - //printf("'%s', '%s'\n", s->ident->toChars(), tempdecl->ident->toChars()); - //printf("setting aliasdecl 2\n"); - aliasdecl = new AliasDeclaration(loc, s->ident, s); - } - } - else if (aliasdecl) - aliasdecl = NULL; - } - - /* 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) - { -#if WINDOWS_SEH - __try - { -#endif - static int nest; - if (++nest > 300) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - semantic3(sc2); - --nest; -#if WINDOWS_SEH - } - __except (__ehfilter(GetExceptionInformation())) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } -#endif - } - - Laftersemantic: - sc2->pop(); - - scope->pop(); - - // Give additional context info if error occurred during instantiation - if (global.errors != errorsave) - { - error(loc, "error instantiating"); - if (tinst) - { tinst->printInstantiationTrace(); - } - errors = 1; - if (global.gag) - { - // Errors are gagged, so remove the template instance from the - // instance/symbol lists we added it to and reset our state to - // finish clean and so we can try to instantiate it again later - // (see bugzilla 4302 and 6602). - tempdecl->instances.remove(tempdecl_instance_idx); - if (target_symbol_list) - { - // Because we added 'this' in the last position above, we - // should be able to remove it without messing other indices up. - assert(target_symbol_list->tdata()[target_symbol_list_idx] == this); - target_symbol_list->remove(target_symbol_list_idx); - } - semanticRun = 0; - inst = NULL; - } - } - -#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, 0); -} - -/********************************** - * Input: - * flags 1: replace const variables with their initializers - */ - -void TemplateInstance::semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags) -{ - // Run semantic on each argument, place results in tiargs[] - //printf("+TemplateInstance::semanticTiargs()\n"); - if (!tiargs) - return; - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[j]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - - //printf("1: tiargs->tdata()[%d] = %p, %p, %p, ea=%p, ta=%p\n", j, o, isDsymbol(o), isTuple(o), ea, ta); - if (ta) - { - //printf("type %s\n", ta->toChars()); - // It might really be an Expression or an Alias - ta->resolve(loc, sc, &ea, &ta, &sa); - if (ea) - { - ea = ea->semantic(sc); - /* This test is to skip substituting a const var with - * its initializer. The problem is the initializer won't - * match with an 'alias' parameter. Instead, do the - * const substitution in TemplateValueParameter::matchArg(). - */ - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - } - else if (sa) - { - Ldsym: - tiargs->tdata()[j] = sa; - TupleDeclaration *d = sa->toAlias()->isTupleDeclaration(); - if (d) - { - size_t dim = d->objects->dim; - tiargs->remove(j); - tiargs->insert(j, d->objects); - j--; - } - } - else if (ta) - { - Ltype: - if (ta->ty == Ttuple) - { // Expand tuple - TypeTuple *tt = (TypeTuple *)ta; - size_t dim = tt->arguments->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - { Parameter *arg = tt->arguments->tdata()[i]; - tiargs->insert(j + i, arg->type); - } - } - j--; - } - else - tiargs->tdata()[j] = ta; - } - else - { - assert(global.errors); - tiargs->tdata()[j] = Type::terror; - } - } - else if (ea) - { - if (!ea) - { assert(global.errors); - ea = new ErrorExp(); - } - assert(ea); - ea = ea->semantic(sc); - if (flags & 1) // only used by __traits, must not interpret the args - ea = ea->optimize(WANTvalue); - else if (ea->op != TOKvar && ea->op != TOKtuple) - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[j] = ea; - if (ea->op == TOKtype) - { ta = ea->type; - goto Ltype; - } - if (ea->op == TOKimport) - { sa = ((ScopeExp *)ea)->sds; - goto Ldsym; - } - if (ea->op == TOKtuple) - { // Expand tuple - TupleExp *te = (TupleExp *)ea; - size_t dim = te->exps->dim; - tiargs->remove(j); - if (dim) - { tiargs->reserve(dim); - for (size_t i = 0; i < dim; i++) - tiargs->insert(j + i, te->exps->tdata()[i]); - } - j--; - } - } - else if (sa) - { - TemplateDeclaration *td = sa->isTemplateDeclaration(); - if (td && !td->semanticRun && td->literal) - td->semantic(sc); - } - else - { - assert(0); - } - //printf("1: tiargs->tdata()[%d] = %p\n", j, tiargs->tdata()[j]); - } -#if 0 - printf("-TemplateInstance::semanticTiargs()\n"); - for (size_t j = 0; j < tiargs->dim; j++) - { - Object *o = tiargs->tdata()[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; - - id = name; - s = sc->search(loc, id, &scopesym); - if (!s) - { - s = sc->search_correct(id); - if (s) - error("template '%s' is not defined, did you mean %s?", id->toChars(), s->toChars()); - else - error("template '%s' is not defined", id->toChars()); - return NULL; - } - - /* If an OverloadSet, look for a unique member that is a template declaration - */ - OverloadSet *os = s->isOverloadSet(); - if (os) - { s = NULL; - for (size_t i = 0; i < os->a.dim; i++) - { Dsymbol *s2 = os->a.tdata()[i]; - if (s2->isTemplateDeclaration()) - { - if (s) - error("ambiguous template declaration %s and %s", s->toPrettyChars(), s2->toPrettyChars()); - s = s2; - } - } - if (!s) - { error("template '%s' is not defined", id->toChars()); - return NULL; - } - } - -#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->tempdecl && ti->tempdecl->ident == id) - { - /* 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, Expressions *fargs) -{ - /* 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 - // First look for forward references - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - if (td->scope) - { // Try to fix forward reference - td->semantic(td->scope); - } - if (!td->semanticRun) - { - error("%s forward references template declaration %s\n", toChars(), td->toChars()); - return NULL; - } - } - } - - 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->tdata()[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(); - assert(td->semanticRun); - m = td->matchWithInstance(this, &dedtypes, fargs, 0); - //printf("matchWithInstance = %d\n", m); - if (!m) // no match at all - continue; - - if (m < m_best) - goto Ltd_best; - if (m > m_best) - goto Ltd; - - { - // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td->leastAsSpecialized(td_best, fargs); - MATCH c2 = td_best->leastAsSpecialized(td, fargs); - //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.tdata(), dedtypes.tdata(), tdtypes.dim * sizeof(void *)); - continue; - } - - if (!td_best) - { - if (tempdecl && !tempdecl->overnext) - // Only one template, so we can give better error message - error("%s does not match template declaration %s", toChars(), tempdecl->toChars()); - else - error("%s does not match any template declaration", toChars()); - return NULL; - } - if (td_ambig) - { - error("%s matches more than one template declaration, %s(%d):%s and %s(%d):%s", - toChars(), - td_best->loc.filename, td_best->loc.linnum, td_best->toChars(), - td_ambig->loc.filename, td_ambig->loc.linnum, td_ambig->toChars()); - } - - /* The best match is td_best - */ - 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 = tiargs->tdata()[i]; - Expression *ea = isExpression(o); // value argument - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - if (tvp) - { - assert(ea); - ea = ea->castTo(tvp->valType); - ea = ea->optimize(WANTvalue | WANTinterpret); - tiargs->tdata()[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::hasNestedArgs(Objects *args) -{ int nested = 0; - //printf("TemplateInstance::hasNestedArgs('%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 = args->tdata()[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: - TemplateDeclaration *td = sa->isTemplateDeclaration(); - Declaration *d = sa->isDeclaration(); - if ((td && td->literal) || - (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 = sa->toParent(); - if (!isnested) - isnested = dparent; - else if (isnested != dparent) - { - /* Select the more deeply nested of the two. - * Error if one is not nested inside the other. - */ - for (Dsymbol *p = isnested; p; p = p->parent) - { - if (p == dparent) - goto L1; // isnested is most nested - } - for (Dsymbol *p = dparent; p; p = p->parent) - { - if (p == isnested) - { isnested = dparent; - goto L1; // dparent is most nested - } - } - error("%s is nested in both %s and %s", - toChars(), isnested->toChars(), dparent->toChars()); - } - L1: - //printf("\tnested inside %s\n", isnested->toChars()); - nested |= 1; - } - else - error("cannot use local '%s' as parameter to non-global template %s", sa->toChars(), tempdecl->toChars()); - } - } - else if (va) - { - nested |= hasNestedArgs(&va->objects); - } - } - return nested; -} - -/**************************************** - * 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(Objects *args) -{ OutBuffer buf; - - //printf("TemplateInstance::genIdent('%s')\n", tempdecl->ident->toChars()); - char *id = tempdecl->ident->toChars(); - buf.printf("__T%zu%s", strlen(id), id); - for (size_t i = 0; i < args->dim; i++) - { Object *o = args->tdata()[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Tuple *va = isTuple(o); - //printf("\to [%d] %p ta %p ea %p sa %p va %p\n", i, o, ta, ea, sa, va); - if (ta) - { - buf.writeByte('T'); - if (ta->deco) - buf.writestring(ta->deco); - else - { -#ifdef DEBUG - printf("ta = %d, %s\n", ta->ty, ta->toChars()); -#endif - assert(global.errors); - } - } - else if (ea) - { - // Don't interpret it yet, it might actually be an alias - ea = ea->optimize(WANTvalue); - if (ea->op == TOKvar) - { - sa = ((VarExp *)ea)->var; - ea = NULL; - goto Lsa; - } - if (ea->op == TOKthis) - { - sa = ((ThisExp *)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; - } - // Now that we know it is not an alias, we MUST obtain a value - ea = ea->optimize(WANTvalue | WANTinterpret); - if (ea->op == TOKerror) - 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 = tempdecl->parameters->tdata()[i]; - assert(tp); - TemplateValueParameter *tvp = tp->isTemplateValueParameter(); - assert(tvp); - buf.writestring(tvp->valType->deco); -#endif - ea->toMangleBuffer(&buf); - } - else if (sa) - { - Lsa: - buf.writeByte('S'); - Declaration *d = sa->isDeclaration(); - if (d && (!d->type || !d->type->deco)) - { error("forward reference of %s", d->toChars()); - continue; - } -#if 0 - VarDeclaration *v = sa->isVarDeclaration(); - if (v && v->storage_class & STCmanifest) - { ExpInitializer *ei = v->init->isExpInitializer(); - if (ei) - { - ea = ei->exp; - goto Lea; - } - } -#endif - const char *p = sa->mangle(); - - /* Bugzilla 3043: if the first character of p is a digit this - * causes ambiguity issues because the digits of the two numbers are adjacent. - * Current demanglers resolve this by trying various places to separate the - * numbers until one gets a successful demangle. - * Unfortunately, fixing this ambiguity will break existing binary - * compatibility and the demanglers, so we'll leave it as is. - */ - buf.printf("%zu%s", strlen(p), p); - } - else if (va) - { - assert(i + 1 == args->dim); // must be last one - args = &va->objects; - i = -1; - } - else - assert(0); - } - buf.writeByte('Z'); - id = buf.toChars(); - //buf.data = NULL; // we can free the string after call to idPool() - //printf("\tgenIdent = %s\n", id); - return Lexer::idPool(id); -} - - -/**************************************************** - * Declare parameters of template instance, initialize them with the - * template instance arguments. - */ - -void TemplateInstance::declareParameters(Scope *sc) -{ - //printf("TemplateInstance::declareParameters()\n"); - for (size_t i = 0; i < tdtypes.dim; i++) - { - TemplateParameter *tp = tempdecl->parameters->tdata()[i]; - //Object *o = tiargs->tdata()[i]; - Object *o = tdtypes.tdata()[i]; // initializer for tp - - //printf("\ttdtypes[%d] = %p\n", i, o); - tempdecl->declareParameter(sc, tp, o); - } -} - -/***************************************************** - * Determine if template instance is really a template function, - * and that template function needs to infer types from the function - * arguments. - */ - -int TemplateInstance::needsTypeInference(Scope *sc) -{ - //printf("TemplateInstance::needsTypeInference() %s\n", toChars()); - if (!tempdecl) - tempdecl = findTemplateDeclaration(sc); - int multipleMatches = FALSE; - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - /* If any of the overloaded template declarations need inference, - * then return TRUE - */ - FuncDeclaration *fd; - if (!td->onemember || - (fd = td->onemember->toAlias()->isFuncDeclaration()) == NULL || - fd->type->ty != Tfunction) - { - /* Not a template function, therefore type inference is not possible. - */ - //printf("false\n"); - return FALSE; - } - - for (size_t i = 0; i < td->parameters->dim; i++) - if (td->parameters->tdata()[i]->isTemplateThisParameter()) - return TRUE; - - /* Determine if the instance arguments, tiargs, are all that is necessary - * to instantiate the template. - */ - TemplateTupleParameter *tp = td->isVariadic(); - //printf("tp = %p, td->parameters->dim = %d, tiargs->dim = %d\n", tp, td->parameters->dim, tiargs->dim); - TypeFunction *fdtype = (TypeFunction *)fd->type; - if (Parameter::dim(fdtype->parameters) && - ((tp && td->parameters->dim > 1) || tiargs->dim < td->parameters->dim)) - return TRUE; - /* If there is more than one function template which matches, we may - * need type inference (see Bugzilla 4430) - */ - if (td != tempdecl) - multipleMatches = TRUE; - } - //printf("false\n"); - return multipleMatches; -} - -void TemplateInstance::semantic2(Scope *sc) -{ int i; - - if (semanticRun >= 2) - return; - semanticRun = 2; -#if LOG - printf("+TemplateInstance::semantic2('%s')\n", toChars()); -#endif - if (!errors && members) - { - sc = tempdecl->scope; - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - for (i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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'), semanticRun = %d\n", toChars(), semanticRun); -#endif -//if (toChars()[0] == 'D') *(char*)0=0; - if (semanticRun >= 3) - return; - semanticRun = 3; - if (!errors && members) - { - sc = tempdecl->scope; - sc = sc->push(argsym); - sc = sc->push(this); - sc->tinst = this; - if (ignore) - sc->ignoreTemplates++; - int oldgag = global.gag; - int olderrors = global.errors; - /* If this is a speculative instantiation, gag errors. - * Future optimisation: If the results are actually needed, errors - * would already be gagged, so we don't really need to run semantic - * on the members. - */ - if (speculative && !oldgag) - olderrors = global.startGagging(); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic3(sc); - if (speculative && global.errors != olderrors) - break; - } - if (speculative && !oldgag) - { // If errors occurred, this instantiation failed - errors += global.errors - olderrors; - global.endGagging(olderrors); - } - sc = sc->pop(); - sc->pop(); - } -} - -#if IN_DMD - -/************************************** - * Given an error instantiating the TemplateInstance, - * give the nested TemplateInstance instantiations that got - * us here. Those are a list threaded into the nested scopes. - */ -void TemplateInstance::printInstantiationTrace() -{ - if (global.gag) - return; - - const unsigned max_shown = 6; - const char format[] = "instantiated from here: %s"; - - // determine instantiation depth and number of recursive instantiations - int n_instantiations = 1; - int n_totalrecursions = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - ++n_instantiations; - // If two instantiations use the same declaration, they are recursive. - // (this works even if they are instantiated from different places in the - // same template). - // In principle, we could also check for multiple-template recursion, but it's - // probably not worthwhile. - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - ++n_totalrecursions; - } - - // show full trace only if it's short or verbose is on - if (n_instantiations <= max_shown || global.params.verbose) - { - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - errorSupplemental(cur->loc, format, cur->toChars()); - } - } - else if (n_instantiations - n_totalrecursions <= max_shown) - { - // By collapsing recursive instantiations into a single line, - // we can stay under the limit. - int recursionDepth=0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (cur->tinst && cur->tempdecl && cur->tinst->tempdecl - && cur->tempdecl->loc.equals(cur->tinst->tempdecl->loc)) - { - ++recursionDepth; - } - else - { - if (recursionDepth) - errorSupplemental(cur->loc, "%d recursive instantiations from here: %s", recursionDepth+2, cur->toChars()); - else - errorSupplemental(cur->loc, format, cur->toChars()); - recursionDepth = 0; - } - } - } - else - { - // Even after collapsing the recursions, the depth is too deep. - // Just display the first few and last few instantiations. - unsigned i = 0; - for (TemplateInstance *cur = this; cur; cur = cur->tinst) - { - if (i == max_shown / 2) - errorSupplemental(cur->loc, "... (%d instantiations, -v to show) ...", n_instantiations - max_shown); - - if (i < max_shown / 2 || - i >= n_instantiations - max_shown + max_shown / 2) - errorSupplemental(cur->loc, format, cur->toChars()); - ++i; - } - } -} - -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); - else - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->toObjFile(multiobj); - } - } - } -} - -#endif - -void TemplateInstance::inlineScan() -{ -#if LOG - printf("TemplateInstance::inlineScan('%s')\n", toChars()); -#endif - if (!errors && members) - { - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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 = args->tdata()[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"); - errors = 1; - 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, Identifier *ident) -{ - *ps = NULL; - return TRUE; -} - -char *TemplateInstance::toChars() -{ - OutBuffer buf; - HdrGenState hgs; - char *s; - - toCBuffer(&buf, &hgs); - s = buf.toChars(); - buf.data = NULL; - return s; -} - -#if IN_LLVM - -void TemplateInstance::printInstantiationTrace() -{ - if(global.gag) - return; - - const int max_shown = 6; - - // determine instantiation depth - int n_instantiations = 1; - TemplateInstance* cur = this; - while(cur = cur->tinst) - ++n_instantiations; - - // show full trace only if it's short or verbose is on - if(n_instantiations <= max_shown || global.params.verbose) - { - cur = this; - while(cur) - { - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - cur = cur->tinst; - } - } - else - { - cur = this; - size_t i = 0; - for(; i < max_shown/2; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - fprintf(stdmsg," ... (%d instantiations, -v to show) ...\n", n_instantiations - max_shown); - for(; i < n_instantiations - max_shown + max_shown/2; ++i, cur = cur->tinst) - {} - for(; i < n_instantiations; ++i, cur = cur->tinst) - fprintf(stdmsg," instantiatied in %s: %s\n", cur->loc.toChars(), cur->toChars()); - } -} - -#endif - -/* ======================== TemplateMixin ================================ */ - -TemplateMixin::TemplateMixin(Loc loc, Identifier *ident, Type *tqual, - Identifiers *idents, Objects *tiargs) - : TemplateInstance(loc, idents->tdata()[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(); -} - -Dsymbol *TemplateMixin::syntaxCopy(Dsymbol *s) -{ TemplateMixin *tm; - - Identifiers *ids = new Identifiers(); - ids->setDim(idents->dim); - for (size_t i = 0; i < idents->dim; i++) - { // Matches TypeQualified::syntaxCopyHelper() - Identifier *id = idents->tdata()[i]; - if (id->dyncast() == DYNCAST_DSYMBOL) - { - TemplateInstance *ti = (TemplateInstance *)id; - - ti = (TemplateInstance *)ti->syntaxCopy(NULL); - id = (Identifier *)ti; - } - ids->tdata()[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 (semanticRun) - { - // This for when a class/struct contains mixin members, and - // is done over because of forward references - if (parent && toParent()->isAggregateDeclaration()) - semanticRun = 1; // do over - else - { -#if LOG - printf("\tsemantic done\n"); -#endif - return; - } - } - if (!semanticRun) - semanticRun = 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; - size_t i; - Identifier *id; - - if (tqual) - { s = tqual->toDsymbol(sc); - i = 0; - } - else - { - i = 1; - id = idents->tdata()[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 = idents->tdata()[i]; - s = s->searchX(loc, sc, id); - } - if (!s) - { - error("is not defined"); - inst = this; - return; - } - tempdecl = s->toAlias()->isTemplateDeclaration(); - if (!tempdecl) - { - error("%s isn't a template", s->toChars()); - inst = this; - return; - } - } - - // Look for forward reference - assert(tempdecl); - for (TemplateDeclaration *td = tempdecl; td; td = td->overnext) - { - if (!td->semanticRun) - { - /* Cannot handle forward references if mixin is a struct member, - * because addField must happen during struct's semantic, not - * during the mixin semantic. - * runDeferred will re-run mixin's semantic outside of the struct's - * semantic. - */ - semanticRun = 0; - AggregateDeclaration *ad = toParent()->isAggregateDeclaration(); - if (ad) - ad->sizeok = 2; - else - { - // Forward reference - //printf("forward reference - deferring\n"); - scope = scx ? scx : new Scope(*sc); - scope->setNoFree(); - scope->module->addDeferredSemantic(this); - } - return; - } - } - - // Run semantic on each argument, place results in tiargs[] - semanticTiargs(sc); - if (errors || arrayObjectIsError(tiargs)) - return; - - tempdecl = findBestMatch(sc, NULL); - if (!tempdecl) - { inst = this; - return; // error recovery - } - - if (!ident) - ident = genIdent(tiargs); - - 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 (size_t i = 0; i < tiargs->dim; i++) - { Object *o = tiargs->tdata()[i]; - Type *ta = isType(o); - Expression *ea = isExpression(o); - Dsymbol *sa = isDsymbol(o); - Object *tmo = tm->tiargs->tdata()[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 *argscope = scy->push(argsym); - - unsigned errorsave = global.errors; - - // Declare each template parameter as an alias for the argument type - declareParameters(argscope); - - // Add members to enclosing scope, as well as this scope - for (unsigned i = 0; i < members->dim; i++) - { Dsymbol *s; - - s = members->tdata()[i]; - s->addMember(argscope, this, i); - //sc->insert(s); - //printf("sc->parent = %p, sc->scopesym = %p\n", sc->parent, sc->scopesym); - //printf("s->parent = %s\n", s->parent->toChars()); - } - - // Do semantic() analysis on template instance members -#if LOG - printf("\tdo semantic() on template instance members '%s'\n", toChars()); -#endif - Scope *sc2; - sc2 = argscope->push(this); - sc2->offset = sc->offset; - - static int nest; - //printf("%d\n", nest); - if (++nest > 500) - { - global.gag = 0; // ensure error message gets printed - error("recursive expansion"); - fatal(); - } - - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[i]; - s->semantic(sc2); - } - - nest--; - - 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(); - - argscope->pop(); - -// if (!isAnonymous()) - { - scy->pop(); - } -#if LOG - printf("-TemplateMixin::semantic('%s', this=%p)\n", toChars(), this); -#endif -} - -void TemplateMixin::semantic2(Scope *sc) -{ - if (semanticRun >= 2) - return; - semanticRun = 2; -#if LOG - printf("+TemplateMixin::semantic2('%s')\n", toChars()); -#endif - if (members) - { - assert(sc); - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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) -{ - if (semanticRun >= 3) - return; - semanticRun = 3; -#if LOG - printf("TemplateMixin::semantic3('%s')\n", toChars()); -#endif - if (members) - { - sc = sc->push(argsym); - sc = sc->push(this); - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = members->tdata()[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, Identifier *ident) -{ - return Dsymbol::oneMember(ps, ident); -} - -int TemplateMixin::hasPointers() -{ - //printf("TemplateMixin::hasPointers() %s\n", toChars()); - - if (members) - for (size_t i = 0; i < members->dim; i++) - { - Dsymbol *s = (*members)[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 (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; - - if (i) - buf->writeByte('.'); - buf->writestring(id->toChars()); - } - buf->writestring("!("); - if (tiargs) - { - for (size_t i = 0; i < tiargs->dim; i++) - { if (i) - buf->writebyte(','); - Object *oarg = tiargs->tdata()[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(); -} - - -#if IN_DMD -void TemplateMixin::toObjFile(int multiobj) -{ - //printf("TemplateMixin::toObjFile('%s')\n", toChars()); - TemplateInstance::toObjFile(multiobj); -} -#endif - diff --git a/dmd2/template.h b/dmd2/template.h deleted file mode 100644 index b659b46b..00000000 --- a/dmd2/template.h +++ /dev/null @@ -1,400 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_TEMPLATE_H -#define DMD_TEMPLATE_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ -#if IN_LLVM -#include -#endif -#include "root.h" -#include "arraytypes.h" -#include "dsymbol.h" -#if IN_LLVM -#include "mtype.h" -#endif - -struct OutBuffer; -struct Identifier; -struct TemplateInstance; -struct TemplateParameter; -struct TemplateTypeParameter; -struct TemplateThisParameter; -struct TemplateValueParameter; -struct TemplateAliasParameter; -struct TemplateTupleParameter; -struct Type; -struct TypeTypeof; -struct Scope; -struct Expression; -struct AliasDeclaration; -struct FuncDeclaration; -struct HdrGenState; -enum MATCH; - -struct Tuple : Object -{ - Objects objects; - - int dyncast() { return DYNCAST_TUPLE; } // kludge for template.isType() -}; - - -struct TemplateDeclaration : ScopeDsymbol -{ - TemplateParameters *parameters; // array of TemplateParameter's - - TemplateParameters *origParameters; // originals for Ddoc - Expression *constraint; - TemplateInstances instances; // array of TemplateInstance's - - TemplateDeclaration *overnext; // next overloaded TemplateDeclaration - TemplateDeclaration *overroot; // first in overnext list - - int semanticRun; // 1 semantic() run - - Dsymbol *onemember; // if !=NULL then one member of this template - - int literal; // this template declaration is a literal - int ismixin; // template declaration is only to be used as a mixin - - struct Previous - { Previous *prev; - Scope *sc; - Objects *dedargs; - }; - Previous *previous; // threaded list of previous instantiation attempts on stack - - TemplateDeclaration(Loc loc, Identifier *id, TemplateParameters *parameters, - Expression *constraint, Dsymbols *decldefs, int ismixin); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc); - int overloadInsert(Dsymbol *s); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - bool hasStaticCtorOrDtor(); - const char *kind(); - char *toChars(); - - void emitComment(Scope *sc); - void toJsonBuffer(OutBuffer *buf); -// void toDocBuffer(OutBuffer *buf); - - MATCH matchWithInstance(TemplateInstance *ti, Objects *atypes, Expressions *fargs, int flag); - MATCH leastAsSpecialized(TemplateDeclaration *td2, Expressions *fargs); - - MATCH deduceFunctionTemplateMatch(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, Objects *dedargs); - FuncDeclaration *deduceFunctionTemplate(Scope *sc, Loc loc, Objects *targsi, Expression *ethis, Expressions *fargs, int flags = 0); - void declareParameter(Scope *sc, TemplateParameter *tp, Object *o); - FuncDeclaration *doHeaderInstantiation(Scope *sc, Objects *tdargs, Expressions *fargs); - - TemplateDeclaration *isTemplateDeclaration() { return this; } - - TemplateTupleParameter *isVariadic(); - int isOverloadable(); - - void makeParamNamesVisibleInConstraint(Scope *paramscope, Expressions *fargs); -#if IN_LLVM - // LDC - std::string intrinsicName; -#endif -}; - -struct TemplateParameter -{ - /* For type-parameter: - * template Foo(ident) // specType is set to NULL - * template Foo(ident : specType) - * For value-parameter: - * template Foo(valType ident) // specValue is set to NULL - * template Foo(valType ident : specValue) - * For alias-parameter: - * template Foo(alias ident) - * For this-parameter: - * template Foo(this ident) - */ - - Loc loc; - Identifier *ident; - - Declaration *sparam; - - TemplateParameter(Loc loc, Identifier *ident); - - virtual TemplateTypeParameter *isTemplateTypeParameter(); - virtual TemplateValueParameter *isTemplateValueParameter(); - virtual TemplateAliasParameter *isTemplateAliasParameter(); -#if DMDV2 - virtual TemplateThisParameter *isTemplateThisParameter(); -#endif - virtual TemplateTupleParameter *isTemplateTupleParameter(); - - virtual TemplateParameter *syntaxCopy() = 0; - virtual void declareParameter(Scope *sc) = 0; - virtual void semantic(Scope *) = 0; - virtual void print(Object *oarg, Object *oded) = 0; - virtual void toCBuffer(OutBuffer *buf, HdrGenState *hgs) = 0; - virtual Object *specialization() = 0; - virtual Object *defaultArg(Loc loc, Scope *sc) = 0; - - /* If TemplateParameter's match as far as overloading goes. - */ - virtual int overloadMatch(TemplateParameter *) = 0; - - /* Match actual argument against parameter. - */ - virtual MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam) = 0; - - /* Create dummy argument based on parameter. - */ - virtual void *dummyArg() = 0; -}; - -struct TemplateTypeParameter : TemplateParameter -{ - /* Syntax: - * ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - static Type *tdummy; - - TemplateTypeParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateTypeParameter *isTemplateTypeParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -#if DMDV2 -struct TemplateThisParameter : TemplateTypeParameter -{ - /* Syntax: - * this ident : specType = defaultType - */ - Type *specType; // type parameter: if !=NULL, this is the type specialization - Type *defaultType; - - TemplateThisParameter(Loc loc, Identifier *ident, Type *specType, Type *defaultType); - - TemplateThisParameter *isTemplateThisParameter(); - TemplateParameter *syntaxCopy(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); -}; -#endif - -struct TemplateValueParameter : TemplateParameter -{ - /* Syntax: - * valType ident : specValue = defaultValue - */ - - Type *valType; - Expression *specValue; - Expression *defaultValue; - - static AA *edummies; - - TemplateValueParameter(Loc loc, Identifier *ident, Type *valType, Expression *specValue, Expression *defaultValue); - - TemplateValueParameter *isTemplateValueParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateAliasParameter : TemplateParameter -{ - /* Syntax: - * specType ident : specAlias = defaultAlias - */ - - Type *specType; - Object *specAlias; - Object *defaultAlias; - - static Dsymbol *sdummy; - - TemplateAliasParameter(Loc loc, Identifier *ident, Type *specType, Object *specAlias, Object *defaultAlias); - - TemplateAliasParameter *isTemplateAliasParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateTupleParameter : TemplateParameter -{ - /* Syntax: - * ident ... - */ - - TemplateTupleParameter(Loc loc, Identifier *ident); - - TemplateTupleParameter *isTemplateTupleParameter(); - TemplateParameter *syntaxCopy(); - void declareParameter(Scope *sc); - void semantic(Scope *); - void print(Object *oarg, Object *oded); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Object *specialization(); - Object *defaultArg(Loc loc, Scope *sc); - int overloadMatch(TemplateParameter *); - MATCH matchArg(Scope *sc, Objects *tiargs, size_t i, TemplateParameters *parameters, Objects *dedtypes, Declaration **psparam); - void *dummyArg(); -}; - -struct TemplateInstance : ScopeDsymbol -{ - /* Given: - * foo!(args) => - * name = foo - * tiargs = args - */ - Identifier *name; - //Identifiers idents; - Objects *tiargs; // Array of Types/Expressions of template - // instance arguments [int*, char, 10*10] - - Objects tdtypes; // Array of Types/Expressions corresponding - // to TemplateDeclaration.parameters - // [int, char, 100] - - TemplateDeclaration *tempdecl; // referenced by foo.bar.abc - TemplateInstance *inst; // refer to existing instance - TemplateInstance *tinst; // enclosing template instance - ScopeDsymbol *argsym; // argument symbol table - AliasDeclaration *aliasdecl; // !=NULL if instance is an alias for its - // sole member - WithScopeSymbol *withsym; // if a member of a with statement - int semanticRun; // has semantic() been done? - int semantictiargsdone; // has semanticTiargs() been done? - int nest; // for recursion detection - int havetempdecl; // 1 if used second constructor - Dsymbol *isnested; // if referencing local symbols, this is the context - int errors; // 1 if compiled with errors - int speculative; // 1 if only instantiated with errors gagged - bool ignore; // true if the instance must be ignored when codegen'ing -#ifdef IN_GCC - /* On some targets, it is necessary to know whether a symbol - will be emitted in the output or not before the symbol - is used. This can be different from getModule(). */ - Module * objFileModule; -#endif - - TemplateInstance(Loc loc, Identifier *temp_id); - TemplateInstance(Loc loc, TemplateDeclaration *tempdecl, Objects *tiargs); - static Objects *arraySyntaxCopy(Objects *objs); - Dsymbol *syntaxCopy(Dsymbol *); - void semantic(Scope *sc, Expressions *fargs); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - Dsymbol *toAlias(); // resolve real symbol - const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); - int needsTypeInference(Scope *sc); - char *toChars(); - char *mangle(); - void printInstantiationTrace(); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - // Internal - static void semanticTiargs(Loc loc, Scope *sc, Objects *tiargs, int flags); - void semanticTiargs(Scope *sc); - TemplateDeclaration *findTemplateDeclaration(Scope *sc); - TemplateDeclaration *findBestMatch(Scope *sc, Expressions *fargs); - void declareParameters(Scope *sc); - int hasNestedArgs(Objects *tiargs); - Identifier *genIdent(Objects *args); - - TemplateInstance *isTemplateInstance() { return this; } - AliasDeclaration *isAliasDeclaration(); - -#if IN_LLVM - Module* tmodule; // module from outermost enclosing template instantiation - Module* emittedInModule; // which module this template instance has been emitted in - - void codegen(Ir*); -#endif -}; - -struct TemplateMixin : TemplateInstance -{ - Identifiers *idents; - Type *tqual; - - TemplateMixin(Loc loc, Identifier *ident, Type *tqual, Identifiers *idents, Objects *tiargs); - Dsymbol *syntaxCopy(Dsymbol *s); - void semantic(Scope *sc); - void semantic2(Scope *sc); - void semantic3(Scope *sc); - void inlineScan(); - const char *kind(); - int oneMember(Dsymbol **ps, Identifier *ident); - int hasPointers(); - char *toChars(); - char *mangle(); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - -#if IN_DMD - void toObjFile(int multiobj); // compile to .obj file -#endif - - TemplateMixin *isTemplateMixin() { return this; } - -#if IN_LLVM - void codegen(Ir*); -#endif -}; - -Expression *isExpression(Object *o); -Dsymbol *isDsymbol(Object *o); -Type *isType(Object *o); -Tuple *isTuple(Object *o); -int arrayObjectIsError(Objects *args); -int isError(Object *o); -Type *getType(Object *o); -Dsymbol *getDsymbol(Object *o); - -void ObjectToCBuffer(OutBuffer *buf, HdrGenState *hgs, Object *oarg); -Object *objectSyntaxCopy(Object *o); - -#endif /* DMD_TEMPLATE_H */ diff --git a/dmd2/total.h b/dmd2/total.h deleted file mode 100644 index 1a0c9a89..00000000 --- a/dmd2/total.h +++ /dev/null @@ -1,46 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_TOTAL_H -#define DMD_TOTAL_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include -#include -#include -#include -#include - -#include "root.h" -#include "stringtable.h" - -#include "arraytypes.h" -#include "mars.h" -#include "lexer.h" -#include "parse.h" -#include "identifier.h" -#include "enum.h" -#include "aggregate.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "statement.h" -#include "scope.h" -#include "import.h" -#include "module.h" -#include "id.h" -#include "cond.h" -#include "version.h" -#include "lib.h" - -#endif /* DMD_TOTAL_H */ diff --git a/dmd2/traits.c b/dmd2/traits.c deleted file mode 100644 index ee3fa3ff..00000000 --- a/dmd2/traits.c +++ /dev/null @@ -1,549 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2011 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include -#include -#include -#include - -#include "rmem.h" - -//#include "port.h" -#include "mtype.h" -#include "init.h" -#include "expression.h" -#include "template.h" -#include "utf.h" -#include "enum.h" -#include "scope.h" -#include "statement.h" -#include "declaration.h" -#include "aggregate.h" -#include "import.h" -#include "id.h" -#include "dsymbol.h" -#include "module.h" -#include "attrib.h" -#include "hdrgen.h" -#include "parse.h" - -#define LOGSEMANTIC 0 - -#if DMDV2 - -/************************************************ - * Delegate to be passed to overloadApply() that looks - * for functions matching a trait. - */ - -struct Ptrait -{ - Expression *e1; - Expressions *exps; // collected results - Identifier *ident; // which trait we're looking for -}; - -static int fptraits(void *param, FuncDeclaration *f) -{ Ptrait *p = (Ptrait *)param; - - if (p->ident == Id::getVirtualFunctions && !f->isVirtual()) - return 0; - - if (p->ident == Id::getVirtualMethods && !f->isVirtualMethod()) - return 0; - - Expression *e; - - if (p->e1->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)p->e1; - e = new DotVarExp(0, dve->e1, f); - } - else - e = new DsymbolExp(0, f); - p->exps->push(e); - return 0; -} - -/************************ TraitsExp ************************************/ - -Expression *TraitsExp::semantic(Scope *sc) -{ -#if LOGSEMANTIC - printf("TraitsExp::semantic() %s\n", toChars()); -#endif - if (ident != Id::compiles && ident != Id::isSame && - ident != Id::identifier) - { - TemplateInstance::semanticTiargs(loc, sc, args, 1); - } - size_t dim = args ? args->dim : 0; - Declaration *d; - -#define ISTYPE(cond) \ - for (size_t i = 0; i < dim; i++) \ - { Type *t = getType(args->tdata()[i]); \ - if (!t) \ - goto Lfalse; \ - if (!(cond)) \ - goto Lfalse; \ - } \ - if (!dim) \ - goto Lfalse; \ - goto Ltrue; - -#define ISDSYMBOL(cond) \ - for (size_t i = 0; i < dim; i++) \ - { Dsymbol *s = getDsymbol(args->tdata()[i]); \ - if (!s) \ - goto Lfalse; \ - if (!(cond)) \ - goto Lfalse; \ - } \ - if (!dim) \ - goto Lfalse; \ - goto Ltrue; - - - - if (ident == Id::isArithmetic) - { - ISTYPE(t->isintegral() || t->isfloating()) - } - else if (ident == Id::isFloating) - { - ISTYPE(t->isfloating()) - } - else if (ident == Id::isIntegral) - { - ISTYPE(t->isintegral()) - } - else if (ident == Id::isScalar) - { - ISTYPE(t->isscalar()) - } - else if (ident == Id::isUnsigned) - { - ISTYPE(t->isunsigned()) - } - else if (ident == Id::isAssociativeArray) - { - ISTYPE(t->toBasetype()->ty == Taarray) - } - else if (ident == Id::isStaticArray) - { - ISTYPE(t->toBasetype()->ty == Tsarray) - } - else if (ident == Id::isAbstractClass) - { - ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->isAbstract()) - } - else if (ident == Id::isFinalClass) - { - ISTYPE(t->toBasetype()->ty == Tclass && ((TypeClass *)t->toBasetype())->sym->storage_class & STCfinal) - } - else if (ident == Id::isAbstractFunction) - { - FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isAbstract()) - } - else if (ident == Id::isVirtualFunction) - { - FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtual()) - } - else if (ident == Id::isVirtualMethod) - { - FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isVirtualMethod()) - } - else if (ident == Id::isFinalFunction) - { - FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && f->isFinal()) - } -#if DMDV2 - else if (ident == Id::isStaticFunction) - { - FuncDeclaration *f; - ISDSYMBOL((f = s->isFuncDeclaration()) != NULL && !f->needThis() && !f->isNested()) - } - else if (ident == Id::isRef) - { - ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isRef()) - } - else if (ident == Id::isOut) - { - ISDSYMBOL((d = s->isDeclaration()) != NULL && d->isOut()) - } - else if (ident == Id::isLazy) - { - ISDSYMBOL((d = s->isDeclaration()) != NULL && d->storage_class & STClazy) - } - else if (ident == Id::identifier) - { // Get identifier for symbol as a string literal - - // Specify 0 for the flags argument to semanticTiargs() so that - // a symbol should not be folded to a constant. - TemplateInstance::semanticTiargs(loc, sc, args, 0); - - if (dim != 1) - goto Ldimerror; - Object *o = args->tdata()[0]; - Dsymbol *s = getDsymbol(o); - if (!s || !s->ident) - { - error("argument %s has no identifier", o->toChars()); - goto Lfalse; - } - StringExp *se = new StringExp(loc, s->ident->toChars()); - return se->semantic(sc); - } - else if (ident == Id::parent) - { - if (dim != 1) - goto Ldimerror; - Object *o = args->tdata()[0]; - Dsymbol *s = getDsymbol(o); - if (s) - s = s->toParent(); - if (!s) - { - error("argument %s has no parent", o->toChars()); - goto Lfalse; - } - return (new DsymbolExp(loc, s))->semantic(sc); - } - -#endif - else if (ident == Id::hasMember || - ident == Id::getMember || - ident == Id::getOverloads || - ident == Id::getVirtualMethods || - ident == Id::getVirtualFunctions) - { - if (dim != 2) - goto Ldimerror; - Object *o = args->tdata()[0]; - Expression *e = isExpression(args->tdata()[1]); - if (!e) - { error("expression expected as second argument of __traits %s", ident->toChars()); - goto Lfalse; - } - e = e->optimize(WANTvalue | WANTinterpret); - StringExp *se = e->toString(); - if (!se || se->length() == 0) - { error("string expected as second argument of __traits %s instead of %s", ident->toChars(), e->toChars()); - goto Lfalse; - } - se = se->toUTF8(sc); - if (se->sz != 1) - { error("string must be chars"); - goto Lfalse; - } - Identifier *id = Lexer::idPool((char *)se->string); - - Type *t = isType(o); - e = isExpression(o); - Dsymbol *s = isDsymbol(o); - if (t) - e = typeDotIdExp(loc, t, id); - else if (e) - e = new DotIdExp(loc, e, id); - else if (s) - { e = new DsymbolExp(loc, s); - e = new DotIdExp(loc, e, id); - } - else - { error("invalid first argument"); - goto Lfalse; - } - - if (ident == Id::hasMember) - { - if (t) - { - Dsymbol *sym = t->toDsymbol(sc); - if (sym) - { - Dsymbol *sm = sym->search(loc, id, 0); - if (sm) - goto Ltrue; - } - } - - /* Take any errors as meaning it wasn't found - */ - Scope *sc2 = sc->push(); - //sc2->inHasMember++; - e = e->trySemantic(sc2); - sc2->pop(); - if (!e) - goto Lfalse; - else - goto Ltrue; - } - else if (ident == Id::getMember) - { - e = e->semantic(sc); - return e; - } - else if (ident == Id::getVirtualFunctions || - ident == Id::getVirtualMethods || - ident == Id::getOverloads) - { - unsigned errors = global.errors; - Expression *ex = e; - e = e->semantic(sc); - if (errors < global.errors) - error("%s cannot be resolved", ex->toChars()); - - /* Create tuple of functions of e - */ - //e->dump(0); - Expressions *exps = new Expressions(); - FuncDeclaration *f; - if (e->op == TOKvar) - { VarExp *ve = (VarExp *)e; - f = ve->var->isFuncDeclaration(); - } - else if (e->op == TOKdotvar) - { DotVarExp *dve = (DotVarExp *)e; - f = dve->var->isFuncDeclaration(); - } - else - f = NULL; - Ptrait p; - p.exps = exps; - p.e1 = e; - p.ident = ident; - overloadApply(f, fptraits, &p); - - TupleExp *tup = new TupleExp(loc, exps); - return tup->semantic(sc); - } - else - assert(0); - } - else if (ident == Id::classInstanceSize) - { - if (dim != 1) - goto Ldimerror; - Object *o = args->tdata()[0]; - Dsymbol *s = getDsymbol(o); - ClassDeclaration *cd; - if (!s || (cd = s->isClassDeclaration()) == NULL) - { - error("first argument is not a class"); - goto Lfalse; - } - return new IntegerExp(loc, cd->structsize, Type::tsize_t); - } - else if (ident == Id::allMembers || ident == Id::derivedMembers) - { - if (dim != 1) - goto Ldimerror; - Object *o = args->tdata()[0]; - Dsymbol *s = getDsymbol(o); - ScopeDsymbol *sd; - if (!s) - { - error("argument has no members"); - goto Lfalse; - } - if ((sd = s->isScopeDsymbol()) == NULL) - { - error("%s %s has no members", s->kind(), s->toChars()); - goto Lfalse; - } - - // use a struct as local function - struct PushIdentsDg - { - static int dg(void *ctx, size_t n, Dsymbol *sm) - { - if (!sm) - return 1; - //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); - if (sm->ident) - { - //printf("\t%s\n", sm->ident->toChars()); - Identifiers *idents = (Identifiers *)ctx; - - /* Skip if already present in idents[] - */ - for (size_t j = 0; j < idents->dim; j++) - { Identifier *id = idents->tdata()[j]; - if (id == sm->ident) - return 0; -#ifdef DEBUG - // Avoid using strcmp in the first place due to the performance impact in an O(N^2) loop. - assert(strcmp(id->toChars(), sm->ident->toChars()) != 0); -#endif - } - - idents->push(sm->ident); - } - return 0; - } - }; - - Identifiers *idents = new Identifiers; - ScopeDsymbol::foreach(sd->members, &PushIdentsDg::dg, idents); - - ClassDeclaration *cd = sd->isClassDeclaration(); - if (cd && ident == Id::allMembers) - { - struct PushBaseMembers - { - static void dg(ClassDeclaration *cd, Identifiers *idents) - { - for (size_t i = 0; i < cd->baseclasses->dim; i++) - { ClassDeclaration *cb = (*cd->baseclasses)[i]->base; - ScopeDsymbol::foreach(cb->members, &PushIdentsDg::dg, idents); - if (cb->baseclasses->dim) - dg(cb, idents); - } - } - }; - PushBaseMembers::dg(cd, idents); - } - - // Turn Identifiers into StringExps reusing the allocated array - assert(sizeof(Expressions) == sizeof(Identifiers)); - Expressions *exps = (Expressions *)idents; - for (size_t i = 0; i < idents->dim; i++) - { Identifier *id = idents->tdata()[i]; - StringExp *se = new StringExp(loc, id->toChars()); - exps->tdata()[i] = se; - } - -#if DMDV1 - Expression *e = new ArrayLiteralExp(loc, exps); -#endif -#if DMDV2 - /* Making this a tuple is more flexible, as it can be statically unrolled. - * To make an array literal, enclose __traits in [ ]: - * [ __traits(allMembers, ...) ] - */ - Expression *e = new TupleExp(loc, exps); -#endif - e = e->semantic(sc); - return e; - } - else if (ident == Id::compiles) - { - /* Determine if all the objects - types, expressions, or symbols - - * compile without error - */ - if (!dim) - goto Lfalse; - - for (size_t i = 0; i < dim; i++) - { Object *o = args->tdata()[i]; - Expression *e; - - unsigned errors = global.startGagging(); - - Type *t = isType(o); - if (t) - { Dsymbol *s; - t->resolve(loc, sc, &e, &t, &s); - if (t) - t->semantic(loc, sc); - else if (e) - { e = e->semantic(sc); - e = e->optimize(WANTvalue); - } - } - else - { e = isExpression(o); - if (e) - { e = e->semantic(sc); - e = e->optimize(WANTvalue); - } - } - - if (global.endGagging(errors)) - { - goto Lfalse; - } - } - goto Ltrue; - } - else if (ident == Id::isSame) - { /* Determine if two symbols are the same - */ - if (dim != 2) - goto Ldimerror; - TemplateInstance::semanticTiargs(loc, sc, args, 0); - Object *o1 = args->tdata()[0]; - Object *o2 = args->tdata()[1]; - Dsymbol *s1 = getDsymbol(o1); - Dsymbol *s2 = getDsymbol(o2); - - //printf("isSame: %s, %s\n", o1->toChars(), o2->toChars()); -#if 0 - printf("o1: %p\n", o1); - printf("o2: %p\n", o2); - if (!s1) - { Expression *ea = isExpression(o1); - if (ea) - printf("%s\n", ea->toChars()); - Type *ta = isType(o1); - if (ta) - printf("%s\n", ta->toChars()); - goto Lfalse; - } - else - printf("%s %s\n", s1->kind(), s1->toChars()); -#endif - if (!s1 && !s2) - { Expression *ea1 = isExpression(o1); - Expression *ea2 = isExpression(o2); - if (ea1 && ea2) - { - if (ea1->equals(ea2)) - goto Ltrue; - } - } - - if (!s1 || !s2) - goto Lfalse; - - s1 = s1->toAlias(); - s2 = s2->toAlias(); - - if (s1 == s2) - goto Ltrue; - else - goto Lfalse; - } - else - { error("unrecognized trait %s", ident->toChars()); - goto Lfalse; - } - - return NULL; - -Ldimerror: - error("wrong number of arguments %d", (int)dim); - goto Lfalse; - - -Lfalse: - return new IntegerExp(loc, 0, Type::tbool); - -Ltrue: - return new IntegerExp(loc, 1, Type::tbool); -} - - -#endif diff --git a/dmd2/unialpha.c b/dmd2/unialpha.c deleted file mode 100644 index 5c407180..00000000 --- a/dmd2/unialpha.c +++ /dev/null @@ -1,323 +0,0 @@ - -// Copyright (c) 2003 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include - -/******************************* - * Return !=0 if unicode alpha. - * Use table from C99 Appendix D. - */ - -int isUniAlpha(unsigned u) -{ - static unsigned short table[][2] = - { - { 0x00AA, 0x00AA }, - { 0x00B5, 0x00B5 }, - { 0x00B7, 0x00B7 }, - { 0x00BA, 0x00BA }, - { 0x00C0, 0x00D6 }, - { 0x00D8, 0x00F6 }, - { 0x00F8, 0x01F5 }, - { 0x01FA, 0x0217 }, - { 0x0250, 0x02A8 }, - { 0x02B0, 0x02B8 }, - { 0x02BB, 0x02BB }, - { 0x02BD, 0x02C1 }, - { 0x02D0, 0x02D1 }, - { 0x02E0, 0x02E4 }, - { 0x037A, 0x037A }, - { 0x0386, 0x0386 }, - { 0x0388, 0x038A }, - { 0x038C, 0x038C }, - { 0x038E, 0x03A1 }, - { 0x03A3, 0x03CE }, - { 0x03D0, 0x03D6 }, - { 0x03DA, 0x03DA }, - { 0x03DC, 0x03DC }, - { 0x03DE, 0x03DE }, - { 0x03E0, 0x03E0 }, - { 0x03E2, 0x03F3 }, - { 0x0401, 0x040C }, - { 0x040E, 0x044F }, - { 0x0451, 0x045C }, - { 0x045E, 0x0481 }, - { 0x0490, 0x04C4 }, - { 0x04C7, 0x04C8 }, - { 0x04CB, 0x04CC }, - { 0x04D0, 0x04EB }, - { 0x04EE, 0x04F5 }, - { 0x04F8, 0x04F9 }, - { 0x0531, 0x0556 }, - { 0x0559, 0x0559 }, - { 0x0561, 0x0587 }, - { 0x05B0, 0x05B9 }, - { 0x05BB, 0x05BD }, - { 0x05BF, 0x05BF }, - { 0x05C1, 0x05C2 }, - { 0x05D0, 0x05EA }, - { 0x05F0, 0x05F2 }, - { 0x0621, 0x063A }, - { 0x0640, 0x0652 }, - { 0x0660, 0x0669 }, - { 0x0670, 0x06B7 }, - { 0x06BA, 0x06BE }, - { 0x06C0, 0x06CE }, - { 0x06D0, 0x06DC }, - { 0x06E5, 0x06E8 }, - { 0x06EA, 0x06ED }, - { 0x06F0, 0x06F9 }, - { 0x0901, 0x0903 }, - { 0x0905, 0x0939 }, - { 0x093D, 0x093D }, - { 0x093E, 0x094D }, - { 0x0950, 0x0952 }, - { 0x0958, 0x0963 }, - { 0x0966, 0x096F }, - { 0x0981, 0x0983 }, - { 0x0985, 0x098C }, - { 0x098F, 0x0990 }, - { 0x0993, 0x09A8 }, - { 0x09AA, 0x09B0 }, - { 0x09B2, 0x09B2 }, - { 0x09B6, 0x09B9 }, - { 0x09BE, 0x09C4 }, - { 0x09C7, 0x09C8 }, - { 0x09CB, 0x09CD }, - { 0x09DC, 0x09DD }, - { 0x09DF, 0x09E3 }, - { 0x09E6, 0x09EF }, - { 0x09F0, 0x09F1 }, - { 0x0A02, 0x0A02 }, - { 0x0A05, 0x0A0A }, - { 0x0A0F, 0x0A10 }, - { 0x0A13, 0x0A28 }, - { 0x0A2A, 0x0A30 }, - { 0x0A32, 0x0A33 }, - { 0x0A35, 0x0A36 }, - { 0x0A38, 0x0A39 }, - { 0x0A3E, 0x0A42 }, - { 0x0A47, 0x0A48 }, - { 0x0A4B, 0x0A4D }, - { 0x0A59, 0x0A5C }, - { 0x0A5E, 0x0A5E }, - { 0x0A66, 0x0A6F }, - { 0x0A74, 0x0A74 }, - { 0x0A81, 0x0A83 }, - { 0x0A85, 0x0A8B }, - { 0x0A8D, 0x0A8D }, - { 0x0A8F, 0x0A91 }, - { 0x0A93, 0x0AA8 }, - { 0x0AAA, 0x0AB0 }, - { 0x0AB2, 0x0AB3 }, - { 0x0AB5, 0x0AB9 }, - { 0x0ABD, 0x0AC5 }, - { 0x0AC7, 0x0AC9 }, - { 0x0ACB, 0x0ACD }, - { 0x0AD0, 0x0AD0 }, - { 0x0AE0, 0x0AE0 }, - { 0x0AE6, 0x0AEF }, - { 0x0B01, 0x0B03 }, - { 0x0B05, 0x0B0C }, - { 0x0B0F, 0x0B10 }, - { 0x0B13, 0x0B28 }, - { 0x0B2A, 0x0B30 }, - { 0x0B32, 0x0B33 }, - { 0x0B36, 0x0B39 }, - { 0x0B3D, 0x0B3D }, - { 0x0B3E, 0x0B43 }, - { 0x0B47, 0x0B48 }, - { 0x0B4B, 0x0B4D }, - { 0x0B5C, 0x0B5D }, - { 0x0B5F, 0x0B61 }, - { 0x0B66, 0x0B6F }, - { 0x0B82, 0x0B83 }, - { 0x0B85, 0x0B8A }, - { 0x0B8E, 0x0B90 }, - { 0x0B92, 0x0B95 }, - { 0x0B99, 0x0B9A }, - { 0x0B9C, 0x0B9C }, - { 0x0B9E, 0x0B9F }, - { 0x0BA3, 0x0BA4 }, - { 0x0BA8, 0x0BAA }, - { 0x0BAE, 0x0BB5 }, - { 0x0BB7, 0x0BB9 }, - { 0x0BBE, 0x0BC2 }, - { 0x0BC6, 0x0BC8 }, - { 0x0BCA, 0x0BCD }, - { 0x0BE7, 0x0BEF }, - { 0x0C01, 0x0C03 }, - { 0x0C05, 0x0C0C }, - { 0x0C0E, 0x0C10 }, - { 0x0C12, 0x0C28 }, - { 0x0C2A, 0x0C33 }, - { 0x0C35, 0x0C39 }, - { 0x0C3E, 0x0C44 }, - { 0x0C46, 0x0C48 }, - { 0x0C4A, 0x0C4D }, - { 0x0C60, 0x0C61 }, - { 0x0C66, 0x0C6F }, - { 0x0C82, 0x0C83 }, - { 0x0C85, 0x0C8C }, - { 0x0C8E, 0x0C90 }, - { 0x0C92, 0x0CA8 }, - { 0x0CAA, 0x0CB3 }, - { 0x0CB5, 0x0CB9 }, - { 0x0CBE, 0x0CC4 }, - { 0x0CC6, 0x0CC8 }, - { 0x0CCA, 0x0CCD }, - { 0x0CDE, 0x0CDE }, - { 0x0CE0, 0x0CE1 }, - { 0x0CE6, 0x0CEF }, - { 0x0D02, 0x0D03 }, - { 0x0D05, 0x0D0C }, - { 0x0D0E, 0x0D10 }, - { 0x0D12, 0x0D28 }, - { 0x0D2A, 0x0D39 }, - { 0x0D3E, 0x0D43 }, - { 0x0D46, 0x0D48 }, - { 0x0D4A, 0x0D4D }, - { 0x0D60, 0x0D61 }, - { 0x0D66, 0x0D6F }, - { 0x0E01, 0x0E3A }, - { 0x0E40, 0x0E5B }, -// { 0x0E50, 0x0E59 }, - { 0x0E81, 0x0E82 }, - { 0x0E84, 0x0E84 }, - { 0x0E87, 0x0E88 }, - { 0x0E8A, 0x0E8A }, - { 0x0E8D, 0x0E8D }, - { 0x0E94, 0x0E97 }, - { 0x0E99, 0x0E9F }, - { 0x0EA1, 0x0EA3 }, - { 0x0EA5, 0x0EA5 }, - { 0x0EA7, 0x0EA7 }, - { 0x0EAA, 0x0EAB }, - { 0x0EAD, 0x0EAE }, - { 0x0EB0, 0x0EB9 }, - { 0x0EBB, 0x0EBD }, - { 0x0EC0, 0x0EC4 }, - { 0x0EC6, 0x0EC6 }, - { 0x0EC8, 0x0ECD }, - { 0x0ED0, 0x0ED9 }, - { 0x0EDC, 0x0EDD }, - { 0x0F00, 0x0F00 }, - { 0x0F18, 0x0F19 }, - { 0x0F20, 0x0F33 }, - { 0x0F35, 0x0F35 }, - { 0x0F37, 0x0F37 }, - { 0x0F39, 0x0F39 }, - { 0x0F3E, 0x0F47 }, - { 0x0F49, 0x0F69 }, - { 0x0F71, 0x0F84 }, - { 0x0F86, 0x0F8B }, - { 0x0F90, 0x0F95 }, - { 0x0F97, 0x0F97 }, - { 0x0F99, 0x0FAD }, - { 0x0FB1, 0x0FB7 }, - { 0x0FB9, 0x0FB9 }, - { 0x10A0, 0x10C5 }, - { 0x10D0, 0x10F6 }, - { 0x1E00, 0x1E9B }, - { 0x1EA0, 0x1EF9 }, - { 0x1F00, 0x1F15 }, - { 0x1F18, 0x1F1D }, - { 0x1F20, 0x1F45 }, - { 0x1F48, 0x1F4D }, - { 0x1F50, 0x1F57 }, - { 0x1F59, 0x1F59 }, - { 0x1F5B, 0x1F5B }, - { 0x1F5D, 0x1F5D }, - { 0x1F5F, 0x1F7D }, - { 0x1F80, 0x1FB4 }, - { 0x1FB6, 0x1FBC }, - { 0x1FBE, 0x1FBE }, - { 0x1FC2, 0x1FC4 }, - { 0x1FC6, 0x1FCC }, - { 0x1FD0, 0x1FD3 }, - { 0x1FD6, 0x1FDB }, - { 0x1FE0, 0x1FEC }, - { 0x1FF2, 0x1FF4 }, - { 0x1FF6, 0x1FFC }, - { 0x203F, 0x2040 }, - { 0x207F, 0x207F }, - { 0x2102, 0x2102 }, - { 0x2107, 0x2107 }, - { 0x210A, 0x2113 }, - { 0x2115, 0x2115 }, - { 0x2118, 0x211D }, - { 0x2124, 0x2124 }, - { 0x2126, 0x2126 }, - { 0x2128, 0x2128 }, - { 0x212A, 0x2131 }, - { 0x2133, 0x2138 }, - { 0x2160, 0x2182 }, - { 0x3005, 0x3007 }, - { 0x3021, 0x3029 }, - { 0x3041, 0x3093 }, - { 0x309B, 0x309C }, - { 0x30A1, 0x30F6 }, - { 0x30FB, 0x30FC }, - { 0x3105, 0x312C }, - { 0x4E00, 0x9FA5 }, - { 0xAC00, 0xD7A3 }, - }; - -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - //printf("%x\n", table[i][0]); - assert(table[i][0] <= table[i][1]); - if (i < sizeof(table) / sizeof(table[0]) - 1) - assert(table[i][1] < table[i + 1][0]); - } -#endif - - if (u > 0xD7A3) - goto Lisnot; - - // Binary search - int mid; - int low; - int high; - - low = 0; - high = sizeof(table) / sizeof(table[0]) - 1; - while (low <= high) - { - mid = (low + high) >> 1; - if (u < table[mid][0]) - high = mid - 1; - else if (u > table[mid][1]) - low = mid + 1; - else - goto Lis; - } - -Lisnot: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - assert(u < table[i][0] || u > table[i][1]); - } -#endif - return 0; - -Lis: -#ifdef DEBUG - for (int i = 0; i < sizeof(table) / sizeof(table[0]); i++) - { - if (u >= table[i][0] && u <= table[i][1]) - return 1; - } - assert(0); // should have been in table -#endif - return 1; -} - diff --git a/dmd2/unittests.c b/dmd2/unittests.c deleted file mode 100644 index 1b3c2770..00000000 --- a/dmd2/unittests.c +++ /dev/null @@ -1,17 +0,0 @@ - -#include - -#include "mars.h" - -void unittest_speller(); -void unittest_importHint(); -void unittest_aa(); - -void unittests() -{ -#if UNITTEST - unittest_speller(); - unittest_importHint(); - unittest_aa(); -#endif -} diff --git a/dmd2/utf.c b/dmd2/utf.c deleted file mode 100644 index 78f8cd4a..00000000 --- a/dmd2/utf.c +++ /dev/null @@ -1,320 +0,0 @@ -// utf.c -// Copyright (c) 2003-2009 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -// Description of UTF-8 at: -// http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - -#include -#include -#include - -#include "utf.h" - -int utf_isValidDchar(dchar_t c) -{ - return c < 0xD800 || - (c > 0xDFFF && c <= 0x10FFFF && c != 0xFFFE && c != 0xFFFF); -} - -static const unsigned char UTF8stride[256] = -{ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, - 4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF, -}; - -/** - * stride() returns the length of a UTF-8 sequence starting at index i - * in string s. - * Returns: - * The number of bytes in the UTF-8 sequence or - * 0xFF meaning s[i] is not the start of of UTF-8 sequence. - */ - -unsigned stride(unsigned char* s, size_t i) -{ - unsigned result = UTF8stride[s[i]]; - return result; -} - -/******************************************** - * Decode a single UTF-8 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult) -{ - dchar_t V; - size_t i = *pidx; - unsigned char u = s[i]; - - //printf("utf_decodeChar(s = %02x, %02x, %02x len = %d)\n", u, s[1], s[2], len); - - assert(i >= 0 && i < len); - - if (u & 0x80) - { unsigned n; - unsigned char u2; - - /* The following encodings are valid, except for the 5 and 6 byte - * combinations: - * 0xxxxxxx - * 110xxxxx 10xxxxxx - * 1110xxxx 10xxxxxx 10xxxxxx - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - * 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - * 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx - */ - for (n = 1; ; n++) - { - if (n > 4) - goto Lerr; // only do the first 4 of 6 encodings - if (((u << n) & 0x80) == 0) - { - if (n == 1) - goto Lerr; - break; - } - } - - // Pick off (7 - n) significant bits of B from first byte of octet - V = (dchar_t)(u & ((1 << (7 - n)) - 1)); - - if (i + (n - 1) >= len) - goto Lerr; // off end of string - - /* The following combinations are overlong, and illegal: - * 1100000x (10xxxxxx) - * 11100000 100xxxxx (10xxxxxx) - * 11110000 1000xxxx (10xxxxxx 10xxxxxx) - * 11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx) - * 11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx) - */ - u2 = s[i + 1]; - if ((u & 0xFE) == 0xC0 || - (u == 0xE0 && (u2 & 0xE0) == 0x80) || - (u == 0xF0 && (u2 & 0xF0) == 0x80) || - (u == 0xF8 && (u2 & 0xF8) == 0x80) || - (u == 0xFC && (u2 & 0xFC) == 0x80)) - goto Lerr; // overlong combination - - for (unsigned j = 1; j != n; j++) - { - u = s[i + j]; - if ((u & 0xC0) != 0x80) - goto Lerr; // trailing bytes are 10xxxxxx - V = (V << 6) | (u & 0x3F); - } - if (!utf_isValidDchar(V)) - goto Lerr; - i += n; - } - else - { - V = (dchar_t) u; - i++; - } - - assert(utf_isValidDchar(V)); - *pidx = i; - *presult = V; - return NULL; - - Lerr: - *presult = (dchar_t) s[i]; - *pidx = i + 1; - return "invalid UTF-8 sequence"; -} - -/*************************************************** - * Validate a UTF-8 string. - * Returns: - * NULL success - * !=NULL error message string - */ - -const char *utf_validateString(unsigned char *s, size_t len) -{ - size_t idx; - const char *err = NULL; - dchar_t dc; - - for (idx = 0; idx < len; ) - { - err = utf_decodeChar(s, len, &idx, &dc); - if (err) - break; - } - return err; -} - - -/******************************************** - * Decode a single UTF-16 character sequence. - * Returns: - * NULL success - * !=NULL error message string - */ - - -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult) -{ - const char *msg; - size_t i = *pidx; - unsigned u = s[i]; - - assert(i >= 0 && i < len); - if (u & ~0x7F) - { if (u >= 0xD800 && u <= 0xDBFF) - { unsigned u2; - - if (i + 1 == len) - { msg = "surrogate UTF-16 high value past end of string"; - goto Lerr; - } - u2 = s[i + 1]; - if (u2 < 0xDC00 || u2 > 0xDFFF) - { msg = "surrogate UTF-16 low value out of range"; - goto Lerr; - } - u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00); - i += 2; - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { msg = "unpaired surrogate UTF-16 value"; - goto Lerr; - } - else if (u == 0xFFFE || u == 0xFFFF) - { msg = "illegal UTF-16 value"; - goto Lerr; - } - else - i++; - } - else - { - i++; - } - - assert(utf_isValidDchar(u)); - *pidx = i; - *presult = (dchar_t)u; - return NULL; - - Lerr: - *presult = (dchar_t)s[i]; - *pidx = i + 1; - return msg; -} - -void utf_encodeChar(unsigned char *s, dchar_t c) -{ - if (c <= 0x7F) - { - s[0] = (char) c; - } - else if (c <= 0x7FF) - { - s[0] = (char)(0xC0 | (c >> 6)); - s[1] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0xFFFF) - { - s[0] = (char)(0xE0 | (c >> 12)); - s[1] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[2] = (char)(0x80 | (c & 0x3F)); - } - else if (c <= 0x10FFFF) - { - s[0] = (char)(0xF0 | (c >> 18)); - s[1] = (char)(0x80 | ((c >> 12) & 0x3F)); - s[2] = (char)(0x80 | ((c >> 6) & 0x3F)); - s[3] = (char)(0x80 | (c & 0x3F)); - } - else - assert(0); -} - -void utf_encodeWchar(unsigned short *s, dchar_t c) -{ - if (c <= 0xFFFF) - { - s[0] = (wchar_t) c; - } - else - { - s[0] = (wchar_t) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800); - s[1] = (wchar_t) (((c - 0x10000) & 0x3FF) + 0xDC00); - } -} - - -/** - * Returns the code length of c in the encoding. - * The code is returned in character count, not in bytes. - */ - -int utf_codeLengthChar(dchar_t c) -{ - return - c <= 0x7F ? 1 - : c <= 0x7FF ? 2 - : c <= 0xFFFF ? 3 - : c <= 0x10FFFF ? 4 - : (assert(false), 6); -} - -int utf_codeLengthWchar(dchar_t c) -{ - return c <= 0xFFFF ? 1 : 2; -} - -/** - * Returns the code length of c in the encoding. - * sz is the encoding: 1 = utf8, 2 = utf16, 4 = utf32. - * The code is returned in character count, not in bytes. - */ -int utf_codeLength(int sz, dchar_t c) -{ - if (sz == 1) - return utf_codeLengthChar(c); - if (sz == 2) - return utf_codeLengthWchar(c); - assert(sz == 4); - return 1; -} - -void utf_encode(int sz, void *s, dchar_t c) -{ - if (sz == 1) - utf_encodeChar((unsigned char *)s, c); - else if (sz == 2) - utf_encodeWchar((unsigned short *)s, c); - else - { - assert(sz == 4); - memcpy((unsigned char *)s, &c, sz); - } -} - diff --git a/dmd2/utf.h b/dmd2/utf.h deleted file mode 100644 index 22d8d3eb..00000000 --- a/dmd2/utf.h +++ /dev/null @@ -1,35 +0,0 @@ -// Compiler implementation of the D programming language -// utf.h -// Copyright (c) 2003-2010 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_UTF_H -#define DMD_UTF_H - - -typedef unsigned dchar_t; - -int utf_isValidDchar(dchar_t c); - -const char *utf_decodeChar(unsigned char *s, size_t len, size_t *pidx, dchar_t *presult); -const char *utf_decodeWchar(unsigned short *s, size_t len, size_t *pidx, dchar_t *presult); - -const char *utf_validateString(unsigned char *s, size_t len); - -extern int isUniAlpha(dchar_t); - -void utf_encodeChar(unsigned char *s, dchar_t c); -void utf_encodeWchar(unsigned short *s, dchar_t c); - -int utf_codeLengthChar(dchar_t c); -int utf_codeLengthWchar(dchar_t c); - -int utf_codeLength(int sz, dchar_t c); -void utf_encode(int sz, void *s, dchar_t c); - -#endif diff --git a/dmd2/version.c b/dmd2/version.c deleted file mode 100644 index 37f33c06..00000000 --- a/dmd2/version.c +++ /dev/null @@ -1,181 +0,0 @@ - -// Copyright (c) 1999-2005 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#include -#include - -#include "root.h" - -#include "identifier.h" -#include "dsymbol.h" -#include "cond.h" -#include "version.h" -#include "module.h" - -/* ================================================== */ - -/* DebugSymbol's happen for statements like: - * debug = identifier; - * debug = integer; - */ - -DebugSymbol::DebugSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -DebugSymbol::DebugSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *DebugSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - DebugSymbol *ds = new DebugSymbol(loc, ident); - ds->level = level; - return ds; -} - -int DebugSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("DebugSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->debugidsNot, ident)) - error("defined after use"); - if (!m->debugids) - m->debugids = new Strings(); - m->debugids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->debuglevel = level; - } - return 0; -} - -void DebugSymbol::semantic(Scope *sc) -{ - //printf("DebugSymbol::semantic() %s\n", toChars()); -} - -void DebugSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("debug = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *DebugSymbol::kind() -{ - return "debug"; -} - -/* ================================================== */ - -/* VersionSymbol's happen for statements like: - * version = identifier; - * version = integer; - */ - -VersionSymbol::VersionSymbol(Loc loc, Identifier *ident) - : Dsymbol(ident) -{ - this->loc = loc; -} - -VersionSymbol::VersionSymbol(Loc loc, unsigned level) - : Dsymbol() -{ - this->level = level; - this->loc = loc; -} - -Dsymbol *VersionSymbol::syntaxCopy(Dsymbol *s) -{ - assert(!s); - VersionSymbol *ds = new VersionSymbol(loc, ident); - ds->level = level; - return ds; -} - -int VersionSymbol::addMember(Scope *sc, ScopeDsymbol *sd, int memnum) -{ - //printf("VersionSymbol::addMember('%s') %s\n", sd->toChars(), toChars()); - Module *m; - - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - m = sd->isModule(); - if (ident) - { - VersionCondition::checkPredefined(loc, ident->toChars()); - if (!m) - error("declaration must be at module level"); - else - { - if (findCondition(m->versionidsNot, ident)) - error("defined after use"); - if (!m->versionids) - m->versionids = new Strings(); - m->versionids->push(ident->toChars()); - } - } - else - { - if (!m) - error("level declaration must be at module level"); - else - m->versionlevel = level; - } - return 0; -} - -void VersionSymbol::semantic(Scope *sc) -{ -} - -void VersionSymbol::toCBuffer(OutBuffer *buf, HdrGenState *hgs) -{ - buf->writestring("version = "); - if (ident) - buf->writestring(ident->toChars()); - else - buf->printf("%u", level); - buf->writestring(";"); - buf->writenl(); -} - -const char *VersionSymbol::kind() -{ - return "version"; -} - - diff --git a/dmd2/version.h b/dmd2/version.h deleted file mode 100644 index b5ae51d2..00000000 --- a/dmd2/version.h +++ /dev/null @@ -1,51 +0,0 @@ - -// Compiler implementation of the D programming language -// Copyright (c) 1999-2006 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// License for redistribution is by either the Artistic License -// in artistic.txt, or the GNU General Public License in gnu.txt. -// See the included readme.txt for details. - -#ifndef DMD_VERSION_H -#define DMD_VERSION_H - -#ifdef __DMC__ -#pragma once -#endif /* __DMC__ */ - -#include "dsymbol.h" - -struct OutBuffer; -struct HdrGenState; - -struct DebugSymbol : Dsymbol -{ - unsigned level; - - DebugSymbol(Loc loc, Identifier *ident); - DebugSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -struct VersionSymbol : Dsymbol -{ - unsigned level; - - VersionSymbol(Loc loc, Identifier *ident); - VersionSymbol(Loc loc, unsigned level); - Dsymbol *syntaxCopy(Dsymbol *); - - int addMember(Scope *sc, ScopeDsymbol *s, int memnum); - void semantic(Scope *sc); - void toCBuffer(OutBuffer *buf, HdrGenState *hgs); - const char *kind(); -}; - -#endif /* DMD_VERSION_H */